regedit: Mark WCHAR szFrameClass static.
[wine.git] / dlls / dbghelp / symbol.c
blob64f376b42f06975ea660fdf72718b09bbeaa6399
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,
232 ULONG_PTR address, unsigned src_idx)
234 struct symt_compiland* sym;
235 struct symt_compiland** p;
237 TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n",
238 debugstr_w(module->modulename), source_get(module, src_idx));
239 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
241 sym->symt.tag = SymTagCompiland;
242 sym->container = module->top;
243 sym->address = address;
244 sym->source = src_idx;
245 vector_init(&sym->vchildren, sizeof(struct symt*), 32);
246 sym->user = NULL;
247 p = vector_add(&module->top->vchildren, &module->pool);
248 *p = sym;
250 return sym;
253 struct symt_public* symt_new_public(struct module* module,
254 struct symt_compiland* compiland,
255 const char* name,
256 BOOL is_function,
257 ULONG_PTR address, unsigned size)
259 struct symt_public* sym;
260 struct symt** p;
262 TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%Ix\n",
263 debugstr_w(module->modulename), name, address);
264 if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
265 symt_find_nearest(module, address) != NULL)
266 return NULL;
267 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
269 sym->symt.tag = SymTagPublicSymbol;
270 sym->hash_elt.name = pool_strdup(&module->pool, name);
271 sym->container = compiland ? &compiland->symt : NULL;
272 sym->is_function = is_function;
273 sym->address = address;
274 sym->size = size;
275 symt_add_module_ht(module, (struct symt_ht*)sym);
276 if (compiland)
278 p = vector_add(&compiland->vchildren, &module->pool);
279 *p = &sym->symt;
282 return sym;
285 struct symt_data* symt_new_global_variable(struct module* module,
286 struct symt_compiland* compiland,
287 const char* name, unsigned is_static,
288 struct location loc, ULONG_PTR size,
289 struct symt* type)
291 struct symt_data* sym;
292 struct symt** p;
293 DWORD64 tsz;
295 TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%Ix %p\n",
296 debugstr_w(module->modulename), name, loc.kind, loc.offset, type);
297 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
299 sym->symt.tag = SymTagData;
300 sym->hash_elt.name = pool_strdup(&module->pool, name);
301 sym->kind = is_static ? DataIsFileStatic : DataIsGlobal;
302 sym->container = compiland ? &compiland->symt : NULL;
303 sym->type = type;
304 sym->u.var = loc;
305 if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz))
307 if (tsz != size)
308 FIXME("Size mismatch for %s.%s between type (%s) and src (%Iu)\n",
309 debugstr_w(module->modulename), name,
310 wine_dbgstr_longlong(tsz), size);
312 symt_add_module_ht(module, (struct symt_ht*)sym);
313 if (compiland)
315 p = vector_add(&compiland->vchildren, &module->pool);
316 *p = &sym->symt;
319 return sym;
322 static void init_function_or_inlinesite(struct symt_function* sym,
323 struct module* module,
324 DWORD tag,
325 struct symt* container,
326 const char* name,
327 ULONG_PTR addr, ULONG_PTR size,
328 struct symt* sig_type)
330 assert(!sig_type || sig_type->tag == SymTagFunctionType);
331 sym->symt.tag = tag;
332 sym->hash_elt.name = pool_strdup(&module->pool, name);
333 sym->container = container;
334 sym->address = addr;
335 sym->type = sig_type;
336 sym->size = size;
337 vector_init(&sym->vlines, sizeof(struct line_info), 64);
338 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
341 struct symt_function* symt_new_function(struct module* module,
342 struct symt_compiland* compiland,
343 const char* name,
344 ULONG_PTR addr, ULONG_PTR size,
345 struct symt* sig_type)
347 struct symt_function* sym;
349 TRACE_(dbghelp_symt)("Adding global function %s:%s @%Ix-%Ix\n",
350 debugstr_w(module->modulename), name, addr, addr + size - 1);
351 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
353 struct symt** p;
354 init_function_or_inlinesite(sym, module, SymTagFunction, &compiland->symt, name, addr, size, sig_type);
355 sym->next_inlinesite = NULL; /* first of list */
356 symt_add_module_ht(module, (struct symt_ht*)sym);
357 if (compiland)
359 p = vector_add(&compiland->vchildren, &module->pool);
360 *p = &sym->symt;
363 return sym;
366 struct symt_inlinesite* symt_new_inlinesite(struct module* module,
367 struct symt_function* func,
368 struct symt* container,
369 const char* name,
370 ULONG_PTR addr,
371 struct symt* sig_type)
373 struct symt_inlinesite* sym;
375 TRACE_(dbghelp_symt)("Adding inline site %s @%Ix\n", name, addr);
376 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
378 struct symt** p;
379 assert(container);
380 init_function_or_inlinesite(&sym->func, module, SymTagInlineSite, container, name, addr, 0, sig_type);
381 vector_init(&sym->vranges, sizeof(struct addr_range), 2); /* FIXME: number of elts => to be set on input */
382 /* chain inline sites */
383 sym->func.next_inlinesite = func->next_inlinesite;
384 func->next_inlinesite = sym;
385 if (container->tag == SymTagFunction || container->tag == SymTagInlineSite)
386 p = vector_add(&((struct symt_function*)container)->vchildren, &module->pool);
387 else
389 assert(container->tag == SymTagBlock);
390 p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool);
392 *p = &sym->func.symt;
394 return sym;
397 void symt_add_func_line(struct module* module, struct symt_function* func,
398 unsigned source_idx, int line_num, ULONG_PTR addr)
400 struct line_info* dli;
401 unsigned vlen;
402 struct line_info* prev;
403 BOOL last_matches = FALSE;
404 int i;
406 if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
408 TRACE_(dbghelp_symt)("(%p)%s:%Ix %s:%u\n",
409 func, func->hash_elt.name, addr,
410 source_get(module, source_idx), line_num);
412 assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite);
414 for (i=vector_length(&func->vlines)-1; i>=0; i--)
416 dli = vector_at(&func->vlines, i);
417 if (dli->is_source_file)
419 last_matches = (source_idx == dli->u.source_file);
420 break;
423 vlen = vector_length(&func->vlines);
424 prev = vlen ? vector_at(&func->vlines, vlen - 1) : NULL;
425 if (last_matches && prev && addr == prev->u.address)
427 WARN("Duplicate addition of line number in %s\n", func->hash_elt.name);
428 return;
430 if (!last_matches)
432 /* we shouldn't have line changes on first line of function */
433 dli = vector_add(&func->vlines, &module->pool);
434 dli->is_source_file = 1;
435 dli->is_first = (prev == NULL);
436 dli->is_last = 0;
437 dli->line_number = 0;
438 dli->u.source_file = source_idx;
440 /* clear previous last */
441 if (prev) prev->is_last = 0;
442 dli = vector_add(&func->vlines, &module->pool);
443 dli->is_source_file = 0;
444 dli->is_first = 0; /* only a source file can be first */
445 dli->is_last = 1;
446 dli->line_number = line_num;
447 dli->u.address = addr;
450 /******************************************************************
451 * symt_add_func_local
453 * Adds a new local/parameter to a given function:
454 * In any cases, dt tells whether it's a local variable or a parameter
455 * If regno it's not 0:
456 * - then variable is stored in a register
457 * - otherwise, value is referenced by register + offset
458 * Otherwise, the variable is stored on the stack:
459 * - offset is then the offset from the frame register
461 struct symt_data* symt_add_func_local(struct module* module,
462 struct symt_function* func,
463 enum DataKind dt,
464 const struct location* loc,
465 struct symt_block* block,
466 struct symt* type, const char* name)
468 struct symt_data* locsym;
469 struct symt** p;
471 TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n",
472 debugstr_w(module->modulename), func->hash_elt.name,
473 name, type);
475 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
476 assert(dt == DataIsParam || dt == DataIsLocal);
478 locsym = pool_alloc(&module->pool, sizeof(*locsym));
479 locsym->symt.tag = SymTagData;
480 locsym->hash_elt.name = pool_strdup(&module->pool, name);
481 locsym->hash_elt.next = NULL;
482 locsym->kind = dt;
483 locsym->container = block ? &block->symt : &func->symt;
484 locsym->type = type;
485 locsym->u.var = *loc;
486 if (block)
487 p = vector_add(&block->vchildren, &module->pool);
488 else
489 p = vector_add(&func->vchildren, &module->pool);
490 *p = &locsym->symt;
491 return locsym;
494 /******************************************************************
495 * symt_add_func_local
497 * Adds a new (local) constant to a given function
499 struct symt_data* symt_add_func_constant(struct module* module,
500 struct symt_function* func,
501 struct symt_block* block,
502 struct symt* type, const char* name,
503 VARIANT* v)
505 struct symt_data* locsym;
506 struct symt** p;
508 TRACE_(dbghelp_symt)("Adding local constant (%s:%s): %s %p\n",
509 debugstr_w(module->modulename), func->hash_elt.name,
510 name, type);
512 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
514 locsym = pool_alloc(&module->pool, sizeof(*locsym));
515 locsym->symt.tag = SymTagData;
516 locsym->hash_elt.name = pool_strdup(&module->pool, name);
517 locsym->hash_elt.next = NULL;
518 locsym->kind = DataIsConstant;
519 locsym->container = block ? &block->symt : &func->symt;
520 locsym->type = type;
521 locsym->u.value = *v;
522 if (block)
523 p = vector_add(&block->vchildren, &module->pool);
524 else
525 p = vector_add(&func->vchildren, &module->pool);
526 *p = &locsym->symt;
527 return locsym;
530 struct symt_block* symt_open_func_block(struct module* module,
531 struct symt_function* func,
532 struct symt_block* parent_block,
533 unsigned pc, unsigned len)
535 struct symt_block* block;
536 struct symt** p;
538 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
540 assert(!parent_block || parent_block->symt.tag == SymTagBlock);
541 block = pool_alloc(&module->pool, sizeof(*block));
542 block->symt.tag = SymTagBlock;
543 block->address = func->address + pc;
544 block->size = len;
545 block->container = parent_block ? &parent_block->symt : &func->symt;
546 vector_init(&block->vchildren, sizeof(struct symt*), 4);
547 if (parent_block)
548 p = vector_add(&parent_block->vchildren, &module->pool);
549 else
550 p = vector_add(&func->vchildren, &module->pool);
551 *p = &block->symt;
553 return block;
556 struct symt_block* symt_close_func_block(struct module* module,
557 const struct symt_function* func,
558 struct symt_block* block, unsigned pc)
560 assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
562 if (pc) block->size = func->address + pc - block->address;
563 return (block->container->tag == SymTagBlock) ?
564 CONTAINING_RECORD(block->container, struct symt_block, symt) : NULL;
567 struct symt_hierarchy_point* symt_add_function_point(struct module* module,
568 struct symt_function* func,
569 enum SymTagEnum point,
570 const struct location* loc,
571 const char* name)
573 struct symt_hierarchy_point*sym;
574 struct symt** p;
576 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
578 sym->symt.tag = point;
579 sym->parent = &func->symt;
580 sym->loc = *loc;
581 sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL;
582 p = vector_add(&func->vchildren, &module->pool);
583 *p = &sym->symt;
585 return sym;
588 /* low and high are absolute addresses */
589 BOOL symt_add_inlinesite_range(struct module* module,
590 struct symt_inlinesite* inlined,
591 ULONG_PTR low, ULONG_PTR high)
593 struct addr_range* p;
595 p = vector_add(&inlined->vranges, &module->pool);
596 p->low = low;
597 p->high = high;
598 if (TRUE)
600 int i;
602 /* see dbghelp_private.h for the assumptions */
603 for (i = 0; i < inlined->vranges.num_elts - 1; i++)
605 if (!addr_range_disjoint((struct addr_range*)vector_at(&inlined->vranges, i), p))
607 FIXME("Added addr_range isn't disjoint from siblings\n");
610 for ( ; inlined->func.symt.tag != SymTagFunction; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined))
612 for (i = 0; i < inlined->vranges.num_elts; i++)
614 struct addr_range* ar = (struct addr_range*)vector_at(&inlined->vranges, i);
615 if (!addr_range_disjoint(ar, p) && !addr_range_inside(ar, p))
616 WARN("Added addr_range not compatible with parent\n");
621 return TRUE;
624 struct symt_thunk* symt_new_thunk(struct module* module,
625 struct symt_compiland* compiland,
626 const char* name, THUNK_ORDINAL ord,
627 ULONG_PTR addr, ULONG_PTR size)
629 struct symt_thunk* sym;
631 TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%Ix-%Ix\n",
632 debugstr_w(module->modulename), name, addr, addr + size - 1);
634 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
636 sym->symt.tag = SymTagThunk;
637 sym->hash_elt.name = pool_strdup(&module->pool, name);
638 sym->container = &compiland->symt;
639 sym->address = addr;
640 sym->size = size;
641 sym->ordinal = ord;
642 symt_add_module_ht(module, (struct symt_ht*)sym);
643 if (compiland)
645 struct symt** p;
646 p = vector_add(&compiland->vchildren, &module->pool);
647 *p = &sym->symt;
650 return sym;
653 struct symt_data* symt_new_constant(struct module* module,
654 struct symt_compiland* compiland,
655 const char* name, struct symt* type,
656 const VARIANT* v)
658 struct symt_data* sym;
660 TRACE_(dbghelp_symt)("Adding constant value %s:%s\n",
661 debugstr_w(module->modulename), name);
663 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
665 sym->symt.tag = SymTagData;
666 sym->hash_elt.name = pool_strdup(&module->pool, name);
667 sym->kind = DataIsConstant;
668 sym->container = compiland ? &compiland->symt : NULL;
669 sym->type = type;
670 sym->u.value = *v;
671 symt_add_module_ht(module, (struct symt_ht*)sym);
672 if (compiland)
674 struct symt** p;
675 p = vector_add(&compiland->vchildren, &module->pool);
676 *p = &sym->symt;
679 return sym;
682 struct symt_hierarchy_point* symt_new_label(struct module* module,
683 struct symt_compiland* compiland,
684 const char* name, ULONG_PTR address)
686 struct symt_hierarchy_point* sym;
688 TRACE_(dbghelp_symt)("Adding global label value %s:%s\n",
689 debugstr_w(module->modulename), name);
691 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
693 sym->symt.tag = SymTagLabel;
694 sym->hash_elt.name = pool_strdup(&module->pool, name);
695 sym->loc.kind = loc_absolute;
696 sym->loc.offset = address;
697 sym->parent = compiland ? &compiland->symt : NULL;
698 symt_add_module_ht(module, (struct symt_ht*)sym);
699 if (compiland)
701 struct symt** p;
702 p = vector_add(&compiland->vchildren, &module->pool);
703 *p = &sym->symt;
706 return sym;
709 struct symt_custom* symt_new_custom(struct module* module, const char* name,
710 DWORD64 addr, DWORD size)
712 struct symt_custom* sym;
714 TRACE_(dbghelp_symt)("Adding custom symbol %s:%s\n",
715 debugstr_w(module->modulename), name);
717 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
719 sym->symt.tag = SymTagCustom;
720 sym->hash_elt.name = pool_strdup(&module->pool, name);
721 sym->address = addr;
722 sym->size = size;
723 symt_add_module_ht(module, (struct symt_ht*)sym);
725 return sym;
728 /* expect sym_info->MaxNameLen to be set before being called */
729 static void symt_fill_sym_info(struct module_pair* pair,
730 const struct symt_function* func,
731 const struct symt* sym, SYMBOL_INFO* sym_info)
733 const char* name;
734 DWORD64 size;
735 char* tmp;
737 if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex))
738 sym_info->TypeIndex = 0;
739 sym_info->Index = symt_ptr2index(pair->effective, sym);
740 sym_info->Reserved[0] = sym_info->Reserved[1] = 0;
741 if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) &&
742 (!sym_info->TypeIndex ||
743 !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex),
744 TI_GET_LENGTH, &size)))
745 size = 0;
746 sym_info->Size = (DWORD)size;
747 sym_info->ModBase = pair->requested->module.BaseOfImage;
748 sym_info->Flags = 0;
749 sym_info->Value = 0;
751 switch (sym->tag)
753 case SymTagData:
755 const struct symt_data* data = (const struct symt_data*)sym;
756 switch (data->kind)
758 case DataIsParam:
759 sym_info->Flags |= SYMFLAG_PARAMETER;
760 /* fall through */
761 case DataIsLocal:
762 sym_info->Flags |= SYMFLAG_LOCAL;
764 struct location loc = data->u.var;
766 if (loc.kind >= loc_user)
768 unsigned i;
769 struct module_format* modfmt;
771 for (i = 0; i < DFI_LAST; i++)
773 modfmt = pair->effective->format_info[i];
774 if (modfmt && modfmt->loc_compute)
776 modfmt->loc_compute(pair->pcs, modfmt, func, &loc);
777 break;
781 switch (loc.kind)
783 case loc_error:
784 /* for now we report error cases as a negative register number */
785 /* fall through */
786 case loc_register:
787 sym_info->Flags |= SYMFLAG_REGISTER;
788 sym_info->Register = loc.reg;
789 sym_info->Address = 0;
790 break;
791 case loc_regrel:
792 sym_info->Flags |= SYMFLAG_REGREL;
793 sym_info->Register = loc.reg;
794 if (loc.reg == CV_REG_NONE || (int)loc.reg < 0 /* error */)
795 FIXME("suspicious register value %x\n", loc.reg);
796 sym_info->Address = loc.offset;
797 break;
798 case loc_absolute:
799 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
800 sym_info->Value = loc.offset;
801 break;
802 default:
803 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", loc.kind);
804 assert(0);
807 break;
808 case DataIsGlobal:
809 case DataIsFileStatic:
810 switch (data->u.var.kind)
812 case loc_tlsrel:
813 sym_info->Flags |= SYMFLAG_TLSREL;
814 /* fall through */
815 case loc_absolute:
816 symt_get_address(sym, &sym_info->Address);
817 sym_info->Register = 0;
818 break;
819 default:
820 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind);
821 assert(0);
823 break;
824 case DataIsConstant:
825 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
826 if (data->container &&
827 (data->container->tag == SymTagFunction || data->container->tag == SymTagBlock))
828 sym_info->Flags |= SYMFLAG_LOCAL;
829 switch (V_VT(&data->u.value))
831 case VT_I8: sym_info->Value = (LONG64)V_I8(&data->u.value); break;
832 case VT_I4: sym_info->Value = (LONG64)V_I4(&data->u.value); break;
833 case VT_I2: sym_info->Value = (LONG64)V_I2(&data->u.value); break;
834 case VT_I1: sym_info->Value = (LONG64)V_I1(&data->u.value); break;
835 case VT_UINT:sym_info->Value = V_UINT(&data->u.value); break;
836 case VT_UI8: sym_info->Value = V_UI8(&data->u.value); break;
837 case VT_UI4: sym_info->Value = V_UI4(&data->u.value); break;
838 case VT_UI2: sym_info->Value = V_UI2(&data->u.value); break;
839 case VT_UI1: sym_info->Value = V_UI1(&data->u.value); break;
840 case VT_BYREF: sym_info->Value = (DWORD_PTR)V_BYREF(&data->u.value); break;
841 case VT_EMPTY: sym_info->Value = 0; break;
842 default:
843 FIXME("Unsupported variant type (%u)\n", V_VT(&data->u.value));
844 sym_info->Value = 0;
845 break;
847 break;
848 default:
849 FIXME("Unhandled kind (%u) in sym data\n", data->kind);
852 break;
853 case SymTagPublicSymbol:
855 const struct symt_public* pub = (const struct symt_public*)sym;
856 if (pub->is_function)
857 sym_info->Flags |= SYMFLAG_PUBLIC_CODE;
858 else
859 sym_info->Flags |= SYMFLAG_EXPORT;
860 symt_get_address(sym, &sym_info->Address);
862 break;
863 case SymTagFunction:
864 case SymTagInlineSite:
865 symt_get_address(sym, &sym_info->Address);
866 break;
867 case SymTagThunk:
868 sym_info->Flags |= SYMFLAG_THUNK;
869 symt_get_address(sym, &sym_info->Address);
870 break;
871 case SymTagCustom:
872 symt_get_address(sym, &sym_info->Address);
873 sym_info->Flags |= SYMFLAG_VIRTUAL;
874 break;
875 default:
876 symt_get_address(sym, &sym_info->Address);
877 sym_info->Register = 0;
878 break;
880 sym_info->Scope = 0; /* FIXME */
881 sym_info->Tag = sym->tag;
882 name = symt_get_name(sym);
883 if (sym_info->MaxNameLen &&
884 sym->tag == SymTagPublicSymbol && (dbghelp_options & SYMOPT_UNDNAME) &&
885 (tmp = __unDName(NULL, name, 0, malloc, free, UNDNAME_NAME_ONLY)) != NULL)
887 symbol_setname(sym_info, tmp);
888 free(tmp);
890 else
891 symbol_setname(sym_info, name);
893 TRACE_(dbghelp_symt)("%p => %s %lu %s\n",
894 sym, sym_info->Name, sym_info->Size,
895 wine_dbgstr_longlong(sym_info->Address));
898 struct sym_enum
900 PSYM_ENUMERATESYMBOLS_CALLBACK cb;
901 PVOID user;
902 SYMBOL_INFO* sym_info;
903 DWORD index;
904 DWORD tag;
905 DWORD64 addr;
906 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
909 static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
910 const struct symt_function* func, const struct symt* sym)
912 symt_fill_sym_info(pair, func, sym, se->sym_info);
913 if (se->index && se->sym_info->Index != se->index) return FALSE;
914 if (se->tag && se->sym_info->Tag != se->tag) return FALSE;
915 if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE;
916 return !se->cb(se->sym_info, se->sym_info->Size, se->user);
919 static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match,
920 const struct sym_enum* se)
922 void* ptr;
923 struct symt_ht* sym = NULL;
924 struct hash_table_iter hti;
925 WCHAR* nameW;
926 BOOL ret;
928 hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
929 while ((ptr = hash_table_iter_up(&hti)))
931 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
932 nameW = symt_get_nameW(&sym->symt);
933 ret = SymMatchStringW(nameW, match, FALSE);
934 HeapFree(GetProcessHeap(), 0, nameW);
935 if (ret)
937 se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
938 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
939 if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
942 return FALSE;
945 static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt)
947 unsigned low = 0, mid = high / 2;
948 ULONG64 addr;
950 if (!high) return 0;
951 symt_get_address(&elt->symt, &addr);
954 switch (cmp_sorttab_addr(module, mid, addr))
956 case 0: return mid;
957 case -1: low = mid + 1; break;
958 case 1: high = mid; break;
960 mid = low + (high - low) / 2;
961 } while (low < high);
962 return mid;
965 /***********************************************************************
966 * resort_symbols
968 * Rebuild sorted list of symbols for a module.
970 static BOOL resort_symbols(struct module* module)
972 int delta;
974 if (!(module->module.NumSyms = module->num_symbols))
975 return FALSE;
977 /* we know that set from 0 up to num_sorttab is already sorted
978 * so sort the remaining (new) symbols, and merge the two sets
979 * (unless the first set is empty)
981 delta = module->num_symbols - module->num_sorttab;
982 qsort(&module->addr_sorttab[module->num_sorttab], delta, sizeof(struct symt_ht*), symt_cmp_addr);
983 if (module->num_sorttab)
985 int i, ins_idx = module->num_sorttab, prev_ins_idx;
986 static struct symt_ht** tmp;
987 static unsigned num_tmp;
989 if (num_tmp < delta)
991 static struct symt_ht** new;
992 if (tmp)
993 new = HeapReAlloc(GetProcessHeap(), 0, tmp, delta * sizeof(struct symt_ht*));
994 else
995 new = HeapAlloc(GetProcessHeap(), 0, delta * sizeof(struct symt_ht*));
996 if (!new)
998 module->num_sorttab = 0;
999 return resort_symbols(module);
1001 tmp = new;
1002 num_tmp = delta;
1004 memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*));
1005 qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr);
1007 for (i = delta - 1; i >= 0; i--)
1009 prev_ins_idx = ins_idx;
1010 ins_idx = where_to_insert(module, ins_idx, tmp[i]);
1011 memmove(&module->addr_sorttab[ins_idx + i + 1],
1012 &module->addr_sorttab[ins_idx],
1013 (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*));
1014 module->addr_sorttab[ins_idx + i] = tmp[i];
1017 module->num_sorttab = module->num_symbols;
1018 return module->sortlist_valid = TRUE;
1021 static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size)
1023 DWORD type_index;
1025 if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size)
1026 return;
1028 if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) &&
1029 symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return;
1030 *size = 0x1000; /* arbitrary value */
1033 /* needed by symt_find_nearest */
1034 static int symt_get_best_at(struct module* module, int idx_sorttab)
1036 ULONG64 ref_addr;
1037 int idx_sorttab_orig = idx_sorttab;
1038 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1040 symt_get_address(&module->addr_sorttab[idx_sorttab]->symt, &ref_addr);
1041 while (idx_sorttab > 0 &&
1042 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1043 !cmp_sorttab_addr(module, idx_sorttab - 1, ref_addr))
1044 idx_sorttab--;
1045 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1047 idx_sorttab = idx_sorttab_orig;
1048 while (idx_sorttab < module->num_sorttab - 1 &&
1049 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol &&
1050 !cmp_sorttab_addr(module, idx_sorttab + 1, ref_addr))
1051 idx_sorttab++;
1053 /* if no better symbol was found restore the original */
1054 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol)
1055 idx_sorttab = idx_sorttab_orig;
1057 return idx_sorttab;
1060 /* assume addr is in module */
1061 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
1063 int mid, high, low;
1064 ULONG64 ref_addr, ref_size;
1066 if (!module->sortlist_valid || !module->addr_sorttab)
1068 if (!resort_symbols(module)) return NULL;
1072 * Binary search to find closest symbol.
1074 low = 0;
1075 high = module->num_sorttab;
1077 symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr);
1078 if (addr < ref_addr) return NULL;
1080 if (high)
1082 symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr);
1083 symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size);
1084 if (addr >= ref_addr + ref_size) return NULL;
1087 while (high > low + 1)
1089 mid = (high + low) / 2;
1090 if (cmp_sorttab_addr(module, mid, addr) < 0)
1091 low = mid;
1092 else
1093 high = mid;
1095 if (low != high && high != module->num_sorttab &&
1096 cmp_sorttab_addr(module, high, addr) <= 0)
1097 low = high;
1099 /* If found symbol is a public symbol, check if there are any other entries that
1100 * might also have the same address, but would get better information
1102 low = symt_get_best_at(module, low);
1104 return module->addr_sorttab[low];
1107 static BOOL symt_enum_locals_helper(struct module_pair* pair,
1108 const WCHAR* match, const struct sym_enum* se,
1109 struct symt_function* func, const struct vector* v)
1111 struct symt* lsym = NULL;
1112 DWORD_PTR pc = pair->pcs->localscope_pc;
1113 unsigned int i;
1114 WCHAR* nameW;
1115 BOOL ret;
1117 for (i=0; i<vector_length(v); i++)
1119 lsym = *(struct symt**)vector_at(v, i);
1120 switch (lsym->tag)
1122 case SymTagBlock:
1124 struct symt_block* block = (struct symt_block*)lsym;
1125 if (pc < block->address || block->address + block->size <= pc)
1126 continue;
1127 if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren))
1128 return FALSE;
1130 break;
1131 case SymTagData:
1132 nameW = symt_get_nameW(lsym);
1133 ret = SymMatchStringW(nameW, match,
1134 !(dbghelp_options & SYMOPT_CASE_INSENSITIVE));
1135 HeapFree(GetProcessHeap(), 0, nameW);
1136 if (ret)
1138 if (send_symbol(se, pair, func, lsym)) return FALSE;
1140 break;
1141 case SymTagLabel:
1142 case SymTagFuncDebugStart:
1143 case SymTagFuncDebugEnd:
1144 case SymTagCustom:
1145 case SymTagInlineSite:
1146 break;
1147 default:
1148 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
1149 assert(0);
1152 return TRUE;
1155 static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask,
1156 const struct sym_enum* se)
1158 struct module_pair pair;
1160 se->sym_info->SizeOfStruct = sizeof(*se->sym_info);
1161 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
1163 pair.pcs = pcs;
1164 pair.requested = module_find_by_addr(pair.pcs, pcs->localscope_pc, DMT_UNKNOWN);
1165 if (!module_get_debug(&pair)) return FALSE;
1167 if (symt_check_tag(pcs->localscope_symt, SymTagFunction) ||
1168 symt_check_tag(pcs->localscope_symt, SymTagInlineSite))
1170 struct symt_function* func = (struct symt_function*)pcs->localscope_symt;
1171 return symt_enum_locals_helper(&pair, mask ? mask : L"*", se, func, &func->vchildren);
1173 return FALSE;
1176 /**********************************************************
1177 * symbol_setname
1179 * Properly sets Name and NameLen in SYMBOL_INFO
1180 * according to MaxNameLen value
1182 void symbol_setname(SYMBOL_INFO* sym_info, const char* name)
1184 SIZE_T len = 0;
1185 if (name)
1187 sym_info->NameLen = strlen(name);
1188 if (sym_info->MaxNameLen)
1190 len = min(sym_info->NameLen, sym_info->MaxNameLen - 1);
1191 memcpy(sym_info->Name, name, len);
1194 else
1195 sym_info->NameLen = 0;
1196 sym_info->Name[len] = '\0';
1199 /******************************************************************
1200 * copy_symbolW
1202 * Helper for transforming an ANSI symbol info into a UNICODE one.
1203 * Assume that MaxNameLen is the same for both version (A & W).
1205 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
1207 siw->SizeOfStruct = si->SizeOfStruct;
1208 siw->TypeIndex = si->TypeIndex;
1209 siw->Reserved[0] = si->Reserved[0];
1210 siw->Reserved[1] = si->Reserved[1];
1211 siw->Index = si->Index;
1212 siw->Size = si->Size;
1213 siw->ModBase = si->ModBase;
1214 siw->Flags = si->Flags;
1215 siw->Value = si->Value;
1216 siw->Address = si->Address;
1217 siw->Register = si->Register;
1218 siw->Scope = si->Scope;
1219 siw->Tag = si->Tag;
1220 siw->NameLen = si->NameLen;
1221 siw->MaxNameLen = si->MaxNameLen;
1222 MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen);
1225 /* return the lowest inline site inside a function */
1226 struct symt_inlinesite* symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr)
1228 struct symt_inlinesite* current;
1229 int i;
1231 assert(func->symt.tag == SymTagFunction);
1232 for (current = func->next_inlinesite; current; current = current->func.next_inlinesite)
1234 for (i = 0; i < current->vranges.num_elts; ++i)
1236 struct addr_range* ar = (struct addr_range*)vector_at(&current->vranges, i);
1237 /* first matching range gives the lowest inline site; see dbghelp_private.h for details */
1238 if (ar->low <= addr && addr < ar->high)
1239 return current;
1242 return NULL;
1245 /* from an inline function, get either the enclosing inlined function, or the top function when no inlined */
1246 struct symt* symt_get_upper_inlined(struct symt_inlinesite* inlined)
1248 struct symt* symt = &inlined->func.symt;
1252 assert(symt);
1253 if (symt->tag == SymTagBlock)
1254 symt = ((struct symt_block*)symt)->container;
1255 else
1256 symt = ((struct symt_function*)symt)->container;
1257 } while (symt->tag == SymTagBlock);
1258 assert(symt->tag == SymTagFunction || symt->tag == SymTagInlineSite);
1259 return symt;
1262 /* lookup in module for an inline site (from addr and inline_ctx) */
1263 struct symt_inlinesite* symt_find_inlined_site(struct module* module, DWORD64 addr, DWORD inline_ctx)
1265 struct symt_ht* symt = symt_find_nearest(module, addr);
1267 if (symt_check_tag(&symt->symt, SymTagFunction))
1269 struct symt_function* func = (struct symt_function*)symt;
1270 struct symt_inlinesite* curr = symt_find_lowest_inlined(func, addr);
1271 DWORD depth = IFC_DEPTH(inline_ctx);
1273 if (curr)
1274 for ( ; &curr->func != func; curr = (struct symt_inlinesite*)symt_get_upper_inlined(curr))
1275 if (depth-- == 0) return curr;
1277 return NULL;
1280 DWORD symt_get_inlinesite_depth(HANDLE hProcess, DWORD64 addr)
1282 struct module_pair pair;
1283 DWORD depth = 0;
1285 if (module_init_pair(&pair, hProcess, addr))
1287 struct symt_ht* symt = symt_find_nearest(pair.effective, addr);
1288 if (symt_check_tag(&symt->symt, SymTagFunction))
1290 struct symt_inlinesite* inlined = symt_find_lowest_inlined((struct symt_function*)symt, addr);
1291 if (inlined)
1293 for ( ; &inlined->func.symt != &symt->symt; inlined = (struct symt_inlinesite*)symt_get_upper_inlined(inlined))
1294 ++depth;
1298 return depth;
1301 /******************************************************************
1302 * sym_enum
1304 * Core routine for most of the enumeration of symbols
1306 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1307 const struct sym_enum* se)
1309 struct module_pair pair;
1310 const WCHAR* bang;
1311 WCHAR* mod;
1313 pair.pcs = process_find_by_handle(hProcess);
1314 if (!pair.pcs) return FALSE;
1315 if (BaseOfDll == 0)
1317 /* do local variables ? */
1318 if (!Mask || !(bang = wcschr(Mask, '!')))
1319 return symt_enum_locals(pair.pcs, Mask, se);
1321 if (bang == Mask) return FALSE;
1323 mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR));
1324 if (!mod) return FALSE;
1325 memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR));
1326 mod[bang - Mask] = 0;
1328 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1330 if (pair.requested->type == DMT_PE && module_get_debug(&pair))
1332 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1333 symt_enum_module(&pair, bang + 1, se))
1334 break;
1337 /* not found in PE modules, retry on the ELF ones
1339 if (!pair.requested && dbghelp_opt_native)
1341 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
1343 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) &&
1344 !module_get_containee(pair.pcs, pair.requested) &&
1345 module_get_debug(&pair))
1347 if (SymMatchStringW(pair.requested->modulename, mod, FALSE) &&
1348 symt_enum_module(&pair, bang + 1, se))
1349 break;
1353 HeapFree(GetProcessHeap(), 0, mod);
1354 return TRUE;
1356 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
1357 if (!module_get_debug(&pair))
1358 return FALSE;
1360 /* we always ignore module name from Mask when BaseOfDll is defined */
1361 if (Mask && (bang = wcschr(Mask, '!')))
1363 if (bang == Mask) return FALSE;
1364 Mask = bang + 1;
1367 symt_enum_module(&pair, Mask ? Mask : L"*", se);
1369 return TRUE;
1372 static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1373 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1374 PVOID UserContext)
1376 struct sym_enum se;
1378 se.cb = EnumSymbolsCallback;
1379 se.user = UserContext;
1380 se.index = 0;
1381 se.tag = 0;
1382 se.addr = 0;
1383 se.sym_info = (PSYMBOL_INFO)se.buffer;
1385 return sym_enum(hProcess, BaseOfDll, Mask, &se);
1388 /******************************************************************
1389 * SymEnumSymbols (DBGHELP.@)
1391 * cases BaseOfDll = 0
1392 * !foo fails always (despite what MSDN states)
1393 * RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2
1394 * no ! in Mask, lookup in local Context
1395 * cases BaseOfDll != 0
1396 * !foo fails always (despite what MSDN states)
1397 * RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is)
1399 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
1400 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
1401 PVOID UserContext)
1403 BOOL ret;
1404 PWSTR maskW = NULL;
1406 TRACE("(%p %s %s %p %p)\n",
1407 hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask),
1408 EnumSymbolsCallback, UserContext);
1410 if (Mask)
1412 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
1413 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
1414 return FALSE;
1415 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
1417 ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext);
1418 HeapFree(GetProcessHeap(), 0, maskW);
1419 return ret;
1422 struct sym_enumW
1424 PSYM_ENUMERATESYMBOLS_CALLBACKW cb;
1425 void* ctx;
1426 PSYMBOL_INFOW sym_info;
1427 char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(WCHAR)];
1430 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx)
1432 struct sym_enumW* sew = ctx;
1434 copy_symbolW(sew->sym_info, si);
1436 return (sew->cb)(sew->sym_info, size, sew->ctx);
1439 /******************************************************************
1440 * SymEnumSymbolsW (DBGHELP.@)
1443 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
1444 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
1445 PVOID UserContext)
1447 struct sym_enumW sew;
1449 sew.ctx = UserContext;
1450 sew.cb = EnumSymbolsCallback;
1451 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
1453 return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew);
1456 struct sym_enumerate
1458 void* ctx;
1459 PSYM_ENUMSYMBOLS_CALLBACK cb;
1462 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1464 struct sym_enumerate* se = ctx;
1465 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1468 /***********************************************************************
1469 * SymEnumerateSymbols (DBGHELP.@)
1471 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
1472 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
1473 PVOID UserContext)
1475 struct sym_enumerate se;
1477 se.ctx = UserContext;
1478 se.cb = EnumSymbolsCallback;
1480 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
1483 struct sym_enumerate64
1485 void* ctx;
1486 PSYM_ENUMSYMBOLS_CALLBACK64 cb;
1489 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
1491 struct sym_enumerate64* se = ctx;
1492 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
1495 /***********************************************************************
1496 * SymEnumerateSymbols64 (DBGHELP.@)
1498 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll,
1499 PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback,
1500 PVOID UserContext)
1502 struct sym_enumerate64 se;
1504 se.ctx = UserContext;
1505 se.cb = EnumSymbolsCallback;
1507 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se);
1510 /******************************************************************
1511 * SymFromAddr (DBGHELP.@)
1514 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address,
1515 DWORD64* Displacement, PSYMBOL_INFO Symbol)
1517 struct module_pair pair;
1518 struct symt_ht* sym;
1520 if (!module_init_pair(&pair, hProcess, Address)) return FALSE;
1521 if ((sym = symt_find_nearest(pair.effective, Address)) == NULL) return FALSE;
1523 symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol);
1524 if (Displacement)
1525 *Displacement = (Address >= Symbol->Address) ? (Address - Symbol->Address) : (DWORD64)-1;
1526 return TRUE;
1529 /******************************************************************
1530 * SymFromAddrW (DBGHELP.@)
1533 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address,
1534 DWORD64* Displacement, PSYMBOL_INFOW Symbol)
1536 PSYMBOL_INFO si;
1537 unsigned len;
1538 BOOL ret;
1540 len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR);
1541 si = HeapAlloc(GetProcessHeap(), 0, len);
1542 if (!si) return FALSE;
1544 si->SizeOfStruct = sizeof(*si);
1545 si->MaxNameLen = Symbol->MaxNameLen;
1546 if ((ret = SymFromAddr(hProcess, Address, Displacement, si)))
1548 copy_symbolW(Symbol, si);
1550 HeapFree(GetProcessHeap(), 0, si);
1551 return ret;
1554 /******************************************************************
1555 * SymGetSymFromAddr (DBGHELP.@)
1558 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
1559 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
1561 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1562 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1563 size_t len;
1564 DWORD64 Displacement64;
1566 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1567 si->SizeOfStruct = sizeof(*si);
1568 si->MaxNameLen = MAX_SYM_NAME;
1569 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1570 return FALSE;
1572 if (Displacement)
1573 *Displacement = Displacement64;
1574 Symbol->Address = si->Address;
1575 Symbol->Size = si->Size;
1576 Symbol->Flags = si->Flags;
1577 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1578 lstrcpynA(Symbol->Name, si->Name, len);
1579 return TRUE;
1582 /******************************************************************
1583 * SymGetSymFromAddr64 (DBGHELP.@)
1586 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address,
1587 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol)
1589 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1590 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1591 size_t len;
1592 DWORD64 Displacement64;
1594 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1595 si->SizeOfStruct = sizeof(*si);
1596 si->MaxNameLen = MAX_SYM_NAME;
1597 if (!SymFromAddr(hProcess, Address, &Displacement64, si))
1598 return FALSE;
1600 if (Displacement)
1601 *Displacement = Displacement64;
1602 Symbol->Address = si->Address;
1603 Symbol->Size = si->Size;
1604 Symbol->Flags = si->Flags;
1605 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1606 lstrcpynA(Symbol->Name, si->Name, len);
1607 return TRUE;
1610 static BOOL find_name(struct process* pcs, struct module* module, const char* name,
1611 SYMBOL_INFO* symbol)
1613 struct hash_table_iter hti;
1614 void* ptr;
1615 struct symt_ht* sym = NULL;
1616 struct module_pair pair;
1618 pair.pcs = pcs;
1619 if (!(pair.requested = module)) return FALSE;
1620 if (!module_get_debug(&pair)) return FALSE;
1622 hash_table_iter_init(&pair.effective->ht_symbols, &hti, name);
1623 while ((ptr = hash_table_iter_up(&hti)))
1625 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
1627 if (!strcmp(sym->hash_elt.name, name))
1629 symt_fill_sym_info(&pair, NULL, &sym->symt, symbol);
1630 return TRUE;
1633 return FALSE;
1636 /******************************************************************
1637 * SymFromName (DBGHELP.@)
1640 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol)
1642 struct process* pcs = process_find_by_handle(hProcess);
1643 struct module* module;
1644 const char* name;
1646 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
1647 if (!pcs) return FALSE;
1648 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1649 name = strchr(Name, '!');
1650 if (name)
1652 char tmp[128];
1653 assert(name - Name < sizeof(tmp));
1654 memcpy(tmp, Name, name - Name);
1655 tmp[name - Name] = '\0';
1656 module = module_find_by_nameA(pcs, tmp);
1657 return find_name(pcs, module, name + 1, Symbol);
1659 for (module = pcs->lmodules; module; module = module->next)
1661 if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol))
1662 return TRUE;
1664 /* not found in PE modules, retry on the ELF ones
1666 if (dbghelp_opt_native)
1668 for (module = pcs->lmodules; module; module = module->next)
1670 if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
1671 !module_get_containee(pcs, module) &&
1672 find_name(pcs, module, Name, Symbol))
1673 return TRUE;
1676 return FALSE;
1679 /***********************************************************************
1680 * SymFromNameW (DBGHELP.@)
1682 BOOL WINAPI SymFromNameW(HANDLE process, const WCHAR *name, SYMBOL_INFOW *symbol)
1684 SYMBOL_INFO *si;
1685 DWORD len;
1686 char *tmp;
1687 BOOL ret;
1689 TRACE("(%p, %s, %p)\n", process, debugstr_w(name), symbol);
1691 len = sizeof(*si) + symbol->MaxNameLen;
1692 if (!(si = HeapAlloc(GetProcessHeap(), 0, len))) return FALSE;
1694 len = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
1695 if (!(tmp = HeapAlloc(GetProcessHeap(), 0, len)))
1697 HeapFree(GetProcessHeap(), 0, si);
1698 return FALSE;
1700 WideCharToMultiByte(CP_ACP, 0, name, -1, tmp, len, NULL, NULL);
1702 si->SizeOfStruct = sizeof(*si);
1703 si->MaxNameLen = symbol->MaxNameLen;
1704 if ((ret = SymFromName(process, tmp, si)))
1705 copy_symbolW(symbol, si);
1707 HeapFree(GetProcessHeap(), 0, tmp);
1708 HeapFree(GetProcessHeap(), 0, si);
1709 return ret;
1712 /***********************************************************************
1713 * SymGetSymFromName64 (DBGHELP.@)
1715 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol)
1717 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1718 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1719 size_t len;
1721 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1722 si->SizeOfStruct = sizeof(*si);
1723 si->MaxNameLen = MAX_SYM_NAME;
1724 if (!SymFromName(hProcess, Name, si)) return FALSE;
1726 Symbol->Address = si->Address;
1727 Symbol->Size = si->Size;
1728 Symbol->Flags = si->Flags;
1729 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1730 lstrcpynA(Symbol->Name, si->Name, len);
1731 return TRUE;
1734 /***********************************************************************
1735 * SymGetSymFromName (DBGHELP.@)
1737 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symbol)
1739 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
1740 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
1741 size_t len;
1743 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
1744 si->SizeOfStruct = sizeof(*si);
1745 si->MaxNameLen = MAX_SYM_NAME;
1746 if (!SymFromName(hProcess, Name, si)) return FALSE;
1748 Symbol->Address = si->Address;
1749 Symbol->Size = si->Size;
1750 Symbol->Flags = si->Flags;
1751 len = min(Symbol->MaxNameLength, si->MaxNameLen);
1752 lstrcpynA(Symbol->Name, si->Name, len);
1753 return TRUE;
1756 struct internal_line_t
1758 BOOL unicode;
1759 PVOID key;
1760 DWORD line_number;
1761 union
1763 CHAR* file_nameA;
1764 WCHAR* file_nameW;
1766 DWORD64 address;
1769 static void init_internal_line(struct internal_line_t* intl, BOOL unicode)
1771 intl->unicode = unicode;
1772 intl->key = NULL;
1773 intl->line_number = 0;
1774 intl->file_nameA = NULL;
1775 intl->address = 0;
1778 static BOOL internal_line_copy_toA32(const struct internal_line_t* intl, IMAGEHLP_LINE* l32)
1780 if (intl->unicode) return FALSE;
1781 l32->Key = intl->key;
1782 l32->LineNumber = intl->line_number;
1783 l32->FileName = intl->file_nameA;
1784 l32->Address = intl->address;
1785 return TRUE;
1788 static BOOL internal_line_copy_toA64(const struct internal_line_t* intl, IMAGEHLP_LINE64* l64)
1790 if (intl->unicode) return FALSE;
1791 l64->Key = intl->key;
1792 l64->LineNumber = intl->line_number;
1793 l64->FileName = intl->file_nameA;
1794 l64->Address = intl->address;
1795 return TRUE;
1798 static BOOL internal_line_copy_toW64(const struct internal_line_t* intl, IMAGEHLP_LINEW64* l64)
1800 if (!intl->unicode) return FALSE;
1801 l64->Key = intl->key;
1802 l64->LineNumber = intl->line_number;
1803 l64->FileName = intl->file_nameW;
1804 l64->Address = intl->address;
1805 return TRUE;
1808 static BOOL internal_line_set_nameA(struct process* pcs, struct internal_line_t* intl, char* str, BOOL copy)
1810 DWORD len;
1812 if (intl->unicode)
1814 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1815 if (!(intl->file_nameW = fetch_buffer(pcs, len * sizeof(WCHAR)))) return FALSE;
1816 MultiByteToWideChar(CP_ACP, 0, str, -1, intl->file_nameW, len);
1818 else
1820 if (copy)
1822 len = strlen(str) + 1;
1823 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1824 memcpy(intl->file_nameA, str, len);
1826 else
1827 intl->file_nameA = str;
1829 return TRUE;
1832 static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* intl, WCHAR* wstr, BOOL copy)
1834 DWORD len;
1836 if (intl->unicode)
1838 if (copy)
1840 len = (lstrlenW(wstr) + 1) * sizeof(WCHAR);
1841 if (!(intl->file_nameW = fetch_buffer(pcs, len))) return FALSE;
1842 memcpy(intl->file_nameW, wstr, len);
1844 else
1845 intl->file_nameW = wstr;
1847 else
1849 DWORD len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
1850 if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE;
1851 WideCharToMultiByte(CP_ACP, 0, wstr, -1, intl->file_nameA, len, NULL, NULL);
1853 return TRUE;
1856 static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr,
1857 PDWORD pdwDisplacement, struct internal_line_t* intl)
1859 struct line_info* dli = NULL;
1860 struct line_info* found_dli = NULL;
1861 int i;
1863 for (i = vector_length(&func->vlines) - 1; i >= 0; i--)
1865 dli = vector_at(&func->vlines, i);
1866 if (!dli->is_source_file)
1868 if (found_dli || dli->u.address > addr) continue;
1869 intl->line_number = dli->line_number;
1870 intl->address = dli->u.address;
1871 intl->key = dli;
1872 found_dli = dli;
1873 continue;
1875 if (found_dli)
1877 BOOL ret;
1878 if (dbghelp_opt_native)
1880 /* Return native file paths when using winedbg */
1881 ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE);
1883 else
1885 WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file));
1886 ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE);
1887 HeapFree( GetProcessHeap(), 0, dospath );
1889 if (ret) *pdwDisplacement = addr - found_dli->u.address;
1890 return ret;
1893 return FALSE;
1896 /******************************************************************
1897 * get_line_from_addr
1899 * fills source file information from an address
1901 static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr,
1902 PDWORD pdwDisplacement, struct internal_line_t* intl)
1904 struct module_pair pair;
1905 struct symt_ht* symt;
1907 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
1908 if ((symt = symt_find_nearest(pair.effective, addr)) == NULL) return FALSE;
1910 if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE;
1911 return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl);
1914 /***********************************************************************
1915 * SymGetSymNext64 (DBGHELP.@)
1917 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1919 /* algo:
1920 * get module from Symbol.Address
1921 * get index in module.addr_sorttab of Symbol.Address
1922 * increment index
1923 * if out of module bounds, move to next module in process address space
1925 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1926 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1927 return FALSE;
1930 /***********************************************************************
1931 * SymGetSymNext (DBGHELP.@)
1933 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1935 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1936 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1937 return FALSE;
1940 /***********************************************************************
1941 * SymGetSymPrev64 (DBGHELP.@)
1943 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol)
1945 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1946 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1947 return FALSE;
1950 /***********************************************************************
1951 * SymGetSymPrev (DBGHELP.@)
1953 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
1955 FIXME("(%p, %p): stub\n", hProcess, Symbol);
1956 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1957 return FALSE;
1960 /******************************************************************
1961 * SymGetLineFromAddr (DBGHELP.@)
1964 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
1965 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
1967 struct internal_line_t intl;
1969 TRACE("(%p %p)\n", hProcess, Line);
1971 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1972 init_internal_line(&intl, FALSE);
1973 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
1974 return internal_line_copy_toA32(&intl, Line);
1977 /******************************************************************
1978 * SymGetLineFromAddr64 (DBGHELP.@)
1981 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
1982 PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line)
1984 struct internal_line_t intl;
1986 TRACE("(%p %p)\n", hProcess, Line);
1988 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
1989 init_internal_line(&intl, FALSE);
1990 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
1991 return internal_line_copy_toA64(&intl, Line);
1994 /******************************************************************
1995 * SymGetLineFromAddrW64 (DBGHELP.@)
1998 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr,
1999 PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line)
2001 struct internal_line_t intl;
2003 TRACE("(%p %p)\n", hProcess, Line);
2005 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2006 init_internal_line(&intl, TRUE);
2007 if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE;
2008 return internal_line_copy_toW64(&intl, Line);
2011 static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2013 struct module_pair pair;
2014 struct line_info* li;
2015 struct line_info* srcli;
2017 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2019 if (key == NULL) return FALSE;
2021 li = key;
2023 while (!li->is_first)
2025 li--;
2026 if (!li->is_source_file)
2028 intl->line_number = li->line_number;
2029 intl->address = li->u.address;
2030 intl->key = li;
2031 /* search source file */
2032 for (srcli = li; !srcli->is_source_file; srcli--);
2034 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2037 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2038 return FALSE;
2041 /******************************************************************
2042 * SymGetLinePrev64 (DBGHELP.@)
2045 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2047 struct internal_line_t intl;
2049 TRACE("(%p %p)\n", hProcess, Line);
2051 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2052 init_internal_line(&intl, FALSE);
2053 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2054 return internal_line_copy_toA64(&intl, Line);
2057 /******************************************************************
2058 * SymGetLinePrev (DBGHELP.@)
2061 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
2063 struct internal_line_t intl;
2065 TRACE("(%p %p)\n", hProcess, Line);
2067 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2068 init_internal_line(&intl, FALSE);
2069 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2070 return internal_line_copy_toA32(&intl, Line);
2073 /******************************************************************
2074 * SymGetLinePrevW64 (DBGHELP.@)
2077 BOOL WINAPI SymGetLinePrevW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2079 struct internal_line_t intl;
2081 TRACE("(%p %p)\n", hProcess, Line);
2083 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2084 init_internal_line(&intl, TRUE);
2085 if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2086 return internal_line_copy_toW64(&intl, Line);
2089 static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr)
2091 struct module_pair pair;
2092 struct line_info* li;
2093 struct line_info* srcli;
2095 if (key == NULL) return FALSE;
2096 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
2098 /* search current source file */
2099 for (srcli = key; !srcli->is_source_file; srcli--);
2101 li = key;
2102 while (!li->is_last)
2104 li++;
2105 if (!li->is_source_file)
2107 intl->line_number = li->line_number;
2108 intl->address = li->u.address;
2109 intl->key = li;
2110 return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE);
2112 srcli = li;
2114 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
2115 return FALSE;
2118 /******************************************************************
2119 * SymGetLineNext64 (DBGHELP.@)
2122 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line)
2124 struct internal_line_t intl;
2126 TRACE("(%p %p)\n", hProcess, Line);
2128 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2129 init_internal_line(&intl, FALSE);
2130 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2131 return internal_line_copy_toA64(&intl, Line);
2134 /******************************************************************
2135 * SymGetLineNext (DBGHELP.@)
2138 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
2140 struct internal_line_t intl;
2142 TRACE("(%p %p)\n", hProcess, Line);
2144 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2145 init_internal_line(&intl, FALSE);
2146 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2147 return internal_line_copy_toA32(&intl, Line);
2150 /******************************************************************
2151 * SymGetLineNextW64 (DBGHELP.@)
2154 BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line)
2156 struct internal_line_t intl;
2158 TRACE("(%p %p)\n", hProcess, Line);
2160 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
2161 init_internal_line(&intl, TRUE);
2162 if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE;
2163 return internal_line_copy_toW64(&intl, Line);
2166 /***********************************************************************
2167 * SymUnDName (DBGHELP.@)
2169 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength)
2171 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2172 UNDNAME_COMPLETE) != 0;
2175 /***********************************************************************
2176 * SymUnDName64 (DBGHELP.@)
2178 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength)
2180 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
2181 UNDNAME_COMPLETE) != 0;
2184 /***********************************************************************
2185 * UnDecorateSymbolName (DBGHELP.@)
2187 DWORD WINAPI UnDecorateSymbolName(const char *decorated_name, char *undecorated_name,
2188 DWORD undecorated_length, DWORD flags)
2190 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2191 debugstr_a(decorated_name), undecorated_name, undecorated_length, flags);
2193 if (!undecorated_name || !undecorated_length)
2194 return 0;
2195 if (!__unDName(undecorated_name, decorated_name, undecorated_length, malloc, free, flags))
2196 return 0;
2197 return strlen(undecorated_name);
2200 /***********************************************************************
2201 * UnDecorateSymbolNameW (DBGHELP.@)
2203 DWORD WINAPI UnDecorateSymbolNameW(const WCHAR *decorated_name, WCHAR *undecorated_name,
2204 DWORD undecorated_length, DWORD flags)
2206 char *buf, *ptr;
2207 int len, ret = 0;
2209 TRACE("(%s, %p, %ld, 0x%08lx)\n",
2210 debugstr_w(decorated_name), undecorated_name, undecorated_length, flags);
2212 if (!undecorated_name || !undecorated_length)
2213 return 0;
2215 len = WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, NULL, 0, NULL, NULL);
2216 if ((buf = HeapAlloc(GetProcessHeap(), 0, len)))
2218 WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, buf, len, NULL, NULL);
2219 if ((ptr = __unDName(NULL, buf, 0, malloc, free, flags)))
2221 MultiByteToWideChar(CP_ACP, 0, ptr, -1, undecorated_name, undecorated_length);
2222 undecorated_name[undecorated_length - 1] = 0;
2223 ret = lstrlenW(undecorated_name);
2224 free(ptr);
2226 HeapFree(GetProcessHeap(), 0, buf);
2229 return ret;
2232 #define WILDCHAR(x) (-(x))
2234 static int re_fetch_char(const WCHAR** re)
2236 switch (**re)
2238 case '\\': (*re)++; return *(*re)++;
2239 case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
2240 default: return *(*re)++;
2244 static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
2246 return _case ? ch1 - ch2 : towupper(ch1) - towupper(ch2);
2249 static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
2251 int ch1, prev = 0;
2252 unsigned state = 0;
2254 switch (ch1 = re_fetch_char(&elt))
2256 default:
2257 return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
2258 case WILDCHAR('?'): return *string ? ++string : NULL;
2259 case WILDCHAR('*'): assert(0);
2260 case WILDCHAR('['): break;
2263 for (;;)
2265 ch1 = re_fetch_char(&elt);
2266 if (ch1 == WILDCHAR(']')) return NULL;
2267 if (state == 1 && ch1 == '-') state = 2;
2268 else
2270 if (re_match_char(*string, ch1, _case) == 0) return ++string;
2271 switch (state)
2273 case 0:
2274 state = 1;
2275 prev = ch1;
2276 break;
2277 case 1:
2278 state = 0;
2279 break;
2280 case 2:
2281 if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
2282 re_match_char(*string, ch1, _case) <= 0)
2283 return ++string;
2284 state = 0;
2285 break;
2291 /******************************************************************
2292 * re_match_multi
2294 * match a substring of *pstring according to *pre regular expression
2295 * pstring and pre are only updated in case of successful match
2297 static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
2299 const WCHAR* re_end = *pre;
2300 const WCHAR* string_end = *pstring;
2301 const WCHAR* re_beg;
2302 const WCHAR* string_beg;
2303 const WCHAR* next;
2304 int ch;
2306 while (*re_end && *string_end)
2308 string_beg = string_end;
2309 re_beg = re_end;
2310 switch (ch = re_fetch_char(&re_end))
2312 case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
2313 case WILDCHAR('*'):
2314 /* transform '*' into '?#' */
2315 re_beg = L"?";
2316 goto closure;
2317 case WILDCHAR('['):
2320 if (!(ch = re_fetch_char(&re_end))) return FALSE;
2321 } while (ch != WILDCHAR(']'));
2322 /* fall through */
2323 case WILDCHAR('?'):
2324 default:
2325 break;
2328 switch (*re_end)
2330 case '+':
2331 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2332 string_beg++;
2333 /* fall through */
2334 case '#':
2335 re_end++;
2336 closure:
2337 while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
2338 for ( ; string_end >= string_beg; string_end--)
2340 if (re_match_multi(&string_end, &re_end, _case)) goto found;
2342 return FALSE;
2343 default:
2344 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
2345 string_end = next;
2349 if (*re_end || *string_end) return FALSE;
2351 found:
2352 *pre = re_end;
2353 *pstring = string_end;
2354 return TRUE;
2357 /******************************************************************
2358 * SymMatchStringA (DBGHELP.@)
2361 BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
2363 WCHAR* strW;
2364 WCHAR* reW;
2365 BOOL ret = FALSE;
2366 DWORD sz;
2368 if (!string || !re)
2370 SetLastError(ERROR_INVALID_HANDLE);
2371 return FALSE;
2373 TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
2375 sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
2376 if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2377 MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
2378 sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
2379 if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2380 MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
2382 if (strW && reW)
2383 ret = SymMatchStringW(strW, reW, _case);
2384 HeapFree(GetProcessHeap(), 0, strW);
2385 HeapFree(GetProcessHeap(), 0, reW);
2386 return ret;
2389 /******************************************************************
2390 * SymMatchStringW (DBGHELP.@)
2393 BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
2395 TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
2397 if (!string || !re)
2399 SetLastError(ERROR_INVALID_HANDLE);
2400 return FALSE;
2402 return re_match_multi(&string, &re, _case);
2405 static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2406 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2407 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2408 PVOID UserContext, DWORD Options)
2410 struct sym_enum se;
2412 if (Options != SYMSEARCH_GLOBALSONLY)
2414 FIXME("Unsupported searching with options (%lx)\n", Options);
2415 SetLastError(ERROR_INVALID_PARAMETER);
2416 return FALSE;
2419 se.cb = EnumSymbolsCallback;
2420 se.user = UserContext;
2421 se.index = Index;
2422 se.tag = SymTag;
2423 se.addr = Address;
2424 se.sym_info = (PSYMBOL_INFO)se.buffer;
2426 return sym_enum(hProcess, BaseOfDll, Mask, &se);
2429 /******************************************************************
2430 * SymSearch (DBGHELP.@)
2432 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2433 DWORD SymTag, PCSTR Mask, DWORD64 Address,
2434 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
2435 PVOID UserContext, DWORD Options)
2437 LPWSTR maskW = NULL;
2438 BOOLEAN ret;
2440 TRACE("(%p %s %lu %lu %s %s %p %p %lx)\n",
2441 hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask,
2442 wine_dbgstr_longlong(Address), EnumSymbolsCallback,
2443 UserContext, Options);
2445 if (Mask)
2447 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
2449 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2450 return FALSE;
2451 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
2453 ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address,
2454 EnumSymbolsCallback, UserContext, Options);
2455 HeapFree(GetProcessHeap(), 0, maskW);
2456 return ret;
2459 /******************************************************************
2460 * SymSearchW (DBGHELP.@)
2462 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
2463 DWORD SymTag, PCWSTR Mask, DWORD64 Address,
2464 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
2465 PVOID UserContext, DWORD Options)
2467 struct sym_enumW sew;
2469 TRACE("(%p %s %lu %lu %s %s %p %p %lx)\n",
2470 hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_w(Mask),
2471 wine_dbgstr_longlong(Address), EnumSymbolsCallback,
2472 UserContext, Options);
2474 sew.ctx = UserContext;
2475 sew.cb = EnumSymbolsCallback;
2476 sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
2478 return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address,
2479 sym_enumW, &sew, Options);
2482 /******************************************************************
2483 * SymAddSymbol (DBGHELP.@)
2486 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name,
2487 DWORD64 addr, DWORD size, DWORD flags)
2489 struct module_pair pair;
2491 TRACE("(%p %s %s %lu)\n", hProcess, wine_dbgstr_a(name), wine_dbgstr_longlong(addr), size);
2493 if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE;
2495 return symt_new_custom(pair.effective, name, addr, size) != NULL;
2498 /******************************************************************
2499 * SymAddSymbolW (DBGHELP.@)
2502 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR nameW,
2503 DWORD64 addr, DWORD size, DWORD flags)
2505 char name[MAX_SYM_NAME];
2507 TRACE("(%p %s %s %lu)\n", hProcess, wine_dbgstr_w(nameW), wine_dbgstr_longlong(addr), size);
2509 WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, ARRAY_SIZE(name), NULL, NULL);
2511 return SymAddSymbol(hProcess, BaseOfDll, name, addr, size, flags);
2514 /******************************************************************
2515 * SymEnumLines (DBGHELP.@)
2518 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
2519 PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
2521 struct module_pair pair;
2522 struct hash_table_iter hti;
2523 struct symt_ht* sym;
2524 WCHAR* srcmask;
2525 struct line_info* dli;
2526 void* ptr;
2527 SRCCODEINFO sci;
2528 const char* file;
2530 if (!cb) return FALSE;
2531 if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
2533 if (!module_init_pair(&pair, hProcess, base)) return FALSE;
2534 if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
2535 if (!(srcmask = file_regex(srcfile))) return FALSE;
2537 sci.SizeOfStruct = sizeof(sci);
2538 sci.ModBase = base;
2540 hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
2541 while ((ptr = hash_table_iter_up(&hti)))
2543 unsigned int i;
2545 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
2546 if (sym->symt.tag != SymTagFunction) continue;
2548 sci.FileName[0] = '\0';
2549 for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
2551 dli = vector_at(&((struct symt_function*)sym)->vlines, i);
2552 if (dli->is_source_file)
2554 file = source_get(pair.effective, dli->u.source_file);
2555 if (!file) sci.FileName[0] = '\0';
2556 else
2558 DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
2559 WCHAR* fileW;
2561 if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
2562 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz);
2563 if (SymMatchStringW(fileW, srcmask, FALSE))
2564 strcpy(sci.FileName, file);
2565 else
2566 sci.FileName[0] = '\0';
2567 HeapFree(GetProcessHeap(), 0, fileW);
2570 else if (sci.FileName[0])
2572 sci.Key = dli;
2573 sci.Obj[0] = '\0'; /* FIXME */
2574 sci.LineNumber = dli->line_number;
2575 sci.Address = dli->u.address;
2576 if (!cb(&sci, user)) break;
2580 HeapFree(GetProcessHeap(), 0, srcmask);
2581 return TRUE;
2584 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2585 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line)
2587 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2588 dwLineNumber, plDisplacement, Line);
2589 return FALSE;
2592 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName,
2593 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line)
2595 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, ModuleName, FileName,
2596 dwLineNumber, lpDisplacement, Line);
2597 return FALSE;
2600 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName,
2601 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line)
2603 FIXME("(%p) (%s, %s, %ld %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName),
2604 dwLineNumber, plDisplacement, Line);
2605 return FALSE;
2608 /******************************************************************
2609 * SymFromIndex (DBGHELP.@)
2612 BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol)
2614 FIXME("hProcess = %p, BaseOfDll = %s, index = %ld, symbol = %p\n",
2615 hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol);
2617 return FALSE;
2620 /******************************************************************
2621 * SymFromIndexW (DBGHELP.@)
2624 BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol)
2626 FIXME("hProcess = %p, BaseOfDll = %s, index = %ld, symbol = %p\n",
2627 hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol);
2629 return FALSE;
2632 /******************************************************************
2633 * SymSetHomeDirectory (DBGHELP.@)
2636 PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR dir)
2638 FIXME("(%p, %s): stub\n", hProcess, dir);
2640 return NULL;
2643 /******************************************************************
2644 * SymSetHomeDirectoryW (DBGHELP.@)
2647 PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir)
2649 FIXME("(%p, %s): stub\n", hProcess, debugstr_w(dir));
2651 return NULL;
2654 /******************************************************************
2655 * SymFromInlineContext (DBGHELP.@)
2658 BOOL WINAPI SymFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFO si)
2660 struct module_pair pair;
2661 struct symt_inlinesite* inlined;
2663 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, si);
2665 switch (IFC_MODE(inline_ctx))
2667 case IFC_MODE_IGNORE:
2668 case IFC_MODE_REGULAR:
2669 return SymFromAddr(hProcess, addr, disp, si);
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->func.symt, si);
2676 *disp = addr - inlined->func.address;
2677 return TRUE;
2679 /* fall through */
2680 default:
2681 SetLastError(ERROR_INVALID_PARAMETER);
2682 return FALSE;
2686 /******************************************************************
2687 * SymFromInlineContextW (DBGHELP.@)
2690 BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, PDWORD64 disp, PSYMBOL_INFOW siW)
2692 PSYMBOL_INFO si;
2693 unsigned len;
2694 BOOL ret;
2696 TRACE("(%p, %#I64x, 0x%lx, %p, %p)\n", hProcess, addr, inline_ctx, disp, siW);
2698 len = sizeof(*si) + siW->MaxNameLen * sizeof(WCHAR);
2699 si = HeapAlloc(GetProcessHeap(), 0, len);
2700 if (!si) return FALSE;
2702 si->SizeOfStruct = sizeof(*si);
2703 si->MaxNameLen = siW->MaxNameLen;
2704 if ((ret = SymFromInlineContext(hProcess, addr, inline_ctx, disp, si)))
2706 copy_symbolW(siW, si);
2708 HeapFree(GetProcessHeap(), 0, si);
2709 return ret;
2712 static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp,
2713 struct internal_line_t* intl)
2715 struct module_pair pair;
2716 struct symt_inlinesite* inlined;
2718 if (!module_init_pair(&pair, hProcess, mod_addr ? mod_addr : addr)) return FALSE;
2719 switch (IFC_MODE(inline_ctx))
2721 case IFC_MODE_INLINE:
2722 inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx);
2723 if (inlined && get_line_from_function(&pair, &inlined->func, addr, disp, intl))
2724 return TRUE;
2725 /* fall through: check if we can find line info at top function level */
2726 case IFC_MODE_IGNORE:
2727 case IFC_MODE_REGULAR:
2728 return get_line_from_addr(hProcess, addr, disp, intl);
2729 default:
2730 SetLastError(ERROR_INVALID_PARAMETER);
2731 return FALSE;
2735 /******************************************************************
2736 * SymGetLineFromInlineContext (DBGHELP.@)
2739 BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line)
2741 struct internal_line_t intl;
2743 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2744 hProcess, addr, inline_ctx, mod_addr, disp, line);
2746 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2747 init_internal_line(&intl, FALSE);
2749 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2750 return internal_line_copy_toA64(&intl, line);
2753 /******************************************************************
2754 * SymGetLineFromInlineContextW (DBGHELP.@)
2757 BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line)
2759 struct internal_line_t intl;
2761 TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n",
2762 hProcess, addr, inline_ctx, mod_addr, disp, line);
2764 if (line->SizeOfStruct < sizeof(*line)) return FALSE;
2765 init_internal_line(&intl, TRUE);
2767 if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE;
2768 return internal_line_copy_toW64(&intl, line);