1 //===- bolt/Rewrite/SDTRewriter.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
27 static cl::opt
<bool> PrintSDTMarkers("print-sdt",
28 cl::desc("print all SDT markers"),
29 cl::Hidden
, cl::cat(BoltCategory
));
33 class SDTRewriter final
: public MetadataRewriter
{
34 ErrorOr
<BinarySection
&> SDTSection
{std::errc::bad_address
};
36 struct SDTMarkerInfo
{
44 /// The offset of PC within the note section
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.
55 void printSDTMarkers() const;
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");
70 StringRef Buf
= SDTSection
->getContents();
71 DataExtractor DE
= DataExtractor(Buf
, BC
.AsmInfo
->isLittleEndian(),
72 BC
.AsmInfo
->getCodePointerSize());
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);
82 errs() << "BOLT-WARNING: SDT note type \"" << Type
83 << "\" is not expected\n";
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";
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
)
111 Error
SDTRewriter::preCFGInitializer() {
112 // Populate SDTMarkers.
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
))
122 const uint64_t Offset
= PC
- BF
->getAddress();
123 MCInst
*Inst
= BF
->getInstructionAtOffset(Offset
);
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() {
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
);
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";
175 std::unique_ptr
<MetadataRewriter
>
176 llvm::bolt::createSDTRewriter(BinaryContext
&BC
) {
177 return std::make_unique
<SDTRewriter
>("sdt-rewriter", BC
);