[DBGHELP]
[reactos.git] / reactos / dll / win32 / dbghelp / symbol.c
index b399b66..1da28dd 100644 (file)
 #include <limits.h>
 #include <sys/types.h>
 #include <assert.h>
-#ifdef HAVE_REGEX_H
-# include <regex.h>
-#endif
 
-#include "wine/debug.h"
 #include "dbghelp_private.h"
+
+#ifndef DBGHELP_STATIC_LIB
+#include "wine/debug.h"
 #include "winnls.h"
+#endif
 
 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
 
+static WCHAR    starW[] = {'*','\0'};
+
 static inline int cmp_addr(ULONG64 a1, ULONG64 a2)
 {
     if (a1 > a2) return 1;
@@ -51,38 +53,56 @@ static inline int cmp_addr(ULONG64 a1, ULONG64 a2)
 static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr)
 {
     ULONG64     ref;
-
-    symt_get_info(module, &module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
+    symt_get_address(&module->addr_sorttab[idx]->symt, &ref);
     return cmp_addr(ref, addr);
 }
 
-struct module*  symt_cmp_addr_module = NULL;
-
 int symt_cmp_addr(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;
 
-    symt_get_info(symt_cmp_addr_module, sym1, TI_GET_ADDRESS, &a1);
-    symt_get_info(symt_cmp_addr_module, sym2, TI_GET_ADDRESS, &a2);
+    symt_get_address(sym1, &a1);
+    symt_get_address(sym2, &a2);
     return cmp_addr(a1, a2);
 }
 
 DWORD             symt_ptr2index(struct module* module, const struct symt* sym)
 {
-#ifdef _WIN64
+#ifdef __x86_64__
     const struct symt** c;
-    int                 len = vector_length(&module->vsymt), i;
-
-    /* FIXME: this is inefficient */
-    for (i = 0; i < len; i++)
-    {
-        if (*(struct symt**)vector_at(&module->vsymt, i) == sym)
-            return i + 1;
+    int len = vector_length(&module->vsymt);
+    struct hash_table_iter hti;
+    void *ptr;
+    struct symt_idx_to_ptr *idx_to_ptr;
+    /* place enough storage on the stack to represent a pointer in %p form */
+    char ptrbuf[3 + (sizeof(void *) * 2)];
+
+    /* make a string representation of the pointer to use as a hash key */
+    sprintf(ptrbuf, "%p", sym);
+    hash_table_iter_init(&module->ht_symaddr, &hti, ptrbuf);
+
+    /* try to find the pointer in our ht */
+    while ((ptr = hash_table_iter_up(&hti))) {
+        idx_to_ptr = GET_ENTRY(ptr, struct symt_idx_to_ptr, hash_elt);
+        if (idx_to_ptr->sym == sym)
+            return idx_to_ptr->idx;
     }
+
     /* not found */
+    /* add the symbol to our symbol vector */
     c = vector_add(&module->vsymt, &module->pool);
+
+    /* add an idx to ptr mapping so we can find it again by address */
+    if ((idx_to_ptr = pool_alloc(&module->pool, sizeof(*idx_to_ptr)))) 
+    {
+        idx_to_ptr->hash_elt.name = pool_strdup(&module->pool, ptrbuf);
+        idx_to_ptr->sym = sym;
+        idx_to_ptr->idx = len + 1;
+        hash_table_add(&module->ht_symaddr, &idx_to_ptr->hash_elt);
+    }
+
     if (c) *c = sym;
     return len + 1;
 #else
@@ -92,7 +112,7 @@ DWORD             symt_ptr2index(struct module* module, const struct symt* sym)
 
 struct symt*      symt_index2ptr(struct module* module, DWORD id)
 {
-#ifdef _WIN64
+#ifdef __x86_64__
     if (!id-- || id >= vector_length(&module->vsymt)) return NULL;
     return *(struct symt**)vector_at(&module->vsymt, id);
 #else
@@ -131,7 +151,7 @@ static void symt_add_module_ht(struct module* module, struct symt_ht* ht)
     /* Don't store in sorttab a symbol without address, they are of
      * no use here (e.g. constant values)
      */
-    if (symt_get_info(module, &ht->symt, TI_GET_ADDRESS, &addr) &&
+    if (symt_get_address(&ht->symt, &addr) &&
         symt_grow_sorttab(module, module->num_symbols + 1))
     {
         module->addr_sorttab[module->num_symbols++] = ht;
@@ -139,151 +159,54 @@ static void symt_add_module_ht(struct module* module, struct symt_ht* ht)
     }
 }
 
-#ifdef HAVE_REGEX_H
-
-/* transforms a dbghelp's regular expression into a POSIX one
- * Here are the valid dbghelp reg ex characters:
- *      *       0 or more characters
- *      ?       a single character
- *      []      list
- *      #       0 or more of preceding char
- *      +       1 or more of preceding char
- *      escapes \ on #, ?, [, ], *, +. don't work on -
- */
-static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
+static WCHAR* file_regex(const char* srcfile)
 {
-    char *mask, *p;
-    BOOL        in_escape = FALSE;
-    unsigned    flags = REG_NOSUB;
-
-    if (numchar == -1) numchar = strlen( str );
-
-    p = mask = HeapAlloc( GetProcessHeap(), 0, 2 * numchar + 3 );
-    *p++ = '^';
+    WCHAR* mask;
+    WCHAR* p;
 
-    while (*str && numchar--)
+    if (!srcfile || !*srcfile)
     {
-        /* FIXME: this shouldn't be valid on '-' */
-        if (in_escape)
-        {
-            *p++ = '\\';
-            *p++ = *str;
-            in_escape = FALSE;
-        }
-        else switch (*str)
-        {
-        case '\\': in_escape = TRUE; break;
-        case '*':  *p++ = '.'; *p++ = '*'; break;
-        case '?':  *p++ = '.'; break;
-        case '#':  *p++ = '*'; break;
-        /* escape some valid characters in dbghelp reg exp:s */
-        case '$':  *p++ = '\\'; *p++ = '$'; break;
-        /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */
-        default:   *p++ = *str; break;
-        }
-        str++;
+        if (!(p = mask = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(WCHAR)))) return NULL;
+        *p++ = '?';
+        *p++ = '#';
     }
-    if (in_escape)
+    else
     {
-        *p++ = '\\';
-        *p++ = '\\';
-    }
-    *p++ = '$';
-    *p = 0;
-    if (_case) flags |= REG_ICASE;
-    if (regcomp(re, mask, flags)) FIXME("Couldn't compile %s\n", mask);
-    HeapFree(GetProcessHeap(), 0, mask);
-}
-
-static BOOL compile_file_regex(regex_t* re, const char* srcfile)
-{
-    char *mask, *p;
-    BOOL ret;
+        DWORD  sz = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
+        WCHAR* srcfileW;
 
-    if (!srcfile || !*srcfile) return regcomp(re, ".*", REG_NOSUB);
+        /* FIXME: we use here the largest conversion for every char... could be optimized */
+        p = mask = HeapAlloc(GetProcessHeap(), 0, (5 * strlen(srcfile) + 1 + sz) * sizeof(WCHAR));
+        if (!mask) return NULL;
+        srcfileW = mask + 5 * strlen(srcfile) + 1;
+        MultiByteToWideChar(CP_ACP, 0, srcfile, -1, srcfileW, sz);
 
-    p = mask = HeapAlloc(GetProcessHeap(), 0, 5 * strlen(srcfile) + 4);
-    *p++ = '^';
-    while (*srcfile)
-    {
-        switch (*srcfile)
+        while (*srcfileW)
         {
-        case '\\':
-        case '/':
-            *p++ = '[';
-            *p++ = '\\';
-            *p++ = '\\';
-            *p++ = '/';
-            *p++ = ']';
-            break;
-        case '.':
-            *p++ = '\\';
-            *p++ = '.';
-            break;
-        default:
-            *p++ = *srcfile;
-            break;
+            switch (*srcfileW)
+            {
+            case '\\':
+            case '/':
+                *p++ = '[';
+                *p++ = '\\';
+                *p++ = '\\';
+                *p++ = '/';
+                *p++ = ']';
+                break;
+            case '.':
+                *p++ = '?';
+                break;
+            default:
+                *p++ = *srcfileW;
+                break;
+            }
+            srcfileW++;
         }
-        srcfile++;
     }
-    *p++ = '$';
     *p = 0;
-    ret = !regcomp(re, mask, REG_NOSUB);
-    HeapFree(GetProcessHeap(), 0, mask);
-    if (!ret)
-    {
-        FIXME("Couldn't compile %s\n", mask);
-        SetLastError(ERROR_INVALID_PARAMETER);
-    }
-    return ret;
-}
-
-static int match_regexp( const regex_t *re, const char *str )
-{
-    return !regexec( re, str, 0, NULL, 0 );
-}
-
-#else /* HAVE_REGEX_H */
-
-/* if we don't have regexp support, fall back to a simple string comparison */
-
-typedef struct
-{
-    char *str;
-    BOOL  icase;
-} regex_t;
-
-static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
-{
-    if (numchar == -1) numchar = strlen( str );
-
-    re->str = HeapAlloc( GetProcessHeap(), 0, numchar + 1 );
-    memcpy( re->str, str, numchar );
-    re->str[numchar] = 0;
-    re->icase = _case;
-}
-
-static BOOL compile_file_regex(regex_t* re, const char* srcfile)
-{
-    if (!srcfile || !*srcfile) re->str = NULL;
-    else compile_regex( srcfile, -1, re, FALSE );
-    return TRUE;
-}
-
-static int match_regexp( const regex_t *re, const char *str )
-{
-    if (!re->str) return 1;
-    if (re->icase) return !lstrcmpiA( re->str, str );
-    return !strcmp( re->str, str );
+    return mask;
 }
 
-static void regfree( regex_t *re )
-{
-    HeapFree( GetProcessHeap(), 0, re->str );
-}
-
-#endif /* HAVE_REGEX_H */
-
 struct symt_compiland* symt_new_compiland(struct module* module, 
                                           unsigned long address, unsigned src_idx)
 {
@@ -334,15 +257,15 @@ struct symt_public* symt_new_public(struct module* module,
 struct symt_data* symt_new_global_variable(struct module* module, 
                                            struct symt_compiland* compiland, 
                                            const char* name, unsigned is_static,
-                                           unsigned long addr, unsigned long size,
+                                           struct location loc, unsigned long size,
                                            struct symt* type)
 {
     struct symt_data*   sym;
     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 %d@%lx %p\n",
+                         debugstr_w(module->module.ModuleName), name, loc.kind, loc.offset, type);
     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
     {
         sym->symt.tag      = SymTagData;
@@ -350,7 +273,7 @@ struct symt_data* symt_new_global_variable(struct module* module,
         sym->kind          = is_static ? DataIsFileStatic : DataIsGlobal;
         sym->container     = compiland ? &compiland->symt : NULL;
         sym->type          = type;
-        sym->u.var.offset  = addr;
+        sym->u.var         = loc;
         if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz))
         {
             if (tsz != size)
@@ -689,6 +612,7 @@ static void symt_fill_sym_info(struct module_pair* pair,
                 sym_info->Flags |= SYMFLAG_PARAMETER;
                 /* fall through */
             case DataIsLocal:
+                sym_info->Flags |= SYMFLAG_LOCAL;
                 {
                     struct location loc = data->u.var;
 
@@ -711,7 +635,6 @@ static void symt_fill_sym_info(struct module_pair* pair,
                     {
                     case loc_error:
                         /* for now we report error cases as a negative register number */
-                        sym_info->Flags |= SYMFLAG_LOCAL;
                         /* fall through */
                     case loc_register:
                         sym_info->Flags |= SYMFLAG_REGISTER;
@@ -719,9 +642,10 @@ static void symt_fill_sym_info(struct module_pair* pair,
                         sym_info->Address = 0;
                         break;
                     case loc_regrel:
-                        sym_info->Flags |= SYMFLAG_LOCAL | SYMFLAG_REGREL;
-                        /* FIXME: it's i386 dependent !!! */
-                        sym_info->Register = loc.reg ? loc.reg : CV_REG_EBP;
+                        sym_info->Flags |= SYMFLAG_REGREL;
+                        sym_info->Register = loc.reg;
+                        if (loc.reg == CV_REG_NONE || (int)loc.reg < 0 /* error */)
+                            FIXME("suspicious register value %x\n", loc.reg);
                         sym_info->Address = loc.offset;
                         break;
                     case loc_absolute:
@@ -736,8 +660,19 @@ static void symt_fill_sym_info(struct module_pair* pair,
                 break;
             case DataIsGlobal:
             case DataIsFileStatic:
-                symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
-                sym_info->Register = 0;
+                switch (data->u.var.kind)
+                {
+                case loc_tlsrel:
+                    sym_info->Flags |= SYMFLAG_TLSREL;
+                    /* fall through */
+                case loc_absolute:
+                    symt_get_address(sym, &sym_info->Address);
+                    sym_info->Register = 0;
+                    break;
+                default:
+                    FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind);
+                    assert(0);
+                }
                 break;
             case DataIsConstant:
                 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
@@ -764,18 +699,18 @@ static void symt_fill_sym_info(struct module_pair* pair,
         break;
     case SymTagPublicSymbol:
         sym_info->Flags |= SYMFLAG_EXPORT;
-        symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
+        symt_get_address(sym, &sym_info->Address);
         break;
     case SymTagFunction:
         sym_info->Flags |= SYMFLAG_FUNCTION;
-        symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
+        symt_get_address(sym, &sym_info->Address);
         break;
     case SymTagThunk:
         sym_info->Flags |= SYMFLAG_THUNK;
-        symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
+        symt_get_address(sym, &sym_info->Address);
         break;
     default:
-        symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
+        symt_get_address(sym, &sym_info->Address);
         sym_info->Register = 0;
         break;
     }
@@ -819,24 +754,29 @@ static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
     return !se->cb(se->sym_info, se->sym_info->Size, se->user);
 }
 
-static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex,
+static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match,
                              const struct sym_enum* se)
 {
     void*                       ptr;
     struct symt_ht*             sym = NULL;
     struct hash_table_iter      hti;
+    WCHAR*                      nameW;
+    BOOL                        ret;
 
     hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
     while ((ptr = hash_table_iter_up(&hti)))
     {
         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
-        if (sym->hash_elt.name && match_regexp(regex, sym->hash_elt.name))
+        nameW = symt_get_nameW(&sym->symt);
+        ret = SymMatchStringW(nameW, match, FALSE);
+        HeapFree(GetProcessHeap(), 0, nameW);
+        if (ret)
         {
             se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
             se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
             if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
         }
-    }   
+    }
     return FALSE;
 }
 
@@ -846,7 +786,7 @@ static inline unsigned where_to_insert(struct module* module, unsigned high, con
     ULONG64     addr;
 
     if (!high) return 0;
-    symt_get_info(module, &elt->symt, TI_GET_ADDRESS, &addr);
+    symt_get_address(&elt->symt, &addr);
     do
     {
         switch (cmp_sorttab_addr(module, mid, addr))
@@ -867,35 +807,51 @@ static inline unsigned where_to_insert(struct module* module, unsigned high, con
  */
 static BOOL resort_symbols(struct module* module)
 {
+    int delta;
+
     if (!(module->module.NumSyms = module->num_symbols))
         return FALSE;
 
-    /* FIXME: what's the optimal value here ??? */
-    if (module->num_sorttab && module->num_symbols <= module->num_sorttab + 30)
+    /* we know that set from 0 up to num_sorttab is already sorted
+     * so sort the remaining (new) symbols, and merge the two sets
+     * (unless the first set is empty)
+     */
+    delta = module->num_symbols - module->num_sorttab;
+    qsort(&module->addr_sorttab[module->num_sorttab], delta, sizeof(struct symt_ht*), symt_cmp_addr);
+    if (module->num_sorttab)
     {
-        int     i, delta, ins_idx = module->num_sorttab, prev_ins_idx;
-        struct symt_ht* tmp[30];
+        int     i, ins_idx = module->num_sorttab, prev_ins_idx;
+        static struct symt_ht** tmp;
+        static unsigned num_tmp;
 
-        delta = module->num_symbols - module->num_sorttab;
+        if (num_tmp < delta)
+        {
+            static struct symt_ht** new;
+            if (tmp)
+                new = HeapReAlloc(GetProcessHeap(), 0, tmp, delta * sizeof(struct symt_ht*));
+            else
+                new = HeapAlloc(GetProcessHeap(), 0, delta * sizeof(struct symt_ht*));
+            if (!new)
+            {
+                module->num_sorttab = 0;
+                return resort_symbols(module);
+            }
+            tmp = new;
+            num_tmp = delta;
+        }
         memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*));
-        symt_cmp_addr_module = module;
         qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr);
 
         for (i = delta - 1; i >= 0; i--)
         {
             prev_ins_idx = ins_idx;
-            ins_idx = where_to_insert(module, prev_ins_idx = ins_idx, tmp[i]);
+            ins_idx = where_to_insert(module, ins_idx, tmp[i]);
             memmove(&module->addr_sorttab[ins_idx + i + 1],
                     &module->addr_sorttab[ins_idx],
                     (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*));
             module->addr_sorttab[ins_idx + i] = tmp[i];
         }
     }
-    else
-    {
-        symt_cmp_addr_module = module;
-        qsort(module->addr_sorttab, module->num_symbols, sizeof(struct symt_ht*), symt_cmp_addr);
-    }
     module->num_sorttab = module->num_symbols;
     return module->sortlist_valid = TRUE;
 }
@@ -929,11 +885,11 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
     low = 0;
     high = module->num_sorttab;
 
-    symt_get_info(module, &module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr);
+    symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr);
     if (addr < ref_addr) return NULL;
     if (high)
     {
-        symt_get_info(module, &module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr);
+        symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr);
         symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size);
         if (addr >= ref_addr + ref_size) return NULL;
     }
@@ -954,8 +910,8 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
      * might also have the same address, but would get better information
      */
     if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
-    {   
-        symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr);
+    {
+        symt_get_address(&module->addr_sorttab[low]->symt, &ref_addr);
         if (low > 0 &&
             module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol &&
             !cmp_sorttab_addr(module, low - 1, ref_addr))
@@ -966,7 +922,7 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
             low++;
     }
     /* finally check that we fit into the found symbol */
-    symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr);
+    symt_get_address(&module->addr_sorttab[low]->symt, &ref_addr);
     if (addr < ref_addr) return NULL;
     symt_get_length(module, &module->addr_sorttab[low]->symt, &ref_size);
     if (addr >= ref_addr + ref_size) return NULL;
@@ -975,12 +931,14 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
 }
 
 static BOOL symt_enum_locals_helper(struct module_pair* pair,
-                                    regex_t* preg, const struct sym_enum* se,
+                                    const WCHAR* match, const struct sym_enum* se,
                                     struct symt_function* func, const struct vector* v)
 {
     struct symt*        lsym = NULL;
     DWORD               pc = pair->pcs->ctx_frame.InstructionOffset;
     unsigned int        i;
+    WCHAR*              nameW;
+    BOOL                ret;
 
     for (i=0; i<vector_length(v); i++)
     {
@@ -992,12 +950,16 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair,
                 struct symt_block*  block = (struct symt_block*)lsym;
                 if (pc < block->address || block->address + block->size <= pc)
                     continue;
-                if (!symt_enum_locals_helper(pair, preg, se, func, &block->vchildren))
+                if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren))
                     return FALSE;
             }
             break;
         case SymTagData:
-            if (match_regexp(preg, symt_get_name(lsym)))
+            nameW = symt_get_nameW(lsym);
+            ret = SymMatchStringW(nameW, match,
+                                  !(dbghelp_options & SYMOPT_CASE_INSENSITIVE));
+            HeapFree(GetProcessHeap(), 0, nameW);
+            if (ret)
             {
                 if (send_symbol(se, pair, func, lsym)) return FALSE;
             }
@@ -1015,7 +977,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair,
     return TRUE;
 }
 
-static BOOL symt_enum_locals(struct process* pcs, const char* mask, 
+static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask,
                              const struct sym_enum* se)
 {
     struct module_pair  pair;
@@ -1032,15 +994,8 @@ static BOOL symt_enum_locals(struct process* pcs, const char* mask,
 
     if (sym->symt.tag == SymTagFunction)
     {
-        BOOL            ret;
-        regex_t         preg;
-
-        compile_regex(mask ? mask : "*", -1, &preg,
-                      dbghelp_options & SYMOPT_CASE_INSENSITIVE);
-        ret = symt_enum_locals_helper(&pair, &preg, se, (struct symt_function*)sym,
-                                      &((struct symt_function*)sym)->vchildren);
-        regfree(&preg);
-        return ret;
+        return symt_enum_locals_helper(&pair, mask ? mask : starW, se, (struct symt_function*)sym,
+                                       &((struct symt_function*)sym)->vchildren);
     }
     return FALSE;
 }
@@ -1076,33 +1031,34 @@ void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
  *
  * Core routine for most of the enumeration of symbols
  */
-static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
+static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
                      const struct sym_enum* se)
 {
     struct module_pair  pair;
-    const char*         bang;
-    regex_t             mod_regex, sym_regex;
+    const WCHAR*        bang;
+    WCHAR*              mod;
 
     pair.pcs = process_find_by_handle(hProcess);
     if (!pair.pcs) return FALSE;
     if (BaseOfDll == 0)
     {
         /* do local variables ? */
-        if (!Mask || !(bang = strchr(Mask, '!')))
+        if (!Mask || !(bang = strchrW(Mask, '!')))
             return symt_enum_locals(pair.pcs, Mask, se);
 
         if (bang == Mask) return FALSE;
 
-        compile_regex(Mask, bang - Mask, &mod_regex, TRUE);
-        compile_regex(bang + 1, -1, &sym_regex, 
-                      dbghelp_options & SYMOPT_CASE_INSENSITIVE);
-        
+        mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR));
+        if (!mod) return FALSE;
+        memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR));
+        mod[bang - Mask] = 0;
+
         for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
         {
             if (pair.requested->type == DMT_PE && module_get_debug(&pair))
             {
-                if (match_regexp(&mod_regex, pair.requested->module_name) &&
-                    symt_enum_module(&pair, &sym_regex, se))
+                if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) &&
+                    symt_enum_module(&pair, bang + 1, se))
                     break;
             }
         }
