dbghelp: Expose some internal information about modules to winedbg.

Signed-off-by: Eric Pouech <epouech@codeweavers.com>
This commit is contained in:
Eric Pouech 2023-11-16 18:38:02 +01:00 committed by Alexandre Julliard
parent 416d29e26c
commit c50e02ec9c
10 changed files with 131 additions and 61 deletions

View file

@ -67,6 +67,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
unsigned dbghelp_options = SYMOPT_UNDNAME; unsigned dbghelp_options = SYMOPT_UNDNAME;
BOOL dbghelp_opt_native = FALSE; BOOL dbghelp_opt_native = FALSE;
BOOL dbghelp_opt_extension_api = FALSE;
BOOL dbghelp_opt_real_path = FALSE; BOOL dbghelp_opt_real_path = FALSE;
BOOL dbghelp_opt_source_actual_path = FALSE; BOOL dbghelp_opt_source_actual_path = FALSE;
SYSTEM_INFO sysinfo; SYSTEM_INFO sysinfo;
@ -612,6 +613,10 @@ BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value)
old = dbghelp_opt_native; old = dbghelp_opt_native;
dbghelp_opt_native = value; dbghelp_opt_native = value;
break; break;
case SYMOPT_EX_WINE_EXTENSION_API:
old = dbghelp_opt_extension_api;
dbghelp_opt_extension_api = value;
break;
case SYMOPT_EX_WINE_MODULE_REAL_PATH: case SYMOPT_EX_WINE_MODULE_REAL_PATH:
old = dbghelp_opt_real_path; old = dbghelp_opt_real_path;
dbghelp_opt_real_path = value; dbghelp_opt_real_path = value;
@ -637,6 +642,8 @@ BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)
{ {
case SYMOPT_EX_WINE_NATIVE_MODULES: case SYMOPT_EX_WINE_NATIVE_MODULES:
return dbghelp_opt_native; return dbghelp_opt_native;
case SYMOPT_EX_WINE_EXTENSION_API:
return dbghelp_opt_extension_api;
case SYMOPT_EX_WINE_MODULE_REAL_PATH: case SYMOPT_EX_WINE_MODULE_REAL_PATH:
return dbghelp_opt_real_path; return dbghelp_opt_real_path;
case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH: case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH:

View file

@ -215,3 +215,6 @@
#@ stub sym #@ stub sym
#@ stub symsrv #@ stub symsrv
#@ stub vc7fpo #@ stub vc7fpo
# wine extensions
@ stdcall wine_get_module_information(long int64 ptr long)

View file

@ -112,6 +112,7 @@ void* hash_table_iter_up(struct hash_table_iter* hti);
extern unsigned dbghelp_options; extern unsigned dbghelp_options;
extern BOOL dbghelp_opt_native; extern BOOL dbghelp_opt_native;
extern BOOL dbghelp_opt_extension_api;
extern BOOL dbghelp_opt_real_path; extern BOOL dbghelp_opt_real_path;
extern BOOL dbghelp_opt_source_actual_path; extern BOOL dbghelp_opt_source_actual_path;
extern SYSTEM_INFO sysinfo; extern SYSTEM_INFO sysinfo;
@ -396,13 +397,6 @@ struct symt_udt
struct vector vchildren; struct vector vchildren;
}; };
enum module_type
{
DMT_ELF, /* a real ELF shared module */
DMT_PE, /* a native or builtin PE module */
DMT_MACHO, /* a real Mach-O shared module */
};
struct process; struct process;
struct module; struct module;
@ -445,7 +439,7 @@ struct module
IMAGEHLP_MODULEW64 module; IMAGEHLP_MODULEW64 module;
WCHAR modulename[64]; /* used for enumeration */ WCHAR modulename[64]; /* used for enumeration */
struct module* next; struct module* next;
enum module_type type : 16; enum dhext_module_type type : 16;
unsigned short is_virtual : 1; unsigned short is_virtual : 1;
struct cpu* cpu; struct cpu* cpu;
DWORD64 reloc_delta; DWORD64 reloc_delta;
@ -453,6 +447,7 @@ struct module
/* specific information for debug types */ /* specific information for debug types */
struct module_format* format_info[DFI_LAST]; struct module_format* format_info[DFI_LAST];
unsigned debug_format_bitmask;
/* memory allocation pool */ /* memory allocation pool */
struct pool pool; struct pool pool;
@ -742,7 +737,7 @@ extern struct module*
extern BOOL module_get_debug(struct module_pair*); extern BOOL module_get_debug(struct module_pair*);
extern struct module* extern struct module*
module_new(struct process* pcs, const WCHAR* name, module_new(struct process* pcs, const WCHAR* name,
enum module_type type, BOOL virtual, enum dhext_module_type type, BOOL virtual,
DWORD64 addr, DWORD64 size, DWORD64 addr, DWORD64 size,
ULONG_PTR stamp, ULONG_PTR checksum, WORD machine); ULONG_PTR stamp, ULONG_PTR checksum, WORD machine);
extern struct module* extern struct module*

