- some more fixes to elf module's symbol table handling (including
  static/global diff for variables)
- now re-synchronizing ELF list in all cases (no longer depending on
  RT_CONSISTENT state)
- now should be able to differentiate properly a native from a builtin
  module
- in symbol lookup, now using size of symbol (if known)
- SymGetTypeInfo now checks and uses BaseAddress
- in MSC-CV, really generate thunk objects

diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c
index c7f326e..e03eec7 100644
--- a/dlls/dbghelp/dbghelp.c
+++ b/dlls/dbghelp/dbghelp.c
@@ -35,6 +35,12 @@
  *      + we should store the underlying type for an enum in the symt_enum struct
  *  - most options (dbghelp_options) are not used (loading lines, decoration, 
  *    deferring reading of module symbols, public symbols...)
+ *  - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
+ *    we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
+ *    we could use hash if name isn't a RE, and fall back to a full search when we
+ *    get a full RE
+ *  - in most of the module enumeration for symbol lookup, we don't search in
+ *    the ELF modules (should we turn wine extented flag for ELF modules on ?)
  *  - (un)decoration is not handled (should make winedump's code a (.a) library
  *    and link it to winedump, and potentially to msvcrt and dbghelp (check best
  *    way not to duplicate code in msvcrt & dbghelp)
diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c
index 952c988..84efa05 100644
--- a/dlls/dbghelp/elf_module.c
+++ b/dlls/dbghelp/elf_module.c
@@ -253,8 +253,11 @@
         switch (sym->symt.tag)
         {
         case SymTagFunction:
-            if (((struct symt_function*)sym)->address != module->elf_info->elf_addr)
+            if (((struct symt_function*)sym)->address != module->elf_info->elf_addr &&
+                ((struct symt_function*)sym)->size)
+            {
                 break;
+            }
             symp = elf_lookup_symtab(module, symtab, sym->hash_elt.name, 
                                      ((struct symt_function*)sym)->container);
             if (symp)
@@ -274,8 +277,12 @@
                 symp = elf_lookup_symtab(module, symtab, sym->hash_elt.name, 
                                          ((struct symt_data*)sym)->container);
                 if (symp)
+                {
                     ((struct symt_data*)sym)->u.address = module->elf_info->elf_addr +
                                                           symp->st_value;
+                    ((struct symt_data*)sym)->kind = (ELF32_ST_BIND(symp->st_info) == STB_LOCAL) ?
+                        DataIsFileStatic : DataIsGlobal;
+                }
                 break;
             default:;
             }
@@ -285,6 +292,8 @@
             break;
         }
     }
+    /* since we may have changed some addresses & sizes, mark the module to be resorted */
+    module->sortlist_valid = FALSE;
 }
 
 /******************************************************************
@@ -301,6 +310,7 @@
     struct hash_table_iter      hti;
     struct symtab_elt*          ste;
     DWORD                       addr;
+    int                         idx;
 
     hash_table_iter_init(ht_symtab, &hti, NULL);
     while ((ste = hash_table_iter_up(&hti)))
@@ -330,25 +340,56 @@
             symt_new_thunk(module, compiland, ste->ht_elt.name, thunks[j].ordinal,
                            addr, ste->symp->st_size);
         }
-        else if (symt_find_nearest(module, addr) == -1)
+        else
         {
-            /* creating public symbols for all the ELF symbols which haven't been
-             * used yet (ie we have no debug information on them)
-             * That's the case, for example, of the .spec.c files
-             */
-            if (ELF32_ST_TYPE(ste->symp->st_info) == STT_FUNC)
+            DWORD       ref_addr;
+
+            idx = symt_find_nearest(module, addr);
+            if (idx != -1)
+                symt_get_info(&module->addr_sorttab[idx]->symt, 
+                              TI_GET_ADDRESS, &ref_addr);
+            if (idx == -1 || addr != ref_addr)
             {
-                symt_new_function(module, compiland, ste->ht_elt.name,
-                                  addr, ste->symp->st_size, NULL);
+                /* creating public symbols for all the ELF symbols which haven't been
+                 * used yet (ie we have no debug information on them)
+                 * That's the case, for example, of the .spec.c files
+                 */
+                if (ELF32_ST_TYPE(ste->symp->st_info) == STT_FUNC)
+                {
+                    symt_new_function(module, compiland, ste->ht_elt.name,
+                                      addr, ste->symp->st_size, NULL);
+                }
+                else
+                {
+                    symt_new_global_variable(module, compiland, ste->ht_elt.name,
+                                             ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL,
+                                             addr, ste->symp->st_size, NULL);
+                }
+                /* FIXME: this is a hack !!!
+                 * we are adding new symbols, but as we're parsing a symbol table
+                 * (hopefully without duplicate symbols) we delay rebuilding the sorted
+                 * module table until we're done with the symbol table
+                 * Otherwise, as we intertwine symbols's add and lookup, performance
+                 * is rather bad
+                 */
+                module->sortlist_valid = TRUE;
             }
