Skip to content

Commit

Permalink
Fix function base address lookup on Win32 and FreeBSD
Browse files Browse the repository at this point in the history
* Add a (slow but cross-platform) fallback lookup method of function name and base address
  using LLVM debug info reader
* Remove windows exported symbol lookup that never worked for sysimg function address lookup
  (since they are never exported)

Fix #17251
Fix #20798
  • Loading branch information
yuyichao committed Jun 23, 2017
1 parent 02804ac commit 116377f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 47 deletions.
90 changes: 50 additions & 40 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,35 +746,12 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
if (onlySysImg && !insysimage) {
return false;
}
static char frame_info_func[
sizeof(SYMBOL_INFO) +
MAX_SYM_NAME * sizeof(TCHAR)];
DWORD64 dwDisplacement64 = 0;
DWORD64 dwAddress = pointer;
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
jl_in_stackwalk = 1;
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64,
pSymbol)) {
// SymFromAddr returned success
// errors are ignored, but are hopefully patched up by
// using llvm to read the object (below)
if (name)
jl_copy_str(name, pSymbol->Name);
if (saddr)
*saddr = (void*)(uintptr_t)pSymbol->Address;
}
else if (saddr) {
*saddr = NULL;
}

// If we didn't find the filename before in the debug
// info, use the dll name
if (filename && !*filename)
jl_copy_str(filename, fname.data());

jl_in_stackwalk = 0;
if (saddr)
*saddr = NULL;

#else // ifdef _OS_WINDOWS_
Dl_info dlinfo;
Expand Down Expand Up @@ -998,33 +975,66 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip
frame0->fromC = 1;
return 1;
}
bool need_saddr = isSysImg && sysimg_fvars;
frame0->fromC = !isSysImg;
if (isSysImg && sysimg_fvars) {
// Try platform specific methods first since they are usually faster
if (need_saddr && !saddr) {
#if defined(_OS_LINUX_) && !defined(JL_DISABLE_LIBUNWIND)
unw_proc_info_t pip;
if (!saddr && unw_get_proc_info_by_ip(unw_local_addr_space,
pointer, &pip, NULL) == 0)
if (unw_get_proc_info_by_ip(unw_local_addr_space, pointer, &pip, NULL) == 0) {
saddr = (void*)pip.start_ip;
}
#endif
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
if (!saddr) {
DWORD64 ImageBase;
PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(pointer, &ImageBase, NULL);
if (fn)
saddr = (void*)(ImageBase + fn->BeginAddress);
DWORD64 ImageBase;
PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(pointer, &ImageBase, NULL);
if (fn) {
saddr = (void*)(ImageBase + fn->BeginAddress);
}
#endif
if (saddr) {
for (size_t i = 0; i < sysimg_fvars_n; i++) {
if (saddr == sysimg_fvars[i]) {
frame0->linfo = sysimg_fvars_linfo[i];
break;
}
if (((need_saddr && !saddr) || !frame0->func_name) && object) {
size_t distance = (size_t)-1;
SymRef sym_found;
for (auto sym: object->symbols()) {
auto addr = sym.getAddress();
if (!addr)
continue;
size_t symptr = addr.get();
if (symptr > pointer + slide)
continue;
size_t new_dist = pointer + slide - symptr;
if (new_dist > distance)
continue;
distance = new_dist;
sym_found = sym;
}
if (distance != (size_t)-1) {
if (!saddr) {
auto addr = sym_found.getAddress();
assert(addr);
saddr = (void*)(uintptr_t)addr.get();
}
if (!frame0->func_name) {
if (auto name_or_err = sym_found.getName()) {
auto name = name_or_err.get();
size_t len = name.size();
frame0->func_name = (char*)malloc(len + 1);
frame0->func_name[len] = 0;
memcpy(frame0->func_name, name.data(), len);
}
}
}
return lookup_pointer(context, frames, pointer+slide, isSysImg, noInline);
}
return lookup_pointer(context, frames, pointer+slide, isSysImg, noInline);
if (need_saddr && saddr) {
for (size_t i = 0; i < sysimg_fvars_n; i++) {
if (saddr == sysimg_fvars[i]) {
frame0->linfo = sysimg_fvars_linfo[i];
break;
}
}
}
return lookup_pointer(context, frames, pointer + slide, isSysImg, noInline);
}

int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, int64_t *section_slide,
Expand Down
8 changes: 1 addition & 7 deletions test/cmdlineargs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -423,13 +423,7 @@ end
for precomp in ("yes", "no")
bt = readstring(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --precompiled=$precomp
-E 'include("____nonexistent_file")'`), stderr=catcmd))
@test contains(bt, "include_from_node1")
if ((is_windows() && Sys.WORD_SIZE == 32) || (is_bsd() && !is_apple())) && precomp == "yes"
# FIXME: Issue #17251 (Windows), #20798 (FreeBSD)
@test_broken contains(bt, "include_from_node1(::Module, ::String) at $(joinpath(".", "loading.jl"))")
else
@test contains(bt, "include_from_node1(::Module, ::String) at $(joinpath(".", "loading.jl"))")
end
@test contains(bt, "include_from_node1(::Module, ::String) at $(joinpath(".", "loading.jl"))")
lno = match(r"at \.[\/\\]loading\.jl:(\d+)", bt)
@test length(lno.captures) == 1
@test parse(Int, lno.captures[1]) > 0
Expand Down

0 comments on commit 116377f

Please sign in to comment.