Skip to content

Commit 8c658c5

Browse files
committed
Fix function base address lookup on Win32 and FreeBSD
* Add a (slow but cross-platform) fallback lookup method of function name and base address using LLVM debug info reader * Disable windows exported symbol lookup that never worked for sysimg function address lookup (since they are never exported). Also move it after LLVM debug info reader since it is less accurate unless LLVM couldn't get any debug info. Fix #17251 Fix #20798
1 parent 02804ac commit 8c658c5

File tree

2 files changed

+90
-55
lines changed

2 files changed

+90
-55
lines changed

src/debuginfo.cpp

Lines changed: 89 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,85 @@ static inline void ignoreError(T &err)
716716
#endif
717717
}
718718

719+
static void get_function_name_and_base(const object::ObjectFile *object, bool insysimage,
720+
void **saddr, char **name, size_t pointer,
721+
int64_t slide)
722+
{
723+
if (!object)
724+
return;
725+
// Assume we only need base address for sysimg for now
726+
if (!insysimage || !sysimg_fvars)
727+
saddr = nullptr;
728+
// Try platform specific methods first since they are usually faster
729+
if (saddr && !*saddr) {
730+
#if defined(_OS_LINUX_) && !defined(JL_DISABLE_LIBUNWIND)
731+
unw_proc_info_t pip;
732+
if (unw_get_proc_info_by_ip(unw_local_addr_space, pointer, &pip, NULL) == 0) {
733+
*saddr = (void*)pip.start_ip;
734+
}
735+
#endif
736+
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
737+
DWORD64 ImageBase;
738+
PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(pointer, &ImageBase, NULL);
739+
if (fn) {
740+
*saddr = (void*)(ImageBase + fn->BeginAddress);
741+
}
742+
#endif
743+
}
744+
if ((saddr && !*saddr) || (name && !*name)) {
745+
size_t distance = (size_t)-1;
746+
SymRef sym_found;
747+
for (auto sym: object->symbols()) {
748+
auto addr = sym.getAddress();
749+
if (!addr)
750+
continue;
751+
size_t symptr = addr.get();
752+
if (symptr > pointer + slide)
753+
continue;
754+
size_t new_dist = pointer + slide - symptr;
755+
if (new_dist > distance)
756+
continue;
757+
distance = new_dist;
758+
sym_found = sym;
759+
}
760+
if (distance != (size_t)-1) {
761+
if (saddr && !*saddr) {
762+
auto addr = sym_found.getAddress();
763+
assert(addr);
764+
*saddr = (void*)(uintptr_t)(addr.get() - slide);
765+
}
766+
if (name && !*name) {
767+
if (auto name_or_err = sym_found.getName()) {
768+
auto nameref = name_or_err.get();
769+
size_t len = nameref.size();
770+
*name = (char*)malloc(len + 1);
771+
(*name)[len] = 0;
772+
memcpy(*name, nameref.data(), len);
773+
}
774+
}
775+
}
776+
}
777+
#ifdef _OS_WINDOWS_
778+
// For ntdll and msvcrt since we are currently only parsing DWARF debug info through LLVM
779+
if (!insysimage && name && !*name) {
780+
static char frame_info_func[
781+
sizeof(SYMBOL_INFO) +
782+
MAX_SYM_NAME * sizeof(TCHAR)];
783+
DWORD64 dwDisplacement64 = 0;
784+
DWORD64 dwAddress = pointer;
785+
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func;
786+
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
787+
pSymbol->MaxNameLen = MAX_SYM_NAME;
788+
jl_in_stackwalk = 1;
789+
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64, pSymbol)) {
790+
// errors are ignored
791+
jl_copy_str(name, pSymbol->Name);
792+
}
793+
jl_in_stackwalk = 0;
794+
}
795+
#endif
796+
}
797+
719798
extern "C" void jl_refresh_dbg_module_list(void);
720799
bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj, llvm::DIContext **context, int64_t *slide, int64_t *section_slide,
721800
bool onlySysImg, bool *isSysImg, void **saddr, char **name, char **filename)
@@ -746,35 +825,12 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
746825
if (onlySysImg && !insysimage) {
747826
return false;
748827
}
749-
static char frame_info_func[
750-
sizeof(SYMBOL_INFO) +
751-
MAX_SYM_NAME * sizeof(TCHAR)];
752-
DWORD64 dwDisplacement64 = 0;
753-
DWORD64 dwAddress = pointer;
754-
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func;
755-
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
756-
pSymbol->MaxNameLen = MAX_SYM_NAME;
757-
jl_in_stackwalk = 1;
758-
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64,
759-
pSymbol)) {
760-
// SymFromAddr returned success
761-
// errors are ignored, but are hopefully patched up by
762-
// using llvm to read the object (below)
763-
if (name)
764-
jl_copy_str(name, pSymbol->Name);
765-
if (saddr)
766-
*saddr = (void*)(uintptr_t)pSymbol->Address;
767-
}
768-
else if (saddr) {
769-
*saddr = NULL;
770-
}
771-
772828
// If we didn't find the filename before in the debug
773829
// info, use the dll name
774830
if (filename && !*filename)
775831
jl_copy_str(filename, fname.data());
776-
777-
jl_in_stackwalk = 0;
832+
if (saddr)
833+
*saddr = NULL;
778834

