Skip to content

Commit 871479d

Browse files
committed
merge main into amd-staging
Change-Id: I8b08d22390bd9e8ec6cccee0cafc8faaabf356c2
2 parents 441c5fc + a8fdc93 commit 871479d

File tree

115 files changed

+2756
-863
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+2756
-863
lines changed

bolt/lib/Rewrite/LinuxKernelRewriter.cpp

Lines changed: 196 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414
#include "bolt/Rewrite/MetadataRewriter.h"
1515
#include "bolt/Rewrite/MetadataRewriters.h"
1616
#include "bolt/Utils/CommandLineOpts.h"
17+
#include "llvm/Support/BinaryStreamWriter.h"
1718
#include "llvm/Support/CommandLine.h"
19+
#include "llvm/Support/Debug.h"
1820
#include "llvm/Support/Errc.h"
1921

22+
#define DEBUG_TYPE "bolt-linux"
23+
2024
using namespace llvm;
2125
using namespace bolt;
2226

@@ -48,20 +52,25 @@ struct ORCState {
4852
bool operator!=(const ORCState &Other) const { return !(*this == Other); }
4953
};
5054

55+
/// Section terminator ORC entry.
56+
static ORCState NullORC = {0, 0, 0};
57+
5158
/// Basic printer for ORC entry. It does not provide the same level of
5259
/// information as objtool (for now).
5360
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)
5564
OS << format("{sp: %d, bp: %d, info: 0x%x}", E.SPOffset, E.BPOffset,
5665
E.Info);
66+
else
67+
OS << "{terminator}";
68+
5769
return OS;
5870
}
5971

6072
namespace {
6173

62-
/// Section terminator ORC entry.
63-
static ORCState NullORC = {0, 0, 0};
64-
6574
class LinuxKernelRewriter final : public MetadataRewriter {
6675
/// Linux Kernel special sections point to a specific instruction in many
6776
/// cases. Unlike SDTMarkerInfo, these markers can come from different
@@ -90,6 +99,8 @@ class LinuxKernelRewriter final : public MetadataRewriter {
9099
BinaryFunction *BF; /// Binary function corresponding to the entry.
91100
ORCState ORC; /// Stack unwind info in ORC format.
92101

102+
/// ORC entries are sorted by their IPs. Terminator entries (NullORC)
103+
/// should precede other entries with the same address.
93104
bool operator<(const ORCListEntry &Other) const {
94105
if (IP < Other.IP)
95106
return 1;
@@ -102,6 +113,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
102113
using ORCListType = std::vector<ORCListEntry>;
103114
ORCListType ORCEntries;
104115

116+
/// Number of entries in the input file ORC sections.
117+
uint64_t NumORCEntries = 0;
118+
105119
/// Insert an LKMarker for a given code pointer \p PC from a non-code section
106120
/// \p SectionName.
107121
void insertLKMarker(uint64_t PC, uint64_t SectionOffset,
@@ -207,8 +221,6 @@ void LinuxKernelRewriter::insertLKMarker(uint64_t PC, uint64_t SectionOffset,
207221
}
208222

209223
void LinuxKernelRewriter::processLKSections() {
210-
assert(BC.IsLinuxKernel && "Linux kernel binary expected.");
211-
212224
processLKExTable();
213225
processLKPCIFixup();
214226
processLKKSymtab();
@@ -464,10 +476,9 @@ Error LinuxKernelRewriter::readORCTables() {
464476
return createStringError(errc::executable_format_error,
465477
"missing ORC section");
466478

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)
471482
return createStringError(errc::executable_format_error,
472483
"ORC entries number mismatch detected");
473484

@@ -481,7 +492,7 @@ Error LinuxKernelRewriter::readORCTables() {
481492
DataExtractor::Cursor ORCCursor(0);
482493
DataExtractor::Cursor IPCursor(0);
483494
uint64_t PrevIP = 0;
484-
for (uint32_t Index = 0; Index < NumEntries; ++Index) {
495+
for (uint32_t Index = 0; Index < NumORCEntries; ++Index) {
485496
const uint64_t IP =
486497
IPSectionAddress + IPCursor.tell() + (int32_t)IPDE.getU32(IPCursor);
487498

@@ -505,35 +516,31 @@ Error LinuxKernelRewriter::readORCTables() {
505516
Entry.ORC.SPOffset = (int16_t)OrcDE.getU16(ORCCursor);
506517
Entry.ORC.BPOffset = (int16_t)OrcDE.getU16(ORCCursor);
507518
Entry.ORC.Info = (int16_t)OrcDE.getU16(ORCCursor);
519+
Entry.BF = nullptr;
508520

509521
// Consume the status of the cursor.
510522
if (!ORCCursor)
511523
return createStringError(errc::executable_format_error,
512524
"out of bounds while reading ORC");
513525

526+
if (Entry.ORC == NullORC)
527+
continue;
528+
514529
BinaryFunction *&BF = Entry.BF;
515530
BF = BC.getBinaryFunctionContainingAddress(IP, /*CheckPastEnd*/ true);
516531

517532
// If the entry immediately pointing past the end of the function is not
518533
// 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)
520535
BF = 0;
521536

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-
527537
if (!BF) {
528538
if (opts::Verbosity)
529539
errs() << "BOLT-WARNING: no binary function found matching ORC 0x"
530540
<< Twine::utohexstr(IP) << ": " << Entry.ORC << '\n';
531541
continue;
532542
}
533543

534-
if (Entry.ORC == NullORC)
535-
continue;
536-
537544
BF->setHasORC(true);
538545

539546
if (!BF->hasInstructions())
@@ -556,9 +563,7 @@ Error LinuxKernelRewriter::readORCTables() {
556563
BC.MIB->addAnnotation(*Inst, "ORC", Entry.ORC);
557564
}
558565

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";
562567

563568
if (opts::DumpORC) {
564569
outs() << "BOLT-INFO: ORC unwind information:\n";
@@ -570,10 +575,51 @@ Error LinuxKernelRewriter::readORCTables() {
570575
}
571576
}
572577

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+
573616
return Error::success();
574617
}
575618

576619
Error LinuxKernelRewriter::processORCPostCFG() {
620+
if (!NumORCEntries)
621+
return Error::success();
622+
577623
// Propagate ORC to the rest of the function. We can annotate every
578624
// instruction in every function, but to minimize the overhead, we annotate
579625
// the first instruction in every basic block to reflect the state at the
@@ -593,19 +639,28 @@ Error LinuxKernelRewriter::processORCPostCFG() {
593639
continue;
594640
}
595641

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.
598643
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.
599648
auto It =
600649
llvm::partition_point(ORCEntries, [&](const ORCListEntry &E) {
601-
return E.IP < BF.getAddress();
650+
return E.IP <= BF.getAddress();
602651
});
603652
if (It != ORCEntries.begin())
604-
It = std::prev(It);
653+
--It;
605654

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()) {
607659
errs() << "BOLT-WARNING: ORC unwind info excludes prologue for "
608660
<< BF << '\n';
661+
}
662+
663+
It->BF = &BF;
609664

610665
CurrentState = It->ORC;
611666
if (It->ORC != NullORC)
@@ -623,9 +678,121 @@ Error LinuxKernelRewriter::processORCPostCFG() {
623678
}
624679

625680
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+
627793
return Error::success();
628794
}
795+
629796
} // namespace
630797

631798
std::unique_ptr<MetadataRewriter>

0 commit comments

Comments
 (0)