wasmtime_cranelift/debug/
gc.rs1use crate::debug::transform::AddressTransform;
2use crate::debug::{Compilation, Reader};
3use gimli::constants;
4use gimli::read;
5use gimli::UnitSectionOffset;
6use std::collections::{HashMap, HashSet};
7use wasmtime_environ::{PrimaryMap, StaticModuleIndex};
8
9#[derive(Debug)]
10pub struct Dependencies {
11 edges: HashMap<UnitSectionOffset, HashSet<UnitSectionOffset>>,
12 roots: HashSet<UnitSectionOffset>,
13}
14
15impl Dependencies {
16 fn new() -> Dependencies {
17 Dependencies {
18 edges: HashMap::new(),
19 roots: HashSet::new(),
20 }
21 }
22
23 fn add_edge(&mut self, a: UnitSectionOffset, b: UnitSectionOffset) {
24 use std::collections::hash_map::Entry;
25 match self.edges.entry(a) {
26 Entry::Occupied(mut o) => {
27 o.get_mut().insert(b);
28 }
29 Entry::Vacant(v) => {
30 let mut set = HashSet::new();
31 set.insert(b);
32 v.insert(set);
33 }
34 }
35 }
36
37 fn add_root(&mut self, root: UnitSectionOffset) {
38 self.roots.insert(root);
39 }
40
41 pub fn get_reachable(&self) -> HashSet<UnitSectionOffset> {
42 let mut reachable = self.roots.clone();
43 let mut queue = Vec::new();
44 for i in self.roots.iter() {
45 if let Some(deps) = self.edges.get(i) {
46 for j in deps {
47 if reachable.contains(j) {
48 continue;
49 }
50 reachable.insert(*j);
51 queue.push(*j);
52 }
53 }
54 }
55 while let Some(i) = queue.pop() {
56 if let Some(deps) = self.edges.get(&i) {
57 for j in deps {
58 if reachable.contains(j) {
59 continue;
60 }
61 reachable.insert(*j);
62 queue.push(*j);
63 }
64 }
65 }
66 reachable
67 }
68}
69
70pub fn build_dependencies(
71 compilation: &mut Compilation<'_>,
72 dwp: &Option<read::DwarfPackage<Reader<'_>>>,
73 at: &PrimaryMap<StaticModuleIndex, AddressTransform>,
74) -> read::Result<Dependencies> {
75 let mut deps = Dependencies::new();
76 for (i, translation) in compilation.translations.iter() {
77 let dwarf = &translation.debuginfo.dwarf;
78 let mut units = dwarf.units();
79 while let Some(unit) = units.next()? {
80 build_unit_dependencies(unit, dwarf, dwp, &at[i], &mut deps)?;
81 }
82 }
83 Ok(deps)
84}
85
86fn build_unit_dependencies(
87 header: read::UnitHeader<Reader<'_>>,
88 dwarf: &read::Dwarf<Reader<'_>>,
89 dwp: &Option<read::DwarfPackage<Reader<'_>>>,
90 at: &AddressTransform,
91 deps: &mut Dependencies,
92) -> read::Result<()> {
93 let unit = dwarf.unit(header)?;
94 let mut tree = unit.entries_tree(None)?;
95 let root = tree.root()?;
96 build_die_dependencies(root, dwarf, &unit, at, deps)?;
97
98 if let Some(dwarf_package) = dwp {
99 if let Some(dwo_id) = unit.dwo_id {
100 if let Some(cu) = dwarf_package.find_cu(dwo_id, dwarf)? {
101 if let Some(unit_header) = cu.debug_info.units().next()? {
102 build_unit_dependencies(unit_header, &cu, &None, at, deps)?;
103 }
104 }
105 }
106 }
107
108 Ok(())
109}
110
111fn has_die_back_edge(die: &read::DebuggingInformationEntry<Reader<'_>>) -> read::Result<bool> {
112 let result = match die.tag() {
120 constants::DW_TAG_array_type
121 | constants::DW_TAG_atomic_type
122 | constants::DW_TAG_base_type
123 | constants::DW_TAG_class_type
124 | constants::DW_TAG_const_type
125 | constants::DW_TAG_dwarf_procedure
126 | constants::DW_TAG_entry_point
127 | constants::DW_TAG_enumeration_type
128 | constants::DW_TAG_pointer_type
129 | constants::DW_TAG_ptr_to_member_type
130 | constants::DW_TAG_reference_type
131 | constants::DW_TAG_restrict_type
132 | constants::DW_TAG_rvalue_reference_type
133 | constants::DW_TAG_string_type
134 | constants::DW_TAG_structure_type
135 | constants::DW_TAG_typedef
136 | constants::DW_TAG_union_type
137 | constants::DW_TAG_unspecified_type
138 | constants::DW_TAG_volatile_type
139 | constants::DW_TAG_coarray_type
140 | constants::DW_TAG_common_block
141 | constants::DW_TAG_dynamic_type
142 | constants::DW_TAG_file_type
143 | constants::DW_TAG_immutable_type
144 | constants::DW_TAG_interface_type
145 | constants::DW_TAG_set_type
146 | constants::DW_TAG_shared_type
147 | constants::DW_TAG_subroutine_type
148 | constants::DW_TAG_packed_type
149 | constants::DW_TAG_template_alias
150 | constants::DW_TAG_namelist
151 | constants::DW_TAG_namespace
152 | constants::DW_TAG_imported_unit
153 | constants::DW_TAG_imported_declaration
154 | constants::DW_TAG_imported_module
155 | constants::DW_TAG_module => false,
156 constants::DW_TAG_subprogram => die.attr(constants::DW_AT_declaration)?.is_some(),
157 _ => true,
158 };
159 Ok(result)
160}
161
162fn has_valid_code_range(
163 die: &read::DebuggingInformationEntry<Reader<'_>>,
164 dwarf: &read::Dwarf<Reader<'_>>,
165 unit: &read::Unit<Reader<'_>>,
166 at: &AddressTransform,
167) -> read::Result<bool> {
168 match die.tag() {
169 constants::DW_TAG_subprogram => {
170 if let Some(ranges_attr) = die.attr_value(constants::DW_AT_ranges)? {
171 let offset = match ranges_attr {
172 read::AttributeValue::RangeListsRef(val) => {
173 dwarf.ranges_offset_from_raw(unit, val)
174 }
175 read::AttributeValue::DebugRngListsIndex(index) => {
176 dwarf.ranges_offset(unit, index)?
177 }
178 _ => return Ok(false),
179 };
180 let mut has_valid_base = if let Some(read::AttributeValue::Addr(low_pc)) =
181 die.attr_value(constants::DW_AT_low_pc)?
182 {
183 Some(at.can_translate_address(low_pc))
184 } else {
185 None
186 };
187 let mut it = dwarf.ranges.raw_ranges(offset, unit.encoding())?;
188 while let Some(range) = it.next()? {
189 match range {
192 read::RawRngListEntry::AddressOrOffsetPair { .. }
193 if has_valid_base.is_some() =>
194 {
195 if has_valid_base.unwrap() {
196 return Ok(true);
197 }
198 }
199 read::RawRngListEntry::StartEnd { begin, .. }
200 | read::RawRngListEntry::StartLength { begin, .. }
201 | read::RawRngListEntry::AddressOrOffsetPair { begin, .. } => {
202 if at.can_translate_address(begin) {
203 return Ok(true);
204 }
205 }
206 read::RawRngListEntry::StartxEndx { begin, .. }
207 | read::RawRngListEntry::StartxLength { begin, .. } => {
208 let addr = dwarf.address(unit, begin)?;
209 if at.can_translate_address(addr) {
210 return Ok(true);
211 }
212 }
213 read::RawRngListEntry::BaseAddress { addr } => {
214 has_valid_base = Some(at.can_translate_address(addr));
215 }
216 read::RawRngListEntry::BaseAddressx { addr } => {
217 let addr = dwarf.address(unit, addr)?;
218 has_valid_base = Some(at.can_translate_address(addr));
219 }
220 read::RawRngListEntry::OffsetPair { .. } => (),
221 }
222 }
223 return Ok(false);
224 } else if let Some(low_pc) = die.attr_value(constants::DW_AT_low_pc)? {
225 if let read::AttributeValue::Addr(a) = low_pc {
226 return Ok(at.can_translate_address(a));
227 } else if let read::AttributeValue::DebugAddrIndex(i) = low_pc {
228 let a = dwarf.debug_addr.get_address(4, unit.addr_base, i)?;
229 return Ok(at.can_translate_address(a));
230 }
231 }
232 }
233 _ => (),
234 }
235 Ok(false)
236}
237
238fn build_die_dependencies(
239 die: read::EntriesTreeNode<Reader<'_>>,
240 dwarf: &read::Dwarf<Reader<'_>>,
241 unit: &read::Unit<Reader<'_>>,
242 at: &AddressTransform,
243 deps: &mut Dependencies,
244) -> read::Result<()> {
245 let entry = die.entry();
246 let offset = entry.offset().to_unit_section_offset(unit);
247 let mut attrs = entry.attrs();
248 while let Some(attr) = attrs.next()? {
249 build_attr_dependencies(&attr, offset, dwarf, unit, at, deps)?;
250 }
251
252 let mut children = die.children();
253 while let Some(child) = children.next()? {
254 let child_entry = child.entry();
255 let child_offset = child_entry.offset().to_unit_section_offset(unit);
256 deps.add_edge(child_offset, offset);
257 if has_die_back_edge(child_entry)? {
258 deps.add_edge(offset, child_offset);
259 }
260 if has_valid_code_range(child_entry, dwarf, unit, at)? {
261 deps.add_root(child_offset);
262 }
263 build_die_dependencies(child, dwarf, unit, at, deps)?;
264 }
265 Ok(())
266}
267
268fn build_attr_dependencies(
269 attr: &read::Attribute<Reader<'_>>,
270 offset: UnitSectionOffset,
271 _dwarf: &read::Dwarf<Reader<'_>>,
272 unit: &read::Unit<Reader<'_>>,
273 _at: &AddressTransform,
274 deps: &mut Dependencies,
275) -> read::Result<()> {
276 match attr.value() {
277 read::AttributeValue::UnitRef(val) => {
278 let ref_offset = val.to_unit_section_offset(unit);
279 deps.add_edge(offset, ref_offset);
280 }
281 read::AttributeValue::DebugInfoRef(val) => {
282 let ref_offset = UnitSectionOffset::DebugInfoOffset(val);
283 deps.add_edge(offset, ref_offset);
284 }
285 _ => (),
286 }
287 Ok(())
288}