fxprof_processed_profile/lib_mappings.rs
1/// Keeps track of mapped libraries in an address space. Stores a value
2/// for each mapping, and allows efficient lookup of that value based on
3/// an address.
4#[derive(Debug, Clone)]
5pub struct LibMappings<T> {
6 sorted_mappings: Vec<Mapping<T>>,
7}
8
9impl<T> Default for LibMappings<T> {
10 fn default() -> Self {
11 Self::new()
12 }
13}
14
15impl<T> LibMappings<T> {
16 /// Creates a new empty instance.
17 pub fn new() -> Self {
18 Self {
19 sorted_mappings: Vec::new(),
20 }
21 }
22
23 /// Add a mapping to this address space. Any existing mappings which overlap with the
24 /// new mapping are removed.
25 ///
26 /// `start_avma` and `end_avma` describe the address range that this mapping
27 /// occupies.
28 ///
29 /// AVMA = "actual virtual memory address"
30 ///
31 /// `relative_address_at_start` is the "relative address" which corresponds
32 /// to `start_avma`, in the library that is mapped in this mapping. This is zero if
33 /// `start_avm` is the base address of the library.
34 ///
35 /// A relative address is a `u32` value which is relative to the library base address.
36 /// So you will usually set `relative_address_at_start` to `start_avma - base_avma`.
37 ///
38 /// For ELF binaries, the base address is the AVMA of the first segment, i.e. the
39 /// start_avma of the mapping created by the first ELF `LOAD` command.
40 ///
41 /// For mach-O binaries, the base address is the vmaddr of the `__TEXT` segment.
42 ///
43 /// For Windows binaries, the base address is the image load address.
44 pub fn add_mapping(
45 &mut self,
46 start_avma: u64,
47 end_avma: u64,
48 relative_address_at_start: u32,
49 value: T,
50 ) {
51 let remove_range_begin = match self
52 .sorted_mappings
53 .binary_search_by_key(&start_avma, |r| r.start_avma)
54 {
55 Ok(i) => i,
56 Err(0) => 0,
57 Err(i) => {
58 // start_avma falls between the start_avmas of `i - 1` and `i`.
59 if start_avma < self.sorted_mappings[i - 1].end_avma {
60 i - 1
61 } else {
62 i
63 }
64 }
65 };
66
67 let mut remove_range_end = remove_range_begin;
68 for mapping in &self.sorted_mappings[remove_range_begin..] {
69 if mapping.start_avma < end_avma {
70 remove_range_end += 1;
71 } else {
72 break;
73 }
74 }
75
76 self.sorted_mappings.splice(
77 remove_range_begin..remove_range_end,
78 [Mapping {
79 start_avma,
80 end_avma,
81 relative_address_at_start,
82 value,
83 }],
84 );
85 }
86
87 /// Remove a mapping which starts at the given address. If found, this returns
88 /// the `relative_address_at_start` and the associated value of the mapping.
89 pub fn remove_mapping(&mut self, start_avma: u64) -> Option<(u32, T)> {
90 self.sorted_mappings
91 .binary_search_by_key(&start_avma, |m| m.start_avma)
92 .ok()
93 .map(|i| self.sorted_mappings.remove(i))
94 .map(|m| (m.relative_address_at_start, m.value))
95 }
96
97 /// Clear all mappings.
98 pub fn clear(&mut self) {
99 self.sorted_mappings.clear();
100 self.sorted_mappings.shrink_to_fit();
101 }
102
103 /// Look up the mapping which covers the given address.
104 fn lookup(&self, avma: u64) -> Option<&Mapping<T>> {
105 let mappings = &self.sorted_mappings[..];
106 let index = match mappings.binary_search_by_key(&avma, |r| r.start_avma) {
107 Err(0) => return None,
108 Ok(exact_match) => exact_match,
109 Err(insertion_index) => {
110 let mapping_index = insertion_index - 1;
111 if avma < mappings[mapping_index].end_avma {
112 mapping_index
113 } else {
114 return None;
115 }
116 }
117 };
118 Some(&mappings[index])
119 }
120
121 /// Converts an absolute address (AVMA, actual virtual memory address) into
122 /// a relative address and the mapping's associated value.
123 pub fn convert_address(&self, avma: u64) -> Option<(u32, &T)> {
124 let mapping = match self.lookup(avma) {
125 Some(mapping) => mapping,
126 None => return None,
127 };
128 let offset_from_mapping_start = (avma - mapping.start_avma) as u32;
129 let relative_address = mapping.relative_address_at_start + offset_from_mapping_start;
130 Some((relative_address, &mapping.value))
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
135struct Mapping<T> {
136 start_avma: u64,
137 end_avma: u64,
138 relative_address_at_start: u32,
139 value: T,
140}