blob: a3928c554ad66c2c65b6cd3b39c4f070ef37e862 [file] [log] [blame] [edit]
//===- bolt/Rewrite/SDTRewriter.cpp ---------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Implement support for System Tap Statically-Defined Trace points stored in
// .note.stapsdt section.
//
//===----------------------------------------------------------------------===//
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Core/DebugData.h"
#include "bolt/Rewrite/MetadataRewriter.h"
#include "bolt/Rewrite/MetadataRewriters.h"
#include "bolt/Utils/CommandLineOpts.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Timer.h"
using namespace llvm;
using namespace bolt;
namespace opts {
static cl::opt<bool> PrintSDTMarkers("print-sdt",
cl::desc("print all SDT markers"),
cl::Hidden, cl::cat(BoltCategory));
}
namespace {
class SDTRewriter final : public MetadataRewriter {
ErrorOr<BinarySection &> SDTSection{std::errc::bad_address};
struct SDTMarkerInfo {
uint64_t PC;
uint64_t Base;
uint64_t Semaphore;
StringRef Provider;
StringRef Name;
StringRef Args;
/// The offset of PC within the note section
unsigned PCOffset;
};
/// Map SDT locations to SDT markers info
using SDTMarkersListType = std::unordered_map<uint64_t, SDTMarkerInfo>;
SDTMarkersListType SDTMarkers;
/// Read section to populate SDTMarkers.
void readSection();
void printSDTMarkers() const;
public:
SDTRewriter(StringRef Name, BinaryContext &BC) : MetadataRewriter(Name, BC) {}
Error preCFGInitializer() override;
Error postEmitFinalizer() override;
};
void SDTRewriter::readSection() {
SDTSection = BC.getUniqueSectionByName(".note.stapsdt");
if (!SDTSection)
return;
StringRef Buf = SDTSection->getContents();
DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(),
BC.AsmInfo->getCodePointerSize());
uint64_t Offset = 0;
while (DE.isValidOffset(Offset)) {
uint32_t NameSz = DE.getU32(&Offset);
DE.getU32(&Offset); // skip over DescSz
uint32_t Type = DE.getU32(&Offset);
Offset = alignTo(Offset, 4);
if (Type != 3)
errs() << "BOLT-WARNING: SDT note type \"" << Type
<< "\" is not expected\n";
if (NameSz == 0)
errs() << "BOLT-WARNING: SDT note has empty name\n";
StringRef Name = DE.getCStr(&Offset);
if (Name != "stapsdt")
errs() << "BOLT-WARNING: SDT note name \"" << Name
<< "\" is not expected\n";
// Parse description
SDTMarkerInfo Marker;
Marker.PCOffset = Offset;
Marker.PC = DE.getU64(&Offset);
Marker.Base = DE.getU64(&Offset);
Marker.Semaphore = DE.getU64(&Offset);
Marker.Provider = DE.getCStr(&Offset);
Marker.Name = DE.getCStr(&Offset);
Marker.Args = DE.getCStr(&Offset);
Offset = alignTo(Offset, 4);
SDTMarkers[Marker.PC] = Marker;
}
if (opts::PrintSDTMarkers)
printSDTMarkers();
}
Error SDTRewriter::preCFGInitializer() {
// Populate SDTMarkers.
readSection();
// Mark nop instructions referenced by SDT and the containing function.
for (const uint64_t PC : llvm::make_first_range(SDTMarkers)) {
BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(PC);
if (!BF || !BC.shouldEmit(*BF))
continue;
const uint64_t Offset = PC - BF->getAddress();
MCInst *Inst = BF->getInstructionAtOffset(Offset);
if (!Inst)
return createStringError(errc::executable_format_error,
"no instruction matches SDT offset");
if (!BC.MIB->isNoop(*Inst))
return createStringError(std::make_error_code(std::errc::not_supported),
"nop instruction expected at SDT offset");
BC.MIB->setOffset(*Inst, static_cast<uint32_t>(Offset));
BF->setHasSDTMarker(true);
}
return Error::success();
}
Error SDTRewriter::postEmitFinalizer() {
if (!SDTSection)
return Error::success();
SDTSection->registerPatcher(std::make_unique<SimpleBinaryPatcher>());
SimpleBinaryPatcher *SDTNotePatcher =
static_cast<SimpleBinaryPatcher *>(SDTSection->getPatcher());
for (auto &SDTInfoKV : SDTMarkers) {
const uint64_t OriginalAddress = SDTInfoKV.first;
const SDTMarkerInfo &SDTInfo = SDTInfoKV.second;
const BinaryFunction *F =
BC.getBinaryFunctionContainingAddress(OriginalAddress);
if (!F)
continue;
const uint64_t NewAddress =
F->translateInputToOutputAddress(OriginalAddress);
SDTNotePatcher->addLE64Patch(SDTInfo.PCOffset, NewAddress);
}
return Error::success();
}
void SDTRewriter::printSDTMarkers() const {
outs() << "BOLT-INFO: Number of SDT markers is " << SDTMarkers.size() << "\n";
for (const SDTMarkerInfo &Marker : llvm::make_second_range(SDTMarkers)) {
outs() << "BOLT-INFO: PC: " << utohexstr(Marker.PC)
<< ", Base: " << utohexstr(Marker.Base)
<< ", Semaphore: " << utohexstr(Marker.Semaphore)
<< ", Provider: " << Marker.Provider << ", Name: " << Marker.Name
<< ", Args: " << Marker.Args << "\n";
}
}
} // namespace
std::unique_ptr<MetadataRewriter>
llvm::bolt::createSDTRewriter(BinaryContext &BC) {
return std::make_unique<SDTRewriter>("sdt-rewriter", BC);
}