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 by_addr(&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 #[must_use]
84 pub fn by_name(&self, name: &str) -> Option<&Module> {
85 self.0.iter().find(|module| module.name == name)
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn basics() {
95 let modules = Modules::new(vec![
96 Module::new("foo".to_string(), 0x1_000, 0x2_000),
97 Module::new("foobar".to_string(), 0x2_000, 0x3_000),
98 Module::new("bar".to_string(), 0x4_000, 0x5_000),
99 ]);
100
101 assert!(modules.by_addr(1).is_none());
102 assert_eq!(modules.by_addr(0x1_000).unwrap().name, "foo");
103 assert_eq!(modules.by_name("foo").unwrap().at.start, 0x1_000);
104 assert_eq!(modules.by_addr(0x2_000).unwrap().name, "foobar");
106 assert_eq!(modules.by_name("foobar").unwrap().at.start, 0x2_000);
107 assert!(modules.by_addr(0x3_000).is_none());
109 assert!(modules.by_name("bleh").is_none());
110 assert_eq!(modules.by_addr(0x4_fff).unwrap().name, "bar");
111 assert_eq!(modules.by_name("bar").unwrap().at.start, 0x4_000);
112 assert!(modules.by_addr(0x6_000).is_none());
113 }
114}