@@ -43,6 +43,7 @@ type pclntab struct {
43
43
findfunctab loader.Sym
44
44
cutab loader.Sym
45
45
filetab loader.Sym
46
+ pctab loader.Sym
46
47
47
48
// The number of functions + number of TEXT sections - 1. This is such an
48
49
// unexpected value because platforms that have more than one TEXT section
@@ -273,10 +274,11 @@ func (state *pclntab) generatePCHeader(ctxt *Link) {
273
274
off = writeSymOffset (off , state .funcnametab )
274
275
off = writeSymOffset (off , state .cutab )
275
276
off = writeSymOffset (off , state .filetab )
277
+ off = writeSymOffset (off , state .pctab )
276
278
off = writeSymOffset (off , state .pclntab )
277
279
}
278
280
279
- size := int64 (8 + 6 * ctxt .Arch .PtrSize )
281
+ size := int64 (8 + 7 * ctxt .Arch .PtrSize )
280
282
state .pcheader = state .addGeneratedSym (ctxt , "runtime.pcheader" , size , writeHeader )
281
283
}
282
284
@@ -463,6 +465,68 @@ func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.Compilat
463
465
return cuOffsets
464
466
}
465
467
468
+ // generatePctab creates the runtime.pctab variable, holding all the
469
+ // deduplicated pcdata.
470
+ func (state * pclntab ) generatePctab (ctxt * Link , container loader.Bitmap ) {
471
+ ldr := ctxt .loader
472
+
473
+ // Pctab offsets of 0 are considered invalid in the runtime. We respect
474
+ // that by just padding a single byte at the beginning of runtime.pctab,
475
+ // that way no real offsets can be zero.
476
+ size := int64 (1 )
477
+
478
+ // Walk the functions, finding offset to store each pcdata.
479
+ seen := make (map [loader.Sym ]struct {})
480
+ saveOffset := func (pcSym loader.Sym ) {
481
+ if _ , ok := seen [pcSym ]; ! ok {
482
+ datSize := ldr .SymSize (pcSym )
483
+ if datSize != 0 {
484
+ ldr .SetSymValue (pcSym , size )
485
+ } else {
486
+ // Invalid PC data, record as zero.
487
+ ldr .SetSymValue (pcSym , 0 )
488
+ }
489
+ size += datSize
490
+ seen [pcSym ] = struct {}{}
491
+ }
492
+ }
493
+ for _ , s := range ctxt .Textp {
494
+ if ! emitPcln (ctxt , s , container ) {
495
+ continue
496
+ }
497
+ fi := ldr .FuncInfo (s )
498
+ if ! fi .Valid () {
499
+ continue
500
+ }
501
+ fi .Preload ()
502
+
503
+ pcSyms := []loader.Sym {fi .Pcsp (), fi .Pcfile (), fi .Pcline ()}
504
+ for _ , pcSym := range pcSyms {
505
+ saveOffset (pcSym )
506
+ }
507
+ for _ , pcSym := range fi .Pcdata () {
508
+ saveOffset (pcSym )
509
+ }
510
+ if fi .NumInlTree () > 0 {
511
+ saveOffset (fi .Pcinline ())
512
+ }
513
+ }
514
+
515
+ // TODO: There is no reason we need a generator for this variable, and it
516
+ // could be moved to a carrier symbol. However, carrier symbols containing
517
+ // carrier symbols don't work yet (as of Aug 2020). Once this is fixed,
518
+ // runtime.pctab could just be a carrier sym.
519
+ writePctab := func (ctxt * Link , s loader.Sym ) {
520
+ ldr := ctxt .loader
521
+ sb := ldr .MakeSymbolUpdater (s )
522
+ for sym := range seen {
523
+ sb .SetBytesAt (ldr .SymValue (sym ), ldr .Data (sym ))
524
+ }
525
+ }
526
+
527
+ state .pctab = state .addGeneratedSym (ctxt , "runtime.pctab" , size , writePctab )
528
+ }
529
+
466
530
// pclntab initializes the pclntab symbol with
467
531
// runtime function and file name information.
468
532
@@ -494,6 +558,9 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
494
558
// runtime.filetab
495
559
// []null terminated filename strings
496
560
//
561
+ // runtime.pctab
562
+ // []byte of deduplicated pc data.
563
+ //
497
564
// runtime.pclntab_old
498
565
// function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
499
566
// end PC [thearch.ptrsize bytes]
@@ -514,6 +581,7 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
514
581
state .generatePCHeader (ctxt )
515
582
state .generateFuncnametab (ctxt , container )
516
583
cuOffsets := state .generateFilenameTabs (ctxt , compUnits , container )
584
+ state .generatePctab (ctxt , container )
517
585
518
586
funcdataBytes := int64 (0 )
519
587
ldr .SetCarrierSym (state .pclntab , state .carrier )
@@ -525,21 +593,6 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
525
593
526
594
ftab .Grow (int64 (state .nfunc )* 2 * int64 (ctxt .Arch .PtrSize ) + int64 (ctxt .Arch .PtrSize ) + 4 )
527
595
528
- szHint := len (ctxt .Textp ) * 2
529
- pctaboff := make (map [string ]uint32 , szHint )
530
- writepctab := func (off int32 , p []byte ) int32 {
531
- start , ok := pctaboff [string (p )]
532
- if ! ok {
533
- if len (p ) > 0 {
534
- start = uint32 (len (ftab .Data ()))
535
- ftab .AddBytes (p )
536
- }
537
- pctaboff [string (p )] = start
538
- }
539
- newoff := int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), start ))
540
- return newoff
541
- }
542
-
543
596
setAddr := (* loader .SymbolBuilder ).SetAddrPlus
544
597
if ctxt .IsExe () && ctxt .IsInternal () {
545
598
// Internal linking static executable. At this point the function
@@ -555,10 +608,6 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
555
608
}
556
609
}
557
610
558
- pcsp := sym.Pcdata {}
559
- pcfile := sym.Pcdata {}
560
- pcline := sym.Pcdata {}
561
- pcdata := []sym.Pcdata {}
562
611
funcdata := []loader.Sym {}
563
612
funcdataoff := []int64 {}
564
613
@@ -583,34 +632,26 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
583
632
}
584
633
prevFunc = s
585
634
586
- pcsp .P = pcsp .P [:0 ]
587
- pcline .P = pcline .P [:0 ]
588
- pcfile .P = pcfile .P [:0 ]
589
- pcdata = pcdata [:0 ]
635
+ var numPCData int32
590
636
funcdataoff = funcdataoff [:0 ]
591
637
funcdata = funcdata [:0 ]
592
638
fi := ldr .FuncInfo (s )
593
639
if fi .Valid () {
594
640
fi .Preload ()
595
- for _ , dataSym := range fi .Pcdata () {
596
- pcdata = append (pcdata , sym.Pcdata {P : ldr .Data (dataSym )})
597
- }
641
+ numPCData = int32 (len (fi .Pcdata ()))
598
642
nfd := fi .NumFuncdataoff ()
599
643
for i := uint32 (0 ); i < nfd ; i ++ {
600
644
funcdataoff = append (funcdataoff , fi .Funcdataoff (int (i )))
601
645
}
602
646
funcdata = fi .Funcdata (funcdata )
603
647
}
604
648
649
+ writeInlPCData := false
605
650
if fi .Valid () && fi .NumInlTree () > 0 {
606
-
607
- if len (pcdata ) <= objabi .PCDATA_InlTreeIndex {
608
- // Create inlining pcdata table.
609
- newpcdata := make ([]sym.Pcdata , objabi .PCDATA_InlTreeIndex + 1 )
610
- copy (newpcdata , pcdata )
611
- pcdata = newpcdata
651
+ writeInlPCData = true
652
+ if numPCData <= objabi .PCDATA_InlTreeIndex {
653
+ numPCData = objabi .PCDATA_InlTreeIndex + 1
612
654
}
613
-
614
655
if len (funcdataoff ) <= objabi .FUNCDATA_InlTree {
615
656
// Create inline tree funcdata.
616
657
newfuncdata := make ([]loader.Sym , objabi .FUNCDATA_InlTree + 1 )
@@ -635,7 +676,7 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
635
676
// fixed size of struct, checked below
636
677
off := funcstart
637
678
638
- end := funcstart + int32 (ctxt .Arch .PtrSize ) + 3 * 4 + 6 * 4 + int32 ( len ( pcdata )) * 4 + int32 (len (funcdata ))* int32 (ctxt .Arch .PtrSize )
679
+ end := funcstart + int32 (ctxt .Arch .PtrSize ) + 3 * 4 + 6 * 4 + numPCData * 4 + int32 (len (funcdata ))* int32 (ctxt .Arch .PtrSize )
639
680
if len (funcdata ) > 0 && (end & int32 (ctxt .Arch .PtrSize - 1 ) != 0 ) {
640
681
end += 4
641
682
}
@@ -664,23 +705,21 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
664
705
off = int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), deferreturn ))
665
706
666
707
cu := ldr .SymUnit (s )
667
- if fi .Valid () {
668
- pcsp = sym.Pcdata {P : ldr .Data (fi .Pcsp ())}
669
- pcfile = sym.Pcdata {P : ldr .Data (fi .Pcfile ())}
670
- pcline = sym.Pcdata {P : ldr .Data (fi .Pcline ())}
671
- }
672
708
673
709
if fi .Valid () && fi .NumInlTree () > 0 {
674
710
its := oldState .genInlTreeSym (cu , fi , ctxt .Arch , state )
675
711
funcdata [objabi .FUNCDATA_InlTree ] = its
676
- pcdata [objabi .PCDATA_InlTreeIndex ] = sym.Pcdata {P : ldr .Data (fi .Pcinline ())}
677
712
}
678
713
679
714
// pcdata
680
- off = writepctab (off , pcsp .P )
681
- off = writepctab (off , pcfile .P )
682
- off = writepctab (off , pcline .P )
683
- off = int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), uint32 (len (pcdata ))))
715
+ if fi .Valid () {
716
+ off = int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), uint32 (ldr .SymValue (fi .Pcsp ()))))
717
+ off = int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), uint32 (ldr .SymValue (fi .Pcfile ()))))
718
+ off = int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), uint32 (ldr .SymValue (fi .Pcline ()))))
719
+ } else {
720
+ off += 12
721
+ }
722
+ off = int32 (ftab .SetUint32 (ctxt .Arch , int64 (off ), uint32 (numPCData )))
684
723
685
724
// Store the offset to compilation unit's file table.
686
725
cuIdx := ^ uint32 (0 )
@@ -700,9 +739,17 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
700
739
701
740
// nfuncdata must be the final entry.
702
741
off = int32 (ftab .SetUint8 (ctxt .Arch , int64 (off ), uint8 (len (funcdata ))))
703
- for i := range pcdata {
704
- off = writepctab (off , pcdata [i ].P )
742
+
743
+ // Output the pcdata.
744
+ if fi .Valid () {
745
+ for i , pcSym := range fi .Pcdata () {
746
+ ftab .SetUint32 (ctxt .Arch , int64 (off + int32 (i * 4 )), uint32 (ldr .SymValue (pcSym )))
747
+ }
748
+ if writeInlPCData {
749
+ ftab .SetUint32 (ctxt .Arch , int64 (off + objabi .PCDATA_InlTreeIndex * 4 ), uint32 (ldr .SymValue (fi .Pcinline ())))
750
+ }
705
751
}
752
+ off += numPCData * 4
706
753
707
754
// funcdata, must be pointer-aligned and we're only int32-aligned.
708
755
// Missing funcdata will be 0 (nil pointer).
@@ -724,7 +771,7 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
724
771
}
725
772
726
773
if off != end {
727
- ctxt .Errorf (s , "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)" , funcstart , off , end , len ( pcdata ) , len (funcdata ), ctxt .Arch .PtrSize )
774
+ ctxt .Errorf (s , "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)" , funcstart , off , end , numPCData , len (funcdata ), ctxt .Arch .PtrSize )
728
775
errorexit ()
729
776
}
730
777
0 commit comments