[BOLT] Add support for dumping counters on MacOS

Summary: Add support for dumping counters on MacOS

(cherry picked from FBD25750516)
This commit is contained in:
Alexander Shaposhnikov 2021-01-28 12:32:03 -08:00 committed by Maksim Panchenko
parent 6a84124e1d
commit 3b876cc3e7
6 changed files with 116 additions and 19 deletions

View File

@ -180,6 +180,17 @@ uint32_t strLen(const char *Str) {
return Size;
}
void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
char Buf[BufSize];
char *Ptr = Buf;
Ptr = strCopy(Ptr, Msg, BufSize - 23);
Ptr = intToStr(Ptr, Num, Base);
Ptr = strCopy(Ptr, "\n");
__write(2, Buf, Ptr - Buf);
}
void report(const char *Msg) { __write(2, Msg, strLen(Msg)); }
#if !defined(__APPLE__)
// We use a stack-allocated buffer for string manipulation in many pieces of
// this code, including the code that prints each line of the fdata file. This
@ -332,17 +343,6 @@ void assert(bool Assertion, const char *Msg) {
reportError(Buf, Ptr - Buf);
}
void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
char Buf[BufSize];
char *Ptr = Buf;
Ptr = strCopy(Ptr, Msg, BufSize - 23);
Ptr = intToStr(Ptr, Num, Base);
Ptr = strCopy(Ptr, "\n");
__write(2, Buf, Ptr - Buf);
}
void report(const char *Msg) { __write(2, Msg, strLen(Msg)); }
/// 1B mutex accessed by lock xchg
class Mutex {
volatile bool InUse{false};

View File

@ -57,7 +57,16 @@
{}
#endif
#if !defined(__APPLE__)
#if defined(__APPLE__)
extern "C" {
extern uint64_t* _bolt_instr_locations_getter();
extern uint32_t _bolt_num_counters_getter();
}
#else
// Main counters inserted by instrumentation, incremented during runtime when
// points of interest (locations) in the program are reached. Those are direct
@ -1463,17 +1472,45 @@ extern "C" void __bolt_instr_fini() {
DEBUG(report("Finished.\n"));
}
#else
#endif
#if defined(__APPLE__)
// On OSX/iOS the final symbol name of an extern "C" function/variable contains
// one extra leading underscore: _bolt_instr_setup -> __bolt_instr_setup.
extern "C" __attribute((section("__TEXT,__setup"))) void _bolt_instr_setup() {
const char* Message = "Hello!\n";
extern "C"
__attribute__((section("__TEXT,__setup")))
__attribute__((force_align_arg_pointer))
void _bolt_instr_setup() {
const char *Message = "Hello!\n";
__write(2, Message, 7);
uint32_t NumCounters = _bolt_num_counters_getter();
reportNumber("__bolt_instr_setup, number of counters: ", NumCounters, 10);
uint64_t *Locs = _bolt_instr_locations_getter();
reportNumber("__bolt_instr_setup, address of counters: ",
reinterpret_cast<uint64_t>(Locs), 10);
for (size_t I = 0; I < NumCounters; ++I)
reportNumber("Counter value: ", Locs[I], 10);
}
extern "C" __attribute((section("__TEXT,__fini"))) void _bolt_instr_fini() {
const char* Message = "Bye!\n";
extern "C"
__attribute__((section("__TEXT,__fini")))
__attribute__((force_align_arg_pointer))
void _bolt_instr_fini() {
uint32_t NumCounters = _bolt_num_counters_getter();
reportNumber("__bolt_instr_fini, number of counters: ", NumCounters, 10);
uint64_t *Locs = _bolt_instr_locations_getter();
reportNumber("__bolt_instr_fini, address of counters: ",
reinterpret_cast<uint64_t>(Locs), 10);
for (size_t I = 0; I < NumCounters; ++I)
reportNumber("Counter value: ", Locs[I], 10);
const char *Message = "Bye!\n";
__write(2, Message, 5);
}

View File

@ -1738,6 +1738,16 @@ public:
return std::vector<MCInst>();
}
virtual std::vector<MCInst> createNumCountersGetter(MCContext *Ctx) const {
llvm_unreachable("not implemented");
return {};
}
virtual std::vector<MCInst> createInstrLocationsGetter(MCContext *Ctx) const {
llvm_unreachable("not implemented");
return {};
}
/// This method takes an indirect call instruction and splits it up into an
/// equivalent set of instructions that use direct calls for target
/// symbols/addresses that are contained in the Targets vector. This is done

View File

@ -344,6 +344,7 @@ void MachORewriteInstance::mapCodeSections(orc::VModuleKey Key) {
BOLT->getInputFileOffset());
Function->setImageAddress(FuncSection->getAllocAddress());
Function->setImageSize(FuncSection->getOutputSize());
BC->registerNameAtAddress(Function->getOneName(), Addr, 0, 0);
Addr += FuncSection->getOutputSize();
}
}
@ -386,8 +387,6 @@ void MachORewriteInstance::emitAndLink() {
auto Resolver = orc::createLegacyLookupResolver(
[&](const std::string &Name) -> JITSymbol {
llvm::errs() << "looking for " << Name << "\n";
assert(!BC->EFMM->ObjectsLoaded &&
"Linking multiple objects is unsupported");
DEBUG(dbgs() << "BOLT: looking for " << Name << "\n");
if (auto *I = BC->getBinaryDataByName(Name)) {
const uint64_t Address = I->isMoved() && !I->isJumpTable()

View File

@ -607,6 +607,11 @@ void Instrumentation::createAuxiliaryFunctions(BinaryContext &BC) {
Summary->InitialIndTailCallHandlerFunction =
createSimpleFunction("__bolt_instr_default_ind_tailcall_handler",
BC.MIB->createInstrumentedNoopIndTailCallHandler());
createSimpleFunction("__bolt_num_counters_getter",
BC.MIB->createNumCountersGetter(BC.Ctx.get()));
createSimpleFunction("__bolt_instr_locations_getter",
BC.MIB->createInstrLocationsGetter(BC.Ctx.get()));
}
void Instrumentation::setupRuntimeLibrary(BinaryContext &BC) {

View File

@ -3325,6 +3325,22 @@ public:
return Insts;
}
std::vector<MCInst> createNumCountersGetter(MCContext *Ctx) const override {
std::vector<MCInst> Insts(2);
MCSymbol *NumLocs = Ctx->getOrCreateSymbol("__bolt_num_counters");
createMove(Insts[0], NumLocs, X86::EAX, Ctx);
createReturn(Insts[1]);
return Insts;
}
std::vector<MCInst> createInstrLocationsGetter(MCContext *Ctx) const override {
std::vector<MCInst> Insts(2);
MCSymbol *Locs = Ctx->getOrCreateSymbol("__bolt_instr_locations");
createLea(Insts[0], Locs, X86::EAX, Ctx);
createReturn(Insts[1]);
return Insts;
}
BlocksVectorTy indirectCallPromotion(
const MCInst &CallInst,
const std::vector<std::pair<MCSymbol *, uint64_t>> &Targets,
@ -3627,6 +3643,36 @@ public:
return Results;
}
private:
bool createMove(MCInst &Inst, const MCSymbol *Src, unsigned Reg,
MCContext *Ctx) const {
Inst.setOpcode(X86::MOV64rm);
Inst.addOperand(MCOperand::createReg(Reg));
Inst.addOperand(MCOperand::createReg(X86::RIP)); // BaseReg
Inst.addOperand(MCOperand::createImm(1)); // ScaleAmt
Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
Inst.addOperand(MCOperand::createExpr(
MCSymbolRefExpr::create(Src, MCSymbolRefExpr::VK_None,
*Ctx))); // Displacement
Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
return true;
}
bool createLea(MCInst &Inst, const MCSymbol *Src, unsigned Reg,
MCContext *Ctx) const {
Inst.setOpcode(X86::LEA64r);
Inst.addOperand(MCOperand::createReg(Reg));
Inst.addOperand(MCOperand::createReg(X86::RIP)); // BaseReg
Inst.addOperand(MCOperand::createImm(1)); // ScaleAmt
Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg
Inst.addOperand(MCOperand::createExpr(
MCSymbolRefExpr::create(Src, MCSymbolRefExpr::VK_None,
*Ctx))); // Displacement
Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg
return true;
}
};
}