Started implementing support for the SubSystemTib field in the TEB of
[wine] / dlls / dbghelp / symbol.c
1 /*
2  * File symbol.c - management of symbols (lexical tree)
3  *
4  * Copyright (C) 1993, Eric Youngdale.
5  *               2004, Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22
23 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <sys/types.h>
29 #include <assert.h>
30 #include <regex.h>
31 #include "wine/debug.h"
32
33 #include "dbghelp_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
36 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symtype);
37
38 #define DLIT_OFFSET     0x00
39 #define DLIT_FIRST      0x01
40 #define DLIT_LAST       0x02
41 #define DLIT_SOURCEFILE 0x04
42
43 struct line_info
44 {
45     unsigned long               cookie : 3,
46                                 line_number;
47     union
48     {
49         unsigned long               pc_offset;
50         unsigned                    source_file;
51     } u;
52 };
53
54 inline static int cmp_addr(DWORD a1, DWORD a2)
55 {
56     if (a1 > a2) return 1;
57     if (a1 < a2) return -1;
58     return 0;
59 }
60
61 inline static int cmp_sorttab_addr(const struct module* module, int idx, DWORD addr)
62 {
63     DWORD       ref;
64
65     symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
66     return cmp_addr(ref, addr);
67 }
68
69 int symt_cmp_addr(const void* p1, const void* p2)
70 {
71     struct symt*        sym1 = *(struct symt**)p1;
72     struct symt*        sym2 = *(struct symt**)p2;
73     DWORD               a1, a2;
74
75     symt_get_info(sym1, TI_GET_ADDRESS, &a1);
76     symt_get_info(sym2, TI_GET_ADDRESS, &a2);
77     return cmp_addr(a1, a2);
78 }
79
80 struct symt_compiland* symt_new_compiland(struct module* module, const char* name)
81 {
82     struct symt_compiland*    sym;
83
84     TRACE_(dbghelp_symtype)("Adding compiland symbol %s:%s\n", 
85                             module->module.ModuleName, name);
86     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
87     {
88         sym->symt.tag = SymTagCompiland;
89         sym->source   = source_new(module, name);
90         vector_init(&sym->vchildren, sizeof(struct symt*), 32);
91     }
92     return sym;
93 }
94
95 struct symt_public* symt_new_public(struct module* module, 
96                                     struct symt_compiland* compiland,
97                                     const char* name,
98                                     unsigned long address, unsigned size,
99                                     BOOL in_code, BOOL is_func)
100 {
101     struct symt_public* sym;
102     struct symt**       p;
103
104     TRACE_(dbghelp_symtype)("Adding public symbol %s:%s @%lx\n", 
105                             module->module.ModuleName, name, address);
106     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
107     {
108         sym->symt.tag      = SymTagPublicSymbol;
109         sym->hash_elt.name = pool_strdup(&module->pool, name);
110         hash_table_add(&module->ht_symbols, &sym->hash_elt);
111         module->sortlist_valid = FALSE;
112         sym->container     = compiland ? &compiland->symt : NULL;
113         sym->address       = address;
114         sym->size          = size;
115         sym->in_code       = in_code;
116         sym->is_function   = is_func;
117         if (compiland)
118         {
119             p = vector_add(&compiland->vchildren, &module->pool);
120             *p = &sym->symt;
121         }
122     }
123     return sym;
124 }
125
126 struct symt_data* symt_new_global_variable(struct module* module, 
127                                            struct symt_compiland* compiland, 
128                                            const char* name, unsigned is_static,
129                                            unsigned long addr, unsigned long size,
130                                            struct symt* type)
131 {
132     struct symt_data*   sym;
133     struct symt**       p;
134
135     TRACE_(dbghelp_symtype)("Adding global symbol %s:%s @%lx %p\n", 
136                             module->module.ModuleName, name, addr, type);
137     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
138     {
139         sym->symt.tag      = SymTagData;
140         sym->hash_elt.name = pool_strdup(&module->pool, name);
141         hash_table_add(&module->ht_symbols, &sym->hash_elt);
142         module->sortlist_valid = FALSE;
143         sym->kind          = is_static ? DataIsFileStatic : DataIsGlobal;
144         sym->container     = compiland ? &compiland->symt : NULL;
145         sym->type          = type;
146         sym->location      = LocIsStatic; /* FIXME */
147         sym->u.address     = addr;
148         if (compiland)
149         {
150             p = vector_add(&compiland->vchildren, &module->pool);
151             *p = &sym->symt;
152         }
153     }
154     return sym;
155 }
156
157 struct symt_function* symt_new_function(struct module* module, 
158                                         struct symt_compiland* compiland, 
159                                         const char* name,
160                                         unsigned long addr, unsigned long size,
161                                         struct symt* type)
162 {
163     struct symt_function*       sym;
164     struct symt**               p;
165
166     TRACE_(dbghelp_symtype)("Adding global function %s:%s @%lx-%lx\n", 
167                             module->module.ModuleName, name, addr, addr + size - 1);
168     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
169     {
170         sym->symt.tag  = SymTagFunction;
171         sym->hash_elt.name = pool_strdup(&module->pool, name);
172         hash_table_add(&module->ht_symbols, &sym->hash_elt);
173         module->sortlist_valid = FALSE;
174         sym->container = &compiland->symt;
175         sym->addr      = addr;
176         sym->type      = type;
177         sym->size      = size;
178         sym->addr      = addr;
179         vector_init(&sym->vlines,  sizeof(struct line_info), 64);
180         vector_init(&sym->vchildren, sizeof(struct symt*), 8);
181         if (compiland)
182         {
183             p = vector_add(&compiland->vchildren, &module->pool);
184             *p = &sym->symt;
185         }
186     }
187     return sym;
188 }
189
190 void symt_add_func_line(struct module* module, struct symt_function* func,
191                         unsigned source_idx, int line_num, unsigned long offset)
192 {
193     struct line_info*   dli;
194     BOOL                last_matches = FALSE;
195
196     if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
197
198     TRACE_(dbghelp_symtype)("(%p)%s:%lx %s:%u\n", 
199                             func, func->hash_elt.name, offset, 
200                             source_get(module, source_idx), line_num);
201
202     assert(func->symt.tag == SymTagFunction);
203
204     dli = NULL;
205     while ((dli = vector_iter_down(&func->vlines, dli)))
206     {
207         if (dli->cookie & DLIT_SOURCEFILE)
208         {
209             last_matches = (source_idx == dli->u.source_file);
210             break;
211         }
212     }
213
214     if (!last_matches)
215     {
216         /* we shouldn't have line changes on first line of function */
217         dli = vector_add(&func->vlines, &module->pool);
218         dli->cookie        = DLIT_SOURCEFILE;
219         dli->line_number   = 0;
220         dli->u.source_file = source_idx;
221     }
222     dli = vector_add(&func->vlines, &module->pool);
223     dli->cookie      = DLIT_OFFSET;
224     dli->line_number = line_num;
225     dli->u.pc_offset = func->addr + offset;
226 }
227
228 struct symt_data* symt_add_func_local(struct module* module, 
229                                       struct symt_function* func, 
230                                       int regno, int offset, 
231                                       struct symt_block* block, 
232                                       struct symt* type, const char* name)
233 {
234     struct symt_data*   locsym;
235     struct symt**       p;
236
237     assert(func);
238     assert(func->symt.tag == SymTagFunction);
239
240     TRACE_(dbghelp_symtype)("Adding local symbol (%s:%s): %s %p\n", 
241                             module->module.ModuleName, func->hash_elt.name, 
242                             name, type);
243     locsym = pool_alloc(&module->pool, sizeof(*locsym));
244     locsym->symt.tag      = SymTagData;
245     locsym->hash_elt.name = pool_strdup(&module->pool, name);
246     locsym->hash_elt.next = NULL;
247     locsym->kind          = DataIsLocal;
248     locsym->container     = &block->symt;
249     locsym->type          = type;
250     if (regno)
251     {
252         locsym->location = LocIsEnregistered;
253         locsym->u.reg_id = regno;
254     }
255     else
256     {
257         locsym->location = LocIsRegRel;
258         locsym->u.reg_id = CV_REG_EBP;
259         locsym->u.offset = offset;
260     }
261     if (block)
262         p = vector_add(&block->vchildren, &module->pool);
263     else
264         p = vector_add(&func->vchildren, &module->pool);
265     *p = &locsym->symt;
266     return locsym;
267 }
268
269 struct symt_block* symt_open_func_block(struct module* module, 
270                                         struct symt_function* func,
271                                         struct symt_block* parent_block, 
272                                         unsigned pc)
273 {
274     struct symt_block*  block;
275     struct symt**       p;
276
277     assert(func);
278     assert(func->symt.tag == SymTagFunction);
279
280     assert(!parent_block || parent_block->symt.tag == SymTagBlock);
281     block = pool_alloc(&module->pool, sizeof(*block));
282     block->symt.tag         = SymTagBlock;
283     block->address = func->addr + pc;
284     block->size    = 0;
285     block->container = parent_block ? &parent_block->symt : &func->symt;
286     vector_init(&block->vchildren, sizeof(struct symt*), 4);
287     if (parent_block)
288         p = vector_add(&parent_block->vchildren, &module->pool);
289     else
290         p = vector_add(&func->vchildren, &module->pool);
291     *p = &block->symt;
292
293     return block;
294 }
295
296 struct symt_block* symt_close_func_block(struct module* module, 
297                                          struct symt_function* func,
298                                          struct symt_block* block, unsigned pc)
299 {
300     assert(func->symt.tag == SymTagFunction);
301
302     block->size = func->addr + pc - block->address;
303     return (block->container->tag == SymTagBlock) ? 
304         GET_ENTRY(block->container, struct symt_block, symt) : NULL;
305 }
306
307 BOOL symt_normalize_function(struct module* module, struct symt_function* func)
308 {
309     unsigned            len;
310     struct line_info*   dli;
311
312     if (!func) return TRUE;
313     /* We aren't adding any more locals or line numbers to this function.
314      * Free any spare memory that we might have allocated.
315      */
316     assert(func->symt.tag == SymTagFunction);
317
318 /* EPP     vector_pool_normalize(&func->vlines,    &module->pool); */
319 /* EPP     vector_pool_normalize(&func->vchildren, &module->pool); */
320
321     len = vector_length(&func->vlines);
322     if (len--)
323     {
324         dli = vector_at(&func->vlines,   0);  dli->cookie |= DLIT_FIRST;
325         dli = vector_at(&func->vlines, len);  dli->cookie |= DLIT_LAST;
326     }
327     return TRUE;
328 }
329
330 /* expect sym_info->MaxNameLen to be set before being called */
331 static void symt_fill_sym_info(const struct module* module, 
332                                const struct symt* sym, SYMBOL_INFO* sym_info)
333 {
334     const char* name;
335
336     sym_info->TypeIndex = (DWORD)sym;
337     sym_info->info = 0; /* TBD */
338     symt_get_info(sym, TI_GET_LENGTH, &sym_info->Size);
339     sym_info->ModBase = module->module.BaseOfImage;
340     sym_info->Flags = 0;
341     switch (sym->tag)
342     {
343     case SymTagData:
344         {
345             struct symt_data*  data = (struct symt_data*)sym;
346             switch (data->location)
347             {
348             case LocIsEnregistered:
349                 sym_info->Flags |= SYMFLAG_REGISTER;
350                 sym_info->Register = data->u.reg_id;
351                 sym_info->Address = 0;
352                 break;
353             case LocIsRegRel:
354                 sym_info->Flags |= 
355                     ((data->u.offset < 0) ? SYMFLAG_LOCAL : SYMFLAG_PARAMETER) |
356                     SYMFLAG_FRAMEREL;
357                 sym_info->Register = data->u.reg_id;
358                 sym_info->Address = data->u.offset;
359                 break;
360             case LocIsStatic:
361                 symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
362                 sym_info->Register = 0;
363                 break;
364             case LocIsConstant:
365                 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
366                 sym_info->Value = data->u.value;
367                 break;
368             default:
369                 FIXME("Unhandled loc (%u) in sym data\n", data->location);
370             }
371         }
372         break;
373     case SymTagPublicSymbol:
374         sym_info->Flags |= SYMFLAG_EXPORT;
375         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
376         break;
377     case SymTagFunction:
378         sym_info->Flags |= SYMFLAG_FUNCTION;
379         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
380         break;
381     default:
382         symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
383         sym_info->Register = 0;
384         break;
385     }
386     sym_info->Scope = 0; /* FIXME */
387     sym_info->Tag = sym->tag;
388     name = symt_get_name(sym);
389     sym_info->NameLen = strlen(name) + 1;
390     if (sym_info->MaxNameLen)
391     {
392         strncpy(sym_info->Name, name, min(sym_info->NameLen, sym_info->MaxNameLen));
393         sym_info->Name[sym_info->MaxNameLen - 1] = '\0';
394     }
395     TRACE_(dbghelp_symtype)("%p => %s %lu %lx\n",
396                             sym, sym_info->Name, sym_info->Size, sym_info->Address);
397 }
398
399 static BOOL symt_enum_module(struct module* module, const char* mask,
400                              PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
401 {
402     char                        buffer[sizeof(SYMBOL_INFO) + 256];
403     SYMBOL_INFO*                sym_info = (SYMBOL_INFO*)buffer;
404     void*                       ptr;
405     struct symt_ht*             sym = NULL;
406     struct hash_table_iter      hti;
407     regex_t                     preg;
408
409     assert(mask);
410     assert(mask[0] != '!');
411     regcomp(&preg, mask, REG_NOSUB);
412     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
413     while ((ptr = hash_table_iter_up(&hti)))
414     {
415         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
416         /* FIXME: this is not true, we should only drop the public
417          * symbol iff no other one is found
418          */
419         if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
420             sym->symt.tag == SymTagPublicSymbol) continue;
421
422         if (sym->hash_elt.name &&
423             regexec(&preg, sym->hash_elt.name, 0, NULL, 0) == 0)
424         {
425             sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
426             sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
427             symt_fill_sym_info(module, &sym->symt, sym_info);
428             if (!cb(sym_info, sym_info->Size, user)) break;
429         }
430     }   
431     regfree(&preg);
432     return sym ? FALSE : TRUE;
433 }
434
435 /***********************************************************************
436  *              resort_symbols
437  *
438  * Rebuild sorted list of symbols for a module.
439  */
440 static BOOL resort_symbols(struct module* module)
441 {
442     int                         nsym = 0;
443     void*                       ptr;
444     struct symt_ht*             sym;
445     struct hash_table_iter      hti;
446
447     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
448     while ((ptr = hash_table_iter_up(&hti)))
449         nsym++;
450
451     if (!(module->module.NumSyms = nsym)) return FALSE;
452     
453     if (module->addr_sorttab)
454         module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0,
455                                            module->addr_sorttab, 
456                                            nsym * sizeof(struct symt_ht*));
457     else
458         module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0,
459                                          nsym * sizeof(struct symt_ht*));
460     if (!module->addr_sorttab) return FALSE;
461
462     nsym = 0;
463     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
464     while ((ptr = hash_table_iter_up(&hti)))
465     {
466         sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
467         assert(sym);
468         module->addr_sorttab[nsym++] = sym;
469     }
470     
471     qsort(module->addr_sorttab, nsym, sizeof(struct symt_ht*), symt_cmp_addr);
472     return module->sortlist_valid = TRUE;
473 }
474
475 /* assume addr is in module */
476 static int symt_find_nearest(struct module* module, DWORD addr)
477 {
478     int         mid, high, low;
479
480     if (!module->sortlist_valid && !resort_symbols(module)) return -1;
481
482     /*
483      * Binary search to find closest symbol.
484      */
485     low = 0;
486     high = module->module.NumSyms;
487     
488     while (high > low + 1)
489     {
490         mid = (high + low) / 2;
491         if (cmp_sorttab_addr(module, mid, addr) < 0)
492             low = mid;
493         else
494             high = mid;
495     }
496     if (low != high && high != module->module.NumSyms && 
497         cmp_sorttab_addr(module, high, addr) <= 0)
498         low = high;
499
500     /* If found symbol is a public symbol, check if there are any other entries that
501      * might also have the same address, but would get better information
502      */
503     if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
504     {   
505         DWORD   ref;
506
507         symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref);
508         if (low > 0 &&
509             module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol &&
510             !cmp_sorttab_addr(module, low - 1, ref))
511             low--;
512         else if (low < module->module.NumSyms - 1 && 
513                  module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol &&
514                  !cmp_sorttab_addr(module, low + 1, ref))
515             low++;
516     }
517
518     return low;
519 }
520
521 static BOOL symt_enum_locals_helper(struct process* pcs, struct module* module,
522                                     regex_t* preg, PSYM_ENUMERATESYMBOLS_CALLBACK cb,
523                                     PVOID user, SYMBOL_INFO* sym_info,
524                                     struct vector* v)
525 {
526     struct symt**       plsym = NULL;
527     struct symt*        lsym = NULL;
528     DWORD               pc = pcs->ctx_frame.InstructionOffset;
529
530     while ((plsym = vector_iter_up(v, plsym)))
531     {
532         lsym = *plsym;
533         switch (lsym->tag)
534         {
535         case SymTagBlock:
536             {
537                 struct symt_block*  block = (struct symt_block*)lsym;
538                 if (pc < block->address || block->address + block->size <= pc)
539                     continue;
540                 if (!symt_enum_locals_helper(pcs, module, preg, cb, user, 
541                                              sym_info, &block->vchildren))
542                     return FALSE;
543             }
544             break;
545         case SymTagData:
546             if (regexec(preg, symt_get_name(lsym), 0, NULL, 0) == 0)
547             {
548                 symt_fill_sym_info(module, lsym, sym_info);
549                 if (!cb(sym_info, sym_info->Size, user))
550                     return FALSE;
551             }
552             break;
553         default:
554             FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
555             assert(0);
556         }
557     }
558     return TRUE;
559 }
560
561 static BOOL symt_enum_locals(struct process* pcs, const char* mask,
562                              PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
563                              PVOID UserContext)
564 {
565     struct module*      module;
566     struct symt_ht*     sym;
567     char                buffer[sizeof(SYMBOL_INFO) + 256];
568     SYMBOL_INFO*        sym_info = (SYMBOL_INFO*)buffer;
569     DWORD               pc = pcs->ctx_frame.InstructionOffset;
570     int                 idx;
571
572     sym_info->SizeOfStruct = sizeof(*sym_info);
573     sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
574
575     module = module_find_by_addr(pcs, pc, DMT_UNKNOWN);
576     if (!(module = module_get_debug(pcs, module))) return FALSE;
577     if ((idx = symt_find_nearest(module, pc)) == -1) return FALSE;
578
579     sym = module->addr_sorttab[idx];
580     if (sym->symt.tag == SymTagFunction)
581     {
582         BOOL            ret;
583         regex_t         preg;
584
585         regcomp(&preg, mask ? mask : ".*", REG_NOSUB);
586         ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback, 
587                                       UserContext, sym_info, 
588                                       &((struct symt_function*)sym)->vchildren);
589         regfree(&preg);
590         return ret;
591         
592     }
593     symt_fill_sym_info(module, &sym->symt, sym_info);
594     return EnumSymbolsCallback(sym_info, sym_info->Size, UserContext);
595 }
596
597 /******************************************************************
598  *              SymEnumSymbols (DBGHELP.@)
599  *
600  */
601 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask,
602                            PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
603                            PVOID UserContext)
604 {
605     struct process*     pcs = process_find_by_handle(hProcess);
606     struct module*      module;
607
608     TRACE("(%p %08lx %s %p %p)\n", 
609           hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
610
611     if (!pcs) return FALSE;
612
613     if (BaseOfDll == 0)
614     {
615         if (Mask && Mask[0] == '!')
616         {
617             if (!Mask[1])
618             {
619                 /* FIXME: is this really what's intended ??? */
620                 for (module = pcs->lmodules; module; module = module->next)
621                 {
622                     if (module->module.SymType != SymNone &&
623                         !symt_enum_module(module, ".*", EnumSymbolsCallback, UserContext))
624                         break;
625                 }
626                 return TRUE;
627             }
628             module = module_find_by_name(pcs, &Mask[1], DMT_UNKNOWN);
629             Mask++;
630         }
631         else return symt_enum_locals(pcs, Mask, EnumSymbolsCallback, UserContext);
632     }
633     else
634     {
635         module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
636         if (Mask && Mask[0] == '!')
637         {
638             if (!Mask[1] ||
639                 strcmp(&Mask[1], module->module.ModuleName))
640             {
641                 FIXME("Strange call mode\n");
642                 return FALSE;
643             }
644             Mask = ".*";
645         }
646         else if (!Mask) Mask = ".*";
647     }
648     if ((module = module_get_debug(pcs, module)))
649         symt_enum_module(module, Mask, EnumSymbolsCallback, UserContext);
650     return TRUE;
651 }
652
653 struct sym_enumerate
654 {
655     void*                       ctx;
656     PSYM_ENUMSYMBOLS_CALLBACK   cb;
657 };
658
659 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
660 {
661     struct sym_enumerate*       se = (struct sym_enumerate*)ctx;
662     return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
663 }
664
665 /***********************************************************************
666  *              SymEnumerateSymbols (DBGHELP.@)
667  */
668 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
669                                 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, 
670                                 PVOID UserContext)
671 {
672     struct sym_enumerate        se;
673
674     se.ctx = UserContext;
675     se.cb  = EnumSymbolsCallback;
676     
677     return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
678 }
679
680 /******************************************************************
681  *              SymFromAddr (DBGHELP.@)
682  *
683  */
684 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD Address, 
685                         DWORD* Displacement, PSYMBOL_INFO Symbol)
686 {
687     struct process*     pcs = process_find_by_handle(hProcess);
688     struct module*      module;
689     struct symt_ht*     sym;
690     int                 idx;
691
692     if (!pcs) return FALSE;
693     module = module_find_by_addr(pcs, Address, DMT_UNKNOWN);
694     if (!(module = module_get_debug(pcs, module))) return FALSE;
695     if ((idx = symt_find_nearest(module, Address)) == -1) return FALSE;
696
697     sym = module->addr_sorttab[idx];
698
699     symt_fill_sym_info(module, &sym->symt, Symbol);
700     if (Displacement) *Displacement = Address - Symbol->Address;
701     return TRUE;
702 }
703
704 /******************************************************************
705  *              SymGetSymFromAddr (DBGHELP.@)
706  *
707  */
708 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
709                               PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
710 {
711     char        buffer[sizeof(SYMBOL_INFO) + 256];
712     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
713     size_t      len;
714
715     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
716     si->SizeOfStruct = sizeof(*si);
717     si->MaxNameLen = 256;
718     if (!SymFromAddr(hProcess, Address, Displacement, si))
719         return FALSE;
720
721     Symbol->Address = si->Address;
722     Symbol->Size    = si->Size;
723     Symbol->Flags   = si->Flags;
724     len = min(Symbol->MaxNameLength, si->MaxNameLen);
725     strncpy(Symbol->Name, si->Name, len);
726     Symbol->Name[len - 1] = '\0';
727     return TRUE;
728 }
729
730 /******************************************************************
731  *              SymFromName (DBGHELP.@)
732  *
733  */
734 BOOL WINAPI SymFromName(HANDLE hProcess, LPSTR Name, PSYMBOL_INFO Symbol)
735 {
736     struct process*             pcs = process_find_by_handle(hProcess);
737     struct module*              module;
738     struct hash_table_iter      hti;
739     void*                       ptr;
740     struct symt_ht*             sym = NULL;
741
742     TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
743     if (!pcs) return FALSE;
744     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
745     for (module = pcs->lmodules; module; module = module->next)
746     {
747         if (module->module.SymType != SymNone)
748         {
749             if (module->module.SymType == SymDeferred)
750             {
751                 struct module*  xmodule = module_get_debug(pcs, module);
752                 if (!xmodule) continue;
753                 module = xmodule;
754             }
755             hash_table_iter_init(&module->ht_symbols, &hti, Name);
756             while ((ptr = hash_table_iter_up(&hti)))
757             {
758                 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
759
760                 if (!strcmp(sym->hash_elt.name, Name))
761                 {
762                     symt_fill_sym_info(module, &sym->symt, Symbol);
763                     return TRUE;
764                 }
765             }
766         }
767     }
768     return FALSE;
769 }
770
771 /***********************************************************************
772  *              SymGetSymFromName (DBGHELP.@)
773  */
774 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, LPSTR Name, PIMAGEHLP_SYMBOL Symbol)
775 {
776     char        buffer[sizeof(SYMBOL_INFO) + 256];
777     SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
778     size_t      len;
779
780     if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
781     si->SizeOfStruct = sizeof(*si);
782     si->MaxNameLen = 256;
783     if (!SymFromName(hProcess, Name, si)) return FALSE;
784
785     Symbol->Address = si->Address;
786     Symbol->Size    = si->Size;
787     Symbol->Flags   = si->Flags;
788     len = min(Symbol->MaxNameLength, si->MaxNameLen);
789     strncpy(Symbol->Name, si->Name, len);
790     Symbol->Name[len - 1] = '\0';
791     return TRUE;
792 }
793
794 /******************************************************************
795  *              fill_line_info
796  *
797  * fills information about a file
798  */
799 static BOOL fill_line_info(struct module* module, struct symt_function* func, 
800                            DWORD addr, IMAGEHLP_LINE* line)
801 {
802     struct line_info*   dli = NULL;
803     BOOL                found = FALSE;
804
805     assert(func->symt.tag == SymTagFunction);
806
807     while ((dli = vector_iter_down(&func->vlines, dli)))
808     {
809         if (!(dli->cookie & DLIT_SOURCEFILE))
810         {
811             if (found || dli->u.pc_offset > addr) continue;
812             line->LineNumber = dli->line_number;
813             line->Address    = dli->u.pc_offset;
814             line->Key        = dli;
815             found = TRUE;
816             continue;
817         }
818         if (found)
819         {
820             line->FileName = (char*)source_get(module, dli->u.source_file);
821             return TRUE;
822         }
823     }
824     return FALSE;
825 }
826
827 /***********************************************************************
828  *              SymGetSymNext (DBGHELP.@)
829  */
830 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
831 {
832     /* algo:
833      * get module from Symbol.Address
834      * get index in module.addr_sorttab of Symbol.Address
835      * increment index
836      * if out of module bounds, move to next module in process address space
837      */
838     FIXME("(%p, %p): stub\n", hProcess, Symbol);
839     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840     return FALSE;
841 }
842
843 /***********************************************************************
844  *              SymGetSymPrev (DBGHELP.@)
845  */
846
847 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
848 {
849     FIXME("(%p, %p): stub\n", hProcess, Symbol);
850     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
851     return FALSE;
852 }
853
854 /******************************************************************
855  *              SymGetLineFromAddr (DBGHELP.@)
856  *
857  */
858 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, 
859                                PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
860 {
861     struct process*     pcs = process_find_by_handle(hProcess);
862     struct module*      module;
863     int                 idx;
864
865     TRACE("%p %08lx %p %p\n", hProcess, dwAddr, pdwDisplacement, Line);
866
867     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
868
869     if (!pcs) return FALSE;
870     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
871     if (!(module = module_get_debug(pcs, module))) return FALSE;
872     if ((idx = symt_find_nearest(module, dwAddr)) == -1) return FALSE;
873
874     if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE;
875     if (!fill_line_info(module, 
876                         (struct symt_function*)module->addr_sorttab[idx],
877                         dwAddr, Line)) return FALSE;
878     if (pdwDisplacement) *pdwDisplacement = dwAddr - Line->Address;
879     return TRUE;
880 }
881
882 /******************************************************************
883  *              SymGetLinePrev (DBGHELP.@)
884  *
885  */
886 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
887 {
888     struct process*     pcs = process_find_by_handle(hProcess);
889     struct module*      module;
890     struct line_info*   li;
891     BOOL                in_search = FALSE;
892
893     TRACE("(%p %p)\n", hProcess, Line);
894
895     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
896
897     if (!pcs) return FALSE;
898     module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
899     if (!(module = module_get_debug(pcs, module))) return FALSE;
900
901     if (Line->Key == 0) return FALSE;
902     li = (struct line_info*)Line->Key;
903     /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE
904      * element we have to go back until we find the prev one to get the real
905      * source file name for the DLIT_OFFSET element just before 
906      * the first DLIT_SOURCEFILE
907      */
908     while (!(li->cookie & DLIT_FIRST))
909     {
910         li--;
911         if (!(li->cookie & DLIT_SOURCEFILE))
912         {
913             Line->LineNumber = li->line_number;
914             Line->Address    = li->u.pc_offset;
915             Line->Key        = li;
916             if (!in_search) return TRUE;
917         }
918         else
919         {
920             if (in_search)
921             {
922                 Line->FileName = (char*)source_get(module, li->u.source_file);
923                 return TRUE;
924             }
925             in_search = TRUE;
926         }
927     }
928     SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
929     return FALSE;
930 }
931
932 /******************************************************************
933  *              SymGetLineNext (DBGHELP.@)
934  *
935  */
936 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
937 {
938     struct process*     pcs = process_find_by_handle(hProcess);
939     struct module*      module;
940     struct line_info*   li;
941
942     TRACE("(%p %p)\n", hProcess, Line);
943
944     if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
945     if (!pcs) return FALSE;
946     module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
947     if (!(module = module_get_debug(pcs, module))) return FALSE;
948
949     if (Line->Key == 0) return FALSE;
950     li = (struct line_info*)Line->Key;
951     while (!(li->cookie & DLIT_LAST))
952     {
953         li++;
954         if (!(li->cookie & DLIT_SOURCEFILE))
955         {
956             Line->LineNumber = li->line_number;
957             Line->Address    = li->u.pc_offset;
958             Line->Key        = li;
959             return TRUE;
960         }
961         Line->FileName = (char*)source_get(module, li->u.source_file);
962     }
963     SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
964     return FALSE;
965 }
966
967 /***********************************************************************
968  *              SymFunctionTableAccess (DBGHELP.@)
969  */
970 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
971 {
972     FIXME("(%p, 0x%08lx): stub\n", hProcess, AddrBase);
973     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
974     return FALSE;
975 }
976
977 /***********************************************************************
978  *              SymUnDName (DBGHELP.@)
979  */
980 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, LPSTR UnDecName, DWORD UnDecNameLength)
981 {
982     FIXME("(%p %s %lu): stub\n", sym, UnDecName, UnDecNameLength);
983     return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, 
984                                 UNDNAME_COMPLETE);
985 }
986
987 /***********************************************************************
988  *              UnDecorateSymbolName (DBGHELP.@)
989  */
990 DWORD WINAPI UnDecorateSymbolName(LPCSTR DecoratedName, LPSTR UnDecoratedName,
991                                   DWORD UndecoratedLength, DWORD Flags)
992 {
993     FIXME("(%s, %p, %ld, 0x%08lx): stub\n",
994           debugstr_a(DecoratedName), UnDecoratedName, UndecoratedLength, Flags);
995
996     strncpy(UnDecoratedName, DecoratedName, UndecoratedLength);
997     UnDecoratedName[UndecoratedLength - 1] = '\0';
998     return TRUE;
999 }