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