-            else
+            else if (strcmp(ste->ht_elt.name, module->addr_sorttab[idx]->hash_elt.name))
             {
-                symt_new_global_variable(module, compiland, ste->ht_elt.name,
-                                         FALSE /* FIXME */,
-                                         addr, ste->symp->st_size, NULL);
+                DWORD   xaddr = 0, xsize = 0;
+
+                symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &xaddr);
+                symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_LENGTH,  &xsize);
+
+                FIXME("Duplicate in %s: %s<%08lx-%08x> %s<%08lx-%08lx>\n", 
+                      module->module.ModuleName,
+                      ste->ht_elt.name, addr, ste->symp->st_size,
+                      module->addr_sorttab[idx]->hash_elt.name, xaddr, xsize);
             }
         }
     }
+    /* see comment above */
+    module->sortlist_valid = FALSE;
     return TRUE;
 }
 
@@ -522,7 +563,8 @@
         FIXME("Unsupported Dwarf2 information\n");
         sym_type = SymNone;
     }
-    if (strstr(module->module.ModuleName, "<elf>"))
+    if (strstr(module->module.ModuleName, "<elf>") ||
+        !strcmp(module->module.ModuleName, "<wine-loader>"))
     {
         /* add the thunks for native libraries */
         if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
@@ -788,8 +830,7 @@
     struct module*      module;
 
     if (!pcs->dbg_hdr_addr) return FALSE;
-    if (!read_mem(pcs->handle, pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)) ||
-        dbg_hdr.r_state != RT_CONSISTENT)
+    if (!read_mem(pcs->handle, pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
         return FALSE;
 
     for (module = pcs->lmodules; module; module = module->next)
@@ -889,8 +930,7 @@
     xname = strrchr(name, '/');
     if (!xname++) xname = name;
 
-    if (!read_mem(pcs->handle, pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)) ||
-        dbg_hdr.r_state != RT_CONSISTENT)
+    if (!read_mem(pcs->handle, pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
         return NULL;
 
     for (lm_addr = (void*)dbg_hdr.r_map; lm_addr; lm_addr = (void*)lm.l_next)
diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c
index 74f37db..f39d13e 100644
--- a/dlls/dbghelp/module.c
+++ b/dlls/dbghelp/module.c
@@ -48,10 +48,18 @@
     if (len > 4 && 
         (!strcasecmp(&out[len - 4], ".dll") || !strcasecmp(&out[len - 4], ".exe")))
         out[len - 4] = '\0';
-    else 
+    else
+    {
         if (len > 7 && 
             (!strcasecmp(&out[len - 7], ".dll.so") || !strcasecmp(&out[len - 7], ".exe.so")))
             strcpy(&out[len - 7], "<elf>");
+        else if (len > 7 &&
+                 out[len - 7] == '.' && !strcasecmp(&out[len - 3], ".so"))
+        {
+            if (len + 3 < size) strcpy(&out[len - 3], "<elf>");
+            else WARN("Buffer too short: %s\n", out);
+        }
+    }
     while ((*out = tolower(*out))) out++;
 }
 
@@ -227,6 +235,29 @@
     return module;
 }
 
+static BOOL module_is_elf_container_loaded(struct process* pcs, const char* ImageName, 
+                                           const char* ModuleName)
+{
+    char                buffer[MAX_PATH];
+    size_t              len;
+    struct module*      module;
+
+    if (!ModuleName)
+    {
+        module_fill_module(ImageName, buffer, sizeof(buffer));
+        ModuleName = buffer;
+    }
+    len = strlen(ModuleName);
+    for (module = pcs->lmodules; module; module = module->next)
+    {
+        if (!strncasecmp(module->module.ModuleName, ModuleName, len) &&
+            module->type == DMT_ELF &&
+            !strcmp(module->module.ModuleName + len, "<elf>"))
+            return TRUE;
+    }
+    return FALSE;
+}
+
 /***********************************************************************
  *			SymLoadModule (DBGHELP.@)
  */
@@ -243,19 +274,28 @@
     pcs = process_find_by_handle(hProcess);
     if (!pcs) return FALSE;
 
-    /* this is a Wine extension to the API */
-    if (!ImageName && !hFile)
+    /* force transparent ELF loading / unloading */
+    elf_synchronize_module_list(pcs);
+
+    /* this is a Wine extension to the API just to redo the synchronisation */
+    if (!ImageName && !hFile) return 0;
+
+    if (module_is_elf_container_loaded(pcs, ImageName, ModuleName))
     {
-        elf_synchronize_module_list(pcs);
+        /* force the loading of DLL as builtin */
+        if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
+            goto done;
+        WARN("Couldn't locate %s\n", ImageName);
         return 0;
     }
-
+    TRACE("Assuming %s as native DLL\n", ImageName);
     if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
     {
         unsigned        len = strlen(ImageName);
 
         if (!strcmp(ImageName + len - 3, ".so") &&
             (module = elf_load_module(pcs, ImageName))) goto done;
+        FIXME("should no longer happen\n");
         if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
             goto done;
         WARN("Couldn't locate %s\n", ImageName);
@@ -274,8 +314,6 @@
     }
     strncpy(module->module.ImageName, ImageName, sizeof(module->module.ImageName));
     module->module.ImageName[sizeof(module->module.ImageName) - 1] = '\0';
-    /* force transparent ELF loading / unloading */
-    if (module->type != DMT_ELF) elf_synchronize_module_list(pcs);
 
     return module->module.BaseOfImage;
 }
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c
index 91e79b5..eee9c5c 100644
--- a/dlls/dbghelp/msc.c
+++ b/dlls/dbghelp/msc.c
@@ -2240,11 +2240,10 @@
             memcpy(symname, sym->thunk.name, sym->thunk.namelen);
             symname[sym->thunk.namelen] = '\0';
             flt = codeview_get_linetab(linetab, sym->thunk.segment, sym->thunk.offset);
