[BOLT] Detect Linux kernel version if the binary is a Linux kernel (#119088)
[llvm-project.git] / bolt / lib / Rewrite / SDTRewriter.cpp
bloba3928c554ad66c2c65b6cd3b39c4f070ef37e862
1 //===- bolt/Rewrite/SDTRewriter.cpp ---------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implement support for System Tap Statically-Defined Trace points stored in
10 // .note.stapsdt section.
12 //===----------------------------------------------------------------------===//
14 #include "bolt/Core/BinaryFunction.h"
15 #include "bolt/Core/DebugData.h"
16 #include "bolt/Rewrite/MetadataRewriter.h"
17 #include "bolt/Rewrite/MetadataRewriters.h"
18 #include "bolt/Utils/CommandLineOpts.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/Errc.h"
21 #include "llvm/Support/Timer.h"
23 using namespace llvm;
24 using namespace bolt;
26 namespace opts {
27 static cl::opt<bool> PrintSDTMarkers("print-sdt",
28 cl::desc("print all SDT markers"),
29 cl::Hidden, cl::cat(BoltCategory));
32 namespace {
33 class SDTRewriter final : public MetadataRewriter {
34 ErrorOr<BinarySection &> SDTSection{std::errc::bad_address};
36 struct SDTMarkerInfo {
37 uint64_t PC;
38 uint64_t Base;
39 uint64_t Semaphore;
40 StringRef Provider;
41 StringRef Name;
42 StringRef Args;
44 /// The offset of PC within the note section
45 unsigned PCOffset;
48 /// Map SDT locations to SDT markers info
49 using SDTMarkersListType = std::unordered_map<uint64_t, SDTMarkerInfo>;
50 SDTMarkersListType SDTMarkers;
52 /// Read section to populate SDTMarkers.
53 void readSection();
55 void printSDTMarkers() const;
57 public:
58 SDTRewriter(StringRef Name, BinaryContext &BC) : MetadataRewriter(Name, BC) {}
60 Error preCFGInitializer() override;
62 Error postEmitFinalizer() override;
65 void SDTRewriter::readSection() {
66 SDTSection = BC.getUniqueSectionByName(".note.stapsdt");
67 if (!SDTSection)
68 return;
70 StringRef Buf = SDTSection->getContents();
71 DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(),
72 BC.AsmInfo->getCodePointerSize());
73 uint64_t Offset = 0;
75 while (DE.isValidOffset(Offset)) {
76 uint32_t NameSz = DE.getU32(&Offset);
77 DE.getU32(&Offset); // skip over DescSz
78 uint32_t Type = DE.getU32(&Offset);
79 Offset = alignTo(Offset, 4);
81 if (Type != 3)
82 errs() << "BOLT-WARNING: SDT note type \"" << Type
83 << "\" is not expected\n";
85 if (NameSz == 0)
86 errs() << "BOLT-WARNING: SDT note has empty name\n";
88 StringRef Name = DE.getCStr(&Offset);
90 if (Name != "stapsdt")
91 errs() << "BOLT-WARNING: SDT note name \"" << Name
92 << "\" is not expected\n";
94 // Parse description
95 SDTMarkerInfo Marker;
96 Marker.PCOffset = Offset;
97 Marker.PC = DE.getU64(&Offset);
98 Marker.Base = DE.getU64(&Offset);
99 Marker.Semaphore = DE.getU64(&Offset);
100 Marker.Provider = DE.getCStr(&Offset);
101 Marker.Name = DE.getCStr(&Offset);
102 Marker.Args = DE.getCStr(&Offset);
103 Offset = alignTo(Offset, 4);
104 SDTMarkers[Marker.PC] = Marker;
107 if (opts::PrintSDTMarkers)
108 printSDTMarkers();
111 Error SDTRewriter::preCFGInitializer() {
112 // Populate SDTMarkers.
113 readSection();
115 // Mark nop instructions referenced by SDT and the containing function.
116 for (const uint64_t PC : llvm::make_first_range(SDTMarkers)) {
117 BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(PC);
119 if (!BF || !BC.shouldEmit(*BF))
120 continue;
122 const uint64_t Offset = PC - BF->getAddress();
123 MCInst *Inst = BF->getInstructionAtOffset(Offset);
124 if (!Inst)
125 return createStringError(errc::executable_format_error,
126 "no instruction matches SDT offset");
128 if (!BC.MIB->isNoop(*Inst))
129 return createStringError(std::make_error_code(std::errc::not_supported),
130 "nop instruction expected at SDT offset");
132 BC.MIB->setOffset(*Inst, static_cast<uint32_t>(Offset));
134 BF->setHasSDTMarker(true);
137 return Error::success();
140 Error SDTRewriter::postEmitFinalizer() {
141 if (!SDTSection)
142 return Error::success();
144 SDTSection->registerPatcher(std::make_unique<SimpleBinaryPatcher>());
146 SimpleBinaryPatcher *SDTNotePatcher =
147 static_cast<SimpleBinaryPatcher *>(SDTSection->getPatcher());
148 for (auto &SDTInfoKV : SDTMarkers) {
149 const uint64_t OriginalAddress = SDTInfoKV.first;
150 const SDTMarkerInfo &SDTInfo = SDTInfoKV.second;
151 const BinaryFunction *F =
152 BC.getBinaryFunctionContainingAddress(OriginalAddress);
153 if (!F)
154 continue;
155 const uint64_t NewAddress =
156 F->translateInputToOutputAddress(OriginalAddress);
157 SDTNotePatcher->addLE64Patch(SDTInfo.PCOffset, NewAddress);
160 return Error::success();
163 void SDTRewriter::printSDTMarkers() const {
164 outs() << "BOLT-INFO: Number of SDT markers is " << SDTMarkers.size() << "\n";
165 for (const SDTMarkerInfo &Marker : llvm::make_second_range(SDTMarkers)) {
166 outs() << "BOLT-INFO: PC: " << utohexstr(Marker.PC)
167 << ", Base: " << utohexstr(Marker.Base)
168 << ", Semaphore: " << utohexstr(Marker.Semaphore)
169 << ", Provider: " << Marker.Provider << ", Name: " << Marker.Name
170 << ", Args: " << Marker.Args << "\n";
173 } // namespace
175 std::unique_ptr<MetadataRewriter>
176 llvm::bolt::createSDTRewriter(BinaryContext &BC) {
177 return std::make_unique<SDTRewriter>("sdt-rewriter", BC);