From: Eric Pouech epouech@codeweavers.com
- respect SymLoadModuleEx(..., SLMFLAG_NO_SYMBOLS) for all formats. - reorder search logic: + matched .pdb + matched .dbg + dwarf + stabs + other debug formats in PE DEBUG directory (codeview...) + other debug formats from PE header (coff...) + unmatched .pdb (if none of previous worked). - only one of these format is loaded (while previously we could merge some of them), - use module's export table in last resort (either SLMFLAG_NO_SYMBOLS is present, or no debug info found) - for handling .pdb/.dbg, separate 1) getting .pdb/.dbg information from image, 2) searching a matching .pdb/.dbg file, 3) loading debug information from that very file.
Note: - we no longer fill CVData field in extended module info.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58837
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 2 + dlls/dbghelp/dwarf.c | 2 +- dlls/dbghelp/msc.c | 131 ++++++++--------------------- dlls/dbghelp/pe_module.c | 146 +++++++++++++++++++++++---------- 4 files changed, 140 insertions(+), 141 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 11094cca122..39a12af130f 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -827,6 +827,7 @@ extern BOOL module_is_wine_host(const WCHAR* module_name, const WCHAR* e extern BOOL module_refresh_list(struct process *pcs);
/* msc.c */ +extern BOOL pdb_load_debug_info(struct module *module, const SYMSRV_INDEX_INFOW *info, BOOL unmatched); extern BOOL pe_load_debug_directory(struct module* module, const BYTE* mapping, const IMAGE_SECTION_HEADER* sectp, DWORD nsect, @@ -857,6 +858,7 @@ extern BOOL pdb_fpo_unwind_parse_cmd_string(struct cpu_stack_walk* csw, const char* cmd, WOW64_CONTEXT *context);
/* pe_module.c */ +extern unsigned pe_clone_sections_table(struct module *module, IMAGE_SECTION_HEADER **sections); extern BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth, BOOL* is_builtin); extern struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 163167b596f..bd1759c99ea 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -4382,7 +4382,7 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, dwarf2_modfmt->module->module.SourceIndexed = TRUE; dwarf2_modfmt->module->module.Publics = TRUE; } - + else ret = FALSE; dwarf2_unload_CU_module(&module_ctx); leave:
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index b55ce1ea6e9..f2a697e1056 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -48,8 +48,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_msc);
-static const GUID null_guid; - struct pdb_stream_name { const char* name; @@ -3994,59 +3992,48 @@ static BOOL old_pdb_process_file(const struct msc_debug_info *msc_dbg, return ret; }
-static BOOL pdb_process_file(const struct msc_debug_info *msc_dbg, - const WCHAR *filename, const GUID *guid, DWORD timestamp, DWORD age) -{ - SYMSRV_INDEX_INFOW info; - BOOL unmatched, has_linenumber_info, ret; +#define MAKESIG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) +#define CODEVIEW_NB09_SIG MAKESIG('N','B','0','9') +#define CODEVIEW_NB10_SIG MAKESIG('N','B','1','0') +#define CODEVIEW_NB11_SIG MAKESIG('N','B','1','1') +#define CODEVIEW_RSDS_SIG MAKESIG('R','S','D','S')
- if (!msc_dbg->module->dont_load_symbols && - path_find_symbol_file(msc_dbg->module, filename, TRUE, guid, timestamp, age, &info, &unmatched)) - { - if (getenv("WINE_DBGHELP_OLD_PDB")) /* keep using old pdb reader */ - ret = old_pdb_process_file(msc_dbg, info.pdbfile, &has_linenumber_info); - else - ret = pdb_init_modfmt(msc_dbg, info.pdbfile, &has_linenumber_info); +BOOL pdb_load_debug_info(struct module *module, const SYMSRV_INDEX_INFOW *info, BOOL unmatched) +{ + BOOL has_linenumber_info, ret; + struct msc_debug_info msc_dbg = {.module = module};
- if (ret) - { - msc_dbg->module->module.SymType = SymPdb; - msc_dbg->module->module.PdbSig = info.sig; - msc_dbg->module->module.PdbAge = info.age; - msc_dbg->module->module.PdbSig70 = info.guid; - msc_dbg->module->module.PdbUnmatched = unmatched; - wcscpy(msc_dbg->module->module.LoadedPdbName, info.pdbfile); - - /* FIXME: we could have a finer grain here */ - msc_dbg->module->module.LineNumbers = has_linenumber_info; - msc_dbg->module->module.GlobalSymbols = TRUE; - msc_dbg->module->module.TypeInfo = TRUE; - msc_dbg->module->module.SourceIndexed = TRUE; - msc_dbg->module->module.Publics = TRUE; + msc_dbg.nsect = pe_clone_sections_table(module, (IMAGE_SECTION_HEADER**)&msc_dbg.sectp); + if (!msc_dbg.nsect) return FALSE; + if (getenv("WINE_DBGHELP_OLD_PDB")) /* keep using old pdb reader */ + ret = old_pdb_process_file(&msc_dbg, info->pdbfile, &has_linenumber_info); + else + ret = pdb_init_modfmt(&msc_dbg, info->pdbfile, &has_linenumber_info);
- return TRUE; - } + HeapFree(GetProcessHeap(), 0, (void*)msc_dbg.sectp); + if (ret) + { + module->module.SymType = SymPdb; + module->module.PdbSig70 = info->guid; + module->module.PdbSig = info->sig; + module->module.PdbAge = info->age; + module->module.PdbUnmatched = unmatched; + wcscpy(module->module.LoadedPdbName, info->pdbfile); + module->module.CVSig = info->sig ? CODEVIEW_NB10_SIG : CODEVIEW_RSDS_SIG; + /* FIXME: we could have a finer grain here */ + module->module.LineNumbers = has_linenumber_info; + module->module.GlobalSymbols = TRUE; + module->module.TypeInfo = TRUE; + module->module.SourceIndexed = TRUE; + module->module.Publics = TRUE; } - msc_dbg->module->module.SymType = SymNone; - if (guid) - msc_dbg->module->module.PdbSig70 = *guid; - else - memset(&msc_dbg->module->module.PdbSig70, 0, sizeof(GUID)); - msc_dbg->module->module.PdbSig = 0; - msc_dbg->module->module.PdbAge = age; - return FALSE; + return ret; }
/*======================================================================== * Process CodeView debug information. */
-#define MAKESIG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#define CODEVIEW_NB09_SIG MAKESIG('N','B','0','9') -#define CODEVIEW_NB10_SIG MAKESIG('N','B','1','0') -#define CODEVIEW_NB11_SIG MAKESIG('N','B','1','1') -#define CODEVIEW_RSDS_SIG MAKESIG('R','S','D','S') - static BOOL codeview_process_info(const struct msc_debug_info *msc_dbg) { const DWORD* signature = (const DWORD*)msc_dbg->root; @@ -4141,46 +4128,15 @@ static BOOL codeview_process_info(const struct msc_debug_info *msc_dbg) }
case CODEVIEW_NB10_SIG: - { - const CODEVIEW_PDB_DATA* pdb = (const CODEVIEW_PDB_DATA*)msc_dbg->root; - WCHAR buffer[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, pdb->name, -1, buffer, ARRAY_SIZE(buffer)); - ret = pdb_process_file(msc_dbg, buffer, NULL, pdb->timestamp, pdb->age); - break; - } case CODEVIEW_RSDS_SIG: - { - const OMFSignatureRSDS* rsds = (const OMFSignatureRSDS*)msc_dbg->root; - - TRACE("Got RSDS type of PDB file: guid=%s age=%08x name=%s\n", - wine_dbgstr_guid(&rsds->guid), rsds->age, debugstr_a(rsds->name)); - /* gcc/mingw and clang can emit build-id information, but with an empty PDB filename. - * Don't search for the .pdb file in that case. - */ - if (rsds->name[0]) - { - WCHAR buffer[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, rsds->name, -1, buffer, ARRAY_SIZE(buffer)); - ret = pdb_process_file(msc_dbg, buffer, &rsds->guid, 0, rsds->age); - } - else - ret = TRUE; + /* should be loaded directly through pe_load_debug_info() */ break; - } default: ERR("Unknown CODEVIEW signature %08lx in module %s\n", *signature, debugstr_w(msc_dbg->module->modulename)); break; } - if (ret) - { - msc_dbg->module->module.CVSig = *signature; - if (*signature == CODEVIEW_RSDS_SIG) - memcpy(msc_dbg->module->module.CVData, msc_dbg->root, - sizeof(msc_dbg->module->module.CVData)); - } + return ret; }
@@ -4274,25 +4230,6 @@ typedef struct _FPO_DATA } __ENDTRY
- /* we haven't found yet any debug information, fallback to unmatched pdb */ - if (!ret && module->module.SymType == SymDeferred) - { - SYMSRV_INDEX_INFOW info = {.sizeofstruct = sizeof(info)}; - WCHAR buffer[MAX_PATH]; - WCHAR *ext; - DWORD options; - - wcscpy(buffer, module->module.LoadedImageName); - ext = wcsrchr(buffer, '.'); - if (ext) wcscpy(ext + 1, L"pdb"); else wcscat(buffer, L".pdb"); - options = SymGetOptions(); - SymSetOptions(options | SYMOPT_LOAD_ANYTHING); - ret = pdb_process_file(&msc_dbg, buffer, &null_guid, 0, 0); - SymSetOptions(options); - if (!ret && module->dont_load_symbols) - module->module.TimeDateStamp = 0; - } - return ret; }
diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 5229ff6ba75..0ce0f0c4fde 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -219,6 +219,26 @@ static const struct image_file_map_ops pe_file_map_ops = pe_unmap_file, };
+unsigned pe_clone_sections_table(struct module *module, IMAGE_SECTION_HEADER **sections) +{ + void* mapping; + struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; + IMAGE_NT_HEADERS* nt_header; + unsigned num; + + if (!(mapping = pe_map_full(fmap, &nt_header))) return 0; + + if ((num = nt_header->FileHeader.NumberOfSections)) + { + if ((*sections = HeapAlloc(GetProcessHeap(), 0, num * sizeof(**sections)))) + memcpy(*sections, IMAGE_FIRST_SECTION( nt_header ), num * sizeof(**sections)); + else + num = 0; + } + pe_unmap_full(fmap); + return num; +} + /****************************************************************** * pe_is_valid_pointer_table * @@ -477,7 +497,7 @@ static BOOL pe_load_coff_symbol_table(struct module* module)
numsym = fmap->u.pe.file_header.NumberOfSymbols; if (!fmap->u.pe.file_header.PointerToSymbolTable || !numsym) - return TRUE; + return FALSE; if (!(mapping = pe_map_full(fmap, NULL))) return FALSE; isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.file_header.PointerToSymbolTable); /* FIXME: no way to get strtable size */ @@ -585,17 +605,15 @@ static BOOL pe_load_dwarf(struct module* module) * * loads a .dbg file */ -static BOOL pe_load_dbg_file(struct module* module, const WCHAR* dbg_name, DWORD timestamp) +static BOOL pe_load_dbg_file(struct module* module, const WCHAR* dbg_name) { HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0; const BYTE* dbg_mapping = NULL; BOOL ret = FALSE; - SYMSRV_INDEX_INFOW info;
TRACE("Processing DBG file %s\n", debugstr_w(dbg_name));
- if (path_find_symbol_file(module, dbg_name, FALSE, NULL, timestamp, 0, &info, &module->module.DbgUnmatched) && - (hFile = CreateFileW(info.dbgfile, GENERIC_READ, FILE_SHARE_READ, NULL, + if ((hFile = CreateFileW(dbg_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE && ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) && ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)) @@ -617,8 +635,6 @@ static BOOL pe_load_dbg_file(struct module* module, const WCHAR* dbg_name, DWORD hdr->NumberOfSections, dbg, hdr->DebugDirectorySize / sizeof(*dbg)); } - else - ERR("Couldn't find .DBG file %s (%s)\n", debugstr_w(dbg_name), debugstr_w(info.dbgfile));
if (dbg_mapping) UnmapViewOfFile(dbg_mapping); if (hMap) CloseHandle(hMap); @@ -646,28 +662,7 @@ static BOOL pe_load_msc_debug_info(struct module* module) nDbg = dbg ? nDbg / sizeof(IMAGE_DEBUG_DIRECTORY) : 0;
/* Parse debug directory */ - if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) - { - /* Debug info is stripped to .DBG file */ - const IMAGE_DEBUG_MISC *misc = NULL; - if (nDbg == 1 && dbg->Type == IMAGE_DEBUG_TYPE_MISC) - { - misc = (const IMAGE_DEBUG_MISC *)((const char *)mapping + dbg->PointerToRawData); - if (misc->DataType == IMAGE_DEBUG_MISC_EXENAME) - { - WCHAR buffer[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, (const char*)misc->Data, -1, buffer, ARRAY_SIZE(buffer)); - ret = pe_load_dbg_file(module, buffer, nth->FileHeader.TimeDateStamp); - } - else - misc = NULL; - } - if (!misc) - WARN("-Debug info stripped, but no .DBG file in module %s\n", - debugstr_w(module->modulename)); - } - else + if (!(nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)) { /* Debug info is embedded into PE module */ ret = pe_load_debug_directory(module, mapping, IMAGE_FIRST_SECTION( nth ), @@ -765,32 +760,97 @@ static BOOL pe_load_export_debug_info(struct module* module) */ BOOL pe_load_debug_info(struct module* module) { - BOOL ret = FALSE; + SYMSRV_INDEX_INFOW srv_info = {.sizeofstruct = sizeof(srv_info)}; + SYMSRV_INDEX_INFOW alt_srv_info; + BOOL ret = FALSE;
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) { - if (!module->dont_load_symbols) + /* do we have .pdb or .dbg link in module's image? */ + if (SymSrvGetFileIndexInfoW(module->module.LoadedImageName, &srv_info, 0)) + { + if (!module->dont_load_symbols) + { + BOOL unmatched; + + if (srv_info.pdbfile[0]) + { + if (path_find_symbol_file(module, srv_info.pdbfile, TRUE, srv_info.sig ? NULL : &srv_info.guid, + srv_info.sig, srv_info.age, &alt_srv_info, &unmatched)) + { + ret = pdb_load_debug_info(module, &alt_srv_info, unmatched); + /* FIXME module->module.CVData is not filled in from image */ + } + else + WARN("Couldn't find .pdb file %s for %s\n", debugstr_w(srv_info.pdbfile), debugstr_w(module->modulename)); + } + else if (srv_info.stripped && srv_info.dbgfile[0]) + { + if (path_find_symbol_file(module, srv_info.dbgfile, FALSE, NULL, srv_info.timestamp, 0, + &alt_srv_info, &unmatched)) + { + ret = pe_load_dbg_file(module, alt_srv_info.dbgfile); + module->module.DbgUnmatched = unmatched; + } + else + WARN("Couldn't find .DBG file %s (%s)\n", debugstr_w(srv_info.dbgfile), debugstr_w(module->modulename)); + } + } + if (!ret) + { + module->module.SymType = SymNone; + module->module.PdbSig70 = srv_info.guid; + module->module.PdbSig = srv_info.sig; + module->module.PdbAge = srv_info.age; + } + } + if (!ret && !module->dont_load_symbols) /* didn't find direct .dbg or .pdb info, try other potential formats */ { - ret = image_check_alternate(&module->format_info[DFI_PE]->u.pe_info->fmap, module); - ret = pe_load_stabs(module) || ret; - ret = pe_load_dwarf(module) || ret; + image_check_alternate(&module->format_info[DFI_PE]->u.pe_info->fmap, module); + ret = pe_load_dwarf(module) || + pe_load_stabs(module) || + pe_load_msc_debug_info(module) || + pe_load_coff_symbol_table(module); + } + if (!ret) /* we haven't found yet any debug information, fallback to unmatched pdb */ + { + static GUID null_guid; + WCHAR buffer[MAX_PATH]; + WCHAR *ext; + DWORD options; + BOOL unmatched; + + wcscpy(buffer, module->module.LoadedImageName); + ext = wcsrchr(buffer, '.'); + if (ext) wcscpy(ext + 1, L"pdb"); else wcscat(buffer, L".pdb"); + options = SymGetOptions(); + SymSetOptions(options | SYMOPT_LOAD_ANYTHING); + if (path_find_symbol_file(module, buffer, TRUE, &null_guid, + 0, 0, &alt_srv_info, &unmatched)) + { + if (!module->dont_load_symbols && module->module.SymType == SymDeferred) + { + ret = pdb_load_debug_info(module, &alt_srv_info, unmatched); + } + else + { + if (module->module.SymType == SymDeferred) + module->module.TimeDateStamp = 0; + module->module.SymType = SymNone; + } + } else if (module->module.SymType == SymNone) + module->module.TimeDateStamp = 0; + SymSetOptions(options); } - ret = pe_load_msc_debug_info(module) || ret; - ret = ret || pe_load_coff_symbol_table(module); /* FIXME */ - /* if we still have no debug info (we could only get SymExport at this - * point), then do the SymExport except if we have an ELF container, - * in which case we'll rely on the export's on the ELF side - */ } /* FIXME: * - only loading export debug info in last resort when none of the available formats succeeded * (assuming export debug info is a subset of actual debug infomation). */ - if (module->module.SymType == SymDeferred) + if (!ret) { ret = pe_load_export_debug_info(module) || ret; - if (module->module.SymType == SymDeferred) - module->module.SymType = SymNone; + module->module.SymType = SymNone; } return ret; }