DIInliningInfo ModuleInfo::symbolizeInlinedCode( uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { DIInliningInfo InlinedContext; if (DebugInfoContext) { InlinedContext = DebugInfoContext->getInliningInfoForAddress( ModuleOffset, getDILineInfoSpecifierFlags(Opts)); } // Make sure there is at least one frame in context. if (InlinedContext.getNumberOfFrames() == 0) { InlinedContext.addFrame(DILineInfo()); } // Override the function name in lower frame with name from symbol table. if (Opts.PrintFunctions && Opts.UseSymbolTable) { DIInliningInfo PatchedInlinedContext; for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { DILineInfo LineInfo = InlinedContext.getFrame(i); if (i == n - 1) { std::string FunctionName; uint64_t Start, Size; if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, FunctionName, Start, Size)) { patchFunctionNameInDILineInfo(FunctionName, LineInfo); } } PatchedInlinedContext.addFrame(LineInfo); } InlinedContext = PatchedInlinedContext; } return InlinedContext; }
void emit_lineinfo(raw_ostream &Out, DIInliningInfo &DI) { uint32_t nframes = DI.getNumberOfFrames(); std::vector<DILineInfo> DIvec(nframes); for (uint32_t i = 0; i < DI.getNumberOfFrames(); i++) { DIvec[i] = DI.getFrame(i); } emit_lineinfo(Out, DIvec); }
DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode( uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const { DIInliningInfo InlinedContext; if (DebugInfoContext) InlinedContext = DebugInfoContext->getInliningInfoForAddress( ModuleOffset, getDILineInfoSpecifier(FNKind)); // Make sure there is at least one frame in context. if (InlinedContext.getNumberOfFrames() == 0) InlinedContext.addFrame(DILineInfo()); // Override the function name in lower frame with name from symbol table. if (shouldOverrideWithSymbolTable(FNKind, UseSymbolTable)) { std::string FunctionName; uint64_t Start, Size; if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, FunctionName, Start, Size)) { InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1) ->FunctionName = FunctionName; } } return InlinedContext; }
static void DumpInput(const StringRef &Filename) { OwningPtr<MemoryBuffer> Buff; if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { errs() << Filename << ": " << ec.message() << "\n"; return; } OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); if (!Obj) { errs() << Filename << ": Unknown object file format\n"; return; } OwningPtr<DIContext> DICtx(DIContext::getDWARFContext(Obj.get())); if (Address == -1ULL) { outs() << Filename << ":\tfile format " << Obj->getFileFormatName() << "\n\n"; // Dump the complete DWARF structure. DICtx->dump(outs(), DumpType); } else { // Print line info for the specified address. int SpecFlags = DILineInfoSpecifier::FileLineInfo | DILineInfoSpecifier::AbsoluteFilePath; if (PrintFunctions) SpecFlags |= DILineInfoSpecifier::FunctionName; if (PrintInlining) { DIInliningInfo InliningInfo = DICtx->getInliningInfoForAddress(Address, SpecFlags); uint32_t n = InliningInfo.getNumberOfFrames(); if (n == 0) { // Print one empty debug line info in any case. PrintDILineInfo(DILineInfo()); } else { for (uint32_t i = 0; i < n; i++) { DILineInfo dli = InliningInfo.getFrame(i); PrintDILineInfo(dli); } } } else { DILineInfo dli = DICtx->getLineInfoForAddress(Address, SpecFlags); PrintDILineInfo(dli); } } }
std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset) { ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); if (Info == 0) return printDILineInfo(DILineInfo()); if (Opts.PrintInlining) { DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(ModuleOffset, Opts); uint32_t FramesNum = InlinedContext.getNumberOfFrames(); assert(FramesNum > 0); std::string Result; for (uint32_t i = 0; i < FramesNum; i++) { DILineInfo LineInfo = InlinedContext.getFrame(i); Result += printDILineInfo(LineInfo); } return Result; } DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts); return printDILineInfo(LineInfo); }
ErrorOr<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName, uint64_t ModuleOffset) { auto InfoOrErr = getOrCreateModuleInfo(ModuleName); if (auto EC = InfoOrErr.getError()) return EC; SymbolizableModule *Info = InfoOrErr.get(); // If the user is giving us relative addresses, add the preferred base of the // object to the offset before we do the query. It's what DIContext expects. if (Opts.RelativeAddresses) ModuleOffset += Info->getModulePreferredBase(); DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable); if (Opts.Demangle) { for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { auto *Frame = InlinedContext.getMutableFrame(i); Frame->FunctionName = DemangleName(Frame->FunctionName, Info); } } return InlinedContext; }
static void jl_dump_asm_internal( uintptr_t Fptr, size_t Fsize, int64_t slide, const object::ObjectFile *object, DIContext *di_ctx, raw_ostream &rstream, const char* asm_variant) { // GC safe // Get the host information std::string TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); const auto &target = jl_get_llvm_disasm_target(); const auto &cpu = target.first; const auto &features = target.second; std::string err; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, err); // Set up required helpers and streamer std::unique_ptr<MCStreamer> Streamer; SourceMgr SrcMgr; std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); assert(MAI && "Unable to create target asm info!"); std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); MOFI->InitMCObjectFileInfo(TheTriple, /* PIC */ false, Ctx); // Set up Subtarget and Disassembler std::unique_ptr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, cpu, features)); std::unique_ptr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI, Ctx)); if (!DisAsm) { jl_printf(JL_STDERR, "ERROR: no disassembler for target %s\n", TripleName.c_str()); return; } unsigned OutputAsmVariant = 0; // ATT or Intel-style assembly if (strcmp(asm_variant, "intel")==0) { OutputAsmVariant = 1; } bool ShowEncoding = false; std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCInstrAnalysis> MCIA(TheTarget->createMCInstrAnalysis(MCII.get())); MCInstPrinter *IP = TheTarget->createMCInstPrinter(TheTriple, OutputAsmVariant, *MAI, *MCII, *MRI); //IP->setPrintImmHex(true); // prefer hex or decimal immediates MCCodeEmitter *CE = 0; MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MCTargetOptions Options; MAB = TheTarget->createMCAsmBackend(*STI, *MRI, Options); } // createAsmStreamer expects a unique_ptr to a formatted stream, which means // it will destruct the stream when it is done. We cannot have this, so we // start out with a raw stream, and create formatted stream from it here. // LLVM will desctruct the formatted stream, and we keep the raw stream. auto ustream = llvm::make_unique<formatted_raw_ostream>(rstream); Streamer.reset(TheTarget->createAsmStreamer(Ctx, std::move(ustream), /*asmverbose*/true, /*useDwarfDirectory*/ true, IP, CE, MAB, /*ShowInst*/ false)); Streamer->InitSections(true); // Make the MemoryObject wrapper ArrayRef<uint8_t> memoryObject(const_cast<uint8_t*>((const uint8_t*)Fptr),Fsize); SymbolTable DisInfo(Ctx, object, slide, memoryObject); DILineInfoTable di_lineinfo; if (di_ctx) di_lineinfo = di_ctx->getLineInfoForAddressRange(Fptr+slide, Fsize); if (!di_lineinfo.empty()) { auto cur_addr = di_lineinfo[0].first; auto nlineinfo = di_lineinfo.size(); // filter out line infos that doesn't contain any instructions unsigned j = 0; for (unsigned i = 1; i < nlineinfo; i++) { auto &info = di_lineinfo[i]; if (info.first != cur_addr) j++; cur_addr = info.first; if (i != j) { di_lineinfo[j] = std::move(info); } } if (j + 1 < nlineinfo) { di_lineinfo.resize(j + 1); } } // Take two passes: In the first pass we record all branch labels, // in the second we actually perform the output for (int pass = 0; pass < 2; ++ pass) { DisInfo.setPass(pass); if (pass != 0) { // Switch to symbolic disassembly. We cannot do this // before the first pass, because this changes branch // targets from immediate values (constants) to // expressions, which are not handled correctly by // MCIA->evaluateBranch. (It should be possible to rewrite // this routine to handle this case correctly as well.) // Could add OpInfoLookup here DisAsm->setSymbolizer(std::unique_ptr<MCSymbolizer>(new MCExternalSymbolizer( Ctx, std::unique_ptr<MCRelocationInfo>(new MCRelocationInfo(Ctx)), OpInfoLookup, SymbolLookup, &DisInfo))); } uint64_t nextLineAddr = -1; DILineInfoTable::iterator di_lineIter = di_lineinfo.begin(); DILineInfoTable::iterator di_lineEnd = di_lineinfo.end(); DILineInfoPrinter dbgctx{';', true}; if (pass != 0) { if (di_ctx && di_lineIter != di_lineEnd) { // Set up the line info nextLineAddr = di_lineIter->first; if (nextLineAddr != (uint64_t)(Fptr + slide)) { std::string buf; dbgctx.emit_lineinfo(buf, di_lineIter->second); if (!buf.empty()) { Streamer->EmitRawText(buf); } } } } uint64_t Index = 0; uint64_t insSize = 0; // Do the disassembly for (Index = 0; Index < Fsize; Index += insSize) { if (pass != 0 && nextLineAddr != (uint64_t)-1 && Index + Fptr + slide == nextLineAddr) { if (di_ctx) { std::string buf; DILineInfoSpecifier infoSpec(DILineInfoSpecifier::FileLineInfoKind::Default, DILineInfoSpecifier::FunctionNameKind::ShortName); DIInliningInfo dbg = di_ctx->getInliningInfoForAddress(Index + Fptr + slide, infoSpec); if (dbg.getNumberOfFrames()) { dbgctx.emit_lineinfo(buf, dbg); } else { dbgctx.emit_lineinfo(buf, di_lineIter->second); } if (!buf.empty()) Streamer->EmitRawText(buf); nextLineAddr = (++di_lineIter)->first; } } DisInfo.setIP(Fptr+Index); if (pass != 0) { // Uncomment this to output addresses for all instructions // stream << Index << ": "; MCSymbol *symbol = DisInfo.lookupSymbol(Fptr+Index); if (symbol) Streamer->EmitLabel(symbol); } MCInst Inst; MCDisassembler::DecodeStatus S; FuncMCView view = memoryObject.slice(Index); S = DisAsm->getInstruction(Inst, insSize, view, 0, /*VStream*/ nulls(), /*CStream*/ pass != 0 ? Streamer->GetCommentOS() : nulls()); if (pass != 0 && Streamer->GetCommentOS().tell() > 0) Streamer->GetCommentOS() << '\n'; switch (S) { case MCDisassembler::Fail: if (insSize == 0) // skip illegible bytes #if defined(_CPU_PPC_) || defined(_CPU_PPC64_) || defined(_CPU_ARM_) || defined(_CPU_AARCH64_) insSize = 4; // instructions are always 4 bytes #else insSize = 1; // attempt to slide 1 byte forward #endif if (pass != 0) { std::ostringstream buf; if (insSize == 4) buf << "\t.long\t0x" << std::hex << std::setfill('0') << std::setw(8) << *(uint32_t*)(Fptr+Index); else for (uint64_t i=0; i<insSize; ++i) buf << "\t.byte\t0x" << std::hex << std::setfill('0') << std::setw(2) << (int)*(uint8_t*)(Fptr+Index+i); Streamer->EmitRawText(StringRef(buf.str())); } break; case MCDisassembler::SoftFail: if (pass != 0) Streamer->EmitRawText(StringRef("potentially undefined instruction encoding:")); // Fall through case MCDisassembler::Success: if (pass == 0) { // Pass 0: Record all branch target references if (MCIA) { const MCInstrDesc &opcode = MCII->get(Inst.getOpcode()); if (opcode.isBranch() || opcode.isCall()) { uint64_t addr; if (MCIA->evaluateBranch(Inst, Fptr + Index, insSize, addr)) DisInfo.insertAddress(addr); } } } else { // Pass 1: Output instruction if (pass != 0) { // attempt to symbolicate any immediate operands const MCInstrDesc &opinfo = MCII->get(Inst.getOpcode()); for (unsigned Op = 0; Op < opinfo.NumOperands; Op++) { const MCOperand &OpI = Inst.getOperand(Op); if (OpI.isImm()) { int64_t imm = OpI.getImm(); if (opinfo.OpInfo[Op].OperandType == MCOI::OPERAND_PCREL) imm += Fptr + Index; const char *name = DisInfo.lookupSymbolName(imm); if (name) Streamer->AddComment(name); } } } Streamer->EmitInstruction(Inst, *STI); } break; } } DisInfo.setIP(Fptr); if (pass == 0) DisInfo.createSymbols(); if (pass != 0 && di_ctx) { std::string buf; dbgctx.emit_finish(buf); if (!buf.empty()) { Streamer->EmitRawText(buf); } } } }