-            symt_new_function(msc_dbg->module, flt ? flt->compiland : NULL,
-                              symname, 
-                              codeview_get_address(msc_dbg, sym->thunk.segment, sym->thunk.offset),
-                              sym->thunk.thunk_len,
-                              codeview_get_type(sym->thunk.thtype, FALSE));
+            symt_new_thunk(msc_dbg->module, flt ? flt->compiland : NULL,
+                           symname, sym->thunk.thtype,
+                           codeview_get_address(msc_dbg, sym->thunk.segment, sym->thunk.offset),
+                           sym->thunk.thunk_len);
 	    break;
 
         /*
diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c
index 91d706d..091afb7 100644
--- a/dlls/dbghelp/pe_module.c
+++ b/dlls/dbghelp/pe_module.c
@@ -89,6 +89,7 @@
 
     WINE_TRACE("Processing DBG file %s\n", dbg_name);
 
+    tmp[0] = '\0';
     if ((hFile = FindDebugInfoFile((char*)dbg_name, pcs->search_path, tmp)) != NULL &&
         ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
         ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
@@ -114,10 +115,8 @@
                                            hdr->DebugDirectorySize / sizeof(*dbg));
     }
     else
-    {
-        WINE_ERR("-Unable to peruse .DBG file %s (%s)\n", 
-                 dbg_name, debugstr_a(tmp));
-    }
+        WINE_ERR("-Unable to peruse .DBG file %s (%s)\n", dbg_name, debugstr_a(tmp));
+
     if (dbg_mapping) UnmapViewOfFile((void*)dbg_mapping);
     if (hMap) CloseHandle(hMap);
     if (hFile != NULL) CloseHandle(hFile);
@@ -324,7 +323,8 @@
     else if (name) strcpy(loaded_name, name);
     else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
         FIXME("Trouble ahead (no module name passed in deferred mode)\n");
-    if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
+    if (!(module = module_find_by_name(pcs, loaded_name, DMT_PE)) &&
+        (hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
     {
         if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
         {
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c
index b43beab..322ef79 100644
--- a/dlls/dbghelp/symbol.c
+++ b/dlls/dbghelp/symbol.c
@@ -94,14 +94,15 @@
  *      +       1 or more of preceding char
  *      escapes \ on #, ?, [, ], *, +. don't work on -
  */