View file

@ -2892,8 +2892,8 @@ static BOOL dwarf2_parse_compilation_unit_head(dwarf2_parse_context_t* ctx,
TRACE("- word_size: %u\n", ctx->head.word_size); TRACE("- word_size: %u\n", ctx->head.word_size);
TRACE("- offset_size: %u\n", ctx->head.offset_size); TRACE("- offset_size: %u\n", ctx->head.offset_size);
if (ctx->head.version >= 2) if (ctx->head.version >= 2 && ctx->head.version <= 5)
ctx->module_ctx->cu_versions |= 1 << (ctx->head.version - 2); ctx->module_ctx->cu_versions |= DHEXT_FORMAT_DWARF2 << (ctx->head.version - 2);
if (max_supported_dwarf_version == 0) if (max_supported_dwarf_version == 0)
{ {
char* env = getenv("DBGHELP_DWARF_VERSION"); char* env = getenv("DBGHELP_DWARF_VERSION");
@ -4259,17 +4259,16 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset,
module_ctx.dwz = dwarf2_load_dwz(fmap, module); module_ctx.dwz = dwarf2_load_dwz(fmap, module);
dwarf2_load_CU_module(&module_ctx, module, section, load_offset, thunks, FALSE); dwarf2_load_CU_module(&module_ctx, module, section, load_offset, thunks, FALSE);
dwarf2_modfmt->module->module.SymType = SymDia; if (module_ctx.cu_versions)
/* hide dwarf versions in CVSig {
* bits 24-31 will be set according to found dwarf version dwarf2_modfmt->module->module.SymType = SymDia;
* different CU can have different dwarf version, so use a bit per version (version 2 => b24) module->debug_format_bitmask |= module_ctx.cu_versions;
*/ /* FIXME: we could have a finer grain here */
dwarf2_modfmt->module->module.CVSig = 'D' | ('W' << 8) | ('F' << 16) | ((module_ctx.cu_versions & 0xFF) << 24); dwarf2_modfmt->module->module.GlobalSymbols = TRUE;
/* FIXME: we could have a finer grain here */ dwarf2_modfmt->module->module.TypeInfo = TRUE;
dwarf2_modfmt->module->module.GlobalSymbols = TRUE; dwarf2_modfmt->module->module.SourceIndexed = TRUE;
dwarf2_modfmt->module->module.TypeInfo = TRUE; dwarf2_modfmt->module->module.Publics = TRUE;
dwarf2_modfmt->module->module.SourceIndexed = TRUE; }
dwarf2_modfmt->module->module.Publics = TRUE;
dwarf2_unload_CU_module(&module_ctx); dwarf2_unload_CU_module(&module_ctx);
leave: leave:

View file

@ -102,7 +102,7 @@ struct macho_section32
*/ */
struct image_file_map struct image_file_map
{ {
enum module_type modtype; enum dhext_module_type modtype;
const struct image_file_map_ops *ops; const struct image_file_map_ops *ops;
unsigned addr_size; /* either 16 (not used), 32 or 64 */ unsigned addr_size; /* either 16 (not used), 32 or 64 */
struct image_file_map* alternate; /* another file linked to this one */ struct image_file_map* alternate; /* another file linked to this one */

View file

@ -162,7 +162,7 @@ WCHAR *get_wine_loader_name(struct process *pcs)
return altname; return altname;
} }
static const char* get_module_type(enum module_type type, BOOL virtual) static const char* get_module_type(enum dhext_module_type type, BOOL virtual)
{ {
switch (type) switch (type)
{ {
@ -177,7 +177,7 @@ static const char* get_module_type(enum module_type type, BOOL virtual)
* Creates and links a new module to a process * Creates and links a new module to a process
*/ */
struct module* module_new(struct process* pcs, const WCHAR* name, struct module* module_new(struct process* pcs, const WCHAR* name,
enum module_type type, BOOL virtual, enum dhext_module_type type, BOOL virtual,
DWORD64 mod_addr, DWORD64 size, DWORD64 mod_addr, DWORD64 size,
ULONG_PTR stamp, ULONG_PTR checksum, WORD machine) ULONG_PTR stamp, ULONG_PTR checksum, WORD machine)
{ {
@ -238,6 +238,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name,
module->cpu = cpu_find(machine); module->cpu = cpu_find(machine);
if (!module->cpu) if (!module->cpu)
module->cpu = dbghelp_current_cpu; module->cpu = dbghelp_current_cpu;
module->debug_format_bitmask = 0;
vector_init(&module->vsymt, sizeof(struct symt*), 128); vector_init(&module->vsymt, sizeof(struct symt*), 128);
vector_init(&module->vcustom_symt, sizeof(struct symt*), 16); vector_init(&module->vcustom_symt, sizeof(struct symt*), 16);
@ -1653,3 +1654,35 @@ const struct loader_ops empty_loader_ops =
empty_enum_modules, empty_enum_modules,
native_fetch_file_info, native_fetch_file_info,
}; };
BOOL WINAPI wine_get_module_information(HANDLE proc, DWORD64 base, struct dhext_module_information* wmi, unsigned len)
{
struct process* pcs;
struct module* module;
struct dhext_module_information dhmi;
/* could be interpreted as a WinDbg extension */
if (!dbghelp_opt_extension_api)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
TRACE("(%p %I64x %p %u\n", proc, base, wmi, len);
if (!(pcs = process_find_by_handle(proc))) return FALSE;
if (len > sizeof(*wmi)) return FALSE;
module = module_find_by_addr(pcs, base);
if (!module) return FALSE;
dhmi.type = module->type;
dhmi.debug_format_bitmask = module->debug_format_bitmask;
if ((module = module_get_container(pcs, module)))
{
dhmi.debug_format_bitmask |= module->debug_format_bitmask;
}
memcpy(wmi, &dhmi, len);
return TRUE;
}

View file

@ -1664,7 +1664,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset,
stab_ptr->n_type, (ULONG_PTR)n_value, debugstr_a(strs + stab_ptr->n_strx)); stab_ptr->n_type, (ULONG_PTR)n_value, debugstr_a(strs + stab_ptr->n_strx));
} }
module->module.SymType = SymDia; module->module.SymType = SymDia;
module->module.CVSig = 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24); module->debug_format_bitmask |= DHEXT_FORMAT_STABS;
/* FIXME: we could have a finer grain here */ /* FIXME: we could have a finer grain here */
module->module.LineNumbers = TRUE; module->module.LineNumbers = TRUE;
module->module.GlobalSymbols = TRUE; module->module.GlobalSymbols = TRUE;

View file

@ -1098,6 +1098,8 @@ typedef enum
#ifdef __WINESRC__ #ifdef __WINESRC__
/* Include ELF/Mach-O modules in module operations */ /* Include ELF/Mach-O modules in module operations */
SYMOPT_EX_WINE_NATIVE_MODULES = 1000, SYMOPT_EX_WINE_NATIVE_MODULES = 1000,
/* Enable Wine's extension APIs */
SYMOPT_EX_WINE_EXTENSION_API,
/* Return the Unix actual path of loaded module */ /* Return the Unix actual path of loaded module */
SYMOPT_EX_WINE_MODULE_REAL_PATH, SYMOPT_EX_WINE_MODULE_REAL_PATH,
/* Return the raw source file path from debug info (not always mapped to DOS) */ /* Return the raw source file path from debug info (not always mapped to DOS) */
@ -1240,6 +1242,37 @@ BOOL IMAGEAPI SymUnloadModule(HANDLE, DWORD);
#endif #endif
#ifdef __WINESRC__
/* Wine extensions to dbghelp */
enum dhext_module_type
{
DMT_UNKNOWN, /* for lookup, not actually used for a module */
DMT_ELF, /* a real ELF shared module */
DMT_MACHO, /* a real Mach-O shared module */
DMT_PE, /* a native or builtin PE module */
};
/* only reporting the formats not exposed in regular IMAGHELP_MODULE_INFO */
enum dhext_debug_format
{
DHEXT_FORMAT_DWARF2 = 0x0001,
DHEXT_FORMAT_DWARF3 = 0x0002,
DHEXT_FORMAT_DWARF4 = 0x0004,
DHEXT_FORMAT_DWARF5 = 0x0008,
DHEXT_FORMAT_STABS = 0x0010,
};
struct dhext_module_information
{
enum dhext_module_type type;
unsigned debug_format_bitmask;
};
extern BOOL WINAPI wine_get_module_information(HANDLE, DWORD64 base, struct dhext_module_information*, unsigned len);
#endif /* __WINESRC__ */
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif /* defined(__cplusplus) */ #endif /* defined(__cplusplus) */

View file

@ -116,9 +116,23 @@ void info_help(void)
while (infotext[i]) dbg_printf("%s\n", infotext[i++]); while (infotext[i]) dbg_printf("%s\n", infotext[i++]);
} }
static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi) struct info_module
{ {
switch (mi->SymType) IMAGEHLP_MODULEW64 mi;
struct dhext_module_information ext_module_info;
char name[64];
};
struct info_modules
{
struct info_module *modules;
unsigned num_alloc;
unsigned num_used;
};
static const char* get_symtype_str(const struct info_module* im)
{
switch (im->mi.SymType)
{ {
default: default:
case SymNone: return "--none--"; case SymNone: return "--none--";
@ -129,43 +143,26 @@ static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi)
case SymDeferred: return "Deferred"; case SymDeferred: return "Deferred";
case SymSym: return "Sym"; case SymSym: return "Sym";
case SymDia: case SymDia:
switch (mi->CVSig) if (im->ext_module_info.debug_format_bitmask)
{ {
case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24): static char tmp[64];
return "Stabs"; tmp[0] = '\0';
case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24): if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_STABS) strcpy(tmp, "stabs");
/* previous versions of dbghelp used to report this... */ if (im->ext_module_info.debug_format_bitmask & (DHEXT_FORMAT_DWARF2 | DHEXT_FORMAT_DWARF3 | DHEXT_FORMAT_DWARF4 | DHEXT_FORMAT_DWARF5))
return "Dwarf";
default:
if ((mi->CVSig & 0x00FFFFFF) == ('D' | ('W' << 8) | ('F' << 16)))
{ {
static char tmp[64]; if (tmp[0]) strcat(tmp, ", ");
DWORD versbit = mi->CVSig >> 24; strcat(tmp, "Dwarf");
strcpy(tmp, "Dwarf"); if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF2) strcat(tmp, "-2");
if (versbit & 1) strcat(tmp, "-2"); if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF3) strcat(tmp, "-3");
if (versbit & 2) strcat(tmp, "-3"); if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF4) strcat(tmp, "-4");
if (versbit & 4) strcat(tmp, "-4"); if (im->ext_module_info.debug_format_bitmask & DHEXT_FORMAT_DWARF5) strcat(tmp, "-5");
if (versbit & 8) strcat(tmp, "-5");
return tmp;
} }
return "DIA"; return tmp;
} }
return "DIA";
} }
} }
struct info_module
{
IMAGEHLP_MODULE64 mi;
char name[64];
};
struct info_modules
{
struct info_module *modules;
unsigned num_alloc;
unsigned num_used;
};
static const char* get_machine_str(DWORD machine) static const char* get_machine_str(DWORD machine)
{ {
static char tmp[32]; static char tmp[32];
@ -187,12 +184,12 @@ static void module_print_info(const struct info_module *module, BOOL is_embedded
module->mi.BaseOfImage, module->mi.BaseOfImage,
module->mi.BaseOfImage + module->mi.ImageSize, module->mi.BaseOfImage + module->mi.ImageSize,
get_machine_str(module->mi.MachineType), get_machine_str(module->mi.MachineType),
is_embedded ? "\\" : get_symtype_str(&module->mi), module->name); is_embedded ? "\\" : get_symtype_str(module), module->name);
else else
dbg_printf("%*.*I64x-%*.*I64x\t%-16s%s\n", dbg_printf("%*.*I64x-%*.*I64x\t%-16s%s\n",
ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage, ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage,
ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage + module->mi.ImageSize, ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage + module->mi.ImageSize,
is_embedded ? "\\" : get_symtype_str(&module->mi), module->name); is_embedded ? "\\" : get_symtype_str(module), module->name);
} }
static int __cdecl module_compare(const void* p1, const void* p2) static int __cdecl module_compare(const void* p1, const void* p2)
@ -226,7 +223,9 @@ static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
im->modules = new; im->modules = new;
} }
im->modules[im->num_used].mi.SizeOfStruct = sizeof(im->modules[im->num_used].mi); im->modules[im->num_used].mi.SizeOfStruct = sizeof(im->modules[im->num_used].mi);
if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->modules[im->num_used].mi)) if (SymGetModuleInfoW64(dbg_curr_process->handle, base, &im->modules[im->num_used].mi) &&
wine_get_module_information(dbg_curr_process->handle, base, &im->modules[im->num_used].ext_module_info,
sizeof(im->modules[im->num_used].ext_module_info)))
{ {
const int dst_len = sizeof(im->modules[im->num_used].name); const int dst_len = sizeof(im->modules[im->num_used].name);
lstrcpynA(im->modules[im->num_used].name, mod_name, dst_len - 1); lstrcpynA(im->modules[im->num_used].name, mod_name, dst_len - 1);

View file

@ -723,6 +723,7 @@ int main(int argc, char** argv)
SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS |
SYMOPT_INCLUDE_32BIT_MODULES); SYMOPT_INCLUDE_32BIT_MODULES);
SymSetExtendedOption(SYMOPT_EX_WINE_EXTENSION_API, TRUE);
SymSetExtendedOption(SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH, TRUE); SymSetExtendedOption(SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH, TRUE);
if (argc && !strcmp(argv[0], "--auto")) if (argc && !strcmp(argv[0], "--auto"))