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}