static DWORD64 WINAPI JuliaGetModuleBase64( _In_ HANDLE hProcess, _In_ DWORD64 dwAddr) { //jl_printf(JL_STDOUT, "lookup base %d\n", dwAddr); #ifdef _CPU_X86_64_ DWORD64 ImageBase; PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(dwAddr, &ImageBase, &HistoryTable); if (fn) return ImageBase; if (jl_in_stackwalk) { return 0; } jl_in_stackwalk = 1; DWORD64 fbase = SymGetModuleBase64(hProcess, dwAddr); jl_in_stackwalk = 0; return fbase; #else if (dwAddr == HistoryTable.dwAddr) return HistoryTable.ImageBase; DWORD64 ImageBase = jl_getUnwindInfo(dwAddr); if (ImageBase) { HistoryTable.dwAddr = dwAddr; HistoryTable.ImageBase = ImageBase; return ImageBase; } return SymGetModuleBase64(hProcess, dwAddr); #endif }
/*********************************************************************** * SymGetModuleBase (DBGHELP.@) */ DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr) { DWORD64 ret; ret = SymGetModuleBase64(hProcess, dwAddr); return validate_addr64(ret) ? ret : 0; }
void StackWalker::WriteModuleName(std::ostream& os, HANDLE process, DWORD64 program_counter) { DWORD64 module_base = SymGetModuleBase64(process, program_counter); if (module_base) { std::string module_name = GetModulePath(reinterpret_cast<HMODULE>(module_base)); if (!module_name.empty()) os << module_name << " | "; else os << "Unknown module | "; } else { os << "Unknown module | "; } }
prmap_t *Paddr_to_map(struct ps_prochandle *P, uintptr_t addr) { DWORD64 p; prmap_t *t; if ((p = SymGetModuleBase64(P->phandle, addr)) == 0) { dprintf("SymGetModuleBase64 failed (%d) at address %p: %x\n", P->pid, addr, GetLastError()); return NULL; } if ((t = malloc(sizeof(prmap_t))) == NULL) { return NULL; } t->pr_vaddr = p; t->pr_mflags = MA_READ; return t; }
void HEART_API InitMemTracking() { #ifdef HEART_TRACK_MEMORY_ALLOCS InitializeCriticalSection(&g_access); hSysCall::hInitSystemDebugLibs(); if (g_file == NULL) { if (g_file = fopen("mem_track.txt", "w")) { g_open = hTrue; hMemTrackingHeader header; header.baseAddress_=SymGetModuleBase64(GetCurrentProcess(), (DWORD64)&InitMemTracking); GetModuleFileName(0, header.moduleName_, (hUint)hArraySize(header.moduleName_)); fwrite(&header, sizeof(hMemTrackingHeader), 1, g_file); fwrite("\n", 1, 1, g_file); atexit(memTrackExitHandle); //TrackPushMarker("ROOT"); } } #endif }
/* * The GetModuleBase64 function retrieves the base address of the module that * contains the specified address. * * Same as SymGetModuleBase64, but that seems to often cause problems. */ DWORD64 WINAPI MgwSymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddress) { if (hProcess == GetCurrentProcess()) { HMODULE hModule = NULL; BOOL bRet = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)(UINT_PTR)dwAddress, &hModule); if (bRet) { return (DWORD64)(UINT_PTR)hModule; } } MEMORY_BASIC_INFORMATION Buffer; if (VirtualQueryEx(hProcess, (LPCVOID)(UINT_PTR)dwAddress, &Buffer, sizeof Buffer) != 0) { return (DWORD64)(UINT_PTR)Buffer.AllocationBase; } return SymGetModuleBase64(hProcess, dwAddress); }
static int find_pe_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol * sym) { HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent); ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; SYMBOL_INFO * info = (SYMBOL_INFO *)buffer; IMAGEHLP_STACK_FRAME stack_frame; DWORD err; if (set_pe_context(ctx, frame, ip, process, &stack_frame) < 0) return -1; memset(info, 0, sizeof(SYMBOL_INFO)); info->SizeOfStruct = sizeof(SYMBOL_INFO); info->MaxNameLen = MAX_SYM_NAME; if (find_cache_symbol(ctx, frame, stack_frame.InstructionOffset, name, sym)) return errno ? -1 : 0; /* TODO: SymFromName() searches only main executable, need to search DLLs too */ if (SymFromName(process, name, info) && info->Tag != SymTagPublicSymbol) { syminfo2symbol(ctx, frame, info, sym); add_cache_symbol(ctx, stack_frame.InstructionOffset, name, sym, 0); return 0; } if (stack_frame.InstructionOffset != 0) { DWORD64 module = SymGetModuleBase64(process, stack_frame.InstructionOffset); if (module != 0 && SymGetTypeFromName(process, module, name, info)) { syminfo2symbol(ctx, frame, info, sym); add_cache_symbol(ctx, stack_frame.InstructionOffset, name, sym, 0); return 0; } } set_win32_errno(err = GetLastError()); if (err == 0 || err == ERROR_MOD_NOT_FOUND) { add_cache_symbol(ctx, stack_frame.InstructionOffset, name, NULL, ERR_SYM_NOT_FOUND); errno = ERR_SYM_NOT_FOUND; } return -1; }
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 }
// This callback function is used by StackWalk64. It provides access to // module list stored in minidump file DWORD64 CALLBACK GetModuleBaseProc64( HANDLE hProcess, DWORD64 Address) { return SymGetModuleBase64(hProcess, Address); }
void jl_getDylibFunctionInfo(const char **name, int *line, const char **filename, size_t pointer, int skipC) { #ifdef _OS_WINDOWS_ DWORD fbase = SymGetModuleBase64(GetCurrentProcess(),(DWORD)pointer); if (fbase != 0) { #else Dl_info dlinfo; if ((dladdr((void*)pointer, &dlinfo) != 0) && dlinfo.dli_fname) { if (skipC && !jl_is_sysimg(dlinfo.dli_fname)) return; 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; 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 LLVM35 ErrorOr<llvm::object::ObjectFile*> origerrorobj = llvm::object::ObjectFile::createObjectFile( #else llvm::object::ObjectFile *origerrorobj = llvm::object::ObjectFile::createObjectFile( #endif MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false) #ifdef LLVM35 ,false, sys::fs::file_magic::unknown #endif ); if (!origerrorobj) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; return; } #ifdef 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; return; } // 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 ErrorOr<llvm::object::ObjectFile*> errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #endif #else #ifndef _OS_WINDOWS_ const char *fname = dlinfo.dli_fname; #else IMAGEHLP_MODULE64 ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); char *fname = ModuleInfo.LoadedImageName; JL_PRINTF(JL_STDOUT,fname); #endif // On non OS X systems we need to mmap another copy because of the permissions on the mmaped // shared library. #ifdef LLVM35 ErrorOr<llvm::object::ObjectFile*> errorobj = llvm::object::ObjectFile::createObjectFile(fname); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(fname); #endif #endif #ifdef 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 context = DIContext::getDWARFContext(obj); 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; } lookup_pointer(context, name, line, filename, pointer+slide, jl_is_sysimg(dlinfo.dli_fname)); } return; }