179 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Implement support for System Tap Statically-Defined Trace points stored in10// .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 section45 unsigned PCOffset;46 };47 48 /// Map SDT locations to SDT markers info49 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(".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 DescSz78 uint32_t Type = DE.getU32(&Offset);79 Offset = alignTo(Offset, 4);80 81 if (Type != 3)82 errs() << "BOLT-WARNING: SDT note type \"" << Type83 << "\" 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 \"" << Name92 << "\" is not expected\n";93 94 // Parse description95 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 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(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 140Error 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 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(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.Name170 << ", Args: " << Marker.Args << "\n";171 }172}173} // namespace174 175std::unique_ptr<MetadataRewriter>176llvm::bolt::createSDTRewriter(BinaryContext &BC) {177 return std::make_unique<SDTRewriter>("sdt-rewriter", BC);178}179