@@ -1116,14 +1072,13 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
                     !module_get_containee(pair.pcs, pair.requested) &&
                     module_get_debug(&pair))
                 {
-                    if (match_regexp(&mod_regex, pair.requested->module_name) &&
-                        symt_enum_module(&pair, &sym_regex, se))
+                    if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) &&
+                        symt_enum_module(&pair, bang + 1, se))
                     break;
                 }
             }
         }
-        regfree(&mod_regex);
-        regfree(&sym_regex);
+        HeapFree(GetProcessHeap(), 0, mod);
         return TRUE;
     }
     pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
@@ -1131,20 +1086,33 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
         return FALSE;
 
     /* we always ignore module name from Mask when BaseOfDll is defined */
-    if (Mask && (bang = strchr(Mask, '!')))
+    if (Mask && (bang = strchrW(Mask, '!')))
     {
         if (bang == Mask) return FALSE;
         Mask = bang + 1;
     }
 
-    compile_regex(Mask ? Mask : "*", -1, &sym_regex, 
-                  dbghelp_options & SYMOPT_CASE_INSENSITIVE);
-    symt_enum_module(&pair, &sym_regex, se);
-    regfree(&sym_regex);
+    symt_enum_module(&pair, Mask ? Mask : starW, se);
 
     return TRUE;
 }
 
