@@ -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,9 @@ 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
+
160
178
// / Section containing Linux bug table.
161
179
ErrorOr<BinarySection &> BugTableSection = std::errc::bad_address;
162
180
@@ -205,6 +223,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
205
223
206
224
Error readBugTable ();
207
225
226
+ // / Read alternative instruction info from .altinstructions.
227
+ Error readAltInstructions ();
228
+
208
229
// / Mark instructions referenced by kernel metadata.
209
230
Error markInstructions ();
210
231
@@ -232,6 +253,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
232
253
if (Error E = readBugTable ())
233
254
return E;
234
255
256
+ if (Error E = readAltInstructions ())
257
+ return E;
258
+
235
259
return Error::success ();
236
260
}
237
261
@@ -1132,6 +1156,123 @@ Error LinuxKernelRewriter::readBugTable() {
1132
1156
return Error::success ();
1133
1157
}
1134
1158
1159
+ // / The kernel can replace certain instruction sequences depending on hardware
1160
+ // / it is running on and features specified during boot time. The information
1161
+ // / about alternative instruction sequences is stored in .altinstructions
1162
+ // / section. The format of entries in this section is defined in
1163
+ // / arch/x86/include/asm/alternative.h:
1164
+ // /
1165
+ // / struct alt_instr {
1166
+ // / s32 instr_offset;
1167
+ // / s32 repl_offset;
1168
+ // / uXX feature;
1169
+ // / u8 instrlen;
1170
+ // / u8 replacementlen;
1171
+ // / u8 padlen; // present in older kernels
1172
+ // / } __packed;
1173
+ // /
1174
+ // / Note the structures is packed.
1175
+ Error LinuxKernelRewriter::readAltInstructions () {
1176
+ AltInstrSection = BC.getUniqueSectionByName (" .altinstructions" );
1177
+ if (!AltInstrSection)
1178
+ return Error::success ();
1179
+
1180
+ const uint64_t Address = AltInstrSection->getAddress ();
1181
+ DataExtractor DE = DataExtractor (AltInstrSection->getContents (),
1182
+ BC.AsmInfo ->isLittleEndian (),
1183
+ BC.AsmInfo ->getCodePointerSize ());
1184
+ uint64_t EntryID = 0 ;
1185
+ DataExtractor::Cursor Cursor (0 );
1186
+ while (Cursor && !DE.eof (Cursor)) {
1187
+ const uint64_t OrgInstAddress =
1188
+ Address + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
1189
+ const uint64_t AltInstAddress =
1190
+ Address + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
1191
+ const uint64_t Feature = DE.getUnsigned (Cursor, opts::AltInstFeatureSize);
1192
+ const uint8_t OrgSize = DE.getU8 (Cursor);
1193
+ const uint8_t AltSize = DE.getU8 (Cursor);
1194
+
1195
+ // Older kernels may have the padlen field.
1196
+ const uint8_t PadLen = opts::AltInstHasPadLen ? DE.getU8 (Cursor) : 0 ;
1197
+
1198
+ if (!Cursor)
1199
+ return createStringError (errc::executable_format_error,
1200
+ " out of bounds while reading .altinstructions" );
1201
+
1202
+ ++EntryID;
1203
+
1204
+ if (opts::DumpAltInstructions) {
1205
+ BC.outs () << " Alternative instruction entry: " << EntryID
1206
+ << " \n\t Org: 0x" << Twine::utohexstr (OrgInstAddress)
1207
+ << " \n\t Alt: 0x" << Twine::utohexstr (AltInstAddress)
1208
+ << " \n\t Feature: 0x" << Twine::utohexstr (Feature)
1209
+ << " \n\t OrgSize: " << (int )OrgSize
1210
+ << " \n\t AltSize: " << (int )AltSize << ' \n ' ;
1211
+ if (opts::AltInstHasPadLen)
1212
+ BC.outs () << " \t PadLen: " << (int )PadLen << ' \n ' ;
1213
+ }
1214
+
1215
+ if (AltSize > OrgSize)
1216
+ return createStringError (errc::executable_format_error,
1217
+ " error reading .altinstructions" );
1218
+
1219
+ BinaryFunction *BF = BC.getBinaryFunctionContainingAddress (OrgInstAddress);
1220
+ if (!BF && opts::Verbosity) {
1221
+ BC.outs () << " BOLT-INFO: no function matches address 0x"
1222
+ << Twine::utohexstr (OrgInstAddress)
1223
+ << " of instruction from .altinstructions\n " ;
1224
+ }
1225
+
1226
+ BinaryFunction *AltBF =
1227
+ BC.getBinaryFunctionContainingAddress (AltInstAddress);
1228
+ if (AltBF && BC.shouldEmit (*AltBF)) {
1229
+ BC.errs ()
1230
+ << " BOLT-WARNING: alternative instruction sequence found in function "
1231
+ << *AltBF << ' \n ' ;
1232
+ AltBF->setIgnored ();
1233
+ }
1234
+
1235
+ if (!BF || !BC.shouldEmit (*BF))
1236
+ continue ;
1237
+
1238
+ if (OrgInstAddress + OrgSize > BF->getAddress () + BF->getSize ())
1239
+ return createStringError (errc::executable_format_error,
1240
+ " error reading .altinstructions" );
1241
+
1242
+ MCInst *Inst =
1243
+ BF->getInstructionAtOffset (OrgInstAddress - BF->getAddress ());
1244
+ if (!Inst)
1245
+ return createStringError (errc::executable_format_error,
1246
+ " no instruction at address 0x%" PRIx64
1247
+ " referenced by .altinstructions entry %d" ,
1248
+ OrgInstAddress, EntryID);
1249
+
1250
+ // There could be more than one alternative instruction sequences for the
1251
+ // same original instruction. Annotate each alternative separately.
1252
+ std::string AnnotationName = " AltInst" ;
1253
+ unsigned N = 2 ;
1254
+ while (BC.MIB ->hasAnnotation (*Inst, AnnotationName))
1255
+ AnnotationName = " AltInst" + std::to_string (N++);
1256
+
1257
+ BC.MIB ->addAnnotation (*Inst, AnnotationName, EntryID);
1258
+
1259
+ // Annotate all instructions from the original sequence. Note that it's not
1260
+ // the most efficient way to look for instructions in the address range,
1261
+ // but since alternative instructions are uncommon, it will do for now.
1262
+ for (uint32_t Offset = 1 ; Offset < OrgSize; ++Offset) {
1263
+ Inst = BF->getInstructionAtOffset (OrgInstAddress + Offset -
1264
+ BF->getAddress ());
1265
+ if (Inst)
1266
+ BC.MIB ->addAnnotation (*Inst, AnnotationName, EntryID);
1267
+ }
1268
+ }
1269
+
1270
+ BC.outs () << " BOLT-INFO: parsed " << EntryID
1271
+ << " alternative instruction entries\n " ;
1272
+
1273
+ return Error::success ();
1274
+ }
1275
+
1135
1276
} // namespace
1136
1277
1137
1278
std::unique_ptr<MetadataRewriter>
0 commit comments