-static void compile_regex(const char* str, regex_t* re)
+static void compile_regex(const char* str, int numchar, regex_t* re)
 {
     char*       mask = HeapAlloc(GetProcessHeap(), 0, 1);
     unsigned    len = 1;
     BOOL        in_escape = FALSE;
 
     re_append(&mask, &len, '^');
-    while (*str)
+
+    while (*str && numchar--)
     {
         /* FIXME: this shouldn't be valid on '-' */
         if (in_escape)
@@ -130,7 +131,7 @@
     }
     re_append(&mask, &len, '$');
     mask[len - 1] = '\0';
-    regcomp(re, mask, REG_NOSUB);
+    if (regcomp(re, mask, REG_NOSUB)) FIXME("Couldn't compile %s\n", mask);
     HeapFree(GetProcessHeap(), 0, mask);
 }
 
@@ -421,7 +422,6 @@
 {
     struct symt_thunk*  sym;
 
-
     TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%lx-%lx\n", 
                          module->module.ModuleName, name, addr, addr + size - 1);
 
@@ -535,7 +535,7 @@
                          sym, sym_info->Name, sym_info->Size, sym_info->Address);
 }
 
-static BOOL symt_enum_module(struct module* module, const char* mask,
+static BOOL symt_enum_module(struct module* module, regex_t* regex,
                              PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
 {
     char                        buffer[sizeof(SYMBOL_INFO) + 256];
@@ -543,11 +543,7 @@
     void*                       ptr;
     struct symt_ht*             sym = NULL;
     struct hash_table_iter      hti;
-    regex_t                     preg;
 
-    assert(mask);
-    assert(mask[0] != '!');
-    compile_regex(mask, &preg);
     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
     while ((ptr = hash_table_iter_up(&hti)))
     {
@@ -559,7 +555,7 @@
             sym->symt.tag == SymTagPublicSymbol) continue;
 
         if (sym->hash_elt.name &&
-            regexec(&preg, sym->hash_elt.name, 0, NULL, 0) == 0)
+            regexec(regex, sym->hash_elt.name, 0, NULL, 0) == 0)
         {
             sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
             sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
@@ -567,7 +563,6 @@
             if (!cb(sym_info, sym_info->Size, user)) break;
         }
     }   
-    regfree(&preg);
     return sym ? FALSE : TRUE;
 }
 