+static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
+                                    PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
+                                    PVOID UserContext)
+{
+    struct sym_enum     se;
+
+    se.cb = EnumSymbolsCallback;
+    se.user = UserContext;
+    se.index = 0;
+    se.tag = 0;
+    se.addr = 0;
+    se.sym_info = (PSYMBOL_INFO)se.buffer;
+
+    return sym_enum(hProcess, BaseOfDll, Mask, &se);
+}
+
 /******************************************************************
  *             SymEnumSymbols (DBGHELP.@)
  *
@@ -1160,20 +1128,23 @@ BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
                            PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
                            PVOID UserContext)
 {
-    struct sym_enum     se;
+    BOOL                ret;
+    PWSTR               maskW = NULL;
 
-    TRACE("(%p %s %s %p %p)\n", 
+    TRACE("(%p %s %s %p %p)\n",
           hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask),
           EnumSymbolsCallback, UserContext);
 
-    se.cb = EnumSymbolsCallback;
-    se.user = UserContext;
-    se.index = 0;
-    se.tag = 0;
-    se.addr = 0;
-    se.sym_info = (PSYMBOL_INFO)se.buffer;
-
-    return sym_enum(hProcess, BaseOfDll, Mask, &se);
+    if (Mask)
+    {
+        DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
+        if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+            return FALSE;
+        MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
+    }
+    ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext);
+    HeapFree(GetProcessHeap(), 0, maskW);
+    return ret;
 }
 
 struct sym_enumW
@@ -1203,24 +1174,12 @@ BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
                             PVOID UserContext)
 {
     struct sym_enumW    sew;
-    BOOL                ret = FALSE;
-    char*               maskA = NULL;
 
     sew.ctx = UserContext;
     sew.cb = EnumSymbolsCallback;
     sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
 
-    if (Mask)
-    {
-        unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
-        maskA = HeapAlloc(GetProcessHeap(), 0, len);
-        if (!maskA) return FALSE;
-        WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
-    }
-    ret = SymEnumSymbols(hProcess, BaseOfDll, maskA, sym_enumW, &sew);
-    HeapFree(GetProcessHeap(), 0, maskA);
-
-    return ret;
+    return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew);
 }
 
 struct sym_enumerate
@@ -1814,8 +1773,8 @@ BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecName
                                 UNDNAME_COMPLETE) != 0;
 }
 
-static void* und_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len); }
-static void  und_free (void* ptr)  { HeapFree(GetProcessHeap(), 0, ptr); }
+static void * CDECL und_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len); }
+static void   CDECL und_free (void* ptr)  { HeapFree(GetProcessHeap(), 0, ptr); }
 
 /***********************************************************************
  *             UnDecorateSymbolName (DBGHELP.@)
@@ -1824,7 +1783,7 @@ DWORD WINAPI UnDecorateSymbolName(PCSTR DecoratedName, PSTR UnDecoratedName,
                                   DWORD UndecoratedLength, DWORD Flags)
 {
     /* undocumented from msvcrt */
