1
+ use std:: collections:: BTreeMap ;
2
+
1
3
/// Keeps track of mapped libraries in an address space. Stores a value
2
4
/// for each mapping, and allows efficient lookup of that value based on
3
5
/// an address.
6
+ ///
7
+ /// A "library" here is a loose term; it could be a normal shared library,
8
+ /// or the main binary, but it could also be a synthetic library for JIT
9
+ /// code. For normal libraries, there's usually just one mapping per library.
10
+ /// For JIT code, you could have many small mappings, one per JIT function,
11
+ /// all pointing to the synthetic JIT "library".
4
12
#[ derive( Debug , Clone ) ]
5
13
pub struct LibMappings < T > {
6
- sorted_mappings : Vec < Mapping < T > > ,
14
+ /// A BTreeMap of non-overlapping Mappings. The key is the start_avma of the mapping.
15
+ ///
16
+ /// When a new mapping is added, overlapping mappings are removed.
17
+ map : BTreeMap < u64 , Mapping < T > > ,
7
18
}
8
19
9
20
impl < T > Default for LibMappings < T > {
@@ -16,7 +27,7 @@ impl<T> LibMappings<T> {
16
27
/// Creates a new empty instance.
17
28
pub fn new ( ) -> Self {
18
29
Self {
19
- sorted_mappings : Vec :: new ( ) ,
30
+ map : BTreeMap :: new ( ) ,
20
31
}
21
32
}
22
33
@@ -48,80 +59,68 @@ impl<T> LibMappings<T> {
48
59
relative_address_at_start : u32 ,
49
60
value : T ,
50
61
) {
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 ;
62
+ let removal_avma_range_start =
63
+ if let Some ( mapping_overlapping_with_start_avma) = self . lookup_impl ( start_avma) {
64
+ mapping_overlapping_with_start_avma. start_avma
71
65
} else {
72
- break ;
73
- }
66
+ start_avma
67
+ } ;
68
+ // self.map.drain(removal_avma_range_start..end_avma);
69
+ let overlapping_keys: Vec < u64 > = self
70
+ . map
71
+ . range ( removal_avma_range_start..end_avma)
72
+ . map ( |( start_avma, _) | * start_avma)
73
+ . collect ( ) ;
74
+ for key in overlapping_keys {
75
+ self . map . remove ( & key) ;
74
76
}
75
77
76
- self . sorted_mappings . splice (
77
- remove_range_begin..remove_range_end ,
78
- [ Mapping {
78
+ self . map . insert (
79
+ start_avma ,
80
+ Mapping {
79
81
start_avma,
80
82
end_avma,
81
83
relative_address_at_start,
82
84
value,
83
- } ] ,
85
+ } ,
84
86
) ;
85
87
}
86
88
87
89
/// Remove a mapping which starts at the given address. If found, this returns
88
90
/// the `relative_address_at_start` and the associated value of the mapping.
89
91
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) )
92
+ self . map
93
+ . remove ( & start_avma)
94
94
. map ( |m| ( m. relative_address_at_start , m. value ) )
95
95
}
96
96
97
97
/// Clear all mappings.
98
98
pub fn clear ( & mut self ) {
99
- self . sorted_mappings . clear ( ) ;
100
- self . sorted_mappings . shrink_to_fit ( ) ;
99
+ self . map . clear ( ) ;
101
100
}
102
101
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 ] )
102
+ /// Look up the mapping which covers the given address and return
103
+ /// the stored value.
104
+ pub fn lookup ( & self , avma : u64 ) -> Option < & T > {
105
+ self . lookup_impl ( avma) . map ( |m| & m . value )
106
+ }
107
+
108
+ /// Look up the mapping which covers the given address and return
109
+ /// its `Mapping<T>``.
110
+ fn lookup_impl ( & self , avma : u64 ) -> Option < & Mapping < T > > {
111
+ let ( _start_avma , last_mapping_starting_at_or_before_avma ) =
112
+ self . map . range ( ..=avma ) . next_back ( ) ? ;
113
+ if avma < last_mapping_starting_at_or_before_avma . end_avma {
114
+ Some ( last_mapping_starting_at_or_before_avma )
115
+ } else {
116
+ None
117
+ }
119
118
}
120
119
121
120
/// Converts an absolute address (AVMA, actual virtual memory address) into
122
121
/// a relative address and the mapping's associated value.
123
122
pub fn convert_address ( & self , avma : u64 ) -> Option < ( u32 , & T ) > {
124
- let mapping = match self . lookup ( avma) {
123
+ let mapping = match self . lookup_impl ( avma) {
125
124
Some ( mapping) => mapping,
126
125
None => return None ,
127
126
} ;
@@ -138,3 +137,28 @@ struct Mapping<T> {
138
137
relative_address_at_start : u32 ,
139
138
value : T ,
140
139
}
140
+
141
+ #[ cfg( test) ]
142
+ mod test {
143
+ use super :: * ;
144
+
145
+ #[ test]
146
+ fn test_lib_mappings ( ) {
147
+ let mut m = LibMappings :: new ( ) ;
148
+ m. add_mapping ( 100 , 200 , 100 , "100..200" ) ;
149
+ m. add_mapping ( 200 , 250 , 200 , "200..250" ) ;
150
+ assert_eq ! ( m. lookup( 200 ) , Some ( & "200..250" ) ) ;
151
+ m. add_mapping ( 180 , 220 , 180 , "180..220" ) ;
152
+ assert_eq ! ( m. lookup( 200 ) , Some ( & "180..220" ) ) ;
153
+ assert_eq ! ( m. lookup( 170 ) , None ) ;
154
+ assert_eq ! ( m. lookup( 220 ) , None ) ;
155
+ m. add_mapping ( 225 , 250 , 225 , "225..250" ) ;
156
+ m. add_mapping ( 255 , 270 , 255 , "255..270" ) ;
157
+ m. add_mapping ( 100 , 150 , 100 , "100..150" ) ;
158
+ assert_eq ! ( m. lookup( 90 ) , None ) ;
159
+ assert_eq ! ( m. lookup( 150 ) , None ) ;
160
+ assert_eq ! ( m. lookup( 149 ) , Some ( & "100..150" ) ) ;
161
+ assert_eq ! ( m. lookup( 200 ) , Some ( & "180..220" ) ) ;
162
+ assert_eq ! ( m. lookup( 260 ) , Some ( & "255..270" ) ) ;
163
+ }
164
+ }
0 commit comments