@@ -615,7 +610,7 @@
 int symt_find_nearest(struct module* module, DWORD addr)
 {
     int         mid, high, low;
-    DWORD       ref;
+    DWORD       ref_addr, ref_size;
 
     if (!module->sortlist_valid && !resort_symbols(module)) return -1;
 
@@ -625,13 +620,14 @@
     low = 0;
     high = module->module.NumSyms;
 
-    symt_get_info(&module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref);
-    if (addr < ref) return -1;
+    symt_get_info(&module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr);
+    if (addr < ref_addr) return -1;
     if (high)
     {
-        symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref);
-        /* FIXME: use the size of symbol here if known */
-        if (addr > ref + 0x1000) return -1;
+        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 -1;
     }
     
     while (high > low + 1)
@@ -651,16 +647,22 @@
      */
     if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
     {   
-        symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref);
+        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))
+            !cmp_sorttab_addr(module, low - 1, ref_addr))
             low--;
         else if (low < module->module.NumSyms - 1 && 
                  module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol &&
-                 !cmp_sorttab_addr(module, low + 1, ref))
+                 !cmp_sorttab_addr(module, low + 1, ref_addr))
             low++;
     }
+    /* 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 -1;
+    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 -1;
 
     return low;
 }
@@ -733,7 +735,7 @@
         BOOL            ret;
         regex_t         preg;
 
-        compile_regex(mask ? mask : "*", &preg);
+        compile_regex(mask ? mask : "*", -1, &preg);
         ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback, 
                                       UserContext, sym_info, 
                                       &((struct symt_function*)sym)->vchildren);
@@ -748,6 +750,13 @@
 /******************************************************************
  *		SymEnumSymbols (DBGHELP.@)
  *
+ * cases BaseOfDll = 0
+ *      !foo fails always (despite what MSDN states)
+ *      RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
+ *      no ! in Mask, lookup in local Context
+ * cases BaseOfDll != 0
+ *      !foo fails always (despite what MSDN states)
+ *      RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
  */
 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask,
                            PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
