--- include/llvm/Target/TargetOptions.h (revision 105825) +++ include/llvm/Target/TargetOptions.h (working copy) @@ -115,6 +115,11 @@ /// debug information and notify a debugger about it. extern bool JITEmitDebugInfo; + /// JITEmitDebugInfoAddr2Line - This flag indicates that the JIT should emit + /// brief debug information (function address and name) for some debugging + /// tools, like addr2line from binutils does + extern bool JITEmitDebugInfoAddr2Line; + /// JITEmitDebugInfoToDisk - This flag indicates that the JIT should write /// the object files generated by the JITEmitDebugInfo flag to disk. This /// flag is hidden and is only for debugging the debug info. --- lib/Target/TargetMachine.cpp (revision 105825) +++ lib/Target/TargetMachine.cpp (working copy) @@ -24,6 +24,7 @@ // namespace llvm { + class raw_fd_ostream; bool LessPreciseFPMADOption; bool PrintMachineCode; bool NoFramePointerElim; @@ -38,6 +39,8 @@ bool NoZerosInBSS; bool JITExceptionHandling; bool JITEmitDebugInfo; + bool JITEmitDebugInfoAddr2Line; + raw_fd_ostream* JITEmitDebugInfoAddr2LineStream(NULL); bool JITEmitDebugInfoToDisk; bool UnwindTablesMandatory; Reloc::Model RelocationModel; @@ -131,6 +134,11 @@ cl::init(EMIT_DEBUG)); #undef EMIT_DEBUG static cl::opt +EmitJitDebugInfoAddr2Line("jit-emit-debug-addr2line", + cl::desc("Emit addr2line-like debug information"), + cl::location(JITEmitDebugInfoAddr2Line), + cl::init(true)); +static cl::opt EmitJitDebugInfoToDisk("jit-emit-debug-to-disk", cl::Hidden, cl::desc("Emit debug info objfiles to disk"), --- lib/ExecutionEngine/JIT/JIT.cpp (revision 105825) +++ lib/ExecutionEngine/JIT/JIT.cpp (working copy) @@ -26,12 +26,14 @@ #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetJITInfo.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MutexGuard.h" #include "llvm/System/DynamicLibrary.h" #include "llvm/Config/config.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -55,6 +57,10 @@ extern void *__dso_handle __attribute__ ((__visibility__ ("hidden"))); #endif +namespace llvm { + extern raw_fd_ostream *JITEmitDebugInfoAddr2LineStream; +} + namespace { static struct RegisterJIT { @@ -392,12 +398,38 @@ return result; } +class addr2line_debug_object { +private: + raw_fd_ostream *os; +public: + addr2line_debug_object() : os(NULL) { + if (JITEmitDebugInfoAddr2Line && JITEmitDebugInfoAddr2LineStream==NULL) { + std::string ErrorInfo; + os = JITEmitDebugInfoAddr2LineStream = new raw_fd_ostream("/tmp/llvm_debug_addr2line.txt", ErrorInfo, raw_fd_ostream::F_Append); + if (!ErrorInfo.empty()) { + errs() << "Error opening debug info file: " << ErrorInfo << "\n"; + exit(1); + } + } + } + ~addr2line_debug_object() { + if (os!=NULL) { + os->flush(); + delete os; + os = JITEmitDebugInfoAddr2LineStream = NULL; + } + } +}; + /// run - Start execution with the specified function and arguments. /// GenericValue JIT::runFunction(Function *F, const std::vector &ArgValues) { assert(F && "Function *F was null at entry to run()"); + // addr2line debug output object: its only active if JITEmitDebugInfoAddr2Line is set + addr2line_debug_object addr2line_debug; + void *FPtr = getPointerToFunction(F); assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); const FunctionType *FTy = F->getFunctionType(); @@ -557,6 +589,7 @@ GenericValue Result = runFunction(Stub, std::vector()); // Erase it, since no other function can have a reference to it. Stub->eraseFromParent(); + // And return the result. return Result; } @@ -687,6 +720,14 @@ return Addr; } +void *JIT::getPointerToBasicBlock(BasicBlock *BB) { + // make sure it's function is compiled by JIT + (void)getPointerToFunction(BB->getParent()); + // return PC address + assert(BB->getPCInJit()!=~uintptr_t(0) && "JIT does not have BB address for address-of-label, was it eliminated by optimizer?"); + return (void*)BB->getPCInJit(); +} + /// getOrEmitGlobalVariable - Return the address of the specified global /// variable, possibly emitting it to memory if needed. This is used by the /// Emitter. --- lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp (revision 105825) +++ lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp (working copy) @@ -31,6 +31,8 @@ namespace llvm { +extern raw_fd_ostream *JITEmitDebugInfoAddr2LineStream; + // This must be kept in sync with gdb/gdb/jit.h . extern "C" { @@ -137,6 +139,11 @@ std::string Buffer = MakeELF(F, I); + // write brief debug info is requested + if (JITEmitDebugInfoAddr2Line) { + *JITEmitDebugInfoAddr2LineStream << I.FnStart << " T " << F->getName() << "\n"; + } + jit_code_entry *JITCodeEntry = new jit_code_entry(); JITCodeEntry->symfile_addr = Buffer.c_str(); JITCodeEntry->symfile_size = Buffer.size();