bool cmpDISP(const DISubprogram & SP1, const DISubprogram & SP2) { int cmp = SP1.getDirectory().compare(SP2.getDirectory()); if (cmp == 0) { cmp = SP1.getFilename().compare(SP2.getFilename()); if (cmp == 0) { cmp = SP1.getLineNumber() - SP2.getLineNumber(); } } return cmp >= 0 ? false : true; }
void getFunctionInfo(const char **name, int *line, const char **filename, size_t pointer) { std::map<size_t, FuncInfo> info = jl_jit_events->getMap(); *name = NULL; *line = -1; *filename = "no file"; for (std::map<size_t, FuncInfo>::iterator it= info.begin(); it!= info.end(); it++) { if ((*it).first <= pointer) { if ((size_t)(*it).first + (*it).second.lengthAdr >= pointer) { #if LLVM_VERSION_MAJOR == 3 #if LLVM_VERSION_MINOR == 0 *name = &(*(*it).second.func).getNameStr()[0]; #elif LLVM_VERSION_MINOR >= 1 *name = (((*(*it).second.func).getName()).data()); #endif #endif if ((*it).second.lines.size() == 0) { continue; } std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit = (*it).second.lines.begin(); JITEvent_EmittedFunctionDetails::LineStart prev = *vit; DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); *filename = debugscope.getFilename().data(); // the DISubprogram has the un-mangled name, so use that if // available. *name = debugscope.getName().data(); vit++; while (vit != (*it).second.lines.end()) { if (pointer <= (*vit).Address) { *line = prev.Loc.getLine(); break; } prev = *vit; vit++; } if (*line == -1) { *line = prev.Loc.getLine(); } break; } } } }
/// addSourceLine - Add location information to specified debug information /// entry. void CompileUnit::addSourceLine(DIE *Die, DISubprogram SP) { // Verify subprogram. if (!SP.Verify()) return; // If the line number is 0, don't add it. if (SP.getLineNumber() == 0) return; unsigned Line = SP.getLineNumber(); if (!SP.getContext().Verify()) return; unsigned FileID = DD->GetOrCreateSourceID(SP.getFilename(), SP.getDirectory()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); }
void LineNumberAnnotatedWriter::emitFunctionAnnot( const Function *F, formatted_raw_ostream &Out) { InstrLoc = nullptr; DISubprogram *FuncLoc = F->getSubprogram(); if (!FuncLoc) { auto SP = Subprogram.find(F); if (SP != Subprogram.end()) FuncLoc = SP->second; } if (!FuncLoc) return; std::vector<DILineInfo> DIvec(1); DILineInfo &DI = DIvec.back(); DI.FunctionName = FuncLoc->getName(); DI.FileName = FuncLoc->getFilename(); DI.Line = FuncLoc->getLine(); LinePrinter.emit_lineinfo(Out, DIvec); }
void jl_getDylibFunctionInfo(const char **name, size_t *line, const char **filename, size_t pointer, int *fromC, int skipC) { #ifdef _OS_WINDOWS_ DWORD fbase = SymGetModuleBase64(GetCurrentProcess(),(DWORD)pointer); char *fname = 0; if (fbase != 0) { #else Dl_info dlinfo; const char *fname = 0; if ((dladdr((void*)pointer, &dlinfo) != 0) && dlinfo.dli_fname) { *fromC = !jl_is_sysimg(dlinfo.dli_fname); if (skipC && *fromC) return; // In case we fail with the debug info lookup, we at least still // have the function name, even if we don't have line numbers *name = dlinfo.dli_sname; *filename = dlinfo.dli_fname; uint64_t fbase = (uint64_t)dlinfo.dli_fbase; #endif obfiletype::iterator it = objfilemap.find(fbase); llvm::object::ObjectFile *obj = NULL; DIContext *context = NULL; int64_t slide = 0; #ifndef _OS_WINDOWS_ fname = dlinfo.dli_fname; #else IMAGEHLP_MODULE64 ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); fname = ModuleInfo.LoadedImageName; *fromC = !jl_is_sysimg(fname); if (skipC && *fromC) return; #endif if (it == objfilemap.end()) { #ifdef _OS_DARWIN_ // First find the uuid of the object file (we'll use this to make sure we find the // correct debug symbol file). uint8_t uuid[16], uuid2[16]; #ifdef LLVM36 std::unique_ptr<MemoryBuffer> membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false); auto origerrorobj = llvm::object::ObjectFile::createObjectFile( membuf->getMemBufferRef(), sys::fs::file_magic::unknown); #elif LLVM35 MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false); std::unique_ptr<MemoryBuffer> buf(membuf); auto origerrorobj = llvm::object::ObjectFile::createObjectFile( buf, sys::fs::file_magic::unknown); #else MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false); llvm::object::ObjectFile *origerrorobj = llvm::object::ObjectFile::createObjectFile( membuf); #endif if (!origerrorobj) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; goto lookup; } #ifdef LLVM36 llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get().release(); #elif LLVM35 llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get(); #else llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj; #endif if (!getObjUUID(morigobj,uuid)) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; goto lookup; } // On OS X debug symbols are not contained in the dynamic library and that's why // we can't have nice things (easily). For now we only support .dSYM files in the same directory // as the shared library. In the future we may use DBGCopyFullDSYMURLForUUID from CoreFoundation to make // use of spotlight to find the .dSYM file. char dsympath[PATH_MAX]; strlcpy(dsympath, dlinfo.dli_fname, sizeof(dsympath)); strlcat(dsympath, ".dSYM/Contents/Resources/DWARF/", sizeof(dsympath)); strlcat(dsympath, strrchr(dlinfo.dli_fname,'/')+1, sizeof(dsympath)); #ifdef LLVM35 auto errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #endif #else // On non OS X systems we need to mmap another copy because of the permissions on the mmaped // shared library. #ifdef LLVM35 auto errorobj = llvm::object::ObjectFile::createObjectFile(fname); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(fname); #endif #endif #ifdef LLVM36 if (errorobj) { obj = errorobj.get().getBinary().release(); errorobj.get().getBuffer().release(); #elif LLVM35 if (errorobj) { obj = errorobj.get(); #else if (errorobj != NULL) { obj = errorobj; #endif #ifdef _OS_DARWIN_ if (getObjUUID(morigobj,uuid2) && memcmp(uuid,uuid2,sizeof(uuid)) == 0) { #endif #ifdef LLVM36 context = DIContext::getDWARFContext(*obj); #else context = DIContext::getDWARFContext(obj); #endif slide = -(uint64_t)fbase; #ifdef _OS_DARWIN_ } #endif #ifdef _OS_WINDOWS_ assert(obj->isCOFF()); llvm::object::COFFObjectFile *coffobj = (llvm::object::COFFObjectFile *)obj; const llvm::object::pe32plus_header *pe32plus; coffobj->getPE32PlusHeader(pe32plus); if (pe32plus != NULL) { slide = pe32plus->ImageBase-fbase; } else { const llvm::object::pe32_header *pe32; coffobj->getPE32Header(pe32); if (pe32 == NULL) { obj = NULL; context = NULL; } else { slide = pe32->ImageBase-fbase; } } #endif } objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; } else { obj = it->second.obj; context = it->second.ctx; slide = it->second.slide; } #ifdef _OS_DARWIN_ lookup: #endif lookup_pointer(context, name, line, filename, pointer+slide, jl_is_sysimg(fname), fromC); return; } *fromC = 1; return; } #endif void jl_getFunctionInfo(const char **name, size_t *line, const char **filename, size_t pointer, int *fromC, int skipC) { *name = NULL; *line = -1; *filename = "no file"; *fromC = 0; #if USE_MCJIT // With MCJIT we can get function information directly from the ObjectFile std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap(); std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(pointer); if (it == objmap.end()) return jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC); if ((pointer - it->first) > it->second.size) return jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC); #ifdef LLVM36 DIContext *context = DIContext::getDWARFContext(*it->second.object); #else DIContext *context = DIContext::getDWARFContext(it->second.object); #endif lookup_pointer(context, name, line, filename, pointer, 1, fromC); #else // !USE_MCJIT // Without MCJIT we use the FuncInfo structure containing address maps std::map<size_t, FuncInfo, revcomp> &info = jl_jit_events->getMap(); std::map<size_t, FuncInfo, revcomp>::iterator it = info.lower_bound(pointer); if (it != info.end() && (size_t)(*it).first + (*it).second.lengthAdr >= pointer) { // We do this to hide the jlcall wrappers when getting julia backtraces, // but it is still good to have them for regular lookup of C frames. if (skipC && (*it).second.lines.empty()) { // Technically not true, but we don't want them // in julia backtraces, so close enough *fromC = 1; return; } *name = (*it).second.name.c_str(); *filename = (*it).second.filename.c_str(); if ((*it).second.lines.empty()) { *fromC = 1; return; } std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit = (*it).second.lines.begin(); JITEvent_EmittedFunctionDetails::LineStart prev = *vit; if ((*it).second.func) { DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); *filename = debugscope.getFilename().data(); // the DISubprogram has the un-mangled name, so use that if // available. However, if the scope need not be the current // subprogram. if (debugscope.getName().data() != NULL) *name = debugscope.getName().data(); else *name = jl_demangle(*name); } vit++; while (vit != (*it).second.lines.end()) { if (pointer <= (*vit).Address) { *line = prev.Loc.getLine(); break; } prev = *vit; vit++; } if (*line == (size_t) -1) { *line = prev.Loc.getLine(); } } else { jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC); } #endif // USE_MCJIT }
void GCOVProfiler::emitProfileNotes() { NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return; for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { // Each compile unit gets its own .gcno file. This means that whether we run // this pass over the original .o's as they're produced, or run it after // LTO, we'll generate the same .gcno files. auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; std::error_code EC; raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, sys::fs::F_None); if (EC) { Ctx->emitError(Twine("failed to open coverage notes file for writing: ") + EC.message()); continue; } std::string EdgeDestinations; unsigned FunctionIdent = 0; for (auto &F : M->functions()) { DISubprogram *SP = F.getSubprogram(); if (!SP) continue; if (!functionHasLines(F)) continue; // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; // gcov expects every function to start with an entry block that has a // single successor, so split the entry block to make sure of that. BasicBlock &EntryBlock = F.getEntryBlock(); BasicBlock::iterator It = EntryBlock.begin(); while (shouldKeepInEntry(It)) ++It; EntryBlock.splitBasicBlock(It); Funcs.push_back(make_unique<GCOVFunction>(SP, &F, &out, FunctionIdent++, Options.UseCfgChecksum, Options.ExitBlockBeforeBody)); GCOVFunction &Func = *Funcs.back(); for (auto &BB : F) { GCOVBlock &Block = Func.getBlock(&BB); TerminatorInst *TI = BB.getTerminator(); if (int successors = TI->getNumSuccessors()) { for (int i = 0; i != successors; ++i) { Block.addEdge(Func.getBlock(TI->getSuccessor(i))); } } else if (isa<ReturnInst>(TI)) { Block.addEdge(Func.getReturnBlock()); } uint32_t Line = 0; for (auto &I : BB) { // Debug intrinsic locations correspond to the location of the // declaration, not necessarily any statements or expressions. if (isa<DbgInfoIntrinsic>(&I)) continue; const DebugLoc &Loc = I.getDebugLoc(); if (!Loc) continue; // Artificial lines such as calls to the global constructors. if (Loc.getLine() == 0) continue; if (Line == Loc.getLine()) continue; Line = Loc.getLine(); if (SP != getDISubprogram(Loc.getScope())) continue; GCOVLines &Lines = Block.getFile(SP->getFilename()); Lines.addLine(Loc.getLine()); } } EdgeDestinations += Func.getEdgeDestinations(); } FileChecksums.push_back(hash_value(EdgeDestinations)); out.write("oncg", 4); out.write(ReversedVersion, 4); out.write(reinterpret_cast<char*>(&FileChecksums.back()), 4); for (auto &Func : Funcs) { Func->setCfgChecksum(FileChecksums.back()); Func->writeOut(); } out.write("\0\0\0\0\0\0\0\0", 8); // EOF out.close(); } }
void jl_dump_function_asm(const char *Fptr, size_t Fsize, #ifndef USE_MCJIT std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo, #else const object::ObjectFile *objectfile, #endif formatted_raw_ostream &stream) { // Initialize targets and assembly printers/parsers. // Avoids hard-coded targets - will generally be only host CPU anyway. llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetDisassembler(); // Get the host information std::string TripleName; if (TripleName.empty()) TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); std::string MCPU = sys::getHostCPUName(); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(TheTriple); std::string err; const Target* TheTarget = TargetRegistry::lookupTarget(TripleName, err); // Set up required helpers and streamer #ifdef LLVM35 std::unique_ptr<MCStreamer> Streamer; #else OwningPtr<MCStreamer> Streamer; #endif SourceMgr SrcMgr; #ifdef LLVM35 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); #elif defined(LLVM34) llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); #else llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); #endif assert(MAI && "Unable to create target asm info!"); #ifdef LLVM35 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); #else llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); #endif assert(MRI && "Unable to create target register info!"); #ifdef LLVM35 std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); #else OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); #endif #ifdef LLVM34 MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); #else MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); #endif MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default, Ctx); // Set up Subtarget and Disassembler #ifdef LLVM35 std::unique_ptr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); std::unique_ptr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI, Ctx)); #else OwningPtr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); OwningPtr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); #endif if (!DisAsm) { JL_PRINTF(JL_STDERR, "error: no disassembler for target", TripleName.c_str(), "\n"); return; } unsigned OutputAsmVariant = 1; bool ShowEncoding = false; bool ShowInst = false; #ifdef LLVM35 std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCInstrAnalysis> MCIA(TheTarget->createMCInstrAnalysis(MCII.get())); #else OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); OwningPtr<MCInstrAnalysis> MCIA(TheTarget->createMCInstrAnalysis(MCII.get())); #endif MCInstPrinter* IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI); MCCodeEmitter *CE = 0; MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); #ifdef LLVM34 MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); #else MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); #endif } Streamer.reset(TheTarget->createAsmStreamer(Ctx, stream, /*asmverbose*/true, #ifndef LLVM35 /*useLoc*/ true, /*useCFI*/ true, #endif /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); #ifdef LLVM36 Streamer->InitSections(true); #else Streamer->InitSections(); #endif // Make the MemoryObject wrapper #ifdef LLVM36 ArrayRef<uint8_t> memoryObject(const_cast<uint8_t*>((const uint8_t*)Fptr),Fsize); #else FuncMCView memoryObject(Fptr, Fsize); #endif SymbolTable DisInfo(Ctx, memoryObject); #ifdef USE_MCJIT if (!objectfile) return; #ifdef LLVM36 DIContext *di_ctx = DIContext::getDWARFContext(*objectfile); #else DIContext *di_ctx = DIContext::getDWARFContext(const_cast<object::ObjectFile*>(objectfile)); #endif if (di_ctx == NULL) return; DILineInfoTable lineinfo = di_ctx->getLineInfoForAddressRange((size_t)Fptr, Fsize); #else typedef std::vector<JITEvent_EmittedFunctionDetails::LineStart> LInfoVec; #endif // 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 #ifdef LLVM35 DisAsm->setSymbolizer(std::unique_ptr<MCSymbolizer>(new MCExternalSymbolizer( Ctx, std::unique_ptr<MCRelocationInfo>(new MCRelocationInfo(Ctx)), OpInfoLookup, SymbolLookup, &DisInfo))); #else DisAsm->setupForSymbolicDisassembly( OpInfoLookup, SymbolLookup, &DisInfo, &Ctx); #endif } uint64_t nextLineAddr = -1; #ifdef USE_MCJIT // Set up the line info DILineInfoTable::iterator lineIter = lineinfo.begin(); DILineInfoTable::iterator lineEnd = lineinfo.end(); if (lineIter != lineEnd) { nextLineAddr = lineIter->first; if (pass != 0) { #ifdef LLVM35 stream << "Filename: " << lineIter->second.FileName << "\n"; #else stream << "Filename: " << lineIter->second.getFileName() << "\n"; #endif } } #else // Set up the line info LInfoVec::iterator lineIter = lineinfo.begin(); LInfoVec::iterator lineEnd = lineinfo.end(); if (lineIter != lineEnd) { nextLineAddr = (*lineIter).Address; DISubprogram debugscope = DISubprogram((*lineIter).Loc.getScope(jl_LLVMContext)); if (pass != 0) { stream << "Filename: " << debugscope.getFilename() << "\n"; stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; } } #endif uint64_t Index = 0; uint64_t absAddr = 0; uint64_t insSize = 0; // Do the disassembly for (Index = 0, absAddr = (uint64_t)Fptr; Index < Fsize; Index += insSize, absAddr += insSize) { if (nextLineAddr != (uint64_t)-1 && absAddr == nextLineAddr) { #ifdef USE_MCJIT #ifdef LLVM35 if (pass != 0) stream << "Source line: " << lineIter->second.Line << "\n"; #else if (pass != 0) stream << "Source line: " << lineIter->second.getLine() << "\n"; #endif nextLineAddr = (++lineIter)->first; #else if (pass != 0) stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; nextLineAddr = (*++lineIter).Address; #endif } if (pass != 0) { // Uncomment this to output addresses for all instructions // stream << Index << ": "; const char *symbolName = DisInfo.lookupSymbol(Index); if (symbolName) stream << symbolName << ":"; } MCInst Inst; MCDisassembler::DecodeStatus S; S = DisAsm->getInstruction(Inst, insSize, memoryObject, Index, /*REMOVE*/ nulls(), nulls()); switch (S) { case MCDisassembler::Fail: if (pass != 0) SrcMgr.PrintMessage(SMLoc::getFromPointer(Fptr + Index), SourceMgr::DK_Warning, "invalid instruction encoding"); if (insSize == 0) insSize = 1; // skip illegible bytes break; case MCDisassembler::SoftFail: if (pass != 0) SrcMgr.PrintMessage(SMLoc::getFromPointer(Fptr + Index), SourceMgr::DK_Warning, "potentially undefined instruction encoding"); // Fall through case MCDisassembler::Success: if (pass == 0) { // Pass 0: Record all branch targets if (MCIA->isBranch(Inst)) { uint64_t addr; #ifdef LLVM35 if (MCIA->evaluateBranch(Inst, Index, insSize, addr)) #else if ((addr = MCIA->evaluateBranch(Inst, Index, insSize)) != (uint64_t)-1) #endif DisInfo.insertAddress(addr); } } else { // Pass 1: Output instruction #ifdef LLVM35 Streamer->EmitInstruction(Inst, *STI); #else Streamer->EmitInstruction(Inst); #endif } break; } } if (pass == 0) DisInfo.createSymbols(); } }
void jl_dump_function_asm(void* Fptr, size_t Fsize, std::vector<JITEvent_EmittedFunctionDetails::LineStart> lineinfo, formatted_raw_ostream &stream) { // Initialize targets and assembly printers/parsers. // Avoids hard-coded targets - will generally be only host CPU anyway. llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetDisassembler(); // Get the host information std::string TripleName; if (TripleName.empty()) TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); std::string MCPU = sys::getHostCPUName(); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(TheTriple); std::string err; const Target* TheTarget = TargetRegistry::lookupTarget(TripleName, err); // Set up required helpers and streamer OwningPtr<MCStreamer> Streamer; SourceMgr SrcMgr; #ifdef LLVM34 llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); #else llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); #endif assert(MAI && "Unable to create target asm info!"); llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); #ifdef LLVM34 MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); #else MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); #endif MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default, Ctx); // Set up Subtarget and Disassembler OwningPtr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); #ifdef LLVM35 OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI, Ctx)); #else OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); #endif if (!DisAsm) { JL_PRINTF(JL_STDERR, "error: no disassembler for target", TripleName.c_str(), "\n"); return; } unsigned OutputAsmVariant = 1; bool ShowEncoding = false; bool ShowInst = false; OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); MCInstPrinter* IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI); MCCodeEmitter *CE = 0; MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); #ifdef LLVM34 MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); #else MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); #endif } Streamer.reset(TheTarget->createAsmStreamer(Ctx, stream, /*asmverbose*/true, #ifndef LLVM35 /*useLoc*/ true, /*useCFI*/ true, #endif /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); Streamer->InitSections(); // Make the MemoryObject wrapper FuncMCView memoryObject(Fptr, Fsize); uint64_t Size; uint64_t Index; uint64_t absAddr; // Set up the line info typedef std::vector<JITEvent_EmittedFunctionDetails::LineStart> LInfoVec; LInfoVec::iterator lineIter = lineinfo.begin(); lineIter = lineinfo.begin(); uint64_t nextLineAddr = -1; DISubprogram debugscope; if (lineIter != lineinfo.end()) { nextLineAddr = (*lineIter).Address; debugscope = DISubprogram((*lineIter).Loc.getScope(jl_LLVMContext)); stream << "Filename: " << debugscope.getFilename().data() << "\n"; stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; } // Do the disassembly for (Index = 0, absAddr = (uint64_t)Fptr; Index < memoryObject.getExtent(); Index += Size, absAddr += Size) { if (nextLineAddr != (uint64_t)-1 && absAddr == nextLineAddr) { stream << "Source line: " << (*lineIter).Loc.getLine() << "\n"; nextLineAddr = (*++lineIter).Address; } MCInst Inst; MCDisassembler::DecodeStatus S; S = DisAsm->getInstruction(Inst, Size, memoryObject, Index, /*REMOVE*/ nulls(), nulls()); switch (S) { case MCDisassembler::Fail: SrcMgr.PrintMessage(SMLoc::getFromPointer(memoryObject[Index]), SourceMgr::DK_Warning, "invalid instruction encoding"); if (Size == 0) Size = 1; // skip illegible bytes break; case MCDisassembler::SoftFail: SrcMgr.PrintMessage(SMLoc::getFromPointer(memoryObject[Index]), SourceMgr::DK_Warning, "potentially undefined instruction encoding"); // Fall through case MCDisassembler::Success: #ifdef LLVM35 Streamer->EmitInstruction(Inst, *STI); #else Streamer->EmitInstruction(Inst); #endif break; } } }
void jl_getFunctionInfo(const char **name, int *line, const char **filename, size_t pointer, int skipC) { *name = NULL; *line = -1; *filename = "no file"; #if USE_MCJIT // With MCJIT we can get function information directly from the ObjectFile std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap(); std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(pointer); if (it == objmap.end()) return jl_getDylibFunctionInfo(name,line,filename,pointer,skipC); if ((pointer - it->first) > it->second.size) return jl_getDylibFunctionInfo(name,line,filename,pointer,skipC); DIContext *context = DIContext::getDWARFContext(it->second.object); lookup_pointer(context, name, line, filename, pointer, 1); #else // !USE_MCJIT // Without MCJIT we use the FuncInfo structure containing address maps std::map<size_t, FuncInfo, revcomp> &info = jl_jit_events->getMap(); std::map<size_t, FuncInfo, revcomp>::iterator it = info.lower_bound(pointer); if (it != info.end() && (size_t)(*it).first + (*it).second.lengthAdr >= pointer) { // commenting these lines out skips functions that don't // have explicit debug info. this is useful for hiding // the jlcall wrapper functions we generate. #if LLVM_VERSION_MAJOR == 3 #if LLVM_VERSION_MINOR == 0 //*name = &(*(*it).second.func).getNameStr()[0]; #elif LLVM_VERSION_MINOR >= 1 //*name = (((*(*it).second.func).getName()).data()); #endif #endif std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit = (*it).second.lines.begin(); JITEvent_EmittedFunctionDetails::LineStart prev = *vit; if ((*it).second.func) { DISubprogram debugscope = DISubprogram(prev.Loc.getScope((*it).second.func->getContext())); *filename = debugscope.getFilename().data(); // the DISubprogram has the un-mangled name, so use that if // available. *name = debugscope.getName().data(); } else { *name = (*it).second.name.c_str(); *filename = (*it).second.filename.c_str(); } vit++; while (vit != (*it).second.lines.end()) { if (pointer <= (*vit).Address) { *line = prev.Loc.getLine(); break; } prev = *vit; vit++; } if (*line == -1) { *line = prev.Loc.getLine(); } } else { jl_getDylibFunctionInfo(name,line,filename,pointer,skipC); } #endif // USE_MCJIT }