From 14d91ebd5974c8fc02f8b83d53e8eff0df7ad76d Mon Sep 17 00:00:00 2001 From: Jason Green Date: Thu, 17 Jan 2008 16:41:11 -0500 Subject: [PATCH] Rewrite much of the symbol lookup method to work with Optimized PDB files as well. Also, improves a number of TRACEs, and wraps strings in the debugstr() functions. From: Eric van Beurden (ericvb@transgaming.com) --- dlls/dbghelp/dbghelp_private.h | 26 ++- dlls/dbghelp/symbol.c | 648 ++++++++++++++++++++++++++++++++++------ 2 files changed, 584 insertions(+), 90 deletions(-) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 99b8b54..a37c437 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -21,6 +21,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifndef __DBGHELP_PRIVATE_H__ +# define __DBGHELP_PRIVATE_H__ + #include #include "windef.h" #include "winbase.h" @@ -307,6 +310,25 @@ enum module_type struct process; + +/* struct symbol_entry: this struct is used to store symbol entries in the address-sorted symbol table + for each module. Since symbol ranges can overlap in memory, we need to have a way of checking all + other symbols that enclose a particular address when searching through the list. This way, all we + need to do is find the first or closest symbol to the address in question using whatever search + method we'd like (the current binary search sounds good), then we'd perform a linear search on the + internal list to see which of the overlapping symbols matches the address best. */ +struct symbol_entry{ + /* pointer to the symbol for this entry */ + struct symt_ht *symt; + + /* pointer to the outtermost (or first) symbol that overlaps this one */ + struct symbol_entry *head; + + /* pointer to the next symbol that overlaps this one */ + struct symbol_entry *next; +}; + + struct module { IMAGEHLP_MODULEW64 module; @@ -326,7 +348,7 @@ struct module /* symbols & symbol tables */ int sortlist_valid; unsigned num_sorttab; /* number of symbols with addresses */ - struct symt_ht** addr_sorttab; + struct symbol_entry * addr_sorttab; struct hash_table ht_symbols; void (*loc_compute)(struct process* pcs, const struct module* module, @@ -607,3 +629,5 @@ extern struct symt_pointer* extern struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, const char* name); + +#endif diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index d76811b..66e843a 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -48,14 +48,84 @@ static inline int cmp_addr(ULONG64 a1, ULONG64 a2) return 0; } -static inline int cmp_sorttab_addr(const struct module* module, int idx, ULONG64 addr) +/************************************************************ + * cmp_sorttab_addr + * + * perform a 3-way compare between the address of the symbol + * at index and the reference address . Returns + * 1 if the symbol's address is above the reference address, + * -1 if the symbol's address space is below the reference + * address, and 0 if the reference address is within the + * symbol's address space. + */ +static int cmp_sorttab_addr(const struct module* module, int idx, ULONG64 addr) { ULONG64 ref; + DWORD64 size; + + + symt_get_info(&module->addr_sorttab[idx].symt->symt, TI_GET_ADDRESS, &ref); - symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref); - return cmp_addr(ref, addr); + /* the requested symbol is higher than the requested address => return 'above' */ + if (ref > addr) + return 1; + + + /* couldn't retrieve the symbol's size => set an arbitrary value as a replacement */ + if (!symt_get_info(&module->addr_sorttab[idx].symt->symt, TI_GET_LENGTH, &size) || size == 0){ + WARN("could not retrieve the size for the symbol at index %d\n", idx); + + size = 0x1000; + } + + /* the requested symbol's address space is below the requested address => return 'below' */ + if (ref + size < addr) + return -1; + + /* the requested address is within the symbol's address space => return 'match' */ + else /* if (addr >= ref && addr < ref + size) */ + return 0; } + +/************************************************************************** + * symt_cmp_addr_and_size + * + * compares two symbols based on their address and size. This will sort in + * ascending order by address, and descending order by size when addresses + * match. + */ +int symt_cmp_addr_and_size(const void* p1, const void* p2){ + const struct symt* sym1 = *(const struct symt* const *)p1; + const struct symt* sym2 = *(const struct symt* const *)p2; + ULONG64 a1, a2; + DWORD64 s1 = 0, s2 = 0; + + symt_get_info(sym1, TI_GET_ADDRESS, &a1); + symt_get_info(sym2, TI_GET_ADDRESS, &a2); + symt_get_info(sym1, TI_GET_LENGTH, &s1); + symt_get_info(sym2, TI_GET_LENGTH, &s2); + + + if (a1 > a2) + return 1; + + else if (a1 < a2) + return -1; + + else{ + if (s1 < s2) + return 1; + + else if (s1 > s2) + return -1; + + else + return 0; + } +} + + int symt_cmp_addr(const void* p1, const void* p2) { const struct symt* sym1 = *(const struct symt* const *)p1; @@ -151,8 +221,8 @@ struct symt_public* symt_new_public(struct module* module, struct symt_public* sym; struct symt** p; - TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%lx\n", - debugstr_w(module->module.ModuleName), name, address); + TRACE_(dbghelp_symt)("Adding public symbol %s:%s {addr = 0x%lx - 0x%lx (size = 0x%x)}\n", + debugstr_w(module->module.ModuleName), debugstr_a(name), address, address + size, size); if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) && symt_find_nearest(module, address) != NULL) return NULL; @@ -186,8 +256,8 @@ struct symt_data* symt_new_global_variable(struct module* module, struct symt** p; DWORD64 tsz; - TRACE_(dbghelp_symt)("Adding global symbol %s:%s @%lx %p\n", - debugstr_w(module->module.ModuleName), name, addr, type); + TRACE_(dbghelp_symt)("Adding global symbol %s:%s {addr = 0x%08lx - 0x%08lx (size = 0x%lx), type = %p}\n", + debugstr_w(module->module.ModuleName), debugstr_a(name), addr, addr + size, size, type); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagData; @@ -202,7 +272,7 @@ struct symt_data* symt_new_global_variable(struct module* module, { if (tsz != size) FIXME("Size mismatch for %s.%s between type (%s) and src (%lu)\n", - debugstr_w(module->module.ModuleName), name, + debugstr_w(module->module.ModuleName), debugstr_a(name), wine_dbgstr_longlong(tsz), size); } if (compiland) @@ -224,7 +294,7 @@ struct symt_function* symt_new_function(struct module* module, struct symt** p; TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n", - debugstr_w(module->module.ModuleName), name, addr, addr + size - 1); + debugstr_w(module->module.ModuleName), debugstr_a(name), addr, addr + size - 1); assert(!sig_type || sig_type->tag == SymTagFunctionType); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) @@ -257,8 +327,8 @@ void symt_add_func_line(struct module* module, struct symt_function* func, if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return; - TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", - func, func->hash_elt.name, offset, + TRACE_(dbghelp_symt)("(%p) %s:%lx %s:%u\n", + func, debugstr_a(func->hash_elt.name), offset, source_get(module, source_idx), line_num); assert(func->symt.tag == SymTagFunction); @@ -311,8 +381,8 @@ struct symt_data* symt_add_func_local(struct module* module, struct symt** p; TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n", - debugstr_w(module->module.ModuleName), func->hash_elt.name, - name, type); + debugstr_w(module->module.ModuleName), debugstr_a(func->hash_elt.name), + debugstr_a(name), type); assert(func); assert(func->symt.tag == SymTagFunction); @@ -426,7 +496,7 @@ struct symt_thunk* symt_new_thunk(struct module* module, struct symt_thunk* sym; TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%lx-%lx\n", - debugstr_w(module->module.ModuleName), name, addr, addr + size - 1); + debugstr_w(module->module.ModuleName), debugstr_a(name), addr, addr + size - 1); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { @@ -456,7 +526,7 @@ struct symt_data* symt_new_constant(struct module* module, struct symt_data* sym; TRACE_(dbghelp_symt)("Adding constant value %s:%s\n", - debugstr_w(module->module.ModuleName), name); + debugstr_w(module->module.ModuleName), debugstr_a(name)); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { @@ -486,14 +556,29 @@ static void symt_fill_sym_info(const struct module_pair* pair, const char* name; DWORD64 size; - if (!symt_get_info(sym, TI_GET_TYPE, &sym_info->TypeIndex)) + + TRACE("(pair = %p, func = %p, sym = %p (0x%08x), sym_info = %p)\n", + pair, func, sym, sym ? sym->tag : 0, sym_info); + + if (sym_info->SizeOfStruct != sizeof(SYMBOL_INFO)) + FIXME("the SYMBOL_INFO struct is the wrong size!\n"); + + if (!symt_get_info(sym, TI_GET_TYPE, &sym_info->TypeIndex)){ + WARN("couldn't retrieve the type of the symbol\n"); sym_info->TypeIndex = 0; + } + sym_info->info = (DWORD)sym; sym_info->Reserved[0] = sym_info->Reserved[1] = 0; + if (!symt_get_info(sym, TI_GET_LENGTH, &size) && (!sym_info->TypeIndex || - !symt_get_info((struct symt*)sym_info->TypeIndex, TI_GET_LENGTH, &size))) + !symt_get_info((struct symt*)sym_info->TypeIndex, TI_GET_LENGTH, &size))){ + ERR("couldn't get the size of the symbol\n"); size = 0; + } + + TRACE("the symbol has a size of %lld bytes\n", size); sym_info->Size = (DWORD)size; sym_info->ModBase = pair->requested->module.BaseOfImage; sym_info->Flags = 0; @@ -502,14 +587,17 @@ static void symt_fill_sym_info(const struct module_pair* pair, switch (sym->tag) { case SymTagData: + TRACE("the symbol is data\n"); { const struct symt_data* data = (const struct symt_data*)sym; switch (data->kind) { case DataIsParam: + TRACE("the symbol is a parameter\n"); sym_info->Flags |= SYMFLAG_PARAMETER; /* fall through */ case DataIsLocal: + TRACE("the symbol is a local variable\n"); { struct location loc = data->u.var; @@ -540,11 +628,14 @@ static void symt_fill_sym_info(const struct module_pair* pair, } break; case DataIsGlobal: + TRACE("the symbol is global\n"); case DataIsFileStatic: + TRACE("the symbol is static\n"); symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); sym_info->Register = 0; break; case DataIsConstant: + TRACE("the symbol is a constant\n"); sym_info->Flags |= SYMFLAG_VALUEPRESENT; switch (data->u.value.n1.n2.vt) { @@ -567,39 +658,59 @@ static void symt_fill_sym_info(const struct module_pair* pair, } break; case SymTagPublicSymbol: + TRACE("the symbol is a public symbol\n"); sym_info->Flags |= SYMFLAG_EXPORT; symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); break; case SymTagFunction: + TRACE("the symbol is a function\n"); sym_info->Flags |= SYMFLAG_FUNCTION; symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); break; case SymTagThunk: + TRACE("the symbol is a thunk\n"); sym_info->Flags |= SYMFLAG_THUNK; symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); break; default: + TRACE("the symbol's type is unknown\n"); symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address); sym_info->Register = 0; break; } sym_info->Scope = 0; /* FIXME */ sym_info->Tag = sym->tag; + name = symt_get_name(sym); + TRACE("found the name %s\n", debugstr_a(name)); + if (sym_info->MaxNameLen) { if (sym->tag != SymTagPublicSymbol || !(dbghelp_options & SYMOPT_UNDNAME) || (sym_info->NameLen = UnDecorateSymbolName(name, sym_info->Name, sym_info->MaxNameLen, UNDNAME_COMPLETE) == 0)) { - sym_info->NameLen = min(strlen(name), sym_info->MaxNameLen - 1); + if (sym->tag != SymTagPublicSymbol || !(dbghelp_options & SYMOPT_UNDNAME) || sym_info->NameLen == 0) + TRACE("not undecorating the symbol %s\n", debugstr_a(name)); + + else + ERR("could not undecorate the symbol %s\n", debugstr_a(name)); + + sym_info->NameLen = (ULONG)min(strlen(name), sym_info->MaxNameLen - 1); memcpy(sym_info->Name, name, sym_info->NameLen); sym_info->Name[sym_info->NameLen] = '\0'; } + + else + TRACE("undecorated the name to %s\n", debugstr_a(sym_info->Name)); } - TRACE_(dbghelp_symt)("%p => %s %u %s\n", - sym, sym_info->Name, sym_info->Size, - wine_dbgstr_longlong(sym_info->Address)); + + else + TRACE("sym_info->MaxNameLen was not set!\n"); + + + TRACE_(dbghelp_symt)("found symbol %p {name = %s, size = %u, addr = 0x%08llx}\n", + sym, debugstr_a(sym_info->Name), sym_info->Size, sym_info->Address); } struct sym_enum @@ -645,6 +756,84 @@ static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex, return FALSE; } + +/*********************************************************************** + * generateSymbolChains + * + * generates a set of sub-lists within the sorted symbol table. Each symbol + * has the potential to overlap other symbols' address spaces. This function + * will create a singly linked list for every symbol. The list will contain + * the set of symbols whose address space overlaps the current symbol. + */ +static BOOL generateSymbolChains(struct module *module){ + ULONG64 addr; + DWORD64 size; + ULONG64 addr2; + DWORD64 size2; + int i; + int j; + int k; + struct symbol_entry * next; + + + if (module->num_sorttab == 0 || module->addr_sorttab == NULL) + return FALSE; + + + for (i = 0; i < (signed)module->num_sorttab;){ + + /* retrieve the address and size of the symbol */ + size = 1; + symt_get_info(&module->addr_sorttab[i].symt->symt, TI_GET_ADDRESS, &addr); + symt_get_info(&module->addr_sorttab[i].symt->symt, TI_GET_LENGTH, &size); + + for (j = k = i + 1; j < (signed)module->num_sorttab; j++){ + + /* retrieve the address and size of the [potentially] overlapping symbol */ + size2 = 1; + symt_get_info(&module->addr_sorttab[j].symt->symt, TI_GET_ADDRESS, &addr2); + symt_get_info(&module->addr_sorttab[j].symt->symt, TI_GET_LENGTH, &size2); + + /* this symbol is out of the range of the symbol we're interested in => stop searching */ + if (addr2 >= addr + size) + break; + + /* this symbol is contained entirely within my address space => continue the search from here */ + if (addr2 + size2 <= addr + size) + k = j + 1; + + else{ + + /* this symbol's address starts within it's container symbol's address space, but it's address + space ends outside the container's address space. Theoretically this shouldn't happen so + we'll just stick a loud FIXME here. */ + FIXME("!!! symbol '%s'(#%d) overlaps the end of its container symbol '%s' (#%d) {addr = 0x%08llx - 0x%08llx (size = 0x%llx), addr2 = 0x%08llx - 0x%08llx (size2 = 0x%llx)}\n", + symt_get_name(&module->addr_sorttab[j].symt->symt), j, + symt_get_name(&module->addr_sorttab[i].symt->symt), i, + addr, addr + size, size, + addr2, addr2 + size2, size2); + FIXME("!!! these symbols may not be able to be found!\n"); + } + + + /* add the new symbol to the head of my list */ + next = module->addr_sorttab[i].next; + module->addr_sorttab[i].next = &module->addr_sorttab[j]; + module->addr_sorttab[j].next = next; + + + /* subordinate symbols will just point back to the containing symbol */ + module->addr_sorttab[j].head = &module->addr_sorttab[i]; + } + + /* all other symbols up to this point are fully contained in symbol 's address space */ + i = k; + } + + + return TRUE; +} + /*********************************************************************** * resort_symbols * @@ -663,12 +852,16 @@ static BOOL resort_symbols(struct module* module) if (module->addr_sorttab) module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab, - module->module.NumSyms * sizeof(struct symt_ht*)); + module->module.NumSyms * sizeof(struct symbol_entry)); else module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0, - module->module.NumSyms * sizeof(struct symt_ht*)); + module->module.NumSyms * sizeof(struct symbol_entry)); if (!module->addr_sorttab) return FALSE; +#ifdef TRACE_SYMBOL_LIST + TRACE("\n\n***** grabbing the symbols for sorting\n"); +#endif + module->num_sorttab = 0; hash_table_iter_init(&module->ht_symbols, &hti, NULL); while ((ptr = hash_table_iter_up(&hti))) @@ -680,10 +873,107 @@ static BOOL resort_symbols(struct module* module) * As the number of those symbols is very couple (a couple per module) * we don't bother for the unused spots at the end of addr_sorttab */ - if (symt_get_info(&sym->symt, TI_GET_ADDRESS, &addr)) - module->addr_sorttab[module->num_sorttab++] = sym; + if (symt_get_info(&sym->symt, TI_GET_ADDRESS, &addr)){ +#ifdef TRACE_SYMBOL_LIST + DWORD64 size = 0; + + + symt_get_info(&sym->symt, TI_GET_LENGTH, &size); + TRACE(" %03d) adding the symbol 0x%p {address = 0x%08llx - 0x%08llx, size = %lld bytes, name = '%s'}\n", + module->num_sorttab, sym, addr, addr + size, size, symt_get_name((const struct symt *)sym)); +#endif + + module->addr_sorttab[module->num_sorttab].symt = sym; + module->addr_sorttab[module->num_sorttab].head = NULL; + module->addr_sorttab[module->num_sorttab].next = NULL; + module->num_sorttab++; + } } - qsort(module->addr_sorttab, module->num_sorttab, sizeof(struct symt_ht*), symt_cmp_addr); + +#ifdef TRACE_SYMBOL_LIST + TRACE("\n\n***** sorting the table {count = %d}\n\n", module->num_sorttab); +#endif + + qsort(module->addr_sorttab, module->num_sorttab, sizeof(struct symbol_entry), symt_cmp_addr_and_size); + + generateSymbolChains(module); + + +#ifdef TRACE_SYMBOL_LIST + if (0){ + ULONG64 prevAddr = 0; + DWORD64 size; + DWORD64 prevSize = -1; + unsigned int i; + BOOL error; + struct symbol_entry * next; + struct symbol_entry * head; + + + addr = 0; + size = 1000000; + + TRACE("\n\n***** done sorting. List contents:\n"); + for (i = 0; i < module->num_sorttab; i++){ + prevAddr = addr; + prevSize = size; + + symt_get_info(&module->addr_sorttab[i].symt->symt, TI_GET_ADDRESS, &addr); + symt_get_info(&module->addr_sorttab[i].symt->symt, TI_GET_LENGTH, &size); + + /* make sure the symbols are in properly sorted order */ + error = prevAddr > addr || (prevAddr == addr && prevSize < size); + + TRACE("%s %03d) symbol 0x%p {address = 0x%08llx - 0x%08llx, size = %lld bytes, name = '%s'}\n", + error ? "!!!" : " ", + i, + module->addr_sorttab[i].symt, + addr, addr + size, + size, + symt_get_name((const struct symt *)module->addr_sorttab[i].symt)); + + + next = module->addr_sorttab[i].next; + head = module->addr_sorttab[i].head; + + if (next || head){ + + /* this is a container symbol => trace all the other symbols its address space contains */ + if (head == NULL){ + do{ + symt_get_info(&next->symt->symt, TI_GET_ADDRESS, &addr); + symt_get_info(&next->symt->symt, TI_GET_LENGTH, &size); + + TRACE(" %03d) symbol 0x%p {address = 0x%08llx - 0x%08llx, size = %lld bytes, name = '%s'}\n", + next - module->addr_sorttab, + next->symt, + addr, addr + size, + size, + symt_get_name((const struct symt *)next->symt)); + + + next = next->next; + } while (next); + } + + /* this symbol is contained in another symbol's address space => just trace the head node */ + else{ + symt_get_info(&head->symt->symt, TI_GET_ADDRESS, &addr); + symt_get_info(&head->symt->symt, TI_GET_LENGTH, &size); + + TRACE(" %03d) head symbol 0x%p {address = 0x%08llx - 0x%08llx, size = %lld bytes, name = '%s'}\n", + head - module->addr_sorttab, + head, + addr, addr + size, + size, + symt_get_name((const struct symt *)head->symt)); + } + } + } + + TRACE("\n\n"); + } +#endif return module->sortlist_valid = TRUE; } @@ -691,7 +981,7 @@ static BOOL resort_symbols(struct module* module) struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) { int mid, high, low; - ULONG64 ref_addr, ref_size; + if (!module->sortlist_valid || !module->addr_sorttab) { @@ -704,51 +994,111 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD addr) low = 0; high = module->num_sorttab; - symt_get_info(&module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr); - if (addr < ref_addr) return NULL; - if (high) - { - symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr); - if (!symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_LENGTH, &ref_size) || !ref_size) - ref_size = 0x1000; /* arbitrary value */ - if (addr >= ref_addr + ref_size) return NULL; + + /* the address is lower than the first symbol address in this module -> not in this module => fail */ + if (cmp_sorttab_addr(module, 0, addr) > 0) + return NULL; + + + /* check if the address is above this module's address space */ + if (high){ + + /* the address is above the last symbol's address space in this module -> not in this module => fail */ + if (cmp_sorttab_addr(module, high - 1, addr) < 0) + return NULL; } - - while (high > low + 1) - { - mid = (high + low) / 2; - if (cmp_sorttab_addr(module, mid, addr) < 0) - low = mid; - else - high = mid; + + + /* perform the binary search to find the first symbol that contains the requested address */ + while (high > low + 1){ + mid = (high + low) >> 1; + + /* a 3-way compare helps us nicely with early out conditions */ + switch (cmp_sorttab_addr(module, mid, addr)){ + case 1: + high = mid; + break; + + case -1: + low = mid; + break; + + case 0: /* found a containing symbol => early out */ + low = high = mid; + break; + } } - if (low != high && high != module->num_sorttab && - cmp_sorttab_addr(module, high, addr) <= 0) + + + if (low != high && high != module->num_sorttab && cmp_sorttab_addr(module, high, addr) <= 0) low = high; - /* If found symbol is a public symbol, check if there are any other entries that - * might also have the same address, but would get better information - */ - if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol) - { - symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); - if (low > 0 && - module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol && - !cmp_sorttab_addr(module, low - 1, ref_addr)) - low--; - else if (low < module->num_sorttab - 1 && - module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol && - !cmp_sorttab_addr(module, low + 1, ref_addr)) - low++; + + /* see if there's a non-public symbol in the chain that better fits the address */ + if (module->addr_sorttab[low].symt->symt.tag == SymTagPublicSymbol || cmp_sorttab_addr(module, low, addr)){ + struct symbol_entry * next; + struct symbol_entry * head; + BOOL found = FALSE; + + + /* start searching at the head container symbol */ + if (module->addr_sorttab[low].head) + head = module->addr_sorttab[low].head; + + /* start searching at the first sub symbol */ + else + head = &module->addr_sorttab[low]; + + + next = head; + + while (next){ + + /* found a non-public symbol that the address fits in */ + if (next->symt->symt.tag != SymTagPublicSymbol && cmp_sorttab_addr(module, (int)(next - module->addr_sorttab), addr) == 0){ + low = (int)(next - module->addr_sorttab); + found = TRUE; + break; + } + + next = next->next; + } + + + /* didn't find a non-public symbol that fit better => search for a public symbol */ + if (!found){ + next = head; + + while (next){ + + /* found a non-public symbol that the address fits in */ + if (cmp_sorttab_addr(module, (int)(next - module->addr_sorttab), addr) == 0){ + low = (int)(next - module->addr_sorttab); + found = TRUE; + break; + } + + next = next->next; + } + + + /* !! if nothing is found still, we could search for the nearest public symbol address. + However... since native doesn't even support this functionality, i'm leaving it + alone for now. The reason that native doesn't support this is probably because + the public symbol addresses are actually just entries in a jump table that go + to the real implementations of the functions. !! */ + + /* didn't find any symbols that contained the address => fail */ + if (!found) + return NULL; + } } - /* finally check that we fit into the found symbol */ - symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr); - if (addr < ref_addr) return NULL; - if (!symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_LENGTH, &ref_size) || !ref_size) - ref_size = 0x1000; /* arbitrary value */ - if (addr >= ref_addr + ref_size) return NULL; - - return module->addr_sorttab[low]; + + /* make sure our address is actually within the symbol that we found */ + if (cmp_sorttab_addr(module, low, addr) != 0) + return NULL; + + return module->addr_sorttab[low].symt; } static BOOL symt_enum_locals_helper(struct module_pair* pair, @@ -1037,14 +1387,82 @@ BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address, struct module_pair pair; struct symt_ht* sym; + + TRACE("(hProcess = %p, Address = 0x%016llx, Displacement = %p, Symbol = %p)\n", hProcess, Address, Displacement, Symbol); + /*TRACE("Symbol->MaxNameLen = %lu\n", Symbol->MaxNameLen); + TRACE("SYMBOL_INFO struct (size = %lu, reportedSize = %lu):\n" + " SizeOfStruct = %lu\n" + " TypeIndex = %lu\n" + " Reserved[0] = %lu\n" + " Reserved[1] = %lu\n" + " info = %lu\n" + " Size = %lu\n" + " ModBase = %lu\n" + " Flags = %lu\n" + " Value = %lu\n" + " Address = %lu\n" + " Register = %lu\n" + " Scope = %lu\n" + " Tag = %lu\n" + " NameLen = %lu\n" + " MaxNameLen = %lu\n" + " Name[1] = %lu\n", + sizeof(SYMBOL_INFO), Symbol->SizeOfStruct, + (intptr_t)&Symbol->SizeOfStruct - (intptr_t)Symbol, + (intptr_t)&Symbol->TypeIndex - (intptr_t)Symbol, + (intptr_t)&Symbol->Reserved[0] - (intptr_t)Symbol, + (intptr_t)&Symbol->Reserved[1] - (intptr_t)Symbol, + (intptr_t)&Symbol->info - (intptr_t)Symbol, + (intptr_t)&Symbol->Size - (intptr_t)Symbol, + (intptr_t)&Symbol->ModBase - (intptr_t)Symbol, + (intptr_t)&Symbol->Flags - (intptr_t)Symbol, + (intptr_t)&Symbol->Value - (intptr_t)Symbol, + (intptr_t)&Symbol->Address - (intptr_t)Symbol, + (intptr_t)&Symbol->Register - (intptr_t)Symbol, + (intptr_t)&Symbol->Scope - (intptr_t)Symbol, + (intptr_t)&Symbol->Tag - (intptr_t)Symbol, + (intptr_t)&Symbol->NameLen - (intptr_t)Symbol, + (intptr_t)&Symbol->MaxNameLen - (intptr_t)Symbol, + (intptr_t)&Symbol->Name[0] - (intptr_t)Symbol);*/ + + pair.pcs = process_find_by_handle(hProcess); - if (!pair.pcs) return FALSE; + if (!pair.pcs){ + ERR("the process %p has not been initialized\n", hProcess); + return FALSE; + } + + pair.requested = module_find_by_addr(pair.pcs, Address, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; - if ((sym = symt_find_nearest(pair.effective, Address)) == NULL) return FALSE; + if (!module_get_debug(&pair)){ + pair.effective = pair.requested; + + /* no module found => fail */ + if (pair.effective == NULL){ + TRACE("could not find the module that contains the address 0x%08llx\n", Address); + + return FALSE; + } + + /* no symbols found in the module => fail */ + if (pair.effective->ht_symbols.num_elts == 0){ + TRACE("the module at 0x%08llx (%s) does not have any symbols loaded for it\n", + pair.effective->module.BaseOfImage, debugstr_a(pair.effective->module_name)); + + return FALSE; + } + } + + + if ((sym = symt_find_nearest(pair.effective, Address)) == NULL){ + TRACE("could not find the nearest symbol to the address 0x%016llx\n", Address); + return FALSE; + } + symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol); *Displacement = Address - Symbol->Address; + TRACE("found the symbol %s near address 0x%08llx {displacement = 0x%08llx}\n", debugstr_a(Symbol->Name), Address, *Displacement); return TRUE; } @@ -1097,7 +1515,7 @@ BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address, Symbol->Size = si->Size; Symbol->Flags = si->Flags; len = min(Symbol->MaxNameLength, si->MaxNameLen); - lstrcpynA(Symbol->Name, si->Name, len); + lstrcpynA(Symbol->Name, si->Name, (int)len); return TRUE; } @@ -1165,7 +1583,7 @@ BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) struct module* module; const char* name; - TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol); + TRACE("(%p, %s, %p)\n", hProcess, debugstr_a(Name), Symbol); if (!pcs) return FALSE; if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; name = strchr(Name, '!'); @@ -1215,7 +1633,7 @@ BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symb Symbol->Size = si->Size; Symbol->Flags = si->Flags; len = min(Symbol->MaxNameLength, si->MaxNameLen); - lstrcpynA(Symbol->Name, si->Name, len); + lstrcpynA(Symbol->Name, si->Name, (int)len); return TRUE; } @@ -1291,19 +1709,52 @@ BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, struct module_pair pair; struct symt_ht* symt; - TRACE("%p %08x %p %p\n", hProcess, dwAddr, pdwDisplacement, Line); + TRACE("(hProcess = %p, dwAddr = %08x, pdwDisplacement = 0x%p, Line = 0x%p)\n", hProcess, dwAddr, pdwDisplacement, Line); + + if (Line->SizeOfStruct < sizeof(*Line)){ + WARN("the destination struct is too small {sizeOfStruct = %d, sizeof(*Line) = %u}\n", Line->SizeOfStruct, sizeof(*Line)); + + return FALSE; + } - if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; pair.pcs = process_find_by_handle(hProcess); - if (!pair.pcs) return FALSE; + if (!pair.pcs){ + WARN("could not find the process for %p\n", hProcess); + + return FALSE; + } + + pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); - if (!module_get_debug(&pair)) return FALSE; - if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; - if (symt->symt.tag != SymTagFunction) return FALSE; - if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, - dwAddr, Line)) return FALSE; + if (!module_get_debug(&pair)){ + WARN("this module does not have debug information\n"); + + return FALSE; + } + + + if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL){ + WARN("could not find the function for the address 0x%08x\n", dwAddr); + + return FALSE; + } + + + if (symt->symt.tag != SymTagFunction){ + WARN("the symbol that was found for 0x%08x is not a function\n", dwAddr); + + return FALSE; + } + + + if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, dwAddr, Line)){ + WARN("could not fill the line info for the function %s()\n", symt_get_name(&symt->symt)); + + return FALSE; + } + *pdwDisplacement = dwAddr - Line->Address; return TRUE; } @@ -1325,7 +1776,9 @@ static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32) * copy_line_W64_from_32 (internal) * */ -static void copy_line_W64_from_32(struct process* pcs, IMAGEHLP_LINEW64* l64, const IMAGEHLP_LINE* l32) +static void copy_line_W64_from_32(struct process* pcs, + IMAGEHLP_LINEW64* l64, + const IMAGEHLP_LINE* l32) { unsigned len; @@ -1359,11 +1812,28 @@ BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, { IMAGEHLP_LINE line32; - if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - if (!validate_addr64(dwAddr)) return FALSE; + + if (Line->SizeOfStruct < sizeof(*Line)) { + WARN("the destination struct is too small!\n"); + + return FALSE; + } + + + if (!validate_addr64(dwAddr)){ + WARN("passed a 64-bit address!\n"); + + return FALSE; + } + + line32.SizeOfStruct = sizeof(line32); - if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32)) + if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32)){ + WARN("could not get the line number info for the address 0x%08llx\n", dwAddr); + return FALSE; + } + copy_line_64_from_32(Line, &line32); return TRUE; } @@ -1524,7 +1994,7 @@ PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase) */ PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) { - WARN("(%p, %s): stub\n", hProcess, wine_dbgstr_longlong(AddrBase)); + WARN("(hProcess = %p, AddrBase = %s): stub\n", hProcess, wine_dbgstr_longlong(AddrBase)); return NULL; } @@ -1533,7 +2003,7 @@ PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) */ BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength) { - TRACE("(%p %s %u)\n", sym, UnDecName, UnDecNameLength); + TRACE("(%p %s %u)\n", sym, debugstr_a(UnDecName), UnDecNameLength); return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, UNDNAME_COMPLETE) != 0; } @@ -1577,7 +2047,7 @@ BOOL WINAPI SymMatchString(PCSTR string, PCSTR re, BOOL _case) regex_t preg; BOOL ret; - TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N'); + TRACE("%s %s %c\n", debugstr_a(string), debugstr_a(re), _case ? 'Y' : 'N'); compile_regex(re, -1, &preg, _case); ret = regexec(&preg, string, 0, NULL, 0) == 0; @@ -1596,7 +2066,7 @@ BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, struct sym_enum se; TRACE("(%p %s %u %u %s %s %p %p %x)\n", - hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask, + hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_a(Mask), wine_dbgstr_longlong(Address), EnumSymbolsCallback, UserContext, Options); -- 1.4.4.2