DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Spec) { DIInliningInfo InliningInfo; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return InliningInfo; const DWARFLineTable *LineTable = nullptr; SmallVector<DWARFDie, 4> InlinedChain; CU->getInlinedChainForAddress(Address, InlinedChain); if (InlinedChain.size() == 0) { // If there is no DIE for address (e.g. it is in unavailable .dwo file), // try to at least get file/line info from symbol table. if (Spec.FLIKind != FileLineInfoKind::None) { DILineInfo Frame; LineTable = getLineTableForUnit(CU); if (LineTable && LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), Spec.FLIKind, Frame)) InliningInfo.addFrame(Frame); } return InliningInfo; } uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) { DWARFDie &FunctionDIE = InlinedChain[i]; DILineInfo Frame; // Get function name if necessary. if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind)) Frame.FunctionName = Name; if (Spec.FLIKind != FileLineInfoKind::None) { if (i == 0) { // For the topmost frame, initialize the line table of this // compile unit and fetch file/line info from it. LineTable = getLineTableForUnit(CU); // For the topmost routine, get file/line info from line table. if (LineTable) LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), Spec.FLIKind, Frame); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. if (LineTable) LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(), Spec.FLIKind, Frame.FileName); Frame.Line = CallLine; Frame.Column = CallColumn; } // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn); } } InliningInfo.addFrame(Frame); } return InliningInfo; }
DIInliningInfo PDBContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DIInliningInfo InlineInfo; DILineInfo Frame = getLineInfoForAddress(Address, Specifier); InlineInfo.addFrame(Frame); return InlineInfo; }
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 DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return DIInliningInfo(); const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.DIEs.size() == 0) return DIInliningInfo(); DIInliningInfo InliningInfo; uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; const DWARFLineTable *LineTable = 0; for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; std::string FileName = "<invalid>"; std::string FunctionName = "<invalid>"; uint32_t Line = 0; uint32_t Column = 0; // Get function name if necessary. if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.U)) FunctionName = Name; } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); if (i == 0) { // For the topmost frame, initialize the line table of this // compile unit and fetch file/line info from it. LineTable = getLineTableForCompileUnit(CU); // For the topmost routine, get file/line info from line table. getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, FileName, Line, Column); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. getFileNameForCompileUnit(CU, LineTable, CallFile, NeedsAbsoluteFilePath, FileName); Line = CallLine; Column = CallColumn; } // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, CallColumn); } } DILineInfo Frame(StringRef(FileName), StringRef(FunctionName), Line, Column); InliningInfo.addFrame(Frame); } return InliningInfo; }
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); } } }
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; }
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; }
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 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); } } } }
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DIInliningInfo InliningInfo; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return InliningInfo; const DWARFLineTable *LineTable = nullptr; const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.DIEs.size() == 0) { // If there is no DIE for address (e.g. it is in unavailable .dwo file), // try to at least get file/line info from symbol table. if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { DILineInfo Frame; LineTable = getLineTableForCompileUnit(CU); if (getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, Frame)) { InliningInfo.addFrame(Frame); } } return InliningInfo; } uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; DILineInfo Frame; // Get function name if necessary. if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.U)) Frame.FunctionName = Name; } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { if (i == 0) { // For the topmost frame, initialize the line table of this // compile unit and fetch file/line info from it. LineTable = getLineTableForCompileUnit(CU); // For the topmost routine, get file/line info from line table. getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, Frame); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. getFileNameForCompileUnit(CU, LineTable, CallFile, NeedsAbsoluteFilePath, Frame.FileName); Frame.Line = CallLine; Frame.Column = CallColumn; } // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, CallColumn); } } InliningInfo.addFrame(Frame); } return InliningInfo; }