Skip to content

Commit f51ade2

Browse files
authored
[BOLT] Add reading support for Linux kernel .parainstructions section (llvm#83965)
Read .parainstruction section and mark call instructions with ParaSite annotations.
1 parent 201572e commit f51ade2

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

bolt/lib/Rewrite/LinuxKernelRewriter.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ static cl::opt<bool>
3636
DumpORC("dump-orc", cl::desc("dump raw ORC unwind information (sorted)"),
3737
cl::init(false), cl::Hidden, cl::cat(BoltCategory));
3838

39+
static cl::opt<bool> DumpParavirtualPatchSites(
40+
"dump-para-sites", cl::desc("dump Linux kernel paravitual patch sites"),
41+
cl::init(false), cl::Hidden, cl::cat(BoltCategory));
42+
3943
static cl::opt<bool> DumpStaticCalls("dump-static-calls",
4044
cl::desc("dump Linux kernel static calls"),
4145
cl::init(false), cl::Hidden,
@@ -147,6 +151,12 @@ class LinuxKernelRewriter final : public MetadataRewriter {
147151
/// Functions with exception handling code.
148152
DenseSet<BinaryFunction *> FunctionsWithExceptions;
149153

154+
/// Section with paravirtual patch sites.
155+
ErrorOr<BinarySection &> ParavirtualPatchSection = std::errc::bad_address;
156+
157+
/// Alignment of paravirtual patch structures.
158+
static constexpr size_t PARA_PATCH_ALIGN = 8;
159+
150160
/// Insert an LKMarker for a given code pointer \p PC from a non-code section
151161
/// \p SectionName.
152162
void insertLKMarker(uint64_t PC, uint64_t SectionOffset,
@@ -187,6 +197,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
187197
Error readExceptionTable();
188198
Error rewriteExceptionTable();
189199

200+
/// Paravirtual instruction patch sites.
201+
Error readParaInstructions();
202+
190203
/// Mark instructions referenced by kernel metadata.
191204
Error markInstructions();
192205

@@ -208,6 +221,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
208221
if (Error E = readExceptionTable())
209222
return E;
210223

224+
if (Error E = readParaInstructions())
225+
return E;
226+
211227
return Error::success();
212228
}
213229

@@ -1013,6 +1029,74 @@ Error LinuxKernelRewriter::rewriteExceptionTable() {
10131029
return Error::success();
10141030
}
10151031

1032+
/// .parainsrtuctions section contains information for patching parvirtual call
1033+
/// instructions during runtime. The entries in the section are in the form:
1034+
///
1035+
/// struct paravirt_patch_site {
1036+
/// u8 *instr; /* original instructions */
1037+
/// u8 type; /* type of this instruction */
1038+
/// u8 len; /* length of original instruction */
1039+
/// };
1040+
///
1041+
/// Note that the structures are aligned at 8-byte boundary.
1042+
Error LinuxKernelRewriter::readParaInstructions() {
1043+
ParavirtualPatchSection = BC.getUniqueSectionByName(".parainstructions");
1044+
if (!ParavirtualPatchSection)
1045+
return Error::success();
1046+
1047+
DataExtractor DE = DataExtractor(ParavirtualPatchSection->getContents(),
1048+
BC.AsmInfo->isLittleEndian(),
1049+
BC.AsmInfo->getCodePointerSize());
1050+
uint32_t EntryID = 0;
1051+
DataExtractor::Cursor Cursor(0);
1052+
while (Cursor && !DE.eof(Cursor)) {
1053+
const uint64_t NextOffset = alignTo(Cursor.tell(), Align(PARA_PATCH_ALIGN));
1054+
if (!DE.isValidOffset(NextOffset))
1055+
break;
1056+
1057+
Cursor.seek(NextOffset);
1058+
1059+
const uint64_t InstrLocation = DE.getU64(Cursor);
1060+
const uint8_t Type = DE.getU8(Cursor);
1061+
const uint8_t Len = DE.getU8(Cursor);
1062+
1063+
if (!Cursor)
1064+
return createStringError(errc::executable_format_error,
1065+
"out of bounds while reading .parainstructions");
1066+
1067+
++EntryID;
1068+
1069+
if (opts::DumpParavirtualPatchSites) {
1070+
BC.outs() << "Paravirtual patch site: " << EntryID << '\n';
1071+
BC.outs() << "\tInstr: 0x" << Twine::utohexstr(InstrLocation)
1072+
<< "\n\tType: 0x" << Twine::utohexstr(Type) << "\n\tLen: 0x"
1073+
<< Twine::utohexstr(Len) << '\n';
1074+
}
1075+
1076+
BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(InstrLocation);
1077+
if (!BF && opts::Verbosity) {
1078+
BC.outs() << "BOLT-INFO: no function matches address 0x"
1079+
<< Twine::utohexstr(InstrLocation)
1080+
<< " referenced by paravirutal patch site\n";
1081+
}
1082+
1083+
if (BF && BC.shouldEmit(*BF)) {
1084+
MCInst *Inst =
1085+
BF->getInstructionAtOffset(InstrLocation - BF->getAddress());
1086+
if (!Inst)
1087+
return createStringError(errc::executable_format_error,
1088+
"no instruction at address 0x%" PRIx64
1089+
" in paravirtual call site %d",
1090+
InstrLocation, EntryID);
1091+
BC.MIB->addAnnotation(*Inst, "ParaSite", EntryID);
1092+
}
1093+
}
1094+
1095+
BC.outs() << "BOLT-INFO: parsed " << EntryID << " paravirtual patch sites\n";
1096+
1097+
return Error::success();
1098+
}
1099+
10161100
} // namespace
10171101

10181102
std::unique_ptr<MetadataRewriter>
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# REQUIRES: system-linux
2+
3+
## Check that BOLT correctly parses the Linux kernel .parainstructions section.
4+
5+
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
6+
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
7+
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
8+
9+
## Verify paravirtual bindings to instructions.
10+
11+
# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s
12+
13+
# CHECK: BOLT-INFO: Linux kernel binary detected
14+
# CHECK: BOLT-INFO: parsed 2 paravirtual patch sites
15+
16+
.rodata
17+
fptr:
18+
.quad 0
19+
20+
.text
21+
.globl _start
22+
.type _start, %function
23+
_start:
24+
# CHECK: Binary Function "_start"
25+
nop
26+
.L1:
27+
call *fptr(%rip)
28+
# CHECK: call
29+
# CHECK-SAME: ParaSite: 1
30+
nop
31+
.L2:
32+
call *fptr(%rip)
33+
# CHECK: call
34+
# CHECK-SAME: ParaSite: 2
35+
ret
36+
.size _start, .-_start
37+
38+
39+
## Paravirtual patch sites.
40+
.section .parainstructions,"a",@progbits
41+
42+
.balign 8
43+
.quad .L1 # instruction
44+
.byte 1 # type
45+
.byte 7 # length
46+
47+
.balign 8
48+
.quad .L2 # instruction
49+
.byte 1 # type
50+
.byte 7 # length
51+
52+
## Fake Linux Kernel sections.
53+
.section __ksymtab,"a",@progbits
54+
.section __ksymtab_gpl,"a",@progbits

0 commit comments

Comments
 (0)