-    static char* (*p_undname)(char*, const char*, int, void* (*)(size_t), void (*)(void*), unsigned short);
+    static char* (CDECL *p_undname)(char*, const char*, int, void* (CDECL*)(size_t), void (CDECL*)(void*), unsigned short);
     static const WCHAR szMsvcrt[] = {'m','s','v','c','r','t','.','d','l','l',0};
 
     TRACE("(%s, %p, %d, 0x%08x)\n",
@@ -1844,37 +1803,186 @@ DWORD WINAPI UnDecorateSymbolName(PCSTR DecoratedName, PSTR UnDecoratedName,
     return strlen(UnDecoratedName);
 }
 
+#define WILDCHAR(x)      (-(x))
+
+static  int     re_fetch_char(const WCHAR** re)
+{
+    switch (**re)
+    {
+    case '\\': (*re)++; return *(*re)++;
+    case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
+    default: return *(*re)++;
+    }
+}
+
+static inline int  re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
+{
+    return _case ? ch1 - ch2 : toupperW(ch1) - toupperW(ch2);
+}
+
+static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
+{
+    int         ch1, prev = 0;
+    unsigned    state = 0;
+
+    switch (ch1 = re_fetch_char(&elt))
+    {
+    default:
+        return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
+    case WILDCHAR('?'): return *string ? ++string : NULL;
+    case WILDCHAR('*'): assert(0);
+    case WILDCHAR('['): break;
+    }
+
+    for (;;)
+    {
+        ch1 = re_fetch_char(&elt);
+        if (ch1 == WILDCHAR(']')) return NULL;
+        if (state == 1 && ch1 == '-') state = 2;
+        else
+        {
+            if (re_match_char(*string, ch1, _case) == 0) return ++string;
+            switch (state)
+            {
+            case 0:
+                state = 1;
+                prev = ch1;
+                break;
+            case 1:
+                state = 0;
+                break;
+            case 2:
+                if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
+                    re_match_char(*string, ch1, _case) <= 0)
+                    return ++string;
+                state = 0;
+                break;
+            }
+        }
+    }
+}
+
+/******************************************************************
+ *             re_match_multi
+ *
+ * match a substring of *pstring according to *pre regular expression
+ * pstring and pre are only updated in case of successful match
+ */
+static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
+{
+    const WCHAR* re_end = *pre;
+    const WCHAR* string_end = *pstring;
+    const WCHAR* re_beg;
+    const WCHAR* string_beg;
+    const WCHAR* next;
+    int          ch;
+
+    while (*re_end && *string_end)
+    {
+        string_beg = string_end;
+        re_beg = re_end;
+        switch (ch = re_fetch_char(&re_end))
+        {
+        case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
+        case WILDCHAR('*'):
+            /* transform '*' into '?#' */
+            {static const WCHAR qmW[] = {'?',0}; re_beg = qmW;}
+            goto closure;
+        case WILDCHAR('['):
+            do
+            {
+                if (!(ch = re_fetch_char(&re_end))) return FALSE;
+            } while (ch != WILDCHAR(']'));
+            /* fall through */
+        case WILDCHAR('?'):
+        default:
+            break;
+        }
+
+        switch (*re_end)
+        {
+        case '+':
+            if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
+            string_beg++;
+            /* fall through */
+        case '#':
+            re_end++;
+        closure:
+            while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
+            for ( ; string_end >= string_beg; string_end--)
+            {
+                if (re_match_multi(&string_end, &re_end, _case)) goto found;
+            }
+            return FALSE;
+        default:
+            if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
+            string_end = next;
+        }
+        re_beg = re_end;
+    }
+
+    if (*re_end || *string_end) return FALSE;
+
+found:
+    *pre = re_end;
+    *pstring = string_end;
+    return TRUE;
+}
+
 /******************************************************************
- *             SymMatchString (DBGHELP.@)
+ *             SymMatchStringA (DBGHELP.@)
  *
  */
