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