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