1 use super::address_transform::AddressTransform;
2 use super::{DebugInputContext, Reader};
3 use anyhow::Error;
4 use gimli::{write, AttributeValue, DebuggingInformationEntry, RangeListsOffset, Unit};
5 use wasmtime_environ::{DefinedFuncIndex, EntityRef};
6 
7 pub(crate) enum RangeInfoBuilder {
8     Undefined,
9     Position(u64),
10     Ranges(Vec<(u64, u64)>),
11     Function(DefinedFuncIndex),
12 }
13 
14 impl RangeInfoBuilder {
15     pub(crate) fn from<R>(
16         dwarf: &gimli::Dwarf<R>,
17         unit: &Unit<R, R::Offset>,
18         entry: &DebuggingInformationEntry<R>,
19         context: &DebugInputContext<R>,
20         cu_low_pc: u64,
21     ) -> Result<Self, Error>
22     where
23         R: Reader,
24     {
25         if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges)? {
26             let r = dwarf.ranges_offset_from_raw(unit, r);
27             return RangeInfoBuilder::from_ranges_ref(unit, r, context, cu_low_pc);
28         };
29 
30         let low_pc =
31             if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? {
32                 addr
33             } else if let Some(AttributeValue::DebugAddrIndex(i)) =
34                 entry.attr_value(gimli::DW_AT_low_pc)?
35             {
36                 context.debug_addr.get_address(4, unit.addr_base, i)?
37             } else {
38                 return Ok(RangeInfoBuilder::Undefined);
39             };
40 
41         Ok(
42             if let Some(AttributeValue::Udata(u)) = entry.attr_value(gimli::DW_AT_high_pc)? {
43                 RangeInfoBuilder::Ranges(vec![(low_pc, low_pc + u)])
44             } else {
45                 RangeInfoBuilder::Position(low_pc)
46             },
47         )
48     }
49 
50     pub(crate) fn from_ranges_ref<R>(
51         unit: &Unit<R, R::Offset>,
52         ranges: RangeListsOffset,
53         context: &DebugInputContext<R>,
54         cu_low_pc: u64,
55     ) -> Result<Self, Error>
56     where
57         R: Reader,
58     {
59         let unit_encoding = unit.encoding();
60         let mut ranges = context.rnglists.ranges(
61             ranges,
62             unit_encoding,
63             cu_low_pc,
64             &context.debug_addr,
65             unit.addr_base,
66         )?;
67         let mut result = Vec::new();
68         while let Some(range) = ranges.next()? {
69             if range.begin >= range.end {
70                 // ignore empty ranges
71             }
72             result.push((range.begin, range.end));
73         }
74 
75         Ok(if result.is_empty() {
76             RangeInfoBuilder::Undefined
77         } else {
78             RangeInfoBuilder::Ranges(result)
79         })
80     }
81 
82     pub(crate) fn from_subprogram_die<R>(
83         dwarf: &gimli::Dwarf<R>,
84         unit: &Unit<R, R::Offset>,
85         entry: &DebuggingInformationEntry<R>,
86         context: &DebugInputContext<R>,
87         addr_tr: &AddressTransform,
88         cu_low_pc: u64,
89     ) -> Result<Self, Error>
90     where
91         R: Reader,
92     {
93         let unit_encoding = unit.encoding();
94         let addr =
95             if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? {
96                 addr
97             } else if let Some(AttributeValue::DebugAddrIndex(i)) =
98                 entry.attr_value(gimli::DW_AT_low_pc)?
99             {
100                 context.debug_addr.get_address(4, unit.addr_base, i)?
101             } else if let Some(AttributeValue::RangeListsRef(r)) =
102                 entry.attr_value(gimli::DW_AT_ranges)?
103             {
104                 let r = dwarf.ranges_offset_from_raw(unit, r);
105                 let mut ranges = context.rnglists.ranges(
106                     r,
107                     unit_encoding,
108                     cu_low_pc,
109                     &context.debug_addr,
110                     unit.addr_base,
111                 )?;
112                 if let Some(range) = ranges.next()? {
113                     range.begin
114                 } else {
115                     return Ok(RangeInfoBuilder::Undefined);
116                 }
117             } else {
118                 return Ok(RangeInfoBuilder::Undefined);
119             };
120 
121         let index = addr_tr.find_func_index(addr);
122         if index.is_none() {
123             return Ok(RangeInfoBuilder::Undefined);
124         }
125         Ok(RangeInfoBuilder::Function(index.unwrap()))
126     }
127 
128     pub(crate) fn build(
129         &self,
130         addr_tr: &AddressTransform,
131         out_unit: &mut write::Unit,
132         current_scope_id: write::UnitEntryId,
133     ) {
134         match self {
135             RangeInfoBuilder::Undefined => (),
136             RangeInfoBuilder::Position(pc) => {
137                 let addr = addr_tr
138                     .translate(*pc)
139                     .unwrap_or(write::Address::Constant(0));
140                 let current_scope = out_unit.get_mut(current_scope_id);
141                 current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));
142             }
143             RangeInfoBuilder::Ranges(ranges) => {
144                 let mut result = Vec::new();
145                 for (begin, end) in ranges {
146                     result.extend(addr_tr.translate_ranges(*begin, *end));
147                 }
148                 if result.len() != 1 {
149                     let range_list = result
150                         .iter()
151                         .map(|tr| write::Range::StartLength {
152                             begin: tr.0,
153                             length: tr.1,
154                         })
155                         .collect::<Vec<_>>();
156                     let range_list_id = out_unit.ranges.add(write::RangeList(range_list));
157                     let current_scope = out_unit.get_mut(current_scope_id);
158                     current_scope.set(
159                         gimli::DW_AT_ranges,
160                         write::AttributeValue::RangeListRef(range_list_id),
161                     );
162                 } else {
163                     let current_scope = out_unit.get_mut(current_scope_id);
164                     current_scope.set(
165                         gimli::DW_AT_low_pc,
166                         write::AttributeValue::Address(result[0].0),
167                     );
168                     current_scope.set(
169                         gimli::DW_AT_high_pc,
170                         write::AttributeValue::Udata(result[0].1),
171                     );
172                 }
173             }
174             RangeInfoBuilder::Function(index) => {
175                 let range = addr_tr.func_range(*index);
176                 let symbol = index.index();
177                 let addr = write::Address::Symbol {
178                     symbol,
179                     addend: range.0 as i64,
180                 };
181                 let len = (range.1 - range.0) as u64;
182                 let current_scope = out_unit.get_mut(current_scope_id);
183                 current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));
184                 current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len));
185             }
186         }
187     }
188 
189     pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> {
190         match self {
191             RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![],
192             RangeInfoBuilder::Ranges(ranges) => ranges.clone(),
193             RangeInfoBuilder::Function(index) => {
194                 let range = addr_tr.func_source_range(*index);
195                 vec![(range.0, range.1)]
196             }
197         }
198     }
199 
200     pub(crate) fn build_ranges(
201         &self,
202         addr_tr: &AddressTransform,
203         out_range_lists: &mut write::RangeListTable,
204     ) -> write::RangeListId {
205         if let RangeInfoBuilder::Ranges(ranges) = self {
206             let mut range_list = Vec::new();
207             for (begin, end) in ranges {
208                 assert!(begin < end);
209                 range_list.extend(addr_tr.translate_ranges(*begin, *end).map(|tr| {
210                     write::Range::StartLength {
211                         begin: tr.0,
212                         length: tr.1,
213                     }
214                 }));
215             }
216             out_range_lists.add(write::RangeList(range_list))
217         } else {
218             unreachable!();
219         }
220     }
221 }
222