dbghelp: Keep compiland's address for Dwarf debug format.
[wine.git] / dlls / dbghelp / symbol.c
blob98e25a32b30bf42fda601fa2b66426db4a7c18ea
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_ht(struct module* module, struct symt_ht* ht)
155 ULONG64 addr;
157 hash_table_add(&module->ht_symbols, &ht->hash_elt);
158 /* Don't store in sorttab a symbol without address, they are of
159 * no use here (e.g. constant values)
161 if (symt_get_address(&ht->symt, &addr) &&
162 symt_grow_sorttab(module, module->num_symbols + 1))
164 module->addr_sorttab[module->num_symbols++] = ht;
165 module->sortlist_valid = FALSE;
169 static WCHAR* file_regex(const char* srcfile)
171 WCHAR* mask;
172 WCHAR* p;
174 if (!srcfile || !*srcfile)
176 if (!(p = mask = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(WCHAR)))) return NULL;
177 *p++ = '?';
178 *p++ = '#';
180 else
182 DWORD sz = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
183 WCHAR* srcfileW;
185 /* FIXME: we use here the largest conversion for every char... could be optimized */
186 p = mask = HeapAlloc(GetProcessHeap(), 0, (5 * strlen(srcfile) + 1 + sz) * sizeof(WCHAR));
187 if (!mask) return NULL;
188 srcfileW = mask + 5 * strlen(srcfile) + 1;
189 MultiByteToWideChar(CP_ACP, 0, srcfile, -1, srcfileW, sz);
191 while (*srcfileW)
193 switch (*srcfileW)
195 case '\\':
196 case '/':
197 *p++ = '[';
198 *p++ = '\\';
199 *p++ = '\\';
200 *p++ = '/';
201 *p++ = ']';
202 break;
203 case '.':
204 *p++ = '?';
205 break;
206 default:
207 *p++ = *srcfileW;
208 break;
210 srcfileW++;
213 *p = 0;
214 return mask;
217 struct symt_module* symt_new_module(struct module* module)
219 struct symt_module* sym;
221 TRACE_(dbghelp_symt)("Adding toplevel exe symbol %s\n", debugstr_w(module->modulename));
222 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
224 sym->symt.tag = SymTagExe;
225 sym->module = module;
226 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
228 return sym;
231 struct symt_compiland* symt_new_compiland(struct module* module, unsigned src_idx)
233 struct symt_compiland* sym;
234 struct symt_compiland** p;
236 TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n",
237 debugstr_w(module->modulename), source_get(module, src_idx));
238 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
240 sym->symt.tag = SymTagCompiland;
241 sym->container = module->top;
242 sym->address = 0;
243 sym->source = src_idx;
244 vector_init(&sym->vchildren, sizeof(struct symt*), 32);
245 sym->user = NULL;
246 p = vector_add(&module->top->vchildren, &module->pool);
247 *p = sym;
249 return sym;
252 struct symt_public* symt_new_public(struct module* module,
253 struct symt_compiland* compiland,
254 const char* name,
255 BOOL is_function,
256 ULONG_PTR address, unsigned size)
258 struct symt_public* sym;
259 struct symt** p;
261 TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%Ix\n",
262 debugstr_w(module->modulename), name, address);
263 if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
264 symt_find_nearest(module, address) != NULL)
265 return NULL;
266 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
268 sym->symt.tag = SymTagPublicSymbol;
269 sym->hash_elt.name = pool_strdup(&module->pool, name);
270 sym->container = compiland ? &compiland->symt : NULL;
271 sym->is_function = is_function;
272 sym->address = address;
273 sym->size = size;
274 symt_add_module_ht(module, (struct symt_ht*)sym);
275 if (compiland)
277 p = vector_add(&compiland->vchildren, &module->pool);
278 *p = &sym->symt;
281 return sym;
284 struct symt_data* symt_new_global_variable(struct module* module,
285 struct symt_compiland* compiland,
286 const char* name, unsigned is_static,
287 struct location loc, ULONG_PTR size,
288 struct symt* type)
290 struct symt_data* sym;
291 struct symt** p;
292 DWORD64 tsz;
294 TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%Ix %p\n",
295 debugstr_w(module->modulename), name, loc.kind, loc.offset, type);
296 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
298 sym->symt.tag = SymTagData;
299 sym->hash_elt.name = pool_strdup(&module->pool, name);
300 sym->kind = is_static ? DataIsFileStatic : DataIsGlobal;
301 sym->container = compiland ? &compiland->symt : &module->top->symt;
302 sym->type = type;
303 sym->u.var = loc;
304 if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz))
306 if (tsz != size)
307 FIXME("Size mismatch for %s.%s between type (%I64u) and src (%Iu)\n",
308 debugstr_w(module->modulename), name, tsz, size);
310 symt_add_module_ht(module, (struct symt_ht*)sym);
311 p = vector_add(compiland ? &compiland->vchildren : &module->top->vchildren, &module->pool);
312 *p = &sym->symt;
314 return sym;
317 static void init_function_or_inlinesite(struct symt_function* sym,
318 struct module* module,
319 DWORD tag,
320 struct symt* container,
321 const char* name,
322 ULONG_PTR addr, ULONG_PTR size,
323 struct symt* sig_type)
325 assert(!sig_type || sig_type->tag == SymTagFunctionType);
326 sym->symt.tag = tag;
327 sym->hash_elt.name = pool_strdup(&module->pool, name);
328 sym->container = container;
329 sym->address = addr;
330 sym->type = sig_type;
331 sym->size = size;
332 vector_init(&sym->vlines, sizeof(struct line_info), 64);
333 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
336 struct symt_function* symt_new_function(struct module* module,
337 struct symt_compiland* compiland,
338 const char* name,
339 ULONG_PTR addr, ULONG_PTR size,
340 struct symt* sig_type)
342 struct symt_function* sym;
344 TRACE_(dbghelp_symt)("Adding global function %s:%s @%Ix-%Ix\n",
345 debugstr_w(module->modulename), name, addr, addr + size - 1);
346 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
348 struct symt** p;
349 init_function_or_inlinesite(sym, module, SymTagFunction, &compiland->symt, name, addr, size, sig_type);
350 sym->next_inlinesite = NULL; /* first of list */
351 symt_add_module_ht(module, (struct symt_ht*)sym);
352 if (compiland)
354 p = vector_add(&compiland->vchildren, &module->pool);
355 *p = &sym->symt;
358 return sym;
361 struct symt_inlinesite* symt_new_inlinesite(struct module* module,
362 struct symt_function* func,
363 struct symt* container,
364 const char* name,
365 ULONG_PTR addr,
366 struct symt* sig_type)
368 struct symt_inlinesite* sym;
370 TRACE_(dbghelp_symt)("Adding inline site %s @%Ix\n", name, addr);
371 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
373 struct symt** p;
374 assert(container);
375 init_function_or_inlinesite(&sym->func, module, SymTagInlineSite, container, name, addr, 0, sig_type);
376 vector_init(&sym->vranges, sizeof(struct addr_range), 2); /* FIXME: number of elts => to be set on input */
377 /* chain inline sites */
378 sym->func.next_inlinesite = func->next_inlinesite;
379 func->next_inlinesite = sym;
380 if (container->tag == SymTagFunction || container->tag == SymTagInlineSite)
381 p = vector_add(&((struct symt_function*)container)->vchildren, &module->pool);
382 else
384 assert(container->tag == SymTagBlock);
385 p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool);
387 *p = &sym->func.symt;
389 return sym;
392 void symt_add_func_line(struct module* module, struct symt_function* func,
393 unsigned source_idx, int line_num, ULONG_PTR addr)
395 struct line_info* dli;
396 unsigned vlen;
397 struct line_info* prev;
398 BOOL last_matches = FALSE;
399 int i;
401 if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
403 TRACE_(dbghelp_symt)("(%p)%s:%Ix %s:%u\n",
404 func, func->hash_elt.name, addr,
405 source_get(module, source_idx), line_num);
407 assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite);
409 for (i=vector_length(&func->vlines)-1; i>=0; i--)
411 dli = vector_at(&func->vlines, i);
412 if (dli->is_source_file)
414 last_matches = (source_idx == dli->u.source_file);
415 break;
418 vlen = vector_length(&func->vlines);
419 prev = vlen ? vector_at(&func->vlines, vlen - 1) : NULL;
420 if (last_matches && prev && addr == prev->u.address)
422 WARN("Duplicate addition of line number in %s\n", func->hash_elt.name);
423 return;
425 if (!last_matches)
427 /* we shouldn't have line changes on first line of function */
428 dli = vector_add(&func->vlines, &module->pool);
429 dli->is_source_file = 1;
430 dli->is_first = (prev == NULL);
431 dli->is_last = 0;
432 dli->line_number = 0;
433 dli->u.source_file = source_idx;
435 /* clear previous last */
436 if (prev) prev->is_last = 0;
437 dli = vector_add(&func->vlines, &module->pool);
438 dli->is_source_file = 0;
439 dli->is_first = 0; /* only a source file can be first */
440 dli->is_last = 1;
441 dli->line_number = line_num;
442 dli->u.address = addr;
445 /******************************************************************
446 * symt_add_func_local
448 * Adds a new local/parameter to a given function:
449 * In any cases, dt tells whether it's a local variable or a parameter
450 * or a static variable inside the function.
451 * If regno it's not 0:
452 * - then variable is stored in a register
453 * - otherwise, value is referenced by register + offset
454 * Otherwise, the variable is stored on the stack:
455 * - offset is then the offset from the frame register
457 struct symt_data* symt_add_func_local(struct module* module,
458 struct symt_function* func,
459 enum DataKind dt,
460 const struct location* loc,
461 struct symt_block* block,
462 struct symt* type, const char* name)
464 struct symt_data* locsym;
465 struct symt** p;
467 TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n",
468 debugstr_w(module->modulename), func->hash_elt.name,
469 name, type);
471 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
472 assert(dt == DataIsParam || dt == DataIsLocal || dt == DataIsStaticLocal);
474 locsym = pool_alloc(&module->pool, sizeof(*locsym));
475 locsym->symt.tag = SymTagData;
476 locsym->hash_elt.name = pool_strdup(&module->pool, name);
477 locsym->hash_elt.next = NULL;
478 locsym->kind = dt;
479 locsym->container = block ? &block->symt : &func->symt;
480 locsym->type = type;
481 locsym->u.var = *loc;
482 if (block)
483 p = vector_add(&block->vchildren, &module->pool);
484 else
485 p = vector_add(&func->vchildren, &module->pool);
486 *p = &locsym->symt;
487 return locsym;
490 /******************************************************************
491 * symt_add_func_local
493 * Adds a new (local) constant to a given function
495 struct symt_data* symt_add_func_constant(struct module* module,
496 struct symt_function* func,
497 struct symt_block* block,
498 struct symt* type, const char* name,
499 VARIANT* v)
501 struct symt_data* locsym;
502 struct symt** p;
504 TRACE_(dbghelp_symt)("Adding local constant (%s:%s): %s %p\n",
505 debugstr_w(module->modulename), func->hash_elt.name,
506 name, type);
508 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
510 locsym = pool_alloc(&module->pool, sizeof(*locsym));
511 locsym->symt.tag = SymTagData;
512 locsym->hash_elt.name = pool_strdup(&module->pool, name);
513 locsym->hash_elt.next = NULL;
514 locsym->kind = DataIsConstant;
515 locsym->container = block ? &block->symt : &func->symt;
516 locsym->type = type;
517 locsym->u.value = *v;
518 if (block)
519 p = vector_add(&block->vchildren, &module->pool);
520 else
521 p = vector_add(&func->vchildren, &module->pool);
522 *p = &locsym->symt;
523 return locsym;
526 struct symt_block* symt_open_func_block(struct module* module,
527 struct symt_function* func,
528 struct symt_block* parent_block,
529 unsigned pc, unsigned len)
531 struct symt_block* block;
532 struct symt** p;
534 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
536 assert(!parent_block || parent_block->symt.tag == SymTagBlock);
537 block = pool_alloc(&module->pool, sizeof(*block));
538 block->symt.tag = SymTagBlock;
539 block->address = func->address + pc;
540 block->size = len;
541 block->container = parent_block ? &parent_block->symt : &func->symt;
542 vector_init(&block->vchildren, sizeof(struct symt*), 4);
543 if (parent_block)
544 p = vector_add(&parent_block->vchildren, &module->pool);
545 else
546 p = vector_add(&func->vchildren, &module->pool);
547 *p = &block->symt;
549 return block;
552 struct symt_block* symt_close_func_block(struct module* module,
553 const struct symt_function* func,
554 struct symt_block* block, unsigned pc)
556 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
558 if (pc) block->size = func->address + pc - block->address;
559 return (block->container->tag == SymTagBlock) ?
560 CONTAINING_RECORD(block->container, struct symt_block, symt) : NULL;
563 struct symt_hierarchy_point* symt_add_function_point(struct module* module,
564 struct symt_function* func,
565 enum SymTagEnum point,
566 const struct location* loc,
567 const char* name)
569 struct symt_hierarchy_point*sym;
570 struct symt** p;
572 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
574 sym->symt.tag = point;
575 sym->parent = &func->symt;
576 sym->loc = *loc;
577 sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL;
578 p = vector_add(&func->vchildren, &module->pool);
579 *p = &sym->symt;
581 return sym;
584 /* low and high are absolute addresses */
585 BOOL symt_add_inlinesite_range(struct module* module,
586 struct symt_inlinesite* inlined,
587 ULONG_PTR low, ULONG_PTR high)
589 struct addr_range* p;
591 p = vector_add(&inlined->vranges, &module->pool);
592 p->low = low;
593 p->high = high;
594 if (TRUE)
596 int i;
598 /* see dbghelp_private.h for the assumptions */
599 for (i = 0; i < inlined->vranges.num_elts - 1; i++)
601 if (!addr_range_disjoint((struct addr_range*)vector_at(&inlined->vranges, i), p))
603 FIXME("Added addr_range isn't disjoint from siblings\n");
606 for ( ; inlined->func.symt.tag != SymTagFunction; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined))
608 for (i = 0; i < inlined->vranges.num_elts; i++)
610 struct addr_range* ar = (struct addr_range*)vector_at(&inlined->vranges, i);
611 if (!addr_range_disjoint(ar, p) && !addr_range_inside(ar, p))
612 WARN("Added addr_range not compatible with parent\n");
617 return TRUE;
620 struct symt_thunk* symt_new_thunk(struct module* module,
621 struct symt_compiland* compiland,
622 const char* name, THUNK_ORDINAL ord,
623 ULONG_PTR addr, ULONG_PTR size)
625 struct symt_thunk* sym;
627 TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%Ix-%Ix\n",
628 debugstr_w(module->modulename), name, addr, addr + size - 1);
630 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
632 sym->symt.tag = SymTagThunk;
633 sym->hash_elt.name = pool_strdup(&module->pool, name);
634 sym->container = &compiland->symt;
635 sym->address = addr;
636 sym->size = size;
637 sym->ordinal = ord;
638 symt_add_module_ht(module, (struct symt_ht*)sym);
639 if (compiland)
641 struct symt** p;
642 p = vector_add(&compiland->vchildren, &module->pool);
643 *p = &sym->symt;
646 return sym;
649 struct symt_data* symt_new_constant(struct module* module,
650 struct symt_compiland* compiland,
651 const char* name, struct symt* type,
652 const VARIANT* v)
654 struct symt_data* sym;
656 TRACE_(dbghelp_symt)("Adding constant value %s:%s\n",
657 debugstr_w(module->modulename), name);
659 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
661 sym->symt.tag = SymTagData;
662 sym->hash_elt.name = pool_strdup(&module->pool, name);
663 sym->kind = DataIsConstant;
664 sym->container = compiland ? &compiland->symt : &module->top->symt;
665 sym->type = type;
666 sym->u.value = *v;
667 symt_add_module_ht(module, (struct symt_ht*)sym);
668 if (compiland)
670 struct symt** p;
671 p = vector_add(&compiland->vchildren, &module->pool);
672 *p = &sym->symt;
675 return sym;
678 struct symt_hierarchy_point* symt_new_label(struct module* module,
679 struct symt_compiland* compiland,
680 const char* name, ULONG_PTR address)
682 struct symt_hierarchy_point* sym;
684 TRACE_(dbghelp_symt)("Adding global label value %s:%s\n",
685 debugstr_w(module->modulename), name);
687 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
689 sym->symt.tag = SymTagLabel;
690 sym->hash_elt.name = pool_strdup(&module->pool, name);
691 sym->loc.kind = loc_absolute;
692 sym->loc.offset = address;
693 sym->parent = compiland ? &compiland->symt : NULL;
694 symt_add_module_ht(module, (struct symt_ht*)sym);
695 if (compiland)
697 struct symt** p;
698 p = vector_add(&compiland->vchildren, &module->pool);
699 *p = &sym->symt;
702 return sym;
705 struct symt_custom* symt_new_custom(struct module* module, const char* name,
706 DWORD64 addr, DWORD size)
708 struct symt_custom* sym;
710 TRACE_(dbghelp_symt)("Adding custom symbol %s:%s\n",
711 debugstr_w(module->modulename), name);
713 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
715 sym->symt.tag = SymTagCustom;
716 sym->hash_elt.name = pool_strdup(&module->pool, name);
717 sym->address = addr;
718 sym->size = size;
719 symt_add_module_ht(module, (struct symt_ht*)sym);
721 return sym;
724 /* expect sym_info->MaxNameLen to be set before being called */
725 static void symt_fill_sym_info(struct module_pair* pair,
726 const struct symt_function* func,
727 const struct symt* sym, SYMBOL_INFO* sym_info)
729 const char* name;
730 DWORD64 size;
731 char* tmp;
733 if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex))
734 sym_info->TypeIndex = 0;
735 sym_info->Index = symt_ptr2index(pair->effective, sym);
736 sym_info->Reserved[0] = sym_info->Reserved[1] = 0;
737 if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) &&
738 (!sym_info->TypeIndex ||
739 !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex),
740 TI_GET_LENGTH, &size)))
741 size = 0;
742 sym_info->Size = (DWORD)size;
743 sym_info->ModBase = pair->requested->module.BaseOfImage;
744 sym_info->Flags = 0;
745 sym_info->Value = 0;
747 switch (sym->tag)
749 case SymTagData:
751 const struct symt_data* data = (const struct symt_data*)sym;
752 switch (data->kind)
754 case DataIsParam:
755 sym_info->Flags |= SYMFLAG_PARAMETER;
756 /* fall through */
757 case DataIsLocal:
758 sym_info->Flags |= SYMFLAG_LOCAL;
760 struct location loc = data->u.var;
762 if (loc.kind >= loc_user)
764 unsigned i;
765 struct module_format* modfmt;
767 for (i = 0; i < DFI_LAST; i++)
769 modfmt = pair->effective->format_info[i];
770 if (modfmt && modfmt->loc_compute)
772 modfmt->loc_compute(pair->pcs, modfmt, func, &loc);
773 break;
777 switch (loc.kind)
779 case loc_error:
780 /* for now we report error cases as a negative register number */
781 /* fall through */
782 case loc_register:
783 sym_info->Flags |= SYMFLAG_REGISTER;
784 sym_info->Register = loc.reg;
785 sym_info->Address = 0;
786 break;
787 case loc_regrel:
788 sym_info->Flags |= SYMFLAG_REGREL;
789 sym_info->Register = loc.reg;
790 if (loc.reg == CV_REG_NONE || (int)loc.reg < 0 /* error */)
791 FIXME("suspicious register value %x\n", loc.reg);
792 sym_info->Address = loc.offset;
793 break;
794 case loc_absolute:
795 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
796 sym_info->Value = loc.offset;
797 break;
798 default:
799 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", loc.kind);
800 assert(0);
803 break;
804 case DataIsGlobal:
805 case DataIsFileStatic:
806 case DataIsStaticLocal:
807 switch (data->u.var.kind)
809 case loc_tlsrel:
810 sym_info->Flags |= SYMFLAG_TLSREL;
811 /* fall through */
812 case loc_absolute:
813 symt_get_address(sym, &sym_info->Address);
814 sym_info->Register = 0;
815 break;
816 default:
817 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind);
818 assert(0);
820 break;
821 case DataIsConstant:
822 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
823 if (data->container &&
824 (data->container->tag == SymTagFunction || data->container->tag == SymTagBlock))
825 sym_info->Flags |= SYMFLAG_LOCAL;
826 switch (V_VT(&data->u.value))
828 case VT_I8: sym_info->Value = (LONG64)V_I8(&data->u.value); break;
829 case VT_I4: sym_info->Value = (LONG64)V_I4(&data->u.value); break;
830 case VT_I2: sym_info->Value = (LONG64)V_I2(&data->u.value); break;
831 case VT_I1: sym_info->Value = (LONG64)V_I1(&data->u.value); break;
832 case VT_UINT:sym_info->Value = V_UINT(&data->u.value); break;
833 case VT_UI8: sym_info->Value = V_UI8(&data->u.value); break;
834 case VT_UI4: sym_info->Value = V_UI4(&data->u.value); break;
835 case VT_UI2: sym_info->Value = V_UI2(&data->u.value); break;
836 case VT_UI1: sym_info->Value = V_UI1(&data->u.value); break;
837 case VT_BYREF: sym_info->Value = (DWORD_PTR)V_BYREF(&data->u.value); break;
838 case VT_EMPTY: sym_info->Value = 0; break;
839 default:
840 FIXME("Unsupported variant type (%u)\n", V_VT(&data->u.value));
841 sym_info->Value = 0;
842 break;
844 break;
845 default:
846 FIXME("Unhandled kind (%u) in sym data\n", data->kind);
849 break;
850 case SymTagPublicSymbol:
852 const struct symt_public* pub = (const struct symt_public*)sym;
853 if (pub->is_function)
854 sym_info->Flags |= SYMFLAG_PUBLIC_CODE;
855 else
856 sym_info->Flags |= SYMFLAG_EXPORT;
857 symt_get_address(sym, &sym_info->Address);
859 break;
860 case SymTagFunction:
861 case SymTagInlineSite:
862 symt_get_address(sym, &sym_info->Address);
863 break;
864 case SymTagThunk:
865 sym_info->Flags |= SYMFLAG_THUNK;
866 symt_get_address(sym, &sym_info->Address);
867 break;
868 case SymTagCustom:
869 symt_get_address(sym, &sym_info->Address);
870 sym_info->Flags |= SYMFLAG_VIRTUAL;
871 break;
872 default:
873 symt_get_address(sym, &sym_info->Address);
874 sym_info->Register = 0;
875 break;
877 sym_info->Scope = 0; /* FIXME */
878 sym_info->Tag = sym->tag;
879 name = symt_get_name(sym);
880 if (sym_info->MaxNameLen &&
881 sym->tag == SymTagPublicSymbol && (dbghelp_options & SYMOPT_UNDNAME) &&
882 (tmp = __unDName(NULL, name, 0, malloc, free, UNDNAME_NAME_ONLY)) != NULL)
884 symbol_setname(sym_info, tmp);
885 free(tmp);
887 else
888 symbol_setname(sym_info, name);
890 TRACE_(dbghelp_symt)("%p => %s %lu %I64x\n",
891 sym, sym_info->Name, sym_info->Size, sym_info->Address);
894 struct sym_enum
896 PSYM_ENUMERATESYMBOLS_CALLBACK cb;
897 PVOID user;
898 SYMBOL_INFO* sym_info;
899 DWORD index;
900 DWORD tag;
901 DWORD64 addr;
902 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
905 static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
906 const struct symt_function* func, const struct symt* sym)
908 symt_fill_sym_info(pair, func, sym, se->sym_info);
909 if (se->index && se->sym_info->Index != se->index) return FALSE;
910 if (se->tag && se->sym_info->Tag != se->tag) return FALSE;
911 if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE;
912 return !se->cb(se->sym_info, se->sym_info->Size, se->user);
915 static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match,
916 const struct sym_enum* se)
918 void* ptr;
919 struct symt_ht* sym = NULL;
920 struct hash_table_iter hti;
921 WCHAR* nameW;
922 BOOL ret;
924 hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
925 while ((ptr = hash_table_iter_up(&hti)))
927 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
928 nameW = symt_get_nameW(&sym->symt);
929 ret = SymMatchStringW(nameW, match, FALSE);
930 HeapFree(GetProcessHeap(), 0, nameW);
931 if (ret)
933 se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
934 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
935 if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
938 return FALSE;
941 static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt)
943 unsigned low = 0, mid = high / 2;
944 ULONG64 addr;
946 if (!high) return 0;
947 symt_get_address(&elt->symt, &addr);
950 switch (cmp_sorttab_addr(module, mid, addr))
952 case 0: return mid;
953 case -1: low = mid + 1; break;
954 case 1: high = mid; break;
956 mid = low + (high - low) / 2;
957 } while (low < high);
958 return mid;
961 /***********************************************************************
962 * resort_symbols
964 * Rebuild sorted list of symbols for a module.
966 static BOOL resort_symbols(struct module* module)
968 int delta;
970 if (!(module->module.NumSyms = module->num_symbols))
971 return FALSE;
973 /* we know that set from 0 up to num_sorttab is already sorted
974 * so sort the remaining (new) symbols, and merge the two sets
975 * (unless the first set is empty)
977 delta = module->num_symbols - module->num_sorttab;
978 qsort(&module->addr_sorttab[module->num_sorttab], delta, sizeof(struct symt_ht*), symt_cmp_addr);
979 if (module->num_sorttab)
981 int i, ins_idx = module->num_sorttab, prev_ins_idx;
982 static struct symt_ht** tmp;
983 static unsigned num_tmp;
985 if (num_tmp < delta)
987 static struct symt_ht** new;
988 if (tmp)
989 new = HeapReAlloc(GetProcessHeap(), 0, tmp, delta * sizeof(struct symt_ht*));
990 else
991 new = HeapAlloc(GetProcessHeap(), 0, delta * sizeof(struct symt_ht*));
992 if (!new)
994 module->num_sorttab = 0;
995 return resort_symbols(module);
997 tmp = new;
998 num_tmp = delta;
1000 memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*));
1001 qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr);
1003 for (i = delta - 1; i >= 0; i--)
1005 prev_ins_idx = ins_idx;
1006 ins_idx = where_to_insert(module, ins_idx, tmp[i]);
1007 memmove(&module->addr_sorttab[ins_idx + i + 1],
1008 &module->addr_sorttab[ins_idx],
1009 (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*));
1010 module->addr_sorttab[ins_idx + i] = tmp[i];
1013 module->num_sorttab = module->num_symbols;
1014 return module->sortlist_valid = TRUE;
1017 static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size)
1019 DWORD type_index;
1021 if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size)
1022 return;
1024 if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) &&
1025 symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return;
1026 *size = 1; /* no size info */
1029 /* needed by symt_find_nearest */
1030 static int symt_get_best_at(struct module* module, int idx_sorttab)
1032 ULONG64 ref_addr;
1033 int idx_sorttab_orig = idx_sorttab;
1034 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1036 symt_get_address(&module->addr_sorttab[idx_sorttab]->symt, &ref_addr);
1037 while (idx_sorttab > 0 &&
1038 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1039 !cmp_sorttab_addr(module, idx_sorttab - 1, ref_addr))
1040 idx_sorttab--;
1041 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1043 idx_sorttab = idx_sorttab_orig;
1044 while (idx_sorttab < module->num_sorttab - 1 &&
1045 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1046 !cmp_sorttab_addr(module, idx_sorttab + 1, ref_addr))
1047 idx_sorttab++;
1049 /* if no better symbol was found restore the original */
1050 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1051 idx_sorttab = idx_sorttab_orig;
1053 return idx_sorttab;
1056 /* assume addr is in module */
1057 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
1059 int mid, high, low;
1060 ULONG64 ref_addr, ref_size;
1062 if (!module->sortlist_valid || !module->addr_sorttab)
1064 if (!resort_symbols(module)) return NULL;
1068 * Binary search to find closest symbol.
1070 low = 0;
1071 high = module->num_sorttab;
1073 symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr);
1074 if (addr < ref_addr) return NULL;
1076 if (high)
1078 symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr);
1079 symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size);
1080 if (addr >= ref_addr + ref_size) return NULL;
1083 while (high > low + 1)
1085 mid = (high + low) / 2;
1086 if (cmp_sorttab_addr(module, mid, addr) < 0)
1087 low = mid;
1088 else
1089 high = mid;
1091 if (low != high && high != module->num_sorttab &&
1092 cmp_sorttab_addr(module, high, addr) <= 0)
1093 low = high;
1095 /* If found symbol is a public symbol, check if there are any other entries that
1096 * might also have the same address, but would get better information
1098 low = symt_get_best_at(module, low);
1100 return module->addr_sorttab[low];
1103 struct symt_ht* symt_find_symbol_at(struct module* module, DWORD_PTR addr)
1105 struct symt_ht* nearest = symt_find_nearest(module, addr);
1106 if (nearest)
1108 ULONG64 symaddr, symsize;
1109 symt_get_address(&nearest->symt, &symaddr);
1110 symt_get_length(module, &nearest->symt, &symsize);
1111 if (addr < symaddr || addr >= symaddr + symsize)
1112 nearest = NULL;
1114 return nearest;
1117 static BOOL symt_enum_locals_helper(struct module_pair* pair,
1118 const WCHAR* match, const struct sym_enum* se,
1119 struct symt_function* func, const struct vector* v)
1121 struct symt* lsym = NULL;
1122 DWORD_PTR pc = pair->pcs->localscope_pc;
1123 unsigned int i;
1124 WCHAR* nameW;
1125 BOOL ret;
1127 for (i=0; i<vector_length(v); i++)
1129 lsym = *(struct symt**)vector_at(v, i);
1130 switch (lsym->tag)
1132 case SymTagBlock:
1134 struct symt_block* block = (struct symt_block*)lsym;
1135 if (pc < block->address || block->address + block->size <= pc)
1136 continue;
1137 if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren))
1138 return FALSE;
1140 break;
1141 case SymTagData:
1142 nameW = symt_get_nameW(lsym);
1143 ret = SymMatchStringW(nameW, match,
1144 !(dbghelp_options & SYMOPT_CASE_INSENSITIVE));
1145 HeapFree(GetProcessHeap(), 0, nameW);
1146 if (ret)
1148 if (send_symbol(se, pair, func, lsym)) return FALSE;
1150 break;
1151 case SymTagLabel:
1152 case SymTagFuncDebugStart:
1153 case SymTagFuncDebugEnd:
1154 case SymTagCustom:
1155 case SymTagInlineSite:
1156 break;
1157 default:
1158 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
1159 assert(0);
1162 return TRUE;
1165 static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask,
1166 const struct sym_enum* se)
1168 struct module_pair pair;
1170 se->sym_info->SizeOfStruct = sizeof(*se->sym_info);
1171 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
1173 pair.pcs = pcs;
1174 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1175 if (!module_get_debug(&pair)) return FALSE;
1177 if (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1178 symt_check_tag(pcs->localscope_symt, SymTagInlineSite))
1180 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1181 return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, func, &func->vchildren);
1183 return FALSE;
1186 /**********************************************************
1187 * symbol_setname
1189 * Properly sets Name and NameLen in SYMBOL_INFO
1190 * according to MaxNameLen value
1192 void symbol_setname(SYMBOL_INFO* sym_info, const char* name)
1194 SIZE_T len = 0;
1195 if (name)
1197 sym_info->NameLen = strlen(name);
1198 if (sym_info->MaxNameLen)
1200 len = min(sym_info->NameLen, sym_info->MaxNameLen - 1);
1201 memcpy(sym_info->Name, name, len);
1204 else
1205 sym_info->NameLen = 0;
1206 sym_info->Name[len] = '\0';
1209 /******************************************************************
1210 * copy_symbolW
1212 * Helper for transforming an ANSI symbol info into a UNICODE one.
1213 * Assume that MaxNameLen is the same for both version (A & W).
1215 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
1217 siw->SizeOfStruct = si->SizeOfStruct;
1218 siw->TypeIndex = si->TypeIndex;
1219 siw->Reserved[0] = si->Reserved[0];
1220 siw->Reserved[1] = si->Reserved[1];
1221 siw->Index = si->Index;
1222 siw->Size = si->Size;
1223 siw->ModBase = si->ModBase;
1224 siw->Flags = si->Flags;
1225 siw->Value = si->Value;
1226 siw->Address = si->Address;
1227 siw->Register = si->Register;
1228 siw->Scope = si->Scope;
1229 siw->Tag = si->Tag;
1230 siw->NameLen = si->NameLen;
1231 siw->MaxNameLen = si->MaxNameLen;
1232 MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen);
1235 /* return the lowest inline site inside a function */
1236 struct symt_inlinesite* symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr)
1238 struct symt_inlinesite* current;
1239 int i;
1241 assert(func->symt.tag == SymTagFunction);
1242 for (current = func->next_inlinesite; current; current = current->func.next_inlinesite)
1244 for (i = 0; i < current->vranges.num_elts; ++i)
1246 struct addr_range* ar = (struct addr_range*)vector_at(&current->vranges, i);
1247 /* first matching range gives the lowest inline site; see dbghelp_private.h for details */
1248 if (ar->low <= addr && addr < ar->high)
1249 return current;
1252 return NULL;
1255 /* from an inline function, get either the enclosing inlined function, or the top function when no inlined */
1256 struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined)
1258 struct symt* symt = &inlined->func.symt;
1262 assert(symt);
1263 if (symt->tag == SymTagBlock)
1264 symt = ((struct symt_block*)symt)->container;
1265 else
1266 symt = ((struct symt_function*)symt)->container;
1267 } while (symt->tag == SymTagBlock);
1268 assert(symt->tag == SymTagFunction || symt->tag == SymTagInlineSite);
1269 return symt;
1272 /* lookup in module for an inline site (from addr and inline_ctx) */
1273 struct symt_inlinesite* symt_find_inlined_site(struct module* module, DWORD64 addr, DWORD inline_ctx)
1275 struct symt_ht* symt = symt_find_symbol_at(module, addr);
1277 if (symt_check_tag(&symt->symt, SymTagFunction))
1279 struct symt_function* func = (struct symt_function*)symt;
1280 struct symt_inlinesite* curr = symt_find_lowest_inlined(func, addr);
1281 DWORD depth = IFC_DEPTH(inline_ctx);
1283 if (curr)
1284 for ( ; &curr->func != func; curr = (struct symt_inlinesite*)symt_get_upper_inlined(curr))
1285 if (depth-- == 0) return curr;
1287 return NULL;
1290 DWORD symt_get_inlinesite_depth(HANDLE hProcess, DWORD64 addr)
1292 struct module_pair pair;
1293 DWORD depth = 0;
1295 if (module_init_pair(&pair, hProcess, addr))
1297 struct symt_ht* symt = symt_find_symbol_at(pair.effective, addr);
1298 if (symt_check_tag(&symt->symt, SymTagFunction))
1300 struct symt_inlinesite* inlined = symt_find_lowest_inlined((struct symt_function*)symt, addr);
1301 if (inlined)
1303 for ( ; &inlined->func.symt != &symt->symt; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined))
1304 ++depth;
1308 return depth;
1311 /******************************************************************
1312 * sym_enum
1314 * Core routine for most of the enumeration of symbols
1316 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1317 const struct sym_enum* se)
1319 struct module_pair pair;
1320 const WCHAR* bang;
1321 WCHAR* mod;
1323 pair.pcs = process_find_by_handle(hProcess);
1324 if (!pair.pcs) return FALSE;
1325 if (BaseOfDll == 0)
1327 /* do local variables ? */
1328 if (!Mask || !(bang = wcschr(Mask, '!')))
1329 return symt_enum_locals(pair.pcs, Mask, se);
1331 if (bang == Mask) return FALSE;
1333 mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR));
1334 if (!mod) return FALSE;
1335 memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR));
1336 mod[bang - Mask] = 0;
1338 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1340 if (pair.requested->type == DMT_PE && module_get_debug(&pair))
1342 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1343 symt_enum_module(&pair, bang + 1, se))
1344 break;
1347 /* not found in PE modules, retry on the ELF ones
1349 if (!pair.requested && dbghelp_opt_native)
1351 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1353 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) &&
1354 !module_get_containee(pair.pcs, pair.requested) &&
1355 module_get_debug(&pair))
1357 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1358 symt_enum_module(&pair, bang + 1, se))
1359 break;
1363 HeapFree(GetProcessHeap(), 0, mod);
1364 return TRUE;
1366 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
1367 if (!module_get_debug(&pair))
1368 return FALSE;
1370 /* we always ignore module name from Mask when BaseOfDll is defined */
1371 if (Mask && (bang = wcschr(Mask, '!')))
1373 if (bang == Mask) return FALSE;
1374 Mask = bang + 1;
1377 symt_enum_module(&pair, Mask ? Mask : L"*", se);
1379 return TRUE;
1382 static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1383 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1384 PVOID UserContext)
1386 struct sym_enum se;
1388 se.cb = EnumSymbolsCallback;
1389 se.user = UserContext;
1390 se.index = 0;
1391 se.tag = 0;
1392 se.addr = 0;
1393 se.sym_info = (PSYMBOL_INFO)se.buffer;
1395 return sym_enum(hProcess, BaseOfDll, Mask, &se);
1398 /******************************************************************
1399 * SymEnumSymbols (DBGHELP.@)
1401 * cases BaseOfDll = 0
1402 * !foo fails always (despite what MSDN states)
1403 * RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
1404 * no ! in Mask, lookup in local Context
1405 * cases BaseOfDll != 0
1406 * !foo fails always (despite what MSDN states)
1407 * RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
1409 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
1410 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1411 PVOID UserContext)
1413 BOOL ret;
1414 PWSTR maskW = NULL;
1416 TRACE("(%p %I64x %s %p %p)\n",
1417 hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
1419 if (Mask)
1421 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
1422 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
1423 return FALSE;
1424 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
1426 ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext);
1427 HeapFree(GetProcessHeap(), 0, maskW);
1428 return ret;
1431 struct sym_enumW
1433 PSYM_ENUMERATESYMBOLS_CALLBACKW cb;
1434 void* ctx;
1435 PSYMBOL_INFOW sym_info;
1436 char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(WCHAR)];
1439 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx)
1441 struct sym_enumW* sew = ctx;
1443 copy_symbolW(sew->sym_info, si);
1445 return (sew->cb)(sew->sym_info, size, sew->ctx);
1448 /******************************************************************
1449 * SymEnumSymbolsW (DBGHELP.@)
1452 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1453 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
1454 PVOID UserContext)
1456 struct sym_enumW sew;
1458 sew.ctx = UserContext;
1459 sew.cb = EnumSymbolsCallback;
1460 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
1462 return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew);
1465 struct sym_enumerate
1467 void* ctx;
1468 PSYM_ENUMSYMBOLS_CALLBACK cb;
1471 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1473 struct sym_enumerate* se = ctx;
1474 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1477 /***********************************************************************
1478 * SymEnumerateSymbols (DBGHELP.@)
1480 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
1481 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
1482 PVOID UserContext)
1484 struct sym_enumerate se;
1486 se.ctx = UserContext;
1487 se.cb = EnumSymbolsCallback;
1489 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
1492 struct sym_enumerate64
1494 void* ctx;
1495 PSYM_ENUMSYMBOLS_CALLBACK64 cb;
1498 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1500 struct sym_enumerate64* se = ctx;
1501 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1504 /***********************************************************************
1505 * SymEnumerateSymbols64 (DBGHELP.@)
1507 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll,
1508 PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,
1509 PVOID UserContext)
1511 struct sym_enumerate64 se;
1513 se.ctx = UserContext;
1514 se.cb = EnumSymbolsCallback;
1516 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se);
1519 /******************************************************************
1520 * SymFromAddr (DBGHELP.@)
1523 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address,
1524 DWORD64* Displacement, PSYMBOL_INFO Symbol)
1526 struct module_pair pair;
1527 struct symt_ht* sym;
1529 if (!module_init_pair(&pair, hProcess, Address)) return FALSE;
1530 if ((sym = symt_find_symbol_at(pair.effective, Address)) == NULL) return FALSE;
1532 symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol);
1533 if (Displacement)
1534 *Displacement = (Address >= Symbol->Address) ? (Address - Symbol->Address) : (DWORD64)-1;
1535 return TRUE;
1538 /******************************************************************
1539 * SymFromAddrW (DBGHELP.@)
1542 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address,
1543 DWORD64* Displacement, PSYMBOL_INFOW Symbol)
1545 PSYMBOL_INFO si;
1546 unsigned len;
1547 BOOL ret;
1549 len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR);
1550 si = HeapAlloc(GetProcessHeap(), 0, len);
1551 if (!si) return FALSE;
1553 si->SizeOfStruct = sizeof(*si);
1554 si->MaxNameLen = Symbol->MaxNameLen;
1555 if ((ret = SymFromAddr(hProcess, Address, Displacement, si)))
1557 copy_symbolW(Symbol, si);
1559 HeapFree(GetProcessHeap(), 0, si);
1560 return ret;
1563 /******************************************************************
1564 * SymGetSymFromAddr (DBGHELP.@)
1567 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
1568 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
1570 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1571 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1572 size_t len;
1573 DWORD64 Displacement64;
1575 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1576 si->SizeOfStruct = sizeof(*si);
1577 si->MaxNameLen = MAX_SYM_NAME;
1578 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1579 return FALSE;
1581 if (Displacement)
1582 *Displacement = Displacement64;
1583 Symbol->Address = si->Address;
1584 Symbol->Size = si->Size;
1585 Symbol->Flags = si->Flags;
1586 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1587 lstrcpynA(Symbol->Name, si->Name, len);
1588 return TRUE;
1591 /******************************************************************
1592 * SymGetSymFromAddr64 (DBGHELP.@)
1595 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address,
1596 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol)
1598 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1599 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1600 size_t len;
1601 DWORD64 Displacement64;
1603 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1604 si->SizeOfStruct = sizeof(*si);
1605 si->MaxNameLen = MAX_SYM_NAME;
1606 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1607 return FALSE;
1609 if (Displacement)
1610 *Displacement = Displacement64;
1611 Symbol->Address = si->Address;
1612 Symbol->Size = si->Size;
1613 Symbol->Flags = si->Flags;
1614 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1615 lstrcpynA(Symbol->Name, si->Name, len);
1616 return TRUE;
1619 static BOOL find_name(struct process* pcs, struct module* module, const char* name,
1620 SYMBOL_INFO* symbol)
1622 struct hash_table_iter hti;
1623 void* ptr;
1624 struct symt_ht* sym = NULL;
1625 struct module_pair pair;
1627 pair.pcs = pcs;
1628 if (!(pair.requested = module)) return FALSE;
1629 if (!module_get_debug(&pair)) return FALSE;
1631 hash_table_iter_init(&pair.effective->ht_symbols, &hti, name);
1632 while ((ptr = hash_table_iter_up(&hti)))
1634 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
1636 if (!strcmp(sym->hash_elt.name, name))
1638 symt_fill_sym_info(&pair, NULL, &sym->symt, symbol);
1639 return TRUE;
1642 return FALSE;
1645 /******************************************************************
1646 * SymFromName (DBGHELP.@)
1649 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol)
1651 struct process* pcs = process_find_by_handle(hProcess);
1652 struct module_pair pair;
1653 struct module* module;
1654 const char* name;
1656 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
1657 if (!pcs) return FALSE;
1658 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1659 name = strchr(Name, '!');
1660 if (name)
1662 char tmp[128];
1663 assert(name - Name < sizeof(tmp));
1664 memcpy(tmp, Name, name - Name);
1665 tmp[name - Name] = '\0';
1666 module = module_find_by_nameA(pcs, tmp);
1667 return find_name(pcs, module, name + 1, Symbol);
1670 /* search first in local context */
1671 pair.pcs = pcs;
1672 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1673 if (module_get_debug(&pair) &&
1674 (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1675 symt_check_tag(pcs->localscope_symt, SymTagInlineSite)))
1677 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1678 struct vector* v = &func->vchildren;
1679 unsigned i;
1681 for (i = 0; i < vector_length(v); i++)
1683 struct symt* lsym = *(struct symt**)vector_at(v, i);
1684 switch (lsym->tag)
1686 case SymTagBlock: /* no recursion */
1687 break;
1688 case SymTagData:
1689 name = symt_get_name(lsym);
1690 if (name && !strcmp(name, Name))
1692 symt_fill_sym_info(&pair, func, lsym, Symbol);
1693 return TRUE;
1695 break;
1696 case SymTagLabel: /* not returned here */
1697 case SymTagFuncDebugStart:
1698 case SymTagFuncDebugEnd:
1699 case SymTagCustom:
1700 case SymTagInlineSite:
1701 break;
1702 default:
1703 WARN("Unsupported tag: %u (%x)\n", lsym->tag, lsym->tag);
1707 /* lookup at global scope */
1708 for (module = pcs->lmodules; module; module = module->next)
1710 if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol))
1711 return TRUE;
1713 /* not found in PE modules, retry on the ELF ones
1715 if (dbghelp_opt_native)
1717 for (module = pcs->lmodules; module; module = module->next)
1719 if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
1720 !module_get_containee(pcs, module) &&
1721 find_name(pcs, module, Name, Symbol))
1722 return TRUE;
1725 SetLastError(ERROR_MOD_NOT_FOUND);
1726 return FALSE;
1729 /***********************************************************************
1730 * SymFromNameW (DBGHELP.@)
1732 BOOL WINAPI SymFromNameW(HANDLE process, const WCHAR *name, SYMBOL_INFOW *symbol)
1734 SYMBOL_INFO *si;
1735 DWORD len;
1736 char *tmp;
1737 BOOL ret;
1739 TRACE("(%p, %s, %p)\n", process, debugstr_w(name), symbol);
1741 len = sizeof(*si) + symbol->MaxNameLen;
1742 if (!(si = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE;
1744 len = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
1745 if (!(tmp = HeapAlloc(GetProcessHeap(), 0, len)))
1747 HeapFree(GetProcessHeap(), 0, si);
1748 return FALSE;
1750 WideCharToMultiByte(CP_ACP, 0, name, -1, tmp, len, NULL, NULL);
1752 si->SizeOfStruct = sizeof(*si);
1753 si->MaxNameLen = symbol->MaxNameLen;
1754 if ((ret = SymFromName(process, tmp, si)))
1755 copy_symbolW(symbol, si);
1757 HeapFree(GetProcessHeap(), 0, tmp);
1758 HeapFree(GetProcessHeap(), 0, si);
1759 return ret;
1762 /***********************************************************************
1763 * SymGetSymFromName64 (DBGHELP.@)
1765 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol)
1767 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1768 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1769 size_t len;
1771 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1772 si->SizeOfStruct = sizeof(*si);
1773 si->MaxNameLen = MAX_SYM_NAME;
1774 if (!SymFromName(hProcess, Name, si)) return FALSE;
1776 Symbol->Address = si->Address;
1777 Symbol->Size = si->Size;
1778 Symbol->Flags = si->Flags;
1779 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1780 lstrcpynA(Symbol->Name, si->Name, len);
1781 return TRUE;
1784 /***********************************************************************
1785 * SymGetSymFromName (DBGHELP.@)
1787 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symbol)
1789 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1790 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1791 size_t len;
1793 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1794 si->SizeOfStruct = sizeof(*si);
1795 si->MaxNameLen = MAX_SYM_NAME;
1796 if (!SymFromName(hProcess, Name, si)) return FALSE;
1798 Symbol->Address = si->Address;
1799 Symbol->Size = si->Size;
1800 Symbol->Flags = si->Flags;
1801 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1802 lstrcpynA(Symbol->Name, si->Name, len);
1803 return TRUE;
1806 struct internal_line_t
1808 BOOL unicode;
1809 PVOID key;
1810 DWORD line_number;
1811 union
1813 CHAR* file_nameA;
1814 WCHAR* file_nameW;
1816 DWORD64 address;
1819 static void init_internal_line(struct internal_line_t* intl, BOOL unicode)
1821 intl->unicode = unicode;
1822 intl->key = NULL;
1823 intl->line_number = 0;
1824 intl->file_nameA = NULL;
1825 intl->address = 0;
1828 static BOOL internal_line_copy_toA32(const struct internal_line_t* intl, IMAGEHLP_LINE* l32)
1830 if (intl->unicode) return FALSE;
1831 l32->Key = intl->key;
1832 l32->LineNumber = intl->line_number;
1833 l32->FileName = intl->file_nameA;
1834 l32->Address = intl->address;
1835 return TRUE;
1838 static BOOL internal_line_copy_toA64(const struct internal_line_t* intl, IMAGEHLP_LINE64* l64)
1840 if (intl->unicode) return FALSE;
1841 l64->Key = intl->key;
1842 l64->LineNumber = intl->line_number;
1843 l64->FileName = intl->file_nameA;
1844 l64->Address = intl->address;
1845 return TRUE;
1848 static BOOL internal_line_copy_toW64(const struct internal_line_t* intl, IMAGEHLP_LINEW64* l64)
1850 if (!intl->unicode) return FALSE;
1851 l64->Key = intl->key;
1852 l64->LineNumber = intl->line_number;
1853 l64->FileName = intl->file_nameW;
1854 l64->Address = intl->address;
1855 return TRUE;
1858 static BOOL internal_line_set_nameA(struct process* pcs, struct internal_line_t* intl, char* str, BOOL copy)
1860 DWORD len;
1862 if (intl->unicode)
1864 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1865 if (!(intl->file_nameW = fetch_buffer(pcs, len * sizeof(WCHAR)))) return FALSE;
1866 MultiByteToWideChar(CP_ACP, 0, str, -1, intl->file_nameW, len);
1868 else
1870 if (copy)
1872 len = strlen(str) + 1;
1873 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1874 memcpy(intl->file_nameA, str, len);
1876 else
1877 intl->file_nameA = str;
1879 return TRUE;
1882 static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* intl, WCHAR* wstr, BOOL copy)
1884 DWORD len;
1886 if (intl->unicode)
1888 if (copy)
1890 len = (lstrlenW(wstr) + 1) * sizeof(WCHAR);
1891 if (!(intl->file_nameW = fetch_buffer(pcs, len))) return FALSE;
1892 memcpy(intl->file_nameW, wstr, len);
1894 else
1895 intl->file_nameW = wstr;
1897 else
1899 DWORD len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
1900 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1901 WideCharToMultiByte(CP_ACP, 0, wstr, -1, intl->file_nameA, len, NULL, NULL);
1903 return TRUE;
1906 static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr,
1907 PDWORD pdwDisplacement, struct internal_line_t* intl)
1909 struct line_info* dli = NULL;
1910 struct line_info* found_dli = NULL;
1911 int i;
1913 for (i = vector_length(&func->vlines) - 1; i >= 0; i--)
1915 dli = vector_at(&func->vlines, i);
1916 if (!dli->is_source_file)
1918 if (found_dli || dli->u.address > addr) continue;
1919 intl->line_number = dli->line_number;
1920 intl->address = dli->u.address;
1921 intl->key = dli;
1922 found_dli = dli;
1923 continue;
1925 if (found_dli)
1927 BOOL ret;
1928 if (dbghelp_opt_native)
1930 /* Return native file paths when using winedbg */
1931 ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE);
1933 else
1935 WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file));
1936 ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE);
1937 HeapFree( GetProcessHeap(), 0, dospath );
1939 if (ret && pdwDisplacement) *pdwDisplacement = addr - found_dli->u.address;
1940 return ret;
1943 return FALSE;
1946 /******************************************************************
1947 * get_line_from_addr
1949 * fills source file information from an address
1951 static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr,
1952 PDWORD pdwDisplacement, struct internal_line_t* intl)
1954 struct module_pair pair;
1955 struct symt_ht* symt;
1957 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
1958 if ((symt = symt_find_symbol_at(pair.effective, addr)) == NULL) return FALSE;
1960 if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE;
1961 return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl);
1964 /***********************************************************************
1965 * SymGetSymNext64 (DBGHELP.@)
1967 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1969 /* algo:
1970 * get module from Symbol.Address
1971 * get index in module.addr_sorttab of Symbol.Address
1972 * increment index
1973 * if out of module bounds, move to next module in process address space
1975 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1976 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1977 return FALSE;
1980 /***********************************************************************
1981 * SymGetSymNext (DBGHELP.@)
1983 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1985 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1986 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1987 return FALSE;
1990 /***********************************************************************
1991 * SymGetSymPrev64 (DBGHELP.@)
1993 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1995 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1996 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1997 return FALSE;
2000 /***********************************************************************
2001 * SymGetSymPrev (DBGHELP.@)
2003 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
2005 FIXME("(%p, %p): stub\n", hProcess, Symbol);
2006 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2007 return FALSE;
2010 /******************************************************************
2011 * SymGetLineFromAddr (DBGHELP.@)
2014 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
2015 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
2017 struct internal_line_t intl;
2019 TRACE("(%p %p)\n", hProcess, Line);
2021 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2022 init_internal_line(&intl, FALSE);
2023 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
2024 return internal_line_copy_toA32(&intl, Line);
2027 /******************************************************************
2028 * SymGetLineFromAddr64 (DBGHELP.@)
2031 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
2032 PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line)
2034 struct internal_line_t intl;
2036 TRACE("(%p %p)\n", hProcess, Line);
2038 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2039 init_internal_line(&intl, FALSE);
2040 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
2041 return internal_line_copy_toA64(&intl, Line);
2044 /******************************************************************
2045 * SymGetLineFromAddrW64 (DBGHELP.@)
2048 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr,
2049 PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line)
2051 struct internal_line_t intl;
2053 TRACE("(%p %p)\n", hProcess, Line);
2055 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2056 init_internal_line(&intl, TRUE);
2057 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
2058 return internal_line_copy_toW64(&intl, Line);
2061 static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2063 struct module_pair pair;
2064 struct line_info* li;
2065 struct line_info* srcli;
2067 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2069 if (key == NULL) return FALSE;
2071 li = key;
2073 while (!li->is_first)
2075 li--;
2076 if (!li->is_source_file)
2078 intl->line_number = li->line_number;
2079 intl->address = li->u.address;
2080 intl->key = li;
2081 /* search source file */
2082 for (srcli = li; !srcli->is_source_file; srcli--);
2084 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2087 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2088 return FALSE;
2091 /******************************************************************
2092 * SymGetLinePrev64 (DBGHELP.@)
2095 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2097 struct internal_line_t intl;
2099 TRACE("(%p %p)\n", hProcess, Line);
2101 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2102 init_internal_line(&intl, FALSE);
2103 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2104 return internal_line_copy_toA64(&intl, Line);
2107 /******************************************************************
2108 * SymGetLinePrev (DBGHELP.@)
2111 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
2113 struct internal_line_t intl;
2115 TRACE("(%p %p)\n", hProcess, Line);
2117 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2118 init_internal_line(&intl, FALSE);
2119 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2120 return internal_line_copy_toA32(&intl, Line);
2123 /******************************************************************
2124 * SymGetLinePrevW64 (DBGHELP.@)
2127 BOOL WINAPI SymGetLinePrevW64(HANDLE hProcess, PIMAGEHLP_LINEW64 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, TRUE);
2135 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2136 return internal_line_copy_toW64(&intl, Line);
2139 static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2141 struct module_pair pair;
2142 struct line_info* li;
2143 struct line_info* srcli;
2145 if (key == NULL) return FALSE;
2146 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2148 /* search current source file */
2149 for (srcli = key; !srcli->is_source_file; srcli--);
2151 li = key;
2152 while (!li->is_last)
2154 li++;
2155 if (!li->is_source_file)
2157 intl->line_number = li->line_number;
2158 intl->address = li->u.address;
2159 intl->key = li;
2160 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2162 srcli = li;
2164 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2165 return FALSE;
2168 /******************************************************************
2169 * SymGetLineNext64 (DBGHELP.@)
2172 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2174 struct internal_line_t intl;
2176 TRACE("(%p %p)\n", hProcess, Line);
2178 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2179 init_internal_line(&intl, FALSE);
2180 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2181 return internal_line_copy_toA64(&intl, Line);
2184 /******************************************************************
2185 * SymGetLineNext (DBGHELP.@)
2188 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
2190 struct internal_line_t intl;
2192 TRACE("(%p %p)\n", hProcess, Line);
2194 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2195 init_internal_line(&intl, FALSE);
2196 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2197 return internal_line_copy_toA32(&intl, Line);
2200 /******************************************************************
2201 * SymGetLineNextW64 (DBGHELP.@)
2204 BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2206 struct internal_line_t intl;
2208 TRACE("(%p %p)\n", hProcess, Line);
2210 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2211 init_internal_line(&intl, TRUE);
2212 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2213 return internal_line_copy_toW64(&intl, Line);
2216 /***********************************************************************
2217 * SymUnDName (DBGHELP.@)
2219 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength)
2221 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2222 UNDNAME_COMPLETE) != 0;
2225 /***********************************************************************
2226 * SymUnDName64 (DBGHELP.@)
2228 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength)
2230 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2231 UNDNAME_COMPLETE) != 0;
2234 /***********************************************************************
2235 * UnDecorateSymbolName (DBGHELP.@)
2237 DWORD WINAPI UnDecorateSymbolName(const char *decorated_name, char *undecorated_name,
2238 DWORD undecorated_length, DWORD flags)
2240 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2241 debugstr_a(decorated_name), undecorated_name, undecorated_length, flags);
2243 if (!undecorated_name || !undecorated_length)
2244 return 0;
2245 if (!__unDName(undecorated_name, decorated_name, undecorated_length, malloc, free, flags))
2246 return 0;
2247 return strlen(undecorated_name);
2250 /***********************************************************************
2251 * UnDecorateSymbolNameW (DBGHELP.@)
2253 DWORD WINAPI UnDecorateSymbolNameW(const WCHAR *decorated_name, WCHAR *undecorated_name,
2254 DWORD undecorated_length, DWORD flags)
2256 char *buf, *ptr;
2257 int len, ret = 0;
2259 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2260 debugstr_w(decorated_name), undecorated_name, undecorated_length, flags);
2262 if (!undecorated_name || !undecorated_length)
2263 return 0;
2265 len = WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, NULL, 0, NULL, NULL);
2266 if ((buf = HeapAlloc(GetProcessHeap(), 0, len)))
2268 WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, buf, len, NULL, NULL);
2269 if ((ptr = __unDName(NULL, buf, 0, malloc, free, flags)))
2271 MultiByteToWideChar(CP_ACP, 0, ptr, -1, undecorated_name, undecorated_length);
2272 undecorated_name[undecorated_length - 1] = 0;
2273 ret = lstrlenW(undecorated_name);
2274 free(ptr);
2276 HeapFree(GetProcessHeap(), 0, buf);
2279 return ret;
2282 #define WILDCHAR(x) (-(x))
2284 static int re_fetch_char(const WCHAR** re)
2286 switch (**re)
2288 case '\\': (*re)++; return *(*re)++;
2289 case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
2290 default: return *(*re)++;
2294 static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
2296 return _case ? ch1 - ch2 : towupper(ch1) - towupper(ch2);
2299 static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
2301 int ch1, prev = 0;
2302 unsigned state = 0;
2304 switch (ch1 = re_fetch_char(&elt))
2306 default:
2307 return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
2308 case WILDCHAR('?'): return *string ? ++string : NULL;
2309 case WILDCHAR('*'): assert(0);
2310 case WILDCHAR('['): break;
2313 for (;;)
2315 ch1 = re_fetch_char(&elt);
2316 if (ch1 == WILDCHAR(']')) return NULL;
2317 if (state == 1 && ch1 == '-') state = 2;
2318 else
2320 if (re_match_char(*string, ch1, _case) == 0) return ++string;
2321 switch (state)
2323 case 0:
2324 state = 1;
2325 prev = ch1;
2326 break;
2327 case 1:
2328 state = 0;
2329 break;
2330 case 2:
2331 if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
2332 re_match_char(*string, ch1, _case) <= 0)
2333 return ++string;
2334 state = 0;
2335 break;
2341 /******************************************************************
2342 * re_match_multi
2344 * match a substring of *pstring according to *pre regular expression
2345 * pstring and pre are only updated in case of successful match
2347 static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
2349 const WCHAR* re_end = *pre;
2350 const WCHAR* string_end = *pstring;
2351 const WCHAR* re_beg;
2352 const WCHAR* string_beg;
2353 const WCHAR* next;
2354 int ch;
2356 while (*re_end && *string_end)
2358 string_beg = string_end;
2359 re_beg = re_end;
2360 switch (ch = re_fetch_char(&re_end))
2362 case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
2363 case WILDCHAR('*'):
2364 /* transform '*' into '?#' */
2365 re_beg = L"?";
2366 goto closure;
2367 case WILDCHAR('['):
2370 if (!(ch = re_fetch_char(&re_end))) return FALSE;
2371 } while (ch != WILDCHAR(']'));
2372 /* fall through */
2373 case WILDCHAR('?'):
2374 default:
2375 break;
2378 switch (*re_end)
2380 case '+':
2381 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2382 string_beg++;
2383 /* fall through */
2384 case '#':
2385 re_end++;
2386 closure:
2387 while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
2388 for ( ; string_end >= string_beg; string_end--)
2390 if (re_match_multi(&string_end, &re_end, _case)) goto found;
2392 return FALSE;
2393 default:
2394 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2395 string_end = next;
2399 if (*re_end || *string_end) return FALSE;
2401 found:
2402 *pre = re_end;
2403 *pstring = string_end;
2404 return TRUE;
2407 /******************************************************************
2408 * SymMatchStringA (DBGHELP.@)
2411 BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
2413 WCHAR* strW;
2414 WCHAR* reW;
2415 BOOL ret = FALSE;
2416 DWORD sz;
2418 if (!string || !re)
2420 SetLastError(ERROR_INVALID_HANDLE);
2421 return FALSE;
2423 TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
2425 sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
2426 if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2427 MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
2428 sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
2429 if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2430 MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
2432 if (strW && reW)
2433 ret = SymMatchStringW(strW, reW, _case);
2434 HeapFree(GetProcessHeap(), 0, strW);
2435 HeapFree(GetProcessHeap(), 0, reW);
2436 return ret;
2439 /******************************************************************
2440 * SymMatchStringW (DBGHELP.@)
2443 BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
2445 TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
2447 if (!string || !re)
2449 SetLastError(ERROR_INVALID_HANDLE);
2450 return FALSE;
2452 return re_match_multi(&string, &re, _case);
2455 static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2456 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2457 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2458 PVOID UserContext, DWORD Options)
2460 struct sym_enum se;
2462 if (Options != SYMSEARCH_GLOBALSONLY)
2464 FIXME("Unsupported searching with options (%lx)\n", Options);
2465 SetLastError(ERROR_INVALID_PARAMETER);
2466 return FALSE;
2469 se.cb = EnumSymbolsCallback;
2470 se.user = UserContext;
2471 se.index = Index;
2472 se.tag = SymTag;
2473 se.addr = Address;
2474 se.sym_info = (PSYMBOL_INFO)se.buffer;
2476 return sym_enum(hProcess, BaseOfDll, Mask, &se);
2479 /******************************************************************
2480 * SymSearch (DBGHELP.@)
2482 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2483 DWORD SymTag, PCSTR Mask, DWORD64 Address,
2484 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2485 PVOID UserContext, DWORD Options)
2487 LPWSTR maskW = NULL;
2488 BOOLEAN ret;
2490 TRACE("(%p %I64x %lu %lu %s %I64x %p %p %lx)\n",
2491 hProcess, BaseOfDll, Index, SymTag, Mask,
2492 Address, EnumSymbolsCallback, UserContext, Options);
2494 if (Mask)
2496 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
2498 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2499 return FALSE;
2500 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
2502 ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address,
2503 EnumSymbolsCallback, UserContext, Options);
2504 HeapFree(GetProcessHeap(), 0, maskW);
2505 return ret;
2508 /******************************************************************
2509 * SymSearchW (DBGHELP.@)
2511 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2512 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2513 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
2514 PVOID UserContext, DWORD Options)
2516 struct sym_enumW sew;
2518 TRACE("(%p %I64x %lu %lu %s %I64x %p %p %lx)\n",
2519 hProcess, BaseOfDll, Index, SymTag, debugstr_w(Mask),
2520 Address, EnumSymbolsCallback, UserContext, Options);
2522 sew.ctx = UserContext;
2523 sew.cb = EnumSymbolsCallback;
2524 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
2526 return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address,
2527 sym_enumW, &sew, Options);
2530 /******************************************************************
2531 * SymAddSymbol (DBGHELP.@)
2534 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name,
2535 DWORD64 addr, DWORD size, DWORD flags)
2537 struct module_pair pair;
2539 TRACE("(%p %s %I64x %lu)\n", hProcess, wine_dbgstr_a(name), addr, size);
2541 if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE;
2543 return symt_new_custom(pair.effective, name, addr, size) != NULL;
2546 /******************************************************************
2547 * SymAddSymbolW (DBGHELP.@)
2550 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR nameW,
2551 DWORD64 addr, DWORD size, DWORD flags)
2553 char name[MAX_SYM_NAME];
2555 TRACE("(%p %s %I64x %lu)\n", hProcess, wine_dbgstr_w(nameW), addr, size);
2557 WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, ARRAY_SIZE(name), NULL, NULL);
2559 return SymAddSymbol(hProcess, BaseOfDll, name, addr, size, flags);
2562 /******************************************************************
2563 * SymEnumLines (DBGHELP.@)
2566 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
2567 PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
2569 struct module_pair pair;
2570 struct hash_table_iter hti;
2571 struct symt_ht* sym;
2572 WCHAR* srcmask;
2573 struct line_info* dli;
2574 void* ptr;
2575 SRCCODEINFO sci;
2576 const char* file;
2578 if (!cb) return FALSE;
2579 if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
2581 if (!module_init_pair(&pair, hProcess, base)) return FALSE;
2582 if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
2583 if (!(srcmask = file_regex(srcfile))) return FALSE;
2585 sci.SizeOfStruct = sizeof(sci);
2586 sci.ModBase = base;
2588 hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
2589 while ((ptr = hash_table_iter_up(&hti)))
2591 unsigned int i;
2593 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
2594 if (sym->symt.tag != SymTagFunction) continue;
2596 sci.FileName[0] = '\0';
2597 for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
2599 dli = vector_at(&((struct symt_function*)sym)->vlines, i);
2600 if (dli->is_source_file)
2602 file = source_get(pair.effective, dli->u.source_file);
2603 if (!file) sci.FileName[0] = '\0';
2604 else
2606 DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
2607 WCHAR* fileW;
2609 if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2610 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz);
2611 if (SymMatchStringW(fileW, srcmask, FALSE))
2612 strcpy(sci.FileName, file);
2613 else
2614 sci.FileName[0] = '\0';
2615 HeapFree(GetProcessHeap(), 0, fileW);
2618 else if (sci.FileName[0])
2620 sci.Key = dli;
2621 sci.Obj[0] = '\0'; /* FIXME */
2622 sci.LineNumber = dli->line_number;
2623 sci.Address = dli->u.address;
2624 if (!cb(&sci, user)) break;
2628 HeapFree(GetProcessHeap(), 0, srcmask);
2629 return TRUE;
2632 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2633 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line)
2635 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2636 dwLineNumber, plDisplacement, Line);
2637 return FALSE;
2640 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2641 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line)
2643 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2644 dwLineNumber, lpDisplacement, Line);
2645 return FALSE;
2648 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName,
2649 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line)
2651 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName),
2652 dwLineNumber, plDisplacement, Line);
2653 return FALSE;
2656 /******************************************************************
2657 * SymFromIndex (DBGHELP.@)
2660 BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol)
2662 FIXME("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n",
2663 hProcess, BaseOfDll, index, symbol);
2665 return FALSE;
2668 /******************************************************************
2669 * SymFromIndexW (DBGHELP.@)
2672 BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol)
2674 FIXME("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n",
2675 hProcess, BaseOfDll, index, symbol);
2677 return FALSE;
2680 /******************************************************************
2681 * SymSetHomeDirectory (DBGHELP.@)
2684 PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR dir)
2686 FIXME("(%p, %s): stub\n", hProcess, dir);
2688 return NULL;
2691 /******************************************************************
2692 * SymSetHomeDirectoryW (DBGHELP.@)
2695 PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir)
2697 FIXME("(%p, %s): stub\n", hProcess, debugstr_w(dir));
2699 return NULL;
2702 /******************************************************************
2703 * SymFromInlineContext (DBGHELP.@)
2706 BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si)
2708 struct module_pair pair;
2709 struct symt_inlinesite* inlined;
2711 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, si);
2713 switch (IFC_MODE(inline_ctx))
2715 case IFC_MODE_INLINE:
2716 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2717 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2718 if (inlined)
2720 symt_fill_sym_info(&pair, NULL, &inlined->func.symt, si);
2721 if (disp) *disp = addr - inlined->func.address;
2722 return TRUE;
2724 /* fall through */
2725 case IFC_MODE_IGNORE:
2726 case IFC_MODE_REGULAR:
2727 return SymFromAddr(hProcess, addr, disp, si);
2728 default:
2729 SetLastError(ERROR_INVALID_PARAMETER);
2730 return FALSE;
2734 /******************************************************************
2735 * SymFromInlineContextW (DBGHELP.@)
2738 BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFOW siW)
2740 PSYMBOL_INFO si;
2741 unsigned len;
2742 BOOL ret;
2744 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, siW);
2746 len = sizeof(*si) + siW->MaxNameLen * sizeof(WCHAR);
2747 si = HeapAlloc(GetProcessHeap(), 0, len);
2748 if (!si) return FALSE;
2750 si->SizeOfStruct = sizeof(*si);
2751 si->MaxNameLen = siW->MaxNameLen;
2752 if ((ret = SymFromInlineContext(hProcess, addr, inline_ctx, disp, si)))
2754 copy_symbolW(siW, si);
2756 HeapFree(GetProcessHeap(), 0, si);
2757 return ret;
2760 static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp,
2761 struct internal_line_t* intl)
2763 struct module_pair pair;
2764 struct symt_inlinesite* inlined;
2766 if (!module_init_pair(&pair, hProcess, mod_addr ? mod_addr : addr)) return FALSE;
2767 switch (IFC_MODE(inline_ctx))
2769 case IFC_MODE_INLINE:
2770 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2771 if (inlined && get_line_from_function(&pair, &inlined->func, addr, disp, intl))
2772 return TRUE;
2773 /* fall through: check if we can find line info at top function level */
2774 case IFC_MODE_IGNORE:
2775 case IFC_MODE_REGULAR:
2776 return get_line_from_addr(hProcess, addr, disp, intl);
2777 default:
2778 SetLastError(ERROR_INVALID_PARAMETER);
2779 return FALSE;
2783 /******************************************************************
2784 * SymGetLineFromInlineContext (DBGHELP.@)
2787 BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line)
2789 struct internal_line_t intl;
2791 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2792 hProcess, addr, inline_ctx, mod_addr, disp, line);
2794 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2795 init_internal_line(&intl, FALSE);
2797 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2798 return internal_line_copy_toA64(&intl, line);
2801 /******************************************************************
2802 * SymGetLineFromInlineContextW (DBGHELP.@)
2805 BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line)
2807 struct internal_line_t intl;
2809 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2810 hProcess, addr, inline_ctx, mod_addr, disp, line);
2812 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2813 init_internal_line(&intl, TRUE);
2815 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2816 return internal_line_copy_toW64(&intl, line);
2819 /******************************************************************
2820 * SymSrvGetFileIndexInfo (DBGHELP.@)
2823 BOOL WINAPI SymSrvGetFileIndexInfo(const char *file, SYMSRV_INDEX_INFO* info, DWORD flags)
2825 FIXME("(%s, %p, 0x%08lx): stub!\n", debugstr_a(file), info, flags);
2826 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2827 return FALSE;