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
23using namespace llvm;
24using namespace bolt;
25
26namespace opts {
27static cl::opt<bool> PrintSDTMarkers("print-sdt",
28 cl::desc("print all SDT markers"),
29 cl::Hidden, cl::cat(BoltCategory));
30}
31
32namespace {
33class 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
57public:
58 SDTRewriter(StringRef Name, BinaryContext &BC) : MetadataRewriter(Name, BC) {}
59
60 Error preCFGInitializer() override;
61
62 Error postEmitFinalizer() override;
63};
64
65void 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
111Error 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
140Error 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
163void 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
175std::unique_ptr<MetadataRewriter>
176llvm::bolt::createSDTRewriter(BinaryContext &BC) {
177 return std::make_unique<SDTRewriter>(args: "sdt-rewriter", args&: BC);
178}
179

source code of bolt/lib/Rewrite/SDTRewriter.cpp