@@ -348,19 +348,37 @@ export class Coverage implements CoverageSession {
348348 } ) ;
349349 Stalker . flush ( ) ;
350350 const eventList = Array . from ( this . events . entries ( ) ) ;
351- const convertedEvents = eventList . map ( ( [ start , end ] ) =>
352- this . convertEvent ( start , end ) ,
351+ const convertedEvents = eventList
352+ . map ( ( [ start , end ] ) => this . convertEvent ( start , end ) )
353+ . filter ( e => e !== undefined ) as ICoverageEvent [ ] ;
354+
355+ const referencedModuleIds = [
356+ ...new Set ( convertedEvents . map ( e => e . moduleId ) ) ,
357+ ] . sort ( ) ;
358+
359+ const referencedModules = this . modules . filter ( ( _mapping , idx ) =>
360+ referencedModuleIds . includes ( idx ) ,
353361 ) ;
354- const nonNullEvents = convertedEvents . filter (
355- e => e !== undefined ,
356- ) as ICoverageEvent [ ] ;
357-
358- this . emitHeader ( nonNullEvents ) ;
359- for ( const convertedEvent of nonNullEvents ) {
360- if ( convertedEvent !== undefined ) {
361- this . emitEvent ( convertedEvent ) ;
362- }
363- }
362+
363+ const mapping : { [ moduleId : number ] : number } = referencedModuleIds . reduce (
364+ ( dict : { [ moduleId : number ] : number } , item : number , index : number ) => {
365+ dict [ item ] = index ;
366+ return dict ;
367+ } ,
368+ { } as { [ moduleId : number ] : number } ,
369+ ) ;
370+
371+ const remapped : ICoverageEvent [ ] = convertedEvents . map (
372+ e =>
373+ ( {
374+ length : e . length ,
375+ moduleId : mapping [ e . moduleId ] ,
376+ offset : e . offset ,
377+ } ) as ICoverageEvent ,
378+ ) ;
379+
380+ this . emitHeader ( referencedModules , convertedEvents ) ;
381+ remapped . forEach ( e => this . emitEvent ( e ) ) ;
364382 }
365383
366384 /**
@@ -436,20 +454,17 @@ export class Coverage implements CoverageSession {
436454
437455 /**
438456 * Function to emit the header information at the start of the DRCOV coverage information format. Note that the
439- * format includes a number of events in the header. This is obviously not ideally suited to streaming data, so we
440- * instead write the value of -1. This does not impair the operation of dragondance (which ignores the field), but
441- * changes may be required for IDA lighthouse to accept this modification.
457+ * format includes a number of events in the header.
458+ * @param modules The modules referenced by the events
442459 * @param events The coverage events to be emitted in the file
443460 */
444- private emitHeader ( events : ICoverageEvent [ ] ) : void {
461+ private emitHeader ( modules : Module [ ] , events : ICoverageEvent [ ] ) : void {
445462 this . emit ( Coverage . convertString ( 'DRCOV VERSION: 2\n' ) , true ) ;
446463 this . emit ( Coverage . convertString ( 'DRCOV FLAVOR: frida\n' ) , true ) ;
447464
448- const referencedModules = [ ...new Set ( events . map ( e => e . moduleId ) ) ] ;
449-
450465 this . emit (
451466 Coverage . convertString (
452- `Module Table: version 2, count ${ referencedModules . length } \n` ,
467+ `Module Table: version 2, count ${ modules . length } \n` ,
453468 ) ,
454469 true ,
455470 ) ;
@@ -461,10 +476,8 @@ export class Coverage implements CoverageSession {
461476 true ,
462477 ) ;
463478
464-
465- referencedModules . sort ( ) . forEach ( id => {
466- const module = this . modules [ id ] as Module ;
467- this . emitModule ( id , module ) ;
479+ modules . forEach ( ( module , idx ) => {
480+ this . emitModule ( idx , module ) ;
468481 } ) ;
469482
470483 this . emit ( Coverage . convertString ( `BB Table: ${ events . length } bbs\n` ) , true ) ;
0 commit comments