xref: /llvm-project/bolt/lib/Rewrite/SDTRewriter.cpp (revision f841ca0c355ae53c96f615996d0aff4648da8618)
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.
11 //
12 //===----------------------------------------------------------------------===//
13 
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"
22 
23 using namespace llvm;
24 using namespace bolt;
25 
26 namespace opts {
27 static cl::opt<bool> PrintSDTMarkers("print-sdt",
28                                      cl::desc("print all SDT markers"),
29                                      cl::Hidden, cl::cat(BoltCategory));
30 }
31 
32 namespace {
33 class SDTRewriter final : public MetadataRewriter {
34   ErrorOr<BinarySection &> SDTSection{std::errc::bad_address};
35 
36   struct SDTMarkerInfo {
37     uint64_t PC;
38     uint64_t Base;
39     uint64_t Semaphore;
40     StringRef Provider;
41     StringRef Name;
42     StringRef Args;
43 
44     /// The offset of PC within the note section
45     unsigned PCOffset;
46   };
47 
48   /// Map SDT locations to SDT markers info
49   using SDTMarkersListType = std::unordered_map<uint64_t, SDTMarkerInfo>;
50   SDTMarkersListType SDTMarkers;
51 
52   /// Read section to populate SDTMarkers.
53   void readSection();
54 
55   void printSDTMarkers() const;
56 
57 public:
SDTRewriter(StringRef Name,BinaryContext & BC)58   SDTRewriter(StringRef Name, BinaryContext &BC) : MetadataRewriter(Name, BC) {}
59 
60   Error preCFGInitializer() override;
61 
62   Error postEmitFinalizer() override;
63 };
64 
readSection()65 void SDTRewriter::readSection() {
66   SDTSection = BC.getUniqueSectionByName(".note.stapsdt");
67   if (!SDTSection)
68     return;
69 
70   StringRef Buf = SDTSection->getContents();
71   DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(),
72                                    BC.AsmInfo->getCodePointerSize());
73   uint64_t Offset = 0;
74 
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);
80 
81     if (Type != 3)
82       errs() << "BOLT-WARNING: SDT note type \"" << Type
83              << "\" is not expected\n";
84 
85     if (NameSz == 0)
86       errs() << "BOLT-WARNING: SDT note has empty name\n";
87 
88     StringRef Name = DE.getCStr(&Offset);
89 
90     if (Name != "stapsdt")
91       errs() << "BOLT-WARNING: SDT note name \"" << Name
92              << "\" is not expected\n";
93 
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;
105   }
106 
107   if (opts::PrintSDTMarkers)
108     printSDTMarkers();
109 }
110 
preCFGInitializer()111 Error SDTRewriter::preCFGInitializer() {
112   // Populate SDTMarkers.
113   readSection();
114 
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);
118 
119     if (!BF || !BC.shouldEmit(*BF))
120       continue;
121 
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");
127 
128     if (!BC.MIB->isNoop(*Inst))
129       return createStringError(std::make_error_code(std::errc::not_supported),
130                                "nop instruction expected at SDT offset");
131 
132     BC.MIB->setOffset(*Inst, static_cast<uint32_t>(Offset));
133 
134     BF->setHasSDTMarker(true);
135   }
136 
137   return Error::success();
138 }
139 
postEmitFinalizer()140 Error SDTRewriter::postEmitFinalizer() {
141   if (!SDTSection)
142     return Error::success();
143 
144   SDTSection->registerPatcher(std::make_unique<SimpleBinaryPatcher>());
145 
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);
158   }
159 
160   return Error::success();
161 }
162 
printSDTMarkers() const163 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";
171   }
172 }
173 } // namespace
174 
175 std::unique_ptr<MetadataRewriter>
createSDTRewriter(BinaryContext & BC)176 llvm::bolt::createSDTRewriter(BinaryContext &BC) {
177   return std::make_unique<SDTRewriter>("sdt-rewriter", BC);
178 }
179