wasmtime_cranelift/debug/transform/
range_info_builder.rs1use super::address_transform::AddressTransform;
2use super::{DebugInputContext, Reader};
3use anyhow::Error;
4use gimli::{write, AttributeValue, DebuggingInformationEntry, RangeListsOffset, Unit};
5use wasmtime_environ::{DefinedFuncIndex, EntityRef};
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 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 }
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}