dbghelp: Live targets.
[wine] / dlls / dbghelp / symbol.c
1 /*
2  * File symbol.c - management of symbols (lexical tree)
3  *
4  * Copyright (C) 1993, Eric Youngdale.
5  *               2004, Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <assert.h>
33 #ifdef HAVE_REGEX_H
34 # include <regex.h>
35 #endif
36
37 #include "wine/debug.h"
38 #include "dbghelp_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
41 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
42
43 inline static int cmp_addr(ULONG64 a1, ULONG64 a2)
44 {
45     if (a1 > a2) return 1;
46     if (a1 < a2) return -1;
47     return 0;
48 }
49
50 inline static int cmp_sorttab_addr(const struct module* module, int idx, ULONG64 addr)
51 {
52     ULONG64     ref;
53
54     symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
55     return cmp_addr(ref, addr);
56 }
57
58 int symt_cmp_addr(const void* p1, const void* p2)
59 {
60     const struct symt*  sym1 = *(const struct symt* const *)p1;
61     const struct symt*  sym2 = *(const struct symt* const *)p2;
62     ULONG64     a1, a2;
63
64     symt_get_info(sym1, TI_GET_ADDRESS, &a1);
65     symt_get_info(sym2, TI_GET_ADDRESS, &a2);
66     return cmp_addr(a1, a2);
67 }
68
69 static inline void re_append(char** mask, unsigned* len, char ch)
70 {
71     *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len));
72     (*mask)[*len - 2] = ch;
73 }
74
75 /* transforms a dbghelp's regular expression into a POSIX one
76  * Here are the valid dbghelp reg ex characters:
77  *      *       0 or more characters
78  *      ?       a single character
79  *      []      list
80  *      #       0 or more of preceding char
81  *      +       1 or more of preceding char
82  *      escapes \ on #, ?, [, ], *, +. don't work on -
83  */
84 static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
85 {
86     char*       mask = HeapAlloc(GetProcessHeap(), 0, 1);
87     unsigned    len = 1;
88     BOOL        in_escape = FALSE;
89     unsigned    flags = REG_NOSUB;
90
91     re_append(&mask, &len, '^');
92
93     while (*str && numchar--)
94     {
95         /* FIXME: this shouldn't be valid on '-' */
96         if (in_escape)
97         {
98             re_append(&mask, &len, '\\');
99             re_append(&mask, &len, *str);
100             in_escape = FALSE;
101         }
102         else switch (*str)
103         {
104         case '\\': in_escape = TRUE; break;
105         case '*':  re_append(&mask, &len, '.'); re_append(&mask, &len, '*'); break;
106         case '?':  re_append(&mask, &len, '.'); break;
107         case '#':  re_append(&mask, &len, '*'); break;
108         /* escape some valid characters in dbghelp reg exp:s */
109         case '$':  re_append(&mask, &len, '\\'); re_append(&mask, &len, '$'); break;
110         /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */
111         default:   re_append(&mask, &len, *str); break;
112         }
113         str++;
114     }
115     if (in_escape)
116     {
117         re_append(&mask, &len, '\\');
118         re_append(&mask, &len, '\\');
119     }
120     re_append(&mask, &len, '$');
121     mask[len - 1] = '\0';
122     if (_case) flags |= REG_ICASE;
123     if (regcomp(re, mask, flags)) FIXME("Couldn't compile %s\n", mask);
124     HeapFree(GetProcessHeap(), 0, mask);
125 }
126
127 struct symt_compiland* symt_new_compiland(struct module* module, const char* name)
128 {
129     struct symt_compiland*    sym;
130
131     TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n", 
132                          module->module.ModuleName, name);
133     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
134     {
135         sym->symt.tag = SymTagCompiland;
136         sym->source   = source_new(module, name);
137         vector_init(&sym->vchildren, sizeof(struct symt*), 32);
138     }
139     return sym;
140 }
141
142 struct symt_public* symt_new_public(struct module* module, 
143                                     struct symt_compiland* compiland,
144                                     const char* name,
145                                     unsigned long address, unsigned size,
146                                     BOOL in_code, BOOL is_func)
147 {
148     struct symt_public* sym;
149     struct symt**       p;
150
151     TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%lx\n", 
152                          module->module.ModuleName, name, address);
153     if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) && 
154         symt_find_nearest(module, address) != -1)
155         return NULL;
156     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
157     {
158         sym->symt.tag      = SymTagPublicSymbol;
159         sym->hash_elt.name = pool_strdup(&module->pool, name);
160         hash_table_add(&module->ht_symbols, &sym->hash_elt);
161         module->sortlist_valid = FALSE;
162         sym->container     = compiland ? &compiland->symt : NULL;
163         sym->address       = address;
164         sym->size          = size;
165         sym->in_code       = in_code;
166         sym->is_function   = is_func;
167         if (compiland)
168         {
169             p = vector_add(&compiland->vchildren, &module->pool);
170             *p = &sym->symt;
171         }
172     }
173     return sym;
174 }
175
176 struct symt_data* symt_new_global_variable(struct module* module, 
177                                            struct symt_compiland* compiland, 
178                                            const char* name, unsigned is_static,
179                                            unsigned long addr, unsigned long size,
180                                            struct symt* type)
181 {
182     struct symt_data*   sym;
183     struct symt**       p;
184     DWORD64             tsz;
185
186     TRACE_(dbghelp_symt)("Adding global symbol %s:%s @%lx %p\n", 
187                          module->module.ModuleName, name, addr, type);
188     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
189     {
190         sym->symt.tag      = SymTagData;
191         sym->hash_elt.name = pool_strdup(&module->pool, name);
192         hash_table_add(&module->ht_symbols, &sym->hash_elt);
193         module->sortlist_valid = FALSE;
194         sym->kind          = is_static ? DataIsFileStatic : DataIsGlobal;
195         sym->container     = compiland ? &compiland->symt : NULL;
196         sym->type          = type;
197         sym->u.address     = addr;
198         if (type && size && symt_get_info(type, TI_GET_LENGTH, &tsz))
199         {
200             if (tsz != size)
201                 FIXME("Size mismatch for %s.%s between type (%s) and src (%lu)\n",
202                       module->module.ModuleName, name, 
203                       wine_dbgstr_longlong(tsz), size);
204         }
205         if (compiland)
206         {
207             p = vector_add(&compiland->vchildren, &module->pool);
208             *p = &sym->symt;
209         }
210     }
211     return sym;
212 }
213
214 struct symt_function* symt_new_function(struct module* module, 
215                                         struct symt_compiland* compiland, 
216                                         const char* name,
217                                         unsigned long addr, unsigned long size,
218                                         struct symt* sig_type)
219 {
220     struct symt_function*       sym;
221     struct symt**               p;
222
223     TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n", 
224                          module->module.ModuleName, name, addr, addr + size - 1);
225
226     assert(!sig_type || sig_type->tag == SymTagFunctionType);
227     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
228     {
229         sym->symt.tag  = SymTagFunction;
230         sym->hash_elt.name = pool_strdup(&module->pool, name);
231         hash_table_add(&module->ht_symbols, &sym->hash_elt);
232         module->sortlist_valid = FALSE;
233         sym->container = &compiland->symt;
234         sym->address   = addr;
235         sym->type      = sig_type;
236         sym->size      = size;
237         vector_init(&sym->vlines,  sizeof(struct line_info), 64);
238         vector_init(&sym->vchildren, sizeof(struct symt*), 8);
239         if (compiland)
240         {
241             p = vector_add(&compiland->vchildren, &module->pool);
242             *p = &sym->symt;
243         }
244     }
245     return sym;
246 }
247
248 void symt_add_func_line(struct module* module, struct symt_function* func,
249                         unsigned source_idx, int line_num, unsigned long offset)
250 {
251     struct line_info*   dli;
252     BOOL                last_matches = FALSE;
253
254     if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
255
256     TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", 
257                          func, func->hash_elt.name, offset, 
258                          source_get(module, source_idx), line_num);
259
260     assert(func->symt.tag == SymTagFunction);
261
262     dli = NULL;
263     while ((dli = vector_iter_down(&func->vlines, dli)))
264     {
265         if (dli->is_source_file)
266         {
267             last_matches = (source_idx == dli->u.source_file);
268             break;
269         }
270     }
271
272     if (!last_matches)
273     {
274         /* we shouldn't have line changes on first line of function */
275         dli = vector_add(&func->vlines, &module->pool);
276         dli->is_source_file = 1;
277         dli->is_first       = dli->is_last = 0;
278         dli->line_number    = 0;
279         dli->u.source_file  = source_idx;
280     }
281     dli = vector_add(&func->vlines, &module->pool);
282     dli->is_source_file = 0;
283     dli->is_first       = dli->is_last = 0;
284     dli->line_number    = line_num;
285     dli->u.pc_offset    = func->address + offset;
286 }
287
288 struct symt_data* symt_add_func_local(struct module* module, 
289                                       struct symt_function* func, 
290                                       int regno, int offset, 
291                                       struct symt_block* block, 
292                                       struct symt* type, const char* name)
293 {
294     struct symt_data*   locsym;
295     struct symt**       p;
296
297     assert(func);
298     assert(func->symt.tag == SymTagFunction);
299
300     TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n", 
301                          module->module.ModuleName, func->hash_elt.name, 
302                          name, type);
303     locsym = pool_alloc(&module->pool, sizeof(*locsym));
304     locsym->symt.tag      = SymTagData;
305     locsym->hash_elt.name = pool_strdup(&module->pool, name);
306     locsym->hash_elt.next = NULL;
307     locsym->kind          = (offset < 0) ? DataIsParam : DataIsLocal;
308     locsym->container     = &block->symt;
309     locsym->type          = type;
310     if (regno)
311     {
312         locsym->u.s.reg_id = regno;
313         locsym->u.s.offset = 0;
314         locsym->u.s.length = 0;
315     }
316     else
317     {
318         locsym->u.s.reg_id = 0;
319         locsym->u.s.offset = offset * 8;
320         locsym->u.s.length = 0;
321     }
322     if (block)
323         p = vector_add(&block->vchildren, &module->pool);
324     else
325         p = vector_add(&func->vchildren, &module->pool);
326     *p = &locsym->symt;
327     return locsym;
328 }
329
330 struct symt_block* symt_open_func_block(struct module* module, 
331                                         struct symt_function* func,
332                                         struct symt_block* parent_block, 
333                                         unsigned pc, unsigned len)
334 {
335     struct symt_block*  block;
336     struct symt**       p;
337
338     assert(func);
339     assert(func->symt.tag == SymTagFunction);
340
341     assert(!parent_block || parent_block->symt.tag == SymTagBlock);
342     block = pool_alloc(&module->pool, sizeof(*block));
343     block->symt.tag = SymTagBlock;
344     block->address  = func->address + pc;
345     block->size     = len;
346     block->container = parent_block ? &parent_block->symt : &func->symt;
347     vector_init(&block->vchildren, sizeof(struct symt*), 4);
348     if (parent_block)
349         p = vector_add(&parent_block->vchildren, &module->pool);
350     else
351         p = vector_add(&func->vchildren, &module->pool);
352     *p = &block->symt;
353
354     return block;
355 }
356
357 struct symt_block* symt_close_func_block(struct module* module, 
358                                          struct symt_function* func,
359                                          struct symt_block* block, unsigned pc)
360 {
361     assert(func->symt.tag == SymTagFunction);
362
363     if (pc) block->size = func->address + pc - block->address;
364     return (block->container->tag == SymTagBlock) ? 
365         GET_ENTRY(block->container, struct symt_block, symt) : NULL;
366 }
367
368 struct symt_function_point* symt_add_function_point(struct module* module, 
369                                                     struct symt_function* func,
370                                                     enum SymTagEnum point, 
371                                                     unsigned offset, const char* name)
372 {
373     struct symt_function_point* sym;
374     struct symt**               p;
375
376     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
377     {
378         sym->symt.tag = point;
379         sym->parent   = func;
380         sym->offset   = offset;
381         sym->name     = name ? pool_strdup(&module->pool, name) : NULL;
382         p = vector_add(&func->vchildren, &module->pool);
383         *p = &sym->symt;
384     }
385     return sym;
386 }
387
388 BOOL symt_normalize_function(struct module* module, struct symt_function* func)
389 {
390     unsigned            len;
391     struct line_info*   dli;
392
393     assert(func);
394     /* We aren't adding any more locals or line numbers to this function.
395      * Free any spare memory that we might have allocated.
396      */
397     assert(func->symt.tag == SymTagFunction);
398
399 /* EPP     vector_pool_normalize(&func->vlines,    &module->pool); */
400 /* EPP     vector_pool_normalize(&func->vchildren, &module->pool); */
401
402     len = vector_length(&func->vlines);
403     if (len--)
404     {
405         dli = vector_at(&func->vlines,   0);  dli->is_first = 1;
406         dli = vector_at(&func->vlines, len);  dli->is_last  = 1;
407     }
408     return TRUE;
409 }
410
411 struct symt_thunk* symt_new_thunk(struct module* module, 
412                                   struct symt_compiland* compiland, 
413                                   const char* name, THUNK_ORDINAL ord,
414                                   unsigned long addr, unsigned long size)
415 {
416     struct symt_thunk*  sym;
417
418     TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%lx-%lx\n", 
419                          module->module.ModuleName, name, addr, addr + size - 1);
420
421     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
422     {
423         sym->symt.tag  = SymTagThunk;
424         sym->hash_elt.name = pool_strdup(&module->pool, name);
425         hash_table_add(&module->ht_symbols, &sym->hash_elt);
426         module->sortlist_valid = FALSE;
427         sym->container = &compiland->symt;
428         sym->address   = addr;
429         sym->size      = size;
430         sym->ordinal   = ord;
431         if (compiland)
432         {
433             struct symt**       p;
434             p = vector_add(&compiland->vchildren, &module->pool);
435             *p = &sym->symt;
436         }
437     }
438     return sym;
439 }
440
441 /* expect sym_info->MaxNameLen to be set before being called */
442 static void symt_fill_sym_info(const struct module* module, 
443                                const struct symt* sym, SYMBOL_INFO* sym_info)
444 {
445     const char* name;
446     DWORD64 size;
447
448     if (!symt_get_info(sym, TI_GET_TYPE, &sym_info->TypeIndex))
449         sym_info->TypeIndex = 0;
450     sym_info->info = (DWORD)sym;
451     sym_info->Reserved[0] = sym_info->Reserved[1] = 0;
452     if (!symt_get_info(sym, TI_GET_LENGTH, &size) &&
453         (!sym_info->TypeIndex ||
454          !symt_get_info((struct symt*)sym_info->TypeIndex, TI_GET_LENGTH, &size)))
455         size = 0;
456     sym_info->Size = (DWORD)size;
457     sym_info->ModBase = module->module.BaseOfImage;
458     sym_info->Flags = 0;
459     sym_info->Value = 0;
460
461     switch (sym->tag)
462     {
463     case SymTagData:
464         {
465             const struct symt_data*  data = (const struct symt_data*)sym;
466             switch (data->kind)
467             {
468             case DataIsLocal:
469             case DataIsParam:
470                 if (data->u.s.reg_id)
471                 {
472                     sym_info->Flags |= SYMFLAG_REGISTER;
473                     sym_info->Register = data->u.s.reg_id;
474                     sym_info->Address = 0;
475                 }
476                 else
477                 {
478                     sym_info->Flags |= SYMFLAG_LOCAL | SYMFLAG_REGREL;
479                     /* FIXME: this is i386 dependent */
480                     if (data->u.s.offset >= 0) sym_info->Flags |= SYMFLAG_PARAMETER;
481                     /* FIXME: needed ? moreover, it's i386 dependent !!! */
482                     sym_info->Register = CV_REG_EBP;
483                     sym_info->Address = data->u.s.offset / 8;
484                 }
485                 break;
486             case DataIsGlobal:
487             case DataIsFileStatic:
488                 symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
489                 sym_info->Register = 0;
490                 break;
491             case DataIsConstant:
492                 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
493                 switch (data->u.value.n1.n2.vt)
494                 {
495                 case VT_I4:  sym_info->Value = (ULONG)data->u.value.n1.n2.n3.lVal; break;
496                 case VT_I2:  sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.iVal; break;
497                 case VT_I1:  sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.cVal; break;
498                 case VT_UI4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.ulVal; break;
499                 case VT_UI2: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.uiVal; break;
500                 case VT_UI1: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.bVal; break;
501                 default:        
502                     FIXME("Unsupported variant type (%u)\n", data->u.value.n1.n2.vt);
503                 }
504                 break;
505             default:
506                 FIXME("Unhandled kind (%u) in sym data\n", data->kind);
507             }
508         }
509         break;
510     case SymTagPublicSymbol:
511         sym_info->Flags |= SYMFLAG_EXPORT;
512         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
513         break;
514     case SymTagFunction:
515         sym_info->Flags |= SYMFLAG_FUNCTION;
516         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
517         break;
518     case SymTagThunk:
519         sym_info->Flags |= SYMFLAG_THUNK;
520         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
521         break;
522     default:
523         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
524         sym_info->Register = 0;
525         break;
526     }
527     sym_info->Scope = 0; /* FIXME */
528     sym_info->Tag = sym->tag;
529     name = symt_get_name(sym);
530     if (sym_info->MaxNameLen)
531     {
532         if (sym->tag != SymTagPublicSymbol || !(dbghelp_options & SYMOPT_UNDNAME) ||
533             (sym_info->NameLen = UnDecorateSymbolName(name, sym_info->Name, 
534                                                       sym_info->MaxNameLen, UNDNAME_COMPLETE) == 0))
535         {
536             sym_info->NameLen = min(strlen(name), sym_info->MaxNameLen - 1);
537             memcpy(sym_info->Name, name, sym_info->NameLen);
538             sym_info->Name[sym_info->NameLen] = '\0';
539         }
540     }
541     TRACE_(dbghelp_symt)("%p => %s %lu %s\n",
542                          sym, sym_info->Name, sym_info->Size,
543                          wine_dbgstr_longlong(sym_info->Address));
544 }
545
546 static BOOL symt_enum_module(struct module* module, regex_t* regex,
547                              PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
548 {
549     char                        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
550     SYMBOL_INFO*                sym_info = (SYMBOL_INFO*)buffer;
551     void*                       ptr;
552     struct symt_ht*             sym = NULL;
553     struct hash_table_iter      hti;
554
555     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
556     while ((ptr = hash_table_iter_up(&hti)))
557     {
558         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
559         if (sym->hash_elt.name &&
560             regexec(regex, sym->hash_elt.name, 0, NULL, 0) == 0)
561         {
562             sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
563             sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
564             symt_fill_sym_info(module, &sym->symt, sym_info);
565             if (!cb(sym_info, sym_info->Size, user)) return TRUE;
566         }
567     }   
568     return FALSE;
569 }
570
571 /***********************************************************************
572  *              resort_symbols
573  *
574  * Rebuild sorted list of symbols for a module.
575  */
576 static BOOL resort_symbols(struct module* module)
577 {
578     int                         nsym = 0;
579     void*                       ptr;
580     struct symt_ht*             sym;
581     struct hash_table_iter      hti;
582
583     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
584     while ((ptr = hash_table_iter_up(&hti)))
585         nsym++;
586
587     if (!(module->module.NumSyms = nsym)) return FALSE;
588     
589     if (module->addr_sorttab)
590         module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0,
591                                            module->addr_sorttab, 
592                                            nsym * sizeof(struct symt_ht*));
593     else
594         module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0,
595                                          nsym * sizeof(struct symt_ht*));
596     if (!module->addr_sorttab) return FALSE;
597
598     nsym = 0;
599     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
600     while ((ptr = hash_table_iter_up(&hti)))
601     {
602         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
603         assert(sym);
604         module->addr_sorttab[nsym++] = sym;
605     }
606     
607     qsort(module->addr_sorttab, nsym, sizeof(struct symt_ht*), symt_cmp_addr);
608     return module->sortlist_valid = TRUE;
609 }
610
611 /* assume addr is in module */
612 int symt_find_nearest(struct module* module, DWORD addr)
613 {
614     int         mid, high, low;
615     ULONG64     ref_addr, ref_size;
616
617     if (!module->sortlist_valid || !module->addr_sorttab)
618     {
619         if (!resort_symbols(module)) return -1;
620     }
621
622     /*
623      * Binary search to find closest symbol.
624      */
625     low = 0;
626     high = module->module.NumSyms;
627
628     symt_get_info(&module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr);
629     if (addr < ref_addr) return -1;
630     if (high)
631     {
632         symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr);
633         if (!symt_get_info(&module->addr_sorttab[high - 1]->symt,  TI_GET_LENGTH, &ref_size) || !ref_size)
634             ref_size = 0x1000; /* arbitrary value */
635         if (addr >= ref_addr + ref_size) return -1;
636     }
637     
638     while (high > low + 1)
639     {
640         mid = (high + low) / 2;
641         if (cmp_sorttab_addr(module, mid, addr) < 0)
642             low = mid;
643         else
644             high = mid;
645     }
646     if (low != high && high != module->module.NumSyms && 
647         cmp_sorttab_addr(module, high, addr) <= 0)
648         low = high;
649
650     /* If found symbol is a public symbol, check if there are any other entries that
651      * might also have the same address, but would get better information
652      */
653     if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
654     {   
655         symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr);
656         if (low > 0 &&
657             module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol &&
658             !cmp_sorttab_addr(module, low - 1, ref_addr))
659             low--;
660         else if (low < module->module.NumSyms - 1 && 
661                  module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol &&
662                  !cmp_sorttab_addr(module, low + 1, ref_addr))
663             low++;
664     }
665     /* finally check that we fit into the found symbol */
666     symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr);
667     if (addr < ref_addr) return -1;
668     if (!symt_get_info(&module->addr_sorttab[high - 1]->symt, TI_GET_LENGTH, &ref_size) || !ref_size)
669         ref_size = 0x1000; /* arbitrary value */
670     if (addr >= ref_addr + ref_size) return -1;
671
672     return low;
673 }
674
675 static BOOL symt_enum_locals_helper(struct process* pcs, struct module* module,
676                                     regex_t* preg, PSYM_ENUMERATESYMBOLS_CALLBACK cb,
677                                     PVOID user, SYMBOL_INFO* sym_info,
678                                     struct vector* v)
679 {
680     struct symt**       plsym = NULL;
681     struct symt*        lsym = NULL;
682     DWORD               pc = pcs->ctx_frame.InstructionOffset;
683
684     while ((plsym = vector_iter_up(v, plsym)))
685     {
686         lsym = *plsym;
687         switch (lsym->tag)
688         {
689         case SymTagBlock:
690             {
691                 struct symt_block*  block = (struct symt_block*)lsym;
692                 if (pc < block->address || block->address + block->size <= pc)
693                     continue;
694                 if (!symt_enum_locals_helper(pcs, module, preg, cb, user, 
695                                              sym_info, &block->vchildren))
696                     return FALSE;
697             }
698             break;
699         case SymTagData:
700             if (regexec(preg, symt_get_name(lsym), 0, NULL, 0) == 0)
701             {
702                 symt_fill_sym_info(module, lsym, sym_info);
703                 if (!cb(sym_info, sym_info->Size, user))
704                     return FALSE;
705             }
706             break;
707         case SymTagLabel:
708         case SymTagFuncDebugStart:
709         case SymTagFuncDebugEnd:
710             break;
711         default:
712             FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
713             assert(0);
714         }
715     }
716     return TRUE;
717 }
718
719 static BOOL symt_enum_locals(struct process* pcs, const char* mask,
720                              PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
721                              PVOID UserContext)
722 {
723     struct module*      module;
724     struct symt_ht*     sym;
725     char                buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
726     SYMBOL_INFO*        sym_info = (SYMBOL_INFO*)buffer;
727     DWORD               pc = pcs->ctx_frame.InstructionOffset;
728     int                 idx;
729
730     sym_info->SizeOfStruct = sizeof(*sym_info);
731     sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
732
733     module = module_find_by_addr(pcs, pc, DMT_UNKNOWN);
734     if (!(module = module_get_debug(pcs, module))) return FALSE;
735     if ((idx = symt_find_nearest(module, pc)) == -1) return FALSE;
736
737     sym = module->addr_sorttab[idx];
738     if (sym->symt.tag == SymTagFunction)
739     {
740         BOOL            ret;
741         regex_t         preg;
742
743         compile_regex(mask ? mask : "*", -1, &preg,
744                       dbghelp_options & SYMOPT_CASE_INSENSITIVE);
745         ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback, 
746                                       UserContext, sym_info, 
747                                       &((struct symt_function*)sym)->vchildren);
748         regfree(&preg);
749         return ret;
750         
751     }
752     symt_fill_sym_info(module, &sym->symt, sym_info);
753     return EnumSymbolsCallback(sym_info, sym_info->Size, UserContext);
754 }
755
756 /******************************************************************
757  *              SymEnumSymbols (DBGHELP.@)
758  *
759  * cases BaseOfDll = 0
760  *      !foo fails always (despite what MSDN states)
761  *      RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
762  *      no ! in Mask, lookup in local Context
763  * cases BaseOfDll != 0
764  *      !foo fails always (despite what MSDN states)
765  *      RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
766  */
767 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
768                            PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
769                            PVOID UserContext)
770 {
771     struct process*     pcs = process_find_by_handle(hProcess);
772     struct module*      module;
773     struct module*      dbg_module;
774     const char*         bang;
775     regex_t             mod_regex, sym_regex;
776
777     TRACE("(%p %s %s %p %p)\n", 
778           hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask),
779           EnumSymbolsCallback, UserContext);
780
781     if (!pcs) return FALSE;
782
783     if (BaseOfDll == 0)
784     {
785         /* do local variables ? */
786         if (!Mask || !(bang = strchr(Mask, '!')))
787             return symt_enum_locals(pcs, Mask, EnumSymbolsCallback, UserContext);
788
789         if (bang == Mask) return FALSE;
790
791         compile_regex(Mask, bang - Mask, &mod_regex, 
792                       dbghelp_options & SYMOPT_CASE_INSENSITIVE);
793         compile_regex(bang + 1, -1, &sym_regex, 
794                       dbghelp_options & SYMOPT_CASE_INSENSITIVE);
795         
796         for (module = pcs->lmodules; module; module = module->next)
797         {
798             if (module->type == DMT_PE && (dbg_module = module_get_debug(pcs, module)))
799             {
800                 if (regexec(&mod_regex, module->module.ModuleName, 0, NULL, 0) == 0 &&
801                     symt_enum_module(dbg_module, &sym_regex, 
802                                      EnumSymbolsCallback, UserContext))
803                     break;
804             }
805         }
806         /* not found in PE modules, retry on the ELF ones
807          */
808         if (!module && (dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES))
809         {
810             for (module = pcs->lmodules; module; module = module->next)
811             {
812                 if (module->type == DMT_ELF &&
813                     !module_get_containee(pcs, module) &&
814                     (dbg_module = module_get_debug(pcs, module)))
815                 {
816                     if (regexec(&mod_regex, module->module.ModuleName, 0, NULL, 0) == 0 &&
817                         symt_enum_module(dbg_module, &sym_regex, EnumSymbolsCallback, UserContext))
818                     break;
819                 }
820             }
821         }
822         regfree(&mod_regex);
823         regfree(&sym_regex);
824         return TRUE;
825     }
826     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
827     if (!(module = module_get_debug(pcs, module)))
828         return FALSE;
829
830     /* we always ignore module name from Mask when BaseOfDll is defined */
831     if (Mask && (bang = strchr(Mask, '!')))
832     {
833         if (bang == Mask) return FALSE;
834         Mask = bang + 1;
835     }
836
837     compile_regex(Mask ? Mask : "*", -1, &sym_regex, 
838                       dbghelp_options & SYMOPT_CASE_INSENSITIVE);
839     symt_enum_module(module, &sym_regex, EnumSymbolsCallback, UserContext);
840     regfree(&sym_regex);
841
842     return TRUE;
843 }
844
845 struct sym_enumerate
846 {
847     void*                       ctx;
848     PSYM_ENUMSYMBOLS_CALLBACK   cb;
849 };
850
851 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
852 {
853     struct sym_enumerate*       se = (struct sym_enumerate*)ctx;
854     return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
855 }
856
857 /***********************************************************************
858  *              SymEnumerateSymbols (DBGHELP.@)
859  */
860 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
861                                 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, 
862                                 PVOID UserContext)
863 {
864     struct sym_enumerate        se;
865
866     se.ctx = UserContext;
867     se.cb  = EnumSymbolsCallback;
868     
869     return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
870 }
871
872 /******************************************************************
873  *              SymFromAddr (DBGHELP.@)
874  *
875  */
876 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address, 
877                         DWORD64* Displacement, PSYMBOL_INFO Symbol)
878 {
879     struct process*     pcs = process_find_by_handle(hProcess);
880     struct module*      module;
881     struct symt_ht*     sym;
882     int                 idx;
883
884     if (!pcs) return FALSE;
885     module = module_find_by_addr(pcs, Address, DMT_UNKNOWN);
886     if (!(module = module_get_debug(pcs, module))) return FALSE;
887     if ((idx = symt_find_nearest(module, Address)) == -1) return FALSE;
888
889     sym = module->addr_sorttab[idx];
890
891     symt_fill_sym_info(module, &sym->symt, Symbol);
892     *Displacement = Address - Symbol->Address;
893     return TRUE;
894 }
895
896 /******************************************************************
897  *              SymGetSymFromAddr (DBGHELP.@)
898  *
899  */
900 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
901                               PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
902 {
903     char        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
904     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
905     size_t      len;
906     DWORD64     Displacement64;
907
908     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
909     si->SizeOfStruct = sizeof(*si);
910     si->MaxNameLen = MAX_SYM_NAME;
911     if (!SymFromAddr(hProcess, Address, &Displacement64, si))
912         return FALSE;
913
914     if (Displacement)
915         *Displacement = Displacement64;
916     Symbol->Address = si->Address;
917     Symbol->Size    = si->Size;
918     Symbol->Flags   = si->Flags;
919     len = min(Symbol->MaxNameLength, si->MaxNameLen);
920     lstrcpynA(Symbol->Name, si->Name, len);
921     return TRUE;
922 }
923
924 /******************************************************************
925  *              SymFromName (DBGHELP.@)
926  *
927  */
928 BOOL WINAPI SymFromName(HANDLE hProcess, LPSTR Name, PSYMBOL_INFO Symbol)
929 {
930     struct process*             pcs = process_find_by_handle(hProcess);
931     struct module*              module;
932     struct hash_table_iter      hti;
933     void*                       ptr;
934     struct symt_ht*             sym = NULL;
935     const char*                 name;
936
937     TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
938     if (!pcs) return FALSE;
939     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
940     name = strchr(Name, '!');
941     if (name)
942     {
943         char    tmp[128];
944         assert(name - Name < sizeof(tmp));
945         memcpy(tmp, Name, name - Name);
946         tmp[name - Name] = '\0';
947         module = module_find_by_name(pcs, tmp, DMT_UNKNOWN);
948         if (!module) return FALSE;
949         Name = (char*)(name + 1);
950     }
951     else module = pcs->lmodules;
952
953     /* FIXME: Name could be made out of a regular expression */
954     for (; module; module = (name) ? NULL : module->next)
955     {
956         if (module->module.SymType == SymNone) continue;
957         if (module->module.SymType == SymDeferred)
958         {
959             struct module*      xmodule = module_get_debug(pcs, module);
960             if (!xmodule || xmodule != module) continue;
961         }
962         hash_table_iter_init(&module->ht_symbols, &hti, Name);
963         while ((ptr = hash_table_iter_up(&hti)))
964         {
965             sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
966
967             if (!strcmp(sym->hash_elt.name, Name))
968             {
969                 symt_fill_sym_info(module, &sym->symt, Symbol);
970                 return TRUE;
971             }
972         }
973     }
974     return FALSE;
975 }
976
977 /***********************************************************************
978  *              SymGetSymFromName (DBGHELP.@)
979  */
980 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, LPSTR Name, PIMAGEHLP_SYMBOL Symbol)
981 {
982     char        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
983     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
984     size_t      len;
985
986     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
987     si->SizeOfStruct = sizeof(*si);
988     si->MaxNameLen = MAX_SYM_NAME;
989     if (!SymFromName(hProcess, Name, si)) return FALSE;
990
991     Symbol->Address = si->Address;
992     Symbol->Size    = si->Size;
993     Symbol->Flags   = si->Flags;
994     len = min(Symbol->MaxNameLength, si->MaxNameLen);
995     lstrcpynA(Symbol->Name, si->Name, len);
996     return TRUE;
997 }
998
999 /******************************************************************
1000  *              sym_fill_func_line_info
1001  *
1002  * fills information about a file
1003  */
1004 BOOL symt_fill_func_line_info(struct module* module, struct symt_function* func, 
1005                               DWORD addr, IMAGEHLP_LINE* line)
1006 {
1007     struct line_info*   dli = NULL;
1008     BOOL                found = FALSE;
1009
1010     assert(func->symt.tag == SymTagFunction);
1011
1012     while ((dli = vector_iter_down(&func->vlines, dli)))
1013     {
1014         if (!dli->is_source_file)
1015         {
1016             if (found || dli->u.pc_offset > addr) continue;
1017             line->LineNumber = dli->line_number;
1018             line->Address    = dli->u.pc_offset;
1019             line->Key        = dli;
1020             found = TRUE;
1021             continue;
1022         }
1023         if (found)
1024         {
1025             line->FileName = (char*)source_get(module, dli->u.source_file);
1026             return TRUE;
1027         }
1028     }
1029     return FALSE;
1030 }
1031
1032 /***********************************************************************
1033  *              SymGetSymNext (DBGHELP.@)
1034  */
1035 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1036 {
1037     /* algo:
1038      * get module from Symbol.Address
1039      * get index in module.addr_sorttab of Symbol.Address
1040      * increment index
1041      * if out of module bounds, move to next module in process address space
1042      */
1043     FIXME("(%p, %p): stub\n", hProcess, Symbol);
1044     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1045     return FALSE;
1046 }
1047
1048 /***********************************************************************
1049  *              SymGetSymPrev (DBGHELP.@)
1050  */
1051
1052 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1053 {
1054     FIXME("(%p, %p): stub\n", hProcess, Symbol);
1055     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1056     return FALSE;
1057 }
1058
1059 /******************************************************************
1060  *              SymGetLineFromAddr (DBGHELP.@)
1061  *
1062  */
1063 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, 
1064                                PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
1065 {
1066     struct process*     pcs = process_find_by_handle(hProcess);
1067     struct module*      module;
1068     int                 idx;
1069
1070     TRACE("%p %08lx %p %p\n", hProcess, dwAddr, pdwDisplacement, Line);
1071
1072     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1073
1074     if (!pcs) return FALSE;
1075     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1076     if (!(module = module_get_debug(pcs, module))) return FALSE;
1077     if ((idx = symt_find_nearest(module, dwAddr)) == -1) return FALSE;
1078
1079     if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE;
1080     if (!symt_fill_func_line_info(module, 
1081                                   (struct symt_function*)module->addr_sorttab[idx],
1082                                   dwAddr, Line)) return FALSE;
1083     *pdwDisplacement = dwAddr - Line->Address;
1084     return TRUE;
1085 }
1086
1087 /******************************************************************
1088  *              copy_line_64_from_32 (internal)
1089  *
1090  */
1091 static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32)
1092
1093 {
1094     l64->Key = l32->Key;
1095     l64->LineNumber = l32->LineNumber;
1096     l64->FileName = l32->FileName;
1097     l64->Address = l32->Address;
1098 }
1099
1100 /******************************************************************
1101  *              copy_line_32_from_64 (internal)
1102  *
1103  */
1104 static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64)
1105
1106 {
1107     l32->Key = l64->Key;
1108     l32->LineNumber = l64->LineNumber;
1109     l32->FileName = l64->FileName;
1110     l32->Address = l64->Address;
1111 }
1112
1113 /******************************************************************
1114  *              SymGetLineFromAddr64 (DBGHELP.@)
1115  *
1116  */
1117 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, 
1118                                  PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line)
1119 {
1120     IMAGEHLP_LINE       line32;
1121
1122     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1123     if (!validate_addr64(dwAddr)) return FALSE;
1124     line32.SizeOfStruct = sizeof(line32);
1125     if (!SymGetLineFromAddr(hProcess, (DWORD)dwAddr, pdwDisplacement, &line32))
1126         return FALSE;
1127     copy_line_64_from_32(Line, &line32);
1128     return TRUE;
1129 }
1130
1131 /******************************************************************
1132  *              SymGetLinePrev (DBGHELP.@)
1133  *
1134  */
1135 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
1136 {
1137     struct process*     pcs = process_find_by_handle(hProcess);
1138     struct module*      module;
1139     struct line_info*   li;
1140     BOOL                in_search = FALSE;
1141
1142     TRACE("(%p %p)\n", hProcess, Line);
1143
1144     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1145
1146     if (!pcs) return FALSE;
1147     module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
1148     if (!(module = module_get_debug(pcs, module))) return FALSE;
1149
1150     if (Line->Key == 0) return FALSE;
1151     li = (struct line_info*)Line->Key;
1152     /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE
1153      * element we have to go back until we find the prev one to get the real
1154      * source file name for the DLIT_OFFSET element just before 
1155      * the first DLIT_SOURCEFILE
1156      */
1157     while (!li->is_first)
1158     {
1159         li--;
1160         if (!li->is_source_file)
1161         {
1162             Line->LineNumber = li->line_number;
1163             Line->Address    = li->u.pc_offset;
1164             Line->Key        = li;
1165             if (!in_search) return TRUE;
1166         }
1167         else
1168         {
1169             if (in_search)
1170             {
1171                 Line->FileName = (char*)source_get(module, li->u.source_file);
1172                 return TRUE;
1173             }
1174             in_search = TRUE;
1175         }
1176     }
1177     SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
1178     return FALSE;
1179 }
1180
1181 /******************************************************************
1182  *              SymGetLinePrev64 (DBGHELP.@)
1183  *
1184  */
1185 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
1186 {
1187     IMAGEHLP_LINE       line32;
1188
1189     line32.SizeOfStruct = sizeof(line32);
1190     copy_line_32_from_64(&line32, Line);
1191     if (!SymGetLinePrev(hProcess, &line32)) return FALSE;
1192     copy_line_64_from_32(Line, &line32);
1193     return TRUE;
1194 }
1195     
1196 BOOL symt_get_func_line_next(struct module* module, PIMAGEHLP_LINE line)
1197 {
1198     struct line_info*   li;
1199
1200     if (line->Key == 0) return FALSE;
1201     li = (struct line_info*)line->Key;
1202     while (!li->is_last)
1203     {
1204         li++;
1205         if (!li->is_source_file)
1206         {
1207             line->LineNumber = li->line_number;
1208             line->Address    = li->u.pc_offset;
1209             line->Key        = li;
1210             return TRUE;
1211         }
1212         line->FileName = (char*)source_get(module, li->u.source_file);
1213     }
1214     return FALSE;
1215 }
1216
1217 /******************************************************************
1218  *              SymGetLineNext (DBGHELP.@)
1219  *
1220  */
1221 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
1222 {
1223     struct process*     pcs = process_find_by_handle(hProcess);
1224     struct module*      module;
1225
1226     TRACE("(%p %p)\n", hProcess, Line);
1227
1228     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1229     if (!pcs) return FALSE;
1230     module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
1231     if (!(module = module_get_debug(pcs, module))) return FALSE;
1232
1233     if (symt_get_func_line_next(module, Line)) return TRUE;
1234     SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
1235     return FALSE;
1236 }
1237
1238 /******************************************************************
1239  *              SymGetLineNext64 (DBGHELP.@)
1240  *
1241  */
1242 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
1243 {
1244     IMAGEHLP_LINE       line32;
1245
1246     line32.SizeOfStruct = sizeof(line32);
1247     copy_line_32_from_64(&line32, Line);
1248     if (!SymGetLineNext(hProcess, &line32)) return FALSE;
1249     copy_line_64_from_32(Line, &line32);
1250     return TRUE;
1251 }
1252     
1253 /***********************************************************************
1254  *              SymFunctionTableAccess (DBGHELP.@)
1255  */
1256 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
1257 {
1258     WARN("(%p, 0x%08lx): stub\n", hProcess, AddrBase);
1259     return NULL;
1260 }
1261
1262 /***********************************************************************
1263  *              SymFunctionTableAccess64 (DBGHELP.@)
1264  */
1265 PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase)
1266 {
1267     WARN("(%p, %s): stub\n", hProcess, wine_dbgstr_longlong(AddrBase));
1268     return NULL;
1269 }
1270
1271 /***********************************************************************
1272  *              SymUnDName (DBGHELP.@)
1273  */
1274 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, LPSTR UnDecName, DWORD UnDecNameLength)
1275 {
1276     TRACE("(%p %s %lu)\n", sym, UnDecName, UnDecNameLength);
1277     return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, 
1278                                 UNDNAME_COMPLETE) != 0;
1279 }
1280
1281 static void* und_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len); }
1282 static void  und_free (void* ptr)  { HeapFree(GetProcessHeap(), 0, ptr); }
1283
1284 /***********************************************************************
1285  *              UnDecorateSymbolName (DBGHELP.@)
1286  */
1287 DWORD WINAPI UnDecorateSymbolName(LPCSTR DecoratedName, LPSTR UnDecoratedName,
1288                                   DWORD UndecoratedLength, DWORD Flags)
1289 {
1290     /* undocumented from msvcrt */
1291     static char* (*p_undname)(char*, const char*, int, void* (*)(size_t), void (*)(void*), unsigned short);
1292     static WCHAR szMsvcrt[] = {'m','s','v','c','r','t','.','d','l','l',0};
1293
1294     TRACE("(%s, %p, %ld, 0x%08lx)\n",
1295           debugstr_a(DecoratedName), UnDecoratedName, UndecoratedLength, Flags);
1296
1297     if (!p_undname)
1298     {
1299         if (!hMsvcrt) hMsvcrt = LoadLibraryW(szMsvcrt);
1300         if (hMsvcrt) p_undname = (void*)GetProcAddress(hMsvcrt, "__unDName");
1301         if (!p_undname) return 0;
1302     }
1303
1304     if (!UnDecoratedName) return 0;
1305     if (!p_undname(UnDecoratedName, DecoratedName, UndecoratedLength, 
1306                    und_alloc, und_free, Flags))
1307         return 0;
1308     return strlen(UnDecoratedName);
1309 }
1310
1311 /******************************************************************
1312  *              SymMatchString (DBGHELP.@)
1313  *
1314  */
1315 BOOL WINAPI SymMatchString(PCSTR string, PCSTR re, BOOL _case)
1316 {
1317     regex_t     preg;
1318     BOOL        ret;
1319
1320     TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
1321
1322     compile_regex(re, -1, &preg, _case);
1323     ret = regexec(&preg, string, 0, NULL, 0) == 0;
1324     regfree(&preg);
1325     return ret;
1326 }
1327
1328 /******************************************************************
1329  *              SymSearch (DBGHELP.@)
1330  */
1331 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
1332                       DWORD SymTag, PCSTR Mask, DWORD64 Address,
1333                       PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1334                       PVOID UserContext, DWORD Options)
1335 {
1336     TRACE("(%p %s %lu %lu %s %s %p %p %lx)\n",
1337           hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask, 
1338           wine_dbgstr_longlong(Address), EnumSymbolsCallback,
1339           UserContext, Options);
1340
1341     if (Index != 0)
1342     {
1343         FIXME("Unsupported searching for a given Index (%lu)\n", Index);
1344         SetLastError(ERROR_INVALID_PARAMETER);
1345         return FALSE;
1346     }
1347     if (SymTag != 0)
1348     {
1349         FIXME("Unsupported searching for a given SymTag (%lu)\n", SymTag);
1350         SetLastError(ERROR_INVALID_PARAMETER);
1351         return FALSE;
1352     }
1353     if (Address != 0)
1354     {
1355         FIXME("Unsupported searching for a given Address (%s)\n", wine_dbgstr_longlong(Address));
1356         SetLastError(ERROR_INVALID_PARAMETER);
1357         return FALSE;
1358     }
1359     if (Options != SYMSEARCH_GLOBALSONLY)
1360     {
1361         FIXME("Unsupported searching with options (%lx)\n", Options);
1362         SetLastError(ERROR_INVALID_PARAMETER);
1363         return FALSE;
1364     }
1365     return SymEnumSymbols(hProcess, BaseOfDll, Mask, EnumSymbolsCallback, UserContext);
1366 }