diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index e6dadac6ba6bf..5af27f4d728b9 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -3,6 +3,8 @@ struct FuncInfo{ const Function* func; size_t lengthAdr; + std::string name; + std::string filename; #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_) PRUNTIME_FUNCTION fnentry; #endif @@ -66,9 +68,10 @@ class JuliaJITEventListener: public JITEventListener } } jl_in_stackwalk = 0; - FuncInfo tmp = {&F, Size, tbl, Details.LineStarts}; + + FuncInfo tmp = {&F, Size, std::string(), std::string(), tbl, Details.LineStarts}; #else - FuncInfo tmp = {&F, Size, Details.LineStarts}; + FuncInfo tmp = {&F, Size, std::string(), std::string(), Details.LineStarts}; #endif if (tmp.lines.size() != 0) info[(size_t)(Code)] = tmp; } @@ -104,12 +107,17 @@ void jl_getFunctionInfo(const char **name, int *line, const char **filename, siz std::vector::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(); + 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++; @@ -249,3 +257,88 @@ extern "C" void jl_write_coverage_data(void) } } } + +#ifndef _OS_WINDOWS_ +typedef std::map FuncInfoMap; +extern "C" void jl_dump_linedebug_info() { + FuncInfoMap info = jl_jit_events->getMap(); + FuncInfoMap::iterator infoiter = info.begin(); + std::vector::iterator lineiter = (*infoiter).second.lines.begin(); + + Type *li_types[2] = {T_size, T_size}; + StructType *T_lineinfo = StructType::get(jl_LLVMContext, ArrayRef(std::vector(li_types, li_types+2)), true); + + std::vector funcinfo_array; + funcinfo_array.push_back( ConstantInt::get(T_size, 0) ); + + for (; infoiter != info.end(); infoiter++) { + std::vector functionlines; + + // get the base address for offset calculation + size_t fptr = (size_t)(*infoiter).first; + + lineiter = (*infoiter).second.lines.begin(); + JITEvent_EmittedFunctionDetails::LineStart prev = *lineiter; + + // loop over the EmittedFunctionDetails vector + while (lineiter != (*infoiter).second.lines.end()) { + // store the individual {offset, line} entries + Constant* tmpline[2] = { ConstantInt::get(T_size, (*lineiter).Address - fptr), + ConstantInt::get(T_size, (*lineiter).Loc.getLine()) }; + Constant *lineinfo = ConstantStruct::get(T_lineinfo, makeArrayRef(tmpline)); + functionlines.push_back(lineinfo); + lineiter++; + } + + DISubprogram debugscope = + DISubprogram(prev.Loc.getScope((*infoiter).second.func->getContext())); + + Constant *info_data[6] = { ConstantExpr::getBitCast( const_cast((*infoiter).second.func), T_psize), + ConstantDataArray::getString( jl_LLVMContext, StringRef(debugscope.getName().str())), + ConstantDataArray::getString( jl_LLVMContext, StringRef(debugscope.getFilename().str())), + ConstantInt::get(T_size, (*infoiter).second.lengthAdr), + ConstantInt::get(T_size, functionlines.size()), + ConstantArray::get(ArrayType::get(T_lineinfo, functionlines.size()), ArrayRef(functionlines)) + }; + Constant *st = ConstantStruct::getAnon(jl_LLVMContext, ArrayRef(info_data), true); + funcinfo_array.push_back( st ); + } + // set first element to the total number of FuncInfo entries + funcinfo_array[0] = ConstantInt::get(T_size, funcinfo_array.size() - 1); + Constant *st_lineinfo = ConstantStruct::getAnon( jl_LLVMContext, ArrayRef(funcinfo_array), true ); + new GlobalVariable( + *jl_Module, + st_lineinfo->getType(), + true, + GlobalVariable::ExternalLinkage, + st_lineinfo, + "jl_linedebug_info"); +} + +extern "C" void jl_restore_linedebug_info(uv_lib_t *handle) { + uintptr_t *infoptr = (uintptr_t*)jl_dlsym(handle, const_cast("jl_linedebug_info")); + size_t funccount = (size_t)(*infoptr++); + + for (size_t i = 0; i < funccount; i++) { + uintptr_t fptr = (*infoptr++); + char *name = (char*)infoptr; + infoptr = (uintptr_t*)(((char*)infoptr) + strlen( (const char*)infoptr) + 1); + char *filename = (char*)infoptr; + infoptr = (uintptr_t*)(((char*)infoptr) + strlen( (const char*)infoptr) + 1); + size_t lengthAdr = (*infoptr++); + size_t numel = (*infoptr++); + + std::vector linestarts; + + for (size_t j = 0; j < numel; j++) { + // dummy element for the MDNode, which we need so that the DebucLoc keeps info + SmallVector tmpelt; + JITEvent_EmittedFunctionDetails::LineStart linestart = + { (uintptr_t)fptr + (*infoptr++), DebugLoc::get( (*infoptr++), 0, MDNode::get(jl_LLVMContext, tmpelt) ) }; + linestarts.push_back(linestart); + } + FuncInfo info = { NULL, lengthAdr, std::string(name), std::string(filename), linestarts }; + jl_jit_events->getMap()[(size_t)fptr] = info; + } +} +#endif diff --git a/src/dump.c b/src/dump.c index f3f1d19571727..d131c969fbac9 100644 --- a/src/dump.c +++ b/src/dump.c @@ -104,24 +104,25 @@ jl_value_t ***sysimg_gvars = NULL; extern int globalUnique; extern void jl_cpuid(int32_t CPUInfo[4], int32_t InfoType); extern const char *jl_cpu_string; +uv_lib_t *jl_sysimg_handle = NULL; static void jl_load_sysimg_so(char *fname) { // attempt to load the pre-compiled sysimg at fname // if this succeeds, sysimg_gvars will be a valid array // otherwise, it will be NULL - uv_lib_t *sysimg_handle = jl_load_dynamic_library_e(fname, JL_RTLD_DEFAULT | JL_RTLD_GLOBAL); - if (sysimg_handle != 0) { - sysimg_gvars = (jl_value_t***)jl_dlsym(sysimg_handle, "jl_sysimg_gvars"); - globalUnique = *(size_t*)jl_dlsym(sysimg_handle, "jl_globalUnique"); - const char *cpu_target = (const char*)jl_dlsym(sysimg_handle, "jl_sysimg_cpu_target"); + jl_sysimg_handle = jl_load_dynamic_library_e(fname, JL_RTLD_DEFAULT | JL_RTLD_GLOBAL); + if (jl_sysimg_handle != 0) { + sysimg_gvars = (jl_value_t***)jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars"); + globalUnique = *(size_t*)jl_dlsym(jl_sysimg_handle, "jl_globalUnique"); + const char *cpu_target = (const char*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_cpu_target"); if (strcmp(cpu_target,jl_cpu_string) != 0) jl_error("Julia and the system image were compiled for different architectures.\n" "Please delete or regenerate sys.{so,dll,dylib}."); uint32_t info[4]; jl_cpuid((int32_t*)info, 1); if (strcmp(cpu_target, "native") == 0) { - uint64_t saved_cpuid = *(uint64_t*)jl_dlsym(sysimg_handle, "jl_sysimg_cpu_cpuid"); + uint64_t saved_cpuid = *(uint64_t*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_cpu_cpuid"); if (saved_cpuid != (((uint64_t)info[2])|(((uint64_t)info[3])<<32))) jl_error("Target architecture mismatch. Please delete or regenerate sys.{so,dll,dylib}."); } @@ -1103,6 +1104,10 @@ void jl_restore_system_image(char *fname) jl_get_binding_wr(jl_core_module, jl_symbol("JULIA_HOME"))->value = jl_cstr_to_string(julia_home); jl_update_all_fptrs(); +#ifndef _OS_WINDOWS_ + // restore the line information for Julia backtraces + if (jl_sysimg_handle != NULL) jl_restore_linedebug_info(jl_sysimg_handle); +#endif } void jl_init_restored_modules() diff --git a/src/init.c b/src/init.c index 780a75f97d343..2dbec6bac0f94 100644 --- a/src/init.c +++ b/src/init.c @@ -881,6 +881,9 @@ DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char * free(build_ji); char *build_o; if (asprintf(&build_o, "%s.o",build_path) > 0) { +#ifndef _OS_WINDOWS_ + jl_dump_linedebug_info(); +#endif jl_dump_objfile(build_o,0); free(build_o); } diff --git a/src/julia_internal.h b/src/julia_internal.h index c5d45b1c51adc..8e44083710ad6 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -117,6 +117,11 @@ DLLEXPORT size_t rec_backtrace_ctx(ptrint_t *data, size_t maxsize, bt_context_t size_t rec_backtrace_ctx_dwarf(ptrint_t *data, size_t maxsize, bt_context_t ctx); #endif +#ifndef _OS_WINDOWS_ +DLLEXPORT void jl_dump_linedebug_info(); +DLLEXPORT void jl_restore_linedebug_info(uv_lib_t* handle); +#endif + #ifdef __cplusplus } #endif