cmd: DIR command outputs free space for the path.
[wine.git] / dlls / dbghelp / symbol.c
blob7d7dc9b40a356aaaab6bad6075b609fdfb66e5de
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 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <assert.h>
28 #include "wine/debug.h"
29 #include "dbghelp_private.h"
30 #include "winnls.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
33 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
35 extern char * CDECL __unDName(char *buffer, const char *mangled, int len,
36 void * (CDECL *pfn_alloc)(size_t), void (CDECL *pfn_free)(void *), unsigned short flags);
38 static inline int cmp_addr(ULONG64 a1, ULONG64 a2)
40 if (a1 > a2) return 1;
41 if (a1 < a2) return -1;
42 return 0;
45 static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr)
47 ULONG64 ref;
48 symt_get_address(&module->addr_sorttab[idx]->symt, &ref);
49 return cmp_addr(ref, addr);
52 int __cdecl symt_cmp_addr(const void* p1, const void* p2)
54 const struct symt* sym1 = *(const struct symt* const *)p1;
55 const struct symt* sym2 = *(const struct symt* const *)p2;
56 ULONG64 a1, a2;
58 symt_get_address(sym1, &a1);
59 symt_get_address(sym2, &a2);
60 return cmp_addr(a1, a2);
63 #define BASE_CUSTOM_SYMT 0x80000000
65 /* dbghelp exposes the internal symbols/types with DWORD indexes.
66 * - custom symbols are always stored with index starting at BASE_CUSTOM_SYMT
67 * - for all the other (non custom) symbols:
68 * + on 32-bit machines, index is set to the actual address of symt
69 * + on 64-bit machines, the symt address is stored in a dedicated array
70 * which is exposed to the caller and index is the index of the symbol in
71 * this array
73 DWORD symt_ptr2index(struct module* module, const struct symt* sym)
75 struct vector* vector;
76 DWORD offset;
77 const struct symt** c;
78 int len, i;
80 if (!sym) return 0;
81 if (sym->tag == SymTagCustom)
83 vector = &module->vcustom_symt;
84 offset = BASE_CUSTOM_SYMT;
86 else
88 #ifdef _WIN64
89 vector = &module->vsymt;
90 offset = 1;
91 #else
92 return (DWORD)sym;
93 #endif
95 len = vector_length(vector);
96 /* FIXME: this is inefficient */
97 for (i = 0; i < len; i++)
99 if (*(struct symt**)vector_at(vector, i) == sym)
100 return i + offset;
102 /* not found */
103 c = vector_add(vector, &module->pool);
104 if (c) *c = sym;
105 return len + offset;
108 struct symt* symt_index2ptr(struct module* module, DWORD id)
110 struct vector* vector;
111 if (id >= BASE_CUSTOM_SYMT)
113 id -= BASE_CUSTOM_SYMT;
114 vector = &module->vcustom_symt;
116 else
118 #ifdef _WIN64
119 if (!id--) return NULL;
120 vector = &module->vsymt;
121 #else
122 return (struct symt*)id;
123 #endif
125 return (id >= vector_length(vector)) ? NULL : *(struct symt**)vector_at(vector, id);
128 static BOOL symt_grow_sorttab(struct module* module, unsigned sz)
130 struct symt_ht** new;
131 unsigned int size;
133 if (sz <= module->sorttab_size) return TRUE;
134 if (module->addr_sorttab)
136 size = module->sorttab_size * 2;
137 new = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab,
138 size * sizeof(struct symt_ht*));
140 else
142 size = 64;
143 new = HeapAlloc(GetProcessHeap(), 0, size * sizeof(struct symt_ht*));
145 if (!new) return FALSE;
146 module->sorttab_size = size;
147 module->addr_sorttab = new;
148 return TRUE;
151 static void symt_add_module_addr(struct module* module, struct symt_ht* ht)
153 ULONG64 addr;
155 /* Don't store in sorttab a symbol without address, they are of
156 * no use here (e.g. constant values)
158 if (symt_get_address(&ht->symt, &addr) &&
159 symt_grow_sorttab(module, module->num_symbols + 1))
161 module->addr_sorttab[module->num_symbols++] = ht;
162 module->sortlist_valid = FALSE;
166 static void symt_add_module_ht(struct module* module, struct symt_ht* ht)
168 hash_table_add(&module->ht_symbols, &ht->hash_elt);
169 symt_add_module_addr(module, ht);
172 static WCHAR* file_regex(const char* srcfile)
174 WCHAR* mask;
175 WCHAR* p;
177 if (!srcfile || !*srcfile)
179 if (!(p = mask = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(WCHAR)))) return NULL;
180 *p++ = '?';
181 *p++ = '#';
183 else
185 DWORD sz = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
186 WCHAR* srcfileW;
188 /* FIXME: we use here the largest conversion for every char... could be optimized */
189 p = mask = HeapAlloc(GetProcessHeap(), 0, (5 * strlen(srcfile) + 1 + sz) * sizeof(WCHAR));
190 if (!mask) return NULL;
191 srcfileW = mask + 5 * strlen(srcfile) + 1;
192 MultiByteToWideChar(CP_ACP, 0, srcfile, -1, srcfileW, sz);
194 while (*srcfileW)
196 switch (*srcfileW)
198 case '\\':
199 case '/':
200 *p++ = '[';
201 *p++ = '\\';
202 *p++ = '\\';
203 *p++ = '/';
204 *p++ = ']';
205 break;
206 case '.':
207 *p++ = '?';
208 break;
209 default:
210 *p++ = *srcfileW;
211 break;
213 srcfileW++;
216 *p = 0;
217 return mask;
220 struct symt_module* symt_new_module(struct module* module)
222 struct symt_module* sym;
224 TRACE_(dbghelp_symt)("Adding toplevel exe symbol %s\n", debugstr_w(module->modulename));
225 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
227 sym->symt.tag = SymTagExe;
228 sym->module = module;
229 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
231 return sym;
234 struct symt_compiland* symt_new_compiland(struct module* module, unsigned src_idx)
236 struct symt_compiland* sym;
237 struct symt_compiland** p;
239 TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n",
240 debugstr_w(module->modulename), source_get(module, src_idx));
241 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
243 sym->symt.tag = SymTagCompiland;
244 sym->container = module->top;
245 sym->address = 0;
246 sym->source = src_idx;
247 vector_init(&sym->vchildren, sizeof(struct symt*), 32);
248 sym->user = NULL;
249 p = vector_add(&module->top->vchildren, &module->pool);
250 *p = sym;
252 return sym;
255 struct symt_public* symt_new_public(struct module* module,
256 struct symt_compiland* compiland,
257 const char* name,
258 BOOL is_function,
259 ULONG_PTR address, unsigned size)
261 struct symt_public* sym;
262 struct symt** p;
264 TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%Ix\n",
265 debugstr_w(module->modulename), name, address);
266 if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
267 symt_find_nearest(module, address) != NULL)
268 return NULL;
269 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
271 sym->symt.tag = SymTagPublicSymbol;
272 sym->hash_elt.name = pool_strdup(&module->pool, name);
273 sym->container = compiland ? &compiland->symt : NULL;
274 sym->is_function = is_function;
275 sym->address = address;
276 sym->size = size;
277 symt_add_module_ht(module, (struct symt_ht*)sym);
278 if (compiland)
280 p = vector_add(&compiland->vchildren, &module->pool);
281 *p = &sym->symt;
284 return sym;
287 struct symt_data* symt_new_global_variable(struct module* module,
288 struct symt_compiland* compiland,
289 const char* name, unsigned is_static,
290 struct location loc, ULONG_PTR size,
291 struct symt* type)
293 struct symt_data* sym;
294 struct symt** p;
295 DWORD64 tsz;
297 TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%Ix %p\n",
298 debugstr_w(module->modulename), name, loc.kind, loc.offset, type);
299 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
301 sym->symt.tag = SymTagData;
302 sym->hash_elt.name = pool_strdup(&module->pool, name);
303 sym->kind = is_static ? DataIsFileStatic : DataIsGlobal;
304 sym->container = compiland ? &compiland->symt : &module->top->symt;
305 sym->type = type;
306 sym->u.var = loc;
307 if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz))
309 if (tsz != size)
310 FIXME("Size mismatch for %s.%s between type (%I64u) and src (%Iu)\n",
311 debugstr_w(module->modulename), name, tsz, size);
313 symt_add_module_ht(module, (struct symt_ht*)sym);
314 p = vector_add(compiland ? &compiland->vchildren : &module->top->vchildren, &module->pool);
315 *p = &sym->symt;
317 return sym;
320 static struct symt_function* init_function_or_inlinesite(struct module* module,
321 DWORD tag,
322 struct symt* container,
323 const char* name,
324 struct symt* sig_type,
325 unsigned num_ranges)
327 struct symt_function* sym;
329 assert(!sig_type || sig_type->tag == SymTagFunctionType);
330 if ((sym = pool_alloc(&module->pool, offsetof(struct symt_function, ranges[num_ranges]))))
332 sym->symt.tag = tag;
333 sym->hash_elt.name = pool_strdup(&module->pool, name);
334 sym->container = container;
335 sym->type = sig_type;
336 vector_init(&sym->vlines, sizeof(struct line_info), 64);
337 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
338 sym->num_ranges = num_ranges;
340 return sym;
343 struct symt_function* symt_new_function(struct module* module,
344 struct symt_compiland* compiland,
345 const char* name,
346 ULONG_PTR addr, ULONG_PTR size,
347 struct symt* sig_type)
349 struct symt_function* sym;
351 TRACE_(dbghelp_symt)("Adding global function %s:%s @%Ix-%Ix\n",
352 debugstr_w(module->modulename), name, addr, addr + size - 1);
353 if ((sym = init_function_or_inlinesite(module, SymTagFunction, &compiland->symt, name, sig_type, 1)))
355 struct symt** p;
356 sym->ranges[0].low = addr;
357 sym->ranges[0].high = addr + size;
358 sym->next_inlinesite = NULL; /* first of list */
359 symt_add_module_ht(module, (struct symt_ht*)sym);
360 if (compiland)
362 p = vector_add(&compiland->vchildren, &module->pool);
363 *p = &sym->symt;
366 return sym;
369 struct symt_function* symt_new_inlinesite(struct module* module,
370 struct symt_function* func,
371 struct symt* container,
372 const char* name,
373 struct symt* sig_type,
374 unsigned num_ranges)
376 struct symt_function* sym;
378 TRACE_(dbghelp_symt)("Adding inline site %s\n", name);
379 if ((sym = init_function_or_inlinesite(module, SymTagInlineSite, container, name, sig_type, num_ranges)))
381 struct symt** p;
382 assert(container);
384 /* chain inline sites */
385 sym->next_inlinesite = func->next_inlinesite;
386 func->next_inlinesite = sym;
387 if (container->tag == SymTagFunction || container->tag == SymTagInlineSite)
388 p = vector_add(&((struct symt_function*)container)->vchildren, &module->pool);
389 else
391 assert(container->tag == SymTagBlock);
392 p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool);
394 *p = &sym->symt;
396 return sym;
399 void symt_add_func_line(struct module* module, struct symt_function* func,
400 unsigned source_idx, int line_num, ULONG_PTR addr)
402 struct line_info* dli;
403 unsigned vlen;
404 struct line_info* prev;
405 BOOL last_matches = FALSE;
406 int i;
408 if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
410 TRACE_(dbghelp_symt)("(%p)%s:%Ix %s:%u\n",
411 func, func->hash_elt.name, addr,
412 source_get(module, source_idx), line_num);
414 assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite);
416 for (i=vector_length(&func->vlines)-1; i>=0; i--)
418 dli = vector_at(&func->vlines, i);
419 if (dli->is_source_file)
421 last_matches = (source_idx == dli->u.source_file);
422 break;
425 vlen = vector_length(&func->vlines);
426 prev = vlen ? vector_at(&func->vlines, vlen - 1) : NULL;
427 if (last_matches && prev && addr == prev->u.address)
429 WARN("Duplicate addition of line number in %s\n", func->hash_elt.name);
430 return;
432 if (!last_matches)
434 /* we shouldn't have line changes on first line of function */
435 dli = vector_add(&func->vlines, &module->pool);
436 dli->is_source_file = 1;
437 dli->is_first = (prev == NULL);
438 dli->is_last = 0;
439 dli->line_number = 0;
440 dli->u.source_file = source_idx;
442 /* clear previous last */
443 if (prev) prev->is_last = 0;
444 dli = vector_add(&func->vlines, &module->pool);
445 dli->is_source_file = 0;
446 dli->is_first = 0; /* only a source file can be first */
447 dli->is_last = 1;
448 dli->line_number = line_num;
449 dli->u.address = addr;
452 /******************************************************************
453 * symt_add_func_local
455 * Adds a new local/parameter to a given function:
456 * In any cases, dt tells whether it's a local variable or a parameter
457 * or a static variable inside the function.
458 * If regno it's not 0:
459 * - then variable is stored in a register
460 * - otherwise, value is referenced by register + offset
461 * Otherwise, the variable is stored on the stack:
462 * - offset is then the offset from the frame register
464 struct symt_data* symt_add_func_local(struct module* module,
465 struct symt_function* func,
466 enum DataKind dt,
467 const struct location* loc,
468 struct symt_block* block,
469 struct symt* type, const char* name)
471 struct symt_data* locsym;
472 struct symt** p;
474 TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n",
475 debugstr_w(module->modulename), func->hash_elt.name,
476 name, type);
478 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
479 assert(dt == DataIsParam || dt == DataIsLocal || dt == DataIsStaticLocal);
481 locsym = pool_alloc(&module->pool, sizeof(*locsym));
482 locsym->symt.tag = SymTagData;
483 locsym->hash_elt.name = pool_strdup(&module->pool, name);
484 locsym->hash_elt.next = NULL;
485 locsym->kind = dt;
486 locsym->container = block ? &block->symt : &func->symt;
487 locsym->type = type;
488 locsym->u.var = *loc;
489 if (block)
490 p = vector_add(&block->vchildren, &module->pool);
491 else
492 p = vector_add(&func->vchildren, &module->pool);
493 *p = &locsym->symt;
494 if (dt == DataIsStaticLocal)
495 symt_add_module_addr(module, (struct symt_ht*)locsym);
496 return locsym;
499 /******************************************************************
500 * symt_add_func_local
502 * Adds a new (local) constant to a given function
504 struct symt_data* symt_add_func_constant(struct module* module,
505 struct symt_function* func,
506 struct symt_block* block,
507 struct symt* type, const char* name,
508 VARIANT* v)
510 struct symt_data* locsym;
511 struct symt** p;
513 TRACE_(dbghelp_symt)("Adding local constant (%s:%s): %s %p\n",
514 debugstr_w(module->modulename), func->hash_elt.name,
515 name, type);
517 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
519 locsym = pool_alloc(&module->pool, sizeof(*locsym));
520 locsym->symt.tag = SymTagData;
521 locsym->hash_elt.name = pool_strdup(&module->pool, name);
522 locsym->hash_elt.next = NULL;
523 locsym->kind = DataIsConstant;
524 locsym->container = block ? &block->symt : &func->symt;
525 locsym->type = type;
526 locsym->u.value = *v;
527 if (block)
528 p = vector_add(&block->vchildren, &module->pool);
529 else
530 p = vector_add(&func->vchildren, &module->pool);
531 *p = &locsym->symt;
532 return locsym;
535 struct symt_block* symt_open_func_block(struct module* module,
536 struct symt_function* func,
537 struct symt_block* parent_block,
538 unsigned num_ranges)
540 struct symt_block* block;
541 struct symt** p;
543 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
544 assert(num_ranges > 0);
545 assert(!parent_block || parent_block->symt.tag == SymTagBlock);
547 block = pool_alloc(&module->pool, offsetof(struct symt_block, ranges[num_ranges]));
548 block->symt.tag = SymTagBlock;
549 block->num_ranges = num_ranges;
550 block->container = parent_block ? &parent_block->symt : &func->symt;
551 vector_init(&block->vchildren, sizeof(struct symt*), 4);
552 if (parent_block)
553 p = vector_add(&parent_block->vchildren, &module->pool);
554 else
555 p = vector_add(&func->vchildren, &module->pool);
556 *p = &block->symt;
558 return block;
561 struct symt_block* symt_close_func_block(struct module* module,
562 const struct symt_function* func,
563 struct symt_block* block)
565 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
567 return (block->container->tag == SymTagBlock) ?
568 CONTAINING_RECORD(block->container, struct symt_block, symt) : NULL;
571 struct symt_hierarchy_point* symt_add_function_point(struct module* module,
572 struct symt_function* func,
573 enum SymTagEnum point,
574 const struct location* loc,
575 const char* name)
577 struct symt_hierarchy_point*sym;
578 struct symt** p;
580 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
582 sym->symt.tag = point;
583 sym->parent = &func->symt;
584 sym->loc = *loc;
585 sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL;
586 p = vector_add(&func->vchildren, &module->pool);
587 *p = &sym->symt;
589 return sym;
592 struct symt_thunk* symt_new_thunk(struct module* module,
593 struct symt_compiland* compiland,
594 const char* name, THUNK_ORDINAL ord,
595 ULONG_PTR addr, ULONG_PTR size)
597 struct symt_thunk* sym;
599 TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%Ix-%Ix\n",
600 debugstr_w(module->modulename), name, addr, addr + size - 1);
602 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
604 sym->symt.tag = SymTagThunk;
605 sym->hash_elt.name = pool_strdup(&module->pool, name);
606 sym->container = &compiland->symt;
607 sym->address = addr;
608 sym->size = size;
609 sym->ordinal = ord;
610 symt_add_module_ht(module, (struct symt_ht*)sym);
611 if (compiland)
613 struct symt** p;
614 p = vector_add(&compiland->vchildren, &module->pool);
615 *p = &sym->symt;
618 return sym;
621 struct symt_data* symt_new_constant(struct module* module,
622 struct symt_compiland* compiland,
623 const char* name, struct symt* type,
624 const VARIANT* v)
626 struct symt_data* sym;
628 TRACE_(dbghelp_symt)("Adding constant value %s:%s\n",
629 debugstr_w(module->modulename), name);
631 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
633 sym->symt.tag = SymTagData;
634 sym->hash_elt.name = pool_strdup(&module->pool, name);
635 sym->kind = DataIsConstant;
636 sym->container = compiland ? &compiland->symt : &module->top->symt;
637 sym->type = type;
638 sym->u.value = *v;
639 symt_add_module_ht(module, (struct symt_ht*)sym);
640 if (compiland)
642 struct symt** p;
643 p = vector_add(&compiland->vchildren, &module->pool);
644 *p = &sym->symt;
647 return sym;
650 struct symt_hierarchy_point* symt_new_label(struct module* module,
651 struct symt_compiland* compiland,
652 const char* name, ULONG_PTR address)
654 struct symt_hierarchy_point* sym;
656 TRACE_(dbghelp_symt)("Adding global label value %s:%s\n",
657 debugstr_w(module->modulename), name);
659 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
661 sym->symt.tag = SymTagLabel;
662 sym->hash_elt.name = pool_strdup(&module->pool, name);
663 sym->loc.kind = loc_absolute;
664 sym->loc.offset = address;
665 sym->parent = compiland ? &compiland->symt : NULL;
666 symt_add_module_ht(module, (struct symt_ht*)sym);
667 if (compiland)
669 struct symt** p;
670 p = vector_add(&compiland->vchildren, &module->pool);
671 *p = &sym->symt;
674 return sym;
677 struct symt_custom* symt_new_custom(struct module* module, const char* name,
678 DWORD64 addr, DWORD size)
680 struct symt_custom* sym;
682 TRACE_(dbghelp_symt)("Adding custom symbol %s:%s\n",
683 debugstr_w(module->modulename), name);
685 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
687 sym->symt.tag = SymTagCustom;
688 sym->hash_elt.name = pool_strdup(&module->pool, name);
689 sym->address = addr;
690 sym->size = size;
691 symt_add_module_ht(module, (struct symt_ht*)sym);
693 return sym;
696 /* expect sym_info->MaxNameLen to be set before being called */
697 static void symt_fill_sym_info(struct module_pair* pair,
698 const struct symt_function* func,
699 const struct symt* sym, SYMBOL_INFO* sym_info)
701 const char* name;
702 DWORD64 size;
703 char* tmp;
705 if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex))
706 sym_info->TypeIndex = 0;
707 sym_info->Index = symt_ptr2index(pair->effective, sym);
708 sym_info->Reserved[0] = sym_info->Reserved[1] = 0;
709 if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) &&
710 (!sym_info->TypeIndex ||
711 !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex),
712 TI_GET_LENGTH, &size)))
713 size = 0;
714 sym_info->Size = (DWORD)size;
715 sym_info->ModBase = pair->requested->module.BaseOfImage;
716 sym_info->Flags = 0;
717 sym_info->Value = 0;
719 switch (sym->tag)
721 case SymTagData:
723 const struct symt_data* data = (const struct symt_data*)sym;
724 switch (data->kind)
726 case DataIsParam:
727 sym_info->Flags |= SYMFLAG_PARAMETER;
728 /* fall through */
729 case DataIsLocal:
730 sym_info->Flags |= SYMFLAG_LOCAL;
732 struct location loc = data->u.var;
734 if (loc.kind >= loc_user)
736 unsigned i;
737 struct module_format* modfmt;
739 for (i = 0; i < DFI_LAST; i++)
741 modfmt = pair->effective->format_info[i];
742 if (modfmt && modfmt->loc_compute)
744 modfmt->loc_compute(pair->pcs, modfmt, func, &loc);
745 break;
749 switch (loc.kind)
751 case loc_error:
752 /* for now we report error cases as a negative register number */
753 /* fall through */
754 case loc_register:
755 sym_info->Flags |= SYMFLAG_REGISTER;
756 sym_info->Register = loc.reg;
757 sym_info->Address = 0;
758 break;
759 case loc_regrel:
760 sym_info->Flags |= SYMFLAG_REGREL;
761 sym_info->Register = loc.reg;
762 if (loc.reg == CV_REG_NONE || (int)loc.reg < 0 /* error */)
763 FIXME("suspicious register value %x\n", loc.reg);
764 sym_info->Address = loc.offset;
765 break;
766 case loc_absolute:
767 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
768 sym_info->Value = loc.offset;
769 break;
770 default:
771 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", loc.kind);
772 assert(0);
775 break;
776 case DataIsGlobal:
777 case DataIsFileStatic:
778 case DataIsStaticLocal:
779 switch (data->u.var.kind)
781 case loc_tlsrel:
782 sym_info->Flags |= SYMFLAG_TLSREL;
783 /* fall through */
784 case loc_absolute:
785 symt_get_address(sym, &sym_info->Address);
786 sym_info->Register = 0;
787 break;
788 default:
789 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind);
790 assert(0);
792 break;
793 case DataIsConstant:
794 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
795 if (data->container &&
796 (data->container->tag == SymTagFunction || data->container->tag == SymTagBlock))
797 sym_info->Flags |= SYMFLAG_LOCAL;
798 switch (V_VT(&data->u.value))
800 case VT_I8: sym_info->Value = (LONG64)V_I8(&data->u.value); break;
801 case VT_I4: sym_info->Value = (LONG64)V_I4(&data->u.value); break;
802 case VT_I2: sym_info->Value = (LONG64)V_I2(&data->u.value); break;
803 case VT_I1: sym_info->Value = (LONG64)V_I1(&data->u.value); break;
804 case VT_UINT:sym_info->Value = V_UINT(&data->u.value); break;
805 case VT_UI8: sym_info->Value = V_UI8(&data->u.value); break;
806 case VT_UI4: sym_info->Value = V_UI4(&data->u.value); break;
807 case VT_UI2: sym_info->Value = V_UI2(&data->u.value); break;
808 case VT_UI1: sym_info->Value = V_UI1(&data->u.value); break;
809 case VT_BYREF: sym_info->Value = (DWORD_PTR)V_BYREF(&data->u.value); break;
810 case VT_EMPTY: sym_info->Value = 0; break;
811 default:
812 FIXME("Unsupported variant type (%u)\n", V_VT(&data->u.value));
813 sym_info->Value = 0;
814 break;
816 break;
817 default:
818 FIXME("Unhandled kind (%u) in sym data\n", data->kind);
821 break;
822 case SymTagPublicSymbol:
824 const struct symt_public* pub = (const struct symt_public*)sym;
825 if (pub->is_function)
826 sym_info->Flags |= SYMFLAG_PUBLIC_CODE;
827 else
828 sym_info->Flags |= SYMFLAG_EXPORT;
829 symt_get_address(sym, &sym_info->Address);
831 break;
832 case SymTagFunction:
833 case SymTagInlineSite:
834 symt_get_address(sym, &sym_info->Address);
835 break;
836 case SymTagThunk:
837 sym_info->Flags |= SYMFLAG_THUNK;
838 symt_get_address(sym, &sym_info->Address);
839 break;
840 case SymTagCustom:
841 symt_get_address(sym, &sym_info->Address);
842 sym_info->Flags |= SYMFLAG_VIRTUAL;
843 break;
844 default:
845 symt_get_address(sym, &sym_info->Address);
846 sym_info->Register = 0;
847 break;
849 sym_info->Scope = 0; /* FIXME */
850 sym_info->Tag = sym->tag;
851 name = symt_get_name(sym);
852 if (sym_info->MaxNameLen &&
853 sym->tag == SymTagPublicSymbol && (dbghelp_options & SYMOPT_UNDNAME) &&
854 (tmp = __unDName(NULL, name, 0, malloc, free, UNDNAME_NAME_ONLY)) != NULL)
856 symbol_setname(sym_info, tmp);
857 free(tmp);
859 else
860 symbol_setname(sym_info, name);
862 TRACE_(dbghelp_symt)("%p => %s %lu %I64x\n",
863 sym, sym_info->Name, sym_info->Size, sym_info->Address);
866 struct sym_enum
868 PSYM_ENUMERATESYMBOLS_CALLBACK cb;
869 PVOID user;
870 SYMBOL_INFO* sym_info;
871 DWORD index;
872 DWORD tag;
873 DWORD64 addr;
874 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
877 static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
878 const struct symt_function* func, const struct symt* sym)
880 symt_fill_sym_info(pair, func, sym, se->sym_info);
881 if (se->index && se->sym_info->Index != se->index) return FALSE;
882 if (se->tag && se->sym_info->Tag != se->tag) return FALSE;
883 if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE;
884 return !se->cb(se->sym_info, se->sym_info->Size, se->user);
887 static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match,
888 const struct sym_enum* se)
890 void* ptr;
891 struct symt_ht* sym = NULL;
892 struct hash_table_iter hti;
893 WCHAR* nameW;
894 BOOL ret;
896 hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
897 while ((ptr = hash_table_iter_up(&hti)))
899 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
900 nameW = symt_get_nameW(&sym->symt);
901 ret = SymMatchStringW(nameW, match, FALSE);
902 HeapFree(GetProcessHeap(), 0, nameW);
903 if (ret)
905 se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
906 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
907 if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
910 return FALSE;
913 static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt)
915 unsigned low = 0, mid = high / 2;
916 ULONG64 addr;
918 if (!high) return 0;
919 symt_get_address(&elt->symt, &addr);
922 switch (cmp_sorttab_addr(module, mid, addr))
924 case 0: return mid;
925 case -1: low = mid + 1; break;
926 case 1: high = mid; break;
928 mid = low + (high - low) / 2;
929 } while (low < high);
930 return mid;
933 /***********************************************************************
934 * resort_symbols
936 * Rebuild sorted list of symbols for a module.
938 static BOOL resort_symbols(struct module* module)
940 int delta;
942 if (!(module->module.NumSyms = module->num_symbols))
943 return FALSE;
945 /* we know that set from 0 up to num_sorttab is already sorted
946 * so sort the remaining (new) symbols, and merge the two sets
947 * (unless the first set is empty)
949 delta = module->num_symbols - module->num_sorttab;
950 qsort(&module->addr_sorttab[module->num_sorttab], delta, sizeof(struct symt_ht*), symt_cmp_addr);
951 if (module->num_sorttab)
953 int i, ins_idx = module->num_sorttab, prev_ins_idx;
954 static struct symt_ht** tmp;
955 static unsigned num_tmp;
957 if (num_tmp < delta)
959 static struct symt_ht** new;
960 if (tmp)
961 new = HeapReAlloc(GetProcessHeap(), 0, tmp, delta * sizeof(struct symt_ht*));
962 else
963 new = HeapAlloc(GetProcessHeap(), 0, delta * sizeof(struct symt_ht*));
964 if (!new)
966 module->num_sorttab = 0;
967 return resort_symbols(module);
969 tmp = new;
970 num_tmp = delta;
972 memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*));
973 qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr);
975 for (i = delta - 1; i >= 0; i--)
977 prev_ins_idx = ins_idx;
978 ins_idx = where_to_insert(module, ins_idx, tmp[i]);
979 memmove(&module->addr_sorttab[ins_idx + i + 1],
980 &module->addr_sorttab[ins_idx],
981 (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*));
982 module->addr_sorttab[ins_idx + i] = tmp[i];
985 module->num_sorttab = module->num_symbols;
986 return module->sortlist_valid = TRUE;
989 static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size)
991 DWORD type_index;
993 if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size)
994 return;
996 if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) &&
997 symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return;
998 *size = 1; /* no size info */
1001 /* needed by symt_find_nearest */
1002 static int symt_get_best_at(struct module* module, int idx_sorttab)
1004 ULONG64 ref_addr;
1005 int idx_sorttab_orig = idx_sorttab;
1006 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1008 symt_get_address(&module->addr_sorttab[idx_sorttab]->symt, &ref_addr);
1009 while (idx_sorttab > 0 &&
1010 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1011 !cmp_sorttab_addr(module, idx_sorttab - 1, ref_addr))
1012 idx_sorttab--;
1013 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1015 idx_sorttab = idx_sorttab_orig;
1016 while (idx_sorttab < module->num_sorttab - 1 &&
1017 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1018 !cmp_sorttab_addr(module, idx_sorttab + 1, ref_addr))
1019 idx_sorttab++;
1021 /* if no better symbol was found restore the original */
1022 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1023 idx_sorttab = idx_sorttab_orig;
1025 return idx_sorttab;
1028 /* assume addr is in module */
1029 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
1031 int mid, high, low;
1032 ULONG64 ref_addr, ref_size;
1034 if (!module->sortlist_valid || !module->addr_sorttab)
1036 if (!resort_symbols(module)) return NULL;
1040 * Binary search to find closest symbol.
1042 low = 0;
1043 high = module->num_sorttab;
1045 symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr);
1046 if (addr < ref_addr) return NULL;
1048 if (high)
1050 symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr);
1051 symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size);
1052 if (addr >= ref_addr + ref_size) return NULL;
1055 while (high > low + 1)
1057 mid = (high + low) / 2;
1058 if (cmp_sorttab_addr(module, mid, addr) < 0)
1059 low = mid;
1060 else
1061 high = mid;
1063 if (low != high && high != module->num_sorttab &&
1064 cmp_sorttab_addr(module, high, addr) <= 0)
1065 low = high;
1067 /* If found symbol is a public symbol, check if there are any other entries that
1068 * might also have the same address, but would get better information
1070 low = symt_get_best_at(module, low);
1072 return module->addr_sorttab[low];
1075 struct symt_ht* symt_find_symbol_at(struct module* module, DWORD_PTR addr)
1077 struct symt_ht* nearest = symt_find_nearest(module, addr);
1078 if (nearest)
1080 ULONG64 symaddr, symsize;
1081 symt_get_address(&nearest->symt, &symaddr);
1082 symt_get_length(module, &nearest->symt, &symsize);
1083 if (addr < symaddr || addr >= symaddr + symsize)
1084 nearest = NULL;
1086 return nearest;
1089 static BOOL symt_enum_locals_helper(struct module_pair* pair,
1090 const WCHAR* match, const struct sym_enum* se,
1091 struct symt_function* func, const struct vector* v)
1093 struct symt* lsym = NULL;
1094 DWORD_PTR pc = pair->pcs->localscope_pc;
1095 unsigned int i;
1096 WCHAR* nameW;
1097 BOOL ret;
1099 for (i=0; i<vector_length(v); i++)
1101 lsym = *(struct symt**)vector_at(v, i);
1102 switch (lsym->tag)
1104 case SymTagBlock:
1106 struct symt_block* block = (struct symt_block*)lsym;
1107 unsigned j;
1108 for (j = 0; j < block->num_ranges; j++)
1110 if (pc >= block->ranges[j].low && pc < block->ranges[j].high)
1112 if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren))
1113 return FALSE;
1117 break;
1118 case SymTagData:
1119 nameW = symt_get_nameW(lsym);
1120 ret = SymMatchStringW(nameW, match,
1121 !(dbghelp_options & SYMOPT_CASE_INSENSITIVE));
1122 HeapFree(GetProcessHeap(), 0, nameW);
1123 if (ret)
1125 if (send_symbol(se, pair, func, lsym)) return FALSE;
1127 break;
1128 case SymTagLabel:
1129 case SymTagFuncDebugStart:
1130 case SymTagFuncDebugEnd:
1131 case SymTagCustom:
1132 case SymTagInlineSite:
1133 break;
1134 default:
1135 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
1136 assert(0);
1139 return TRUE;
1142 static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask,
1143 const struct sym_enum* se)
1145 struct module_pair pair;
1147 se->sym_info->SizeOfStruct = sizeof(*se->sym_info);
1148 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
1150 pair.pcs = pcs;
1151 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1152 if (!module_get_debug(&pair)) return FALSE;
1154 if (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1155 symt_check_tag(pcs->localscope_symt, SymTagInlineSite))
1157 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1158 return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, func, &func->vchildren);
1160 return FALSE;
1163 /**********************************************************
1164 * symbol_setname
1166 * Properly sets Name and NameLen in SYMBOL_INFO
1167 * according to MaxNameLen value
1169 void symbol_setname(SYMBOL_INFO* sym_info, const char* name)
1171 SIZE_T len = 0;
1172 if (name)
1174 sym_info->NameLen = strlen(name);
1175 if (sym_info->MaxNameLen)
1177 len = min(sym_info->NameLen, sym_info->MaxNameLen - 1);
1178 memcpy(sym_info->Name, name, len);
1181 else
1182 sym_info->NameLen = 0;
1183 sym_info->Name[len] = '\0';
1186 /******************************************************************
1187 * copy_symbolW
1189 * Helper for transforming an ANSI symbol info into a UNICODE one.
1190 * Assume that MaxNameLen is the same for both version (A & W).
1192 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
1194 siw->SizeOfStruct = si->SizeOfStruct;
1195 siw->TypeIndex = si->TypeIndex;
1196 siw->Reserved[0] = si->Reserved[0];
1197 siw->Reserved[1] = si->Reserved[1];
1198 siw->Index = si->Index;
1199 siw->Size = si->Size;
1200 siw->ModBase = si->ModBase;
1201 siw->Flags = si->Flags;
1202 siw->Value = si->Value;
1203 siw->Address = si->Address;
1204 siw->Register = si->Register;
1205 siw->Scope = si->Scope;
1206 siw->Tag = si->Tag;
1207 siw->NameLen = si->NameLen;
1208 siw->MaxNameLen = si->MaxNameLen;
1209 MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen);
1212 /* return the lowest inline site inside a function */
1213 struct symt_function* symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr)
1215 struct symt_function* current;
1216 int i;
1218 assert(func->symt.tag == SymTagFunction);
1219 for (current = func->next_inlinesite; current; current = current->next_inlinesite)
1221 for (i = 0; i < current->num_ranges; ++i)
1223 /* first matching range gives the lowest inline site; see dbghelp_private.h for details */
1224 if (current->ranges[i].low <= addr && addr < current->ranges[i].high)
1225 return current;
1228 return NULL;
1231 /* from an inline function, get either the enclosing inlined function, or the top function when no inlined */
1232 struct symt* symt_get_upper_inlined(struct symt_function* inlined)
1234 struct symt* symt = &inlined->symt;
1238 assert(symt);
1239 if (symt->tag == SymTagBlock)
1240 symt = ((struct symt_block*)symt)->container;
1241 else
1242 symt = ((struct symt_function*)symt)->container;
1243 } while (symt->tag == SymTagBlock);
1244 assert(symt->tag == SymTagFunction || symt->tag == SymTagInlineSite);
1245 return symt;
1248 /* lookup in module for an inline site (from addr and inline_ctx) */
1249 struct symt_function* symt_find_inlined_site(struct module* module, DWORD64 addr, DWORD inline_ctx)
1251 struct symt_ht* symt = symt_find_symbol_at(module, addr);
1253 if (symt_check_tag(&symt->symt, SymTagFunction))
1255 struct symt_function* func = (struct symt_function*)symt;
1256 struct symt_function* curr = symt_find_lowest_inlined(func, addr);
1257 DWORD depth = IFC_DEPTH(inline_ctx);
1259 if (curr)
1260 for ( ; curr != func; curr = (struct symt_function*)symt_get_upper_inlined(curr))
1261 if (depth-- == 0) return curr;
1263 return NULL;
1266 /******************************************************************
1267 * sym_enum
1269 * Core routine for most of the enumeration of symbols
1271 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1272 const struct sym_enum* se)
1274 struct module_pair pair;
1275 const WCHAR* bang;
1276 WCHAR* mod;
1278 pair.pcs = process_find_by_handle(hProcess);
1279 if (!pair.pcs) return FALSE;
1280 if (BaseOfDll == 0)
1282 /* do local variables ? */
1283 if (!Mask || !(bang = wcschr(Mask, '!')))
1284 return symt_enum_locals(pair.pcs, Mask, se);
1286 if (bang == Mask) return FALSE;
1288 mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR));
1289 if (!mod) return FALSE;
1290 memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR));
1291 mod[bang - Mask] = 0;
1293 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1295 if (pair.requested->type == DMT_PE && module_get_debug(&pair))
1297 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1298 symt_enum_module(&pair, bang + 1, se))
1299 break;
1302 /* not found in PE modules, retry on the ELF ones
1304 if (!pair.requested && dbghelp_opt_native)
1306 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1308 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) &&
1309 !module_get_containee(pair.pcs, pair.requested) &&
1310 module_get_debug(&pair))
1312 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1313 symt_enum_module(&pair, bang + 1, se))
1314 break;
1318 HeapFree(GetProcessHeap(), 0, mod);
1319 return TRUE;
1321 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
1322 if (!module_get_debug(&pair))
1323 return FALSE;
1325 /* we always ignore module name from Mask when BaseOfDll is defined */
1326 if (Mask && (bang = wcschr(Mask, '!')))
1328 if (bang == Mask) return FALSE;
1329 Mask = bang + 1;
1332 symt_enum_module(&pair, Mask ? Mask : L"*", se);
1334 return TRUE;
1337 static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1338 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1339 PVOID UserContext)
1341 struct sym_enum se;
1343 se.cb = EnumSymbolsCallback;
1344 se.user = UserContext;
1345 se.index = 0;
1346 se.tag = 0;
1347 se.addr = 0;
1348 se.sym_info = (PSYMBOL_INFO)se.buffer;
1350 return sym_enum(hProcess, BaseOfDll, Mask, &se);
1353 /******************************************************************
1354 * SymEnumSymbols (DBGHELP.@)
1356 * cases BaseOfDll = 0
1357 * !foo fails always (despite what MSDN states)
1358 * RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
1359 * no ! in Mask, lookup in local Context
1360 * cases BaseOfDll != 0
1361 * !foo fails always (despite what MSDN states)
1362 * RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
1364 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
1365 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1366 PVOID UserContext)
1368 BOOL ret;
1369 PWSTR maskW = NULL;
1371 TRACE("(%p %I64x %s %p %p)\n",
1372 hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
1374 if (Mask)
1376 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
1377 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
1378 return FALSE;
1379 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
1381 ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext);
1382 HeapFree(GetProcessHeap(), 0, maskW);
1383 return ret;
1386 struct sym_enumW
1388 PSYM_ENUMERATESYMBOLS_CALLBACKW cb;
1389 void* ctx;
1390 PSYMBOL_INFOW sym_info;
1391 char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(WCHAR)];
1394 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx)
1396 struct sym_enumW* sew = ctx;
1398 copy_symbolW(sew->sym_info, si);
1400 return (sew->cb)(sew->sym_info, size, sew->ctx);
1403 /******************************************************************
1404 * SymEnumSymbolsW (DBGHELP.@)
1407 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1408 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
1409 PVOID UserContext)
1411 struct sym_enumW sew;
1413 sew.ctx = UserContext;
1414 sew.cb = EnumSymbolsCallback;
1415 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
1417 return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew);
1420 struct sym_enumerate
1422 void* ctx;
1423 PSYM_ENUMSYMBOLS_CALLBACK cb;
1426 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1428 struct sym_enumerate* se = ctx;
1429 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1432 /***********************************************************************
1433 * SymEnumerateSymbols (DBGHELP.@)
1435 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
1436 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
1437 PVOID UserContext)
1439 struct sym_enumerate se;
1441 se.ctx = UserContext;
1442 se.cb = EnumSymbolsCallback;
1444 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
1447 struct sym_enumerate64
1449 void* ctx;
1450 PSYM_ENUMSYMBOLS_CALLBACK64 cb;
1453 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1455 struct sym_enumerate64* se = ctx;
1456 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1459 /***********************************************************************
1460 * SymEnumerateSymbols64 (DBGHELP.@)
1462 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll,
1463 PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,
1464 PVOID UserContext)
1466 struct sym_enumerate64 se;
1468 se.ctx = UserContext;
1469 se.cb = EnumSymbolsCallback;
1471 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se);
1474 /******************************************************************
1475 * SymFromAddr (DBGHELP.@)
1478 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address,
1479 DWORD64* Displacement, PSYMBOL_INFO Symbol)
1481 struct module_pair pair;
1482 struct symt_ht* sym;
1484 if (!module_init_pair(&pair, hProcess, Address)) return FALSE;
1485 if ((sym = symt_find_symbol_at(pair.effective, Address)) == NULL) return FALSE;
1487 symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol);
1488 if (Displacement)
1489 *Displacement = (Address >= Symbol->Address) ? (Address - Symbol->Address) : (DWORD64)-1;
1490 return TRUE;
1493 /******************************************************************
1494 * SymFromAddrW (DBGHELP.@)
1497 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address,
1498 DWORD64* Displacement, PSYMBOL_INFOW Symbol)
1500 PSYMBOL_INFO si;
1501 unsigned len;
1502 BOOL ret;
1504 len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR);
1505 si = HeapAlloc(GetProcessHeap(), 0, len);
1506 if (!si) return FALSE;
1508 si->SizeOfStruct = sizeof(*si);
1509 si->MaxNameLen = Symbol->MaxNameLen;
1510 if ((ret = SymFromAddr(hProcess, Address, Displacement, si)))
1512 copy_symbolW(Symbol, si);
1514 HeapFree(GetProcessHeap(), 0, si);
1515 return ret;
1518 /******************************************************************
1519 * SymGetSymFromAddr (DBGHELP.@)
1522 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
1523 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
1525 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1526 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1527 size_t len;
1528 DWORD64 Displacement64;
1530 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1531 si->SizeOfStruct = sizeof(*si);
1532 si->MaxNameLen = MAX_SYM_NAME;
1533 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1534 return FALSE;
1536 if (Displacement)
1537 *Displacement = Displacement64;
1538 Symbol->Address = si->Address;
1539 Symbol->Size = si->Size;
1540 Symbol->Flags = si->Flags;
1541 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1542 lstrcpynA(Symbol->Name, si->Name, len);
1543 return TRUE;
1546 /******************************************************************
1547 * SymGetSymFromAddr64 (DBGHELP.@)
1550 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address,
1551 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol)
1553 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1554 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1555 size_t len;
1556 DWORD64 Displacement64;
1558 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1559 si->SizeOfStruct = sizeof(*si);
1560 si->MaxNameLen = MAX_SYM_NAME;
1561 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1562 return FALSE;
1564 if (Displacement)
1565 *Displacement = Displacement64;
1566 Symbol->Address = si->Address;
1567 Symbol->Size = si->Size;
1568 Symbol->Flags = si->Flags;
1569 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1570 lstrcpynA(Symbol->Name, si->Name, len);
1571 return TRUE;
1574 static BOOL find_name(struct process* pcs, struct module* module, const char* name,
1575 SYMBOL_INFO* symbol)
1577 struct hash_table_iter hti;
1578 void* ptr;
1579 struct symt_ht* sym = NULL;
1580 struct module_pair pair;
1582 pair.pcs = pcs;
1583 if (!(pair.requested = module)) return FALSE;
1584 if (!module_get_debug(&pair)) return FALSE;
1586 hash_table_iter_init(&pair.effective->ht_symbols, &hti, name);
1587 while ((ptr = hash_table_iter_up(&hti)))
1589 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
1591 if (!strcmp(sym->hash_elt.name, name))
1593 symt_fill_sym_info(&pair, NULL, &sym->symt, symbol);
1594 return TRUE;
1597 return FALSE;
1600 /******************************************************************
1601 * SymFromName (DBGHELP.@)
1604 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol)
1606 struct process* pcs = process_find_by_handle(hProcess);
1607 struct module_pair pair;
1608 struct module* module;
1609 const char* name;
1611 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
1612 if (!pcs) return FALSE;
1613 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1614 name = strchr(Name, '!');
1615 if (name)
1617 char tmp[128];
1618 assert(name - Name < sizeof(tmp));
1619 memcpy(tmp, Name, name - Name);
1620 tmp[name - Name] = '\0';
1621 module = module_find_by_nameA(pcs, tmp);
1622 return find_name(pcs, module, name + 1, Symbol);
1625 /* search first in local context */
1626 pair.pcs = pcs;
1627 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1628 if (module_get_debug(&pair) &&
1629 (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1630 symt_check_tag(pcs->localscope_symt, SymTagInlineSite)))
1632 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1633 struct vector* v = &func->vchildren;
1634 unsigned i;
1636 for (i = 0; i < vector_length(v); i++)
1638 struct symt* lsym = *(struct symt**)vector_at(v, i);
1639 switch (lsym->tag)
1641 case SymTagBlock: /* no recursion */
1642 break;
1643 case SymTagData:
1644 name = symt_get_name(lsym);
1645 if (name && !strcmp(name, Name))
1647 symt_fill_sym_info(&pair, func, lsym, Symbol);
1648 return TRUE;
1650 break;
1651 case SymTagLabel: /* not returned here */
1652 case SymTagFuncDebugStart:
1653 case SymTagFuncDebugEnd:
1654 case SymTagCustom:
1655 case SymTagInlineSite:
1656 break;
1657 default:
1658 WARN("Unsupported tag: %u (%x)\n", lsym->tag, lsym->tag);
1662 /* lookup at global scope */
1663 for (module = pcs->lmodules; module; module = module->next)
1665 if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol))
1666 return TRUE;
1668 /* not found in PE modules, retry on the ELF ones
1670 if (dbghelp_opt_native)
1672 for (module = pcs->lmodules; module; module = module->next)
1674 if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
1675 !module_get_containee(pcs, module) &&
1676 find_name(pcs, module, Name, Symbol))
1677 return TRUE;
1680 SetLastError(ERROR_MOD_NOT_FOUND);
1681 return FALSE;
1684 /***********************************************************************
1685 * SymFromNameW (DBGHELP.@)
1687 BOOL WINAPI SymFromNameW(HANDLE process, const WCHAR *name, SYMBOL_INFOW *symbol)
1689 SYMBOL_INFO *si;
1690 DWORD len;
1691 char *tmp;
1692 BOOL ret;
1694 TRACE("(%p, %s, %p)\n", process, debugstr_w(name), symbol);
1696 len = sizeof(*si) + symbol->MaxNameLen;
1697 if (!(si = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE;
1699 len = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
1700 if (!(tmp = HeapAlloc(GetProcessHeap(), 0, len)))
1702 HeapFree(GetProcessHeap(), 0, si);
1703 return FALSE;
1705 WideCharToMultiByte(CP_ACP, 0, name, -1, tmp, len, NULL, NULL);
1707 si->SizeOfStruct = sizeof(*si);
1708 si->MaxNameLen = symbol->MaxNameLen;
1709 if ((ret = SymFromName(process, tmp, si)))
1710 copy_symbolW(symbol, si);
1712 HeapFree(GetProcessHeap(), 0, tmp);
1713 HeapFree(GetProcessHeap(), 0, si);
1714 return ret;
1717 /***********************************************************************
1718 * SymGetSymFromName64 (DBGHELP.@)
1720 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol)
1722 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1723 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1724 size_t len;
1726 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1727 si->SizeOfStruct = sizeof(*si);
1728 si->MaxNameLen = MAX_SYM_NAME;
1729 if (!SymFromName(hProcess, Name, si)) return FALSE;
1731 Symbol->Address = si->Address;
1732 Symbol->Size = si->Size;
1733 Symbol->Flags = si->Flags;
1734 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1735 lstrcpynA(Symbol->Name, si->Name, len);
1736 return TRUE;
1739 /***********************************************************************
1740 * SymGetSymFromName (DBGHELP.@)
1742 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symbol)
1744 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1745 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1746 size_t len;
1748 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1749 si->SizeOfStruct = sizeof(*si);
1750 si->MaxNameLen = MAX_SYM_NAME;
1751 if (!SymFromName(hProcess, Name, si)) return FALSE;
1753 Symbol->Address = si->Address;
1754 Symbol->Size = si->Size;
1755 Symbol->Flags = si->Flags;
1756 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1757 lstrcpynA(Symbol->Name, si->Name, len);
1758 return TRUE;
1761 struct internal_line_t
1763 BOOL unicode;
1764 PVOID key;
1765 DWORD line_number;
1766 union
1768 CHAR* file_nameA;
1769 WCHAR* file_nameW;
1771 DWORD64 address;
1774 static void init_internal_line(struct internal_line_t* intl, BOOL unicode)
1776 intl->unicode = unicode;
1777 intl->key = NULL;
1778 intl->line_number = 0;
1779 intl->file_nameA = NULL;
1780 intl->address = 0;
1783 static BOOL internal_line_copy_toA32(const struct internal_line_t* intl, IMAGEHLP_LINE* l32)
1785 if (intl->unicode) return FALSE;
1786 l32->Key = intl->key;
1787 l32->LineNumber = intl->line_number;
1788 l32->FileName = intl->file_nameA;
1789 l32->Address = intl->address;
1790 return TRUE;
1793 static BOOL internal_line_copy_toA64(const struct internal_line_t* intl, IMAGEHLP_LINE64* l64)
1795 if (intl->unicode) return FALSE;
1796 l64->Key = intl->key;
1797 l64->LineNumber = intl->line_number;
1798 l64->FileName = intl->file_nameA;
1799 l64->Address = intl->address;
1800 return TRUE;
1803 static BOOL internal_line_copy_toW64(const struct internal_line_t* intl, IMAGEHLP_LINEW64* l64)
1805 if (!intl->unicode) return FALSE;
1806 l64->Key = intl->key;
1807 l64->LineNumber = intl->line_number;
1808 l64->FileName = intl->file_nameW;
1809 l64->Address = intl->address;
1810 return TRUE;
1813 static BOOL internal_line_set_nameA(struct process* pcs, struct internal_line_t* intl, char* str, BOOL copy)
1815 DWORD len;
1817 if (intl->unicode)
1819 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1820 if (!(intl->file_nameW = fetch_buffer(pcs, len * sizeof(WCHAR)))) return FALSE;
1821 MultiByteToWideChar(CP_ACP, 0, str, -1, intl->file_nameW, len);
1823 else
1825 if (copy)
1827 len = strlen(str) + 1;
1828 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1829 memcpy(intl->file_nameA, str, len);
1831 else
1832 intl->file_nameA = str;
1834 return TRUE;
1837 static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* intl, WCHAR* wstr, BOOL copy)
1839 DWORD len;
1841 if (intl->unicode)
1843 if (copy)
1845 len = (lstrlenW(wstr) + 1) * sizeof(WCHAR);
1846 if (!(intl->file_nameW = fetch_buffer(pcs, len))) return FALSE;
1847 memcpy(intl->file_nameW, wstr, len);
1849 else
1850 intl->file_nameW = wstr;
1852 else
1854 DWORD len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
1855 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1856 WideCharToMultiByte(CP_ACP, 0, wstr, -1, intl->file_nameA, len, NULL, NULL);
1858 return TRUE;
1861 static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr,
1862 PDWORD pdwDisplacement, struct internal_line_t* intl)
1864 struct line_info* dli = NULL;
1865 struct line_info* found_dli = NULL;
1866 int i;
1868 for (i = vector_length(&func->vlines) - 1; i >= 0; i--)
1870 dli = vector_at(&func->vlines, i);
1871 if (!dli->is_source_file)
1873 if (found_dli || dli->u.address > addr) continue;
1874 intl->line_number = dli->line_number;
1875 intl->address = dli->u.address;
1876 intl->key = dli;
1877 found_dli = dli;
1878 continue;
1880 if (found_dli)
1882 BOOL ret;
1883 if (dbghelp_opt_source_actual_path)
1885 /* Return native file paths when using winedbg */
1886 ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE);
1888 else
1890 WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file));
1891 ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE);
1892 HeapFree( GetProcessHeap(), 0, dospath );
1894 if (ret && pdwDisplacement) *pdwDisplacement = addr - found_dli->u.address;
1895 return ret;
1898 return FALSE;
1901 /******************************************************************
1902 * get_line_from_addr
1904 * fills source file information from an address
1906 static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr,
1907 PDWORD pdwDisplacement, struct internal_line_t* intl)
1909 struct module_pair pair;
1910 struct symt_ht* symt;
1912 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
1913 if ((symt = symt_find_symbol_at(pair.effective, addr)) == NULL) return FALSE;
1915 if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE;
1916 return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl);
1919 /***********************************************************************
1920 * SymGetSymNext64 (DBGHELP.@)
1922 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1924 /* algo:
1925 * get module from Symbol.Address
1926 * get index in module.addr_sorttab of Symbol.Address
1927 * increment index
1928 * if out of module bounds, move to next module in process address space
1930 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1931 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1932 return FALSE;
1935 /***********************************************************************
1936 * SymGetSymNext (DBGHELP.@)
1938 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1940 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1942 return FALSE;
1945 /***********************************************************************
1946 * SymGetSymPrev64 (DBGHELP.@)
1948 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1950 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1951 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1952 return FALSE;
1955 /***********************************************************************
1956 * SymGetSymPrev (DBGHELP.@)
1958 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1960 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1962 return FALSE;
1965 /******************************************************************
1966 * SymGetLineFromAddr (DBGHELP.@)
1969 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
1970 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
1972 struct internal_line_t intl;
1974 TRACE("(%p %p)\n", hProcess, Line);
1976 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1977 init_internal_line(&intl, FALSE);
1978 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
1979 return internal_line_copy_toA32(&intl, Line);
1982 /******************************************************************
1983 * SymGetLineFromAddr64 (DBGHELP.@)
1986 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
1987 PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line)
1989 struct internal_line_t intl;
1991 TRACE("(%p %p)\n", hProcess, Line);
1993 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1994 init_internal_line(&intl, FALSE);
1995 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
1996 return internal_line_copy_toA64(&intl, Line);
1999 /******************************************************************
2000 * SymGetLineFromAddrW64 (DBGHELP.@)
2003 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr,
2004 PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line)
2006 struct internal_line_t intl;
2008 TRACE("(%p %p)\n", hProcess, Line);
2010 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2011 init_internal_line(&intl, TRUE);
2012 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
2013 return internal_line_copy_toW64(&intl, Line);
2016 static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2018 struct module_pair pair;
2019 struct line_info* li;
2020 struct line_info* srcli;
2022 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2024 if (key == NULL) return FALSE;
2026 li = key;
2028 while (!li->is_first)
2030 li--;
2031 if (!li->is_source_file)
2033 intl->line_number = li->line_number;
2034 intl->address = li->u.address;
2035 intl->key = li;
2036 /* search source file */
2037 for (srcli = li; !srcli->is_source_file; srcli--);
2039 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2042 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2043 return FALSE;
2046 /******************************************************************
2047 * SymGetLinePrev64 (DBGHELP.@)
2050 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2052 struct internal_line_t intl;
2054 TRACE("(%p %p)\n", hProcess, Line);
2056 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2057 init_internal_line(&intl, FALSE);
2058 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2059 return internal_line_copy_toA64(&intl, Line);
2062 /******************************************************************
2063 * SymGetLinePrev (DBGHELP.@)
2066 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
2068 struct internal_line_t intl;
2070 TRACE("(%p %p)\n", hProcess, Line);
2072 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2073 init_internal_line(&intl, FALSE);
2074 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2075 return internal_line_copy_toA32(&intl, Line);
2078 /******************************************************************
2079 * SymGetLinePrevW64 (DBGHELP.@)
2082 BOOL WINAPI SymGetLinePrevW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2084 struct internal_line_t intl;
2086 TRACE("(%p %p)\n", hProcess, Line);
2088 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2089 init_internal_line(&intl, TRUE);
2090 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2091 return internal_line_copy_toW64(&intl, Line);
2094 static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2096 struct module_pair pair;
2097 struct line_info* li;
2098 struct line_info* srcli;
2100 if (key == NULL) return FALSE;
2101 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2103 /* search current source file */
2104 for (srcli = key; !srcli->is_source_file; srcli--);
2106 li = key;
2107 while (!li->is_last)
2109 li++;
2110 if (!li->is_source_file)
2112 intl->line_number = li->line_number;
2113 intl->address = li->u.address;
2114 intl->key = li;
2115 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2117 srcli = li;
2119 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2120 return FALSE;
2123 /******************************************************************
2124 * SymGetLineNext64 (DBGHELP.@)
2127 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2129 struct internal_line_t intl;
2131 TRACE("(%p %p)\n", hProcess, Line);
2133 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2134 init_internal_line(&intl, FALSE);
2135 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2136 return internal_line_copy_toA64(&intl, Line);
2139 /******************************************************************
2140 * SymGetLineNext (DBGHELP.@)
2143 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
2145 struct internal_line_t intl;
2147 TRACE("(%p %p)\n", hProcess, Line);
2149 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2150 init_internal_line(&intl, FALSE);
2151 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2152 return internal_line_copy_toA32(&intl, Line);
2155 /******************************************************************
2156 * SymGetLineNextW64 (DBGHELP.@)
2159 BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2161 struct internal_line_t intl;
2163 TRACE("(%p %p)\n", hProcess, Line);
2165 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2166 init_internal_line(&intl, TRUE);
2167 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2168 return internal_line_copy_toW64(&intl, Line);
2171 /***********************************************************************
2172 * SymUnDName (DBGHELP.@)
2174 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength)
2176 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2177 UNDNAME_COMPLETE) != 0;
2180 /***********************************************************************
2181 * SymUnDName64 (DBGHELP.@)
2183 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength)
2185 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2186 UNDNAME_COMPLETE) != 0;
2189 /***********************************************************************
2190 * UnDecorateSymbolName (DBGHELP.@)
2192 DWORD WINAPI UnDecorateSymbolName(const char *decorated_name, char *undecorated_name,
2193 DWORD undecorated_length, DWORD flags)
2195 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2196 debugstr_a(decorated_name), undecorated_name, undecorated_length, flags);
2198 if (!undecorated_name || !undecorated_length)
2199 return 0;
2200 if (!__unDName(undecorated_name, decorated_name, undecorated_length, malloc, free, flags))
2201 return 0;
2202 return strlen(undecorated_name);
2205 /***********************************************************************
2206 * UnDecorateSymbolNameW (DBGHELP.@)
2208 DWORD WINAPI UnDecorateSymbolNameW(const WCHAR *decorated_name, WCHAR *undecorated_name,
2209 DWORD undecorated_length, DWORD flags)
2211 char *buf, *ptr;
2212 int len, ret = 0;
2214 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2215 debugstr_w(decorated_name), undecorated_name, undecorated_length, flags);
2217 if (!undecorated_name || !undecorated_length)
2218 return 0;
2220 len = WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, NULL, 0, NULL, NULL);
2221 if ((buf = HeapAlloc(GetProcessHeap(), 0, len)))
2223 WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, buf, len, NULL, NULL);
2224 if ((ptr = __unDName(NULL, buf, 0, malloc, free, flags)))
2226 MultiByteToWideChar(CP_ACP, 0, ptr, -1, undecorated_name, undecorated_length);
2227 undecorated_name[undecorated_length - 1] = 0;
2228 ret = lstrlenW(undecorated_name);
2229 free(ptr);
2231 HeapFree(GetProcessHeap(), 0, buf);
2234 return ret;
2237 #define WILDCHAR(x) (-(x))
2239 static int re_fetch_char(const WCHAR** re)
2241 switch (**re)
2243 case '\\': (*re)++; return *(*re)++;
2244 case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
2245 default: return *(*re)++;
2249 static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
2251 return _case ? ch1 - ch2 : towupper(ch1) - towupper(ch2);
2254 static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
2256 int ch1, prev = 0;
2257 unsigned state = 0;
2259 switch (ch1 = re_fetch_char(&elt))
2261 default:
2262 return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
2263 case WILDCHAR('?'): return *string ? ++string : NULL;
2264 case WILDCHAR('*'): assert(0);
2265 case WILDCHAR('['): break;
2268 for (;;)
2270 ch1 = re_fetch_char(&elt);
2271 if (ch1 == WILDCHAR(']')) return NULL;
2272 if (state == 1 && ch1 == '-') state = 2;
2273 else
2275 if (re_match_char(*string, ch1, _case) == 0) return ++string;
2276 switch (state)
2278 case 0:
2279 state = 1;
2280 prev = ch1;
2281 break;
2282 case 1:
2283 state = 0;
2284 break;
2285 case 2:
2286 if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
2287 re_match_char(*string, ch1, _case) <= 0)
2288 return ++string;
2289 state = 0;
2290 break;
2296 /******************************************************************
2297 * re_match_multi
2299 * match a substring of *pstring according to *pre regular expression
2300 * pstring and pre are only updated in case of successful match
2302 static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
2304 const WCHAR* re_end = *pre;
2305 const WCHAR* string_end = *pstring;
2306 const WCHAR* re_beg;
2307 const WCHAR* string_beg;
2308 const WCHAR* next;
2309 int ch;
2311 while (*re_end && *string_end)
2313 string_beg = string_end;
2314 re_beg = re_end;
2315 switch (ch = re_fetch_char(&re_end))
2317 case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
2318 case WILDCHAR('*'):
2319 /* transform '*' into '?#' */
2320 re_beg = L"?";
2321 goto closure;
2322 case WILDCHAR('['):
2325 if (!(ch = re_fetch_char(&re_end))) return FALSE;
2326 } while (ch != WILDCHAR(']'));
2327 /* fall through */
2328 case WILDCHAR('?'):
2329 default:
2330 break;
2333 switch (*re_end)
2335 case '+':
2336 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2337 string_beg++;
2338 /* fall through */
2339 case '#':
2340 re_end++;
2341 closure:
2342 while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
2343 for ( ; string_end >= string_beg; string_end--)
2345 if (re_match_multi(&string_end, &re_end, _case)) goto found;
2347 return FALSE;
2348 default:
2349 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2350 string_end = next;
2354 if (*re_end || *string_end) return FALSE;
2356 found:
2357 *pre = re_end;
2358 *pstring = string_end;
2359 return TRUE;
2362 /******************************************************************
2363 * SymMatchStringA (DBGHELP.@)
2366 BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
2368 WCHAR* strW;
2369 WCHAR* reW;
2370 BOOL ret = FALSE;
2371 DWORD sz;
2373 if (!string || !re)
2375 SetLastError(ERROR_INVALID_HANDLE);
2376 return FALSE;
2378 TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
2380 sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
2381 if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2382 MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
2383 sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
2384 if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2385 MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
2387 if (strW && reW)
2388 ret = SymMatchStringW(strW, reW, _case);
2389 HeapFree(GetProcessHeap(), 0, strW);
2390 HeapFree(GetProcessHeap(), 0, reW);
2391 return ret;
2394 /******************************************************************
2395 * SymMatchStringW (DBGHELP.@)
2398 BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
2400 TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
2402 if (!string || !re)
2404 SetLastError(ERROR_INVALID_HANDLE);
2405 return FALSE;
2407 return re_match_multi(&string, &re, _case);
2410 static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2411 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2412 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2413 PVOID UserContext, DWORD Options)
2415 struct sym_enum se;
2417 if (Options != SYMSEARCH_GLOBALSONLY)
2419 FIXME("Unsupported searching with options (%lx)\n", Options);
2420 SetLastError(ERROR_INVALID_PARAMETER);
2421 return FALSE;
2424 se.cb = EnumSymbolsCallback;
2425 se.user = UserContext;
2426 se.index = Index;
2427 se.tag = SymTag;
2428 se.addr = Address;
2429 se.sym_info = (PSYMBOL_INFO)se.buffer;
2431 return sym_enum(hProcess, BaseOfDll, Mask, &se);
2434 /******************************************************************
2435 * SymSearch (DBGHELP.@)
2437 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2438 DWORD SymTag, PCSTR Mask, DWORD64 Address,
2439 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2440 PVOID UserContext, DWORD Options)
2442 LPWSTR maskW = NULL;
2443 BOOLEAN ret;
2445 TRACE("(%p %I64x %lu %lu %s %I64x %p %p %lx)\n",
2446 hProcess, BaseOfDll, Index, SymTag, Mask,
2447 Address, EnumSymbolsCallback, UserContext, Options);
2449 if (Mask)
2451 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
2453 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2454 return FALSE;
2455 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
2457 ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address,
2458 EnumSymbolsCallback, UserContext, Options);
2459 HeapFree(GetProcessHeap(), 0, maskW);
2460 return ret;
2463 /******************************************************************
2464 * SymSearchW (DBGHELP.@)
2466 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2467 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2468 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
2469 PVOID UserContext, DWORD Options)
2471 struct sym_enumW sew;
2473 TRACE("(%p %I64x %lu %lu %s %I64x %p %p %lx)\n",
2474 hProcess, BaseOfDll, Index, SymTag, debugstr_w(Mask),
2475 Address, EnumSymbolsCallback, UserContext, Options);
2477 sew.ctx = UserContext;
2478 sew.cb = EnumSymbolsCallback;
2479 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
2481 return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address,
2482 sym_enumW, &sew, Options);
2485 /******************************************************************
2486 * SymAddSymbol (DBGHELP.@)
2489 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name,
2490 DWORD64 addr, DWORD size, DWORD flags)
2492 struct module_pair pair;
2494 TRACE("(%p %s %I64x %lu)\n", hProcess, wine_dbgstr_a(name), addr, size);
2496 if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE;
2498 return symt_new_custom(pair.effective, name, addr, size) != NULL;
2501 /******************************************************************
2502 * SymAddSymbolW (DBGHELP.@)
2505 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR nameW,
2506 DWORD64 addr, DWORD size, DWORD flags)
2508 char name[MAX_SYM_NAME];
2510 TRACE("(%p %s %I64x %lu)\n", hProcess, wine_dbgstr_w(nameW), addr, size);
2512 WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, ARRAY_SIZE(name), NULL, NULL);
2514 return SymAddSymbol(hProcess, BaseOfDll, name, addr, size, flags);
2517 /******************************************************************
2518 * SymEnumLines (DBGHELP.@)
2521 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
2522 PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
2524 struct module_pair pair;
2525 struct hash_table_iter hti;
2526 struct symt_ht* sym;
2527 WCHAR* srcmask;
2528 struct line_info* dli;
2529 void* ptr;
2530 SRCCODEINFO sci;
2531 const char* file;
2533 if (!cb) return FALSE;
2534 if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
2536 if (!module_init_pair(&pair, hProcess, base)) return FALSE;
2537 if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
2538 if (!(srcmask = file_regex(srcfile))) return FALSE;
2540 sci.SizeOfStruct = sizeof(sci);
2541 sci.ModBase = base;
2543 hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
2544 while ((ptr = hash_table_iter_up(&hti)))
2546 unsigned int i;
2548 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
2549 if (sym->symt.tag != SymTagFunction) continue;
2551 sci.FileName[0] = '\0';
2552 for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
2554 dli = vector_at(&((struct symt_function*)sym)->vlines, i);
2555 if (dli->is_source_file)
2557 file = source_get(pair.effective, dli->u.source_file);
2558 if (!file) sci.FileName[0] = '\0';
2559 else
2561 DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
2562 WCHAR* fileW;
2564 if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2565 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz);
2566 if (SymMatchStringW(fileW, srcmask, FALSE))
2567 strcpy(sci.FileName, file);
2568 else
2569 sci.FileName[0] = '\0';
2570 HeapFree(GetProcessHeap(), 0, fileW);
2573 else if (sci.FileName[0])
2575 sci.Key = dli;
2576 sci.Obj[0] = '\0'; /* FIXME */
2577 sci.LineNumber = dli->line_number;
2578 sci.Address = dli->u.address;
2579 if (!cb(&sci, user)) break;
2583 HeapFree(GetProcessHeap(), 0, srcmask);
2584 return TRUE;
2587 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2588 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line)
2590 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2591 dwLineNumber, plDisplacement, Line);
2592 return FALSE;
2595 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2596 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line)
2598 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2599 dwLineNumber, lpDisplacement, Line);
2600 return FALSE;
2603 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName,
2604 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line)
2606 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName),
2607 dwLineNumber, plDisplacement, Line);
2608 return FALSE;
2611 /******************************************************************
2612 * SymFromIndex (DBGHELP.@)
2615 BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol)
2617 FIXME("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n",
2618 hProcess, BaseOfDll, index, symbol);
2620 return FALSE;
2623 /******************************************************************
2624 * SymFromIndexW (DBGHELP.@)
2627 BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol)
2629 FIXME("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n",
2630 hProcess, BaseOfDll, index, symbol);
2632 return FALSE;
2635 /******************************************************************
2636 * SymSetHomeDirectory (DBGHELP.@)
2639 PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR dir)
2641 FIXME("(%p, %s): stub\n", hProcess, dir);
2643 return NULL;
2646 /******************************************************************
2647 * SymSetHomeDirectoryW (DBGHELP.@)
2650 PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir)
2652 FIXME("(%p, %s): stub\n", hProcess, debugstr_w(dir));
2654 return NULL;
2657 /******************************************************************
2658 * SymFromInlineContext (DBGHELP.@)
2661 BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si)
2663 struct module_pair pair;
2664 struct symt_function* inlined;
2666 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, si);
2668 switch (IFC_MODE(inline_ctx))
2670 case IFC_MODE_INLINE:
2671 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2672 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2673 if (inlined)
2675 symt_fill_sym_info(&pair, NULL, &inlined->symt, si);
2676 if (disp) *disp = addr - inlined->ranges[0].low;
2677 return TRUE;
2679 /* fall through */
2680 case IFC_MODE_IGNORE:
2681 case IFC_MODE_REGULAR:
2682 return SymFromAddr(hProcess, addr, disp, si);
2683 default:
2684 SetLastError(ERROR_INVALID_PARAMETER);
2685 return FALSE;
2689 /******************************************************************
2690 * SymFromInlineContextW (DBGHELP.@)
2693 BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFOW siW)
2695 PSYMBOL_INFO si;
2696 unsigned len;
2697 BOOL ret;
2699 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, siW);
2701 len = sizeof(*si) + siW->MaxNameLen * sizeof(WCHAR);
2702 si = HeapAlloc(GetProcessHeap(), 0, len);
2703 if (!si) return FALSE;
2705 si->SizeOfStruct = sizeof(*si);
2706 si->MaxNameLen = siW->MaxNameLen;
2707 if ((ret = SymFromInlineContext(hProcess, addr, inline_ctx, disp, si)))
2709 copy_symbolW(siW, si);
2711 HeapFree(GetProcessHeap(), 0, si);
2712 return ret;
2715 static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp,
2716 struct internal_line_t* intl)
2718 struct module_pair pair;
2719 struct symt_function* inlined;
2721 if (!module_init_pair(&pair, hProcess, mod_addr ? mod_addr : addr)) return FALSE;
2722 switch (IFC_MODE(inline_ctx))
2724 case IFC_MODE_INLINE:
2725 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2726 if (inlined && get_line_from_function(&pair, inlined, addr, disp, intl))
2727 return TRUE;
2728 /* fall through: check if we can find line info at top function level */
2729 case IFC_MODE_IGNORE:
2730 case IFC_MODE_REGULAR:
2731 return get_line_from_addr(hProcess, addr, disp, intl);
2732 default:
2733 SetLastError(ERROR_INVALID_PARAMETER);
2734 return FALSE;
2738 /******************************************************************
2739 * SymGetLineFromInlineContext (DBGHELP.@)
2742 BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line)
2744 struct internal_line_t intl;
2746 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2747 hProcess, addr, inline_ctx, mod_addr, disp, line);
2749 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2750 init_internal_line(&intl, FALSE);
2752 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2753 return internal_line_copy_toA64(&intl, line);
2756 /******************************************************************
2757 * SymGetLineFromInlineContextW (DBGHELP.@)
2760 BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line)
2762 struct internal_line_t intl;
2764 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2765 hProcess, addr, inline_ctx, mod_addr, disp, line);
2767 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2768 init_internal_line(&intl, TRUE);
2770 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2771 return internal_line_copy_toW64(&intl, line);
2774 /******************************************************************
2775 * SymAddrIncludeInlineTrace (DBGHELP.@)
2777 * MSDN doesn't state that the maximum depth (of embedded inline sites) at <addr>
2778 * is actually returned. (It just says non zero means that there are some inline site(s)).
2779 * But this is what native actually returns.
2781 DWORD WINAPI SymAddrIncludeInlineTrace(HANDLE hProcess, DWORD64 addr)
2783 struct module_pair pair;
2784 DWORD depth = 0;
2786 TRACE("(%p, %#I64x)\n", hProcess, addr);
2788 if (module_init_pair(&pair, hProcess, addr))
2790 struct symt_ht* symt = symt_find_symbol_at(pair.effective, addr);
2791 if (symt_check_tag(&symt->symt, SymTagFunction))
2793 struct symt_function* inlined = symt_find_lowest_inlined((struct symt_function*)symt, addr);
2794 if (inlined)
2796 for ( ; &inlined->symt != &symt->symt; inlined = (struct symt_function*)symt_get_upper_inlined(inlined))
2797 ++depth;
2801 return depth;
2804 /******************************************************************
2805 * SymQueryInlineTrace (DBGHELP.@)
2808 BOOL WINAPI SymQueryInlineTrace(HANDLE hProcess, DWORD64 StartAddress, DWORD StartContext,
2809 DWORD64 StartRetAddress, DWORD64 CurAddress,
2810 LPDWORD CurContext, LPDWORD CurFrameIndex)
2812 struct module_pair pair;
2813 struct symt_ht* sym_curr;
2814 struct symt_ht* sym_start;
2815 struct symt_ht* sym_startret;
2816 DWORD depth;
2818 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %I64x, %p, %p)\n",
2819 hProcess, StartAddress, StartContext, StartRetAddress, CurAddress, CurContext, CurFrameIndex);
2821 if (!module_init_pair(&pair, hProcess, CurAddress)) return FALSE;
2822 if (!(sym_curr = symt_find_symbol_at(pair.effective, CurAddress))) return FALSE;
2823 if (!symt_check_tag(&sym_curr->symt, SymTagFunction)) return FALSE;
2825 sym_start = symt_find_symbol_at(pair.effective, StartAddress);
2826 sym_startret = symt_find_symbol_at(pair.effective, StartRetAddress);
2827 if (sym_start != sym_curr && sym_startret != sym_curr)
2829 SetLastError(ERROR_INVALID_PARAMETER);
2830 return FALSE;
2832 if (sym_start != sym_curr || StartContext)
2834 FIXME("(%p, %#I64x, 0x%lx, %#I64x, %I64x, %p, %p): semi-stub\n",
2835 hProcess, StartAddress, StartContext, StartRetAddress, CurAddress, CurContext, CurFrameIndex);
2836 return ERROR_CALL_NOT_IMPLEMENTED;
2839 depth = SymAddrIncludeInlineTrace(hProcess, CurAddress);
2840 if (depth)
2842 *CurContext = IFC_MODE_INLINE; /* deepest inline site */
2843 *CurFrameIndex = depth;
2845 else
2847 *CurContext = IFC_MODE_REGULAR;
2848 *CurFrameIndex = 0;
2850 return TRUE;