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