62
62
static struct LiteralEntry * module_build_literals_table (const void * literalsBuf );
63
63
static void module_add_label (Module * mod , int index , const uint8_t * ptr );
64
64
static enum ModuleLoadResult module_build_imported_functions_table (Module * this_module , uint8_t * table_data , GlobalContext * glb );
65
- static void parse_line_table ( uint16_t * * line_refs , struct ModuleFilename * * filenames , uint8_t * data , size_t len );
65
+ static void module_parse_line_table ( Module * mod , const uint8_t * data , size_t len );
66
66
67
67
#define IMPL_CODE_LOADER 1
68
68
#include "opcodesswitch.h"
@@ -281,7 +281,7 @@ Module *module_new_from_iff_binary(GlobalContext *global, const void *iff_binary
281
281
return NULL ;
282
282
}
283
283
284
- parse_line_table ( & mod -> line_refs , & mod -> filenames , beam_file + offsets [LINT ] + 8 , sizes [LINT ]);
284
+ module_parse_line_table ( mod , beam_file + offsets [LINT ] + 8 , sizes [LINT ]);
285
285
list_init (& mod -> line_ref_offsets );
286
286
287
287
if (offsets [LITT ]) {
@@ -437,117 +437,187 @@ const struct ExportedFunction *module_resolve_function0(Module *mod, int import_
437
437
}
438
438
}
439
439
440
- static uint16_t * parse_line_refs ( uint8_t * * data , size_t num_refs , size_t len )
440
+ static bool module_check_line_refs ( Module * mod , const uint8_t * * data , size_t len )
441
441
{
442
- uint16_t * ref_table = malloc ((num_refs + 1 ) * sizeof (uint16_t ));
443
- if (IS_NULL_PTR (ref_table )) {
444
- return NULL ;
445
- }
446
-
447
442
// assert pos >= *data
448
- uint8_t * pos = * data ;
449
- for (size_t i = 0 ; i < num_refs + 1 ; ++ i ) {
443
+ const uint8_t * pos = * data ;
444
+ size_t i = 0 ;
445
+ while (i < mod -> line_refs_count ) {
450
446
if ((size_t ) (pos - * data ) > len ) {
451
447
fprintf (stderr , "Invalid line_ref: expected tag.\n" );
452
- free (ref_table );
453
- return NULL ;
448
+ return false;
454
449
}
455
450
uint8_t tag = * pos ;
456
451
switch (tag & 0x0F ) {
457
452
case TAG_COMPACT_INT : {
458
- uint16_t line_idx = ((tag & 0xF0 ) >> 4 );
459
- ref_table [i ] = line_idx ;
460
- ++ pos ;
461
- break ;
462
- }
463
- case TAG_COMPACT_ATOM : {
464
- uint16_t line_idx = ((tag & 0xF0 ) >> 4 );
465
- ref_table [i ] = line_idx ;
453
+ ++ i ;
466
454
++ pos ;
467
455
break ;
468
456
}
469
457
case TAG_EXTENDED_INT : {
470
- uint16_t high_order_3_bits = (tag & 0xE0 );
471
458
++ pos ;
472
459
if ((size_t ) (pos - * data ) > len ) {
473
460
fprintf (stderr , "Invalid line_ref: expected extended int.\n" );
474
- free (ref_table );
475
- return NULL ;
461
+ return false;
462
+ }
463
+ ++ i ;
464
+ ++ pos ;
465
+ break ;
466
+ }
467
+ case TAG_COMPACT_ATOM : {
468
+ uint16_t location_ix = ((tag & 0xF0 ) >> 4 );
469
+ if (location_ix > mod -> locations_count ) {
470
+ fprintf (stderr , "Invalid line_ref: location_ix = %d is greater than locations_count = %d.\n" , (int ) location_ix , (int ) mod -> locations_count );
471
+ return false;
476
472
}
477
- uint8_t next_byte = * pos ;
478
- uint16_t line_idx = ((high_order_3_bits << 3 ) | next_byte );
479
473
++ pos ;
480
- ref_table [i ] = line_idx ;
481
474
break ;
482
475
}
483
476
case TAG_EXTENDED_ATOM : {
484
- uint16_t file_idx = (( tag & 0xF0 ) >> 4 );
477
+ uint16_t high_order_3_bits = (tag & 0xE0 );
485
478
++ pos ;
486
479
if ((size_t ) (pos - * data ) > len ) {
487
- fprintf (stderr , "Invalid line_ref: expected extended atom.\n" );
488
- free (ref_table );
489
- return NULL ;
480
+ fprintf (stderr , "Invalid line_ref: expected extended int.\n" );
481
+ return false;
490
482
}
491
483
uint8_t next_byte = * pos ;
492
- uint16_t line_idx = ((next_byte & 0xF0 ) >> 4 );
484
+ uint16_t location_ix = ((high_order_3_bits << 3 ) | next_byte );
485
+ if (location_ix > mod -> locations_count ) {
486
+ fprintf (stderr , "Invalid line_ref: location_ix = %d is greater than locations_count = %d.\n" , (int ) location_ix , (int ) mod -> locations_count );
487
+ return false;
488
+ }
493
489
++ pos ;
494
- ref_table [file_idx - 1 ] = line_idx ;
495
490
break ;
496
491
}
497
492
default :
498
493
// TODO handle integer compact encodings > 2048
499
494
fprintf (stderr , "Unsupported line_ref tag: %u\n" , tag );
500
- free (ref_table );
501
- return NULL ;
495
+ return false;
502
496
}
503
497
}
504
498
505
499
* data = pos ;
506
- return ref_table ;
500
+ return true ;
507
501
}
508
502
509
- struct ModuleFilename * parse_filename_table ( uint8_t * * data , size_t num_filenames , size_t len )
503
+ static bool module_check_locations ( Module * mod , const uint8_t * data , size_t len )
510
504
{
511
- struct ModuleFilename * filenames = malloc (num_filenames * sizeof (struct ModuleFilename ));
512
- if (IS_NULL_PTR (filenames )) {
513
- return NULL ;
514
- }
515
-
516
- // assert pos >= *data
517
- uint8_t * pos = * data ;
518
- for (size_t i = 0 ; i < num_filenames ; ++ i ) {
519
- if ((size_t ) ((pos + 2 ) - * data ) > len ) {
505
+ const uint8_t * pos = data ;
506
+ for (size_t i = 1 ; i <= mod -> locations_count ; i ++ ) {
507
+ if ((size_t ) ((pos + 2 ) - data ) > len ) {
520
508
fprintf (stderr , "Invalid filename: expected 16-bit size.\n" );
521
- free (filenames );
522
- return NULL ;
509
+ return false;
523
510
}
524
511
uint16_t size = READ_16_UNALIGNED (pos );
525
- pos += 2 ;
526
- if ((size_t ) ((pos + size ) - * data ) > len ) {
512
+ pos += 2 ;
513
+ if ((size_t ) ((pos + size ) - data ) > len ) {
527
514
fprintf (stderr , "Invalid filename: expected filename data (%u bytes).\n" , size );
528
- free (filenames );
529
- return NULL ;
515
+ return false;
530
516
}
531
- filenames [i ].len = size ;
532
- filenames [i ].data = pos ;
533
517
pos += size ;
534
518
}
535
519
536
- * data = pos ;
537
- return filenames ;
520
+ return true;
521
+ }
522
+
523
+ static bool module_get_line_ref (Module * mod , uint16_t line_ref , uint16_t * out_line , uint16_t * out_location )
524
+ {
525
+ // First is undefined
526
+ if (line_ref == 0 ) {
527
+ * out_line = 0 ;
528
+ * out_location = 0 ;
529
+ return true;
530
+ }
531
+
532
+ const uint8_t * pos = mod -> line_refs_table ;
533
+ uint16_t location_ix = 0 ;
534
+ size_t i = 1 ;
535
+ while (i <= mod -> line_refs_count ) {
536
+ uint8_t tag = * pos ;
537
+ switch (tag & 0x0F ) {
538
+ case TAG_COMPACT_INT : {
539
+ if (i == line_ref ) {
540
+ uint16_t line_idx = ((tag & 0xF0 ) >> 4 );
541
+ * out_line = line_idx ;
542
+ * out_location = location_ix ;
543
+ return true;
544
+ }
545
+ ++ i ;
546
+ ++ pos ;
547
+ break ;
548
+ }
549
+ case TAG_EXTENDED_INT : {
550
+ if (i == line_ref ) {
551
+ uint16_t high_order_3_bits = (tag & 0xE0 );
552
+ uint16_t line_idx = ((high_order_3_bits << 3 ) | pos [1 ]);
553
+ * out_line = line_idx ;
554
+ * out_location = location_ix ;
555
+ return true;
556
+ }
557
+ pos += 2 ;
558
+ ++ i ;
559
+ break ;
560
+ }
561
+ case TAG_COMPACT_ATOM : {
562
+ location_ix = ((tag & 0xF0 ) >> 4 );
563
+ ++ pos ;
564
+ break ;
565
+ }
566
+ case TAG_EXTENDED_ATOM : {
567
+ uint16_t high_order_3_bits = (tag & 0xE0 );
568
+ location_ix = ((high_order_3_bits << 3 ) | pos [1 ]);
569
+ pos += 2 ;
570
+ break ;
571
+ }
572
+ default :
573
+ // TODO handle integer compact encodings > 2048
574
+ return false;
575
+ }
576
+ }
577
+
578
+ return false;
538
579
}
539
580
540
- static void parse_line_table (uint16_t * * line_refs , struct ModuleFilename * * filenames , uint8_t * data , size_t len )
581
+
582
+ static bool module_get_location (Module * mod , uint16_t location_ix , size_t * filename_len , const uint8_t * * filename )
541
583
{
584
+ // 0 is module.erl
585
+ if (location_ix == 0 ) {
586
+ * filename_len = 0 ;
587
+ if (filename ) {
588
+ * filename = NULL ;
589
+ }
590
+ return true;
591
+ }
592
+
593
+ const uint8_t * pos = mod -> locations_table ;
594
+ for (size_t i = 1 ; i <= mod -> locations_count ; i ++ ) {
595
+ uint16_t size = READ_16_UNALIGNED (pos );
596
+ pos += 2 ;
597
+ if (i == location_ix ) {
598
+ * filename_len = size ;
599
+ if (filename ) {
600
+ * filename = pos ;
601
+ }
602
+ return true;
603
+ }
604
+ pos += size ;
605
+ }
542
606
543
- * line_refs = NULL ;
544
- * filenames = NULL ;
607
+ return false ;
608
+ }
545
609
610
+ static void module_parse_line_table (Module * mod , const uint8_t * data , size_t len )
611
+ {
546
612
if (len == 0 ) {
613
+ mod -> line_refs_count = 0 ;
614
+ mod -> line_refs_table = NULL ;
615
+ mod -> locations_count = 0 ;
616
+ mod -> locations_table = NULL ;
547
617
return ;
548
618
}
549
619
550
- uint8_t * pos = data ;
620
+ const uint8_t * pos = data ;
551
621
552
622
CHECK_FREE_SPACE (4 , "Error reading Line chunk: version\n" );
553
623
uint32_t version = READ_32_UNALIGNED (pos );
@@ -568,28 +638,36 @@ static void parse_line_table(uint16_t **line_refs, struct ModuleFilename **filen
568
638
pos += 4 ;
569
639
570
640
CHECK_FREE_SPACE (4 , "Error reading Line chunk: num_refs\n" );
571
- uint32_t num_refs = READ_32_UNALIGNED (pos );
641
+ mod -> line_refs_count = READ_32_UNALIGNED (pos );
572
642
pos += 4 ;
573
643
574
644
CHECK_FREE_SPACE (4 , "Error reading Line chunk: num_filenames\n" );
575
- uint32_t num_filenames = READ_32_UNALIGNED (pos );
645
+ mod -> locations_count = READ_32_UNALIGNED (pos );
576
646
pos += 4 ;
577
647
578
- * line_refs = parse_line_refs (& pos , num_refs , len - (pos - data ));
579
- if (IS_NULL_PTR (* line_refs )) {
648
+ mod -> line_refs_table = pos ;
649
+
650
+ if (UNLIKELY (!module_check_line_refs (mod , & pos , len - (pos - data )))) {
651
+ mod -> line_refs_count = 0 ;
652
+ mod -> line_refs_table = NULL ;
653
+ mod -> locations_count = 0 ;
654
+ mod -> locations_table = NULL ;
580
655
return ;
581
656
}
582
657
583
- * filenames = parse_filename_table (& pos , num_filenames , len - (pos - data ));
584
- if (IS_NULL_PTR (* filenames )) {
585
- free (* line_refs );
586
- return ;
658
+ mod -> locations_table = pos ;
659
+
660
+ if (UNLIKELY (!module_check_locations (mod , pos , len - (pos - data )))) {
661
+ mod -> line_refs_count = 0 ;
662
+ mod -> line_refs_table = NULL ;
663
+ mod -> locations_count = 0 ;
664
+ mod -> locations_table = NULL ;
587
665
}
588
666
}
589
667
590
668
void module_insert_line_ref_offset (Module * mod , int line_ref , int offset )
591
669
{
592
- if (IS_NULL_PTR (mod -> line_refs ) || line_ref == 0 ) {
670
+ if (IS_NULL_PTR (mod -> line_refs_table ) || line_ref == 0 ) {
593
671
return ;
594
672
}
595
673
struct LineRefOffset * ref_offset = malloc (sizeof (struct LineRefOffset ));
@@ -602,7 +680,16 @@ void module_insert_line_ref_offset(Module *mod, int line_ref, int offset)
602
680
list_append (& mod -> line_ref_offsets , & ref_offset -> head );
603
681
}
604
682
605
- int module_find_line (Module * mod , unsigned int offset )
683
+ static bool module_find_line_ref (Module * mod , uint16_t line_ref , uint16_t * line , size_t * filename_len , const uint8_t * * filename )
684
+ {
685
+ uint16_t location_ix ;
686
+ if (UNLIKELY (!module_get_line_ref (mod , line_ref , line , & location_ix ))) {
687
+ return false;
688
+ }
689
+ return module_get_location (mod , location_ix , filename_len , filename );
690
+ }
691
+
692
+ bool module_find_line (Module * mod , unsigned int offset , uint16_t * line , size_t * filename_len , const uint8_t * * filename )
606
693
{
607
694
int i = 0 ;
608
695
struct LineRefOffset * head = GET_LIST_ENTRY (& mod -> line_ref_offsets , struct LineRefOffset , head );
@@ -611,25 +698,23 @@ int module_find_line(Module *mod, unsigned int offset)
611
698
struct LineRefOffset * ref_offset = GET_LIST_ENTRY (item , struct LineRefOffset , head );
612
699
613
700
if (offset == ref_offset -> offset ) {
614
- return mod -> line_refs [ ref_offset -> line_ref ] ;
701
+ return module_find_line_ref ( mod , ref_offset -> line_ref , line , filename_len , filename ) ;
615
702
} else if (i == 0 && offset < ref_offset -> offset ) {
616
- return -1 ;
703
+ return false ;
617
704
} else {
618
705
619
706
struct LineRefOffset * prev_ref_offset = GET_LIST_ENTRY (ref_offset -> head .prev , struct LineRefOffset , head );
620
707
if (prev_ref_offset -> offset <= offset && offset < ref_offset -> offset ) {
621
- return mod -> line_refs [ prev_ref_offset -> line_ref ] ;
708
+ return module_find_line_ref ( mod , prev_ref_offset -> line_ref , line , filename_len , filename ) ;
622
709
}
623
710
624
711
struct LineRefOffset * next_ref_offset = GET_LIST_ENTRY (ref_offset -> head .next , struct LineRefOffset , head );
625
712
if (next_ref_offset == head && ref_offset -> offset <= offset ) {
626
- return mod -> line_refs [ ref_offset -> line_ref ] ;
713
+ return module_find_line_ref ( mod , ref_offset -> line_ref , line , filename_len , filename ) ;
627
714
}
628
715
}
629
716
630
717
++ i ;
631
718
}
632
- // should never occur, but return is needed to squelch compiler warnings
633
- AVM_ABORT ();
634
- return -1 ;
719
+ return false;
635
720
}
0 commit comments