From 114335a7210eaf36183b49e7c3d6d2568c773a7c Mon Sep 17 00:00:00 2001 From: Isaiah Norton Date: Wed, 9 Apr 2014 22:37:17 -0400 Subject: [PATCH 1/2] Dump EmittedFunctionDetails to sysimage --- src/debuginfo.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++++ src/init.c | 1 + src/julia.h | 2 ++ 3 files changed, 51 insertions(+) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index e6dadac6ba6bf..201e627f82648 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -249,3 +249,51 @@ extern "C" void jl_write_coverage_data(void) } } } + +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++) { + // loop over the EmittedFunctionDetails vector + lineiter = (*infoiter).second.lines.begin(); + + // get the base address for offset calculation + size_t fptr = (size_t)(*infoiter).first; + + std::vector functionlines; + 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++; + } + Constant *info_data[4] = { ConstantDataArray::getString( jl_LLVMContext, StringRef((*infoiter).second.func->getName().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"); +} diff --git a/src/init.c b/src/init.c index 780a75f97d343..e1c73f9e12974 100644 --- a/src/init.c +++ b/src/init.c @@ -881,6 +881,7 @@ 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) { + jl_dump_linedebug_info(); jl_dump_objfile(build_o,0); free(build_o); } diff --git a/src/julia.h b/src/julia.h index 6985d8bbd328a..5da9bf3c548d8 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1288,6 +1288,8 @@ DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v); void jl_print_gc_stats(JL_STREAM *s); #endif +DLLEXPORT void jl_dump_linedebug_info(); + // compiler options ----------------------------------------------------------- typedef struct { From 05a5109f2eb78a186edef4a41ac3c6177a4537f6 Mon Sep 17 00:00:00 2001 From: Isaiah Norton Date: Sat, 12 Apr 2014 01:09:34 -0400 Subject: [PATCH 2/2] Restore linedebug info from sysimage - Fiddles with FuncInfo struct to optionally store name and filename info - sysimg_handle -> jl_sysimg_handle (not exported) - adds jl_restore_linedebug_info(uv_lib_t*) --- src/debuginfo.cpp | 75 +++++++++++++++++++++++++++++++++++--------- src/dump.c | 17 ++++++---- src/init.c | 2 ++ src/julia.h | 2 -- src/julia_internal.h | 5 +++ 5 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 201e627f82648..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++; @@ -250,6 +258,7 @@ 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(); @@ -261,15 +270,17 @@ extern "C" void jl_dump_linedebug_info() { std::vector funcinfo_array; funcinfo_array.push_back( ConstantInt::get(T_size, 0) ); - + for (; infoiter != info.end(); infoiter++) { - // loop over the EmittedFunctionDetails vector - lineiter = (*infoiter).second.lines.begin(); - + std::vector functionlines; + // get the base address for offset calculation size_t fptr = (size_t)(*infoiter).first; - - std::vector functionlines; + + 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), @@ -278,7 +289,13 @@ extern "C" void jl_dump_linedebug_info() { functionlines.push_back(lineinfo); lineiter++; } - Constant *info_data[4] = { ConstantDataArray::getString( jl_LLVMContext, StringRef((*infoiter).second.func->getName().str())), + + 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)) @@ -297,3 +314,31 @@ extern "C" void jl_dump_linedebug_info() { 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 e1c73f9e12974..2dbec6bac0f94 100644 --- a/src/init.c +++ b/src/init.c @@ -881,7 +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.h b/src/julia.h index 5da9bf3c548d8..6985d8bbd328a 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1288,8 +1288,6 @@ DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v); void jl_print_gc_stats(JL_STREAM *s); #endif -DLLEXPORT void jl_dump_linedebug_info(); - // compiler options ----------------------------------------------------------- typedef struct { 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