@@ -97,6 +97,19 @@ impl Drop for BoxedCallback {
9797 }
9898}
9999
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+
100113/// An Image defines the memory image that was traced as a collection
101114/// of file sections and the virtual addresses at which those sections were loaded.
102115#[ derive( Debug ) ]
@@ -108,7 +121,9 @@ pub struct Image {
108121 // Any read data callback set by this `Image` instance.
109122 callback : Option < BoxedCallback > ,
110123 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 > > ,
112127}
113128
114129impl Image {
@@ -233,7 +248,9 @@ impl Image {
233248 } ) ?;
234249
235250 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+ }
237254 Ok ( res)
238255 }
239256
@@ -252,7 +269,7 @@ impl Image {
252269 ) -> Result < ( ) , PtError > {
253270 let asid_ptr = if let Some ( a) = asid {
254271 // fixme: use get_or_insert once stable (if ever)
255- self . asids . insert ( * a ) ;
272+ self . asids . insert ( Rc :: new ( * a ) ) ;
256273 & raw const self . asids . get ( a) . unwrap ( ) . 0
257274 } else {
258275 ptr:: null ( )
@@ -275,9 +292,6 @@ impl Image {
275292 ) ;
276293 } ) ?;
277294 self . caches . push ( iscache) ;
278- if let Some ( a) = asid {
279- self . asids . insert ( * a) ;
280- }
281295 Ok ( ( ) )
282296 }
283297
@@ -303,7 +317,7 @@ impl Image {
303317 let cfilename = str_to_cstring_pterror ( filename) ?;
304318 let asid_ptr = if let Some ( a) = asid {
305319 // fixme: use get_or_insert once stable (if ever)
306- self . asids . insert ( * a ) ;
320+ self . asids . insert ( Rc :: new ( * a ) ) ;
307321 & raw const self . asids . get ( a) . unwrap ( ) . 0
308322 } else {
309323 ptr:: null ( )
@@ -318,9 +332,31 @@ impl Image {
318332 vaddr,
319333 )
320334 } ) ?;
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) ;
323353 }
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+
324360 Ok ( ( ) )
325361 }
326362}
@@ -488,4 +524,47 @@ mod test {
488524 i. add_cached ( Rc :: new ( c) , isid, Some ( & asid) ) . unwrap ( ) ;
489525 assert_eq ! ( i. remove_by_asid( & asid) . unwrap( ) , 1 ) ;
490526 }
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+ }
491570}
0 commit comments