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