779835
#else // ifdef _OS_WINDOWS_
780836
Dl_info dlinfo;
@@ -832,6 +888,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
832888
*context = it->second.ctx;
833889
*slide = it->second.slide;
834890
*section_slide = it->second.section_slide;
891+
get_function_name_and_base(*obj, insysimage, saddr, name, pointer, *slide);
835892
return true;
836893
}
837894

@@ -961,6 +1018,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
9611018
// update cache
9621019
objfileentry_t entry = {*obj, *context, *slide, *section_slide};
9631020
objfilemap[fbase] = entry;
1021+
get_function_name_and_base(*obj, insysimage, saddr, name, pointer, *slide);
9641022
return true;
9651023
}
9661024

@@ -999,32 +1057,15 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip
9991057
return 1;
10001058
}
10011059
frame0->fromC = !isSysImg;
1002-
if (isSysImg && sysimg_fvars) {
1003-
#if defined(_OS_LINUX_) && !defined(JL_DISABLE_LIBUNWIND)
1004-
unw_proc_info_t pip;
1005-
if (!saddr && unw_get_proc_info_by_ip(unw_local_addr_space,
1006-
pointer, &pip, NULL) == 0)
1007-
saddr = (void*)pip.start_ip;
1008-
#endif
1009-
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
1010-
if (!saddr) {
1011-
DWORD64 ImageBase;
1012-
PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(pointer, &ImageBase, NULL);
1013-
if (fn)
1014-
saddr = (void*)(ImageBase + fn->BeginAddress);
1015-
}
1016-
#endif
1017-
if (saddr) {
1018-
for (size_t i = 0; i < sysimg_fvars_n; i++) {
1019-
if (saddr == sysimg_fvars[i]) {
1020-
frame0->linfo = sysimg_fvars_linfo[i];
1021-
break;
1022-
}
1060+
if (isSysImg && sysimg_fvars && saddr) {
1061+
for (size_t i = 0; i < sysimg_fvars_n; i++) {
1062+
if (saddr == sysimg_fvars[i]) {
1063+
frame0->linfo = sysimg_fvars_linfo[i];
1064+
break;
10231065
}
10241066
}
1025-
return lookup_pointer(context, frames, pointer+slide, isSysImg, noInline);
10261067
}
1027-
return lookup_pointer(context, frames, pointer+slide, isSysImg, noInline);
1068+
return lookup_pointer(context, frames, pointer + slide, isSysImg, noInline);
10281069
}
10291070

10301071
int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, int64_t *section_slide,

test/cmdlineargs.jl

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,7 @@ end
423423
for precomp in ("yes", "no")
424424
bt = readstring(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --precompiled=$precomp
425425
-E 'include("____nonexistent_file")'`), stderr=catcmd))
426-
@test contains(bt, "include_from_node1")
427-
if ((is_windows() && Sys.WORD_SIZE == 32) || (is_bsd() && !is_apple())) && precomp == "yes"
428-
# FIXME: Issue #17251 (Windows), #20798 (FreeBSD)
429-
@test_broken contains(bt, "include_from_node1(::Module, ::String) at $(joinpath(".", "loading.jl"))")
430-
else
431-
@test contains(bt, "include_from_node1(::Module, ::String) at $(joinpath(".", "loading.jl"))")
432-
end
426+
@test contains(bt, "include_from_node1(::Module, ::String) at $(joinpath(".", "loading.jl"))")
433427
lno = match(r"at \.[\/\\]loading\.jl:(\d+)", bt)
434428
@test length(lno.captures) == 1
435429
@test parse(Int, lno.captures[1]) > 0

0 commit comments

Comments
 (0)