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