@@ -27,6 +27,21 @@ using namespace bolt;
27
27
28
28
namespace opts {
29
29
30
+ static cl::opt<bool >
31
+ AltInstHasPadLen (" alt-inst-has-padlen" ,
32
+ cl::desc (" specify that .altinstructions has padlen field" ),
33
+ cl::init(false ), cl::Hidden, cl::cat(BoltCategory));
34
+
35
+ static cl::opt<uint32_t >
36
+ AltInstFeatureSize (" alt-inst-feature-size" ,
37
+ cl::desc (" size of feature field in .altinstructions" ),
38
+ cl::init(2 ), cl::Hidden, cl::cat(BoltCategory));
39
+
40
+ static cl::opt<bool >
41
+ DumpAltInstructions (" dump-alt-instructions" ,
42
+ cl::desc (" dump Linux alternative instructions info" ),
43
+ cl::init(false ), cl::Hidden, cl::cat(BoltCategory));
44
+
30
45
static cl::opt<bool >
31
46
DumpExceptions (" dump-linux-exceptions" ,
32
47
cl::desc (" dump Linux kernel exception table" ),
@@ -157,6 +172,15 @@ class LinuxKernelRewriter final : public MetadataRewriter {
157
172
// / Alignment of paravirtual patch structures.
158
173
static constexpr size_t PARA_PATCH_ALIGN = 8 ;
159
174
175
+ // / .altinstructions section.
176
+ ErrorOr<BinarySection &> AltInstrSection = std::errc::bad_address;
177
+
178
+ // / Section containing Linux bug table.
179
+ ErrorOr<BinarySection &> BugTableSection = std::errc::bad_address;
180
+
181
+ // / Size of bug_entry struct.
182
+ static constexpr size_t BUG_TABLE_ENTRY_SIZE = 12 ;
183
+
160
184
// / Insert an LKMarker for a given code pointer \p PC from a non-code section
161
185
// / \p SectionName.
162
186
void insertLKMarker (uint64_t PC, uint64_t SectionOffset,
@@ -172,9 +196,6 @@ class LinuxKernelRewriter final : public MetadataRewriter {
172
196
// / Process __ksymtab and __ksymtab_gpl.
173
197
void processLKKSymtab (bool IsGPL = false );
174
198
175
- // / Process special linux kernel section, __bug_table.
176
- void processLKBugTable ();
177
-
178
199
// / Process special linux kernel section, .smp_locks.
179
200
void processLKSMPLocks ();
180
201
@@ -200,6 +221,11 @@ class LinuxKernelRewriter final : public MetadataRewriter {
200
221
// / Paravirtual instruction patch sites.
201
222
Error readParaInstructions ();
202
223
224
+ Error readBugTable ();
225
+
226
+ // / Read alternative instruction info from .altinstructions.
227
+ Error readAltInstructions ();
228
+
203
229
// / Mark instructions referenced by kernel metadata.
204
230
Error markInstructions ();
205
231
@@ -224,6 +250,12 @@ class LinuxKernelRewriter final : public MetadataRewriter {
224
250
if (Error E = readParaInstructions ())
225
251
return E;
226
252
253
+ if (Error E = readBugTable ())
254
+ return E;
255
+
256
+ if (Error E = readAltInstructions ())
257
+ return E;
258
+
227
259
return Error::success ();
228
260
}
229
261
@@ -289,7 +321,6 @@ void LinuxKernelRewriter::processLKSections() {
289
321
processLKPCIFixup ();
290
322
processLKKSymtab ();
291
323
processLKKSymtab (true );
292
- processLKBugTable ();
293
324
processLKSMPLocks ();
294
325
}
295
326
@@ -356,37 +387,6 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) {
356
387
}
357
388
}
358
389
359
- // / Process __bug_table section.
360
- // / This section contains information useful for kernel debugging.
361
- // / Each entry in the section is a struct bug_entry that contains a pointer to
362
- // / the ud2 instruction corresponding to the bug, corresponding file name (both
363
- // / pointers use PC relative offset addressing), line number, and flags.
364
- // / The definition of the struct bug_entry can be found in
365
- // / `include/asm-generic/bug.h`
366
- void LinuxKernelRewriter::processLKBugTable () {
367
- ErrorOr<BinarySection &> SectionOrError =
368
- BC.getUniqueSectionByName (" __bug_table" );
369
- if (!SectionOrError)
370
- return ;
371
-
372
- const uint64_t SectionSize = SectionOrError->getSize ();
373
- const uint64_t SectionAddress = SectionOrError->getAddress ();
374
- assert ((SectionSize % 12 ) == 0 &&
375
- " The size of the __bug_table section should be a multiple of 12" );
376
- for (uint64_t I = 0 ; I < SectionSize; I += 12 ) {
377
- const uint64_t EntryAddress = SectionAddress + I;
378
- ErrorOr<uint64_t > Offset = BC.getSignedValueAtAddress (EntryAddress, 4 );
379
- assert (Offset &&
380
- " Reading valid PC-relative offset for a __bug_table entry" );
381
- const int32_t SignedOffset = *Offset;
382
- const uint64_t RefAddress = EntryAddress + SignedOffset;
383
- assert (BC.getBinaryFunctionContainingAddress (RefAddress) &&
384
- " __bug_table entries should point to a function" );
385
-
386
- insertLKMarker (RefAddress, I, SignedOffset, true , " __bug_table" );
387
- }
388
- }
389
-
390
390
// / .smp_locks section contains PC-relative references to instructions with LOCK
391
391
// / prefix. The prefix can be converted to NOP at boot time on non-SMP systems.
392
392
void LinuxKernelRewriter::processLKSMPLocks () {
@@ -500,7 +500,8 @@ Error LinuxKernelRewriter::readORCTables() {
500
500
// Consume the status of the cursor.
501
501
if (!IPCursor)
502
502
return createStringError (errc::executable_format_error,
503
- " out of bounds while reading ORC IP table" );
503
+ " out of bounds while reading ORC IP table: %s" ,
504
+ toString (IPCursor.takeError ()).c_str ());
504
505
505
506
if (IP < PrevIP && opts::Verbosity)
506
507
BC.errs () << " BOLT-WARNING: out of order IP 0x" << Twine::utohexstr (IP)
@@ -522,7 +523,8 @@ Error LinuxKernelRewriter::readORCTables() {
522
523
// Consume the status of the cursor.
523
524
if (!ORCCursor)
524
525
return createStringError (errc::executable_format_error,
525
- " out of bounds while reading ORC" );
526
+ " out of bounds while reading ORC: %s" ,
527
+ toString (ORCCursor.takeError ()).c_str ());
526
528
527
529
if (Entry.ORC == NullORC)
528
530
continue ;
@@ -843,7 +845,8 @@ Error LinuxKernelRewriter::readStaticCalls() {
843
845
// Consume the status of the cursor.
844
846
if (!Cursor)
845
847
return createStringError (errc::executable_format_error,
846
- " out of bounds while reading static calls" );
848
+ " out of bounds while reading static calls: %s" ,
849
+ toString (Cursor.takeError ()).c_str ());
847
850
848
851
++EntryID;
849
852
@@ -954,8 +957,10 @@ Error LinuxKernelRewriter::readExceptionTable() {
954
957
955
958
// Consume the status of the cursor.
956
959
if (!Cursor)
957
- return createStringError (errc::executable_format_error,
958
- " out of bounds while reading exception table" );
960
+ return createStringError (
961
+ errc::executable_format_error,
962
+ " out of bounds while reading exception table: %s" ,
963
+ toString (Cursor.takeError ()).c_str ());
959
964
960
965
++EntryID;
961
966
@@ -1061,8 +1066,10 @@ Error LinuxKernelRewriter::readParaInstructions() {
1061
1066
const uint8_t Len = DE.getU8 (Cursor);
1062
1067
1063
1068
if (!Cursor)
1064
- return createStringError (errc::executable_format_error,
1065
- " out of bounds while reading .parainstructions" );
1069
+ return createStringError (
1070
+ errc::executable_format_error,
1071
+ " out of bounds while reading .parainstructions: %s" ,
1072
+ toString (Cursor.takeError ()).c_str ());
1066
1073
1067
1074
++EntryID;
1068
1075
@@ -1097,6 +1104,185 @@ Error LinuxKernelRewriter::readParaInstructions() {
1097
1104
return Error::success ();
1098
1105
}
1099
1106
1107
+ // / Process __bug_table section.
1108
+ // / This section contains information useful for kernel debugging.
1109
+ // / Each entry in the section is a struct bug_entry that contains a pointer to
1110
+ // / the ud2 instruction corresponding to the bug, corresponding file name (both
1111
+ // / pointers use PC relative offset addressing), line number, and flags.
1112
+ // / The definition of the struct bug_entry can be found in
1113
+ // / `include/asm-generic/bug.h`
1114
+ // /
1115
+ // / NB: find_bug() uses linear search to match an address to an entry in the bug
1116
+ // / table. Hence there is no need to sort entries when rewriting the table.
1117
+ Error LinuxKernelRewriter::readBugTable () {
1118
+ BugTableSection = BC.getUniqueSectionByName (" __bug_table" );
1119
+ if (!BugTableSection)
1120
+ return Error::success ();
1121
+
1122
+ if (BugTableSection->getSize () % BUG_TABLE_ENTRY_SIZE)
1123
+ return createStringError (errc::executable_format_error,
1124
+ " bug table size error" );
1125
+
1126
+ const uint64_t SectionAddress = BugTableSection->getAddress ();
1127
+ DataExtractor DE (BugTableSection->getContents (), BC.AsmInfo ->isLittleEndian (),
1128
+ BC.AsmInfo ->getCodePointerSize ());
1129
+ DataExtractor::Cursor Cursor (0 );
1130
+ uint32_t EntryID = 0 ;
1131
+ while (Cursor && Cursor.tell () < BugTableSection->getSize ()) {
1132
+ const uint64_t Pos = Cursor.tell ();
1133
+ const uint64_t InstAddress =
1134
+ SectionAddress + Pos + (int32_t )DE.getU32 (Cursor);
1135
+ Cursor.seek (Pos + BUG_TABLE_ENTRY_SIZE);
1136
+
1137
+ if (!Cursor)
1138
+ return createStringError (errc::executable_format_error,
1139
+ " out of bounds while reading __bug_table: %s" ,
1140
+ toString (Cursor.takeError ()).c_str ());
1141
+
1142
+ ++EntryID;
1143
+
1144
+ BinaryFunction *BF = BC.getBinaryFunctionContainingAddress (InstAddress);
1145
+ if (!BF && opts::Verbosity) {
1146
+ BC.outs () << " BOLT-INFO: no function matches address 0x"
1147
+ << Twine::utohexstr (InstAddress)
1148
+ << " referenced by bug table\n " ;
1149
+ }
1150
+
1151
+ if (BF && BC.shouldEmit (*BF)) {
1152
+ MCInst *Inst = BF->getInstructionAtOffset (InstAddress - BF->getAddress ());
1153
+ if (!Inst)
1154
+ return createStringError (errc::executable_format_error,
1155
+ " no instruction at address 0x%" PRIx64
1156
+ " referenced by bug table entry %d" ,
1157
+ InstAddress, EntryID);
1158
+ BC.MIB ->addAnnotation (*Inst, " BugEntry" , EntryID);
1159
+ }
1160
+ }
1161
+
1162
+ BC.outs () << " BOLT-INFO: parsed " << EntryID << " bug table entries\n " ;
1163
+
1164
+ return Error::success ();
1165
+ }
1166
+
1167
+ // / The kernel can replace certain instruction sequences depending on hardware
1168
+ // / it is running on and features specified during boot time. The information
1169
+ // / about alternative instruction sequences is stored in .altinstructions
1170
+ // / section. The format of entries in this section is defined in
1171
+ // / arch/x86/include/asm/alternative.h:
1172
+ // /
1173
+ // / struct alt_instr {
1174
+ // / s32 instr_offset;
1175
+ // / s32 repl_offset;
1176
+ // / uXX feature;
1177
+ // / u8 instrlen;
1178
+ // / u8 replacementlen;
1179
+ // / u8 padlen; // present in older kernels
1180
+ // / } __packed;
1181
+ // /
1182
+ // / Note the structures is packed.
1183
+ Error LinuxKernelRewriter::readAltInstructions () {
1184
+ AltInstrSection = BC.getUniqueSectionByName (" .altinstructions" );
1185
+ if (!AltInstrSection)
1186
+ return Error::success ();
1187
+
1188
+ const uint64_t Address = AltInstrSection->getAddress ();
1189
+ DataExtractor DE = DataExtractor (AltInstrSection->getContents (),
1190
+ BC.AsmInfo ->isLittleEndian (),
1191
+ BC.AsmInfo ->getCodePointerSize ());
1192
+ uint64_t EntryID = 0 ;
1193
+ DataExtractor::Cursor Cursor (0 );
1194
+ while (Cursor && !DE.eof (Cursor)) {
1195
+ const uint64_t OrgInstAddress =
1196
+ Address + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
1197
+ const uint64_t AltInstAddress =
1198
+ Address + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
1199
+ const uint64_t Feature = DE.getUnsigned (Cursor, opts::AltInstFeatureSize);
1200
+ const uint8_t OrgSize = DE.getU8 (Cursor);
1201
+ const uint8_t AltSize = DE.getU8 (Cursor);
1202
+
1203
+ // Older kernels may have the padlen field.
1204
+ const uint8_t PadLen = opts::AltInstHasPadLen ? DE.getU8 (Cursor) : 0 ;
1205
+
1206
+ if (!Cursor)
1207
+ return createStringError (
1208
+ errc::executable_format_error,
1209
+ " out of bounds while reading .altinstructions: %s" ,
1210
+ toString (Cursor.takeError ()).c_str ());
1211
+
1212
+ ++EntryID;
1213
+
1214
+ if (opts::DumpAltInstructions) {
1215
+ BC.outs () << " Alternative instruction entry: " << EntryID
1216
+ << " \n\t Org: 0x" << Twine::utohexstr (OrgInstAddress)
1217
+ << " \n\t Alt: 0x" << Twine::utohexstr (AltInstAddress)
1218
+ << " \n\t Feature: 0x" << Twine::utohexstr (Feature)
1219
+ << " \n\t OrgSize: " << (int )OrgSize
1220
+ << " \n\t AltSize: " << (int )AltSize << ' \n ' ;
1221
+ if (opts::AltInstHasPadLen)
1222
+ BC.outs () << " \t PadLen: " << (int )PadLen << ' \n ' ;
1223
+ }
1224
+
1225
+ if (AltSize > OrgSize)
1226
+ return createStringError (errc::executable_format_error,
1227
+ " error reading .altinstructions" );
1228
+
1229
+ BinaryFunction *BF = BC.getBinaryFunctionContainingAddress (OrgInstAddress);
1230
+ if (!BF && opts::Verbosity) {
1231
+ BC.outs () << " BOLT-INFO: no function matches address 0x"
1232
+ << Twine::utohexstr (OrgInstAddress)
1233
+ << " of instruction from .altinstructions\n " ;
1234
+ }
1235
+
1236
+ BinaryFunction *AltBF =
1237
+ BC.getBinaryFunctionContainingAddress (AltInstAddress);
1238
+ if (AltBF && BC.shouldEmit (*AltBF)) {
1239
+ BC.errs ()
1240
+ << " BOLT-WARNING: alternative instruction sequence found in function "
1241
+ << *AltBF << ' \n ' ;
1242
+ AltBF->setIgnored ();
1243
+ }
1244
+
1245
+ if (!BF || !BC.shouldEmit (*BF))
1246
+ continue ;
1247
+
1248
+ if (OrgInstAddress + OrgSize > BF->getAddress () + BF->getSize ())
1249
+ return createStringError (errc::executable_format_error,
1250
+ " error reading .altinstructions" );
1251
+
1252
+ MCInst *Inst =
1253
+ BF->getInstructionAtOffset (OrgInstAddress - BF->getAddress ());
1254
+ if (!Inst)
1255
+ return createStringError (errc::executable_format_error,
1256
+ " no instruction at address 0x%" PRIx64
1257
+ " referenced by .altinstructions entry %d" ,
1258
+ OrgInstAddress, EntryID);
1259
+
1260
+ // There could be more than one alternative instruction sequences for the
1261
+ // same original instruction. Annotate each alternative separately.
1262
+ std::string AnnotationName = " AltInst" ;
1263
+ unsigned N = 2 ;
1264
+ while (BC.MIB ->hasAnnotation (*Inst, AnnotationName))
1265
+ AnnotationName = " AltInst" + std::to_string (N++);
1266
+
1267
+ BC.MIB ->addAnnotation (*Inst, AnnotationName, EntryID);
1268
+
1269
+ // Annotate all instructions from the original sequence. Note that it's not
1270
+ // the most efficient way to look for instructions in the address range,
1271
+ // but since alternative instructions are uncommon, it will do for now.
1272
+ for (uint32_t Offset = 1 ; Offset < OrgSize; ++Offset) {
1273
+ Inst = BF->getInstructionAtOffset (OrgInstAddress + Offset -
1274
+ BF->getAddress ());
1275
+ if (Inst)
1276
+ BC.MIB ->addAnnotation (*Inst, AnnotationName, EntryID);
1277
+ }
1278
+ }
1279
+
1280
+ BC.outs () << " BOLT-INFO: parsed " << EntryID
1281
+ << " alternative instruction entries\n " ;
1282
+
1283
+ return Error::success ();
1284
+ }
1285
+
1100
1286
} // namespace
1101
1287
1102
1288
std::unique_ptr<MetadataRewriter>
0 commit comments