-BOOL WINAPI SymMatchString(PCSTR string, PCSTR re, BOOL _case)
+BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
 {
-    regex_t     preg;
-    BOOL        ret;
+    WCHAR*      strW;
+    WCHAR*      reW;
+    BOOL        ret = FALSE;
+    DWORD       sz;
 
+    if (!string || !re)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
     TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
 
-    compile_regex(re, -1, &preg, _case);
-    ret = match_regexp(&preg, string);
-    regfree(&preg);
+    sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
+    if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+        MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
+    sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
+    if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+        MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
+
+    if (strW && reW)
+        ret = SymMatchStringW(strW, reW, _case);
+    HeapFree(GetProcessHeap(), 0, strW);
+    HeapFree(GetProcessHeap(), 0, reW);
     return ret;
 }
 
 /******************************************************************
- *             SymSearch (DBGHELP.@)
+ *             SymMatchStringW (DBGHELP.@)
+ *
  */
-BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
-                      DWORD SymTag, PCSTR Mask, DWORD64 Address,
-                      PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
-                      PVOID UserContext, DWORD Options)
+BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
 {
-    struct sym_enum     se;
+    TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
 
-    TRACE("(%p %s %u %u %s %s %p %p %x)\n",
-          hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask,
-          wine_dbgstr_longlong(Address), EnumSymbolsCallback,
-          UserContext, Options);
+    if (!string || !re)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    return re_match_multi(&string, &re, _case);
+}
+
+static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
+                               DWORD SymTag, PCWSTR Mask, DWORD64 Address,
+                               PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
+                               PVOID UserContext, DWORD Options)
+{
+    struct sym_enum     se;
 
     if (Options != SYMSEARCH_GLOBALSONLY)
     {
@@ -1893,6 +2001,36 @@ BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
     return sym_enum(hProcess, BaseOfDll, Mask, &se);
 }
 
+/******************************************************************
+ *             SymSearch (DBGHELP.@)
+ */
+BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
+                      DWORD SymTag, PCSTR Mask, DWORD64 Address,
+                      PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
+                      PVOID UserContext, DWORD Options)
+{
+    LPWSTR      maskW = NULL;
+    BOOLEAN     ret;
+
+    TRACE("(%p %s %u %u %s %s %p %p %x)\n",
+          hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask,
+          wine_dbgstr_longlong(Address), EnumSymbolsCallback,
+          UserContext, Options);
+
+    if (Mask)
+    {
+        DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
+
+        if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+            return FALSE;
+        MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
+    }
+    ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address,
+                      EnumSymbolsCallback, UserContext, Options);
+    HeapFree(GetProcessHeap(), 0, maskW);
+    return ret;
+}
+
 /******************************************************************
  *             SymSearchW (DBGHELP.@)
  */
