dinput/tests: Add EnumObjects callback return value test.
[wine.git] / dlls / dbghelp / symbol.c
blobe3352761c539328b6f05112c6ba3e431d5a0cae9
1 /*
2 * File symbol.c - management of symbols (lexical tree)
4 * Copyright (C) 1993, Eric Youngdale.
5 * 2004, Eric Pouech
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.
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.
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
22 #define NONAMELESSUNION
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <assert.h>
30 #include "wine/debug.h"
31 #include "dbghelp_private.h"
32 #include "winnls.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
35 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
37 extern char * CDECL __unDName(char *buffer, const char *mangled, int len,
38 void * (CDECL *pfn_alloc)(size_t), void (CDECL *pfn_free)(void *), unsigned short flags);
40 static inline int cmp_addr(ULONG64 a1, ULONG64 a2)
42 if (a1 > a2) return 1;
43 if (a1 < a2) return -1;
44 return 0;
47 static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr)
49 ULONG64 ref;
50 symt_get_address(&module->addr_sorttab[idx]->symt, &ref);
51 return cmp_addr(ref, addr);
54 int __cdecl symt_cmp_addr(const void* p1, const void* p2)
56 const struct symt* sym1 = *(const struct symt* const *)p1;
57 const struct symt* sym2 = *(const struct symt* const *)p2;
58 ULONG64 a1, a2;
60 symt_get_address(sym1, &a1);
61 symt_get_address(sym2, &a2);
62 return cmp_addr(a1, a2);
65 #define BASE_CUSTOM_SYMT 0x80000000
67 /* dbghelp exposes the internal symbols/types with DWORD indexes.
68 * - custom symbols are always stored with index starting at BASE_CUSTOM_SYMT
69 * - for all the other (non custom) symbols:
70 * + on 32-bit machines, index is set to the actual address of symt
71 * + on 64-bit machines, the symt address is stored in a dedicated array
72 * which is exposed to the caller and index is the index of the symbol in
73 * this array
75 DWORD symt_ptr2index(struct module* module, const struct symt* sym)
77 struct vector* vector;
78 DWORD offset;
79 const struct symt** c;
80 int len, i;
82 if (!sym) return 0;
83 if (sym->tag == SymTagCustom)
85 vector = &module->vcustom_symt;
86 offset = BASE_CUSTOM_SYMT;
88 else
90 #ifdef _WIN64
91 vector = &module->vsymt;
92 offset = 1;
93 #else
94 return (DWORD)sym;
95 #endif
97 len = vector_length(vector);
98 /* FIXME: this is inefficient */
99 for (i = 0; i < len; i++)
101 if (*(struct symt**)vector_at(vector, i) == sym)
102 return i + offset;
104 /* not found */
105 c = vector_add(vector, &module->pool);
106 if (c) *c = sym;
107 return len + offset;
110 struct symt* symt_index2ptr(struct module* module, DWORD id)
112 struct vector* vector;
113 if (id >= BASE_CUSTOM_SYMT)
115 id -= BASE_CUSTOM_SYMT;
116 vector = &module->vcustom_symt;
118 else
120 #ifdef _WIN64
121 if (!id--) return NULL;
122 vector = &module->vsymt;
123 #else
124 return (struct symt*)id;
125 #endif
127 return (id >= vector_length(vector)) ? NULL : *(struct symt**)vector_at(vector, id);
130 static BOOL symt_grow_sorttab(struct module* module, unsigned sz)
132 struct symt_ht** new;
133 unsigned int size;
135 if (sz <= module->sorttab_size) return TRUE;
136 if (module->addr_sorttab)
138 size = module->sorttab_size * 2;
139 new = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab,
140 size * sizeof(struct symt_ht*));
142 else
144 size = 64;
145 new = HeapAlloc(GetProcessHeap(), 0, size * sizeof(struct symt_ht*));
147 if (!new) return FALSE;
148 module->sorttab_size = size;
149 module->addr_sorttab = new;
150 return TRUE;
153 static void symt_add_module_addr(struct module* module, struct symt_ht* ht)
155 ULONG64 addr;
157 /* Don't store in sorttab a symbol without address, they are of
158 * no use here (e.g. constant values)
160 if (symt_get_address(&ht->symt, &addr) &&
161 symt_grow_sorttab(module, module->num_symbols + 1))
163 module->addr_sorttab[module->num_symbols++] = ht;
164 module->sortlist_valid = FALSE;
168 static void symt_add_module_ht(struct module* module, struct symt_ht* ht)
170 hash_table_add(&module->ht_symbols, &ht->hash_elt);
171 symt_add_module_addr(module, ht);
174 static WCHAR* file_regex(const char* srcfile)
176 WCHAR* mask;
177 WCHAR* p;
179 if (!srcfile || !*srcfile)
181 if (!(p = mask = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(WCHAR)))) return NULL;
182 *p++ = '?';
183 *p++ = '#';
185 else
187 DWORD sz = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
188 WCHAR* srcfileW;
190 /* FIXME: we use here the largest conversion for every char... could be optimized */
191 p = mask = HeapAlloc(GetProcessHeap(), 0, (5 * strlen(srcfile) + 1 + sz) * sizeof(WCHAR));
192 if (!mask) return NULL;
193 srcfileW = mask + 5 * strlen(srcfile) + 1;
194 MultiByteToWideChar(CP_ACP, 0, srcfile, -1, srcfileW, sz);
196 while (*srcfileW)
198 switch (*srcfileW)
200 case '\\':
201 case '/':
202 *p++ = '[';
203 *p++ = '\\';
204 *p++ = '\\';
205 *p++ = '/';
206 *p++ = ']';
207 break;
208 case '.':
209 *p++ = '?';
210 break;
211 default:
212 *p++ = *srcfileW;
213 break;
215 srcfileW++;
218 *p = 0;
219 return mask;
222 struct symt_module* symt_new_module(struct module* module)
224 struct symt_module* sym;
226 TRACE_(dbghelp_symt)("Adding toplevel exe symbol %s\n", debugstr_w(module->modulename));
227 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
229 sym->symt.tag = SymTagExe;
230 sym->module = module;
231 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
233 return sym;
236 struct symt_compiland* symt_new_compiland(struct module* module, unsigned src_idx)
238 struct symt_compiland* sym;
239 struct symt_compiland** p;
241 TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n",
242 debugstr_w(module->modulename), source_get(module, src_idx));
243 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
245 sym->symt.tag = SymTagCompiland;
246 sym->container = module->top;
247 sym->address = 0;
248 sym->source = src_idx;
249 vector_init(&sym->vchildren, sizeof(struct symt*), 32);
250 sym->user = NULL;
251 p = vector_add(&module->top->vchildren, &module->pool);
252 *p = sym;
254 return sym;
257 struct symt_public* symt_new_public(struct module* module,
258 struct symt_compiland* compiland,
259 const char* name,
260 BOOL is_function,
261 ULONG_PTR address, unsigned size)
263 struct symt_public* sym;
264 struct symt** p;
266 TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%Ix\n",
267 debugstr_w(module->modulename), name, address);
268 if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
269 symt_find_nearest(module, address) != NULL)
270 return NULL;
271 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
273 sym->symt.tag = SymTagPublicSymbol;
274 sym->hash_elt.name = pool_strdup(&module->pool, name);
275 sym->container = compiland ? &compiland->symt : NULL;
276 sym->is_function = is_function;
277 sym->address = address;
278 sym->size = size;
279 symt_add_module_ht(module, (struct symt_ht*)sym);
280 if (compiland)
282 p = vector_add(&compiland->vchildren, &module->pool);
283 *p = &sym->symt;
286 return sym;
289 struct symt_data* symt_new_global_variable(struct module* module,
290 struct symt_compiland* compiland,
291 const char* name, unsigned is_static,
292 struct location loc, ULONG_PTR size,
293 struct symt* type)
295 struct symt_data* sym;
296 struct symt** p;
297 DWORD64 tsz;
299 TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%Ix %p\n",
300 debugstr_w(module->modulename), name, loc.kind, loc.offset, type);
301 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
303 sym->symt.tag = SymTagData;
304 sym->hash_elt.name = pool_strdup(&module->pool, name);
305 sym->kind = is_static ? DataIsFileStatic : DataIsGlobal;
306 sym->container = compiland ? &compiland->symt : &module->top->symt;
307 sym->type = type;
308 sym->u.var = loc;
309 if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz))
311 if (tsz != size)
312 FIXME("Size mismatch for %s.%s between type (%I64u) and src (%Iu)\n",
313 debugstr_w(module->modulename), name, tsz, size);
315 symt_add_module_ht(module, (struct symt_ht*)sym);
316 p = vector_add(compiland ? &compiland->vchildren : &module->top->vchildren, &module->pool);
317 *p = &sym->symt;
319 return sym;
322 static struct symt_function* init_function_or_inlinesite(struct module* module,
323 DWORD tag,
324 struct symt* container,
325 const char* name,
326 struct symt* sig_type,
327 unsigned num_ranges)
329 struct symt_function* sym;
331 assert(!sig_type || sig_type->tag == SymTagFunctionType);
332 if ((sym = pool_alloc(&module->pool, offsetof(struct symt_function, ranges[num_ranges]))))
334 sym->symt.tag = tag;
335 sym->hash_elt.name = pool_strdup(&module->pool, name);
336 sym->container = container;
337 sym->type = sig_type;
338 vector_init(&sym->vlines, sizeof(struct line_info), 64);
339 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
340 sym->num_ranges = num_ranges;
342 return sym;
345 struct symt_function* symt_new_function(struct module* module,
346 struct symt_compiland* compiland,
347 const char* name,
348 ULONG_PTR addr, ULONG_PTR size,
349 struct symt* sig_type)
351 struct symt_function* sym;
353 TRACE_(dbghelp_symt)("Adding global function %s:%s @%Ix-%Ix\n",
354 debugstr_w(module->modulename), name, addr, addr + size - 1);
355 if ((sym = init_function_or_inlinesite(module, SymTagFunction, &compiland->symt, name, sig_type, 1)))
357 struct symt** p;
358 sym->ranges[0].low = addr;
359 sym->ranges[0].high = addr + size;
360 sym->next_inlinesite = NULL; /* first of list */
361 symt_add_module_ht(module, (struct symt_ht*)sym);
362 if (compiland)
364 p = vector_add(&compiland->vchildren, &module->pool);
365 *p = &sym->symt;
368 return sym;
371 struct symt_function* symt_new_inlinesite(struct module* module,
372 struct symt_function* func,
373 struct symt* container,
374 const char* name,
375 struct symt* sig_type,
376 unsigned num_ranges)
378 struct symt_function* sym;
380 TRACE_(dbghelp_symt)("Adding inline site %s\n", name);
381 if ((sym = init_function_or_inlinesite(module, SymTagInlineSite, container, name, sig_type, num_ranges)))
383 struct symt** p;
384 assert(container);
386 /* chain inline sites */
387 sym->next_inlinesite = func->next_inlinesite;
388 func->next_inlinesite = sym;
389 if (container->tag == SymTagFunction || container->tag == SymTagInlineSite)
390 p = vector_add(&((struct symt_function*)container)->vchildren, &module->pool);
391 else
393 assert(container->tag == SymTagBlock);
394 p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool);
396 *p = &sym->symt;
398 return sym;
401 void symt_add_func_line(struct module* module, struct symt_function* func,
402 unsigned source_idx, int line_num, ULONG_PTR addr)
404 struct line_info* dli;
405 unsigned vlen;
406 struct line_info* prev;
407 BOOL last_matches = FALSE;
408 int i;
410 if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
412 TRACE_(dbghelp_symt)("(%p)%s:%Ix %s:%u\n",
413 func, func->hash_elt.name, addr,
414 source_get(module, source_idx), line_num);
416 assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite);
418 for (i=vector_length(&func->vlines)-1; i>=0; i--)
420 dli = vector_at(&func->vlines, i);
421 if (dli->is_source_file)
423 last_matches = (source_idx == dli->u.source_file);
424 break;
427 vlen = vector_length(&func->vlines);
428 prev = vlen ? vector_at(&func->vlines, vlen - 1) : NULL;
429 if (last_matches && prev && addr == prev->u.address)
431 WARN("Duplicate addition of line number in %s\n", func->hash_elt.name);
432 return;
434 if (!last_matches)
436 /* we shouldn't have line changes on first line of function */
437 dli = vector_add(&func->vlines, &module->pool);
438 dli->is_source_file = 1;
439 dli->is_first = (prev == NULL);
440 dli->is_last = 0;
441 dli->line_number = 0;
442 dli->u.source_file = source_idx;
444 /* clear previous last */
445 if (prev) prev->is_last = 0;
446 dli = vector_add(&func->vlines, &module->pool);
447 dli->is_source_file = 0;
448 dli->is_first = 0; /* only a source file can be first */
449 dli->is_last = 1;
450 dli->line_number = line_num;
451 dli->u.address = addr;
454 /******************************************************************
455 * symt_add_func_local
457 * Adds a new local/parameter to a given function:
458 * In any cases, dt tells whether it's a local variable or a parameter
459 * or a static variable inside the function.
460 * If regno it's not 0:
461 * - then variable is stored in a register
462 * - otherwise, value is referenced by register + offset
463 * Otherwise, the variable is stored on the stack:
464 * - offset is then the offset from the frame register
466 struct symt_data* symt_add_func_local(struct module* module,
467 struct symt_function* func,
468 enum DataKind dt,
469 const struct location* loc,
470 struct symt_block* block,
471 struct symt* type, const char* name)
473 struct symt_data* locsym;
474 struct symt** p;
476 TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n",
477 debugstr_w(module->modulename), func->hash_elt.name,
478 name, type);
480 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
481 assert(dt == DataIsParam || dt == DataIsLocal || dt == DataIsStaticLocal);
483 locsym = pool_alloc(&module->pool, sizeof(*locsym));
484 locsym->symt.tag = SymTagData;
485 locsym->hash_elt.name = pool_strdup(&module->pool, name);
486 locsym->hash_elt.next = NULL;
487 locsym->kind = dt;
488 locsym->container = block ? &block->symt : &func->symt;
489 locsym->type = type;
490 locsym->u.var = *loc;
491 if (block)
492 p = vector_add(&block->vchildren, &module->pool);
493 else
494 p = vector_add(&func->vchildren, &module->pool);
495 *p = &locsym->symt;
496 if (dt == DataIsStaticLocal)
497 symt_add_module_addr(module, (struct symt_ht*)locsym);
498 return locsym;
501 /******************************************************************
502 * symt_add_func_local
504 * Adds a new (local) constant to a given function
506 struct symt_data* symt_add_func_constant(struct module* module,
507 struct symt_function* func,
508 struct symt_block* block,
509 struct symt* type, const char* name,
510 VARIANT* v)
512 struct symt_data* locsym;
513 struct symt** p;
515 TRACE_(dbghelp_symt)("Adding local constant (%s:%s): %s %p\n",
516 debugstr_w(module->modulename), func->hash_elt.name,
517 name, type);
519 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
521 locsym = pool_alloc(&module->pool, sizeof(*locsym));
522 locsym->symt.tag = SymTagData;
523 locsym->hash_elt.name = pool_strdup(&module->pool, name);
524 locsym->hash_elt.next = NULL;
525 locsym->kind = DataIsConstant;
526 locsym->container = block ? &block->symt : &func->symt;
527 locsym->type = type;
528 locsym->u.value = *v;
529 if (block)
530 p = vector_add(&block->vchildren, &module->pool);
531 else
532 p = vector_add(&func->vchildren, &module->pool);
533 *p = &locsym->symt;
534 return locsym;
537 struct symt_block* symt_open_func_block(struct module* module,
538 struct symt_function* func,
539 struct symt_block* parent_block,
540 unsigned num_ranges)
542 struct symt_block* block;
543 struct symt** p;
545 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
546 assert(num_ranges > 0);
547 assert(!parent_block || parent_block->symt.tag == SymTagBlock);
549 block = pool_alloc(&module->pool, offsetof(struct symt_block, ranges[num_ranges]));
550 block->symt.tag = SymTagBlock;
551 block->num_ranges = num_ranges;
552 block->container = parent_block ? &parent_block->symt : &func->symt;
553 vector_init(&block->vchildren, sizeof(struct symt*), 4);
554 if (parent_block)
555 p = vector_add(&parent_block->vchildren, &module->pool);
556 else
557 p = vector_add(&func->vchildren, &module->pool);
558 *p = &block->symt;
560 return block;
563 struct symt_block* symt_close_func_block(struct module* module,
564 const struct symt_function* func,
565 struct symt_block* block)
567 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
569 return (block->container->tag == SymTagBlock) ?
570 CONTAINING_RECORD(block->container, struct symt_block, symt) : NULL;
573 struct symt_hierarchy_point* symt_add_function_point(struct module* module,
574 struct symt_function* func,
575 enum SymTagEnum point,
576 const struct location* loc,
577 const char* name)
579 struct symt_hierarchy_point*sym;
580 struct symt** p;
582 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
584 sym->symt.tag = point;
585 sym->parent = &func->symt;
586 sym->loc = *loc;
587 sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL;
588 p = vector_add(&func->vchildren, &module->pool);
589 *p = &sym->symt;
591 return sym;
594 struct symt_thunk* symt_new_thunk(struct module* module,
595 struct symt_compiland* compiland,
596 const char* name, THUNK_ORDINAL ord,
597 ULONG_PTR addr, ULONG_PTR size)
599 struct symt_thunk* sym;
601 TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%Ix-%Ix\n",
602 debugstr_w(module->modulename), name, addr, addr + size - 1);
604 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
606 sym->symt.tag = SymTagThunk;
607 sym->hash_elt.name = pool_strdup(&module->pool, name);
608 sym->container = &compiland->symt;
609 sym->address = addr;
610 sym->size = size;
611 sym->ordinal = ord;
612 symt_add_module_ht(module, (struct symt_ht*)sym);
613 if (compiland)
615 struct symt** p;
616 p = vector_add(&compiland->vchildren, &module->pool);
617 *p = &sym->symt;
620 return sym;
623 struct symt_data* symt_new_constant(struct module* module,
624 struct symt_compiland* compiland,
625 const char* name, struct symt* type,
626 const VARIANT* v)
628 struct symt_data* sym;
630 TRACE_(dbghelp_symt)("Adding constant value %s:%s\n",
631 debugstr_w(module->modulename), name);
633 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
635 sym->symt.tag = SymTagData;
636 sym->hash_elt.name = pool_strdup(&module->pool, name);
637 sym->kind = DataIsConstant;
638 sym->container = compiland ? &compiland->symt : &module->top->symt;
639 sym->type = type;
640 sym->u.value = *v;
641 symt_add_module_ht(module, (struct symt_ht*)sym);
642 if (compiland)
644 struct symt** p;
645 p = vector_add(&compiland->vchildren, &module->pool);
646 *p = &sym->symt;
649 return sym;
652 struct symt_hierarchy_point* symt_new_label(struct module* module,
653 struct symt_compiland* compiland,
654 const char* name, ULONG_PTR address)
656 struct symt_hierarchy_point* sym;
658 TRACE_(dbghelp_symt)("Adding global label value %s:%s\n",
659 debugstr_w(module->modulename), name);
661 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
663 sym->symt.tag = SymTagLabel;
664 sym->hash_elt.name = pool_strdup(&module->pool, name);
665 sym->loc.kind = loc_absolute;
666 sym->loc.offset = address;
667 sym->parent = compiland ? &compiland->symt : NULL;
668 symt_add_module_ht(module, (struct symt_ht*)sym);
669 if (compiland)
671 struct symt** p;
672 p = vector_add(&compiland->vchildren, &module->pool);
673 *p = &sym->symt;
676 return sym;
679 struct symt_custom* symt_new_custom(struct module* module, const char* name,
680 DWORD64 addr, DWORD size)
682 struct symt_custom* sym;
684 TRACE_(dbghelp_symt)("Adding custom symbol %s:%s\n",
685 debugstr_w(module->modulename), name);
687 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
689 sym->symt.tag = SymTagCustom;
690 sym->hash_elt.name = pool_strdup(&module->pool, name);
691 sym->address = addr;
692 sym->size = size;
693 symt_add_module_ht(module, (struct symt_ht*)sym);
695 return sym;
698 /* expect sym_info->MaxNameLen to be set before being called */
699 static void symt_fill_sym_info(struct module_pair* pair,
700 const struct symt_function* func,
701 const struct symt* sym, SYMBOL_INFO* sym_info)
703 const char* name;
704 DWORD64 size;
705 char* tmp;
707 if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex))
708 sym_info->TypeIndex = 0;
709 sym_info->Index = symt_ptr2index(pair->effective, sym);
710 sym_info->Reserved[0] = sym_info->Reserved[1] = 0;
711 if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) &&
712 (!sym_info->TypeIndex ||
713 !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex),
714 TI_GET_LENGTH, &size)))
715 size = 0;
716 sym_info->Size = (DWORD)size;
717 sym_info->ModBase = pair->requested->module.BaseOfImage;
718 sym_info->Flags = 0;
719 sym_info->Value = 0;
721 switch (sym->tag)
723 case SymTagData:
725 const struct symt_data* data = (const struct symt_data*)sym;
726 switch (data->kind)
728 case DataIsParam:
729 sym_info->Flags |= SYMFLAG_PARAMETER;
730 /* fall through */
731 case DataIsLocal:
732 sym_info->Flags |= SYMFLAG_LOCAL;
734 struct location loc = data->u.var;
736 if (loc.kind >= loc_user)
738 unsigned i;
739 struct module_format* modfmt;
741 for (i = 0; i < DFI_LAST; i++)
743 modfmt = pair->effective->format_info[i];
744 if (modfmt && modfmt->loc_compute)
746 modfmt->loc_compute(pair->pcs, modfmt, func, &loc);
747 break;
751 switch (loc.kind)
753 case loc_error:
754 /* for now we report error cases as a negative register number */
755 /* fall through */
756 case loc_register:
757 sym_info->Flags |= SYMFLAG_REGISTER;
758 sym_info->Register = loc.reg;
759 sym_info->Address = 0;
760 break;
761 case loc_regrel:
762 sym_info->Flags |= SYMFLAG_REGREL;
763 sym_info->Register = loc.reg;
764 if (loc.reg == CV_REG_NONE || (int)loc.reg < 0 /* error */)
765 FIXME("suspicious register value %x\n", loc.reg);
766 sym_info->Address = loc.offset;
767 break;
768 case loc_absolute:
769 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
770 sym_info->Value = loc.offset;
771 break;
772 default:
773 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", loc.kind);
774 assert(0);
777 break;
778 case DataIsGlobal:
779 case DataIsFileStatic:
780 case DataIsStaticLocal:
781 switch (data->u.var.kind)
783 case loc_tlsrel:
784 sym_info->Flags |= SYMFLAG_TLSREL;
785 /* fall through */
786 case loc_absolute:
787 symt_get_address(sym, &sym_info->Address);
788 sym_info->Register = 0;
789 break;
790 default:
791 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind);
792 assert(0);
794 break;
795 case DataIsConstant:
796 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
797 if (data->container &&
798 (data->container->tag == SymTagFunction || data->container->tag == SymTagBlock))
799 sym_info->Flags |= SYMFLAG_LOCAL;
800 switch (V_VT(&data->u.value))
802 case VT_I8: sym_info->Value = (LONG64)V_I8(&data->u.value); break;
803 case VT_I4: sym_info->Value = (LONG64)V_I4(&data->u.value); break;
804 case VT_I2: sym_info->Value = (LONG64)V_I2(&data->u.value); break;
805 case VT_I1: sym_info->Value = (LONG64)V_I1(&data->u.value); break;
806 case VT_UINT:sym_info->Value = V_UINT(&data->u.value); break;
807 case VT_UI8: sym_info->Value = V_UI8(&data->u.value); break;
808 case VT_UI4: sym_info->Value = V_UI4(&data->u.value); break;
809 case VT_UI2: sym_info->Value = V_UI2(&data->u.value); break;
810 case VT_UI1: sym_info->Value = V_UI1(&data->u.value); break;
811 case VT_BYREF: sym_info->Value = (DWORD_PTR)V_BYREF(&data->u.value); break;
812 case VT_EMPTY: sym_info->Value = 0; break;
813 default:
814 FIXME("Unsupported variant type (%u)\n", V_VT(&data->u.value));
815 sym_info->Value = 0;
816 break;
818 break;
819 default:
820 FIXME("Unhandled kind (%u) in sym data\n", data->kind);
823 break;
824 case SymTagPublicSymbol:
826 const struct symt_public* pub = (const struct symt_public*)sym;
827 if (pub->is_function)
828 sym_info->Flags |= SYMFLAG_PUBLIC_CODE;
829 else
830 sym_info->Flags |= SYMFLAG_EXPORT;
831 symt_get_address(sym, &sym_info->Address);
833 break;
834 case SymTagFunction:
835 case SymTagInlineSite:
836 symt_get_address(sym, &sym_info->Address);
837 break;
838 case SymTagThunk:
839 sym_info->Flags |= SYMFLAG_THUNK;
840 symt_get_address(sym, &sym_info->Address);
841 break;
842 case SymTagCustom:
843 symt_get_address(sym, &sym_info->Address);
844 sym_info->Flags |= SYMFLAG_VIRTUAL;
845 break;
846 default:
847 symt_get_address(sym, &sym_info->Address);
848 sym_info->Register = 0;
849 break;
851 sym_info->Scope = 0; /* FIXME */
852 sym_info->Tag = sym->tag;
853 name = symt_get_name(sym);
854 if (sym_info->MaxNameLen &&
855 sym->tag == SymTagPublicSymbol && (dbghelp_options & SYMOPT_UNDNAME) &&
856 (tmp = __unDName(NULL, name, 0, malloc, free, UNDNAME_NAME_ONLY)) != NULL)
858 symbol_setname(sym_info, tmp);
859 free(tmp);
861 else
862 symbol_setname(sym_info, name);
864 TRACE_(dbghelp_symt)("%p => %s %lu %I64x\n",
865 sym, sym_info->Name, sym_info->Size, sym_info->Address);
868 struct sym_enum
870 PSYM_ENUMERATESYMBOLS_CALLBACK cb;
871 PVOID user;
872 SYMBOL_INFO* sym_info;
873 DWORD index;
874 DWORD tag;
875 DWORD64 addr;
876 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
879 static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
880 const struct symt_function* func, const struct symt* sym)
882 symt_fill_sym_info(pair, func, sym, se->sym_info);
883 if (se->index && se->sym_info->Index != se->index) return FALSE;
884 if (se->tag && se->sym_info->Tag != se->tag) return FALSE;
885 if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE;
886 return !se->cb(se->sym_info, se->sym_info->Size, se->user);
889 static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match,
890 const struct sym_enum* se)
892 void* ptr;
893 struct symt_ht* sym = NULL;
894 struct hash_table_iter hti;
895 WCHAR* nameW;
896 BOOL ret;
898 hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
899 while ((ptr = hash_table_iter_up(&hti)))
901 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
902 nameW = symt_get_nameW(&sym->symt);
903 ret = SymMatchStringW(nameW, match, FALSE);
904 HeapFree(GetProcessHeap(), 0, nameW);
905 if (ret)
907 se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
908 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
909 if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
912 return FALSE;
915 static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt)
917 unsigned low = 0, mid = high / 2;
918 ULONG64 addr;
920 if (!high) return 0;
921 symt_get_address(&elt->symt, &addr);
924 switch (cmp_sorttab_addr(module, mid, addr))
926 case 0: return mid;
927 case -1: low = mid + 1; break;
928 case 1: high = mid; break;
930 mid = low + (high - low) / 2;
931 } while (low < high);
932 return mid;
935 /***********************************************************************
936 * resort_symbols
938 * Rebuild sorted list of symbols for a module.
940 static BOOL resort_symbols(struct module* module)
942 int delta;
944 if (!(module->module.NumSyms = module->num_symbols))
945 return FALSE;
947 /* we know that set from 0 up to num_sorttab is already sorted
948 * so sort the remaining (new) symbols, and merge the two sets
949 * (unless the first set is empty)
951 delta = module->num_symbols - module->num_sorttab;
952 qsort(&module->addr_sorttab[module->num_sorttab], delta, sizeof(struct symt_ht*), symt_cmp_addr);
953 if (module->num_sorttab)
955 int i, ins_idx = module->num_sorttab, prev_ins_idx;
956 static struct symt_ht** tmp;
957 static unsigned num_tmp;
959 if (num_tmp < delta)
961 static struct symt_ht** new;
962 if (tmp)
963 new = HeapReAlloc(GetProcessHeap(), 0, tmp, delta * sizeof(struct symt_ht*));
964 else
965 new = HeapAlloc(GetProcessHeap(), 0, delta * sizeof(struct symt_ht*));
966 if (!new)
968 module->num_sorttab = 0;
969 return resort_symbols(module);
971 tmp = new;
972 num_tmp = delta;
974 memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*));
975 qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr);
977 for (i = delta - 1; i >= 0; i--)
979 prev_ins_idx = ins_idx;
980 ins_idx = where_to_insert(module, ins_idx, tmp[i]);
981 memmove(&module->addr_sorttab[ins_idx + i + 1],
982 &module->addr_sorttab[ins_idx],
983 (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*));
984 module->addr_sorttab[ins_idx + i] = tmp[i];
987 module->num_sorttab = module->num_symbols;
988 return module->sortlist_valid = TRUE;
991 static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size)
993 DWORD type_index;
995 if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size)
996 return;
998 if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) &&
999 symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return;
1000 *size = 1; /* no size info */
1003 /* needed by symt_find_nearest */
1004 static int symt_get_best_at(struct module* module, int idx_sorttab)
1006 ULONG64 ref_addr;
1007 int idx_sorttab_orig = idx_sorttab;
1008 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1010 symt_get_address(&module->addr_sorttab[idx_sorttab]->symt, &ref_addr);
1011 while (idx_sorttab > 0 &&
1012 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1013 !cmp_sorttab_addr(module, idx_sorttab - 1, ref_addr))
1014 idx_sorttab--;
1015 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1017 idx_sorttab = idx_sorttab_orig;
1018 while (idx_sorttab < module->num_sorttab - 1 &&
1019 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1020 !cmp_sorttab_addr(module, idx_sorttab + 1, ref_addr))
1021 idx_sorttab++;
1023 /* if no better symbol was found restore the original */
1024 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1025 idx_sorttab = idx_sorttab_orig;
1027 return idx_sorttab;
1030 /* assume addr is in module */
1031 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
1033 int mid, high, low;
1034 ULONG64 ref_addr, ref_size;
1036 if (!module->sortlist_valid || !module->addr_sorttab)
1038 if (!resort_symbols(module)) return NULL;
1042 * Binary search to find closest symbol.
1044 low = 0;
1045 high = module->num_sorttab;
1047 symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr);
1048 if (addr < ref_addr) return NULL;
1050 if (high)
1052 symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr);
1053 symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size);
1054 if (addr >= ref_addr + ref_size) return NULL;
1057 while (high > low + 1)
1059 mid = (high + low) / 2;
1060 if (cmp_sorttab_addr(module, mid, addr) < 0)
1061 low = mid;
1062 else
1063 high = mid;
1065 if (low != high && high != module->num_sorttab &&
1066 cmp_sorttab_addr(module, high, addr) <= 0)
1067 low = high;
1069 /* If found symbol is a public symbol, check if there are any other entries that
1070 * might also have the same address, but would get better information
1072 low = symt_get_best_at(module, low);
1074 return module->addr_sorttab[low];
1077 struct symt_ht* symt_find_symbol_at(struct module* module, DWORD_PTR addr)
1079 struct symt_ht* nearest = symt_find_nearest(module, addr);
1080 if (nearest)
1082 ULONG64 symaddr, symsize;
1083 symt_get_address(&nearest->symt, &symaddr);
1084 symt_get_length(module, &nearest->symt, &symsize);
1085 if (addr < symaddr || addr >= symaddr + symsize)
1086 nearest = NULL;
1088 return nearest;
1091 static BOOL symt_enum_locals_helper(struct module_pair* pair,
1092 const WCHAR* match, const struct sym_enum* se,
1093 struct symt_function* func, const struct vector* v)
1095 struct symt* lsym = NULL;
1096 DWORD_PTR pc = pair->pcs->localscope_pc;
1097 unsigned int i;
1098 WCHAR* nameW;
1099 BOOL ret;
1101 for (i=0; i<vector_length(v); i++)
1103 lsym = *(struct symt**)vector_at(v, i);
1104 switch (lsym->tag)
1106 case SymTagBlock:
1108 struct symt_block* block = (struct symt_block*)lsym;
1109 unsigned j;
1110 for (j = 0; j < block->num_ranges; j++)
1112 if (pc >= block->ranges[j].low && pc < block->ranges[j].high)
1114 if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren))
1115 return FALSE;
1119 break;
1120 case SymTagData:
1121 nameW = symt_get_nameW(lsym);
1122 ret = SymMatchStringW(nameW, match,
1123 !(dbghelp_options & SYMOPT_CASE_INSENSITIVE));
1124 HeapFree(GetProcessHeap(), 0, nameW);
1125 if (ret)
1127 if (send_symbol(se, pair, func, lsym)) return FALSE;
1129 break;
1130 case SymTagLabel:
1131 case SymTagFuncDebugStart:
1132 case SymTagFuncDebugEnd:
1133 case SymTagCustom:
1134 case SymTagInlineSite:
1135 break;
1136 default:
1137 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
1138 assert(0);
1141 return TRUE;
1144 static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask,
1145 const struct sym_enum* se)
1147 struct module_pair pair;
1149 se->sym_info->SizeOfStruct = sizeof(*se->sym_info);
1150 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
1152 pair.pcs = pcs;
1153 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1154 if (!module_get_debug(&pair)) return FALSE;
1156 if (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1157 symt_check_tag(pcs->localscope_symt, SymTagInlineSite))
1159 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1160 return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, func, &func->vchildren);
1162 return FALSE;
1165 /**********************************************************
1166 * symbol_setname
1168 * Properly sets Name and NameLen in SYMBOL_INFO
1169 * according to MaxNameLen value
1171 void symbol_setname(SYMBOL_INFO* sym_info, const char* name)
1173 SIZE_T len = 0;
1174 if (name)
1176 sym_info->NameLen = strlen(name);
1177 if (sym_info->MaxNameLen)
1179 len = min(sym_info->NameLen, sym_info->MaxNameLen - 1);
1180 memcpy(sym_info->Name, name, len);
1183 else
1184 sym_info->NameLen = 0;
1185 sym_info->Name[len] = '\0';
1188 /******************************************************************
1189 * copy_symbolW
1191 * Helper for transforming an ANSI symbol info into a UNICODE one.
1192 * Assume that MaxNameLen is the same for both version (A & W).
1194 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
1196 siw->SizeOfStruct = si->SizeOfStruct;
1197 siw->TypeIndex = si->TypeIndex;
1198 siw->Reserved[0] = si->Reserved[0];
1199 siw->Reserved[1] = si->Reserved[1];
1200 siw->Index = si->Index;
1201 siw->Size = si->Size;
1202 siw->ModBase = si->ModBase;
1203 siw->Flags = si->Flags;
1204 siw->Value = si->Value;
1205 siw->Address = si->Address;
1206 siw->Register = si->Register;
1207 siw->Scope = si->Scope;
1208 siw->Tag = si->Tag;
1209 siw->NameLen = si->NameLen;
1210 siw->MaxNameLen = si->MaxNameLen;
1211 MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen);
1214 /* return the lowest inline site inside a function */
1215 struct symt_function* symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr)
1217 struct symt_function* current;
1218 int i;
1220 assert(func->symt.tag == SymTagFunction);
1221 for (current = func->next_inlinesite; current; current = current->next_inlinesite)
1223 for (i = 0; i < current->num_ranges; ++i)
1225 /* first matching range gives the lowest inline site; see dbghelp_private.h for details */
1226 if (current->ranges[i].low <= addr && addr < current->ranges[i].high)
1227 return current;
1230 return NULL;
1233 /* from an inline function, get either the enclosing inlined function, or the top function when no inlined */
1234 struct symt* symt_get_upper_inlined(struct symt_function* inlined)
1236 struct symt* symt = &inlined->symt;
1240 assert(symt);
1241 if (symt->tag == SymTagBlock)
1242 symt = ((struct symt_block*)symt)->container;
1243 else
1244 symt = ((struct symt_function*)symt)->container;
1245 } while (symt->tag == SymTagBlock);
1246 assert(symt->tag == SymTagFunction || symt->tag == SymTagInlineSite);
1247 return symt;
1250 /* lookup in module for an inline site (from addr and inline_ctx) */
1251 struct symt_function* symt_find_inlined_site(struct module* module, DWORD64 addr, DWORD inline_ctx)
1253 struct symt_ht* symt = symt_find_symbol_at(module, addr);
1255 if (symt_check_tag(&symt->symt, SymTagFunction))
1257 struct symt_function* func = (struct symt_function*)symt;
1258 struct symt_function* curr = symt_find_lowest_inlined(func, addr);
1259 DWORD depth = IFC_DEPTH(inline_ctx);
1261 if (curr)
1262 for ( ; curr != func; curr = (struct symt_function*)symt_get_upper_inlined(curr))
1263 if (depth-- == 0) return curr;
1265 return NULL;
1268 /******************************************************************
1269 * sym_enum
1271 * Core routine for most of the enumeration of symbols
1273 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1274 const struct sym_enum* se)
1276 struct module_pair pair;
1277 const WCHAR* bang;
1278 WCHAR* mod;
1280 pair.pcs = process_find_by_handle(hProcess);
1281 if (!pair.pcs) return FALSE;
1282 if (BaseOfDll == 0)
1284 /* do local variables ? */
1285 if (!Mask || !(bang = wcschr(Mask, '!')))
1286 return symt_enum_locals(pair.pcs, Mask, se);
1288 if (bang == Mask) return FALSE;
1290 mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR));
1291 if (!mod) return FALSE;
1292 memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR));
1293 mod[bang - Mask] = 0;
1295 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1297 if (pair.requested->type == DMT_PE && module_get_debug(&pair))
1299 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1300 symt_enum_module(&pair, bang + 1, se))
1301 break;
1304 /* not found in PE modules, retry on the ELF ones
1306 if (!pair.requested && dbghelp_opt_native)
1308 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1310 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) &&
1311 !module_get_containee(pair.pcs, pair.requested) &&
1312 module_get_debug(&pair))
1314 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1315 symt_enum_module(&pair, bang + 1, se))
1316 break;
1320 HeapFree(GetProcessHeap(), 0, mod);
1321 return TRUE;
1323 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
1324 if (!module_get_debug(&pair))
1325 return FALSE;
1327 /* we always ignore module name from Mask when BaseOfDll is defined */
1328 if (Mask && (bang = wcschr(Mask, '!')))
1330 if (bang == Mask) return FALSE;
1331 Mask = bang + 1;
1334 symt_enum_module(&pair, Mask ? Mask : L"*", se);
1336 return TRUE;
1339 static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1340 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1341 PVOID UserContext)
1343 struct sym_enum se;
1345 se.cb = EnumSymbolsCallback;
1346 se.user = UserContext;
1347 se.index = 0;
1348 se.tag = 0;
1349 se.addr = 0;
1350 se.sym_info = (PSYMBOL_INFO)se.buffer;
1352 return sym_enum(hProcess, BaseOfDll, Mask, &se);
1355 /******************************************************************
1356 * SymEnumSymbols (DBGHELP.@)
1358 * cases BaseOfDll = 0
1359 * !foo fails always (despite what MSDN states)
1360 * RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
1361 * no ! in Mask, lookup in local Context
1362 * cases BaseOfDll != 0
1363 * !foo fails always (despite what MSDN states)
1364 * RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
1366 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
1367 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1368 PVOID UserContext)
1370 BOOL ret;
1371 PWSTR maskW = NULL;
1373 TRACE("(%p %I64x %s %p %p)\n",
1374 hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
1376 if (Mask)
1378 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
1379 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
1380 return FALSE;
1381 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
1383 ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext);
1384 HeapFree(GetProcessHeap(), 0, maskW);
1385 return ret;
1388 struct sym_enumW
1390 PSYM_ENUMERATESYMBOLS_CALLBACKW cb;
1391 void* ctx;
1392 PSYMBOL_INFOW sym_info;
1393 char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(WCHAR)];
1396 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx)
1398 struct sym_enumW* sew = ctx;
1400 copy_symbolW(sew->sym_info, si);
1402 return (sew->cb)(sew->sym_info, size, sew->ctx);
1405 /******************************************************************
1406 * SymEnumSymbolsW (DBGHELP.@)
1409 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1410 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
1411 PVOID UserContext)
1413 struct sym_enumW sew;
1415 sew.ctx = UserContext;
1416 sew.cb = EnumSymbolsCallback;
1417 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
1419 return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew);
1422 struct sym_enumerate
1424 void* ctx;
1425 PSYM_ENUMSYMBOLS_CALLBACK cb;
1428 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1430 struct sym_enumerate* se = ctx;
1431 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1434 /***********************************************************************
1435 * SymEnumerateSymbols (DBGHELP.@)
1437 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
1438 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
1439 PVOID UserContext)
1441 struct sym_enumerate se;
1443 se.ctx = UserContext;
1444 se.cb = EnumSymbolsCallback;
1446 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
1449 struct sym_enumerate64
1451 void* ctx;
1452 PSYM_ENUMSYMBOLS_CALLBACK64 cb;
1455 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1457 struct sym_enumerate64* se = ctx;
1458 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1461 /***********************************************************************
1462 * SymEnumerateSymbols64 (DBGHELP.@)
1464 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll,
1465 PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,
1466 PVOID UserContext)
1468 struct sym_enumerate64 se;
1470 se.ctx = UserContext;
1471 se.cb = EnumSymbolsCallback;
1473 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se);
1476 /******************************************************************
1477 * SymFromAddr (DBGHELP.@)
1480 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address,
1481 DWORD64* Displacement, PSYMBOL_INFO Symbol)
1483 struct module_pair pair;
1484 struct symt_ht* sym;
1486 if (!module_init_pair(&pair, hProcess, Address)) return FALSE;
1487 if ((sym = symt_find_symbol_at(pair.effective, Address)) == NULL) return FALSE;
1489 symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol);
1490 if (Displacement)
1491 *Displacement = (Address >= Symbol->Address) ? (Address - Symbol->Address) : (DWORD64)-1;
1492 return TRUE;
1495 /******************************************************************
1496 * SymFromAddrW (DBGHELP.@)
1499 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address,
1500 DWORD64* Displacement, PSYMBOL_INFOW Symbol)
1502 PSYMBOL_INFO si;
1503 unsigned len;
1504 BOOL ret;
1506 len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR);
1507 si = HeapAlloc(GetProcessHeap(), 0, len);
1508 if (!si) return FALSE;
1510 si->SizeOfStruct = sizeof(*si);
1511 si->MaxNameLen = Symbol->MaxNameLen;
1512 if ((ret = SymFromAddr(hProcess, Address, Displacement, si)))
1514 copy_symbolW(Symbol, si);
1516 HeapFree(GetProcessHeap(), 0, si);
1517 return ret;
1520 /******************************************************************
1521 * SymGetSymFromAddr (DBGHELP.@)
1524 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
1525 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
1527 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1528 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1529 size_t len;
1530 DWORD64 Displacement64;
1532 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1533 si->SizeOfStruct = sizeof(*si);
1534 si->MaxNameLen = MAX_SYM_NAME;
1535 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1536 return FALSE;
1538 if (Displacement)
1539 *Displacement = Displacement64;
1540 Symbol->Address = si->Address;
1541 Symbol->Size = si->Size;
1542 Symbol->Flags = si->Flags;
1543 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1544 lstrcpynA(Symbol->Name, si->Name, len);
1545 return TRUE;
1548 /******************************************************************
1549 * SymGetSymFromAddr64 (DBGHELP.@)
1552 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address,
1553 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol)
1555 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1556 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1557 size_t len;
1558 DWORD64 Displacement64;
1560 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1561 si->SizeOfStruct = sizeof(*si);
1562 si->MaxNameLen = MAX_SYM_NAME;
1563 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1564 return FALSE;
1566 if (Displacement)
1567 *Displacement = Displacement64;
1568 Symbol->Address = si->Address;
1569 Symbol->Size = si->Size;
1570 Symbol->Flags = si->Flags;
1571 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1572 lstrcpynA(Symbol->Name, si->Name, len);
1573 return TRUE;
1576 static BOOL find_name(struct process* pcs, struct module* module, const char* name,
1577 SYMBOL_INFO* symbol)
1579 struct hash_table_iter hti;
1580 void* ptr;
1581 struct symt_ht* sym = NULL;
1582 struct module_pair pair;
1584 pair.pcs = pcs;
1585 if (!(pair.requested = module)) return FALSE;
1586 if (!module_get_debug(&pair)) return FALSE;
1588 hash_table_iter_init(&pair.effective->ht_symbols, &hti, name);
1589 while ((ptr = hash_table_iter_up(&hti)))
1591 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
1593 if (!strcmp(sym->hash_elt.name, name))
1595 symt_fill_sym_info(&pair, NULL, &sym->symt, symbol);
1596 return TRUE;
1599 return FALSE;
1602 /******************************************************************
1603 * SymFromName (DBGHELP.@)
1606 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol)
1608 struct process* pcs = process_find_by_handle(hProcess);
1609 struct module_pair pair;
1610 struct module* module;
1611 const char* name;
1613 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
1614 if (!pcs) return FALSE;
1615 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1616 name = strchr(Name, '!');
1617 if (name)
1619 char tmp[128];
1620 assert(name - Name < sizeof(tmp));
1621 memcpy(tmp, Name, name - Name);
1622 tmp[name - Name] = '\0';
1623 module = module_find_by_nameA(pcs, tmp);
1624 return find_name(pcs, module, name + 1, Symbol);
1627 /* search first in local context */
1628 pair.pcs = pcs;
1629 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1630 if (module_get_debug(&pair) &&
1631 (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1632 symt_check_tag(pcs->localscope_symt, SymTagInlineSite)))
1634 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1635 struct vector* v = &func->vchildren;
1636 unsigned i;
1638 for (i = 0; i < vector_length(v); i++)
1640 struct symt* lsym = *(struct symt**)vector_at(v, i);
1641 switch (lsym->tag)
1643 case SymTagBlock: /* no recursion */
1644 break;
1645 case SymTagData:
1646 name = symt_get_name(lsym);
1647 if (name && !strcmp(name, Name))
1649 symt_fill_sym_info(&pair, func, lsym, Symbol);
1650 return TRUE;
1652 break;
1653 case SymTagLabel: /* not returned here */
1654 case SymTagFuncDebugStart:
1655 case SymTagFuncDebugEnd:
1656 case SymTagCustom:
1657 case SymTagInlineSite:
1658 break;
1659 default:
1660 WARN("Unsupported tag: %u (%x)\n", lsym->tag, lsym->tag);
1664 /* lookup at global scope */
1665 for (module = pcs->lmodules; module; module = module->next)
1667 if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol))
1668 return TRUE;
1670 /* not found in PE modules, retry on the ELF ones
1672 if (dbghelp_opt_native)
1674 for (module = pcs->lmodules; module; module = module->next)
1676 if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
1677 !module_get_containee(pcs, module) &&
1678 find_name(pcs, module, Name, Symbol))
1679 return TRUE;
1682 SetLastError(ERROR_MOD_NOT_FOUND);
1683 return FALSE;
1686 /***********************************************************************
1687 * SymFromNameW (DBGHELP.@)
1689 BOOL WINAPI SymFromNameW(HANDLE process, const WCHAR *name, SYMBOL_INFOW *symbol)
1691 SYMBOL_INFO *si;
1692 DWORD len;
1693 char *tmp;
1694 BOOL ret;
1696 TRACE("(%p, %s, %p)\n", process, debugstr_w(name), symbol);
1698 len = sizeof(*si) + symbol->MaxNameLen;
1699 if (!(si = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE;
1701 len = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
1702 if (!(tmp = HeapAlloc(GetProcessHeap(), 0, len)))
1704 HeapFree(GetProcessHeap(), 0, si);
1705 return FALSE;
1707 WideCharToMultiByte(CP_ACP, 0, name, -1, tmp, len, NULL, NULL);
1709 si->SizeOfStruct = sizeof(*si);
1710 si->MaxNameLen = symbol->MaxNameLen;
1711 if ((ret = SymFromName(process, tmp, si)))
1712 copy_symbolW(symbol, si);
1714 HeapFree(GetProcessHeap(), 0, tmp);
1715 HeapFree(GetProcessHeap(), 0, si);
1716 return ret;
1719 /***********************************************************************
1720 * SymGetSymFromName64 (DBGHELP.@)
1722 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol)
1724 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1725 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1726 size_t len;
1728 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1729 si->SizeOfStruct = sizeof(*si);
1730 si->MaxNameLen = MAX_SYM_NAME;
1731 if (!SymFromName(hProcess, Name, si)) return FALSE;
1733 Symbol->Address = si->Address;
1734 Symbol->Size = si->Size;
1735 Symbol->Flags = si->Flags;
1736 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1737 lstrcpynA(Symbol->Name, si->Name, len);
1738 return TRUE;
1741 /***********************************************************************
1742 * SymGetSymFromName (DBGHELP.@)
1744 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symbol)
1746 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1747 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1748 size_t len;
1750 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1751 si->SizeOfStruct = sizeof(*si);
1752 si->MaxNameLen = MAX_SYM_NAME;
1753 if (!SymFromName(hProcess, Name, si)) return FALSE;
1755 Symbol->Address = si->Address;
1756 Symbol->Size = si->Size;
1757 Symbol->Flags = si->Flags;
1758 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1759 lstrcpynA(Symbol->Name, si->Name, len);
1760 return TRUE;
1763 struct internal_line_t
1765 BOOL unicode;
1766 PVOID key;
1767 DWORD line_number;
1768 union
1770 CHAR* file_nameA;
1771 WCHAR* file_nameW;
1773 DWORD64 address;
1776 static void init_internal_line(struct internal_line_t* intl, BOOL unicode)
1778 intl->unicode = unicode;
1779 intl->key = NULL;
1780 intl->line_number = 0;
1781 intl->file_nameA = NULL;
1782 intl->address = 0;
1785 static BOOL internal_line_copy_toA32(const struct internal_line_t* intl, IMAGEHLP_LINE* l32)
1787 if (intl->unicode) return FALSE;
1788 l32->Key = intl->key;
1789 l32->LineNumber = intl->line_number;
1790 l32->FileName = intl->file_nameA;
1791 l32->Address = intl->address;
1792 return TRUE;
1795 static BOOL internal_line_copy_toA64(const struct internal_line_t* intl, IMAGEHLP_LINE64* l64)
1797 if (intl->unicode) return FALSE;
1798 l64->Key = intl->key;
1799 l64->LineNumber = intl->line_number;
1800 l64->FileName = intl->file_nameA;
1801 l64->Address = intl->address;
1802 return TRUE;
1805 static BOOL internal_line_copy_toW64(const struct internal_line_t* intl, IMAGEHLP_LINEW64* l64)
1807 if (!intl->unicode) return FALSE;
1808 l64->Key = intl->key;
1809 l64->LineNumber = intl->line_number;
1810 l64->FileName = intl->file_nameW;
1811 l64->Address = intl->address;
1812 return TRUE;
1815 static BOOL internal_line_set_nameA(struct process* pcs, struct internal_line_t* intl, char* str, BOOL copy)
1817 DWORD len;
1819 if (intl->unicode)
1821 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1822 if (!(intl->file_nameW = fetch_buffer(pcs, len * sizeof(WCHAR)))) return FALSE;
1823 MultiByteToWideChar(CP_ACP, 0, str, -1, intl->file_nameW, len);
1825 else
1827 if (copy)
1829 len = strlen(str) + 1;
1830 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1831 memcpy(intl->file_nameA, str, len);
1833 else
1834 intl->file_nameA = str;
1836 return TRUE;
1839 static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* intl, WCHAR* wstr, BOOL copy)
1841 DWORD len;
1843 if (intl->unicode)
1845 if (copy)
1847 len = (lstrlenW(wstr) + 1) * sizeof(WCHAR);
1848 if (!(intl->file_nameW = fetch_buffer(pcs, len))) return FALSE;
1849 memcpy(intl->file_nameW, wstr, len);
1851 else
1852 intl->file_nameW = wstr;
1854 else
1856 DWORD len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
1857 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1858 WideCharToMultiByte(CP_ACP, 0, wstr, -1, intl->file_nameA, len, NULL, NULL);
1860 return TRUE;
1863 static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr,
1864 PDWORD pdwDisplacement, struct internal_line_t* intl)
1866 struct line_info* dli = NULL;
1867 struct line_info* found_dli = NULL;
1868 int i;
1870 for (i = vector_length(&func->vlines) - 1; i >= 0; i--)
1872 dli = vector_at(&func->vlines, i);
1873 if (!dli->is_source_file)
1875 if (found_dli || dli->u.address > addr) continue;
1876 intl->line_number = dli->line_number;
1877 intl->address = dli->u.address;
1878 intl->key = dli;
1879 found_dli = dli;
1880 continue;
1882 if (found_dli)
1884 BOOL ret;
1885 if (dbghelp_opt_native)
1887 /* Return native file paths when using winedbg */
1888 ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE);
1890 else
1892 WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file));
1893 ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE);
1894 HeapFree( GetProcessHeap(), 0, dospath );
1896 if (ret && pdwDisplacement) *pdwDisplacement = addr - found_dli->u.address;
1897 return ret;
1900 return FALSE;
1903 /******************************************************************
1904 * get_line_from_addr
1906 * fills source file information from an address
1908 static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr,
1909 PDWORD pdwDisplacement, struct internal_line_t* intl)
1911 struct module_pair pair;
1912 struct symt_ht* symt;
1914 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
1915 if ((symt = symt_find_symbol_at(pair.effective, addr)) == NULL) return FALSE;
1917 if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE;
1918 return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl);
1921 /***********************************************************************
1922 * SymGetSymNext64 (DBGHELP.@)
1924 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1926 /* algo:
1927 * get module from Symbol.Address
1928 * get index in module.addr_sorttab of Symbol.Address
1929 * increment index
1930 * if out of module bounds, move to next module in process address space
1932 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1933 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1934 return FALSE;
1937 /***********************************************************************
1938 * SymGetSymNext (DBGHELP.@)
1940 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1942 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1943 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1944 return FALSE;
1947 /***********************************************************************
1948 * SymGetSymPrev64 (DBGHELP.@)
1950 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1952 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1953 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1954 return FALSE;
1957 /***********************************************************************
1958 * SymGetSymPrev (DBGHELP.@)
1960 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1962 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1963 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1964 return FALSE;
1967 /******************************************************************
1968 * SymGetLineFromAddr (DBGHELP.@)
1971 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
1972 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
1974 struct internal_line_t intl;
1976 TRACE("(%p %p)\n", hProcess, Line);
1978 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1979 init_internal_line(&intl, FALSE);
1980 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
1981 return internal_line_copy_toA32(&intl, Line);
1984 /******************************************************************
1985 * SymGetLineFromAddr64 (DBGHELP.@)
1988 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
1989 PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line)
1991 struct internal_line_t intl;
1993 TRACE("(%p %p)\n", hProcess, Line);
1995 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1996 init_internal_line(&intl, FALSE);
1997 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
1998 return internal_line_copy_toA64(&intl, Line);
2001 /******************************************************************
2002 * SymGetLineFromAddrW64 (DBGHELP.@)
2005 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr,
2006 PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line)
2008 struct internal_line_t intl;
2010 TRACE("(%p %p)\n", hProcess, Line);
2012 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2013 init_internal_line(&intl, TRUE);
2014 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
2015 return internal_line_copy_toW64(&intl, Line);
2018 static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2020 struct module_pair pair;
2021 struct line_info* li;
2022 struct line_info* srcli;
2024 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2026 if (key == NULL) return FALSE;
2028 li = key;
2030 while (!li->is_first)
2032 li--;
2033 if (!li->is_source_file)
2035 intl->line_number = li->line_number;
2036 intl->address = li->u.address;
2037 intl->key = li;
2038 /* search source file */
2039 for (srcli = li; !srcli->is_source_file; srcli--);
2041 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2044 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2045 return FALSE;
2048 /******************************************************************
2049 * SymGetLinePrev64 (DBGHELP.@)
2052 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2054 struct internal_line_t intl;
2056 TRACE("(%p %p)\n", hProcess, Line);
2058 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2059 init_internal_line(&intl, FALSE);
2060 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2061 return internal_line_copy_toA64(&intl, Line);
2064 /******************************************************************
2065 * SymGetLinePrev (DBGHELP.@)
2068 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
2070 struct internal_line_t intl;
2072 TRACE("(%p %p)\n", hProcess, Line);
2074 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2075 init_internal_line(&intl, FALSE);
2076 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2077 return internal_line_copy_toA32(&intl, Line);
2080 /******************************************************************
2081 * SymGetLinePrevW64 (DBGHELP.@)
2084 BOOL WINAPI SymGetLinePrevW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2086 struct internal_line_t intl;
2088 TRACE("(%p %p)\n", hProcess, Line);
2090 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2091 init_internal_line(&intl, TRUE);
2092 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2093 return internal_line_copy_toW64(&intl, Line);
2096 static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2098 struct module_pair pair;
2099 struct line_info* li;
2100 struct line_info* srcli;
2102 if (key == NULL) return FALSE;
2103 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2105 /* search current source file */
2106 for (srcli = key; !srcli->is_source_file; srcli--);
2108 li = key;
2109 while (!li->is_last)
2111 li++;
2112 if (!li->is_source_file)
2114 intl->line_number = li->line_number;
2115 intl->address = li->u.address;
2116 intl->key = li;
2117 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2119 srcli = li;
2121 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2122 return FALSE;
2125 /******************************************************************
2126 * SymGetLineNext64 (DBGHELP.@)
2129 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2131 struct internal_line_t intl;
2133 TRACE("(%p %p)\n", hProcess, Line);
2135 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2136 init_internal_line(&intl, FALSE);
2137 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2138 return internal_line_copy_toA64(&intl, Line);
2141 /******************************************************************
2142 * SymGetLineNext (DBGHELP.@)
2145 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
2147 struct internal_line_t intl;
2149 TRACE("(%p %p)\n", hProcess, Line);
2151 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2152 init_internal_line(&intl, FALSE);
2153 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2154 return internal_line_copy_toA32(&intl, Line);
2157 /******************************************************************
2158 * SymGetLineNextW64 (DBGHELP.@)
2161 BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2163 struct internal_line_t intl;
2165 TRACE("(%p %p)\n", hProcess, Line);
2167 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2168 init_internal_line(&intl, TRUE);
2169 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2170 return internal_line_copy_toW64(&intl, Line);
2173 /***********************************************************************
2174 * SymUnDName (DBGHELP.@)
2176 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength)
2178 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2179 UNDNAME_COMPLETE) != 0;
2182 /***********************************************************************
2183 * SymUnDName64 (DBGHELP.@)
2185 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength)
2187 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2188 UNDNAME_COMPLETE) != 0;
2191 /***********************************************************************
2192 * UnDecorateSymbolName (DBGHELP.@)
2194 DWORD WINAPI UnDecorateSymbolName(const char *decorated_name, char *undecorated_name,
2195 DWORD undecorated_length, DWORD flags)
2197 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2198 debugstr_a(decorated_name), undecorated_name, undecorated_length, flags);
2200 if (!undecorated_name || !undecorated_length)
2201 return 0;
2202 if (!__unDName(undecorated_name, decorated_name, undecorated_length, malloc, free, flags))
2203 return 0;
2204 return strlen(undecorated_name);
2207 /***********************************************************************
2208 * UnDecorateSymbolNameW (DBGHELP.@)
2210 DWORD WINAPI UnDecorateSymbolNameW(const WCHAR *decorated_name, WCHAR *undecorated_name,
2211 DWORD undecorated_length, DWORD flags)
2213 char *buf, *ptr;
2214 int len, ret = 0;
2216 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2217 debugstr_w(decorated_name), undecorated_name, undecorated_length, flags);
2219 if (!undecorated_name || !undecorated_length)
2220 return 0;
2222 len = WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, NULL, 0, NULL, NULL);
2223 if ((buf = HeapAlloc(GetProcessHeap(), 0, len)))
2225 WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, buf, len, NULL, NULL);
2226 if ((ptr = __unDName(NULL, buf, 0, malloc, free, flags)))
2228 MultiByteToWideChar(CP_ACP, 0, ptr, -1, undecorated_name, undecorated_length);
2229 undecorated_name[undecorated_length - 1] = 0;
2230 ret = lstrlenW(undecorated_name);
2231 free(ptr);
2233 HeapFree(GetProcessHeap(), 0, buf);
2236 return ret;
2239 #define WILDCHAR(x) (-(x))
2241 static int re_fetch_char(const WCHAR** re)
2243 switch (**re)
2245 case '\\': (*re)++; return *(*re)++;
2246 case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
2247 default: return *(*re)++;
2251 static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
2253 return _case ? ch1 - ch2 : towupper(ch1) - towupper(ch2);
2256 static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
2258 int ch1, prev = 0;
2259 unsigned state = 0;
2261 switch (ch1 = re_fetch_char(&elt))
2263 default:
2264 return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
2265 case WILDCHAR('?'): return *string ? ++string : NULL;
2266 case WILDCHAR('*'): assert(0);
2267 case WILDCHAR('['): break;
2270 for (;;)
2272 ch1 = re_fetch_char(&elt);
2273 if (ch1 == WILDCHAR(']')) return NULL;
2274 if (state == 1 && ch1 == '-') state = 2;
2275 else
2277 if (re_match_char(*string, ch1, _case) == 0) return ++string;
2278 switch (state)
2280 case 0:
2281 state = 1;
2282 prev = ch1;
2283 break;
2284 case 1:
2285 state = 0;
2286 break;
2287 case 2:
2288 if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
2289 re_match_char(*string, ch1, _case) <= 0)
2290 return ++string;
2291 state = 0;
2292 break;
2298 /******************************************************************
2299 * re_match_multi
2301 * match a substring of *pstring according to *pre regular expression
2302 * pstring and pre are only updated in case of successful match
2304 static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
2306 const WCHAR* re_end = *pre;
2307 const WCHAR* string_end = *pstring;
2308 const WCHAR* re_beg;
2309 const WCHAR* string_beg;
2310 const WCHAR* next;
2311 int ch;
2313 while (*re_end && *string_end)
2315 string_beg = string_end;
2316 re_beg = re_end;
2317 switch (ch = re_fetch_char(&re_end))
2319 case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
2320 case WILDCHAR('*'):
2321 /* transform '*' into '?#' */
2322 re_beg = L"?";
2323 goto closure;
2324 case WILDCHAR('['):
2327 if (!(ch = re_fetch_char(&re_end))) return FALSE;
2328 } while (ch != WILDCHAR(']'));
2329 /* fall through */
2330 case WILDCHAR('?'):
2331 default:
2332 break;
2335 switch (*re_end)
2337 case '+':
2338 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2339 string_beg++;
2340 /* fall through */
2341 case '#':
2342 re_end++;
2343 closure:
2344 while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
2345 for ( ; string_end >= string_beg; string_end--)
2347 if (re_match_multi(&string_end, &re_end, _case)) goto found;
2349 return FALSE;
2350 default:
2351 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2352 string_end = next;
2356 if (*re_end || *string_end) return FALSE;
2358 found:
2359 *pre = re_end;
2360 *pstring = string_end;
2361 return TRUE;
2364 /******************************************************************
2365 * SymMatchStringA (DBGHELP.@)
2368 BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
2370 WCHAR* strW;
2371 WCHAR* reW;
2372 BOOL ret = FALSE;
2373 DWORD sz;
2375 if (!string || !re)
2377 SetLastError(ERROR_INVALID_HANDLE);
2378 return FALSE;
2380 TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
2382 sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
2383 if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2384 MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
2385 sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
2386 if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2387 MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
2389 if (strW && reW)
2390 ret = SymMatchStringW(strW, reW, _case);
2391 HeapFree(GetProcessHeap(), 0, strW);
2392 HeapFree(GetProcessHeap(), 0, reW);
2393 return ret;
2396 /******************************************************************
2397 * SymMatchStringW (DBGHELP.@)
2400 BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
2402 TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
2404 if (!string || !re)
2406 SetLastError(ERROR_INVALID_HANDLE);
2407 return FALSE;
2409 return re_match_multi(&string, &re, _case);
2412 static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2413 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2414 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2415 PVOID UserContext, DWORD Options)
2417 struct sym_enum se;
2419 if (Options != SYMSEARCH_GLOBALSONLY)
2421 FIXME("Unsupported searching with options (%lx)\n", Options);
2422 SetLastError(ERROR_INVALID_PARAMETER);
2423 return FALSE;
2426 se.cb = EnumSymbolsCallback;
2427 se.user = UserContext;
2428 se.index = Index;
2429 se.tag = SymTag;
2430 se.addr = Address;
2431 se.sym_info = (PSYMBOL_INFO)se.buffer;
2433 return sym_enum(hProcess, BaseOfDll, Mask, &se);
2436 /******************************************************************
2437 * SymSearch (DBGHELP.@)
2439 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2440 DWORD SymTag, PCSTR Mask, DWORD64 Address,
2441 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2442 PVOID UserContext, DWORD Options)
2444 LPWSTR maskW = NULL;
2445 BOOLEAN ret;
2447 TRACE("(%p %I64x %lu %lu %s %I64x %p %p %lx)\n",
2448 hProcess, BaseOfDll, Index, SymTag, Mask,
2449 Address, EnumSymbolsCallback, UserContext, Options);
2451 if (Mask)
2453 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
2455 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2456 return FALSE;
2457 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
2459 ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address,
2460 EnumSymbolsCallback, UserContext, Options);
2461 HeapFree(GetProcessHeap(), 0, maskW);
2462 return ret;
2465 /******************************************************************
2466 * SymSearchW (DBGHELP.@)
2468 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2469 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2470 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
2471 PVOID UserContext, DWORD Options)
2473 struct sym_enumW sew;
2475 TRACE("(%p %I64x %lu %lu %s %I64x %p %p %lx)\n",
2476 hProcess, BaseOfDll, Index, SymTag, debugstr_w(Mask),
2477 Address, EnumSymbolsCallback, UserContext, Options);
2479 sew.ctx = UserContext;
2480 sew.cb = EnumSymbolsCallback;
2481 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
2483 return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address,
2484 sym_enumW, &sew, Options);
2487 /******************************************************************
2488 * SymAddSymbol (DBGHELP.@)
2491 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name,
2492 DWORD64 addr, DWORD size, DWORD flags)
2494 struct module_pair pair;
2496 TRACE("(%p %s %I64x %lu)\n", hProcess, wine_dbgstr_a(name), addr, size);
2498 if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE;
2500 return symt_new_custom(pair.effective, name, addr, size) != NULL;
2503 /******************************************************************
2504 * SymAddSymbolW (DBGHELP.@)
2507 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR nameW,
2508 DWORD64 addr, DWORD size, DWORD flags)
2510 char name[MAX_SYM_NAME];
2512 TRACE("(%p %s %I64x %lu)\n", hProcess, wine_dbgstr_w(nameW), addr, size);
2514 WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, ARRAY_SIZE(name), NULL, NULL);
2516 return SymAddSymbol(hProcess, BaseOfDll, name, addr, size, flags);
2519 /******************************************************************
2520 * SymEnumLines (DBGHELP.@)
2523 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
2524 PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
2526 struct module_pair pair;
2527 struct hash_table_iter hti;
2528 struct symt_ht* sym;
2529 WCHAR* srcmask;
2530 struct line_info* dli;
2531 void* ptr;
2532 SRCCODEINFO sci;
2533 const char* file;
2535 if (!cb) return FALSE;
2536 if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
2538 if (!module_init_pair(&pair, hProcess, base)) return FALSE;
2539 if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
2540 if (!(srcmask = file_regex(srcfile))) return FALSE;
2542 sci.SizeOfStruct = sizeof(sci);
2543 sci.ModBase = base;
2545 hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
2546 while ((ptr = hash_table_iter_up(&hti)))
2548 unsigned int i;
2550 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
2551 if (sym->symt.tag != SymTagFunction) continue;
2553 sci.FileName[0] = '\0';
2554 for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
2556 dli = vector_at(&((struct symt_function*)sym)->vlines, i);
2557 if (dli->is_source_file)
2559 file = source_get(pair.effective, dli->u.source_file);
2560 if (!file) sci.FileName[0] = '\0';
2561 else
2563 DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
2564 WCHAR* fileW;
2566 if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2567 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz);
2568 if (SymMatchStringW(fileW, srcmask, FALSE))
2569 strcpy(sci.FileName, file);
2570 else
2571 sci.FileName[0] = '\0';
2572 HeapFree(GetProcessHeap(), 0, fileW);
2575 else if (sci.FileName[0])
2577 sci.Key = dli;
2578 sci.Obj[0] = '\0'; /* FIXME */
2579 sci.LineNumber = dli->line_number;
2580 sci.Address = dli->u.address;
2581 if (!cb(&sci, user)) break;
2585 HeapFree(GetProcessHeap(), 0, srcmask);
2586 return TRUE;
2589 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2590 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line)
2592 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2593 dwLineNumber, plDisplacement, Line);
2594 return FALSE;
2597 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2598 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line)
2600 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2601 dwLineNumber, lpDisplacement, Line);
2602 return FALSE;
2605 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName,
2606 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line)
2608 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName),
2609 dwLineNumber, plDisplacement, Line);
2610 return FALSE;
2613 /******************************************************************
2614 * SymFromIndex (DBGHELP.@)
2617 BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol)
2619 FIXME("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n",
2620 hProcess, BaseOfDll, index, symbol);
2622 return FALSE;
2625 /******************************************************************
2626 * SymFromIndexW (DBGHELP.@)
2629 BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol)
2631 FIXME("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n",
2632 hProcess, BaseOfDll, index, symbol);
2634 return FALSE;
2637 /******************************************************************
2638 * SymSetHomeDirectory (DBGHELP.@)
2641 PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR dir)
2643 FIXME("(%p, %s): stub\n", hProcess, dir);
2645 return NULL;
2648 /******************************************************************
2649 * SymSetHomeDirectoryW (DBGHELP.@)
2652 PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir)
2654 FIXME("(%p, %s): stub\n", hProcess, debugstr_w(dir));
2656 return NULL;
2659 /******************************************************************
2660 * SymFromInlineContext (DBGHELP.@)
2663 BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si)
2665 struct module_pair pair;
2666 struct symt_function* inlined;
2668 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, si);
2670 switch (IFC_MODE(inline_ctx))
2672 case IFC_MODE_INLINE:
2673 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2674 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2675 if (inlined)
2677 symt_fill_sym_info(&pair, NULL, &inlined->symt, si);
2678 if (disp) *disp = addr - inlined->ranges[0].low;
2679 return TRUE;
2681 /* fall through */
2682 case IFC_MODE_IGNORE:
2683 case IFC_MODE_REGULAR:
2684 return SymFromAddr(hProcess, addr, disp, si);
2685 default:
2686 SetLastError(ERROR_INVALID_PARAMETER);
2687 return FALSE;
2691 /******************************************************************
2692 * SymFromInlineContextW (DBGHELP.@)
2695 BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFOW siW)
2697 PSYMBOL_INFO si;
2698 unsigned len;
2699 BOOL ret;
2701 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, siW);
2703 len = sizeof(*si) + siW->MaxNameLen * sizeof(WCHAR);
2704 si = HeapAlloc(GetProcessHeap(), 0, len);
2705 if (!si) return FALSE;
2707 si->SizeOfStruct = sizeof(*si);
2708 si->MaxNameLen = siW->MaxNameLen;
2709 if ((ret = SymFromInlineContext(hProcess, addr, inline_ctx, disp, si)))
2711 copy_symbolW(siW, si);
2713 HeapFree(GetProcessHeap(), 0, si);
2714 return ret;
2717 static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp,
2718 struct internal_line_t* intl)
2720 struct module_pair pair;
2721 struct symt_function* inlined;
2723 if (!module_init_pair(&pair, hProcess, mod_addr ? mod_addr : addr)) return FALSE;
2724 switch (IFC_MODE(inline_ctx))
2726 case IFC_MODE_INLINE:
2727 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2728 if (inlined && get_line_from_function(&pair, inlined, addr, disp, intl))
2729 return TRUE;
2730 /* fall through: check if we can find line info at top function level */
2731 case IFC_MODE_IGNORE:
2732 case IFC_MODE_REGULAR:
2733 return get_line_from_addr(hProcess, addr, disp, intl);
2734 default:
2735 SetLastError(ERROR_INVALID_PARAMETER);
2736 return FALSE;
2740 /******************************************************************
2741 * SymGetLineFromInlineContext (DBGHELP.@)
2744 BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line)
2746 struct internal_line_t intl;
2748 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2749 hProcess, addr, inline_ctx, mod_addr, disp, line);
2751 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2752 init_internal_line(&intl, FALSE);
2754 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2755 return internal_line_copy_toA64(&intl, line);
2758 /******************************************************************
2759 * SymGetLineFromInlineContextW (DBGHELP.@)
2762 BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line)
2764 struct internal_line_t intl;
2766 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2767 hProcess, addr, inline_ctx, mod_addr, disp, line);
2769 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2770 init_internal_line(&intl, TRUE);
2772 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2773 return internal_line_copy_toW64(&intl, line);
2776 /******************************************************************
2777 * SymAddrIncludeInlineTrace (DBGHELP.@)
2779 * MSDN doesn't state that the maximum depth (of embedded inline sites) at <addr>
2780 * is actually returned. (It just says non zero means that there are some inline site(s)).
2781 * But this is what native actually returns.
2783 DWORD WINAPI SymAddrIncludeInlineTrace(HANDLE hProcess, DWORD64 addr)
2785 struct module_pair pair;
2786 DWORD depth = 0;
2788 TRACE("(%p, %#I64x)\n", hProcess, addr);
2790 if (module_init_pair(&pair, hProcess, addr))
2792 struct symt_ht* symt = symt_find_symbol_at(pair.effective, addr);
2793 if (symt_check_tag(&symt->symt, SymTagFunction))
2795 struct symt_function* inlined = symt_find_lowest_inlined((struct symt_function*)symt, addr);
2796 if (inlined)
2798 for ( ; &inlined->symt != &symt->symt; inlined = (struct symt_function*)symt_get_upper_inlined(inlined))
2799 ++depth;
2803 return depth;
2806 /******************************************************************
2807 * SymQueryInlineTrace (DBGHELP.@)
2810 BOOL WINAPI SymQueryInlineTrace(HANDLE hProcess, DWORD64 StartAddress, DWORD StartContext,
2811 DWORD64 StartRetAddress, DWORD64 CurAddress,
2812 LPDWORD CurContext, LPDWORD CurFrameIndex)
2814 struct module_pair pair;
2815 struct symt_ht* sym_curr;
2816 struct symt_ht* sym_start;
2817 struct symt_ht* sym_startret;
2818 DWORD depth;
2820 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %I64x, %p, %p)\n",
2821 hProcess, StartAddress, StartContext, StartRetAddress, CurAddress, CurContext, CurFrameIndex);
2823 if (!module_init_pair(&pair, hProcess, CurAddress)) return FALSE;
2824 if (!(sym_curr = symt_find_symbol_at(pair.effective, CurAddress))) return FALSE;
2825 if (!symt_check_tag(&sym_curr->symt, SymTagFunction)) return FALSE;
2827 sym_start = symt_find_symbol_at(pair.effective, StartAddress);
2828 sym_startret = symt_find_symbol_at(pair.effective, StartRetAddress);
2829 if (sym_start != sym_curr && sym_startret != sym_curr)
2831 SetLastError(ERROR_INVALID_PARAMETER);
2832 return FALSE;
2834 if (sym_start != sym_curr || StartContext)
2836 FIXME("(%p, %#I64x, 0x%lx, %#I64x, %I64x, %p, %p): semi-stub\n",
2837 hProcess, StartAddress, StartContext, StartRetAddress, CurAddress, CurContext, CurFrameIndex);
2838 return ERROR_CALL_NOT_IMPLEMENTED;
2841 depth = SymAddrIncludeInlineTrace(hProcess, CurAddress);
2842 if (depth)
2844 *CurContext = IFC_MODE_INLINE; /* deepest inline site */
2845 *CurFrameIndex = depth;
2847 else
2849 *CurContext = IFC_MODE_REGULAR;
2850 *CurFrameIndex = 0;
2852 return TRUE;
2855 /******************************************************************
2856 * SymSrvGetFileIndexInfo (DBGHELP.@)
2859 BOOL WINAPI SymSrvGetFileIndexInfo(const char *file, SYMSRV_INDEX_INFO* info, DWORD flags)
2861 FIXME("(%s, %p, 0x%08lx): stub!\n", debugstr_a(file), info, flags);
2862 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2863 return FALSE;