From: Eric Pouech epouech@codeweavers.com
Implement it for PDB debug info. - only the types in TPI stream will be enumerated; - the typedefs, which are in DBI stream, will be migrated later on.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 1 + dlls/dbghelp/dwarf.c | 1 + dlls/dbghelp/msc.c | 1 + dlls/dbghelp/pdb.c | 43 +++++++++++++++++++++++++++ dlls/dbghelp/type.c | 53 ++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 0cbe94062a2..45239b04fd3 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -442,6 +442,7 @@ struct module_format_vtable
/* types management */ enum method_result (*find_type)(struct module_format *modfmt, const char *name, symref_t *ref); + enum method_result (*enumerate_types)(struct module_format *modfmt, BOOL (*cb)(symref_t, const char *, void*), void *user);
/* stack walk */ void (*loc_compute)(const struct module_format* modfmt, diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index e438405fee5..2361df37647 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -4299,6 +4299,7 @@ static const struct module_format_vtable dwarf2_module_format_vtable = dwarf2_module_remove, NULL, NULL, + NULL, dwarf2_location_compute, };
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index e8fc090d2e2..729c860342c 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -3992,6 +3992,7 @@ static const struct module_format_vtable old_pdb_module_format_vtable = pdb_module_remove, NULL, NULL, + NULL, pdb_location_compute, };
diff --git a/dlls/dbghelp/pdb.c b/dlls/dbghelp/pdb.c index df20829bcf6..a38372503b4 100644 --- a/dlls/dbghelp/pdb.c +++ b/dlls/dbghelp/pdb.c @@ -1755,6 +1755,48 @@ static enum method_result pdb_method_find_type(struct module_format *modfmt, con return MR_SUCCESS; }
+static enum method_result pdb_method_enumerate_types(struct module_format *modfmt, BOOL (*cb)(symref_t, const char *, void*), void *user) +{ + struct pdb_reader *pdb; + enum pdb_result result; + unsigned i; + struct pdb_reader_walker walker; + struct pdb_type_details *type_details; + struct pdb_type_hash_entry *hash_entry; + union codeview_type cv_type; + char *name; + VARIANT v; + BOOL ret; + + if (!pdb_hack_get_main_info(modfmt, &pdb, NULL)) return MR_FAILURE; + if ((result = pdb_reader_init_TPI(pdb))) return pdb_method_result(result); + walker = pdb->tpi_types_walker; + /* Note: walking the types through the hash table may not be the most efficient */ + for (i = 0; i < pdb->tpi_header.hash_num_buckets; i++) + { + if (&pdb->tpi_types_hash[i] == pdb->tpi_types_hash[i].next) continue; /* empty */ + for (hash_entry = &pdb->tpi_types_hash[i]; hash_entry; hash_entry = hash_entry->next) + { + if ((result = pdb_reader_get_type_details(pdb, hash_entry->cv_typeid, &type_details))) + continue; + + walker.offset = type_details->stream_offset; + if ((result = pdb_reader_read_partial_codeview_type(pdb, &walker, &cv_type))) return pdb_method_result(result); + result = pdb_reader_alloc_and_read_codeview_type_variablepart(pdb, walker, &cv_type, &v, &name, NULL); + if (!result) + { + if (*name) + ret = (*cb)(cv_hack_ptr_to_symref(pdb, hash_entry->cv_typeid, type_details->symt), name, user); + else + ret = TRUE; + pdb_reader_free(pdb, name); + if (!ret) return MR_SUCCESS; + } + } + } + return MR_NOT_FOUND; /* hack: as typedef are not migrated yet, ask to continue searching */ +} + symref_t cv_hack_ptr_to_symref(struct pdb_reader *pdb, cv_typ_t cv_typeid, struct symt *symt) { if (pdb) @@ -1785,6 +1827,7 @@ static struct module_format_vtable pdb_module_format_vtable = NULL,/*pdb_module_remove*/ pdb_method_request_symref_t, pdb_method_find_type, + pdb_method_enumerate_types, pdb_method_location_compute, pdb_method_get_line_from_address, pdb_method_advance_line_info, diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index 5e61137d0f2..23e4ace6eca 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -445,24 +445,77 @@ struct symt_typedef* symt_new_typedef(struct module* module, symref_t ref, return sym; }
+struct sym_modfmt_type_enum +{ + struct module *module; + SYMBOL_INFO *sym_info; + PSYM_ENUMERATESYMBOLS_CALLBACK cb; + void *user; + const char *type_name; +}; + +static BOOL sym_modfmt_type_enum_cb(symref_t symref, const char *name, void *user) +{ + struct sym_modfmt_type_enum *info = user; + DWORD64 size; + + if (info->type_name && !SymMatchStringA(name, info->type_name, TRUE)) return TRUE; + info->sym_info->TypeIndex = symt_symref_to_index(info->module, symref); + info->sym_info->Index = 0; + symt_get_info_from_symref(info->module, symref, TI_GET_LENGTH, &size); + info->sym_info->Size = size; + info->sym_info->ModBase = info->module->module.BaseOfImage; + info->sym_info->Flags = 0; /* FIXME */ + info->sym_info->Value = 0; /* FIXME */ + info->sym_info->Address = 0; /* FIXME */ + info->sym_info->Register = 0; /* FIXME */ + info->sym_info->Scope = 0; /* FIXME */ + symt_get_info_from_symref(info->module, symref, TI_GET_SYMTAG, &info->sym_info->Tag); + symbol_setname(info->sym_info, name); + + return (*info->cb)(info->sym_info, info->sym_info->Size, info->user); +} + static BOOL sym_enum_types(struct module_pair *pair, const char *type_name, PSYM_ENUMERATESYMBOLS_CALLBACK cb, void *user) { + struct module_format_vtable_iterator iter = {}; char buffer[sizeof(SYMBOL_INFO) + 256]; SYMBOL_INFO *sym_info = (SYMBOL_INFO*)buffer; struct hash_table_iter hti; void* ptr; struct symt_ht *type; DWORD64 size; + BOOL hack_only_typedef = FALSE;
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
+ /* FIXME could optim if type_name doesn't contain wild cards */ + while ((module_format_vtable_iterator_next(pair->effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(enumerate_types)))) + { + struct sym_modfmt_type_enum info = {pair->effective, sym_info, cb, user, type_name}; + enum method_result result = iter.modfmt->vtable->enumerate_types(iter.modfmt, sym_modfmt_type_enum_cb, &info); + + switch (result) + { + case MR_FAILURE: + return FALSE; + case MR_SUCCESS: + return TRUE; + case MR_NOT_FOUND: + hack_only_typedef = TRUE; + break; + } + } + hash_table_iter_init(&pair->effective->ht_types, &hti, type_name); while ((ptr = hash_table_iter_up(&hti))) { type = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
if (type_name && !SymMatchStringA(type->hash_elt.name, type_name, TRUE)) continue; + if (hack_only_typedef && !symt_check_tag(&type->symt, SymTagTypedef)) continue;
sym_info->TypeIndex = symt_ptr_to_index(pair->effective, &type->symt); sym_info->Index = 0; /* FIXME */