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}