198e2d630SMaksim Panchenko //===- bolt/Rewrite/SDTRewriter.cpp ---------------------------------------===//
298e2d630SMaksim Panchenko //
398e2d630SMaksim Panchenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
498e2d630SMaksim Panchenko // See https://llvm.org/LICENSE.txt for license information.
598e2d630SMaksim Panchenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
698e2d630SMaksim Panchenko //
798e2d630SMaksim Panchenko //===----------------------------------------------------------------------===//
898e2d630SMaksim Panchenko //
998e2d630SMaksim Panchenko // Implement support for System Tap Statically-Defined Trace points stored in
1098e2d630SMaksim Panchenko // .note.stapsdt section.
1198e2d630SMaksim Panchenko //
1298e2d630SMaksim Panchenko //===----------------------------------------------------------------------===//
1398e2d630SMaksim Panchenko
1498e2d630SMaksim Panchenko #include "bolt/Core/BinaryFunction.h"
1598e2d630SMaksim Panchenko #include "bolt/Core/DebugData.h"
1698e2d630SMaksim Panchenko #include "bolt/Rewrite/MetadataRewriter.h"
1798e2d630SMaksim Panchenko #include "bolt/Rewrite/MetadataRewriters.h"
1898e2d630SMaksim Panchenko #include "bolt/Utils/CommandLineOpts.h"
1998e2d630SMaksim Panchenko #include "llvm/Support/CommandLine.h"
2098e2d630SMaksim Panchenko #include "llvm/Support/Errc.h"
2198e2d630SMaksim Panchenko #include "llvm/Support/Timer.h"
2298e2d630SMaksim Panchenko
2398e2d630SMaksim Panchenko using namespace llvm;
2498e2d630SMaksim Panchenko using namespace bolt;
2598e2d630SMaksim Panchenko
2698e2d630SMaksim Panchenko namespace opts {
2798e2d630SMaksim Panchenko static cl::opt<bool> PrintSDTMarkers("print-sdt",
2898e2d630SMaksim Panchenko cl::desc("print all SDT markers"),
2998e2d630SMaksim Panchenko cl::Hidden, cl::cat(BoltCategory));
3098e2d630SMaksim Panchenko }
3198e2d630SMaksim Panchenko
3298e2d630SMaksim Panchenko namespace {
3398e2d630SMaksim Panchenko class SDTRewriter final : public MetadataRewriter {
3498e2d630SMaksim Panchenko ErrorOr<BinarySection &> SDTSection{std::errc::bad_address};
3598e2d630SMaksim Panchenko
3698e2d630SMaksim Panchenko struct SDTMarkerInfo {
3798e2d630SMaksim Panchenko uint64_t PC;
3898e2d630SMaksim Panchenko uint64_t Base;
3998e2d630SMaksim Panchenko uint64_t Semaphore;
4098e2d630SMaksim Panchenko StringRef Provider;
4198e2d630SMaksim Panchenko StringRef Name;
4298e2d630SMaksim Panchenko StringRef Args;
4398e2d630SMaksim Panchenko
4498e2d630SMaksim Panchenko /// The offset of PC within the note section
4598e2d630SMaksim Panchenko unsigned PCOffset;
4698e2d630SMaksim Panchenko };
4798e2d630SMaksim Panchenko
4898e2d630SMaksim Panchenko /// Map SDT locations to SDT markers info
4998e2d630SMaksim Panchenko using SDTMarkersListType = std::unordered_map<uint64_t, SDTMarkerInfo>;
5098e2d630SMaksim Panchenko SDTMarkersListType SDTMarkers;
5198e2d630SMaksim Panchenko
5298e2d630SMaksim Panchenko /// Read section to populate SDTMarkers.
5398e2d630SMaksim Panchenko void readSection();
5498e2d630SMaksim Panchenko
5598e2d630SMaksim Panchenko void printSDTMarkers() const;
5698e2d630SMaksim Panchenko
5798e2d630SMaksim Panchenko public:
SDTRewriter(StringRef Name,BinaryContext & BC)5898e2d630SMaksim Panchenko SDTRewriter(StringRef Name, BinaryContext &BC) : MetadataRewriter(Name, BC) {}
5998e2d630SMaksim Panchenko
6098e2d630SMaksim Panchenko Error preCFGInitializer() override;
6198e2d630SMaksim Panchenko
6298e2d630SMaksim Panchenko Error postEmitFinalizer() override;
6398e2d630SMaksim Panchenko };
6498e2d630SMaksim Panchenko
readSection()6598e2d630SMaksim Panchenko void SDTRewriter::readSection() {
6698e2d630SMaksim Panchenko SDTSection = BC.getUniqueSectionByName(".note.stapsdt");
6798e2d630SMaksim Panchenko if (!SDTSection)
6898e2d630SMaksim Panchenko return;
6998e2d630SMaksim Panchenko
7098e2d630SMaksim Panchenko StringRef Buf = SDTSection->getContents();
7198e2d630SMaksim Panchenko DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(),
7298e2d630SMaksim Panchenko BC.AsmInfo->getCodePointerSize());
7398e2d630SMaksim Panchenko uint64_t Offset = 0;
7498e2d630SMaksim Panchenko
7598e2d630SMaksim Panchenko while (DE.isValidOffset(Offset)) {
7698e2d630SMaksim Panchenko uint32_t NameSz = DE.getU32(&Offset);
7798e2d630SMaksim Panchenko DE.getU32(&Offset); // skip over DescSz
7898e2d630SMaksim Panchenko uint32_t Type = DE.getU32(&Offset);
7998e2d630SMaksim Panchenko Offset = alignTo(Offset, 4);
8098e2d630SMaksim Panchenko
8198e2d630SMaksim Panchenko if (Type != 3)
8298e2d630SMaksim Panchenko errs() << "BOLT-WARNING: SDT note type \"" << Type
8398e2d630SMaksim Panchenko << "\" is not expected\n";
8498e2d630SMaksim Panchenko
8598e2d630SMaksim Panchenko if (NameSz == 0)
8698e2d630SMaksim Panchenko errs() << "BOLT-WARNING: SDT note has empty name\n";
8798e2d630SMaksim Panchenko
8898e2d630SMaksim Panchenko StringRef Name = DE.getCStr(&Offset);
8998e2d630SMaksim Panchenko
90*f841ca0cSKazu Hirata if (Name != "stapsdt")
9198e2d630SMaksim Panchenko errs() << "BOLT-WARNING: SDT note name \"" << Name
9298e2d630SMaksim Panchenko << "\" is not expected\n";
9398e2d630SMaksim Panchenko
9498e2d630SMaksim Panchenko // Parse description
9598e2d630SMaksim Panchenko SDTMarkerInfo Marker;
9698e2d630SMaksim Panchenko Marker.PCOffset = Offset;
9798e2d630SMaksim Panchenko Marker.PC = DE.getU64(&Offset);
9898e2d630SMaksim Panchenko Marker.Base = DE.getU64(&Offset);
9998e2d630SMaksim Panchenko Marker.Semaphore = DE.getU64(&Offset);
10098e2d630SMaksim Panchenko Marker.Provider = DE.getCStr(&Offset);
10198e2d630SMaksim Panchenko Marker.Name = DE.getCStr(&Offset);
10298e2d630SMaksim Panchenko Marker.Args = DE.getCStr(&Offset);
10398e2d630SMaksim Panchenko Offset = alignTo(Offset, 4);
10498e2d630SMaksim Panchenko SDTMarkers[Marker.PC] = Marker;
10598e2d630SMaksim Panchenko }
10698e2d630SMaksim Panchenko
10798e2d630SMaksim Panchenko if (opts::PrintSDTMarkers)
10898e2d630SMaksim Panchenko printSDTMarkers();
10998e2d630SMaksim Panchenko }
11098e2d630SMaksim Panchenko
preCFGInitializer()11198e2d630SMaksim Panchenko Error SDTRewriter::preCFGInitializer() {
11298e2d630SMaksim Panchenko // Populate SDTMarkers.
11398e2d630SMaksim Panchenko readSection();
11498e2d630SMaksim Panchenko
11598e2d630SMaksim Panchenko // Mark nop instructions referenced by SDT and the containing function.
11698e2d630SMaksim Panchenko for (const uint64_t PC : llvm::make_first_range(SDTMarkers)) {
11798e2d630SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(PC);
11898e2d630SMaksim Panchenko
11998e2d630SMaksim Panchenko if (!BF || !BC.shouldEmit(*BF))
12098e2d630SMaksim Panchenko continue;
12198e2d630SMaksim Panchenko
12298e2d630SMaksim Panchenko const uint64_t Offset = PC - BF->getAddress();
12398e2d630SMaksim Panchenko MCInst *Inst = BF->getInstructionAtOffset(Offset);
12498e2d630SMaksim Panchenko if (!Inst)
12598e2d630SMaksim Panchenko return createStringError(errc::executable_format_error,
12698e2d630SMaksim Panchenko "no instruction matches SDT offset");
12798e2d630SMaksim Panchenko
12898e2d630SMaksim Panchenko if (!BC.MIB->isNoop(*Inst))
12998e2d630SMaksim Panchenko return createStringError(std::make_error_code(std::errc::not_supported),
13098e2d630SMaksim Panchenko "nop instruction expected at SDT offset");
13198e2d630SMaksim Panchenko
13298e2d630SMaksim Panchenko BC.MIB->setOffset(*Inst, static_cast<uint32_t>(Offset));
13398e2d630SMaksim Panchenko
13498e2d630SMaksim Panchenko BF->setHasSDTMarker(true);
13598e2d630SMaksim Panchenko }
13698e2d630SMaksim Panchenko
13798e2d630SMaksim Panchenko return Error::success();
13898e2d630SMaksim Panchenko }
13998e2d630SMaksim Panchenko
postEmitFinalizer()14098e2d630SMaksim Panchenko Error SDTRewriter::postEmitFinalizer() {
14198e2d630SMaksim Panchenko if (!SDTSection)
14298e2d630SMaksim Panchenko return Error::success();
14398e2d630SMaksim Panchenko
14498e2d630SMaksim Panchenko SDTSection->registerPatcher(std::make_unique<SimpleBinaryPatcher>());
14598e2d630SMaksim Panchenko
14698e2d630SMaksim Panchenko SimpleBinaryPatcher *SDTNotePatcher =
14798e2d630SMaksim Panchenko static_cast<SimpleBinaryPatcher *>(SDTSection->getPatcher());
14898e2d630SMaksim Panchenko for (auto &SDTInfoKV : SDTMarkers) {
14998e2d630SMaksim Panchenko const uint64_t OriginalAddress = SDTInfoKV.first;
15098e2d630SMaksim Panchenko const SDTMarkerInfo &SDTInfo = SDTInfoKV.second;
15198e2d630SMaksim Panchenko const BinaryFunction *F =
15298e2d630SMaksim Panchenko BC.getBinaryFunctionContainingAddress(OriginalAddress);
15398e2d630SMaksim Panchenko if (!F)
15498e2d630SMaksim Panchenko continue;
15598e2d630SMaksim Panchenko const uint64_t NewAddress =
15698e2d630SMaksim Panchenko F->translateInputToOutputAddress(OriginalAddress);
15798e2d630SMaksim Panchenko SDTNotePatcher->addLE64Patch(SDTInfo.PCOffset, NewAddress);
15898e2d630SMaksim Panchenko }
15998e2d630SMaksim Panchenko
16098e2d630SMaksim Panchenko return Error::success();
16198e2d630SMaksim Panchenko }
16298e2d630SMaksim Panchenko
printSDTMarkers() const16398e2d630SMaksim Panchenko void SDTRewriter::printSDTMarkers() const {
16498e2d630SMaksim Panchenko outs() << "BOLT-INFO: Number of SDT markers is " << SDTMarkers.size() << "\n";
16598e2d630SMaksim Panchenko for (const SDTMarkerInfo &Marker : llvm::make_second_range(SDTMarkers)) {
16698e2d630SMaksim Panchenko outs() << "BOLT-INFO: PC: " << utohexstr(Marker.PC)
16798e2d630SMaksim Panchenko << ", Base: " << utohexstr(Marker.Base)
16898e2d630SMaksim Panchenko << ", Semaphore: " << utohexstr(Marker.Semaphore)
16998e2d630SMaksim Panchenko << ", Provider: " << Marker.Provider << ", Name: " << Marker.Name
17098e2d630SMaksim Panchenko << ", Args: " << Marker.Args << "\n";
17198e2d630SMaksim Panchenko }
17298e2d630SMaksim Panchenko }
17398e2d630SMaksim Panchenko } // namespace
17498e2d630SMaksim Panchenko
17598e2d630SMaksim Panchenko std::unique_ptr<MetadataRewriter>
createSDTRewriter(BinaryContext & BC)17698e2d630SMaksim Panchenko llvm::bolt::createSDTRewriter(BinaryContext &BC) {
17798e2d630SMaksim Panchenko return std::make_unique<SDTRewriter>("sdt-rewriter", BC);
17898e2d630SMaksim Panchenko }
179