First shot at implementing dbghelp.
[wine/multimedia.git] / dlls / dbghelp / symbol.c
blob21d562ecb9086a455331de6089ea874cf57df537
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <sys/types.h>
29 #include <assert.h>
30 #include <regex.h>
31 #include "wine/debug.h"
33 #include "dbghelp_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
36 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symtype);
38 #define DLIT_OFFSET 0x00
39 #define DLIT_FIRST 0x01
40 #define DLIT_LAST 0x02
41 #define DLIT_SOURCEFILE 0x04
43 struct line_info
45 unsigned long cookie : 3,
46 line_number;
47 union
49 unsigned long pc_offset;
50 unsigned source_file;
51 } u;
54 inline static int cmp_addr(DWORD a1, DWORD a2)
56 if (a1 > a2) return 1;
57 if (a1 < a2) return -1;
58 return 0;
61 inline static int cmp_sorttab_addr(const struct module* module, int idx, DWORD addr)
63 DWORD ref;
65 symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
66 return cmp_addr(ref, addr);
69 int symt_cmp_addr(const void* p1, const void* p2)
71 struct symt* sym1 = *(struct symt**)p1;
72 struct symt* sym2 = *(struct symt**)p2;
73 DWORD a1, a2;
75 symt_get_info(sym1, TI_GET_ADDRESS, &a1);
76 symt_get_info(sym2, TI_GET_ADDRESS, &a2);
77 return cmp_addr(a1, a2);
80 struct symt_compiland* symt_new_compiland(struct module* module, const char* name)
82 struct symt_compiland* sym;
84 TRACE_(dbghelp_symtype)("Adding compiland symbol %s:%s\n",
85 module->module.ModuleName, name);
86 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
88 sym->symt.tag = SymTagCompiland;
89 sym->source = source_new(module, name);
90 vector_init(&sym->vchildren, sizeof(struct symt*), 32);
92 return sym;
95 struct symt_public* symt_new_public(struct module* module,
96 struct symt_compiland* compiland,
97 const char* name,
98 unsigned long address, unsigned size,
99 BOOL in_code, BOOL is_func)
101 struct symt_public* sym;
102 struct symt** p;
104 TRACE_(dbghelp_symtype)("Adding public symbol %s:%s @%lx\n",
105 module->module.ModuleName, name, address);
106 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
108 sym->symt.tag = SymTagPublicSymbol;
109 sym->hash_elt.name = pool_strdup(&module->pool, name);
110 hash_table_add(&module->ht_symbols, &sym->hash_elt);
111 module->sortlist_valid = FALSE;
112 sym->container = compiland ? &compiland->symt : NULL;
113 sym->address = address;
114 sym->size = size;
115 sym->in_code = in_code;
116 sym->is_function = is_func;
117 if (compiland)
119 p = vector_add(&compiland->vchildren, &module->pool);
120 *p = &sym->symt;
123 return sym;
126 struct symt_data* symt_new_global_variable(struct module* module,
127 struct symt_compiland* compiland,
128 const char* name, unsigned is_static,
129 unsigned long addr, unsigned long size,
130 struct symt* type)
132 struct symt_data* sym;
133 struct symt** p;
135 TRACE_(dbghelp_symtype)("Adding global symbol %s:%s @%lx %p\n",
136 module->module.ModuleName, name, addr, type);
137 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
139 sym->symt.tag = SymTagData;
140 sym->hash_elt.name = pool_strdup(&module->pool, name);
141 hash_table_add(&module->ht_symbols, &sym->hash_elt);
142 module->sortlist_valid = FALSE;
143 sym->kind = is_static ? DataIsFileStatic : DataIsGlobal;
144 sym->container = compiland ? &compiland->symt : NULL;
145 sym->type = type;
146 sym->location = LocIsStatic; /* FIXME */
147 sym->u.address = addr;
148 if (compiland)
150 p = vector_add(&compiland->vchildren, &module->pool);
151 *p = &sym->symt;
154 return sym;
157 struct symt_function* symt_new_function(struct module* module,
158 struct symt_compiland* compiland,
159 const char* name,
160 unsigned long addr, unsigned long size,
161 struct symt* type)
163 struct symt_function* sym;
164 struct symt** p;
166 TRACE_(dbghelp_symtype)("Adding global function %s:%s @%lx-%lx\n",
167 module->module.ModuleName, name, addr, addr + size - 1);
168 if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
170 sym->symt.tag = SymTagFunction;
171 sym->hash_elt.name = pool_strdup(&module->pool, name);
172 hash_table_add(&module->ht_symbols, &sym->hash_elt);
173 module->sortlist_valid = FALSE;
174 sym->container = &compiland->symt;
175 sym->addr = addr;
176 sym->type = type;
177 sym->size = size;
178 sym->addr = addr;
179 vector_init(&sym->vlines, sizeof(struct line_info), 64);
180 vector_init(&sym->vchildren, sizeof(struct symt*), 8);
181 if (compiland)
183 p = vector_add(&compiland->vchildren, &module->pool);
184 *p = &sym->symt;
187 return sym;
190 void symt_add_func_line(struct module* module, struct symt_function* func,
191 unsigned source_idx, int line_num, unsigned long offset)
193 struct line_info* dli;
194 BOOL last_matches = FALSE;
196 if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
198 TRACE_(dbghelp_symtype)("(%p)%s:%lx %s:%u\n",
199 func, func->hash_elt.name, offset,
200 source_get(module, source_idx), line_num);
202 assert(func->symt.tag == SymTagFunction);
204 dli = NULL;
205 while ((dli = vector_iter_down(&func->vlines, dli)))
207 if (dli->cookie & DLIT_SOURCEFILE)
209 last_matches = (source_idx == dli->u.source_file);
210 break;
214 if (!last_matches)
216 /* we shouldn't have line changes on first line of function */
217 dli = vector_add(&func->vlines, &module->pool);
218 dli->cookie = DLIT_SOURCEFILE;
219 dli->line_number = 0;
220 dli->u.source_file = source_idx;
222 dli = vector_add(&func->vlines, &module->pool);
223 dli->cookie = DLIT_OFFSET;
224 dli->line_number = line_num;
225 dli->u.pc_offset = func->addr + offset;
228 struct symt_data* symt_add_func_local(struct module* module,
229 struct symt_function* func,
230 int regno, int offset,
231 struct symt_block* block,
232 struct symt* type, const char* name)
234 struct symt_data* locsym;
235 struct symt** p;
237 assert(func);
238 assert(func->symt.tag == SymTagFunction);
240 TRACE_(dbghelp_symtype)("Adding local symbol (%s:%s): %s %p\n",
241 module->module.ModuleName, func->hash_elt.name,
242 name, type);
243 locsym = pool_alloc(&module->pool, sizeof(*locsym));
244 locsym->symt.tag = SymTagData;
245 locsym->hash_elt.name = pool_strdup(&module->pool, name);
246 locsym->hash_elt.next = NULL;
247 locsym->kind = DataIsLocal;
248 locsym->container = &block->symt;
249 locsym->type = type;
250 if (regno)
252 locsym->location = LocIsEnregistered;
253 locsym->u.reg_id = regno;
255 else
257 locsym->location = LocIsRegRel;
258 locsym->u.reg_id = CV_REG_EBP;
259 locsym->u.offset = offset;
261 if (block)
262 p = vector_add(&block->vchildren, &module->pool);
263 else
264 p = vector_add(&func->vchildren, &module->pool);
265 *p = &locsym->symt;
266 return locsym;
269 struct symt_block* symt_open_func_block(struct module* module,
270 struct symt_function* func,
271 struct symt_block* parent_block,
272 unsigned pc)
274 struct symt_block* block;
275 struct symt** p;
277 assert(func);
278 assert(func->symt.tag == SymTagFunction);
280 assert(!parent_block || parent_block->symt.tag == SymTagBlock);
281 block = pool_alloc(&module->pool, sizeof(*block));
282 block->symt.tag = SymTagBlock;
283 block->address = func->addr + pc;
284 block->size = 0;
285 block->container = parent_block ? &parent_block->symt : &func->symt;
286 vector_init(&block->vchildren, sizeof(struct symt*), 4);
287 if (parent_block)
288 p = vector_add(&parent_block->vchildren, &module->pool);
289 else
290 p = vector_add(&func->vchildren, &module->pool);
291 *p = &block->symt;
293 return block;
296 struct symt_block* symt_close_func_block(struct module* module,
297 struct symt_function* func,
298 struct symt_block* block, unsigned pc)
300 assert(func->symt.tag == SymTagFunction);
302 block->size = func->addr + pc - block->address;
303 return (block->container->tag == SymTagBlock) ?
304 GET_ENTRY(block->container, struct symt_block, symt) : NULL;
307 BOOL symt_normalize_function(struct module* module, struct symt_function* func)
309 unsigned len;
310 struct line_info* dli;
312 if (!func) return TRUE;
313 /* We aren't adding any more locals or line numbers to this function.
314 * Free any spare memory that we might have allocated.
316 assert(func->symt.tag == SymTagFunction);
318 /* EPP vector_pool_normalize(&func->vlines, &module->pool); */
319 /* EPP vector_pool_normalize(&func->vchildren, &module->pool); */
321 len = vector_length(&func->vlines);
322 if (len--)
324 dli = vector_at(&func->vlines, 0); dli->cookie |= DLIT_FIRST;
325 dli = vector_at(&func->vlines, len); dli->cookie |= DLIT_LAST;
327 return TRUE;
330 /* expect sym_info->MaxNameLen to be set before being called */
331 static void symt_fill_sym_info(const struct module* module,
332 const struct symt* sym, SYMBOL_INFO* sym_info)
334 const char* name;
336 sym_info->TypeIndex = (DWORD)sym;
337 sym_info->info = 0; /* TBD */
338 symt_get_info(sym, TI_GET_LENGTH, &sym_info->Size);
339 sym_info->ModBase = module->module.BaseOfImage;
340 sym_info->Flags = 0;
341 switch (sym->tag)
343 case SymTagData:
345 struct symt_data* data = (struct symt_data*)sym;
346 switch (data->location)
348 case LocIsEnregistered:
349 sym_info->Flags |= SYMFLAG_REGISTER;
350 sym_info->Register = data->u.reg_id;
351 sym_info->Address = 0;
352 break;
353 case LocIsRegRel:
354 sym_info->Flags |=
355 ((data->u.offset < 0) ? SYMFLAG_LOCAL : SYMFLAG_PARAMETER) |
356 SYMFLAG_FRAMEREL;
357 sym_info->Register = data->u.reg_id;
358 sym_info->Address = data->u.offset;
359 break;
360 case LocIsStatic:
361 symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
362 sym_info->Register = 0;
363 break;
364 case LocIsConstant:
365 sym_info->Flags |= SYMFLAG_VALUEPRESENT;
366 sym_info->Value = data->u.value;
367 break;
368 default:
369 FIXME("Unhandled loc (%u) in sym data\n", data->location);
372 break;
373 case SymTagPublicSymbol:
374 sym_info->Flags |= SYMFLAG_EXPORT;
375 symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
376 break;
377 case SymTagFunction:
378 sym_info->Flags |= SYMFLAG_FUNCTION;
379 symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
380 break;
381 default:
382 symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
383 sym_info->Register = 0;
384 break;
386 sym_info->Scope = 0; /* FIXME */
387 sym_info->Tag = sym->tag;
388 name = symt_get_name(sym);
389 sym_info->NameLen = strlen(name) + 1;
390 if (sym_info->MaxNameLen)
392 strncpy(sym_info->Name, name, min(sym_info->NameLen, sym_info->MaxNameLen));
393 sym_info->Name[sym_info->MaxNameLen - 1] = '\0';
395 TRACE_(dbghelp_symtype)("%p => %s %lu %lx\n",
396 sym, sym_info->Name, sym_info->Size, sym_info->Address);
399 static BOOL symt_enum_module(struct module* module, const char* mask,
400 PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
402 char buffer[sizeof(SYMBOL_INFO) + 256];
403 SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
404 void* ptr;
405 struct symt_ht* sym = NULL;
406 struct hash_table_iter hti;
407 regex_t preg;
409 assert(mask);
410 assert(mask[0] != '!');
411 regcomp(&preg, mask, REG_NOSUB);
412 hash_table_iter_init(&module->ht_symbols, &hti, NULL);
413 while ((ptr = hash_table_iter_up(&hti)))
415 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
416 /* FIXME: this is not true, we should only drop the public
417 * symbol iff no other one is found
419 if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
420 sym->symt.tag == SymTagPublicSymbol) continue;
422 if (sym->hash_elt.name &&
423 regexec(&preg, sym->hash_elt.name, 0, NULL, 0) == 0)
425 sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
426 sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
427 symt_fill_sym_info(module, &sym->symt, sym_info);
428 if (!cb(sym_info, sym_info->Size, user)) break;
431 regfree(&preg);
432 return sym ? FALSE : TRUE;
435 /***********************************************************************
436 * resort_symbols
438 * Rebuild sorted list of symbols for a module.
440 static BOOL resort_symbols(struct module* module)
442 int nsym = 0;
443 void* ptr;
444 struct symt_ht* sym;
445 struct hash_table_iter hti;
447 hash_table_iter_init(&module->ht_symbols, &hti, NULL);
448 while ((ptr = hash_table_iter_up(&hti)))
449 nsym++;
451 if (!(module->module.NumSyms = nsym)) return FALSE;
453 if (module->addr_sorttab)
454 module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0,
455 module->addr_sorttab,
456 nsym * sizeof(struct symt_ht*));
457 else
458 module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0,
459 nsym * sizeof(struct symt_ht*));
460 if (!module->addr_sorttab) return FALSE;
462 nsym = 0;
463 hash_table_iter_init(&module->ht_symbols, &hti, NULL);
464 while ((ptr = hash_table_iter_up(&hti)))
466 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
467 assert(sym);
468 module->addr_sorttab[nsym++] = sym;
471 qsort(module->addr_sorttab, nsym, sizeof(struct symt_ht*), symt_cmp_addr);
472 return module->sortlist_valid = TRUE;
475 /* assume addr is in module */
476 static int symt_find_nearest(struct module* module, DWORD addr)
478 int mid, high, low;
480 if (!module->sortlist_valid && !resort_symbols(module)) return -1;
483 * Binary search to find closest symbol.
485 low = 0;
486 high = module->module.NumSyms;
488 while (high > low + 1)
490 mid = (high + low) / 2;
491 if (cmp_sorttab_addr(module, mid, addr) < 0)
492 low = mid;
493 else
494 high = mid;
496 if (low != high && high != module->module.NumSyms &&
497 cmp_sorttab_addr(module, high, addr) <= 0)
498 low = high;
500 /* If found symbol is a public symbol, check if there are any other entries that
501 * might also have the same address, but would get better information
503 if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
505 DWORD ref;
507 symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref);
508 if (low > 0 &&
509 module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol &&
510 !cmp_sorttab_addr(module, low - 1, ref))
511 low--;
512 else if (low < module->module.NumSyms - 1 &&
513 module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol &&
514 !cmp_sorttab_addr(module, low + 1, ref))
515 low++;
518 return low;
521 static BOOL symt_enum_locals_helper(struct process* pcs, struct module* module,
522 regex_t* preg, PSYM_ENUMERATESYMBOLS_CALLBACK cb,
523 PVOID user, SYMBOL_INFO* sym_info,
524 struct vector* v)
526 struct symt** plsym = NULL;
527 struct symt* lsym = NULL;
528 DWORD pc = pcs->ctx_frame.InstructionOffset;
530 while ((plsym = vector_iter_up(v, plsym)))
532 lsym = *plsym;
533 switch (lsym->tag)
535 case SymTagBlock:
537 struct symt_block* block = (struct symt_block*)lsym;
538 if (pc < block->address || block->address + block->size <= pc)
539 continue;
540 if (!symt_enum_locals_helper(pcs, module, preg, cb, user,
541 sym_info, &block->vchildren))
542 return FALSE;
544 break;
545 case SymTagData:
546 if (regexec(preg, symt_get_name(lsym), 0, NULL, 0) == 0)
548 symt_fill_sym_info(module, lsym, sym_info);
549 if (!cb(sym_info, sym_info->Size, user))
550 return FALSE;
552 break;
553 default:
554 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
555 assert(0);
558 return TRUE;
561 static BOOL symt_enum_locals(struct process* pcs, const char* mask,
562 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
563 PVOID UserContext)
565 struct module* module;
566 struct symt_ht* sym;
567 char buffer[sizeof(SYMBOL_INFO) + 256];
568 SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
569 DWORD pc = pcs->ctx_frame.InstructionOffset;
570 int idx;
572 sym_info->SizeOfStruct = sizeof(*sym_info);
573 sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
575 module = module_find_by_addr(pcs, pc, DMT_UNKNOWN);
576 if (!(module = module_get_debug(pcs, module))) return FALSE;
577 if ((idx = symt_find_nearest(module, pc)) == -1) return FALSE;
579 sym = module->addr_sorttab[idx];
580 if (sym->symt.tag == SymTagFunction)
582 BOOL ret;
583 regex_t preg;
585 regcomp(&preg, mask ? mask : ".*", REG_NOSUB);
586 ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback,
587 UserContext, sym_info,
588 &((struct symt_function*)sym)->vchildren);
589 regfree(&preg);
590 return ret;
593 symt_fill_sym_info(module, &sym->symt, sym_info);
594 return EnumSymbolsCallback(sym_info, sym_info->Size, UserContext);
597 /******************************************************************
598 * SymEnumSymbols (DBGHELP.@)
601 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask,
602 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
603 PVOID UserContext)
605 struct process* pcs = process_find_by_handle(hProcess);
606 struct module* module;
608 TRACE("(%p %08lx %s %p %p)\n",
609 hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
611 if (!pcs) return FALSE;
613 if (BaseOfDll == 0)
615 if (Mask && Mask[0] == '!')
617 if (!Mask[1])
619 /* FIXME: is this really what's intended ??? */
620 for (module = pcs->lmodules; module; module = module->next)
622 if (module->module.SymType != SymNone &&
623 !symt_enum_module(module, ".*", EnumSymbolsCallback, UserContext))
624 break;
626 return TRUE;
628 module = module_find_by_name(pcs, &Mask[1], DMT_UNKNOWN);
629 Mask++;
631 else return symt_enum_locals(pcs, Mask, EnumSymbolsCallback, UserContext);
633 else
635 module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
636 if (Mask && Mask[0] == '!')
638 if (!Mask[1] ||
639 strcmp(&Mask[1], module->module.ModuleName))
641 FIXME("Strange call mode\n");
642 return FALSE;
644 Mask = ".*";
646 else if (!Mask) Mask = ".*";
648 if ((module = module_get_debug(pcs, module)))
649 symt_enum_module(module, Mask, EnumSymbolsCallback, UserContext);
650 return TRUE;
653 struct sym_enumerate
655 void* ctx;
656 PSYM_ENUMSYMBOLS_CALLBACK cb;
659 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
661 struct sym_enumerate* se = (struct sym_enumerate*)ctx;
662 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
665 /***********************************************************************
666 * SymEnumerateSymbols (DBGHELP.@)
668 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
669 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
670 PVOID UserContext)
672 struct sym_enumerate se;
674 se.ctx = UserContext;
675 se.cb = EnumSymbolsCallback;
677 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
680 /******************************************************************
681 * SymFromAddr (DBGHELP.@)
684 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD Address,
685 DWORD* Displacement, PSYMBOL_INFO Symbol)
687 struct process* pcs = process_find_by_handle(hProcess);
688 struct module* module;
689 struct symt_ht* sym;
690 int idx;
692 if (!pcs) return FALSE;
693 module = module_find_by_addr(pcs, Address, DMT_UNKNOWN);
694 if (!(module = module_get_debug(pcs, module))) return FALSE;
695 if ((idx = symt_find_nearest(module, Address)) == -1) return FALSE;
697 sym = module->addr_sorttab[idx];
699 symt_fill_sym_info(module, &sym->symt, Symbol);
700 if (Displacement) *Displacement = Address - Symbol->Address;
701 return TRUE;
704 /******************************************************************
705 * SymGetSymFromAddr (DBGHELP.@)
708 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
709 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
711 char buffer[sizeof(SYMBOL_INFO) + 256];
712 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
713 size_t len;
715 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
716 si->SizeOfStruct = sizeof(*si);
717 si->MaxNameLen = 256;
718 if (!SymFromAddr(hProcess, Address, Displacement, si))
719 return FALSE;
721 Symbol->Address = si->Address;
722 Symbol->Size = si->Size;
723 Symbol->Flags = si->Flags;
724 len = min(Symbol->MaxNameLength, si->MaxNameLen);
725 strncpy(Symbol->Name, si->Name, len);
726 Symbol->Name[len - 1] = '\0';
727 return TRUE;
730 /******************************************************************
731 * SymFromName (DBGHELP.@)
734 BOOL WINAPI SymFromName(HANDLE hProcess, LPSTR Name, PSYMBOL_INFO Symbol)
736 struct process* pcs = process_find_by_handle(hProcess);
737 struct module* module;
738 struct hash_table_iter hti;
739 void* ptr;
740 struct symt_ht* sym = NULL;
742 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
743 if (!pcs) return FALSE;
744 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
745 for (module = pcs->lmodules; module; module = module->next)
747 if (module->module.SymType != SymNone)
749 if (module->module.SymType == SymDeferred)
751 struct module* xmodule = module_get_debug(pcs, module);
752 if (!xmodule) continue;
753 module = xmodule;
755 hash_table_iter_init(&module->ht_symbols, &hti, Name);
756 while ((ptr = hash_table_iter_up(&hti)))
758 sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
760 if (!strcmp(sym->hash_elt.name, Name))
762 symt_fill_sym_info(module, &sym->symt, Symbol);
763 return TRUE;
768 return FALSE;
771 /***********************************************************************
772 * SymGetSymFromName (DBGHELP.@)
774 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, LPSTR Name, PIMAGEHLP_SYMBOL Symbol)
776 char buffer[sizeof(SYMBOL_INFO) + 256];
777 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
778 size_t len;
780 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
781 si->SizeOfStruct = sizeof(*si);
782 si->MaxNameLen = 256;
783 if (!SymFromName(hProcess, Name, si)) return FALSE;
785 Symbol->Address = si->Address;
786 Symbol->Size = si->Size;
787 Symbol->Flags = si->Flags;
788 len = min(Symbol->MaxNameLength, si->MaxNameLen);
789 strncpy(Symbol->Name, si->Name, len);
790 Symbol->Name[len - 1] = '\0';
791 return TRUE;
794 /******************************************************************
795 * fill_line_info
797 * fills information about a file
799 static BOOL fill_line_info(struct module* module, struct symt_function* func,
800 DWORD addr, IMAGEHLP_LINE* line)
802 struct line_info* dli = NULL;
803 BOOL found = FALSE;
805 assert(func->symt.tag == SymTagFunction);
807 while ((dli = vector_iter_down(&func->vlines, dli)))
809 if (!(dli->cookie & DLIT_SOURCEFILE))
811 if (found || dli->u.pc_offset > addr) continue;
812 line->LineNumber = dli->line_number;
813 line->Address = dli->u.pc_offset;
814 line->Key = dli;
815 found = TRUE;
816 continue;
818 if (found)
820 line->FileName = (char*)source_get(module, dli->u.source_file);
821 return TRUE;
824 return FALSE;
827 /***********************************************************************
828 * SymGetSymNext (DBGHELP.@)
830 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
832 /* algo:
833 * get module from Symbol.Address
834 * get index in module.addr_sorttab of Symbol.Address
835 * increment index
836 * if out of module bounds, move to next module in process address space
838 FIXME("(%p, %p): stub\n", hProcess, Symbol);
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840 return FALSE;
843 /***********************************************************************
844 * SymGetSymPrev (DBGHELP.@)
847 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
849 FIXME("(%p, %p): stub\n", hProcess, Symbol);
850 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
851 return FALSE;
854 /******************************************************************
855 * SymGetLineFromAddr (DBGHELP.@)
858 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
859 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
861 struct process* pcs = process_find_by_handle(hProcess);
862 struct module* module;
863 int idx;
865 TRACE("%p %08lx %p %p\n", hProcess, dwAddr, pdwDisplacement, Line);
867 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
869 if (!pcs) return FALSE;
870 module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
871 if (!(module = module_get_debug(pcs, module))) return FALSE;
872 if ((idx = symt_find_nearest(module, dwAddr)) == -1) return FALSE;
874 if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE;
875 if (!fill_line_info(module,
876 (struct symt_function*)module->addr_sorttab[idx],
877 dwAddr, Line)) return FALSE;
878 if (pdwDisplacement) *pdwDisplacement = dwAddr - Line->Address;
879 return TRUE;
882 /******************************************************************
883 * SymGetLinePrev (DBGHELP.@)
886 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
888 struct process* pcs = process_find_by_handle(hProcess);
889 struct module* module;
890 struct line_info* li;
891 BOOL in_search = FALSE;
893 TRACE("(%p %p)\n", hProcess, Line);
895 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
897 if (!pcs) return FALSE;
898 module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
899 if (!(module = module_get_debug(pcs, module))) return FALSE;
901 if (Line->Key == 0) return FALSE;
902 li = (struct line_info*)Line->Key;
903 /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE
904 * element we have to go back until we find the prev one to get the real
905 * source file name for the DLIT_OFFSET element just before
906 * the first DLIT_SOURCEFILE
908 while (!(li->cookie & DLIT_FIRST))
910 li--;
911 if (!(li->cookie & DLIT_SOURCEFILE))
913 Line->LineNumber = li->line_number;
914 Line->Address = li->u.pc_offset;
915 Line->Key = li;
916 if (!in_search) return TRUE;
918 else
920 if (in_search)
922 Line->FileName = (char*)source_get(module, li->u.source_file);
923 return TRUE;
925 in_search = TRUE;
928 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
929 return FALSE;
932 /******************************************************************
933 * SymGetLineNext (DBGHELP.@)
936 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
938 struct process* pcs = process_find_by_handle(hProcess);
939 struct module* module;
940 struct line_info* li;
942 TRACE("(%p %p)\n", hProcess, Line);
944 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
945 if (!pcs) return FALSE;
946 module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
947 if (!(module = module_get_debug(pcs, module))) return FALSE;
949 if (Line->Key == 0) return FALSE;
950 li = (struct line_info*)Line->Key;
951 while (!(li->cookie & DLIT_LAST))
953 li++;
954 if (!(li->cookie & DLIT_SOURCEFILE))
956 Line->LineNumber = li->line_number;
957 Line->Address = li->u.pc_offset;
958 Line->Key = li;
959 return TRUE;
961 Line->FileName = (char*)source_get(module, li->u.source_file);
963 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
964 return FALSE;
967 /***********************************************************************
968 * SymFunctionTableAccess (DBGHELP.@)
970 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
972 FIXME("(%p, 0x%08lx): stub\n", hProcess, AddrBase);
973 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
974 return FALSE;
977 /***********************************************************************
978 * SymUnDName (DBGHELP.@)
980 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, LPSTR UnDecName, DWORD UnDecNameLength)
982 FIXME("(%p %s %lu): stub\n", sym, UnDecName, UnDecNameLength);
983 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
984 UNDNAME_COMPLETE);
987 /***********************************************************************
988 * UnDecorateSymbolName (DBGHELP.@)
990 DWORD WINAPI UnDecorateSymbolName(LPCSTR DecoratedName, LPSTR UnDecoratedName,
991 DWORD UndecoratedLength, DWORD Flags)
993 FIXME("(%s, %p, %ld, 0x%08lx): stub\n",
994 debugstr_a(DecoratedName), UnDecoratedName, UndecoratedLength, Flags);
996 strncpy(UnDecoratedName, DecoratedName, UndecoratedLength);
997 UnDecoratedName[UndecoratedLength - 1] = '\0';
998 return TRUE;