addr_symbolizer/
modules.rs1use std::ops::Range;
5
6use crate::misc::Rva;
7
8#[derive(Debug, Default, Clone)]
10pub struct Module {
11 pub at: Range<u64>,
13 pub name: String,
15}
16
17impl Module {
18 pub fn new(name: impl Into<String>, start: u64, end: u64) -> Self {
20 Module {
21 name: name.into(),
22 at: start..end,
23 }
24 }
25
26 #[expect(clippy::cast_possible_truncation)]
28 #[must_use]
29 pub fn rva(&self, addr: u64) -> Rva {
30 debug_assert!(self.at.contains(&addr));
31
32 let offset = addr - self.at.start;
33 assert!(offset <= u32::MAX.into());
34
35 offset as Rva
36 }
37}
38
39#[derive(Debug, Default)]
41pub struct Modules(Vec<Module>);
42
43impl Modules {
44 #[must_use]
46 pub fn new(mut modules: Vec<Module>) -> Self {
47 modules.sort_unstable_by_key(|e| e.at.end);
49
50 Self(modules)
51 }
52
53 #[must_use]
55 pub fn find(&self, addr: u64) -> Option<&Module> {
56 let idx = self.0.partition_point(|m| m.at.end <= addr);
58
59 if idx == self.0.len() {
65 return None;
66 }
67
68 let module = &self.0[idx];
72
73 if module.at.contains(&addr) {
76 Some(module)
77 } else {
78 None
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn basics() {
89 let modules = Modules::new(vec![
90 Module::new("foo".to_string(), 0x1_000, 0x2_000),
91 Module::new("foobar".to_string(), 0x2_000, 0x3_000),
92 Module::new("bar".to_string(), 0x4_000, 0x5_000),
93 ]);
94
95 assert!(modules.find(1).is_none());
96 assert_eq!(modules.find(0x1_000).unwrap().name, "foo");
97 assert_eq!(modules.find(0x2_000).unwrap().name, "foobar");
98 assert!(modules.find(0x3_000).is_none());
99 assert_eq!(modules.find(0x4_fff).unwrap().name, "bar");
100 assert!(modules.find(0x6_000).is_none());
101 }
102}