Commit 60108ea1 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

dbghelp: Pretend mach-o is present in case of failure.

On MacOs, starting with Big Sur 11.0.1, the system dynamic libraries are no longer directly accessible on disk. They are still available 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 this 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). Apart 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 cuts startup time of 'winedbg notepad' from 9.9 to 7.4s. YMMV. Signed-off-by: 's avatarEric Pouech <epouech@codeweavers.com>
parent 01c98c5e
...@@ -441,7 +441,8 @@ struct module ...@@ -441,7 +441,8 @@ struct module
struct module* next; struct module* next;
enum dhext_module_type type : 16; enum dhext_module_type type : 16;
unsigned short is_virtual : 1, unsigned short is_virtual : 1,
is_wine_builtin : 1; is_wine_builtin : 1,
has_file_image : 1;
struct cpu* cpu; struct cpu* cpu;
DWORD64 reloc_delta; DWORD64 reloc_delta;
WCHAR* real_path; WCHAR* real_path;
......
...@@ -1405,6 +1405,9 @@ static BOOL macho_load_debug_info(struct process *pcs, struct module* module) ...@@ -1405,6 +1405,9 @@ static BOOL macho_load_debug_info(struct process *pcs, struct module* module)
return FALSE; 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; ifm = &module->format_info[DFI_MACHO]->u.macho_info->file_map;
fmap = &ifm->u.macho; fmap = &ifm->u.macho;
...@@ -1489,17 +1492,22 @@ static void macho_module_remove(struct process* pcs, struct module_format* modfm ...@@ -1489,17 +1492,22 @@ static void macho_module_remove(struct process* pcs, struct module_format* modfm
* TRUE on success * TRUE on success
*/ */
static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, 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 ret = TRUE;
BOOL split_segs; BOOL split_segs;
struct image_file_map fmap; struct image_file_map fmap;
TRACE("(%p/%p, %s, 0x%08Ix, %p/0x%08x)\n", pcs, pcs->handle, debugstr_w(filename), TRACE("(%p/%p, %s, 0x%08Ix, %p/0x%08x, %u)\n", pcs, pcs->handle, debugstr_w(filename),
load_addr, macho_info, macho_info->flags); load_addr, macho_info, macho_info->flags, with_image);
split_segs = image_uses_split_segs(pcs, load_addr); split_segs = image_uses_split_segs(pcs, load_addr);
if (with_image)
{
if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE; if (!macho_map_file(pcs, filename, split_segs, &fmap)) return FALSE;
}
else
reset_file_map(&fmap);
if (macho_info->flags & MACHO_INFO_MODULE) if (macho_info->flags & MACHO_INFO_MODULE)
{ {
...@@ -1507,18 +1515,21 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, ...@@ -1507,18 +1515,21 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
struct module_format* modfmt = struct module_format* modfmt =
HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info)); HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct macho_module_info));
if (!modfmt) goto leave; if (!modfmt) goto leave;
if (!load_addr) if (!load_addr && with_image)
load_addr = fmap.u.macho.segs_start; load_addr = fmap.u.macho.segs_start;
macho_info->module = module_new(pcs, filename, DMT_MACHO, module_is_wine_host(filename, L".so"), macho_info->module = module_new(pcs, filename, DMT_MACHO, module_is_wine_host(filename, L".so"),
FALSE, load_addr, 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)); image_get_machine(pcs, load_addr));
if (!macho_info->module) if (!macho_info->module)
{ {
HeapFree(GetProcessHeap(), 0, modfmt); HeapFree(GetProcessHeap(), 0, modfmt);
goto leave; 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_module_info = (void*)(modfmt + 1);
macho_info->module->format_info[DFI_MACHO] = modfmt; macho_info->module->format_info[DFI_MACHO] = modfmt;
...@@ -1531,6 +1542,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, ...@@ -1531,6 +1542,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename,
macho_module_info->file_map = fmap; macho_module_info->file_map = fmap;
reset_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->in_use = 1;
macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0; macho_info->module->format_info[DFI_MACHO]->u.macho_info->is_loader = 0;
...@@ -1566,7 +1578,7 @@ struct macho_load_params ...@@ -1566,7 +1578,7 @@ struct macho_load_params
static BOOL macho_load_file_cb(void *param, HANDLE handle, const WCHAR *filename) static BOOL macho_load_file_cb(void *param, HANDLE handle, const WCHAR *filename)
{ {
struct macho_load_params *macho_load = param; 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 ...@@ -1606,7 +1618,7 @@ static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filenam
/* Try the path as given. */ /* Try the path as given. */
if (!ret) 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). */ /* Try DYLD_FALLBACK_LIBRARY_PATH, with just the filename (no directories). */
if (!ret) if (!ret)
{ {
...@@ -1618,6 +1630,19 @@ static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filenam ...@@ -1618,6 +1630,19 @@ static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filenam
if (!ret && p == filename) if (!ret && p == filename)
ret = search_dll_path(pcs, filename, IMAGE_FILE_MACHINE_UNKNOWN, macho_load_file_cb, &load_params); 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; return ret;
} }
...@@ -1908,7 +1933,7 @@ static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_in ...@@ -1908,7 +1933,7 @@ static BOOL macho_search_loader(struct process* pcs, struct macho_info* macho_in
if (pathW) if (pathW)
{ {
MultiByteToWideChar(CP_UNIXCP, 0, path, -1, pathW, len); 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); HeapFree(GetProcessHeap(), 0, pathW);
} }
} }
......
...@@ -237,6 +237,8 @@ struct module* module_new(struct process* pcs, const WCHAR* name, ...@@ -237,6 +237,8 @@ struct module* module_new(struct process* pcs, const WCHAR* name,
module->type = type; module->type = type;
module->is_virtual = !!virtual; module->is_virtual = !!virtual;
module->is_wine_builtin = !!builtin; module->is_wine_builtin = !!builtin;
module->has_file_image = TRUE;
for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL; for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL;
module->sortlist_valid = FALSE; module->sortlist_valid = FALSE;
module->sorttab_size = 0; module->sorttab_size = 0;
...@@ -1687,6 +1689,7 @@ BOOL WINAPI wine_get_module_information(HANDLE proc, DWORD64 base, struct dhext_ ...@@ -1687,6 +1689,7 @@ BOOL WINAPI wine_get_module_information(HANDLE proc, DWORD64 base, struct dhext_
dhmi.type = module->type; dhmi.type = module->type;
dhmi.is_virtual = module->is_virtual; dhmi.is_virtual = module->is_virtual;
dhmi.is_wine_builtin = module->is_wine_builtin; dhmi.is_wine_builtin = module->is_wine_builtin;
dhmi.has_file_image = module->has_file_image;
dhmi.debug_format_bitmask = module->debug_format_bitmask; dhmi.debug_format_bitmask = module->debug_format_bitmask;
if ((module = module_get_container(pcs, module))) if ((module = module_get_container(pcs, module)))
{ {
......
...@@ -1267,7 +1267,8 @@ struct dhext_module_information ...@@ -1267,7 +1267,8 @@ struct dhext_module_information
{ {
enum dhext_module_type type; enum dhext_module_type type;
unsigned is_wine_builtin : 1, unsigned is_wine_builtin : 1,
is_virtual : 1; is_virtual : 1,
has_file_image : 1;
unsigned debug_format_bitmask; unsigned debug_format_bitmask;
}; };
......
...@@ -191,9 +191,10 @@ static const char* get_machine_str(DWORD machine) ...@@ -191,9 +191,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) static void module_print_info(const struct info_module *module, BOOL is_embedded, BOOL multi_machine)
{ {
char buffer[9]; char buffer[9];
snprintf(buffer, sizeof(buffer), "%s%s", snprintf(buffer, sizeof(buffer), "%s%s%s",
is_embedded ? " \\-" : "", is_embedded ? " \\-" : "",
get_module_type(module, is_embedded)); get_module_type(module, is_embedded),
module->ext_module_info.has_file_image ? "" : "^");
if (multi_machine) if (multi_machine)
dbg_printf("%-8s%16I64x-%16I64x %-16s%-16s%s\n", dbg_printf("%-8s%16I64x-%16I64x %-16s%-16s%s\n",
...@@ -266,6 +267,7 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) ...@@ -266,6 +267,7 @@ void info_win32_module(DWORD64 base, BOOL multi_machine)
UINT i, j, num_printed = 0; UINT i, j, num_printed = 0;
BOOL opt; BOOL opt;
DWORD machine; DWORD machine;
BOOL has_missing_filename = FALSE;
if (!dbg_curr_process) if (!dbg_curr_process)
{ {
...@@ -308,6 +310,7 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) ...@@ -308,6 +310,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)) (base < im.modules[i].mi.BaseOfImage || base >= im.modules[i].mi.BaseOfImage + im.modules[i].mi.ImageSize))
continue; continue;
if (!multi_machine && machine != im.modules[i].mi.MachineType) 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) 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); module_print_info(&im.modules[i], FALSE, multi_machine);
...@@ -335,6 +338,8 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) ...@@ -335,6 +338,8 @@ void info_win32_module(DWORD64 base, BOOL multi_machine)
if (base && !num_printed) if (base && !num_printed)
dbg_printf("'0x%0*I64x' is not a valid module address\n", ADDRWIDTH, base); 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 struct class_walker
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment