wined3d: Merge the various resource desc structures.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #include "winnls.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
42 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
43
44 static inline int cmp_addr(ULONG64 a1, ULONG64 a2)
45 {
46     if (a1 > a2) return 1;
47     if (a1 < a2) return -1;
48     return 0;
49 }
50
51 static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr)
52 {
53     ULONG64     ref;
54
55     symt_get_info(module, &module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
56     return cmp_addr(ref, addr);
57 }
58
59 struct module*  symt_cmp_addr_module = NULL;
60
61 int symt_cmp_addr(const void* p1, const void* p2)
62 {
63     const struct symt*  sym1 = *(const struct symt* const *)p1;
64     const struct symt*  sym2 = *(const struct symt* const *)p2;
65     ULONG64     a1, a2;
66
67     symt_get_info(symt_cmp_addr_module, sym1, TI_GET_ADDRESS, &a1);
68     symt_get_info(symt_cmp_addr_module, sym2, TI_GET_ADDRESS, &a2);
69     return cmp_addr(a1, a2);
70 }
71
72 DWORD             symt_ptr2index(struct module* module, const struct symt* sym)
73 {
74 #ifdef _WIN64
75     const struct symt** c;
76     int                 len = vector_length(&module->vsymt), i;
77
78     /* FIXME: this is inefficient */
79     for (i = 0; i < len; i++)
80     {
81         if (*(struct symt**)vector_at(&module->vsymt, i) == sym)
82             return i + 1;
83     }
84     /* not found */
85     c = vector_add(&module->vsymt, &module->pool);
86     if (c) *c = sym;
87     return len + 1;
88 #else
89     return (DWORD)sym;
90 #endif
91 }
92
93 struct symt*      symt_index2ptr(struct module* module, DWORD id)
94 {
95 #ifdef _WIN64
96     if (!id-- || id >= vector_length(&module->vsymt)) return NULL;
97     return *(struct symt**)vector_at(&module->vsymt, id);
98 #else
99     return (struct symt*)id;
100 #endif
101 }
102
103 static BOOL symt_grow_sorttab(struct module* module, unsigned sz)
104 {
105     struct symt_ht**    new;
106     unsigned int size;
107
108     if (sz <= module->sorttab_size) return TRUE;
109     if (module->addr_sorttab)
110     {
111         size = module->sorttab_size * 2;
112         new = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab,
113                           size * sizeof(struct symt_ht*));
114     }
115     else
116     {
117         size = 64;
118         new = HeapAlloc(GetProcessHeap(), 0, size * sizeof(struct symt_ht*));
119     }
120     if (!new) return FALSE;
121     module->sorttab_size = size;
122     module->addr_sorttab = new;
123     return TRUE;
124 }
125
126 static void symt_add_module_ht(struct module* module, struct symt_ht* ht)
127 {
128     ULONG64             addr;
129
130     hash_table_add(&module->ht_symbols, &ht->hash_elt);
131     /* Don't store in sorttab a symbol without address, they are of
132      * no use here (e.g. constant values)
133      */
134     if (symt_get_info(module, &ht->symt, TI_GET_ADDRESS, &addr) &&
135         symt_grow_sorttab(module, module->num_symbols + 1))
136     {
137         module->addr_sorttab[module->num_symbols++] = ht;
138         module->sortlist_valid = FALSE;
139     }
140 }
141
142 #ifdef HAVE_REGEX_H
143
144 /* transforms a dbghelp's regular expression into a POSIX one
145  * Here are the valid dbghelp reg ex characters:
146  *      *       0 or more characters
147  *      ?       a single character
148  *      []      list
149  *      #       0 or more of preceding char
150  *      +       1 or more of preceding char
151  *      escapes \ on #, ?, [, ], *, +. don't work on -
152  */
153 static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
154 {
155     char *mask, *p;
156     BOOL        in_escape = FALSE;
157     unsigned    flags = REG_NOSUB;
158
159     if (numchar == -1) numchar = strlen( str );
160
161     p = mask = HeapAlloc( GetProcessHeap(), 0, 2 * numchar + 3 );
162     *p++ = '^';
163
164     while (*str && numchar--)
165     {
166         /* FIXME: this shouldn't be valid on '-' */
167         if (in_escape)
168         {
169             *p++ = '\\';
170             *p++ = *str;
171             in_escape = FALSE;
172         }
173         else switch (*str)
174         {
175         case '\\': in_escape = TRUE; break;
176         case '*':  *p++ = '.'; *p++ = '*'; break;
177         case '?':  *p++ = '.'; break;
178         case '#':  *p++ = '*'; break;
179         /* escape some valid characters in dbghelp reg exp:s */
180         case '$':  *p++ = '\\'; *p++ = '$'; break;
181         /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */
182         default:   *p++ = *str; break;
183         }
184         str++;
185     }
186     if (in_escape)
187     {
188         *p++ = '\\';
189         *p++ = '\\';
190     }
191     *p++ = '$';
192     *p = 0;
193     if (_case) flags |= REG_ICASE;
194     if (regcomp(re, mask, flags)) FIXME("Couldn't compile %s\n", mask);
195     HeapFree(GetProcessHeap(), 0, mask);
196 }
197
198 static BOOL compile_file_regex(regex_t* re, const char* srcfile)
199 {
200     char *mask, *p;
201     BOOL ret;
202
203     if (!srcfile || !*srcfile) return regcomp(re, ".*", REG_NOSUB);
204
205     p = mask = HeapAlloc(GetProcessHeap(), 0, 5 * strlen(srcfile) + 4);
206     *p++ = '^';
207     while (*srcfile)
208     {
209         switch (*srcfile)
210         {
211         case '\\':
212         case '/':
213             *p++ = '[';
214             *p++ = '\\';
215             *p++ = '\\';
216             *p++ = '/';
217             *p++ = ']';
218             break;
219         case '.':
220             *p++ = '\\';
221             *p++ = '.';
222             break;
223         case '*':
224             *p++ = '.';
225             *p++ = '*';
226             break;
227         default:
228             *p++ = *srcfile;
229             break;
230         }
231         srcfile++;
232     }
233     *p++ = '$';
234     *p = 0;
235     ret = !regcomp(re, mask, REG_NOSUB);
236     HeapFree(GetProcessHeap(), 0, mask);
237     if (!ret)
238     {
239         FIXME("Couldn't compile %s\n", mask);
240         SetLastError(ERROR_INVALID_PARAMETER);
241     }
242     return ret;
243 }
244
245 static int match_regexp( const regex_t *re, const char *str )
246 {
247     return !regexec( re, str, 0, NULL, 0 );
248 }
249
250 #else /* HAVE_REGEX_H */
251
252 /* if we don't have regexp support, fall back to a simple string comparison */
253
254 typedef struct
255 {
256     char *str;
257     BOOL  icase;
258 } regex_t;
259
260 static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
261 {
262     if (numchar == -1) numchar = strlen( str );
263
264     re->str = HeapAlloc( GetProcessHeap(), 0, numchar + 1 );
265     memcpy( re->str, str, numchar );
266     re->str[numchar] = 0;
267     re->icase = _case;
268 }
269
270 static BOOL compile_file_regex(regex_t* re, const char* srcfile)
271 {
272     if (!srcfile || !*srcfile) re->str = NULL;
273     else compile_regex( srcfile, -1, re, FALSE );
274     return TRUE;
275 }
276
277 static int match_regexp( const regex_t *re, const char *str )
278 {
279     if (!re->str) return 1;
280     if (re->icase) return !lstrcmpiA( re->str, str );
281     return !strcmp( re->str, str );
282 }
283
284 static void regfree( regex_t *re )
285 {
286     HeapFree( GetProcessHeap(), 0, re->str );
287 }
288
289 #endif /* HAVE_REGEX_H */
290
291 struct symt_compiland* symt_new_compiland(struct module* module, 
292                                           unsigned long address, unsigned src_idx)
293 {
294     struct symt_compiland*    sym;
295
296     TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n",
297                          debugstr_w(module->module.ModuleName), source_get(module, src_idx));
298     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
299     {
300         sym->symt.tag = SymTagCompiland;
301         sym->address  = address;
302         sym->source   = src_idx;
303         vector_init(&sym->vchildren, sizeof(struct symt*), 32);
304     }
305     return sym;
306 }
307
308 struct symt_public* symt_new_public(struct module* module, 
309                                     struct symt_compiland* compiland,
310                                     const char* name,
311                                     unsigned long address, unsigned size)
312 {
313     struct symt_public* sym;
314     struct symt**       p;
315
316     TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%lx\n",
317                          debugstr_w(module->module.ModuleName), name, address);
318     if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
319         symt_find_nearest(module, address) != NULL)
320         return NULL;
321     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
322     {
323         sym->symt.tag      = SymTagPublicSymbol;
324         sym->hash_elt.name = pool_strdup(&module->pool, name);
325         sym->container     = compiland ? &compiland->symt : NULL;
326         sym->address       = address;
327         sym->size          = size;
328         symt_add_module_ht(module, (struct symt_ht*)sym);
329         if (compiland)
330         {
331             p = vector_add(&compiland->vchildren, &module->pool);
332             *p = &sym->symt;
333         }
334     }
335     return sym;
336 }
337
338 struct symt_data* symt_new_global_variable(struct module* module, 
339                                            struct symt_compiland* compiland, 
340                                            const char* name, unsigned is_static,
341                                            struct location loc, unsigned long size,
342                                            struct symt* type)
343 {
344     struct symt_data*   sym;
345     struct symt**       p;
346     DWORD64             tsz;
347
348     TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%lx %p\n",
349                          debugstr_w(module->module.ModuleName), name, loc.kind, loc.offset, type);
350     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
351     {
352         sym->symt.tag      = SymTagData;
353         sym->hash_elt.name = pool_strdup(&module->pool, name);
354         sym->kind          = is_static ? DataIsFileStatic : DataIsGlobal;
355         sym->container     = compiland ? &compiland->symt : NULL;
356         sym->type          = type;
357         sym->u.var         = loc;
358         if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz))
359         {
360             if (tsz != size)
361                 FIXME("Size mismatch for %s.%s between type (%s) and src (%lu)\n",
362                       debugstr_w(module->module.ModuleName), name,
363                       wine_dbgstr_longlong(tsz), size);
364         }
365         symt_add_module_ht(module, (struct symt_ht*)sym);
366         if (compiland)
367         {
368             p = vector_add(&compiland->vchildren, &module->pool);
369             *p = &sym->symt;
370         }
371     }
372     return sym;
373 }
374
375 struct symt_function* symt_new_function(struct module* module, 
376                                         struct symt_compiland* compiland, 
377                                         const char* name,
378                                         unsigned long addr, unsigned long size,
379                                         struct symt* sig_type)
380 {
381     struct symt_function*       sym;
382     struct symt**               p;
383
384     TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n",
385                          debugstr_w(module->module.ModuleName), name, addr, addr + size - 1);
386
387     assert(!sig_type || sig_type->tag == SymTagFunctionType);
388     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
389     {
390         sym->symt.tag  = SymTagFunction;
391         sym->hash_elt.name = pool_strdup(&module->pool, name);
392         sym->container = &compiland->symt;
393         sym->address   = addr;
394         sym->type      = sig_type;
395         sym->size      = size;
396         vector_init(&sym->vlines,  sizeof(struct line_info), 64);
397         vector_init(&sym->vchildren, sizeof(struct symt*), 8);
398         symt_add_module_ht(module, (struct symt_ht*)sym);
399         if (compiland)
400         {
401             p = vector_add(&compiland->vchildren, &module->pool);
402             *p = &sym->symt;
403         }
404     }
405     return sym;
406 }
407
408 void symt_add_func_line(struct module* module, struct symt_function* func,
409                         unsigned source_idx, int line_num, unsigned long offset)
410 {
411     struct line_info*   dli;
412     BOOL                last_matches = FALSE;
413     int                 i;
414
415     if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
416
417     TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", 
418                          func, func->hash_elt.name, offset, 
419                          source_get(module, source_idx), line_num);
420
421     assert(func->symt.tag == SymTagFunction);
422
423     for (i=vector_length(&func->vlines)-1; i>=0; i--)
424     {
425         dli = vector_at(&func->vlines, i);
426         if (dli->is_source_file)
427         {
428             last_matches = (source_idx == dli->u.source_file);
429             break;
430         }
431     }
432
433     if (!last_matches)
434     {
435         /* we shouldn't have line changes on first line of function */
436         dli = vector_add(&func->vlines, &module->pool);
437         dli->is_source_file = 1;
438         dli->is_first       = dli->is_last = 0;
439         dli->line_number    = 0;
440         dli->u.source_file  = source_idx;
441     }
442     dli = vector_add(&func->vlines, &module->pool);
443     dli->is_source_file = 0;
444     dli->is_first       = dli->is_last = 0;
445     dli->line_number    = line_num;
446     dli->u.pc_offset    = func->address + offset;
447 }
448
449 /******************************************************************
450  *             symt_add_func_local
451  *
452  * Adds a new local/parameter to a given function:
453  * In any cases, dt tells whether it's a local variable or a parameter
454  * If regno it's not 0:
455  *      - then variable is stored in a register
456  *      - otherwise, value is referenced by register + offset
457  * Otherwise, the variable is stored on the stack:
458  *      - offset is then the offset from the frame register
459  */
460 struct symt_data* symt_add_func_local(struct module* module, 
461                                       struct symt_function* func, 
462                                       enum DataKind dt,
463                                       const struct location* loc,
464                                       struct symt_block* block, 
465                                       struct symt* type, const char* name)
466 {
467     struct symt_data*   locsym;
468     struct symt**       p;
469
470     TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n",
471                          debugstr_w(module->module.ModuleName), func->hash_elt.name,
472                          name, type);
473
474     assert(func);
475     assert(func->symt.tag == SymTagFunction);
476     assert(dt == DataIsParam || dt == DataIsLocal);
477
478     locsym = pool_alloc(&module->pool, sizeof(*locsym));
479     locsym->symt.tag      = SymTagData;
480     locsym->hash_elt.name = pool_strdup(&module->pool, name);
481     locsym->hash_elt.next = NULL;
482     locsym->kind          = dt;
483     locsym->container     = block ? &block->symt : &func->symt;
484     locsym->type          = type;
485     locsym->u.var         = *loc;
486     if (block)
487         p = vector_add(&block->vchildren, &module->pool);
488     else
489         p = vector_add(&func->vchildren, &module->pool);
490     *p = &locsym->symt;
491     return locsym;
492 }
493
494
495 struct symt_block* symt_open_func_block(struct module* module, 
496                                         struct symt_function* func,
497                                         struct symt_block* parent_block, 
498                                         unsigned pc, unsigned len)
499 {
500     struct symt_block*  block;
501     struct symt**       p;
502
503     assert(func);
504     assert(func->symt.tag == SymTagFunction);
505
506     assert(!parent_block || parent_block->symt.tag == SymTagBlock);
507     block = pool_alloc(&module->pool, sizeof(*block));
508     block->symt.tag = SymTagBlock;
509     block->address  = func->address + pc;
510     block->size     = len;
511     block->container = parent_block ? &parent_block->symt : &func->symt;
512     vector_init(&block->vchildren, sizeof(struct symt*), 4);
513     if (parent_block)
514         p = vector_add(&parent_block->vchildren, &module->pool);
515     else
516         p = vector_add(&func->vchildren, &module->pool);
517     *p = &block->symt;
518
519     return block;
520 }
521
522 struct symt_block* symt_close_func_block(struct module* module, 
523                                          const struct symt_function* func,
524                                          struct symt_block* block, unsigned pc)
525 {
526     assert(func);
527     assert(func->symt.tag == SymTagFunction);
528
529     if (pc) block->size = func->address + pc - block->address;
530     return (block->container->tag == SymTagBlock) ? 
531         GET_ENTRY(block->container, struct symt_block, symt) : NULL;
532 }
533
534 struct symt_hierarchy_point* symt_add_function_point(struct module* module,
535                                                      struct symt_function* func,
536                                                      enum SymTagEnum point,
537                                                      const struct location* loc,
538                                                      const char* name)
539 {
540     struct symt_hierarchy_point*sym;
541     struct symt**               p;
542
543     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
544     {
545         sym->symt.tag = point;
546         sym->parent   = &func->symt;
547         sym->loc      = *loc;
548         sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL;
549         p = vector_add(&func->vchildren, &module->pool);
550         *p = &sym->symt;
551     }
552     return sym;
553 }
554
555 BOOL symt_normalize_function(struct module* module, const struct symt_function* func)
556 {
557     unsigned            len;
558     struct line_info*   dli;
559
560     assert(func);
561     /* We aren't adding any more locals or line numbers to this function.
562      * Free any spare memory that we might have allocated.
563      */
564     assert(func->symt.tag == SymTagFunction);
565
566 /* EPP     vector_pool_normalize(&func->vlines,    &module->pool); */
567 /* EPP     vector_pool_normalize(&func->vchildren, &module->pool); */
568
569     len = vector_length(&func->vlines);
570     if (len--)
571     {
572         dli = vector_at(&func->vlines,   0);  dli->is_first = 1;
573         dli = vector_at(&func->vlines, len);  dli->is_last  = 1;
574     }
575     return TRUE;
576 }
577
578 struct symt_thunk* symt_new_thunk(struct module* module, 
579                                   struct symt_compiland* compiland, 
580                                   const char* name, THUNK_ORDINAL ord,
581                                   unsigned long addr, unsigned long size)
582 {
583     struct symt_thunk*  sym;
584
585     TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%lx-%lx\n",
586                          debugstr_w(module->module.ModuleName), name, addr, addr + size - 1);
587
588     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
589     {
590         sym->symt.tag  = SymTagThunk;
591         sym->hash_elt.name = pool_strdup(&module->pool, name);
592         sym->container = &compiland->symt;
593         sym->address   = addr;
594         sym->size      = size;
595         sym->ordinal   = ord;
596         symt_add_module_ht(module, (struct symt_ht*)sym);
597         if (compiland)
598         {
599             struct symt**       p;
600             p = vector_add(&compiland->vchildren, &module->pool);
601             *p = &sym->symt;
602         }
603     }
604     return sym;
605 }
606
607 struct symt_data* symt_new_constant(struct module* module,
608                                     struct symt_compiland* compiland,
609                                     const char* name, struct symt* type,
610                                     const VARIANT* v)
611 {
612     struct symt_data*  sym;
613
614     TRACE_(dbghelp_symt)("Adding constant value %s:%s\n",
615                          debugstr_w(module->module.ModuleName), name);
616
617     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
618     {
619         sym->symt.tag      = SymTagData;
620         sym->hash_elt.name = pool_strdup(&module->pool, name);
621         sym->kind          = DataIsConstant;
622         sym->container     = compiland ? &compiland->symt : NULL;
623         sym->type          = type;
624         sym->u.value       = *v;
625         symt_add_module_ht(module, (struct symt_ht*)sym);
626         if (compiland)
627         {
628             struct symt**       p;
629             p = vector_add(&compiland->vchildren, &module->pool);
630             *p = &sym->symt;
631         }
632     }
633     return sym;
634 }
635
636 struct symt_hierarchy_point* symt_new_label(struct module* module,
637                                             struct symt_compiland* compiland,
638                                             const char* name, unsigned long address)
639 {
640     struct symt_hierarchy_point*        sym;
641
642     TRACE_(dbghelp_symt)("Adding global label value %s:%s\n",
643                          debugstr_w(module->module.ModuleName), name);
644
645     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
646     {
647         sym->symt.tag      = SymTagLabel;
648         sym->hash_elt.name = pool_strdup(&module->pool, name);
649         sym->loc.kind      = loc_absolute;
650         sym->loc.offset    = address;
651         sym->parent        = compiland ? &compiland->symt : NULL;
652         symt_add_module_ht(module, (struct symt_ht*)sym);
653         if (compiland)
654         {
655             struct symt**       p;
656             p = vector_add(&compiland->vchildren, &module->pool);
657             *p = &sym->symt;
658         }
659     }
660     return sym;
661 }
662
663 /* expect sym_info->MaxNameLen to be set before being called */
664 static void symt_fill_sym_info(struct module_pair* pair,
665                                const struct symt_function* func,
666                                const struct symt* sym, SYMBOL_INFO* sym_info)
667 {
668     const char* name;
669     DWORD64 size;
670
671     if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex))
672         sym_info->TypeIndex = 0;
673     sym_info->info = symt_ptr2index(pair->effective, sym);
674     sym_info->Reserved[0] = sym_info->Reserved[1] = 0;
675     if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) &&
676         (!sym_info->TypeIndex ||
677          !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex),
678                          TI_GET_LENGTH, &size)))
679         size = 0;
680     sym_info->Size = (DWORD)size;
681     sym_info->ModBase = pair->requested->module.BaseOfImage;
682     sym_info->Flags = 0;
683     sym_info->Value = 0;
684
685     switch (sym->tag)
686     {
687     case SymTagData:
688         {
689             const struct symt_data*  data = (const struct symt_data*)sym;
690             switch (data->kind)
691             {
692             case DataIsParam:
693                 sym_info->Flags |= SYMFLAG_PARAMETER;
694                 /* fall through */
695             case DataIsLocal:
696                 {
697                     struct location loc = data->u.var;
698
699                     if (loc.kind >= loc_user)
700                     {
701                         unsigned                i;
702                         struct module_format*   modfmt;
703
704                         for (i = 0; i < DFI_LAST; i++)
705                         {
706                             modfmt = pair->effective->format_info[i];
707                             if (modfmt && modfmt->loc_compute)
708                             {
709                                 modfmt->loc_compute(pair->pcs, modfmt, func, &loc);
710                                 break;
711                             }
712                         }
713                     }
714                     switch (loc.kind)
715                     {
716                     case loc_error:
717                         /* for now we report error cases as a negative register number */
718                         sym_info->Flags |= SYMFLAG_LOCAL;
719                         /* fall through */
720                     case loc_register:
721                         sym_info->Flags |= SYMFLAG_REGISTER;
722                         sym_info->Register = loc.reg;
723                         sym_info->Address = 0;
724                         break;
725                     case loc_regrel:
726                         sym_info->Flags |= SYMFLAG_LOCAL | SYMFLAG_REGREL;
727                         /* FIXME: it's i386 dependent !!! */
728                         sym_info->Register = loc.reg ? loc.reg : CV_REG_EBP;
729                         sym_info->Address = loc.offset;
730                         break;
731                     case loc_absolute:
732                         sym_info->Flags |= SYMFLAG_VALUEPRESENT;
733                         sym_info->Value = loc.offset;
734                         break;
735                     default:
736                         FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", loc.kind);
737                         assert(0);
738                     }
739                 }
740                 break;
741             case DataIsGlobal:
742             case DataIsFileStatic:
743                 switch (data->u.var.kind)
744                 {
745                 case loc_tlsrel:
746                     sym_info->Flags |= SYMFLAG_TLSREL;
747                     /* fall through */
748                 case loc_absolute:
749                     symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
750                     sym_info->Register = 0;
751                     break;
752                 default:
753                     FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind);
754                     assert(0);
755                 }
756                 break;
757             case DataIsConstant:
758                 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
759                 switch (data->u.value.n1.n2.vt)
760                 {
761                 case VT_I4:  sym_info->Value = (ULONG)data->u.value.n1.n2.n3.lVal; break;
762                 case VT_I2:  sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.iVal; break;
763                 case VT_I1:  sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.cVal; break;
764                 case VT_UI4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.ulVal; break;
765                 case VT_UI2: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.uiVal; break;
766                 case VT_UI1: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.bVal; break;
767                 case VT_I1 | VT_BYREF: sym_info->Value = (ULONG64)(DWORD_PTR)data->u.value.n1.n2.n3.byref; break;
768                 case VT_EMPTY: sym_info->Value = 0; break;
769                 default:
770                     FIXME("Unsupported variant type (%u)\n", data->u.value.n1.n2.vt);
771                     sym_info->Value = 0;
772                     break;
773                 }
774                 break;
775             default:
776                 FIXME("Unhandled kind (%u) in sym data\n", data->kind);
777             }
778         }
779         break;
780     case SymTagPublicSymbol:
781         sym_info->Flags |= SYMFLAG_EXPORT;
782         symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
783         break;
784     case SymTagFunction:
785         sym_info->Flags |= SYMFLAG_FUNCTION;
786         symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
787         break;
788     case SymTagThunk:
789         sym_info->Flags |= SYMFLAG_THUNK;
790         symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
791         break;
792     default:
793         symt_get_info(pair->effective, sym, TI_GET_ADDRESS, &sym_info->Address);
794         sym_info->Register = 0;
795         break;
796     }
797     sym_info->Scope = 0; /* FIXME */
798     sym_info->Tag = sym->tag;
799     name = symt_get_name(sym);
800     if (sym_info->MaxNameLen)
801     {
802         if (sym->tag != SymTagPublicSymbol || !(dbghelp_options & SYMOPT_UNDNAME) ||
803             (sym_info->NameLen = UnDecorateSymbolName(name, sym_info->Name,
804                                                       sym_info->MaxNameLen, UNDNAME_NAME_ONLY) == 0))
805         {
806             sym_info->NameLen = min(strlen(name), sym_info->MaxNameLen - 1);
807             memcpy(sym_info->Name, name, sym_info->NameLen);
808             sym_info->Name[sym_info->NameLen] = '\0';
809         }
810     }
811     TRACE_(dbghelp_symt)("%p => %s %u %s\n",
812                          sym, sym_info->Name, sym_info->Size,
813                          wine_dbgstr_longlong(sym_info->Address));
814 }
815
816 struct sym_enum
817 {
818     PSYM_ENUMERATESYMBOLS_CALLBACK      cb;
819     PVOID                               user;
820     SYMBOL_INFO*                        sym_info;
821     DWORD                               index;
822     DWORD                               tag;
823     DWORD64                             addr;
824     char                                buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
825 };
826
827 static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
828                         const struct symt_function* func, const struct symt* sym)
829 {
830     symt_fill_sym_info(pair, func, sym, se->sym_info);
831     if (se->index && se->sym_info->info != se->index) return FALSE;
832     if (se->tag && se->sym_info->Tag != se->tag) return FALSE;
833     if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE;
834     return !se->cb(se->sym_info, se->sym_info->Size, se->user);
835 }
836
837 static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex,
838                              const struct sym_enum* se)
839 {
840     void*                       ptr;
841     struct symt_ht*             sym = NULL;
842     struct hash_table_iter      hti;
843
844     hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
845     while ((ptr = hash_table_iter_up(&hti)))
846     {
847         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
848         if (sym->hash_elt.name && match_regexp(regex, sym->hash_elt.name))
849         {
850             se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
851             se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
852             if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
853         }
854     }   
855     return FALSE;
856 }
857
858 static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt)
859 {
860     unsigned    low = 0, mid = high / 2;
861     ULONG64     addr;
862
863     if (!high) return 0;
864     symt_get_info(module, &elt->symt, TI_GET_ADDRESS, &addr);
865     do
866     {
867         switch (cmp_sorttab_addr(module, mid, addr))
868         {
869         case 0: return mid;
870         case -1: low = mid + 1; break;
871         case 1: high = mid; break;
872         }
873         mid = low + (high - low) / 2;
874     } while (low < high);
875     return mid;
876 }
877
878 /***********************************************************************
879  *              resort_symbols
880  *
881  * Rebuild sorted list of symbols for a module.
882  */
883 static BOOL resort_symbols(struct module* module)
884 {
885     if (!(module->module.NumSyms = module->num_symbols))
886         return FALSE;
887
888     /* FIXME: what's the optimal value here ??? */
889     if (module->num_sorttab && module->num_symbols <= module->num_sorttab + 30)
890     {
891         int     i, delta, ins_idx = module->num_sorttab, prev_ins_idx;
892         struct symt_ht* tmp[30];
893
894         delta = module->num_symbols - module->num_sorttab;
895         memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*));
896         symt_cmp_addr_module = module;
897         qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr);
898
899         for (i = delta - 1; i >= 0; i--)
900         {
901             prev_ins_idx = ins_idx;
902             ins_idx = where_to_insert(module, prev_ins_idx = ins_idx, tmp[i]);
903             memmove(&module->addr_sorttab[ins_idx + i + 1],
904                     &module->addr_sorttab[ins_idx],
905                     (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*));
906             module->addr_sorttab[ins_idx + i] = tmp[i];
907         }
908     }
909     else
910     {
911         symt_cmp_addr_module = module;
912         qsort(module->addr_sorttab, module->num_symbols, sizeof(struct symt_ht*), symt_cmp_addr);
913     }
914     module->num_sorttab = module->num_symbols;
915     return module->sortlist_valid = TRUE;
916 }
917
918 static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size)
919 {
920     DWORD       type_index;
921
922     if (symt_get_info(module,  symt, TI_GET_LENGTH, size) && *size)
923         return;
924
925     if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) &&
926         symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return;
927     *size = 0x1000; /* arbitrary value */
928 }
929
930 /* assume addr is in module */
931 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
932 {
933     int         mid, high, low;
934     ULONG64     ref_addr, ref_size;
935
936     if (!module->sortlist_valid || !module->addr_sorttab)
937     {
938         if (!resort_symbols(module)) return NULL;
939     }
940
941     /*
942      * Binary search to find closest symbol.
943      */
944     low = 0;
945     high = module->num_sorttab;
946
947     symt_get_info(module, &module->addr_sorttab[0]->symt, TI_GET_ADDRESS, &ref_addr);
948     if (addr < ref_addr) return NULL;
949     if (high)
950     {
951         symt_get_info(module, &module->addr_sorttab[high - 1]->symt, TI_GET_ADDRESS, &ref_addr);
952         symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size);
953         if (addr >= ref_addr + ref_size) return NULL;
954     }
955     
956     while (high > low + 1)
957     {
958         mid = (high + low) / 2;
959         if (cmp_sorttab_addr(module, mid, addr) < 0)
960             low = mid;
961         else
962             high = mid;
963     }
964     if (low != high && high != module->num_sorttab &&
965         cmp_sorttab_addr(module, high, addr) <= 0)
966         low = high;
967
968     /* If found symbol is a public symbol, check if there are any other entries that
969      * might also have the same address, but would get better information
970      */
971     if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
972     {   
973         symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr);
974         if (low > 0 &&
975             module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol &&
976             !cmp_sorttab_addr(module, low - 1, ref_addr))
977             low--;
978         else if (low < module->num_sorttab - 1 &&
979                  module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol &&
980                  !cmp_sorttab_addr(module, low + 1, ref_addr))
981             low++;
982     }
983     /* finally check that we fit into the found symbol */
984     symt_get_info(module, &module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref_addr);
985     if (addr < ref_addr) return NULL;
986     symt_get_length(module, &module->addr_sorttab[low]->symt, &ref_size);
987     if (addr >= ref_addr + ref_size) return NULL;
988
989     return module->addr_sorttab[low];
990 }
991
992 static BOOL symt_enum_locals_helper(struct module_pair* pair,
993                                     regex_t* preg, const struct sym_enum* se,
994                                     struct symt_function* func, const struct vector* v)
995 {
996     struct symt*        lsym = NULL;
997     DWORD               pc = pair->pcs->ctx_frame.InstructionOffset;
998     unsigned int        i;
999
1000     for (i=0; i<vector_length(v); i++)
1001     {
1002         lsym = *(struct symt**)vector_at(v, i);
1003         switch (lsym->tag)
1004         {
1005         case SymTagBlock:
1006             {
1007                 struct symt_block*  block = (struct symt_block*)lsym;
1008                 if (pc < block->address || block->address + block->size <= pc)
1009                     continue;
1010                 if (!symt_enum_locals_helper(pair, preg, se, func, &block->vchildren))
1011                     return FALSE;
1012             }
1013             break;
1014         case SymTagData:
1015             if (match_regexp(preg, symt_get_name(lsym)))
1016             {
1017                 if (send_symbol(se, pair, func, lsym)) return FALSE;
1018             }
1019             break;
1020         case SymTagLabel:
1021         case SymTagFuncDebugStart:
1022         case SymTagFuncDebugEnd:
1023         case SymTagCustom:
1024             break;
1025         default:
1026             FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
1027             assert(0);
1028         }
1029     }
1030     return TRUE;
1031 }
1032
1033 static BOOL symt_enum_locals(struct process* pcs, const char* mask, 
1034                              const struct sym_enum* se)
1035 {
1036     struct module_pair  pair;
1037     struct symt_ht*     sym;
1038     DWORD_PTR           pc = pcs->ctx_frame.InstructionOffset;
1039
1040     se->sym_info->SizeOfStruct = sizeof(*se->sym_info);
1041     se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
1042
1043     pair.pcs = pcs;
1044     pair.requested = module_find_by_addr(pair.pcs, pc, DMT_UNKNOWN);
1045     if (!module_get_debug(&pair)) return FALSE;
1046     if ((sym = symt_find_nearest(pair.effective, pc)) == NULL) return FALSE;
1047
1048     if (sym->symt.tag == SymTagFunction)
1049     {
1050         BOOL            ret;
1051         regex_t         preg;
1052
1053         compile_regex(mask ? mask : "*", -1, &preg,
1054                       dbghelp_options & SYMOPT_CASE_INSENSITIVE);
1055         ret = symt_enum_locals_helper(&pair, &preg, se, (struct symt_function*)sym,
1056                                       &((struct symt_function*)sym)->vchildren);
1057         regfree(&preg);
1058         return ret;
1059     }
1060     return FALSE;
1061 }
1062
1063 /******************************************************************
1064  *              copy_symbolW
1065  *
1066  * Helper for transforming an ANSI symbol info into a UNICODE one.
1067  * Assume that MaxNameLen is the same for both version (A & W).
1068  */
1069 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
1070 {
1071     siw->SizeOfStruct = si->SizeOfStruct;
1072     siw->TypeIndex = si->TypeIndex; 
1073     siw->Reserved[0] = si->Reserved[0];
1074     siw->Reserved[1] = si->Reserved[1];
1075     siw->Index = si->info; /* FIXME: see dbghelp.h */
1076     siw->Size = si->Size;
1077     siw->ModBase = si->ModBase;
1078     siw->Flags = si->Flags;
1079     siw->Value = si->Value;
1080     siw->Address = si->Address;
1081     siw->Register = si->Register;
1082     siw->Scope = si->Scope;
1083     siw->Tag = si->Tag;
1084     siw->NameLen = si->NameLen;
1085     siw->MaxNameLen = si->MaxNameLen;
1086     MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen);
1087 }
1088
1089 /******************************************************************
1090  *              sym_enum
1091  *
1092  * Core routine for most of the enumeration of symbols
1093  */
1094 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
1095                      const struct sym_enum* se)
1096 {
1097     struct module_pair  pair;
1098     const char*         bang;
1099     regex_t             mod_regex, sym_regex;
1100
1101     pair.pcs = process_find_by_handle(hProcess);
1102     if (!pair.pcs) return FALSE;
1103     if (BaseOfDll == 0)
1104     {
1105         /* do local variables ? */
1106         if (!Mask || !(bang = strchr(Mask, '!')))
1107             return symt_enum_locals(pair.pcs, Mask, se);
1108
1109         if (bang == Mask) return FALSE;
1110
1111         compile_regex(Mask, bang - Mask, &mod_regex, TRUE);
1112         compile_regex(bang + 1, -1, &sym_regex, 
1113                       dbghelp_options & SYMOPT_CASE_INSENSITIVE);
1114         
1115         for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1116         {
1117             if (pair.requested->type == DMT_PE && module_get_debug(&pair))
1118             {
1119                 if (match_regexp(&mod_regex, pair.requested->module_name) &&
1120                     symt_enum_module(&pair, &sym_regex, se))
1121                     break;
1122             }
1123         }
1124         /* not found in PE modules, retry on the ELF ones
1125          */
1126         if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES))
1127         {
1128             for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1129             {
1130                 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) &&
1131                     !module_get_containee(pair.pcs, pair.requested) &&
1132                     module_get_debug(&pair))
1133                 {
1134                     if (match_regexp(&mod_regex, pair.requested->module_name) &&
1135                         symt_enum_module(&pair, &sym_regex, se))
1136                     break;
1137                 }
1138             }
1139         }
1140         regfree(&mod_regex);
1141         regfree(&sym_regex);
1142         return TRUE;
1143     }
1144     pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
1145     if (!module_get_debug(&pair))
1146         return FALSE;
1147
1148     /* we always ignore module name from Mask when BaseOfDll is defined */
1149     if (Mask && (bang = strchr(Mask, '!')))
1150     {
1151         if (bang == Mask) return FALSE;
1152         Mask = bang + 1;
1153     }
1154
1155     compile_regex(Mask ? Mask : "*", -1, &sym_regex, 
1156                   dbghelp_options & SYMOPT_CASE_INSENSITIVE);
1157     symt_enum_module(&pair, &sym_regex, se);
1158     regfree(&sym_regex);
1159
1160     return TRUE;
1161 }
1162
1163 /******************************************************************
1164  *              SymEnumSymbols (DBGHELP.@)
1165  *
1166  * cases BaseOfDll = 0
1167  *      !foo fails always (despite what MSDN states)
1168  *      RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
1169  *      no ! in Mask, lookup in local Context
1170  * cases BaseOfDll != 0
1171  *      !foo fails always (despite what MSDN states)
1172  *      RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
1173  */
1174 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
1175                            PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1176                            PVOID UserContext)
1177 {
1178     struct sym_enum     se;
1179
1180     TRACE("(%p %s %s %p %p)\n", 
1181           hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask),
1182           EnumSymbolsCallback, UserContext);
1183
1184     se.cb = EnumSymbolsCallback;
1185     se.user = UserContext;
1186     se.index = 0;
1187     se.tag = 0;
1188     se.addr = 0;
1189     se.sym_info = (PSYMBOL_INFO)se.buffer;
1190
1191     return sym_enum(hProcess, BaseOfDll, Mask, &se);
1192 }
1193
1194 struct sym_enumW
1195 {
1196     PSYM_ENUMERATESYMBOLS_CALLBACKW     cb;
1197     void*                               ctx;
1198     PSYMBOL_INFOW                       sym_info;
1199     char                                buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME];
1200
1201 };
1202     
1203 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx)
1204 {
1205     struct sym_enumW*   sew = ctx;
1206
1207     copy_symbolW(sew->sym_info, si);
1208
1209     return (sew->cb)(sew->sym_info, size, sew->ctx);
1210 }
1211
1212 /******************************************************************
1213  *              SymEnumSymbolsW (DBGHELP.@)
1214  *
1215  */
1216 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1217                             PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
1218                             PVOID UserContext)
1219 {
1220     struct sym_enumW    sew;
1221     BOOL                ret = FALSE;
1222     char*               maskA = NULL;
1223
1224     sew.ctx = UserContext;
1225     sew.cb = EnumSymbolsCallback;
1226     sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
1227
1228     if (Mask)
1229     {
1230         unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
1231         maskA = HeapAlloc(GetProcessHeap(), 0, len);
1232         if (!maskA) return FALSE;
1233         WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
1234     }
1235     ret = SymEnumSymbols(hProcess, BaseOfDll, maskA, sym_enumW, &sew);
1236     HeapFree(GetProcessHeap(), 0, maskA);
1237
1238     return ret;
1239 }
1240
1241 struct sym_enumerate
1242 {
1243     void*                       ctx;
1244     PSYM_ENUMSYMBOLS_CALLBACK   cb;
1245 };
1246
1247 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1248 {
1249     struct sym_enumerate*       se = ctx;
1250     return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1251 }
1252
1253 /***********************************************************************
1254  *              SymEnumerateSymbols (DBGHELP.@)
1255  */
1256 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
1257                                 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, 
1258                                 PVOID UserContext)
1259 {
1260     struct sym_enumerate        se;
1261
1262     se.ctx = UserContext;
1263     se.cb  = EnumSymbolsCallback;
1264     
1265     return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
1266 }
1267
1268 struct sym_enumerate64
1269 {
1270     void*                       ctx;
1271     PSYM_ENUMSYMBOLS_CALLBACK64 cb;
1272 };
1273
1274 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1275 {
1276     struct sym_enumerate64*     se = ctx;
1277     return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1278 }
1279
1280 /***********************************************************************
1281  *              SymEnumerateSymbols64 (DBGHELP.@)
1282  */
1283 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll,
1284                                   PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,
1285                                   PVOID UserContext)
1286 {
1287     struct sym_enumerate64      se;
1288
1289     se.ctx = UserContext;
1290     se.cb  = EnumSymbolsCallback;
1291
1292     return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se);
1293 }
1294
1295 /******************************************************************
1296  *              SymFromAddr (DBGHELP.@)
1297  *
1298  */
1299 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address, 
1300                         DWORD64* Displacement, PSYMBOL_INFO Symbol)
1301 {
1302     struct module_pair  pair;
1303     struct symt_ht*     sym;
1304
1305     pair.pcs = process_find_by_handle(hProcess);
1306     if (!pair.pcs) return FALSE;
1307     pair.requested = module_find_by_addr(pair.pcs, Address, DMT_UNKNOWN);
1308     if (!module_get_debug(&pair)) return FALSE;
1309     if ((sym = symt_find_nearest(pair.effective, Address)) == NULL) return FALSE;
1310
1311     symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol);
1312     *Displacement = Address - Symbol->Address;
1313     return TRUE;
1314 }
1315
1316 /******************************************************************
1317  *              SymFromAddrW (DBGHELP.@)
1318  *
1319  */
1320 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address, 
1321                          DWORD64* Displacement, PSYMBOL_INFOW Symbol)
1322 {
1323     PSYMBOL_INFO        si;
1324     unsigned            len;
1325     BOOL                ret;
1326
1327     len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR);
1328     si = HeapAlloc(GetProcessHeap(), 0, len);
1329     if (!si) return FALSE;
1330
1331     si->SizeOfStruct = sizeof(*si);
1332     si->MaxNameLen = Symbol->MaxNameLen;
1333     if ((ret = SymFromAddr(hProcess, Address, Displacement, si)))
1334     {
1335         copy_symbolW(Symbol, si);
1336     }
1337     HeapFree(GetProcessHeap(), 0, si);
1338     return ret;
1339 }
1340
1341 /******************************************************************
1342  *              SymGetSymFromAddr (DBGHELP.@)
1343  *
1344  */
1345 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
1346                               PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
1347 {
1348     char        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1349     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1350     size_t      len;
1351     DWORD64     Displacement64;
1352
1353     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1354     si->SizeOfStruct = sizeof(*si);
1355     si->MaxNameLen = MAX_SYM_NAME;
1356     if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1357         return FALSE;
1358
1359     if (Displacement)
1360         *Displacement = Displacement64;
1361     Symbol->Address = si->Address;
1362     Symbol->Size    = si->Size;
1363     Symbol->Flags   = si->Flags;
1364     len = min(Symbol->MaxNameLength, si->MaxNameLen);
1365     lstrcpynA(Symbol->Name, si->Name, len);
1366     return TRUE;
1367 }
1368
1369 /******************************************************************
1370  *              SymGetSymFromAddr64 (DBGHELP.@)
1371  *
1372  */
1373 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address,
1374                                 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol)
1375 {
1376     char        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1377     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1378     size_t      len;
1379     DWORD64     Displacement64;
1380
1381     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1382     si->SizeOfStruct = sizeof(*si);
1383     si->MaxNameLen = MAX_SYM_NAME;
1384     if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1385         return FALSE;
1386
1387     if (Displacement)
1388         *Displacement = Displacement64;
1389     Symbol->Address = si->Address;
1390     Symbol->Size    = si->Size;
1391     Symbol->Flags   = si->Flags;
1392     len = min(Symbol->MaxNameLength, si->MaxNameLen);
1393     lstrcpynA(Symbol->Name, si->Name, len);
1394     return TRUE;
1395 }
1396
1397 static BOOL find_name(struct process* pcs, struct module* module, const char* name,
1398                       SYMBOL_INFO* symbol)
1399 {
1400     struct hash_table_iter      hti;
1401     void*                       ptr;
1402     struct symt_ht*             sym = NULL;
1403     struct module_pair          pair;
1404
1405     pair.pcs = pcs;
1406     if (!(pair.requested = module)) return FALSE;
1407     if (!module_get_debug(&pair)) return FALSE;
1408
1409     hash_table_iter_init(&pair.effective->ht_symbols, &hti, name);
1410     while ((ptr = hash_table_iter_up(&hti)))
1411     {
1412         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
1413
1414         if (!strcmp(sym->hash_elt.name, name))
1415         {
1416             symt_fill_sym_info(&pair, NULL, &sym->symt, symbol);
1417             return TRUE;
1418         }
1419     }
1420     return FALSE;
1421
1422 }
1423 /******************************************************************
1424  *              SymFromName (DBGHELP.@)
1425  *
1426  */
1427 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol)
1428 {
1429     struct process*             pcs = process_find_by_handle(hProcess);
1430     struct module*              module;
1431     const char*                 name;
1432
1433     TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
1434     if (!pcs) return FALSE;
1435     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1436     name = strchr(Name, '!');
1437     if (name)
1438     {
1439         char    tmp[128];
1440         assert(name - Name < sizeof(tmp));
1441         memcpy(tmp, Name, name - Name);
1442         tmp[name - Name] = '\0';
1443         module = module_find_by_nameA(pcs, tmp);
1444         return find_name(pcs, module, name + 1, Symbol);
1445     }
1446     for (module = pcs->lmodules; module; module = module->next)
1447     {
1448         if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol))
1449             return TRUE;
1450     }
1451     /* not found in PE modules, retry on the ELF ones
1452      */
1453     if (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES)
1454     {
1455         for (module = pcs->lmodules; module; module = module->next)
1456         {
1457             if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
1458                 !module_get_containee(pcs, module) &&
1459                 find_name(pcs, module, Name, Symbol))
1460                 return TRUE;
1461         }
1462     }
1463     return FALSE;
1464 }
1465
1466 /***********************************************************************
1467  *              SymGetSymFromName64 (DBGHELP.@)
1468  */
1469 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol)
1470 {
1471     char        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1472     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1473     size_t      len;
1474
1475     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1476     si->SizeOfStruct = sizeof(*si);
1477     si->MaxNameLen = MAX_SYM_NAME;
1478     if (!SymFromName(hProcess, Name, si)) return FALSE;
1479
1480     Symbol->Address = si->Address;
1481     Symbol->Size    = si->Size;
1482     Symbol->Flags   = si->Flags;
1483     len = min(Symbol->MaxNameLength, si->MaxNameLen);
1484     lstrcpynA(Symbol->Name, si->Name, len);
1485     return TRUE;
1486 }
1487
1488 /***********************************************************************
1489  *              SymGetSymFromName (DBGHELP.@)
1490  */
1491 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symbol)
1492 {
1493     char        buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1494     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1495     size_t      len;
1496
1497     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1498     si->SizeOfStruct = sizeof(*si);
1499     si->MaxNameLen = MAX_SYM_NAME;
1500     if (!SymFromName(hProcess, Name, si)) return FALSE;
1501
1502     Symbol->Address = si->Address;
1503     Symbol->Size    = si->Size;
1504     Symbol->Flags   = si->Flags;
1505     len = min(Symbol->MaxNameLength, si->MaxNameLen);
1506     lstrcpynA(Symbol->Name, si->Name, len);
1507     return TRUE;
1508 }
1509
1510 /******************************************************************
1511  *              sym_fill_func_line_info
1512  *
1513  * fills information about a file
1514  */
1515 BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func,
1516                               DWORD64 addr, IMAGEHLP_LINE64* line)
1517 {
1518     struct line_info*   dli = NULL;
1519     BOOL                found = FALSE;
1520     int                 i;
1521
1522     assert(func->symt.tag == SymTagFunction);
1523
1524     for (i=vector_length(&func->vlines)-1; i>=0; i--)
1525     {
1526         dli = vector_at(&func->vlines, i);
1527         if (!dli->is_source_file)
1528         {
1529             if (found || dli->u.pc_offset > addr) continue;
1530             line->LineNumber = dli->line_number;
1531             line->Address    = dli->u.pc_offset;
1532             line->Key        = dli;
1533             found = TRUE;
1534             continue;
1535         }
1536         if (found)
1537         {
1538             line->FileName = (char*)source_get(module, dli->u.source_file);
1539             return TRUE;
1540         }
1541     }
1542     return FALSE;
1543 }
1544
1545 /***********************************************************************
1546  *              SymGetSymNext64 (DBGHELP.@)
1547  */
1548 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1549 {
1550     /* algo:
1551      * get module from Symbol.Address
1552      * get index in module.addr_sorttab of Symbol.Address
1553      * increment index
1554      * if out of module bounds, move to next module in process address space
1555      */
1556     FIXME("(%p, %p): stub\n", hProcess, Symbol);
1557     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1558     return FALSE;
1559 }
1560
1561 /***********************************************************************
1562  *              SymGetSymNext (DBGHELP.@)
1563  */
1564 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1565 {
1566     FIXME("(%p, %p): stub\n", hProcess, Symbol);
1567     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1568     return FALSE;
1569 }
1570
1571 /***********************************************************************
1572  *              SymGetSymPrev64 (DBGHELP.@)
1573  */
1574 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1575 {
1576     FIXME("(%p, %p): stub\n", hProcess, Symbol);
1577     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1578     return FALSE;
1579 }
1580
1581 /***********************************************************************
1582  *              SymGetSymPrev (DBGHELP.@)
1583  */
1584 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1585 {
1586     FIXME("(%p, %p): stub\n", hProcess, Symbol);
1587     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1588     return FALSE;
1589 }
1590
1591 /******************************************************************
1592  *              copy_line_64_from_32 (internal)
1593  *
1594  */
1595 static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32)
1596
1597 {
1598     l64->Key = l32->Key;
1599     l64->LineNumber = l32->LineNumber;
1600     l64->FileName = l32->FileName;
1601     l64->Address = l32->Address;
1602 }
1603
1604 /******************************************************************
1605  *              copy_line_W64_from_32 (internal)
1606  *
1607  */
1608 static void copy_line_W64_from_64(struct process* pcs, IMAGEHLP_LINEW64* l64w, const IMAGEHLP_LINE64* l64)
1609 {
1610     unsigned len;
1611
1612     l64w->Key = l64->Key;
1613     l64w->LineNumber = l64->LineNumber;
1614     len = MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, NULL, 0);
1615     if ((l64w->FileName = fetch_buffer(pcs, len * sizeof(WCHAR))))
1616         MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, l64w->FileName, len);
1617     l64w->Address = l64->Address;
1618 }
1619
1620 /******************************************************************
1621  *              copy_line_32_from_64 (internal)
1622  *
1623  */
1624 static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64)
1625
1626 {
1627     l32->Key = l64->Key;
1628     l32->LineNumber = l64->LineNumber;
1629     l32->FileName = l64->FileName;
1630     l32->Address = l64->Address;
1631 }
1632
1633 /******************************************************************
1634  *              SymGetLineFromAddr (DBGHELP.@)
1635  *
1636  */
1637 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
1638                                PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
1639 {
1640     IMAGEHLP_LINE64     il64;
1641
1642     il64.SizeOfStruct = sizeof(il64);
1643     if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64))
1644         return FALSE;
1645     copy_line_32_from_64(Line, &il64);
1646     return TRUE;
1647 }
1648
1649 /******************************************************************
1650  *              SymGetLineFromAddr64 (DBGHELP.@)
1651  *
1652  */
1653 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, 
1654                                  PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line)
1655 {
1656     struct module_pair  pair;
1657     struct symt_ht*     symt;
1658
1659     TRACE("%p %s %p %p\n", hProcess, wine_dbgstr_longlong(dwAddr), pdwDisplacement, Line);
1660
1661     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1662
1663     pair.pcs = process_find_by_handle(hProcess);
1664     if (!pair.pcs) return FALSE;
1665     pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN);
1666     if (!module_get_debug(&pair)) return FALSE;
1667     if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE;
1668
1669     if (symt->symt.tag != SymTagFunction) return FALSE;
1670     if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt,
1671                                   dwAddr, Line)) return FALSE;
1672     *pdwDisplacement = dwAddr - Line->Address;
1673     return TRUE;
1674 }
1675
1676 /******************************************************************
1677  *              SymGetLineFromAddrW64 (DBGHELP.@)
1678  *
1679  */
1680 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, 
1681                                   PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line)
1682 {
1683     IMAGEHLP_LINE64     il64;
1684
1685     il64.SizeOfStruct = sizeof(il64);
1686     if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64))
1687         return FALSE;
1688     copy_line_W64_from_64(process_find_by_handle(hProcess), Line, &il64);
1689     return TRUE;
1690 }
1691
1692 /******************************************************************
1693  *              SymGetLinePrev64 (DBGHELP.@)
1694  *
1695  */
1696 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
1697 {
1698     struct module_pair  pair;
1699     struct line_info*   li;
1700     BOOL                in_search = FALSE;
1701
1702     TRACE("(%p %p)\n", hProcess, Line);
1703
1704     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1705
1706     pair.pcs = process_find_by_handle(hProcess);
1707     if (!pair.pcs) return FALSE;
1708     pair.requested = module_find_by_addr(pair.pcs, Line->Address, DMT_UNKNOWN);
1709     if (!module_get_debug(&pair)) return FALSE;
1710
1711     if (Line->Key == 0) return FALSE;
1712     li = Line->Key;
1713     /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE
1714      * element we have to go back until we find the prev one to get the real
1715      * source file name for the DLIT_OFFSET element just before 
1716      * the first DLIT_SOURCEFILE
1717      */
1718     while (!li->is_first)
1719     {
1720         li--;
1721         if (!li->is_source_file)
1722         {
1723             Line->LineNumber = li->line_number;
1724             Line->Address    = li->u.pc_offset;
1725             Line->Key        = li;
1726             if (!in_search) return TRUE;
1727         }
1728         else
1729         {
1730             if (in_search)
1731             {
1732                 Line->FileName = (char*)source_get(pair.effective, li->u.source_file);
1733                 return TRUE;
1734             }
1735             in_search = TRUE;
1736         }
1737     }
1738     SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
1739     return FALSE;
1740 }
1741
1742 /******************************************************************
1743  *              SymGetLinePrev (DBGHELP.@)
1744  *
1745  */
1746 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
1747 {
1748     IMAGEHLP_LINE64     line64;
1749
1750     line64.SizeOfStruct = sizeof(line64);
1751     copy_line_64_from_32(&line64, Line);
1752     if (!SymGetLinePrev64(hProcess, &line64)) return FALSE;
1753     copy_line_32_from_64(Line, &line64);
1754     return TRUE;
1755 }
1756
1757 BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line)
1758 {
1759     struct line_info*   li;
1760
1761     if (line->Key == 0) return FALSE;
1762     li = line->Key;
1763     while (!li->is_last)
1764     {
1765         li++;
1766         if (!li->is_source_file)
1767         {
1768             line->LineNumber = li->line_number;
1769             line->Address    = li->u.pc_offset;
1770             line->Key        = li;
1771             return TRUE;
1772         }
1773         line->FileName = (char*)source_get(module, li->u.source_file);
1774     }
1775     return FALSE;
1776 }
1777
1778 /******************************************************************
1779  *              SymGetLineNext64 (DBGHELP.@)
1780  *
1781  */
1782 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
1783 {
1784     struct module_pair  pair;
1785
1786     TRACE("(%p %p)\n", hProcess, Line);
1787
1788     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1789     pair.pcs = process_find_by_handle(hProcess);
1790     if (!pair.pcs) return FALSE;
1791     pair.requested = module_find_by_addr(pair.pcs, Line->Address, DMT_UNKNOWN);
1792     if (!module_get_debug(&pair)) return FALSE;
1793
1794     if (symt_get_func_line_next(pair.effective, Line)) return TRUE;
1795     SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
1796     return FALSE;
1797 }
1798
1799 /******************************************************************
1800  *              SymGetLineNext (DBGHELP.@)
1801  *
1802  */
1803 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
1804 {
1805     IMAGEHLP_LINE64     line64;
1806
1807     line64.SizeOfStruct = sizeof(line64);
1808     copy_line_64_from_32(&line64, Line);
1809     if (!SymGetLineNext64(hProcess, &line64)) return FALSE;
1810     copy_line_32_from_64(Line, &line64);
1811     return TRUE;
1812 }
1813
1814 /***********************************************************************
1815  *              SymUnDName (DBGHELP.@)
1816  */
1817 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength)
1818 {
1819     return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
1820                                 UNDNAME_COMPLETE) != 0;
1821 }
1822
1823 /***********************************************************************
1824  *              SymUnDName64 (DBGHELP.@)
1825  */
1826 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength)
1827 {
1828     return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
1829                                 UNDNAME_COMPLETE) != 0;
1830 }
1831
1832 static void* und_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len); }
1833 static void  und_free (void* ptr)  { HeapFree(GetProcessHeap(), 0, ptr); }
1834
1835 /***********************************************************************
1836  *              UnDecorateSymbolName (DBGHELP.@)
1837  */
1838 DWORD WINAPI UnDecorateSymbolName(PCSTR DecoratedName, PSTR UnDecoratedName,
1839                                   DWORD UndecoratedLength, DWORD Flags)
1840 {
1841     /* undocumented from msvcrt */
1842     static char* (*p_undname)(char*, const char*, int, void* (*)(size_t), void (*)(void*), unsigned short);
1843     static const WCHAR szMsvcrt[] = {'m','s','v','c','r','t','.','d','l','l',0};
1844
1845     TRACE("(%s, %p, %d, 0x%08x)\n",
1846           debugstr_a(DecoratedName), UnDecoratedName, UndecoratedLength, Flags);
1847
1848     if (!p_undname)
1849     {
1850         if (!hMsvcrt) hMsvcrt = LoadLibraryW(szMsvcrt);
1851         if (hMsvcrt) p_undname = (void*)GetProcAddress(hMsvcrt, "__unDName");
1852         if (!p_undname) return 0;
1853     }
1854
1855     if (!UnDecoratedName) return 0;
1856     if (!p_undname(UnDecoratedName, DecoratedName, UndecoratedLength, 
1857                    und_alloc, und_free, Flags))
1858         return 0;
1859     return strlen(UnDecoratedName);
1860 }
1861
1862 /******************************************************************
1863  *              SymMatchString (DBGHELP.@)
1864  *
1865  */
1866 BOOL WINAPI SymMatchString(PCSTR string, PCSTR re, BOOL _case)
1867 {
1868     regex_t     preg;
1869     BOOL        ret;
1870
1871     TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
1872
1873     compile_regex(re, -1, &preg, _case);
1874     ret = match_regexp(&preg, string);
1875     regfree(&preg);
1876     return ret;
1877 }
1878
1879 /******************************************************************
1880  *              SymSearch (DBGHELP.@)
1881  */
1882 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
1883                       DWORD SymTag, PCSTR Mask, DWORD64 Address,
1884                       PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1885                       PVOID UserContext, DWORD Options)
1886 {
1887     struct sym_enum     se;
1888
1889     TRACE("(%p %s %u %u %s %s %p %p %x)\n",
1890           hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask,
1891           wine_dbgstr_longlong(Address), EnumSymbolsCallback,
1892           UserContext, Options);
1893
1894     if (Options != SYMSEARCH_GLOBALSONLY)
1895     {
1896         FIXME("Unsupported searching with options (%x)\n", Options);
1897         SetLastError(ERROR_INVALID_PARAMETER);
1898         return FALSE;
1899     }
1900
1901     se.cb = EnumSymbolsCallback;
1902     se.user = UserContext;
1903     se.index = Index;
1904     se.tag = SymTag;
1905     se.addr = Address;
1906     se.sym_info = (PSYMBOL_INFO)se.buffer;
1907
1908     return sym_enum(hProcess, BaseOfDll, Mask, &se);
1909 }
1910
1911 /******************************************************************
1912  *              SymSearchW (DBGHELP.@)
1913  */
1914 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
1915                        DWORD SymTag, PCWSTR Mask, DWORD64 Address,
1916                        PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
1917                        PVOID UserContext, DWORD Options)
1918 {
1919     struct sym_enumW    sew;
1920     BOOL                ret = FALSE;
1921     char*               maskA = NULL;
1922
1923     TRACE("(%p %s %u %u %s %s %p %p %x)\n",
1924           hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_w(Mask),
1925           wine_dbgstr_longlong(Address), EnumSymbolsCallback,
1926           UserContext, Options);
1927
1928     sew.ctx = UserContext;
1929     sew.cb = EnumSymbolsCallback;
1930     sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
1931
1932     if (Mask)
1933     {
1934         unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
1935         maskA = HeapAlloc(GetProcessHeap(), 0, len);
1936         if (!maskA) return FALSE;
1937         WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
1938     }
1939     ret = SymSearch(hProcess, BaseOfDll, Index, SymTag, maskA, Address,
1940                     sym_enumW, &sew, Options);
1941     HeapFree(GetProcessHeap(), 0, maskA);
1942
1943     return ret;
1944 }
1945
1946 /******************************************************************
1947  *              SymAddSymbol (DBGHELP.@)
1948  *
1949  */
1950 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name,
1951                          DWORD64 addr, DWORD size, DWORD flags)
1952 {
1953     WCHAR       nameW[MAX_SYM_NAME];
1954
1955     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1956     return SymAddSymbolW(hProcess, BaseOfDll, nameW, addr, size, flags);
1957 }
1958
1959 /******************************************************************
1960  *              SymAddSymbolW (DBGHELP.@)
1961  *
1962  */
1963 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR name,
1964                           DWORD64 addr, DWORD size, DWORD flags)
1965 {
1966     struct module_pair  pair;
1967
1968     TRACE("(%p %s %s %u)\n", hProcess, wine_dbgstr_w(name), wine_dbgstr_longlong(addr), size);
1969
1970     pair.pcs = process_find_by_handle(hProcess);
1971     if (!pair.pcs) return FALSE;
1972     pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
1973     if (!module_get_debug(&pair)) return FALSE;
1974
1975     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1976     return FALSE;
1977 }
1978
1979 /******************************************************************
1980  *              SymSetScopeFromAddr (DBGHELP.@)
1981  */
1982 BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr)
1983 {
1984     struct process*     pcs;
1985
1986     FIXME("(%p %s): stub\n", hProcess, wine_dbgstr_longlong(addr));
1987
1988     if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
1989     return TRUE;
1990 }
1991
1992 /******************************************************************
1993  *              SymEnumLines (DBGHELP.@)
1994  *
1995  */
1996 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
1997                          PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
1998 {
1999     struct module_pair          pair;
2000     struct hash_table_iter      hti;
2001     struct symt_ht*             sym;
2002     regex_t                     re;
2003     struct line_info*           dli;
2004     void*                       ptr;
2005     SRCCODEINFO                 sci;
2006     const char*                 file;
2007
2008     if (!cb) return FALSE;
2009     if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
2010
2011     pair.pcs = process_find_by_handle(hProcess);
2012     if (!pair.pcs) return FALSE;
2013     if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
2014     pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN);
2015     if (!module_get_debug(&pair)) return FALSE;
2016     if (!compile_file_regex(&re, srcfile)) return FALSE;
2017
2018     sci.SizeOfStruct = sizeof(sci);
2019     sci.ModBase      = base;
2020
2021     hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
2022     while ((ptr = hash_table_iter_up(&hti)))
2023     {
2024         unsigned int    i;
2025
2026         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
2027         if (sym->symt.tag != SymTagFunction) continue;
2028
2029         sci.FileName[0] = '\0';
2030         for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
2031         {
2032             dli = vector_at(&((struct symt_function*)sym)->vlines, i);
2033             if (dli->is_source_file)
2034             {
2035                 file = source_get(pair.effective, dli->u.source_file);
2036                 if (!match_regexp(&re, file)) sci.FileName[0] = '\0';
2037                 else strcpy(sci.FileName, file);
2038             }
2039             else if (sci.FileName[0])
2040             {
2041                 sci.Key = dli;
2042                 sci.Obj[0] = '\0'; /* FIXME */
2043                 sci.LineNumber = dli->line_number;
2044                 sci.Address = dli->u.pc_offset;
2045                 if (!cb(&sci, user)) break;
2046             }
2047         }
2048     }
2049     regfree(&re);
2050     return TRUE;
2051 }
2052
2053 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2054                 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line)
2055 {
2056     FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName,
2057                 dwLineNumber, plDisplacement, Line);
2058     return FALSE;
2059 }
2060
2061 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2062                 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line)
2063 {
2064     FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName,
2065                 dwLineNumber, lpDisplacement, Line);
2066     return FALSE;
2067 }
2068
2069 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName,
2070                 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line)
2071 {
2072     FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName),
2073                 dwLineNumber, plDisplacement, Line);
2074     return FALSE;
2075 }