Skip to content

Commit 540893e

Browse files
authored
[BOLT] Add auto parsing for Linux kernel .altinstructions (#95068)
.altinstructions section contains a list of structures where fields can have different sizes while other fields could be present or not depending on the kernel version. Add automatic detection of such variations and use it by default. The user can still overwrite the automatic detection with `--alt-inst-has-padlen` and `--alt-inst-feature-size` options.
1 parent 56f668c commit 540893e

File tree

2 files changed

+80
-12
lines changed

2 files changed

+80
-12
lines changed

bolt/lib/Rewrite/LinuxKernelRewriter.cpp

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ class LinuxKernelRewriter final : public MetadataRewriter {
273273

274274
/// Handle alternative instruction info from .altinstructions.
275275
Error readAltInstructions();
276+
Error tryReadAltInstructions(uint32_t AltInstFeatureSize,
277+
bool AltInstHasPadLen, bool ParseOnly);
276278
Error rewriteAltInstructions();
277279

278280
/// Read .pci_fixup
@@ -1319,12 +1321,69 @@ Error LinuxKernelRewriter::rewriteBugTable() {
13191321
/// u8 padlen; // present in older kernels
13201322
/// } __packed;
13211323
///
1322-
/// Note the structures is packed.
1324+
/// Note that the structure is packed.
1325+
///
1326+
/// Since the size of the "feature" field could be either u16 or u32, and
1327+
/// "padlen" presence is unknown, we attempt to parse .altinstructions section
1328+
/// using all possible combinations (four at this time). Since we validate the
1329+
/// contents of the section and its size, the detection works quite well.
1330+
/// Still, we leave the user the opportunity to specify these features on the
1331+
/// command line and skip the guesswork.
13231332
Error LinuxKernelRewriter::readAltInstructions() {
13241333
AltInstrSection = BC.getUniqueSectionByName(".altinstructions");
13251334
if (!AltInstrSection)
13261335
return Error::success();
13271336

1337+
// Presence of "padlen" field.
1338+
std::vector<bool> PadLenVariants;
1339+
if (opts::AltInstHasPadLen.getNumOccurrences())
1340+
PadLenVariants.push_back(opts::AltInstHasPadLen);
1341+
else
1342+
PadLenVariants = {false, true};
1343+
1344+
// Size (in bytes) variants of "feature" field.
1345+
std::vector<uint32_t> FeatureSizeVariants;
1346+
if (opts::AltInstFeatureSize.getNumOccurrences())
1347+
FeatureSizeVariants.push_back(opts::AltInstFeatureSize);
1348+
else
1349+
FeatureSizeVariants = {2, 4};
1350+
1351+
for (bool AltInstHasPadLen : PadLenVariants) {
1352+
for (uint32_t AltInstFeatureSize : FeatureSizeVariants) {
1353+
LLVM_DEBUG({
1354+
dbgs() << "BOLT-DEBUG: trying AltInstHasPadLen = " << AltInstHasPadLen
1355+
<< "; AltInstFeatureSize = " << AltInstFeatureSize << ";\n";
1356+
});
1357+
if (Error E = tryReadAltInstructions(AltInstFeatureSize, AltInstHasPadLen,
1358+
/*ParseOnly*/ true)) {
1359+
consumeError(std::move(E));
1360+
continue;
1361+
}
1362+
1363+
LLVM_DEBUG(dbgs() << "Matched .altinstructions format\n");
1364+
1365+
if (!opts::AltInstHasPadLen.getNumOccurrences())
1366+
BC.outs() << "BOLT-INFO: setting --" << opts::AltInstHasPadLen.ArgStr
1367+
<< '=' << AltInstHasPadLen << '\n';
1368+
1369+
if (!opts::AltInstFeatureSize.getNumOccurrences())
1370+
BC.outs() << "BOLT-INFO: setting --" << opts::AltInstFeatureSize.ArgStr
1371+
<< '=' << AltInstFeatureSize << '\n';
1372+
1373+
return tryReadAltInstructions(AltInstFeatureSize, AltInstHasPadLen,
1374+
/*ParseOnly*/ false);
1375+
}
1376+
}
1377+
1378+
// We couldn't match the format. Read again to properly propagate the error
1379+
// to the user.
1380+
return tryReadAltInstructions(opts::AltInstFeatureSize,
1381+
opts::AltInstHasPadLen, /*ParseOnly*/ false);
1382+
}
1383+
1384+
Error LinuxKernelRewriter::tryReadAltInstructions(uint32_t AltInstFeatureSize,
1385+
bool AltInstHasPadLen,
1386+
bool ParseOnly) {
13281387
const uint64_t Address = AltInstrSection->getAddress();
13291388
DataExtractor DE = DataExtractor(AltInstrSection->getContents(),
13301389
BC.AsmInfo->isLittleEndian(),
@@ -1336,12 +1395,12 @@ Error LinuxKernelRewriter::readAltInstructions() {
13361395
Address + Cursor.tell() + (int32_t)DE.getU32(Cursor);
13371396
const uint64_t AltInstAddress =
13381397
Address + Cursor.tell() + (int32_t)DE.getU32(Cursor);
1339-
const uint64_t Feature = DE.getUnsigned(Cursor, opts::AltInstFeatureSize);
1398+
const uint64_t Feature = DE.getUnsigned(Cursor, AltInstFeatureSize);
13401399
const uint8_t OrgSize = DE.getU8(Cursor);
13411400
const uint8_t AltSize = DE.getU8(Cursor);
13421401

13431402
// Older kernels may have the padlen field.
1344-
const uint8_t PadLen = opts::AltInstHasPadLen ? DE.getU8(Cursor) : 0;
1403+
const uint8_t PadLen = AltInstHasPadLen ? DE.getU8(Cursor) : 0;
13451404

13461405
if (!Cursor)
13471406
return createStringError(
@@ -1358,7 +1417,7 @@ Error LinuxKernelRewriter::readAltInstructions() {
13581417
<< "\n\tFeature: 0x" << Twine::utohexstr(Feature)
13591418
<< "\n\tOrgSize: " << (int)OrgSize
13601419
<< "\n\tAltSize: " << (int)AltSize << '\n';
1361-
if (opts::AltInstHasPadLen)
1420+
if (AltInstHasPadLen)
13621421
BC.outs() << "\tPadLen: " << (int)PadLen << '\n';
13631422
}
13641423

@@ -1375,7 +1434,7 @@ Error LinuxKernelRewriter::readAltInstructions() {
13751434

13761435
BinaryFunction *AltBF =
13771436
BC.getBinaryFunctionContainingAddress(AltInstAddress);
1378-
if (AltBF && BC.shouldEmit(*AltBF)) {
1437+
if (!ParseOnly && AltBF && BC.shouldEmit(*AltBF)) {
13791438
BC.errs()
13801439
<< "BOLT-WARNING: alternative instruction sequence found in function "
13811440
<< *AltBF << '\n';
@@ -1397,6 +1456,9 @@ Error LinuxKernelRewriter::readAltInstructions() {
13971456
" referenced by .altinstructions entry %d",
13981457
OrgInstAddress, EntryID);
13991458

1459+
if (ParseOnly)
1460+
continue;
1461+
14001462
// There could be more than one alternative instruction sequences for the
14011463
// same original instruction. Annotate each alternative separately.
14021464
std::string AnnotationName = "AltInst";

bolt/test/X86/linux-alt-instruction.s

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,30 @@
1212
## Older kernels used to have padlen field in alt_instr. Check compatibility.
1313

1414
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown --defsym PADLEN=1 \
15-
# RUN: %s -o %t.o
16-
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
15+
# RUN: %s -o %t.padlen.o
16+
# RUN: %clang %cflags -nostdlib %t.padlen.o -o %t.padlen.exe \
1717
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
18-
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-has-padlen -o %t.out \
18+
# RUN: llvm-bolt %t.padlen.exe --print-normalized --alt-inst-has-padlen -o %t.padlen.out \
1919
# RUN: | FileCheck %s
2020

2121
## Check with a larger size of "feature" field in alt_instr.
2222

2323
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
24-
# RUN: --defsym FEATURE_SIZE_4=1 %s -o %t.o
25-
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
24+
# RUN: --defsym FEATURE_SIZE_4=1 %s -o %t.fs4.o
25+
# RUN: %clang %cflags -nostdlib %t.fs4.o -o %t.fs4.exe \
2626
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
27-
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=4 -o %t.out \
27+
# RUN: llvm-bolt %t.fs4.exe --print-normalized --alt-inst-feature-size=4 -o %t.fs4.out \
2828
# RUN: | FileCheck %s
2929

3030
## Check that out-of-bounds read is handled properly.
3131

32-
# RUN: not llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=2 -o %t.out
32+
# RUN: not llvm-bolt %t.fs4.exe --alt-inst-feature-size=2 -o %t.fs4.out
33+
34+
## Check that BOLT automatically detects structure fields in .altinstructions.
35+
36+
# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s
37+
# RUN: llvm-bolt %t.exe --print-normalized -o %t.padlen.out | FileCheck %s
38+
# RUN: llvm-bolt %t.exe --print-normalized -o %t.fs4.out | FileCheck %s
3339

3440
# CHECK: BOLT-INFO: Linux kernel binary detected
3541
# CHECK: BOLT-INFO: parsed 2 alternative instruction entries

0 commit comments

Comments
 (0)