14
14
#include " bolt/Rewrite/MetadataRewriter.h"
15
15
#include " bolt/Rewrite/MetadataRewriters.h"
16
16
#include " bolt/Utils/CommandLineOpts.h"
17
+ #include " llvm/Support/BinaryStreamWriter.h"
17
18
#include " llvm/Support/CommandLine.h"
18
19
#include " llvm/Support/Errc.h"
19
20
21
+ #define DEBUG_TYPE " bolt-linux"
22
+
20
23
using namespace llvm ;
21
24
using namespace bolt ;
22
25
@@ -48,20 +51,25 @@ struct ORCState {
48
51
bool operator !=(const ORCState &Other) const { return !(*this == Other); }
49
52
};
50
53
54
+ // / Section terminator ORC entry.
55
+ static ORCState NullORC = {0 , 0 , 0 };
56
+
51
57
// / Basic printer for ORC entry. It does not provide the same level of
52
58
// / information as objtool (for now).
53
59
inline raw_ostream &operator <<(raw_ostream &OS, const ORCState &E) {
54
- if (opts::PrintORC)
60
+ if (!opts::PrintORC)
61
+ return OS;
62
+ if (E != NullORC)
55
63
OS << format (" {sp: %d, bp: %d, info: 0x%x}" , E.SPOffset , E.BPOffset ,
56
64
E.Info );
65
+ else
66
+ OS << " {terminator}" ;
67
+
57
68
return OS;
58
69
}
59
70
60
71
namespace {
61
72
62
- // / Section terminator ORC entry.
63
- static ORCState NullORC = {0 , 0 , 0 };
64
-
65
73
class LinuxKernelRewriter final : public MetadataRewriter {
66
74
// / Linux Kernel special sections point to a specific instruction in many
67
75
// / cases. Unlike SDTMarkerInfo, these markers can come from different
@@ -102,6 +110,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
102
110
using ORCListType = std::vector<ORCListEntry>;
103
111
ORCListType ORCEntries;
104
112
113
+ // / Number of entries in the input file ORC sections.
114
+ uint64_t NumORCEntries = 0 ;
115
+
105
116
// / Insert an LKMarker for a given code pointer \p PC from a non-code section
106
117
// / \p SectionName.
107
118
void insertLKMarker (uint64_t PC, uint64_t SectionOffset,
@@ -207,8 +218,6 @@ void LinuxKernelRewriter::insertLKMarker(uint64_t PC, uint64_t SectionOffset,
207
218
}
208
219
209
220
void LinuxKernelRewriter::processLKSections () {
210
- assert (BC.IsLinuxKernel && " Linux kernel binary expected." );
211
-
212
221
processLKExTable ();
213
222
processLKPCIFixup ();
214
223
processLKKSymtab ();
@@ -464,10 +473,9 @@ Error LinuxKernelRewriter::readORCTables() {
464
473
return createStringError (errc::executable_format_error,
465
474
" missing ORC section" );
466
475
467
- const uint64_t NumEntries =
468
- ORCUnwindIPSection->getSize () / ORC_UNWIND_IP_ENTRY_SIZE;
469
- if (ORCUnwindSection->getSize () != NumEntries * ORC_UNWIND_ENTRY_SIZE ||
470
- ORCUnwindIPSection->getSize () != NumEntries * ORC_UNWIND_IP_ENTRY_SIZE)
476
+ NumORCEntries = ORCUnwindIPSection->getSize () / ORC_UNWIND_IP_ENTRY_SIZE;
477
+ if (ORCUnwindSection->getSize () != NumORCEntries * ORC_UNWIND_ENTRY_SIZE ||
478
+ ORCUnwindIPSection->getSize () != NumORCEntries * ORC_UNWIND_IP_ENTRY_SIZE)
471
479
return createStringError (errc::executable_format_error,
472
480
" ORC entries number mismatch detected" );
473
481
@@ -481,7 +489,7 @@ Error LinuxKernelRewriter::readORCTables() {
481
489
DataExtractor::Cursor ORCCursor (0 );
482
490
DataExtractor::Cursor IPCursor (0 );
483
491
uint64_t PrevIP = 0 ;
484
- for (uint32_t Index = 0 ; Index < NumEntries ; ++Index) {
492
+ for (uint32_t Index = 0 ; Index < NumORCEntries ; ++Index) {
485
493
const uint64_t IP =
486
494
IPSectionAddress + IPCursor.tell () + (int32_t )IPDE.getU32 (IPCursor);
487
495
@@ -505,35 +513,31 @@ Error LinuxKernelRewriter::readORCTables() {
505
513
Entry.ORC .SPOffset = (int16_t )OrcDE.getU16 (ORCCursor);
506
514
Entry.ORC .BPOffset = (int16_t )OrcDE.getU16 (ORCCursor);
507
515
Entry.ORC .Info = (int16_t )OrcDE.getU16 (ORCCursor);
516
+ Entry.BF = nullptr ;
508
517
509
518
// Consume the status of the cursor.
510
519
if (!ORCCursor)
511
520
return createStringError (errc::executable_format_error,
512
521
" out of bounds while reading ORC" );
513
522
523
+ if (Entry.ORC == NullORC)
524
+ continue ;
525
+
514
526
BinaryFunction *&BF = Entry.BF ;
515
527
BF = BC.getBinaryFunctionContainingAddress (IP, /* CheckPastEnd*/ true );
516
528
517
529
// If the entry immediately pointing past the end of the function is not
518
530
// the terminator entry, then it does not belong to this function.
519
- if (BF && BF->getAddress () + BF->getSize () == IP && Entry. ORC != NullORC )
531
+ if (BF && BF->getAddress () + BF->getSize () == IP)
520
532
BF = 0 ;
521
533
522
- // If terminator entry points to the start of the function, then it belongs
523
- // to a different function that contains the previous IP.
524
- if (BF && BF->getAddress () == IP && Entry.ORC == NullORC)
525
- BF = BC.getBinaryFunctionContainingAddress (IP - 1 );
526
-
527
534
if (!BF) {
528
535
if (opts::Verbosity)
529
536
errs () << " BOLT-WARNING: no binary function found matching ORC 0x"
530
537
<< Twine::utohexstr (IP) << " : " << Entry.ORC << ' \n ' ;
531
538
continue ;
532
539
}
533
540
534
- if (Entry.ORC == NullORC)
535
- continue ;
536
-
537
541
BF->setHasORC (true );
538
542
539
543
if (!BF->hasInstructions ())
@@ -556,12 +560,46 @@ Error LinuxKernelRewriter::readORCTables() {
556
560
BC.MIB ->addAnnotation (*Inst, " ORC" , Entry.ORC );
557
561
}
558
562
559
- // Older kernels could contain unsorted tables in the file as the tables were
560
- // sorted during boot time.
563
+ if (opts::DumpORC) {
564
+ outs () << " BOLT-INFO: ORC unwind information:\n " ;
565
+ for (const ORCListEntry &E : ORCEntries) {
566
+ outs () << " 0x" << Twine::utohexstr (E.IP ) << " : " << E.ORC ;
567
+ if (E.BF )
568
+ outs () << " : " << *E.BF ;
569
+ outs () << ' \n ' ;
570
+ }
571
+ }
572
+
573
+ // Add entries for functions that don't have explicit ORC info at the start.
574
+ // We'll have the correct info for them even if ORC for the preceding function
575
+ // changes.
576
+ ORCListType NewEntries;
577
+ for (BinaryFunction &BF : llvm::make_second_range (BC.getBinaryFunctions ())) {
578
+ auto It = llvm::partition_point (ORCEntries, [&](const ORCListEntry &E) {
579
+ return E.IP <= BF.getAddress ();
580
+ });
581
+ if (It != ORCEntries.begin ())
582
+ --It;
583
+
584
+ if (It->BF == &BF)
585
+ continue ;
586
+
587
+ if (It->ORC == NullORC && It->IP == BF.getAddress ()) {
588
+ assert (!It->BF );
589
+ It->BF = &BF;
590
+ continue ;
591
+ }
592
+
593
+ NewEntries.push_back ({BF.getAddress (), &BF, It->ORC });
594
+ if (It->ORC != NullORC)
595
+ BF.setHasORC (true );
596
+ }
597
+
598
+ llvm::copy (NewEntries, std::back_inserter (ORCEntries));
561
599
llvm::sort (ORCEntries);
562
600
563
601
if (opts::DumpORC) {
564
- outs () << " BOLT-INFO: ORC unwind information:\n " ;
602
+ outs () << " BOLT-INFO: amended ORC unwind information:\n " ;
565
603
for (const ORCListEntry &E : ORCEntries) {
566
604
outs () << " 0x" << Twine::utohexstr (E.IP ) << " : " << E.ORC ;
567
605
if (E.BF )
@@ -593,20 +631,26 @@ Error LinuxKernelRewriter::processORCPostCFG() {
593
631
continue ;
594
632
}
595
633
596
- // In case there was no ORC entry that matched the function start
597
- // address, we need to propagate ORC state from the previous entry.
634
+ // Get state for the start of the function.
598
635
if (!CurrentState) {
599
636
auto It =
600
637
llvm::partition_point (ORCEntries, [&](const ORCListEntry &E) {
601
- return E.IP < BF.getAddress ();
638
+ return E.IP <= BF.getAddress ();
602
639
});
603
640
if (It != ORCEntries.begin ())
604
- It = std::prev (It);
641
+ --It;
642
+
643
+ if (It->IP != BF.getAddress () || It->BF != &BF)
644
+ dbgs () << " 0x" << Twine::utohexstr (It->IP ) << " : " << BF << ' \n ' ;
645
+ assert (It->IP == BF.getAddress () && (!It->BF || It->BF == &BF) &&
646
+ " Function entry expected." );
605
647
606
648
if (It->ORC == NullORC && BF.hasORC ())
607
649
errs () << " BOLT-WARNING: ORC unwind info excludes prologue for "
608
650
<< BF << ' \n ' ;
609
651
652
+ It->BF = &BF;
653
+
610
654
CurrentState = It->ORC ;
611
655
if (It->ORC != NullORC)
612
656
BF.setHasORC (true );
@@ -623,9 +667,121 @@ Error LinuxKernelRewriter::processORCPostCFG() {
623
667
}
624
668
625
669
Error LinuxKernelRewriter::rewriteORCTables () {
626
- // TODO:
670
+ if (!ORCUnwindSection || !ORCUnwindIPSection)
671
+ return Error::success ();
672
+
673
+ // Update ORC sections in-place. As we change the code, the number of ORC
674
+ // entries may increase for some functions. However, as we remove terminator
675
+ // redundancy (see below), more space is freed up and we should always be able
676
+ // to fit new ORC tables in the reserved space.
677
+ auto createInPlaceWriter = [&](BinarySection &Section) -> BinaryStreamWriter {
678
+ const size_t Size = Section.getSize ();
679
+ uint8_t *NewContents = new uint8_t [Size ];
680
+ Section.updateContents (NewContents, Size );
681
+ Section.setOutputFileOffset (Section.getInputFileOffset ());
682
+ return BinaryStreamWriter ({NewContents, Size }, BC.AsmInfo ->isLittleEndian ()
683
+ ? endianness::little
684
+ : endianness::big);
685
+ };
686
+ BinaryStreamWriter UnwindWriter = createInPlaceWriter (*ORCUnwindSection);
687
+ BinaryStreamWriter UnwindIPWriter = createInPlaceWriter (*ORCUnwindIPSection);
688
+
689
+ uint64_t NumEmitted = 0 ;
690
+ std::optional<ORCState> LastEmittedORC;
691
+ auto emitORCEntry = [&](const uint64_t IP, const ORCState &ORC,
692
+ MCSymbol *Label = 0 , bool Force = false ) -> Error {
693
+ if (LastEmittedORC && ORC == *LastEmittedORC && !Force)
694
+ return Error::success ();
695
+
696
+ LastEmittedORC = ORC;
697
+
698
+ if (++NumEmitted > NumORCEntries)
699
+ return createStringError (errc::executable_format_error,
700
+ " exceeded the number of allocated ORC entries" );
701
+
702
+ if (Label)
703
+ ORCUnwindIPSection->addRelocation (UnwindIPWriter.getOffset (), Label,
704
+ Relocation::getPC32 (), /* Addend*/ 0 );
705
+
706
+ const int32_t IPValue =
707
+ IP - ORCUnwindIPSection->getAddress () - UnwindIPWriter.getOffset ();
708
+ if (Error E = UnwindIPWriter.writeInteger (IPValue))
709
+ return E;
710
+
711
+ if (Error E = UnwindWriter.writeInteger (ORC.SPOffset ))
712
+ return E;
713
+ if (Error E = UnwindWriter.writeInteger (ORC.BPOffset ))
714
+ return E;
715
+ if (Error E = UnwindWriter.writeInteger (ORC.Info ))
716
+ return E;
717
+
718
+ return Error::success ();
719
+ };
720
+
721
+ // Emit new ORC entries for an emitted function.
722
+ auto emitORC = [&](const BinaryFunction &BF) -> Error {
723
+ assert (!BF.isSplit () && " Split functions not supported by ORC writer yet." );
724
+
725
+ ORCState CurrentState = NullORC;
726
+ for (BinaryBasicBlock *BB : BF.getLayout ().blocks ()) {
727
+ for (MCInst &Inst : *BB) {
728
+ ErrorOr<ORCState> ErrorOrState =
729
+ BC.MIB ->tryGetAnnotationAs <ORCState>(Inst, " ORC" );
730
+ if (!ErrorOrState || *ErrorOrState == CurrentState)
731
+ continue ;
732
+
733
+ // Issue label for the instruction.
734
+ MCSymbol *Label = BC.MIB ->getLabel (Inst);
735
+ if (!Label) {
736
+ Label = BC.Ctx ->createTempSymbol (" __ORC_" );
737
+ BC.MIB ->setLabel (Inst, Label);
738
+ }
739
+
740
+ if (Error E = emitORCEntry (0 , *ErrorOrState, Label))
741
+ return E;
742
+
743
+ CurrentState = *ErrorOrState;
744
+ }
745
+ }
746
+
747
+ return Error::success ();
748
+ };
749
+
750
+ for (ORCListEntry &Entry : ORCEntries) {
751
+ // Emit original entries for functions that we haven't modified.
752
+ if (!Entry.BF || !BC.shouldEmit (*Entry.BF )) {
753
+ // Emit terminator only if it marks the start of a function.
754
+ if (Entry.ORC == NullORC && !Entry.BF )
755
+ continue ;
756
+ if (Error E = emitORCEntry (Entry.IP , Entry.ORC ))
757
+ return E;
758
+ continue ;
759
+ }
760
+
761
+ // Emit all ORC entries for a function referenced by an entry and skip over
762
+ // the rest of entries for this function by resetting its ORC attribute.
763
+ if (Entry.BF ->hasORC ()) {
764
+ if (Error E = emitORC (*Entry.BF ))
765
+ return E;
766
+ Entry.BF ->setHasORC (false );
767
+ }
768
+ }
769
+
770
+ LLVM_DEBUG (dbgs () << " BOLT-DEBUG: emitted " << NumEmitted
771
+ << " ORC entries\n " );
772
+
773
+ // Replicate terminator entry at the end of sections to match the original
774
+ // table sizes.
775
+ const BinaryFunction &LastBF = BC.getBinaryFunctions ().rbegin ()->second ;
776
+ const uint64_t LastIP = LastBF.getAddress () + LastBF.getMaxSize ();
777
+ while (UnwindWriter.bytesRemaining ()) {
778
+ if (Error E = emitORCEntry (LastIP, NullORC, nullptr , /* Force*/ true ))
779
+ return E;
780
+ }
781
+
627
782
return Error::success ();
628
783
}
784
+
629
785
} // namespace
630
786
631
787
std::unique_ptr<MetadataRewriter>
0 commit comments