rudy_dwarf/address/mod.rs
1mod resolution;
2
3use std::fmt;
4
5pub(crate) use resolution::{address_to_location, location_to_address};
6
7use crate::file::DebugFile;
8
9#[derive(Clone, PartialEq, Eq, Hash)]
10pub struct FunctionAddressInfo {
11 /// The start address of the function
12 ///
13 /// These are absolute addresses in the binary, not relative to any debug file.
14 pub absolute_start: u64,
15 pub absolute_end: u64,
16
17 /// The relative start address of the function within the debug file
18 pub relative_start: u64,
19 pub relative_end: u64,
20 pub file: DebugFile,
21 pub name: crate::SymbolName,
22}
23
24impl fmt::Debug for FunctionAddressInfo {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 salsa::with_attached_database(|db| {
27 let file_path = self.file.file(db).path(db);
28 f.debug_struct("FunctionAddressInfo")
29 .field("absolute_start", &self.absolute_start)
30 .field("absolute_end", &self.absolute_end)
31 .field("relative_start", &self.relative_start)
32 .field("relative_end", &self.relative_end)
33 .field("file", &file_path)
34 .field("name", &self.name)
35 .finish()
36 })
37 .unwrap_or_else(|| {
38 f.debug_struct("FunctionAddressInfo")
39 .field("absolute_start", &self.absolute_start)
40 .field("absolute_end", &self.absolute_end)
41 .field("relative_start", &self.relative_start)
42 .field("relative_end", &self.relative_end)
43 .finish()
44 })
45 }
46}
47
48impl FunctionAddressInfo {}
49
50// Define the Node for the Interval Tree
51#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52struct Node {
53 info: FunctionAddressInfo,
54 start: u64, // Start of the function's address range
55 end: u64, // End of the function's address range
56 max_end_in_subtree: u64, // Maximum endpoint in the subtree rooted at this node
57 left: Option<Box<Node>>,
58 right: Option<Box<Node>>,
59}
60
61impl Node {
62 fn new(info: FunctionAddressInfo, absolute: bool) -> Self {
63 let (start, end) = if absolute {
64 (info.absolute_start, info.absolute_end)
65 } else {
66 (info.relative_start, info.relative_end)
67 };
68
69 Node {
70 start,
71 end,
72 max_end_in_subtree: end,
73 info,
74 left: None,
75 right: None,
76 }
77 }
78
79 fn contains_address(&self, address: u64) -> bool {
80 address >= self.start && address < self.end
81 }
82
83 fn overlaps(&self, start: u64, end: u64) -> bool {
84 // Check if the current function's range overlaps with the query range
85 self.start < end && start < self.end
86 }
87
88 fn update_max_end(&mut self) {
89 self.max_end_in_subtree = self.end;
90 if let Some(ref left_child) = self.left {
91 self.max_end_in_subtree =
92 std::cmp::max(self.max_end_in_subtree, left_child.max_end_in_subtree);
93 }
94 if let Some(ref right_child) = self.right {
95 self.max_end_in_subtree =
96 std::cmp::max(self.max_end_in_subtree, right_child.max_end_in_subtree);
97 }
98 }
99}
100
101#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
102pub struct AddressTree {
103 absolute_root: Option<Box<Node>>,
104 relative_root: Option<Box<Node>>,
105}
106
107impl AddressTree {
108 pub fn new(mut info: Vec<FunctionAddressInfo>) -> Self {
109 /// Recursive helper function to build the tree from a sorted slice of addresses.
110 fn build_recursive(
111 sorted_ranges: &[FunctionAddressInfo],
112 absolute: bool,
113 ) -> Option<Box<Node>> {
114 if sorted_ranges.is_empty() {
115 return None;
116 }
117
118 let mid_idx = sorted_ranges.len() / 2;
119 let median_range = sorted_ranges[mid_idx].clone(); // This range becomes the root
120
121 let mut node = Box::new(Node::new(median_range, absolute));
122
123 // Recursively build the left subtree from the part of the slice to the left of the median
124 node.left = build_recursive(&sorted_ranges[0..mid_idx], absolute);
125
126 // Recursively build the right subtree from the part of the slice to the right of the median
127 node.right = build_recursive(&sorted_ranges[mid_idx + 1..], absolute);
128
129 // Update the max_end_in_subtree for the current node after its children are built
130 node.update_max_end();
131
132 Some(node)
133 }
134
135 if info.is_empty() {
136 return AddressTree::default();
137 }
138
139 info.sort_unstable_by_key(|i| i.absolute_start); // Sort intervals by start point
140
141 let absolute_root = build_recursive(&info, true);
142
143 info.sort_unstable_by_key(|i| i.relative_start); // Sort intervals by relative start point
144 let relative_root = build_recursive(&info, false);
145 AddressTree {
146 absolute_root,
147 relative_root,
148 }
149 }
150
151 /// Finds all functions in the tree that contain the given address.
152 pub fn query_address(&self, address: u64, absolute: bool) -> Vec<&FunctionAddressInfo> {
153 let mut result = Vec::new();
154 if absolute {
155 if let Some(ref root_node) = self.absolute_root {
156 Self::query_address_recursive(root_node, address, &mut result);
157 }
158 } else if let Some(ref root_node) = self.relative_root {
159 Self::query_address_recursive(root_node, address, &mut result);
160 }
161
162 if result.is_empty() {
163 tracing::debug!("No function found for address {address} in {self:#?}");
164 }
165
166 result
167 }
168
169 fn query_address_recursive<'a>(
170 node: &'a Node,
171 address: u64,
172 result: &mut Vec<&'a FunctionAddressInfo>,
173 ) {
174 // 1. Check if the address is contained in the current node's range
175 if node.contains_address(address) {
176 result.push(&node.info);
177 }
178
179 // 2. Check left child:
180 // The point must be less than or equal to the max_end in the left subtree
181 // AND (for this simple BST-like insertion based on start point) the point
182 // could potentially be in an interval starting to its left.
183 if let Some(ref left_child) = node.left {
184 // Pruning: if the query point is beyond the maximum reach of the left subtree, don't go there.
185 if address <= left_child.max_end_in_subtree {
186 // Crucial pruning step
187 Self::query_address_recursive(left_child, address, result);
188 }
189 }
190
191 // 3. Check right child:
192 // The point must be greater than or equal to the start of the current node's interval
193 // (because intervals in the right subtree start at or after the current node's interval start).
194 // AND the point must be less than or equal to the max_end in the right subtree.
195 //
196 // For point queries, the `max_end_in_subtree` check is still useful.
197 // If the point is less than the start of an interval, it cannot be contained.
198 if let Some(ref right_child) = node.right {
199 // Pruning: if the query point is beyond the maximum reach of the right subtree, don't go there.
200 if address <= right_child.max_end_in_subtree && address >= node.start {
201 // The second condition (point >= node.info.start) is because our insertion
202 // puts smaller start times to the left. If the point is smaller than the
203 // current node's interval's start, it won't be in the right subtree intervals
204 // which all have starts >= current node's interval start.
205 // However, for point query, the primary condition is `point <= right_child.max_end_in_subtree`.
206 // Let's refine the condition for going right.
207 // We go right if the point *could* be in an interval there.
208 // An interval [s,e] in the right subtree has s >= node.info.start.
209 // So if point < node.info.start, it can't be in any interval in the right subtree.
210 // Combined with max_end_in_subtree:
211 if address >= node.start || address <= right_child.max_end_in_subtree {
212 // The check `point >= node.info.start` is more about interval overlap queries.
213 // For a point query, if point > node.info.start, it *might* be in the right.
214 // If point < node.info.start, it *might* still be in the right if an interval there
215 // starts small but extends far.
216 // The crucial pruning is max_end_in_subtree.
217 // If point > right_child.max_end_in_subtree, no interval in the right child can contain it.
218 //
219 // Let's simplify the traversal logic for point query:
220 // If the node's interval's start point is to the left of or at the query point,
221 // and the max_end_in_subtree of the right child extends to or past the query point,
222 // then the query point *could* be in an interval in the right subtree.
223 if address <= right_child.max_end_in_subtree {
224 // Check if we even need to go right
225 Self::query_address_recursive(right_child, address, result);
226 }
227 }
228 }
229 }
230 }
231
232 #[allow(dead_code)]
233 /// Finds all functions in the tree that overlap with the given address range.
234 pub fn query_address_range(
235 &self,
236 query_start: u64,
237 query_end: u64,
238 absolute: bool,
239 ) -> Vec<&FunctionAddressInfo> {
240 let mut result = Vec::new();
241 if absolute {
242 if let Some(ref root_node) = self.absolute_root {
243 Self::query_interval_recursive(root_node, query_start, query_end, &mut result);
244 }
245 } else if let Some(ref root_node) = self.relative_root {
246 Self::query_interval_recursive(root_node, query_start, query_end, &mut result);
247 }
248 result
249 }
250
251 fn query_interval_recursive<'a>(
252 node: &'a Node,
253 query_start: u64,
254 query_end: u64,
255 result: &mut Vec<&'a FunctionAddressInfo>,
256 ) {
257 // 1. Check if current node overlaps with the query range
258 if node.overlaps(query_start, query_end) {
259 result.push(&node.info);
260 }
261
262 // 2. If left child exists and its max_end_in_subtree overlaps the query_start
263 if let Some(ref left_child) = node.left {
264 if left_child.max_end_in_subtree >= query_start {
265 Self::query_interval_recursive(left_child, query_start, query_end, result);
266 }
267 }
268
269 // 3. If right child exists and the current node's interval starts before query_end
270 // and the right child's max_end_in_subtree is relevant
271 if let Some(ref right_child) = node.right {
272 // The query interval must potentially overlap with intervals in the right subtree.
273 // Intervals in the right subtree start at or after node.start.
274 // The query must extend to or past node.start.
275 // And the query must not end before any interval in the right subtree could start.
276 if node.start <= query_end && // Current node's interval allows going right
277 right_child.max_end_in_subtree >= query_start
278 // Right subtree might contain an overlap
279 {
280 Self::query_interval_recursive(right_child, query_start, query_end, result);
281 }
282 }
283 }
284}