|
21 | 21 | #include "llvm/Support/CommandLine.h"
|
22 | 22 | #include "llvm/Support/Debug.h"
|
23 | 23 | #include "llvm/Support/Errc.h"
|
| 24 | +#include "llvm/Support/ErrorOr.h" |
| 25 | +#include <regex> |
24 | 26 |
|
25 | 27 | #define DEBUG_TYPE "bolt-linux"
|
26 | 28 |
|
@@ -89,6 +91,34 @@ static cl::opt<bool>
|
89 | 91 |
|
90 | 92 | } // namespace opts
|
91 | 93 |
|
| 94 | +/// Linux kernel version |
| 95 | +struct LKVersion { |
| 96 | + LKVersion() {} |
| 97 | + LKVersion(unsigned Major, unsigned Minor, unsigned Rev) |
| 98 | + : Major(Major), Minor(Minor), Rev(Rev) {} |
| 99 | + |
| 100 | + bool operator<(const LKVersion &Other) const { |
| 101 | + return std::make_tuple(Major, Minor, Rev) < |
| 102 | + std::make_tuple(Other.Major, Other.Minor, Other.Rev); |
| 103 | + } |
| 104 | + |
| 105 | + bool operator>(const LKVersion &Other) const { return Other < *this; } |
| 106 | + |
| 107 | + bool operator<=(const LKVersion &Other) const { return !(*this > Other); } |
| 108 | + |
| 109 | + bool operator>=(const LKVersion &Other) const { return !(*this < Other); } |
| 110 | + |
| 111 | + bool operator==(const LKVersion &Other) const { |
| 112 | + return Major == Other.Major && Minor == Other.Minor && Rev == Other.Rev; |
| 113 | + } |
| 114 | + |
| 115 | + bool operator!=(const LKVersion &Other) const { return !(*this == Other); } |
| 116 | + |
| 117 | + unsigned Major{0}; |
| 118 | + unsigned Minor{0}; |
| 119 | + unsigned Rev{0}; |
| 120 | +}; |
| 121 | + |
92 | 122 | /// Linux Kernel supports stack unwinding using ORC (oops rewind capability).
|
93 | 123 | /// ORC state at every IP can be described by the following data structure.
|
94 | 124 | struct ORCState {
|
@@ -148,6 +178,8 @@ class AddressExtractor : public DataExtractor {
|
148 | 178 | };
|
149 | 179 |
|
150 | 180 | class LinuxKernelRewriter final : public MetadataRewriter {
|
| 181 | + LKVersion LinuxKernelVersion; |
| 182 | + |
151 | 183 | /// Information required for updating metadata referencing an instruction.
|
152 | 184 | struct InstructionFixup {
|
153 | 185 | BinarySection &Section; // Section referencing the instruction.
|
@@ -249,6 +281,8 @@ class LinuxKernelRewriter final : public MetadataRewriter {
|
249 | 281 | ErrorOr<BinarySection &> PCIFixupSection = std::errc::bad_address;
|
250 | 282 | static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16;
|
251 | 283 |
|
| 284 | + Error detectLinuxKernelVersion(); |
| 285 | + |
252 | 286 | /// Process linux kernel special sections and their relocations.
|
253 | 287 | void processLKSections();
|
254 | 288 |
|
@@ -314,6 +348,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
|
314 | 348 | : MetadataRewriter("linux-kernel-rewriter", BC) {}
|
315 | 349 |
|
316 | 350 | Error preCFGInitializer() override {
|
| 351 | + if (Error E = detectLinuxKernelVersion()) |
| 352 | + return E; |
| 353 | + |
317 | 354 | processLKSections();
|
318 | 355 |
|
319 | 356 | if (Error E = processSMPLocks())
|
@@ -394,6 +431,28 @@ class LinuxKernelRewriter final : public MetadataRewriter {
|
394 | 431 | }
|
395 | 432 | };
|
396 | 433 |
|
| 434 | +Error LinuxKernelRewriter::detectLinuxKernelVersion() { |
| 435 | + if (BinaryData *BD = BC.getBinaryDataByName("linux_banner")) { |
| 436 | + const BinarySection &Section = BD->getSection(); |
| 437 | + const std::string S = |
| 438 | + Section.getContents().substr(BD->getOffset(), BD->getSize()).str(); |
| 439 | + |
| 440 | + const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---"); |
| 441 | + std::smatch Match; |
| 442 | + if (std::regex_search(S, Match, Re)) { |
| 443 | + const unsigned Major = std::stoi(Match[2].str()); |
| 444 | + const unsigned Minor = std::stoi(Match[3].str()); |
| 445 | + const unsigned Rev = Match[5].matched ? std::stoi(Match[5].str()) : 0; |
| 446 | + LinuxKernelVersion = LKVersion(Major, Minor, Rev); |
| 447 | + BC.outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str() |
| 448 | + << "\n"; |
| 449 | + return Error::success(); |
| 450 | + } |
| 451 | + } |
| 452 | + return createStringError(errc::executable_format_error, |
| 453 | + "Linux kernel version is unknown"); |
| 454 | +} |
| 455 | + |
397 | 456 | void LinuxKernelRewriter::processLKSections() {
|
398 | 457 | processLKKSymtab();
|
399 | 458 | processLKKSymtab(true);
|
|
0 commit comments