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