diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 531beb571d..7991c4834e 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -1249,13 +1249,13 @@ static void find_address_in_section(bfd *abfd, asection *section, void *data) if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) return; + bfd_vma addr = info->addr + info->image_base; bfd_vma vma = bfd_get_section_vma(abfd, section); - if (info->addr < vma) return; - bfd_size_type size = get_bfd_section_size(abfd, section); - if (info->addr >= vma + size) return; - info->found = bfd_find_nearest_line(abfd, section, info->syms, info->addr - vma, + if (addr < vma || addr >= vma + size) return; + + info->found = bfd_find_nearest_line(abfd, section, info->syms, addr - vma, &(info->file_name), &(info->function_name), &(info->line)); if (info->found && info->function_name) { @@ -1266,7 +1266,7 @@ static void find_address_in_section(bfd *abfd, asection *section, void *data) } } } else if (info->found) { - bfd_vma target = info->addr - vma; + bfd_vma target = addr - vma; bfd_vma best_diff = size; for (long i = 0; i < info->sym_count; i++) { asymbol *sym = info->syms[i]; @@ -1302,11 +1302,34 @@ void lookup_addr_bfd(const char *obj_file_name, sym_bfd_obj_cache &bfdc, sym_inf if (obj.sym_count <= 0) return; obj.usable = true; + +#if defined(__MINGW32__) + /* Handle Windows PE relocation. + * libbfd sections (and thus symbol addresses) are relative to the image base address (i.e. absolute). + * Due to relocation/ASLR/etc the module base address in memory may not match the image base address. + * Instead of using the absolute addresses, expect the inputs here to be relative to the module base address + * in memory, which is easy to get. + * The original image base address is very awkward to get, but as it's always the same, just hard-code it + * via the expected .text section address here. */ +#ifdef _M_AMD64 + asection *section = bfd_get_section_by_name(obj.abfd, ".text"); + if (section != nullptr && section->vma == 0x140001000) { + obj.image_base = 0x140000000; + } +#elif defined(_M_IX86) + asection *section = bfd_get_section_by_name(obj.abfd, ".text"); + if (section != nullptr && section->vma == 0x401000) { + obj.image_base = 0x400000; + } +#endif + if (obj.image_base == 0) obj.usable = false; +#endif } if (!obj.usable) return; info.abfd = obj.abfd; + info.image_base = obj.image_base; info.syms = obj.syms; info.sym_count = obj.sym_count; diff --git a/src/crashlog_bfd.h b/src/crashlog_bfd.h index 9ab79872c2..35db413d58 100644 --- a/src/crashlog_bfd.h +++ b/src/crashlog_bfd.h @@ -35,6 +35,7 @@ struct sym_bfd_obj { bfd *abfd = nullptr; + bfd_vma image_base = 0; asymbol **syms = nullptr; const char *file_name = nullptr; long sym_count = 0; @@ -50,6 +51,7 @@ struct sym_bfd_obj_cache { struct sym_info_bfd { bfd_vma addr; bfd *abfd; + bfd_vma image_base = 0; asymbol **syms; long sym_count; const char *file_name; diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 06cbf83c9d..9d5221794f 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -427,12 +427,14 @@ static const uint MAX_FRAMES = 64; /* Get module name. */ const char *mod_name = "???"; const char *image_name = nullptr; + DWORD64 image_base = 0; IMAGEHLP_MODULE64 module; module.SizeOfStruct = sizeof(module); if (proc.pSymGetModuleInfo64(hCur, frame.AddrPC.Offset, &module)) { mod_name = module.ModuleName; image_name = module.ImageName; + image_base = module.BaseOfImage; } /* Print module and instruction pointer. */ @@ -452,7 +454,7 @@ static const uint MAX_FRAMES = 64; } else if (image_name != nullptr) { #if defined (WITH_BFD) /* subtract one to get the line before the return address, i.e. the function call line */ - sym_info_bfd bfd_info(static_cast(frame.AddrPC.Offset) - 1); + sym_info_bfd bfd_info(static_cast(frame.AddrPC.Offset) - static_cast(image_base) - 1); lookup_addr_bfd(image_name, bfd_cache, bfd_info); if (bfd_info.function_name != nullptr) { const char *func_name = bfd_info.function_name;