CVS: winex/dlls/dbghelp dbghelp_private.h, 1.2, 1.3 symbol.c, 1.3, 1.4

[email protected] 30 Aug 2007 14:18:03 -0000
Newsgroups gmane.comp.emulators.winex.cvs
Message-ID <[email protected]>
Subject: winex/dlls/dbghelp dbghelp_private.h,1.2,1.3 symbol.c,1.3,1.4Update of /var/lib/cvsd/cvsroot/winex/dlls/dbghelp
In directory agravaine:/tmp/cvs-serv19060/dlls/dbghelp

Modified Files:
	dbghelp_private.h symbol.c 
Log Message:

- changed the symbol lookup method so it works with optimized PDB files as well.
- removed a few of the more annoying TRACE messages


Index: dbghelp_private.h
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/dbghelp/dbghelp_private.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- dbghelp_private.h	30 Aug 2007 14:16:43 -0000	1.2
+++ dbghelp_private.h	30 Aug 2007 14:18:01 -0000	1.3
@@ -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 <stdarg.h>
 #include "windef.h"
 #include "winbase.h"
@@ -307,6 +310,25 @@
 
 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 @@
     /* 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_typedef*
                     symt_new_typedef(struct module* module, struct symt* ref, 
                                      const char* name);
+
+#endif
\ No newline at end of file

Index: symbol.c
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/dbghelp/symbol.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- symbol.c	30 Aug 2007 14:17:01 -0000	1.3
+++ symbol.c	30 Aug 2007 14:18:01 -0000	1.4
@@ -48,14 +48,84 @@
     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 <idx> and the reference address <addr>.  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, TI_GET_ADDRESS, &ref);
-    return cmp_addr(ref, addr);
+
+    symt_get_info(&module->addr_sorttab[idx].symt->symt, TI_GET_ADDRESS, &ref);
+
+    /* 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* 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), name, address, address + size, size);
     if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
         symt_find_nearest(module, address) != NULL)
         return NULL;
@@ -508,7 +578,7 @@
         size = 0;
     }
 
-    TRACE("the symbol has a size of %lld bytes (as DWORD = %ld)\n", size, (DWORD)size);
+    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;
@@ -611,13 +681,11 @@
     sym_info->Scope = 0; /* FIXME */
     sym_info->Tag = sym->tag;
 
-    TRACE("trying to retrieve the name for the symbol %p\n", sym);
     name = symt_get_name(sym);
     TRACE("found the name '%s'\n", name);
 
     if (sym_info->MaxNameLen)
     {
-        TRACE("attempting to undecorate the function name\n");
         if (sym->tag != SymTagPublicSymbol || !(dbghelp_options & SYMOPT_UNDNAME) ||
             (sym_info->NameLen = UnDecorateSymbolName(name, sym_info->Name, 
                                                       sym_info->MaxNameLen, UNDNAME_COMPLETE) == 0))
@@ -628,7 +696,7 @@
             else
                 ERR("could not undecorate the symbol '%s'\n", name);
 
-            sym_info->NameLen = min(strlen(name), sym_info->MaxNameLen - 1);
+            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';
         }
@@ -641,12 +709,8 @@
         TRACE("sym_info->MaxNameLen was not set!\n");
 
 
-    TRACE("%p => %s %lu %s\n",
-          sym, sym_info->Name, sym_info->Size,
-          wine_dbgstr_longlong(sym_info->Address));
-    /*TRACE_(dbghelp_symt)("%p => %s %lu %s\n",
-                         sym, sym_info->Name, sym_info->Size,
-                         wine_dbgstr_longlong(sym_info->Address));*/
+    TRACE_(dbghelp_symt)("found symbol %p {name = '%s', size = %lu, addr = 0x%08llx}\n",
+                            sym, sym_info->Name, sym_info->Size, sym_info->Address);
 }
 
 struct sym_enum
@@ -692,6 +756,80 @@
     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 */
+        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 */
+            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, but 
+                   we'll add a loud fixme here just to make sure */
+                FIXME("!!! symbol %d overlaps the end of its container symbol {addr = 0x%08llx - 0x%08llx (size = 0x%llx), addr2 = 0x%08llx - 0x%08llx (size2 = 0x%llx)}\n",
+                        j,
+                        addr, addr + size, size,
+                        addr2, addr2 + size2, size2);
+            }
+
+
+            /* 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 <i>'s address space */
+        i = k;
+    }
+
+
+    return TRUE;
+}
+
 /***********************************************************************
  *              resort_symbols
  *
@@ -710,12 +848,16 @@
     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)))
@@ -727,10 +869,107 @@
          * 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;
 }
 
@@ -738,7 +977,7 @@
 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)
     {
@@ -751,51 +990,111 @@
     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,
@@ -1145,7 +1444,7 @@
 
     symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol);
     *Displacement = Address - Symbol->Address;
-    TRACE("found the symbol '%s' near address 0x%016llx {displacement = 0x%016llx}\n", Symbol->Name, Address, *Displacement);
+    TRACE("found the symbol '%s' near address 0x%08llx {displacement = 0x%08llx}\n", Symbol->Name, Address, *Displacement);
     return TRUE;
 }