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: |
58 | SDTRewriter(StringRef Name, BinaryContext &BC) : MetadataRewriter(Name, BC) {} |
59 | |
60 | Error preCFGInitializer() override; |
61 | |
62 | Error postEmitFinalizer() override; |
63 | }; |
64 | |
65 | void SDTRewriter::readSection() { |
66 | SDTSection = BC.getUniqueSectionByName(SectionName: ".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: Offset)) { |
76 | uint32_t NameSz = DE.getU32(offset_ptr: &Offset); |
77 | DE.getU32(offset_ptr: &Offset); // skip over DescSz |
78 | uint32_t Type = DE.getU32(offset_ptr: &Offset); |
79 | Offset = alignTo(Value: Offset, Align: 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(OffsetPtr: &Offset); |
89 | |
90 | if (!Name.equals(RHS: "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_ptr: &Offset); |
98 | Marker.Base = DE.getU64(offset_ptr: &Offset); |
99 | Marker.Semaphore = DE.getU64(offset_ptr: &Offset); |
100 | Marker.Provider = DE.getCStr(OffsetPtr: &Offset); |
101 | Marker.Name = DE.getCStr(OffsetPtr: &Offset); |
102 | Marker.Args = DE.getCStr(OffsetPtr: &Offset); |
103 | Offset = alignTo(Value: Offset, Align: 4); |
104 | SDTMarkers[Marker.PC] = Marker; |
105 | } |
106 | |
107 | if (opts::PrintSDTMarkers) |
108 | printSDTMarkers(); |
109 | } |
110 | |
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(c&: SDTMarkers)) { |
117 | BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(Address: PC); |
118 | |
119 | if (!BF || !BC.shouldEmit(Function: *BF)) |
120 | continue; |
121 | |
122 | const uint64_t Offset = PC - BF->getAddress(); |
123 | MCInst *Inst = BF->getInstructionAtOffset(Offset); |
124 | if (!Inst) |
125 | return createStringError(EC: errc::executable_format_error, |
126 | Msg: "no instruction matches SDT offset" ); |
127 | |
128 | if (!BC.MIB->isNoop(Inst: *Inst)) |
129 | return createStringError(EC: std::make_error_code(e: std::errc::not_supported), |
130 | Msg: "nop instruction expected at SDT offset" ); |
131 | |
132 | BC.MIB->setOffset(Inst&: *Inst, Offset: static_cast<uint32_t>(Offset)); |
133 | |
134 | BF->setHasSDTMarker(true); |
135 | } |
136 | |
137 | return Error::success(); |
138 | } |
139 | |
140 | Error SDTRewriter::postEmitFinalizer() { |
141 | if (!SDTSection) |
142 | return Error::success(); |
143 | |
144 | SDTSection->registerPatcher(BPatcher: 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(Address: OriginalAddress); |
153 | if (!F) |
154 | continue; |
155 | const uint64_t NewAddress = |
156 | F->translateInputToOutputAddress(Address: OriginalAddress); |
157 | SDTNotePatcher->addLE64Patch(Offset: SDTInfo.PCOffset, NewValue: NewAddress); |
158 | } |
159 | |
160 | return Error::success(); |
161 | } |
162 | |
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(c: SDTMarkers)) { |
166 | outs() << "BOLT-INFO: PC: " << utohexstr(X: Marker.PC) |
167 | << ", Base: " << utohexstr(X: Marker.Base) |
168 | << ", Semaphore: " << utohexstr(X: Marker.Semaphore) |
169 | << ", Provider: " << Marker.Provider << ", Name: " << Marker.Name |
170 | << ", Args: " << Marker.Args << "\n" ; |
171 | } |
172 | } |
173 | } // namespace |
174 | |
175 | std::unique_ptr<MetadataRewriter> |
176 | llvm::bolt::createSDTRewriter(BinaryContext &BC) { |
177 | return std::make_unique<SDTRewriter>(args: "sdt-rewriter" , args&: BC); |
178 | } |
179 | |