1 use crate::transform::AddressTransform;
2 use gimli::constants;
3 use gimli::read;
4 use gimli::{Reader, UnitSectionOffset};
5 use std::collections::{HashMap, HashSet};
6
7 #[derive(Debug)]
8 pub struct Dependencies {
9 edges: HashMap<UnitSectionOffset, HashSet<UnitSectionOffset>>,
10 roots: HashSet<UnitSectionOffset>,
11 }
12
13 impl Dependencies {
new() -> Dependencies14 fn new() -> Dependencies {
15 Dependencies {
16 edges: HashMap::new(),
17 roots: HashSet::new(),
18 }
19 }
20
add_edge(&mut self, a: UnitSectionOffset, b: UnitSectionOffset)21 fn add_edge(&mut self, a: UnitSectionOffset, b: UnitSectionOffset) {
22 use std::collections::hash_map::Entry;
23 match self.edges.entry(a) {
24 Entry::Occupied(mut o) => {
25 o.get_mut().insert(b);
26 }
27 Entry::Vacant(v) => {
28 let mut set = HashSet::new();
29 set.insert(b);
30 v.insert(set);
31 }
32 }
33 }
34
add_root(&mut self, root: UnitSectionOffset)35 fn add_root(&mut self, root: UnitSectionOffset) {
36 self.roots.insert(root);
37 }
38
get_reachable(&self) -> HashSet<UnitSectionOffset>39 pub fn get_reachable(&self) -> HashSet<UnitSectionOffset> {
40 let mut reachable = self.roots.clone();
41 let mut queue = Vec::new();
42 for i in self.roots.iter() {
43 if let Some(deps) = self.edges.get(i) {
44 for j in deps {
45 if reachable.contains(j) {
46 continue;
47 }
48 reachable.insert(*j);
49 queue.push(*j);
50 }
51 }
52 }
53 while let Some(i) = queue.pop() {
54 if let Some(deps) = self.edges.get(&i) {
55 for j in deps {
56 if reachable.contains(j) {
57 continue;
58 }
59 reachable.insert(*j);
60 queue.push(*j);
61 }
62 }
63 }
64 reachable
65 }
66 }
67
build_dependencies<R: Reader<Offset = usize>>( dwarf: &read::Dwarf<R>, at: &AddressTransform, ) -> read::Result<Dependencies>68 pub fn build_dependencies<R: Reader<Offset = usize>>(
69 dwarf: &read::Dwarf<R>,
70 at: &AddressTransform,
71 ) -> read::Result<Dependencies> {
72 let mut deps = Dependencies::new();
73 let mut units = dwarf.units();
74 while let Some(unit) = units.next()? {
75 build_unit_dependencies(unit, dwarf, at, &mut deps)?;
76 }
77 Ok(deps)
78 }
79
build_unit_dependencies<R: Reader<Offset = usize>>( header: read::CompilationUnitHeader<R>, dwarf: &read::Dwarf<R>, at: &AddressTransform, deps: &mut Dependencies, ) -> read::Result<()>80 fn build_unit_dependencies<R: Reader<Offset = usize>>(
81 header: read::CompilationUnitHeader<R>,
82 dwarf: &read::Dwarf<R>,
83 at: &AddressTransform,
84 deps: &mut Dependencies,
85 ) -> read::Result<()> {
86 let unit = dwarf.unit(header)?;
87 let mut tree = unit.entries_tree(None)?;
88 let root = tree.root()?;
89 build_die_dependencies(root, dwarf, &unit, at, deps)?;
90 Ok(())
91 }
92
has_die_back_edge<R: Reader<Offset = usize>>(die: &read::DebuggingInformationEntry<R>) -> bool93 fn has_die_back_edge<R: Reader<Offset = usize>>(die: &read::DebuggingInformationEntry<R>) -> bool {
94 match die.tag() {
95 constants::DW_TAG_variable
96 | constants::DW_TAG_constant
97 | constants::DW_TAG_inlined_subroutine
98 | constants::DW_TAG_lexical_block
99 | constants::DW_TAG_label
100 | constants::DW_TAG_with_stmt
101 | constants::DW_TAG_try_block
102 | constants::DW_TAG_catch_block
103 | constants::DW_TAG_template_type_parameter
104 | constants::DW_TAG_member
105 | constants::DW_TAG_formal_parameter => true,
106 _ => false,
107 }
108 }
109
has_valid_code_range<R: Reader<Offset = usize>>( die: &read::DebuggingInformationEntry<R>, dwarf: &read::Dwarf<R>, unit: &read::Unit<R>, at: &AddressTransform, ) -> read::Result<bool>110 fn has_valid_code_range<R: Reader<Offset = usize>>(
111 die: &read::DebuggingInformationEntry<R>,
112 dwarf: &read::Dwarf<R>,
113 unit: &read::Unit<R>,
114 at: &AddressTransform,
115 ) -> read::Result<bool> {
116 match die.tag() {
117 constants::DW_TAG_subprogram => {
118 if let Some(ranges_attr) = die.attr_value(constants::DW_AT_ranges)? {
119 let offset = match ranges_attr {
120 read::AttributeValue::RangeListsRef(val) => val,
121 read::AttributeValue::DebugRngListsIndex(index) => {
122 dwarf.ranges_offset(unit, index)?
123 }
124 _ => return Ok(false),
125 };
126 let mut has_valid_base = if let Some(read::AttributeValue::Addr(low_pc)) =
127 die.attr_value(constants::DW_AT_low_pc)?
128 {
129 Some(at.can_translate_address(low_pc))
130 } else {
131 None
132 };
133 let mut it = dwarf.ranges.raw_ranges(offset, unit.encoding())?;
134 while let Some(range) = it.next()? {
135 // If at least one of the range addresses can be converted,
136 // declaring code range as valid.
137 match range {
138 read::RawRngListEntry::AddressOrOffsetPair { .. }
139 if has_valid_base.is_some() =>
140 {
141 if has_valid_base.unwrap() {
142 return Ok(true);
143 }
144 }
145 read::RawRngListEntry::StartEnd { begin, .. }
146 | read::RawRngListEntry::StartLength { begin, .. }
147 | read::RawRngListEntry::AddressOrOffsetPair { begin, .. } => {
148 if at.can_translate_address(begin) {
149 return Ok(true);
150 }
151 }
152 read::RawRngListEntry::StartxEndx { begin, .. }
153 | read::RawRngListEntry::StartxLength { begin, .. } => {
154 let addr = dwarf.address(unit, begin)?;
155 if at.can_translate_address(addr) {
156 return Ok(true);
157 }
158 }
159 read::RawRngListEntry::BaseAddress { addr } => {
160 has_valid_base = Some(at.can_translate_address(addr));
161 }
162 read::RawRngListEntry::BaseAddressx { addr } => {
163 let addr = dwarf.address(unit, addr)?;
164 has_valid_base = Some(at.can_translate_address(addr));
165 }
166 read::RawRngListEntry::OffsetPair { .. } => (),
167 }
168 }
169 return Ok(false);
170 } else if let Some(low_pc) = die.attr_value(constants::DW_AT_low_pc)? {
171 if let read::AttributeValue::Addr(a) = low_pc {
172 return Ok(at.can_translate_address(a));
173 } else if let read::AttributeValue::DebugAddrIndex(i) = low_pc {
174 let a = dwarf.debug_addr.get_address(4, unit.addr_base, i)?;
175 return Ok(at.can_translate_address(a));
176 }
177 }
178 }
179 _ => (),
180 }
181 Ok(false)
182 }
183
build_die_dependencies<R: Reader<Offset = usize>>( die: read::EntriesTreeNode<R>, dwarf: &read::Dwarf<R>, unit: &read::Unit<R>, at: &AddressTransform, deps: &mut Dependencies, ) -> read::Result<()>184 fn build_die_dependencies<R: Reader<Offset = usize>>(
185 die: read::EntriesTreeNode<R>,
186 dwarf: &read::Dwarf<R>,
187 unit: &read::Unit<R>,
188 at: &AddressTransform,
189 deps: &mut Dependencies,
190 ) -> read::Result<()> {
191 let entry = die.entry();
192 let offset = entry.offset().to_unit_section_offset(unit);
193 let mut attrs = entry.attrs();
194 while let Some(attr) = attrs.next()? {
195 build_attr_dependencies(&attr, offset, dwarf, unit, at, deps)?;
196 }
197
198 let mut children = die.children();
199 while let Some(child) = children.next()? {
200 let child_entry = child.entry();
201 let child_offset = child_entry.offset().to_unit_section_offset(unit);
202 deps.add_edge(child_offset, offset);
203 if has_die_back_edge(child_entry) {
204 deps.add_edge(offset, child_offset);
205 }
206 if has_valid_code_range(child_entry, dwarf, unit, at)? {
207 deps.add_root(child_offset);
208 }
209 build_die_dependencies(child, dwarf, unit, at, deps)?;
210 }
211 Ok(())
212 }
213
build_attr_dependencies<R: Reader<Offset = usize>>( attr: &read::Attribute<R>, offset: UnitSectionOffset, _dwarf: &read::Dwarf<R>, unit: &read::Unit<R>, _at: &AddressTransform, deps: &mut Dependencies, ) -> read::Result<()>214 fn build_attr_dependencies<R: Reader<Offset = usize>>(
215 attr: &read::Attribute<R>,
216 offset: UnitSectionOffset,
217 _dwarf: &read::Dwarf<R>,
218 unit: &read::Unit<R>,
219 _at: &AddressTransform,
220 deps: &mut Dependencies,
221 ) -> read::Result<()> {
222 match attr.value() {
223 read::AttributeValue::UnitRef(val) => {
224 let ref_offset = val.to_unit_section_offset(unit);
225 deps.add_edge(offset, ref_offset);
226 }
227 read::AttributeValue::DebugInfoRef(val) => {
228 let ref_offset = UnitSectionOffset::DebugInfoOffset(val);
229 deps.add_edge(offset, ref_offset);
230 }
231 _ => (),
232 }
233 Ok(())
234 }
235