@@ -755,6 +764,9 @@
 {
     struct process*     pcs = process_find_by_handle(hProcess);
     struct module*      module;
+    struct module*      dbg_module;
+    const char*         bang;
+    regex_t             mod_regex, sym_regex;
 
     TRACE("(%p %08lx %s %p %p)\n", 
           hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
@@ -763,41 +775,42 @@
 
     if (BaseOfDll == 0)
     {
-        if (Mask && Mask[0] == '!')
+        /* do local variables ? */
+        if (!Mask || !(bang = strchr(Mask, '!')))
+            return symt_enum_locals(pcs, Mask, EnumSymbolsCallback, UserContext);
+
+        if (bang == Mask) return FALSE;
+
+        compile_regex(Mask, bang - Mask, &mod_regex);
+        compile_regex(bang + 1, -1, &sym_regex);
+        
+        for (module = pcs->lmodules; module; module = module->next)
         {
-            if (!Mask[1])
+            if (module->type == DMT_PE && (dbg_module = module_get_debug(pcs, module)))
             {
-                /* FIXME: is this really what's intended ??? */
-                for (module = pcs->lmodules; module; module = module->next)
-                {
-                    if (module->module.SymType != SymNone &&
-                        !symt_enum_module(module, "*", EnumSymbolsCallback, UserContext))
-                        break;
-                }
-                return TRUE;
+                if (regexec(&mod_regex, module->module.ModuleName, 0, NULL, 0) == 0)
+                    symt_enum_module(dbg_module, &sym_regex, EnumSymbolsCallback, UserContext);
             }
-            module = module_find_by_name(pcs, &Mask[1], DMT_UNKNOWN);
-            Mask++;
         }
-        else return symt_enum_locals(pcs, Mask, EnumSymbolsCallback, UserContext);
+        regfree(&mod_regex);
+        regfree(&sym_regex);
+        return TRUE;
     }
-    else
+    module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
+    if (!(module = module_get_debug(pcs, module)))
+        return FALSE;
+
+    /* we always ignore module name from Mask when BaseOfDll is defined */
+    if (Mask && (bang = strchr(Mask, '!')))
     {
-        module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
-        if (Mask && Mask[0] == '!')
-        {
-            if (!Mask[1] ||
-                strcmp(&Mask[1], module->module.ModuleName))
-            {
-                FIXME("Strange call mode\n");
-                return FALSE;
-            }
-            Mask = "*";
-        }
-        else if (!Mask) Mask = "*";
+        if (bang == Mask) return FALSE;
+        Mask = bang + 1;
     }
-    if ((module = module_get_debug(pcs, module)))
-        symt_enum_module(module, Mask, EnumSymbolsCallback, UserContext);
+
+    compile_regex(Mask ? Mask : "*", -1, &sym_regex);
+    symt_enum_module(module, &sym_regex, EnumSymbolsCallback, UserContext);
+    regfree(&sym_regex);
+
     return TRUE;
 }
 
@@ -889,32 +902,45 @@
     struct hash_table_iter      hti;
     void*                       ptr;
     struct symt_ht*             sym = NULL;
+    const char*                 name;
 
     TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
     if (!pcs) return FALSE;
     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
-    for (module = pcs->lmodules; module; module = module->next)
+    name = strchr(Name, '!');
+    if (name)
     {
-        if (module->module.SymType != SymNone)
-        {
-            if (module->module.SymType == SymDeferred)
-            {
-                struct module*  xmodule = module_get_debug(pcs, module);
-                if (!xmodule) continue;
-                module = xmodule;
-            }
-            hash_table_iter_init(&module->ht_symbols, &hti, Name);
-            while ((ptr = hash_table_iter_up(&hti)))
-            {
-                sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
+        char    tmp[128];
+        assert(name - Name < sizeof(tmp));
+        memcpy(tmp, Name, name - Name);
+        tmp[name - Name] = '\0';
+        module = module_find_by_name(pcs, tmp, DMT_UNKNOWN);
+        if (!module) return FALSE;
+        Name = (char*)(name + 1);
+    }
+    else module = pcs->lmodules;
 
-                if (!strcmp(sym->hash_elt.name, Name))
-                {
-                    symt_fill_sym_info(module, &sym->symt, Symbol);
-                    return TRUE;
-                }
+    /* FIXME: Name could be made out of a regular expression */
+    while (module)
+    {
+        if (module->module.SymType == SymNone) continue;
+        if (module->module.SymType == SymDeferred)
+        {
+            struct module*      xmodule = module_get_debug(pcs, module);
+            if (!xmodule || xmodule != module) continue;
+        }
+        hash_table_iter_init(&module->ht_symbols, &hti, Name);
+        while ((ptr = hash_table_iter_up(&hti)))
+        {
+            sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
+
+            if (!strcmp(sym->hash_elt.name, Name))
+            {
+                symt_fill_sym_info(module, &sym->symt, Symbol);
+                return TRUE;
             }
         }
+        module = (name) ? NULL : module->next;
     }
     return FALSE;
 }
diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c
index 2be65c3..ee81af7 100644
--- a/dlls/dbghelp/type.c
+++ b/dlls/dbghelp/type.c
@@ -361,8 +361,7 @@
     TRACE("(%p %08lx %p %p)\n",
           hProcess, BaseOfDll, EnumSymbolsCallback, UserContext);
 
-    pcs = process_find_by_handle(hProcess);
-    if (!pcs) return FALSE;
+    if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
     if (!(module = module_get_debug(pcs, module))) return FALSE;
 
@@ -730,13 +729,16 @@
                            PVOID pInfo)
 {
     struct process*     pcs = process_find_by_handle(hProcess);
+    struct module*      module;
 
     if (!pcs) return FALSE;
-#if 0
-    struct module*      module;
+
     module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
-    if (!(module = module_get_debug(pcs, module))) return FALSE;
-#endif
+    if (!(module = module_get_debug(pcs, module)))
+    {
+        FIXME("Someone didn't properly set ModBase (0x%08lx)\n", ModBase);
+        return FALSE;
+    }
 
     return symt_get_info((struct symt*)TypeId, GetType, pInfo);
 }