@@ -1902,8 +2040,6 @@ BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
                        PVOID UserContext, DWORD Options)
 {
     struct sym_enumW    sew;
-    BOOL                ret = FALSE;
-    char*               maskA = NULL;
 
     TRACE("(%p %s %u %u %s %s %p %p %x)\n",
           hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_w(Mask),
@@ -1914,18 +2050,8 @@ BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
     sew.cb = EnumSymbolsCallback;
     sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
 
-    if (Mask)
-    {
-        unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
-        maskA = HeapAlloc(GetProcessHeap(), 0, len);
-        if (!maskA) return FALSE;
-        WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
-    }
-    ret = SymSearch(hProcess, BaseOfDll, Index, SymTag, maskA, Address,
-                    sym_enumW, &sew, Options);
-    HeapFree(GetProcessHeap(), 0, maskA);
-
-    return ret;
+    return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address,
+                       sym_enumW, &sew, Options);
 }
 
 /******************************************************************
@@ -1984,7 +2110,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
     struct module_pair          pair;
     struct hash_table_iter      hti;
     struct symt_ht*             sym;
-    regex_t                     re;
+    WCHAR*                      srcmask;
     struct line_info*           dli;
     void*                       ptr;
     SRCCODEINFO                 sci;
@@ -1998,7 +2124,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
     if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
     pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN);
     if (!module_get_debug(&pair)) return FALSE;
-    if (!compile_file_regex(&re, srcfile)) return FALSE;
+    if (!(srcmask = file_regex(srcfile))) return FALSE;
 
     sci.SizeOfStruct = sizeof(sci);
     sci.ModBase      = base;
@@ -2018,8 +2144,20 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
             if (dli->is_source_file)
             {
                 file = source_get(pair.effective, dli->u.source_file);
-                if (!match_regexp(&re, file)) file = "";
-                strcpy(sci.FileName, file);
+                if (!file) sci.FileName[0] = '\0';
+                else
+                {
+                    DWORD   sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
+                    WCHAR*  fileW;
+
+                    if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
+                        MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz);
+                    if (SymMatchStringW(fileW, srcmask, FALSE))
+                        strcpy(sci.FileName, file);
+                    else
+                        sci.FileName[0] = '\0';
+                    HeapFree(GetProcessHeap(), 0, fileW);
+                }
             }
             else if (sci.FileName[0])
             {
@@ -2031,7 +2169,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
             }
         }
     }
-    regfree(&re);
+    HeapFree(GetProcessHeap(), 0, srcmask);
     return TRUE;
 }
 
@@ -2058,3 +2196,27 @@ BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR Fil
                 dwLineNumber, plDisplacement, Line);
     return FALSE;
 }
+
+/******************************************************************
+ *             SymFromIndex (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol)
+{
+    FIXME("hProcess = %p, BaseOfDll = %s, index = %d, symbol = %p\n",
+          hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol);
+
+    return FALSE;
+}
+
+/******************************************************************
+ *             SymFromIndexW (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol)
+{
+    FIXME("hProcess = %p, BaseOfDll = %s, index = %d, symbol = %p\n",
+          hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol);
+
+    return FALSE;
+}