@@ -142,16 +142,21 @@ pub struct Object<'a> {
142
142
data : Bytes < ' a > ,
143
143
dwarf : Option < & ' a [ MachSection ] > ,
144
144
syms : Vec < ( & ' a [ u8 ] , u64 ) > ,
145
+ object_map : Option < object:: ObjectMap < ' a > > ,
146
+ object_mappings : Vec < Option < Option < Mapping > > > ,
145
147
}
146
148
147
149
impl < ' a > Object < ' a > {
148
150
fn parse ( mach : & ' a Mach , endian : NativeEndian , data : Bytes < ' a > ) -> Option < Object < ' a > > {
151
+ let is_object = mach. filetype ( endian) == object:: macho:: MH_OBJECT ;
149
152
let mut dwarf = None ;
150
153
let mut syms = Vec :: new ( ) ;
151
154
let mut commands = mach. load_commands ( endian, data) . ok ( ) ?;
155
+ let mut object_map = None ;
156
+ let mut object_mappings = Vec :: new ( ) ;
152
157
while let Ok ( Some ( command) ) = commands. next ( ) {
153
158
if let Some ( ( segment, section_data) ) = MachSegment :: from_command ( command) . ok ( ) ? {
154
- if segment. name ( ) == b"__DWARF" {
159
+ if segment. name ( ) == b"__DWARF" || ( is_object && segment . name ( ) == b"" ) {
155
160
dwarf = segment. sections ( endian, section_data) . ok ( ) ;
156
161
}
157
162
} else if let Some ( symtab) = command. symtab ( ) . ok ( ) ? {
@@ -160,14 +165,19 @@ impl<'a> Object<'a> {
160
165
. iter ( )
161
166
. filter_map ( |nlist : & MachNlist | {
162
167
let name = nlist. name ( endian, symbols. strings ( ) ) . ok ( ) ?;
163
- if name. len ( ) > 0 && ! nlist. is_undefined ( ) {
168
+ if name. len ( ) > 0 && nlist. is_definition ( ) {
164
169
Some ( ( name, u64:: from ( nlist. n_value ( endian) ) ) )
165
170
} else {
166
171
None
167
172
}
168
173
} )
169
174
. collect ( ) ;
170
175
syms. sort_unstable_by_key ( |( _, addr) | * addr) ;
176
+ if !is_object {
177
+ let map = symbols. object_map ( endian) ;
178
+ object_mappings. resize_with ( map. objects ( ) . len ( ) , || None ) ;
179
+ object_map = Some ( map) ;
180
+ }
171
181
}
172
182
}
173
183
@@ -176,6 +186,8 @@ impl<'a> Object<'a> {
176
186
data,
177
187
dwarf,
178
188
syms,
189
+ object_map,
190
+ object_mappings,
179
191
} )
180
192
}
181
193
@@ -201,4 +213,72 @@ impl<'a> Object<'a> {
201
213
let ( sym, _addr) = self . syms . get ( i) ?;
202
214
Some ( sym)
203
215
}
216
+
217
+ /// Try to load a context for an object file.
218
+ ///
219
+ /// If dsymutil was not run, then the DWARF may be found in the source object files.
220
+ pub ( super ) fn search_object_map < ' b > ( & ' b mut self , addr : u64 ) -> Option < ( & Context < ' b > , u64 ) > {
221
+ // `object_map` contains a map from addresses to symbols and object paths.
222
+ // Look up the address and get a mapping for the object.
223
+ let object_map = self . object_map . as_ref ( ) ?;
224
+ let symbol = object_map. get ( addr) ?;
225
+ let object_index = symbol. object_index ( ) ;
226
+ let mapping = self . object_mappings . get_mut ( object_index) ?;
227
+ if mapping. is_none ( ) {
228
+ // No cached mapping, so create it.
229
+ * mapping = Some ( object_mapping ( object_map. objects ( ) . get ( object_index) ?) ) ;
230
+ }
231
+ let cx: & ' b Context < ' static > = & mapping. as_ref ( ) ?. as_ref ( ) ?. cx ;
232
+ // Don't leak the `'static` lifetime, make sure it's scoped to just ourselves.
233
+ let cx = unsafe { core:: mem:: transmute :: < & ' b Context < ' static > , & ' b Context < ' b > > ( cx) } ;
234
+
235
+ // We must translate the address in order to be able to look it up
236
+ // in the DWARF in the object file.
237
+ let object_symbol = cx. object . syms . iter ( ) . find ( |sym| sym. 0 == symbol. name ( ) ) ?;
238
+ let object_addr = addr
239
+ . wrapping_sub ( symbol. address ( ) )
240
+ . wrapping_add ( object_symbol. 1 ) ;
241
+ Some ( ( cx, object_addr) )
242
+ }
243
+ }
244
+
245
+ fn object_mapping ( path : & [ u8 ] ) -> Option < Mapping > {
246
+ use super :: mystd:: ffi:: OsStr ;
247
+ use super :: mystd:: os:: unix:: prelude:: * ;
248
+
249
+ // `N_OSO` symbol names can be either `/path/to/object.o` or `/path/to/archive.a(object.o)`.
250
+ if let Some ( ( archive_path, member_name) ) = split_archive_path ( path) {
251
+ let map = super :: mmap ( Path :: new ( OsStr :: from_bytes ( archive_path) ) ) ?;
252
+ let archive = object:: read:: archive:: ArchiveFile :: parse ( & map) . ok ( ) ?;
253
+ for member in archive. members ( ) {
254
+ let member = member. ok ( ) ?;
255
+ if member. name ( ) == member_name {
256
+ let ( macho, data) = find_header ( Bytes ( member. data ( ) ) ) ?;
257
+ let endian = macho. endian ( ) . ok ( ) ?;
258
+ let object = Object :: parse ( macho, endian, data) ?;
259
+ let stash = Stash :: new ( ) ;
260
+ let inner = super :: cx ( & stash, object) ?;
261
+ return Some ( mk ! ( Mapping { map, inner, stash } ) ) ;
262
+ }
263
+ }
264
+ None
265
+ } else {
266
+ let map = super :: mmap ( Path :: new ( OsStr :: from_bytes ( path) ) ) ?;
267
+ let ( macho, data) = find_header ( Bytes ( & map) ) ?;
268
+ let endian = macho. endian ( ) . ok ( ) ?;
269
+ let object = Object :: parse ( macho, endian, data) ?;
270
+ let stash = Stash :: new ( ) ;
271
+ let inner = super :: cx ( & stash, object) ?;
272
+ Some ( mk ! ( Mapping { map, inner, stash } ) )
273
+ }
274
+ }
275
+
276
+ fn split_archive_path ( path : & [ u8 ] ) -> Option < ( & [ u8 ] , & [ u8 ] ) > {
277
+ let ( last, path) = path. split_last ( ) ?;
278
+ if * last != b')' {
279
+ return None ;
280
+ }
281
+ let index = path. iter ( ) . position ( |& x| x == b'(' ) ?;
282
+ let ( archive, rest) = path. split_at ( index) ;
283
+ Some ( ( archive, & rest[ 1 ..] ) )
204
284
}
0 commit comments