From: Eric Pouech <epouech@codeweavers.com> Signed-off-by: Eric Pouech <epouech@codeweavers.com> --- dlls/dbghelp/pdb.c | 367 ++++++++++++++++++++++++++++++++---------- dlls/dbghelp/symbol.c | 44 ++++- 2 files changed, 325 insertions(+), 86 deletions(-) diff --git a/dlls/dbghelp/pdb.c b/dlls/dbghelp/pdb.c index 657ee77d683..d8fddbef155 100644 --- a/dlls/dbghelp/pdb.c +++ b/dlls/dbghelp/pdb.c @@ -120,6 +120,12 @@ struct pdb_compiland struct symt_compiland* compiland; }; +struct pdb_global +{ + unsigned rva; + symref_t symref; +}; + struct pdb_reader { struct module *module; @@ -170,6 +176,10 @@ struct pdb_reader const IMAGE_SECTION_HEADER *sections; unsigned num_sections; + /* global symbols map */ + struct pdb_global *globals; + unsigned num_globals; + /* PDB file access */ pdb_reader_fetch_block_t fetch; struct {unsigned block_no; unsigned age;} cache[4*4]; @@ -1840,16 +1850,6 @@ static enum pdb_result pdb_reader_whole_stream_access_codeview_symbol(struct pdb return R_PDB_SUCCESS; } -static int my_action_global_obj_cmp(const void *p1, const void *p2) -{ - pdbsize_t o1 = ((const struct pdb_action_entry *)p1)->stream_offset; - pdbsize_t o2 = ((const struct pdb_action_entry *)p2)->stream_offset; - - if (o1 < o2) return -1; - if (o1 > o2) return +1; - return 0; -} - static enum pdb_result pdb_reader_init_DBI_substreams(struct pdb_reader *pdb) { enum pdb_result result; @@ -1871,14 +1871,23 @@ static enum pdb_result pdb_reader_init_DBI_substreams(struct pdb_reader *pdb) return R_PDB_SUCCESS; } +static int pdb_global_cmp(const void *p1, const void *p2) +{ + const struct pdb_global *g1 = p1; + const struct pdb_global *g2 = p2; + if (g1->rva < g2->rva) return -1; + if (g1->rva > g2->rva) return +1; + return 0; +} + static enum pdb_result pdb_reader_init_DBI(struct pdb_reader *pdb) { enum pdb_result result; struct pdb_reader_compiland_iterator compiland_iter; struct pdb_reader_walker walker; - struct pdb_reader_whole_stream whole; - const union codeview_symbol *cv_global_symbol, *cv_global_symbol2; - unsigned hash; + union codeview_symbol cv_symbol; + struct symref_code code; + symref_t top_symref; symref_t symref; unsigned i; @@ -1913,65 +1922,46 @@ static enum pdb_result pdb_reader_init_DBI(struct pdb_reader *pdb) } if ((result = pdb_reader_load_DBI_hash_table(pdb))) return result; - if ((result = pdb_reader_alloc_and_load_whole_stream(pdb, pdb->dbi_header.gsym_stream, &whole))) return result; + if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.gsym_stream, &walker))) return result; + if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_top(&code), &top_symref))) return result; - for (hash = 0; hash < DBI_MAX_HASH; hash++) + pdb->num_globals = 0; + pdb->globals = NULL; + while (!(result = pdb_reader_read_partial_codeview_symbol(pdb, &walker, &cv_symbol))) { - struct pdb_dbi_hash_bucket *bucket = &pdb->dbi_symbols_hash_buckets[hash]; - DWORD64 address; - struct symref_code code; - symref_t top_symref, type_symref; - unsigned int i, j; - BOOL found; - - if (!bucket->num_entries) continue; - if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_top(&code), &top_symref))) return result; - for (i = 0; i < bucket->num_entries; i++) + DWORD64 addr; + switch (cv_symbol.generic.id) { - if (!pdb_reader_whole_stream_access_codeview_symbol(pdb, &whole, bucket->entries[i].dbi_stream_offset, &cv_global_symbol)) + case S_GDATA32: + case S_LDATA32: + case S_GTHREAD32: + case S_LTHREAD32: + case S_UDT: + if ((result = pdb_reader_push_action(pdb, action_type_globals, walker.offset - sizeof(cv_symbol.generic.len), + cv_symbol.generic.len + sizeof(cv_symbol.generic.len), + top_symref, &symref))) return result; + if (cv_symbol.generic.id == S_GDATA32 || cv_symbol.generic.id == S_LDATA32) { - switch (cv_global_symbol->generic.id) + if (!pdb_reader_get_segment_address(pdb, cv_symbol.data_v3.segment, cv_symbol.data_v3.offset, &addr)) { - case S_UDT: - if ((result = pdb_reader_push_action(pdb, action_type_globals, bucket->entries[i].dbi_stream_offset, - cv_global_symbol->generic.len + sizeof(cv_global_symbol->generic.len), - top_symref, &symref))) return result; - break; - case S_GDATA32: - /* There are cases (incremental linking) where we have several entries of same name, but - * only one is valid. - * We discriminate valid with: - * - there's no other entry with same name before this entry in hash bucket, - * - the address is valid - * - the typeid is valid - * Note: checking address map doesn't bring nothing as the invalid entries are also listed - * there. - */ - found = FALSE; - for (j = 0; !found && j < i; j++) + if (!(pdb->num_globals & (pdb->num_globals - 1))) { - if (!pdb_reader_whole_stream_access_codeview_symbol(pdb, &whole, bucket->entries[j].dbi_stream_offset, &cv_global_symbol2)) - found = !strcmp(cv_global_symbol->data_v3.name, cv_global_symbol2->data_v3.name); + unsigned sz = pdb->num_globals ? pdb->num_globals * 2 : 1; + if ((result = pdb_reader_realloc(pdb, (void **)&pdb->globals, sz * sizeof(pdb->globals[0])))) + return result; } - if (!found && - !pdb_reader_get_segment_address(pdb, cv_global_symbol->data_v3.segment, cv_global_symbol->data_v3.offset, &address) && - !pdb_reader_symref_from_cv_typeid(pdb, cv_global_symbol->data_v3.symtype, &type_symref)) - { - struct location loc = {.kind = loc_absolute, .reg = 0, .offset = address}; - symt_new_global_variable(pdb->module, 0, cv_global_symbol->data_v3.name, - FALSE, loc, 0, type_symref); - } - break; + pdb->globals[pdb->num_globals].rva = addr - pdb->module->module.BaseOfImage; + pdb->globals[pdb->num_globals].symref = symref; + pdb->num_globals++; } } + break; } + walker.offset += cv_symbol.generic.len; } - if ((result = pdb_reader_dispose_whole_stream(pdb, &whole))) return result; pdb->num_action_globals = pdb->num_action_entries; - /* as we walked the DBI stream according to hash order, resort by stream_offset */ - qsort(pdb->action_store, pdb->num_action_globals, sizeof(pdb->action_store[0]), - &my_action_global_obj_cmp); - + /* Note: rva is not unique */ + qsort(pdb->globals, pdb->num_globals, sizeof(*pdb->globals), &pdb_global_cmp); if ((result = pdb_reader_init_DBI_substreams(pdb))) return result; return R_PDB_SUCCESS; @@ -2778,28 +2768,21 @@ static enum method_result pdb_method_enumerate_types(struct module_format *modfm struct pdb_reader_walker walker; union codeview_symbol *cv_symbol; struct pdb_action_entry *entry; - pdbsize_t num_read; entry = &pdb->action_store[i]; if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.gsym_stream, &walker))) return MR_FAILURE; walker.offset = entry->stream_offset; - if ((result = pdb_reader_alloc(pdb, entry->action_length, (void**)&cv_symbol))) return MR_FAILURE; - if ((result = pdb_reader_read_from_stream(pdb, &walker, cv_symbol, entry->action_length, &num_read))) return MR_FAILURE; + if ((result = pdb_reader_alloc_and_read_full_codeview_symbol(pdb, &walker, &cv_symbol))) return MR_FAILURE; if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_action(&code, i), &symref))) return MR_FAILURE; - if (num_read == entry->action_length) + switch (cv_symbol->generic.id) { - switch (cv_symbol->generic.id) - { - case S_UDT: - ret = (*cb)(symref, cv_symbol->udt_v3.name, user); - break; - default: - WARN("Got unexpected %x\n", cv_symbol->generic.id); - ret = FALSE; - break; - } + case S_UDT: + ret = (*cb)(symref, cv_symbol->udt_v3.name, user); + break; + default: + ret = TRUE; + break; } - else ret = TRUE; pdb_reader_free(pdb, cv_symbol); if (!ret) break; } @@ -3512,6 +3495,65 @@ static enum method_result pdb_reader_DBI_typedef_request(struct pdb_reader *pdb, } } +static enum method_result pdb_reader_symbol_data_request(struct pdb_reader *pdb, union codeview_symbol *cv_symbol, symref_t parent_symref, + IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagData; + return MR_SUCCESS; + case TI_GET_SYMNAME: + *((WCHAR **)data) = heap_allocate_symname(cv_symbol->data_v3.name); + return *((WCHAR **)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_DATAKIND: + *((DWORD*)data) = cv_symbol->generic.id == S_GDATA32 ? DataIsGlobal : DataIsFileStatic; + return MR_SUCCESS; + case TI_GET_LEXICALPARENT: + *((DWORD*)data) = symt_symref_to_index(pdb->module, parent_symref); + return MR_SUCCESS; + case TI_GET_ADDRESS: + return pdb_method_result(pdb_reader_get_segment_address(pdb, cv_symbol->data_v3.segment, cv_symbol->data_v3.offset, data)); + case TI_GET_LENGTH: + return pdb_reader_request_cv_typeid(pdb, cv_symbol->data_v3.symtype, req, data); + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_symbol->data_v3.symtype, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_symbol_tls_request(struct pdb_reader *pdb, union codeview_symbol *cv_symbol, symref_t parent_symref, + IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagData; + return MR_SUCCESS; + case TI_GET_SYMNAME: + *((WCHAR **)data) = heap_allocate_symname(cv_symbol->thread_v3.name); + return *((WCHAR **)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_DATAKIND: + *((DWORD*)data) = cv_symbol->generic.id == S_GTHREAD32 ? DataIsGlobal : DataIsFileStatic; + return MR_SUCCESS; + case TI_GET_LEXICALPARENT: + *((DWORD*)data) = symt_symref_to_index(pdb->module, parent_symref); + return MR_SUCCESS; + case TI_GET_ADDRESSOFFSET: + *((DWORD*)data) = cv_symbol->thread_v3.offset; + return MR_SUCCESS; + case TI_GET_LENGTH: + return pdb_reader_request_cv_typeid(pdb, cv_symbol->thread_v3.symtype, req, data); + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_symbol->thread_v3.symtype, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + default: + return MR_FAILURE; + } +} + static enum method_result pdb_reader_codeview_symbol_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) { enum pdb_result result; @@ -3545,6 +3587,12 @@ static enum method_result pdb_reader_codeview_symbol_request(struct pdb_reader * else FIXME("Unexpected encoding kind %u\n", code.kind); break; + case S_GDATA32: + case S_LDATA32: + return pdb_reader_symbol_data_request(pdb, cv_symbol, entry->container_symref, req, data); + case S_GTHREAD32: + case S_LTHREAD32: + return pdb_reader_symbol_tls_request(pdb, cv_symbol, entry->container_symref, req, data); default: WARN("Got unexpected %x\n", cv_symbol->generic.id); break; @@ -3598,6 +3646,121 @@ static enum method_result pdb_reader_TPI_request(struct pdb_reader *pdb, symref_ return ret; } +static enum pdb_result pdb_reader_top_fill_in(struct pdb_reader *pdb, unsigned *count, DWORD *ids, unsigned first, unsigned last) +{ + struct pdb_reader_whole_stream whole; + struct symref_code code; + symref_t top_symref; + enum pdb_result result = R_PDB_SUCCESS; + unsigned int hash; + + if ((result = pdb_reader_alloc_and_load_whole_stream(pdb, pdb->dbi_header.gsym_stream, &whole))) return result; + *count = 0; + if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_top(&code), &top_symref))) return result; + for (hash = 0; hash < DBI_MAX_HASH && !result; hash++) + { + struct pdb_dbi_hash_bucket *bucket = &pdb->dbi_symbols_hash_buckets[hash]; + const union codeview_symbol *cv_global_symbol, *cv_global_symbol2; + symref_t symref; + unsigned int i, j; + BOOL found; + + if (!bucket->num_entries) continue; + for (i = 0; i < bucket->num_entries && !result; i++) + { + if (!pdb_reader_whole_stream_access_codeview_symbol(pdb, &whole, bucket->entries[i].dbi_stream_offset, &cv_global_symbol)) + { + symref = 0; + found = FALSE; + switch (cv_global_symbol->generic.id) + { + case S_UDT: + found = TRUE; + break; + case S_GDATA32: + /* There are cases (incremental linking) where we have several entries of same name, but + * only one is valid. + * We discriminate valid with: + * - there's no other entry with same name before this entry in hash bucket, + * - the address is valid + * - the typeid is valid + * Note: checking address map doesn't bring nothing as the invalid entries are also listed + * there. + */ + for (j = 0; !found && j < i; j++) + { + if (!pdb_reader_whole_stream_access_codeview_symbol(pdb, &whole, bucket->entries[j].dbi_stream_offset, &cv_global_symbol2)) + found = !strcmp(cv_global_symbol->data_v3.name, cv_global_symbol2->data_v3.name); + } + found = !found; + break; + default: + break; + } + if (found) + { + if (ids) + { + if (*count >= last) + result = R_PDB_BUFFER_TOO_SMALL; + if (*count >= first) + { + if (!(result = pdb_reader_push_action(pdb, action_type_globals, + bucket->entries[i].dbi_stream_offset, + cv_global_symbol->generic.len + sizeof(cv_global_symbol->generic.len), + top_symref, &symref))) + ids[*count] = symt_symref_to_index(pdb->module, symref); + } + } + (*count)++; + } + } + } + } + (void)pdb_reader_dispose_whole_stream(pdb, &whole); + return result; +} + +static enum method_result pdb_reader_top_request(struct pdb_reader *pdb, symref_t symref, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum pdb_result result; + + switch (req) + { + case TI_GET_SYMTAG: + *(DWORD*)data = SymTagExe; + return MR_SUCCESS; + case TI_GET_CHILDRENCOUNT: + { + unsigned count; + if (!symt_get_info(pdb->module, &pdb->module->top->symt, req, data) || + pdb_reader_top_fill_in(pdb, &count, NULL, 0, 0)) return MR_FAILURE; + *(DWORD*)data += count; + return MR_SUCCESS; + } + case TI_FINDCHILDREN: + { + TI_FINDCHILDREN_PARAMS *p = data; + TI_FINDCHILDREN_PARAMS *alt; + unsigned int count; + + if (pdb_reader_top_fill_in(pdb, &count, p->ChildId, p->Start, p->Count)) return MR_FAILURE; + if (!(alt = malloc(offsetof(TI_FINDCHILDREN_PARAMS, ChildId[p->Count - count])))) return MR_FAILURE; + alt->Start = 0; + alt->Count = p->Count - count; + result = symt_get_info(pdb->module, &pdb->module->top->symt, TI_FINDCHILDREN, alt); + if (result == R_PDB_SUCCESS) + memcpy(&p->ChildId[count], alt->ChildId, (p->Count - count) * sizeof(p->ChildId[0])); + free(alt); + return pdb_method_result(result); + } + case TI_GET_SYMNAME: + return symt_get_info(pdb->module, &pdb->module->top->symt, req, data) ? MR_SUCCESS : MR_FAILURE; + default: + return MR_FAILURE; + } +} + static enum method_result pdb_reader_request_symref_t(struct pdb_reader *pdb, symref_t symref, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) { struct pdb_type_details *type_details; @@ -3613,7 +3776,7 @@ static enum method_result pdb_reader_request_symref_t(struct pdb_reader *pdb, sy switch (code.kind) { case symref_code_top: - return symt_get_info(pdb->module, &pdb->module->top->symt, req, data) ? MR_SUCCESS : MR_FAILURE; + return pdb_reader_top_request(pdb, symref, req, data); case symref_code_compiland: return symt_get_info(pdb->module, &pdb->compilands[code.compiland].compiland->symt, req, data) ? MR_SUCCESS : MR_FAILURE; case symref_code_cv_typeid: @@ -3809,6 +3972,8 @@ static enum pdb_result pdb_reader_search_codeview_symbol_by_address(struct pdb_r case S_BUILDINFO: case S_UDT: case S_UNAMESPACE: + case S_GTHREAD32: + case S_LTHREAD32: segment = 0; offset = 0; pend = 0; @@ -4302,7 +4467,7 @@ static enum pdb_result pdb_reader_create_variable(struct pdb_reader *pdb, } if (is_local ^ (compiland != 0)) FIXME("Unsupported construct\n"); - symt_new_global_variable(pdb->module, compiland, name, is_local, *loc, 0, symref); + symt_new_global_variable(pdb->module, (is_local && loc->kind == loc_tlsrel) ? 0 : compiland, name, is_local, *loc, 0, symref); } return R_PDB_SUCCESS; } @@ -4359,7 +4524,6 @@ static enum pdb_result pdb_reader_load_compiland_symbols(struct pdb_reader *pdb, break; /* variables with thread storage */ - case S_GTHREAD32: case S_LTHREAD32: loc.kind = loc_tlsrel; loc.reg = 0; @@ -4625,6 +4789,7 @@ static enum pdb_result pdb_reader_load_compiland_symbols(struct pdb_reader *pdb, case S_LPROCREF: case S_TOKENREF: case S_GDATA32: + case S_GTHREAD32: case S_UDT: PDB_REPORT_UNEXPECTED("(compiland stream) symbol id", cv_symbol->generic.id); break; @@ -4727,9 +4892,30 @@ static enum method_result pdb_method_lookup_symbol_by_address(struct module_form enum pdb_result result; struct pdb_reader *pdb; unsigned segment, offset; + struct pdb_global key, *found; pdb = pdb_get_current_reader(modfmt); - if ((result = pdb_reader_get_segment_offset_from_address(pdb, address, &segment, &offset))) return MR_FAILURE; + if ((result = pdb_reader_get_segment_offset_from_address(pdb, address, &segment, &offset))) + { + struct symref_code code; + if (address == pdb->module->module.BaseOfImage && !pdb_reader_encode_symref(pdb, symref_code_init_from_top(&code), symref)) + return MR_SUCCESS; + return MR_FAILURE; + } + key.rva = address - pdb->module->module.BaseOfImage; + found = bsearch(&key, pdb->globals, pdb->num_globals, sizeof(*pdb->globals), &pdb_global_cmp); + if (found && found->rva == key.rva) + { + /* Note: we can have several names for the same address. + * For now, we return one of the entries, no clear way of choosing one or another + */ + if (found > pdb->globals && (found - 1)->rva == key.rva) + WARN("Duplicate found before\n"); + if (found + 1 < pdb->globals + pdb->num_globals && (found + 1)->rva == key.rva) + WARN("Duplicate found after\n"); + *symref = found->symref; + return MR_SUCCESS; + } return pdb_method_result(pdb_reader_lookup_top_symbol_by_segment_offset(pdb, segment, offset, symref)); } @@ -4791,10 +4977,16 @@ static enum method_result pdb_method_lookup_symbol_by_name(struct module_format switch (cv_symbol.generic.id) { case S_GDATA32: + case S_GTHREAD32: + return pdb_method_result(pdb_reader_DBI_globals_symref(pdb, globals_offset, symref)); case S_LDATA32: segment = cv_symbol.data_v3.segment; offset = cv_symbol.data_v3.offset; break; + case S_LTHREAD32: + segment = cv_symbol.thread_v3.segment; + offset = cv_symbol.thread_v3.offset; + break; case S_PROCREF: case S_LPROCREF: if ((result = pdb_reader_dereference_procedure(pdb, cv_symbol.refsym2_v3.imod, cv_symbol.refsym2_v3.ibSym, @@ -4864,12 +5056,21 @@ static enum method_result pdb_method_enumerate_symbols(struct module_format *mod if (symbol_name) { BOOL do_continue = TRUE; - symref_t symref; - if (symt_match_stringAW(symbol_name, match, TRUE) && - pdb_reader_lookup_top_symbol_by_segment_offset(pdb, segment, offset, &symref) == R_PDB_SUCCESS) + if (symt_match_stringAW(symbol_name, match, TRUE)) { - do_continue = cb(symref, symbol_name, user); + symref_t symref; + switch (cv_symbol.generic.id) + { + case S_GDATA32: + result = pdb_reader_DBI_globals_symref(pdb, walker.offset - sizeof(cv_symbol.generic.len), &symref); + break; + default: + result = pdb_reader_lookup_top_symbol_by_segment_offset(pdb, segment, offset, &symref); + break; + } + if (result == R_PDB_SUCCESS) + do_continue = cb(symref, symbol_name, user); } pdb_reader_free(pdb, symbol_name); if (!do_continue) return MR_SUCCESS; diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index d6b7dba4426..e786dc61e66 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -876,6 +876,7 @@ static BOOL symt_fill_sym_info_from_symref(struct module_pair* pair, const struc DWORD tag; DWORD64 size; WCHAR *name; + DWORD data_kind, offset; if (!symt_get_info_from_symref(pair->effective, symref, TI_GET_SYMTAG, &tag)) return FALSE; @@ -911,7 +912,7 @@ static BOOL symt_fill_sym_info_from_symref(struct module_pair* pair, const struc char *buffer; char *tmp; - if (sym_info->MaxNameLen && (buffer = malloc(len))) + if (len && (buffer = malloc(len))) { WideCharToMultiByte(CP_ACP, 0, name, -1, buffer, len, NULL, NULL); if (sym_info->Tag == SymTagPublicSymbol && (dbghelp_options & SYMOPT_UNDNAME) && @@ -929,6 +930,41 @@ static BOOL symt_fill_sym_info_from_symref(struct module_pair* pair, const struc } else symbol_setname(sym_info, ""); + switch (sym_info->Tag) + { + case SymTagData: + if (symt_get_info_from_symref(pair->effective, symref, TI_GET_DATAKIND, &data_kind)) + switch (data_kind) + { + case DataIsGlobal: + case DataIsFileStatic: + case DataIsStaticLocal: + if (symt_get_info_from_symref(pair->effective, symref, TI_GET_ADDRESSOFFSET, &offset)) + sym_info->Flags |= SYMFLAG_TLSREL; + break; + case DataIsConstant: + if (symt_get_info_from_symref(pair->effective, symref, TI_GET_VALUE, &sym_info->Value)) + sym_info->Flags |= SYMFLAG_VALUEPRESENT; + break; + default: + FIXME("Unhandled kind (%lu) in sym data\n", data_kind); + break; + } + else WARN("Couldn't get data kind\n"); + break; + case SymTagUDT: + case SymTagEnum: + case SymTagFunctionType: + case SymTagPointerType: + case SymTagArrayType: + case SymTagBaseType: + case SymTagTypedef: + break; + default: + FIXME("%Ix => %lu %s %lu %I64x\n", + symref, sym_info->Tag, debugstr_a(sym_info->Name), sym_info->Size, sym_info->Address); + } + TRACE_(dbghelp_symt)("%Ix => %s %lu %I64x\n", symref, debugstr_a(sym_info->Name), sym_info->Size, sym_info->Address); return TRUE; @@ -1188,7 +1224,6 @@ symref_t symt_find_nearest(struct module *module, DWORD_PTR addr) if (result == MR_SUCCESS) { recursive--; - if (!symt_is_symref_ptr(symref)) FIXME("No support for this case yet\n"); return symref; } /* fall back in all the other cases */ @@ -1221,10 +1256,13 @@ static symref_t symt_find_symref_at(struct module* module, DWORD_PTR addr) return nearest; } +/* callers really expect a symt ptr from here, so fail when found + * symbol is a symref + */ struct symt_ht* symt_find_symbol_at(struct module* module, DWORD_PTR addr) { symref_t nearest = symt_find_symref_at(module, addr); - return (struct symt_ht*)SYMT_SYMREF_TO_PTR(nearest); + return (symt_is_symref_ptr(nearest)) ? (struct symt_ht*)SYMT_SYMREF_TO_PTR(nearest) : NULL; } static BOOL symt_enum_locals_helper(struct module_pair* pair, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10018