@@ -97,6 +97,19 @@ impl Drop for BoxedCallback {
97
97
}
98
98
}
99
99
100
+ /// Info of a binary's section that can be used to populate an `Image`
101
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
102
+ pub struct SectionInfo {
103
+ /// Path of the binary
104
+ pub filename : String ,
105
+ /// Offset of the section in the file
106
+ pub offset : u64 ,
107
+ /// Size of the section
108
+ pub size : u64 ,
109
+ /// Start virtual address of the section once loaded in memory
110
+ pub virtual_address : u64 ,
111
+ }
112
+
100
113
/// An Image defines the memory image that was traced as a collection
101
114
/// of file sections and the virtual addresses at which those sections were loaded.
102
115
#[ derive( Debug ) ]
@@ -108,7 +121,9 @@ pub struct Image {
108
121
// Any read data callback set by this `Image` instance.
109
122
callback : Option < BoxedCallback > ,
110
123
caches : Vec < Rc < SectionCache > > ,
111
- asids : HashSet < Asid > ,
124
+ // `HashSet` might grow and move the content around, we cannot use `Asid` directly since we
125
+ // share a pointer with libipt, and it must be valid for the entire Image (section) lifetime.
126
+ asids : HashSet < Rc < Asid > > ,
112
127
}
113
128
114
129
impl Image {
@@ -233,7 +248,9 @@ impl Image {
233
248
} ) ?;
234
249
235
250
self . caches . extend_from_slice ( & src. caches ) ;
236
- self . asids . extend ( & src. asids ) ;
251
+ for asid in & src. asids {
252
+ self . asids . insert ( asid. clone ( ) ) ;
253
+ }
237
254
Ok ( res)
238
255
}
239
256
@@ -252,7 +269,7 @@ impl Image {
252
269
) -> Result < ( ) , PtError > {
253
270
let asid_ptr = if let Some ( a) = asid {
254
271
// fixme: use get_or_insert once stable (if ever)
255
- self . asids . insert ( * a ) ;
272
+ self . asids . insert ( Rc :: new ( * a ) ) ;
256
273
& raw const self . asids . get ( a) . unwrap ( ) . 0
257
274
} else {
258
275
ptr:: null ( )
@@ -275,9 +292,6 @@ impl Image {
275
292
) ;
276
293
} ) ?;
277
294
self . caches . push ( iscache) ;
278
- if let Some ( a) = asid {
279
- self . asids . insert ( * a) ;
280
- }
281
295
Ok ( ( ) )
282
296
}
283
297
@@ -303,7 +317,7 @@ impl Image {
303
317
let cfilename = str_to_cstring_pterror ( filename) ?;
304
318
let asid_ptr = if let Some ( a) = asid {
305
319
// fixme: use get_or_insert once stable (if ever)
306
- self . asids . insert ( * a ) ;
320
+ self . asids . insert ( Rc :: new ( * a ) ) ;
307
321
& raw const self . asids . get ( a) . unwrap ( ) . 0
308
322
} else {
309
323
ptr:: null ( )
@@ -318,9 +332,31 @@ impl Image {
318
332
vaddr,
319
333
)
320
334
} ) ?;
321
- if let Some ( a) = asid {
322
- self . asids . insert ( * a) ;
335
+ Ok ( ( ) )
336
+ }
337
+
338
+ /// Add multiple file sections to the traced memory image, backed by a cache.
339
+ ///
340
+ /// This is the same as creating a `SectionCache` and subsequently calling `add_cached()` for
341
+ /// each section.
342
+ pub fn add_files_cached (
343
+ & mut self ,
344
+ sections_info : & [ SectionInfo ] ,
345
+ asid : Option < & Asid > ,
346
+ ) -> Result < ( ) , PtError > {
347
+ let mut image_cache = SectionCache :: new ( None ) ?;
348
+
349
+ let mut isids = Vec :: with_capacity ( sections_info. len ( ) ) ;
350
+ for s in sections_info {
351
+ let isid = image_cache. add_file ( & s. filename , s. offset , s. size , s. virtual_address ) ?;
352
+ isids. push ( isid) ;
323
353
}
354
+
355
+ let rc_cache = Rc :: new ( image_cache) ;
356
+ for isid in isids {
357
+ self . add_cached ( rc_cache. clone ( ) , isid, asid) ?;
358
+ }
359
+
324
360
Ok ( ( ) )
325
361
}
326
362
}
@@ -488,4 +524,47 @@ mod test {
488
524
i. add_cached ( Rc :: new ( c) , isid, Some ( & asid) ) . unwrap ( ) ;
489
525
assert_eq ! ( i. remove_by_asid( & asid) . unwrap( ) , 1 ) ;
490
526
}
527
+
528
+ #[ test]
529
+ fn img_extend ( ) {
530
+ let file: PathBuf = [ env ! ( "CARGO_MANIFEST_DIR" ) , "testfiles" , "garbage.txt" ]
531
+ . iter ( )
532
+ . collect ( ) ;
533
+
534
+ let mut img = Image :: new ( None ) . unwrap ( ) ;
535
+ {
536
+ let mut img2 = Image :: new ( None ) . unwrap ( ) ;
537
+ for i in 0 ..100 {
538
+ let mut cache = SectionCache :: new ( None ) . unwrap ( ) ;
539
+ let asid = Asid :: new ( Some ( i) , Some ( i) ) ;
540
+ let isid = cache. add_file ( file. to_str ( ) . unwrap ( ) , i, 1 , i) . unwrap ( ) ;
541
+ let rc = Rc :: new ( cache) ;
542
+ img2. add_cached ( rc. clone ( ) , isid, Some ( & asid) ) . unwrap ( )
543
+ }
544
+
545
+ img. extend ( & img2) . unwrap ( ) ;
546
+ }
547
+
548
+ for i in 0 ..100 {
549
+ assert_eq ! ( img. remove_by_asid( & Asid :: new( Some ( i) , Some ( i) ) ) . unwrap( ) , 1 ) ;
550
+ }
551
+ }
552
+
553
+ #[ test]
554
+ fn img_add_files_cached ( ) {
555
+ let file: PathBuf = [ env ! ( "CARGO_MANIFEST_DIR" ) , "testfiles" , "garbage.txt" ]
556
+ . iter ( )
557
+ . collect ( ) ;
558
+
559
+ let section = SectionInfo {
560
+ filename : file. to_string_lossy ( ) . to_string ( ) ,
561
+ offset : 5 ,
562
+ size : 15 ,
563
+ virtual_address : 0x1337 ,
564
+ } ;
565
+ let mut i = img_with_file ( ) ;
566
+ let asid = Asid :: new ( Some ( 3 ) , Some ( 4 ) ) ;
567
+ i. add_files_cached ( & [ section] , Some ( & asid) ) . unwrap ( ) ;
568
+ assert_eq ! ( i. remove_by_asid( & asid) . unwrap( ) , 1 ) ;
569
+ }
491
570
}
0 commit comments