#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;
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
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
/* 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;
}
}
-#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)
{
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;
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)
sym_info->Flags |= SYMFLAG_PARAMETER;
/* fall through */
case DataIsLocal:
+ sym_info->Flags |= SYMFLAG_LOCAL;
{
struct location loc = data->u.var;
{
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;
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:
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;
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;
}
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;
}
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))
*/
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;
}
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;
}
* 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))
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;
}
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++)
{
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;
}
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;
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;
}
*
* 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;
}
}
!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);
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.@)
*
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
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
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.@)
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",
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)
{
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.@)
*/
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),
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);
}
/******************************************************************
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;
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;
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])
{
}
}
}
- regfree(&re);
+ HeapFree(GetProcessHeap(), 0, srcmask);
return TRUE;
}
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;
+}