1 use super::address_transform::AddressTransform;
2 use crate::debug::Reader;
3 use gimli::{AttributeValue, RangeListsOffset, UnitRef, write};
4 use wasmtime_environ::DefinedFuncIndex;
5 use wasmtime_environ::error::Error;
6 
7 pub(crate) enum RangeInfoBuilder {
8     Undefined,
9     Position(u64),
10     Ranges(Vec<(u64, u64)>),
11     Function(DefinedFuncIndex),
12 }
13 
14 impl RangeInfoBuilder {
from(entry: &write::ConvertUnitEntry<Reader<'_>>) -> Result<Self, Error>15     pub(crate) fn from(entry: &write::ConvertUnitEntry<Reader<'_>>) -> Result<Self, Error> {
16         if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges) {
17             let r = entry.read_unit.ranges_offset_from_raw(r);
18             return RangeInfoBuilder::from_ranges_ref(entry.read_unit, r);
19         };
20 
21         let low_pc = if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)
22         {
23             addr
24         } else if let Some(AttributeValue::DebugAddrIndex(i)) =
25             entry.attr_value(gimli::DW_AT_low_pc)
26         {
27             entry.read_unit.address(i)?
28         } else {
29             return Ok(RangeInfoBuilder::Undefined);
30         };
31 
32         Ok(
33             if let Some(AttributeValue::Udata(u)) = entry.attr_value(gimli::DW_AT_high_pc) {
34                 RangeInfoBuilder::Ranges(vec![(low_pc, low_pc + u)])
35             } else {
36                 RangeInfoBuilder::Position(low_pc)
37             },
38         )
39     }
40 
from_ranges_ref( unit: UnitRef<'_, Reader<'_>>, ranges: RangeListsOffset, ) -> Result<Self, Error>41     pub(crate) fn from_ranges_ref(
42         unit: UnitRef<'_, Reader<'_>>,
43         ranges: RangeListsOffset,
44     ) -> Result<Self, Error> {
45         let mut ranges = unit.ranges(ranges)?;
46         let mut result = Vec::new();
47         while let Some(range) = ranges.next()? {
48             if range.begin >= range.end {
49                 // ignore empty ranges
50             }
51             result.push((range.begin, range.end));
52         }
53 
54         Ok(if result.is_empty() {
55             RangeInfoBuilder::Undefined
56         } else {
57             RangeInfoBuilder::Ranges(result)
58         })
59     }
60 
from_subprogram_die( entry: &write::ConvertUnitEntry<Reader<'_>>, addr_tr: &AddressTransform, ) -> Result<Self, Error>61     pub(crate) fn from_subprogram_die(
62         entry: &write::ConvertUnitEntry<Reader<'_>>,
63         addr_tr: &AddressTransform,
64     ) -> Result<Self, Error> {
65         let unit = entry.read_unit;
66         let addr = if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc) {
67             addr
68         } else if let Some(AttributeValue::DebugAddrIndex(i)) =
69             entry.attr_value(gimli::DW_AT_low_pc)
70         {
71             unit.address(i)?
72         } else if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges)
73         {
74             let r = unit.ranges_offset_from_raw(r);
75             let mut ranges = unit.ranges(r)?;
76             if let Some(range) = ranges.next()? {
77                 range.begin
78             } else {
79                 return Ok(RangeInfoBuilder::Undefined);
80             }
81         } else {
82             return Ok(RangeInfoBuilder::Undefined);
83         };
84 
85         let index = addr_tr.find_func_index(addr);
86         if index.is_none() {
87             return Ok(RangeInfoBuilder::Undefined);
88         }
89         Ok(RangeInfoBuilder::Function(index.unwrap()))
90     }
91 
build( &self, addr_tr: &AddressTransform, out_unit: &mut write::Unit, current_scope_id: write::UnitEntryId, )92     pub(crate) fn build(
93         &self,
94         addr_tr: &AddressTransform,
95         out_unit: &mut write::Unit,
96         current_scope_id: write::UnitEntryId,
97     ) {
98         match self {
99             RangeInfoBuilder::Undefined => (),
100             RangeInfoBuilder::Position(pc) => {
101                 let addr = addr_tr
102                     .translate(*pc)
103                     .unwrap_or(write::Address::Constant(0));
104                 let current_scope = out_unit.get_mut(current_scope_id);
105                 current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));
106             }
107             RangeInfoBuilder::Ranges(ranges) => {
108                 let mut result = Vec::new();
109                 for (begin, end) in ranges {
110                     result.extend(addr_tr.translate_ranges(*begin, *end));
111                 }
112 
113                 // If we're seeing the ranges for a `DW_TAG_compile_unit` DIE
114                 // then don't use `DW_AT_low_pc` and `DW_AT_high_pc`. These
115                 // attributes, if set, will configure the base address of all
116                 // location lists that this unit refers to. Currently this
117                 // debug transform does not take this base address into account
118                 // when generate the `.debug_loc` section. Consequently when a
119                 // compile unit is configured here the `DW_AT_ranges` attribute
120                 // is unconditionally used instead of
121                 // `DW_AT_low_pc`/`DW_AT_high_pc`.
122                 let is_attr_for_compile_unit =
123                     out_unit.get(current_scope_id).tag() == gimli::DW_TAG_compile_unit;
124 
125                 if result.len() != 1 || is_attr_for_compile_unit {
126                     let range_list = result
127                         .iter()
128                         .map(|tr| write::Range::StartLength {
129                             begin: tr.0,
130                             length: tr.1,
131                         })
132                         .collect::<Vec<_>>();
133                     let range_list_id = out_unit.ranges.add(write::RangeList(range_list));
134                     let current_scope = out_unit.get_mut(current_scope_id);
135                     current_scope.set(
136                         gimli::DW_AT_ranges,
137                         write::AttributeValue::RangeListRef(range_list_id),
138                     );
139                 } else {
140                     let current_scope = out_unit.get_mut(current_scope_id);
141                     current_scope.set(
142                         gimli::DW_AT_low_pc,
143                         write::AttributeValue::Address(result[0].0),
144                     );
145                     current_scope.set(
146                         gimli::DW_AT_high_pc,
147                         write::AttributeValue::Udata(result[0].1),
148                     );
149                 }
150             }
151             RangeInfoBuilder::Function(index) => {
152                 let symbol = addr_tr.map()[*index].symbol;
153                 let range = addr_tr.func_range(*index);
154                 let addr = write::Address::Symbol {
155                     symbol,
156                     addend: range.0 as i64,
157                 };
158                 let len = (range.1 - range.0) as u64;
159                 let current_scope = out_unit.get_mut(current_scope_id);
160                 current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));
161                 current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len));
162             }
163         }
164     }
165 
get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)>166     pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> {
167         match self {
168             RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![],
169             RangeInfoBuilder::Ranges(ranges) => ranges.clone(),
170             RangeInfoBuilder::Function(index) => {
171                 let range = addr_tr.func_source_range(*index);
172                 vec![(range.0, range.1)]
173             }
174         }
175     }
176 
build_ranges( &self, addr_tr: &AddressTransform, out_range_lists: &mut write::RangeListTable, ) -> write::RangeListId177     pub(crate) fn build_ranges(
178         &self,
179         addr_tr: &AddressTransform,
180         out_range_lists: &mut write::RangeListTable,
181     ) -> write::RangeListId {
182         if let RangeInfoBuilder::Ranges(ranges) = self {
183             let mut range_list = Vec::new();
184             for (begin, end) in ranges {
185                 assert!(begin < end);
186                 range_list.extend(addr_tr.translate_ranges(*begin, *end).map(|tr| {
187                     write::Range::StartLength {
188                         begin: tr.0,
189                         length: tr.1,
190                     }
191                 }));
192             }
193             out_range_lists.add(write::RangeList(range_list))
194         } else {
195             unreachable!();
196         }
197     }
198 }
199