From: Eric Pouech eric.pouech@gmail.com
On MacOs, starting with Big Sur 11.0.1, the system dynamic libraries are no longer directly accessible on disk. They are still avaible through dlopen and friends. For getting access to the images (and their debug symbol), Apple provides in the developper kit the tools to extract the files. Note that is handled as a database of all system libraries, where ASLR is in place such that segments of a given library are no longer contiguous in memory (dbghelp doesn't currently handle this).
A part from not having image information nor debug information, another side effect is that dbghelp tries every time it refreshes the mach-o module list to reload any library for which it didn't have an image file. This can be lengthy (esp when a typical process has more than 300 modules loaded).
This patch forces the creation of the dbghelp module even if the image file isn't found.
this patch cut startup time of 'winedbg notepad' from 9.9 to 7.4s. YMMV.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 3 ++- dlls/dbghelp/macho_module.c | 45 ++++++++++++++++++++++++++-------- dlls/dbghelp/module.c | 3 +++ include/wine/dbghelp_ext.h | 3 ++- programs/winedbg/info.c | 9 +++++-- 5 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index fcf37d56a30..0ac1307df96 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -442,7 +442,8 @@ struct module struct module* next; enum module_type type : 16; unsigned short is_virtual : 1, - is_wine_builtin : 1; + is_wine_builtin : 1, + has_file_image : 1; struct cpu* cpu; DWORD64 reloc_delta; WCHAR* real_path; diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index 2d831449d39..90c38b557bb 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -1405,6 +1405,9 @@ static BOOL macho_load_debug_info(struct process *pcs, struct module* module) return FALSE; }
+ if (!module->has_file_image) /* no much more we can do here */ + return FALSE; + ifm = &module->format_info[DFI_MACHO]->u.macho_info->file_map; fmap = &ifm->u.macho;
@@ -1489,17 +1492,22 @@ static void macho_module_remove(struct process* pcs, struct module_format* modfm * TRUE on success */ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, - ULONG_PTR load_addr, struct macho_info* macho_info) + ULONG_PTR load_addr, struct macho_info* macho_info, BOOL with_image) { BOOL ret = TRUE; BOOL split_segs; struct image_file_map fmap;
- TRACE("(%p/%p, %s, 0x%08Ix, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename), - load_addr, macho_info, macho_info->flags); + TRACE("(%p/%p, %s, 0x%08Ix, %p/0x%08x, %u)\n", pcs, pcs->handle, debugstr_w(filename), + load_addr, macho_info, macho_info->flags, with_image);
split_segs = image_uses_split_segs(pcs, load_addr); - if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE; + if (with_image) + { + if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE; + } + else + reset_file_map(&fmap);
if (macho_info->flags & MACHO_INFO_MODULE) { @@ -1507,18 +1515,21 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, struct module_format* modfmt = HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info)); if (!modfmt) goto leave; - if (!load_addr) + if (!load_addr && with_image) load_addr = fmap.u.macho.segs_start; macho_info->module = module_new(pcs, filename, DMT_MACHO, module_is_wine_host(filename, L".so"), FALSE, load_addr, - fmap.u.macho.segs_size, 0, calc_crc32(fmap.u.macho.handle), + with_image ? fmap.u.macho.segs_size : 1024, + 0, with_image ? calc_crc32(fmap.u.macho.handle) : 0, image_get_machine(pcs, load_addr)); if (!macho_info->module) { HeapFree(GetProcessHeap(), 0, modfmt); goto leave; } - macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage - fmap.u.macho.segs_start; + macho_info->module->reloc_delta = macho_info->module->module.BaseOfImage; + if (with_image) macho_info->module->reloc_delta -= fmap.u.macho.segs_start; + macho_module_info = (void*)(modfmt + 1); macho_info->module->format_info[DFI_MACHO] = modfmt;
@@ -1531,6 +1542,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
macho_module_info->file_map = fmap; reset_file_map(&fmap); + if (!with_image) macho_info->module->has_file_image = 0;
macho_info->module->format_info[DFI_MACHO]->u.macho_info->in_use = 1; macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0; @@ -1566,7 +1578,7 @@ struct macho_load_params static BOOL macho_load_file_cb(void *param, HANDLE handle, const WCHAR *filename) { struct macho_load_params *macho_load = param; - return macho_load_file(macho_load->process, filename, macho_load->load_addr, macho_load->macho_info); + return macho_load_file(macho_load->process, filename, macho_load->load_addr, macho_load->macho_info, TRUE); }
/****************************************************************** @@ -1606,7 +1618,7 @@ static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filenam
/* Try the path as given. */ if (!ret) - ret = macho_load_file(pcs, filename, load_addr, macho_info); + ret = macho_load_file(pcs, filename, load_addr, macho_info, TRUE); /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */ if (!ret) { @@ -1618,6 +1630,19 @@ static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filenam if (!ret && p == filename) ret = search_dll_path(pcs, filename, IMAGE_FILE_MACHINE_UNKNOWN, macho_load_file_cb, &load_params);
+ if (!ret && load_addr) + { + /* Starting at macos 11.0, the system libraries are no longer present on the file system. + * So, if we cannot find an image by its filename, just declare the module without + * any debug information. + * This avoids, when walking the internal module list, to search each time + * for the module filename. + * Note: doesn't seem to be a simple way to get the size of the loaded Mach-O module + * without the corresponding file image. And it has also ASLR in place, + * where segments of the same module are not contiguous. + */ + ret = macho_load_file(pcs, filename, load_addr, macho_info, FALSE); + } return ret; }
@@ -1908,7 +1933,7 @@ static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_in if (pathW) { MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len); - ret = macho_load_file(pcs, pathW, 0, macho_info); + ret = macho_load_file(pcs, pathW, 0, macho_info, TRUE); HeapFree(GetProcessHeap(), 0, pathW); } } diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index aa8da17309b..72fb6876e12 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -237,6 +237,8 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->type = type; module->is_virtual = !!virtual; module->is_wine_builtin = !!builtin; + module->has_file_image = TRUE; + for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL; module->sortlist_valid = FALSE; module->sorttab_size = 0; @@ -1687,6 +1689,7 @@ BOOL WINAPI wine_get_module_information(HANDLE proc, DWORD64 base, struct dhext_ dhmi.type = module->type; dhmi.is_virtual = module->is_virtual; dhmi.is_wine_builtin = module->is_wine_builtin; + dhmi.has_file_image = module->has_file_image; dhmi.debug_format_bitmask = module->debug_format_bitmask; if ((module = module_get_container(pcs, module))) { diff --git a/include/wine/dbghelp_ext.h b/include/wine/dbghelp_ext.h index c043019ac59..3cafc49028b 100644 --- a/include/wine/dbghelp_ext.h +++ b/include/wine/dbghelp_ext.h @@ -45,7 +45,8 @@ struct dhext_module_information { enum module_type type; unsigned is_wine_builtin : 1, - is_virtual : 1; + is_virtual : 1, + has_file_image : 1; unsigned debug_format_bitmask; };
diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 01a771604c9..01cfc3e85c6 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -192,9 +192,10 @@ static const char* get_machine_str(DWORD machine) static void module_print_info(const struct info_module *module, BOOL is_embedded, BOOL multi_machine) { char buffer[9]; - snprintf(buffer, sizeof(buffer), "%s%s", + snprintf(buffer, sizeof(buffer), "%s%s%s", is_embedded ? " \-" : "", - get_module_type(module, is_embedded)); + get_module_type(module, is_embedded), + module->ext_module_info.has_file_image ? "" : "^");
if (multi_machine) dbg_printf("%-8s%16I64x-%16I64x %-16s%-16s%s\n", @@ -267,6 +268,7 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) UINT i, j, num_printed = 0; BOOL opt; DWORD machine; + BOOL has_missing_filename = FALSE;
if (!dbg_curr_process) { @@ -309,6 +311,7 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) (base < im.modules[i].mi.BaseOfImage || base >= im.modules[i].mi.BaseOfImage + im.modules[i].mi.ImageSize)) continue; if (!multi_machine && machine != im.modules[i].mi.MachineType) continue; + if (!im.modules[i].ext_module_info.has_file_image) has_missing_filename = TRUE; if (im.modules[i].ext_module_info.type == DMT_ELF || im.modules[i].ext_module_info.type == DMT_MACHO) { module_print_info(&im.modules[i], FALSE, multi_machine); @@ -336,6 +339,8 @@ void info_win32_module(DWORD64 base, BOOL multi_machine)
if (base && !num_printed) dbg_printf("'0x%0*I64x' is not a valid module address\n", ADDRWIDTH, base); + if (has_missing_filename) + dbg_printf("^ denotes modules for which image file couldn't be found\n"); }
struct class_walker