@@ -273,6 +273,8 @@ class LinuxKernelRewriter final : public MetadataRewriter {
273
273
274
274
// / Handle alternative instruction info from .altinstructions.
275
275
Error readAltInstructions ();
276
+ Error tryReadAltInstructions (uint32_t AltInstFeatureSize,
277
+ bool AltInstHasPadLen, bool ParseOnly);
276
278
Error rewriteAltInstructions ();
277
279
278
280
// / Read .pci_fixup
@@ -1319,12 +1321,69 @@ Error LinuxKernelRewriter::rewriteBugTable() {
1319
1321
// / u8 padlen; // present in older kernels
1320
1322
// / } __packed;
1321
1323
// /
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.
1323
1332
Error LinuxKernelRewriter::readAltInstructions () {
1324
1333
AltInstrSection = BC.getUniqueSectionByName (" .altinstructions" );
1325
1334
if (!AltInstrSection)
1326
1335
return Error::success ();
1327
1336
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) {
1328
1387
const uint64_t Address = AltInstrSection->getAddress ();
1329
1388
DataExtractor DE = DataExtractor (AltInstrSection->getContents (),
1330
1389
BC.AsmInfo ->isLittleEndian (),
@@ -1336,12 +1395,12 @@ Error LinuxKernelRewriter::readAltInstructions() {
1336
1395
Address + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
1337
1396
const uint64_t AltInstAddress =
1338
1397
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);
1340
1399
const uint8_t OrgSize = DE.getU8 (Cursor);
1341
1400
const uint8_t AltSize = DE.getU8 (Cursor);
1342
1401
1343
1402
// 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 ;
1345
1404
1346
1405
if (!Cursor)
1347
1406
return createStringError (
@@ -1358,7 +1417,7 @@ Error LinuxKernelRewriter::readAltInstructions() {
1358
1417
<< " \n\t Feature: 0x" << Twine::utohexstr (Feature)
1359
1418
<< " \n\t OrgSize: " << (int )OrgSize
1360
1419
<< " \n\t AltSize: " << (int )AltSize << ' \n ' ;
1361
- if (opts:: AltInstHasPadLen)
1420
+ if (AltInstHasPadLen)
1362
1421
BC.outs () << " \t PadLen: " << (int )PadLen << ' \n ' ;
1363
1422
}
1364
1423
@@ -1375,7 +1434,7 @@ Error LinuxKernelRewriter::readAltInstructions() {
1375
1434
1376
1435
BinaryFunction *AltBF =
1377
1436
BC.getBinaryFunctionContainingAddress (AltInstAddress);
1378
- if (AltBF && BC.shouldEmit (*AltBF)) {
1437
+ if (!ParseOnly && AltBF && BC.shouldEmit (*AltBF)) {
1379
1438
BC.errs ()
1380
1439
<< " BOLT-WARNING: alternative instruction sequence found in function "
1381
1440
<< *AltBF << ' \n ' ;
@@ -1397,6 +1456,9 @@ Error LinuxKernelRewriter::readAltInstructions() {
1397
1456
" referenced by .altinstructions entry %d" ,
1398
1457
OrgInstAddress, EntryID);
1399
1458
1459
+ if (ParseOnly)
1460
+ continue ;
1461
+
1400
1462
// There could be more than one alternative instruction sequences for the
1401
1463
// same original instruction. Annotate each alternative separately.
1402
1464
std::string AnnotationName = " AltInst" ;
0 commit comments