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