diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index ca90828ad88..3ee317b5522 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -29,22 +29,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); /* TODO * - support for symbols' types is still partly missing - * + debug start/stop in functions - * + parameters in function prototype... * + C++ support + * + funcargtype:s are (partly) wrong: they should be a specific struct (like + * typedef) pointing to the actual type (and not a direct access) + * + we should store the underlying type for an enum in the symt_enum struct * - most options (dbghelp_options) are not used (loading lines, decoration, * deferring reading of module symbols, public symbols...) * - (un)decoration is not handled (should make winedump's code a (.a) library * and link it to winedump, and potentially to msvcrt and dbghelp (check best * way not to duplicate code in msvcrt & dbghelp) * - msc: - * + handle the debug_start & debug_end information block + * + we should add parameters' types to the function's signature + * while processing a function's parameters * + get rid of MSC reading FIXME:s (lots of types are not defined) * + C++ management * - stabs: - * + we should add parameters' types to the function's signature - * while processing a function's parameters - * + should generate the func debug_{start,end} statements (black magic ?) * + should identify the relay code in Wine and mark it as thunk type * + C++ management * - implement the callback notification mechanism diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index ebf59884911..d5f3710ec83 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -26,6 +26,7 @@ #include "winbase.h" #include "winver.h" #include "dbghelp.h" +#include "oaidl.h" #include "cvconst.h" @@ -142,11 +143,7 @@ struct symt_data unsigned position; unsigned length; } bitfield; /* used by BitField */ -#if 1 - unsigned value; /* LocIsConstant */ -#else VARIANT value; /* LocIsConstant */ -#endif } u; }; @@ -159,7 +156,15 @@ struct symt_function struct symt* type; /* points to function_signature */ unsigned long size; struct vector vlines; - struct vector vchildren; /* locals, params, blocks */ + struct vector vchildren; /* locals, params, blocks, start/end, labels */ +}; + +struct symt_function_point +{ + struct symt symt; /* either SymTagFunctionDebugStart, SymTagFunctionDebugEnd, SymTagLabel */ + struct symt_function* parent; + unsigned long offset; + const char* name; /* for labels */ }; struct symt_public @@ -201,6 +206,7 @@ struct symt_function_signature { struct symt symt; struct symt* rettype; + struct vector vchildren; }; struct symt_pointer @@ -367,11 +373,21 @@ extern struct symt_data* extern struct symt_block* symt_open_func_block(struct module* module, struct symt_function* func, - struct symt_block* block, unsigned pc); + struct symt_block* block, + unsigned pc, unsigned len); extern struct symt_block* symt_close_func_block(struct module* module, struct symt_function* func, struct symt_block* block, unsigned pc); +extern struct symt_function_point* + symt_add_function_point(struct module* module, + struct symt_function* func, + enum SymTagEnum point, + unsigned offset, const char* name); +extern BOOL symt_fill_func_line_info(struct module* module, + struct symt_function* func, + DWORD addr, IMAGEHLP_LINE* line); +extern BOOL symt_get_func_line_next(struct module* module, PIMAGEHLP_LINE line); /* type.c */ extern void symt_init_basic(struct module* module); @@ -394,13 +410,19 @@ extern struct symt_enum* symt_new_enum(struct module* module, const char* typename); extern BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type, - const char* name, unsigned value); + const char* name, int value); extern struct symt_array* symt_new_array(struct module* module, int min, int max, struct symt* base); extern struct symt_function_signature* symt_new_function_signature(struct module* module, struct symt* ret_type); +extern BOOL symt_add_function_signature_parameter(struct module* module, + struct symt_function_signature* sig, + struct symt* param); extern struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_type); +extern struct symt_typedef* + symt_new_typedef(struct module* module, struct symt* ref, + const char* name); diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 1f3b394dae2..e1d719e4ce9 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -1068,7 +1068,7 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_SHORT] = &symt_new_basic(module, btInt, "short int", 2)->symt; cv_basic_types[T_LONG] = &symt_new_basic(module, btInt, "long int", 4)->symt; cv_basic_types[T_QUAD] = &symt_new_basic(module, btInt, "long long int", 8)->symt; - cv_basic_types[T_UCHAR] = &symt_new_basic(module, btUInt, "unsignd char", 1)->symt; + cv_basic_types[T_UCHAR] = &symt_new_basic(module, btUInt, "unsigned char", 1)->symt; cv_basic_types[T_USHORT] = &symt_new_basic(module, btUInt, "unsigned short", 2)->symt; cv_basic_types[T_ULONG] = &symt_new_basic(module, btUInt, "unsigned long", 4)->symt; cv_basic_types[T_UQUAD] = &symt_new_basic(module, btUInt, "unsigned long long", 8)->symt; @@ -1937,9 +1937,9 @@ union codeview_symbol struct { - short int len; /* Total length of this entry */ - short int id; /* Always S_BPREL32 */ - unsigned int offset; /* Stack offset relative to BP */ + short int len; /* Total length of this entry */ + short int id; /* Always S_BPREL */ + unsigned int offset; /* Stack offset relative to BP */ unsigned short symtype; unsigned char namelen; unsigned char name[1]; @@ -1947,13 +1947,101 @@ union codeview_symbol struct { - short int len; /* Total length of this entry */ - short int id; /* Always S_BPREL32 */ - unsigned int offset; /* Stack offset relative to BP */ + short int len; /* Total length of this entry */ + short int id; /* Always S_BPREL_32 */ + unsigned int offset; /* Stack offset relative to EBP */ unsigned int symtype; unsigned char namelen; unsigned char name[1]; } stack32; + + struct + { + short int len; /* Total length of this entry */ + short int id; /* Always S_REGISTER */ + unsigned short type; + unsigned short reg; + unsigned char namelen; + unsigned char name[1]; + /* don't handle register tracking */ + } s_register; + + struct + { + short int len; /* Total length of this entry */ + short int id; /* Always S_REGISTER_32 */ + unsigned int type; /* check whether type & reg are correct */ + unsigned int reg; + unsigned char namelen; + unsigned char name[1]; + /* don't handle register tracking */ + } s_register32; + + struct + { + short int len; + short int id; + unsigned int parent; + unsigned int end; + unsigned int length; + unsigned int offset; + unsigned short segment; + unsigned char namelen; + unsigned char name[1]; + } block; + + struct + { + short int len; + short int id; + unsigned int offset; + unsigned short segment; + unsigned char flags; + unsigned char namelen; + unsigned char name[1]; + } label; + + struct + { + short int len; + short int id; + unsigned short type; + unsigned short arrlen; /* numeric leaf */ +#if 0 + unsigned char namelen; + unsigned char name[1]; +#endif + } constant; + + struct + { + short int len; + short int id; + unsigned type; + unsigned short arrlen; /* numeric leaf */ +#if 0 + unsigned char namelen; + unsigned char name[1]; +#endif + } constant32; + + struct + { + short int len; + short int id; + unsigned short type; + unsigned char namelen; + unsigned char name[1]; + } udt; + + struct + { + short int len; + short int id; + unsigned type; + unsigned char namelen; + unsigned char name[1]; + } udt32; }; #define S_COMPILE 0x0001 @@ -1997,7 +2085,6 @@ union codeview_symbol #define S_UDT_32 0x1003 #define S_COBOLUDT_32 0x1004 #define S_MANYREG_32 0x1005 - #define S_BPREL_32 0x1006 #define S_LDATA_32 0x1007 #define S_GDATA_32 0x1008 @@ -2081,6 +2168,8 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root int i, length; char symname[PATH_MAX]; const struct codeview_linetab* flt; + struct symt_block* block = NULL; + struct symt* symt; /* * Loop over the different types of records and whenever we @@ -2102,13 +2191,9 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root memcpy(symname, sym->data.name, sym->data.namelen); symname[sym->data.namelen] = '\0'; flt = codeview_get_linetab(linetab, sym->data.seg, sym->data.offset); - /* global data should be the only one of type global var... - * the other ones sound different - * FIXME - */ symt_new_global_variable(msc_dbg->module, flt ? flt->compiland : NULL, - symname, sym->generic.id == S_GDATA, + symname, sym->generic.id == S_LDATA, codeview_get_address(msc_dbg, sym->data.seg, sym->data.offset), 0, codeview_get_type(sym->data.symtype, FALSE)); @@ -2119,12 +2204,8 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root memcpy(symname, sym->data32.name, sym->data32.namelen); symname[sym->data32.namelen] = '\0'; flt = codeview_get_linetab(linetab, sym->data32.seg, sym->data32.offset); - /* global data should be the only one of type global var... - * the other ones sound different - * FIXME - */ symt_new_global_variable(msc_dbg->module, flt ? flt->compiland : NULL, - symname, sym->generic.id == S_GDATA_32, + symname, sym->generic.id == S_LDATA_32, codeview_get_address(msc_dbg, sym->data32.seg, sym->data32.offset), 0, codeview_get_type(sym->data32.symtype, FALSE)); @@ -2171,8 +2252,6 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root */ case S_GPROC: case S_LPROC: - if (curr_func) symt_normalize_function(msc_dbg->module, curr_func); - memcpy(symname, sym->proc.name, sym->proc.namelen); symname[sym->proc.namelen] = '\0'; flt = codeview_get_linetab(linetab, sym->proc.segment, sym->proc.offset); @@ -2181,15 +2260,13 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root codeview_get_address(msc_dbg, sym->proc.segment, sym->proc.offset), sym->proc.proc_len, codeview_get_type(sym->proc.proctype, FALSE)); - codeview_add_func_linenum(msc_dbg->module, curr_func, flt, sym->proc.offset, sym->proc.proc_len); - /* DEBUG_SetSymbolBPOff(curr_func, sym->proc.debug_start); */ + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, sym->proc.debug_start, NULL); + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, sym->proc.debug_end, NULL); break; case S_GPROC_32: case S_LPROC_32: - if (curr_func) symt_normalize_function(msc_dbg->module, curr_func); - memcpy(symname, sym->proc32.name, sym->proc32.namelen); symname[sym->proc32.namelen] = '\0'; flt = codeview_get_linetab(linetab, sym->proc32.segment, sym->proc32.offset); @@ -2198,10 +2275,10 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root codeview_get_address(msc_dbg, sym->proc32.segment, sym->proc32.offset), sym->proc32.proc_len, codeview_get_type(sym->proc32.proctype, FALSE)); - codeview_add_func_linenum(msc_dbg->module, curr_func, flt, sym->proc32.offset, sym->proc32.proc_len); - /* DEBUG_SetSymbolBPOff(curr_func, sym->proc32.debug_start); */ + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, sym->proc32.debug_start, NULL); + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, sym->proc32.debug_end, NULL); break; /* @@ -2211,17 +2288,116 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root memcpy(symname, sym->stack.name, sym->stack.namelen); symname[sym->stack.namelen] = '\0'; symt_add_func_local(msc_dbg->module, curr_func, 0, sym->stack.offset, - NULL, codeview_get_type(sym->stack.symtype, FALSE), + block, codeview_get_type(sym->stack.symtype, FALSE), symname); break; case S_BPREL_32: memcpy(symname, sym->stack32.name, sym->stack32.namelen); symname[sym->stack32.namelen] = '\0'; symt_add_func_local(msc_dbg->module, curr_func, 0, sym->stack32.offset, - NULL, codeview_get_type(sym->stack32.symtype, FALSE), + block, codeview_get_type(sym->stack32.symtype, FALSE), symname); break; + case S_REGISTER: + memcpy(symname, sym->s_register.name, sym->s_register.namelen); + symname[sym->s_register.namelen] = '\0'; + symt_add_func_local(msc_dbg->module, curr_func, 0, sym->s_register.reg, + block, codeview_get_type(sym->s_register.type, FALSE), + symname); + break; + + case S_REGISTER_32: + memcpy(symname, sym->s_register32.name, sym->s_register32.namelen); + symname[sym->s_register32.namelen] = '\0'; + symt_add_func_local(msc_dbg->module, curr_func, 0, sym->s_register32.reg, + block, codeview_get_type(sym->s_register32.type, FALSE), + symname); + break; + + case S_BLOCK: + block = symt_open_func_block(msc_dbg->module, curr_func, block, + codeview_get_address(msc_dbg, sym->block.segment, sym->block.offset), + sym->block.length); + break; + + case S_END: + if (block) + { + block = symt_close_func_block(msc_dbg->module, curr_func, block, 0); + } + else if (curr_func) + { + symt_normalize_function(msc_dbg->module, curr_func); + curr_func = NULL; + } + break; + + case S_COMPILE: + TRACE("S-Compile %x %.*s\n", ((LPBYTE)sym)[4], ((LPBYTE)sym)[8], (LPBYTE)sym + 9); + break; + + case S_OBJNAME: + TRACE("S-ObjName %.*s\n", ((LPBYTE)sym)[8], (LPBYTE)sym + 9); + break; + + case S_LABEL: + memcpy(symname, sym->label.name, sym->label.namelen); + symname[sym->label.namelen] = '\0'; + if (curr_func) + { + symt_add_function_point(msc_dbg->module, curr_func, SymTagLabel, + codeview_get_address(msc_dbg, sym->label.segment, sym->label.offset) - curr_func->addr, + symname); + } + else FIXME("No current function for label %s\n", symname); + break; + +#if 0 + case S_CONSTANT_32: + { + int val, vlen; + char* ptr; + const char* x; + struct symt* se; + + vlen = numeric_leaf(&val, &sym->constant32.arrlen); + ptr = (char*)&sym->constant32.arrlen + vlen; + se = codeview_get_type(sym->constant32.type, FALSE); + if (!se) x = "---"; + else if (se->tag == SymTagEnum) x = ((struct symt_enum*)se)->name; + else x = "###"; + + FIXME("S-Constant %u %.*s %x (%s)\n", + val, ptr[0], ptr + 1, sym->constant32.type, x); + } + break; +#endif + + case S_UDT: + symt = codeview_get_type(sym->udt.type, FALSE); + if (symt) + { + memcpy(symname, sym->udt.name, sym->udt.namelen); + symname[sym->udt.namelen] = '\0'; + symt_new_typedef(msc_dbg->module, symt, symname); + } + else FIXME("S-Udt %.*s: couldn't find type 0x%x\n", + sym->udt.namelen, sym->udt.name, sym->udt.type); + break; + + case S_UDT_32: + symt = codeview_get_type(sym->udt32.type, FALSE); + if (symt) + { + memcpy(symname, sym->udt32.name, sym->udt32.namelen); + symname[sym->udt32.namelen] = '\0'; + symt_new_typedef(msc_dbg->module, symt, symname); + } + else FIXME("S-Udt %.*s: couldn't find type 0x%x\n", + sym->udt32.namelen, sym->udt32.name, sym->udt32.type); + break; + /* * These are special, in that they are always followed by an * additional length-prefixed string which is *not* included diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index 76c5dda851e..e08a86c1969 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -1112,6 +1112,30 @@ struct symt_public* lookup_public(const struct module* module, return found; } +/****************************************************************** + * stabs_finalize_function + * + * Ends function creation: mainly: + * - cleans up line number information + * - tries to set up a debug-start tag (FIXME: heuristic to be enhanced) + */ +static void stabs_finalize_function(struct module* module, struct symt_function* func) +{ + IMAGEHLP_LINE il; + + if (!func) return; + symt_normalize_function(module, func); + /* To define the debug-start of the function, we use the second line number. + * Not 100% bullet proof, but better than nothing + */ + if (symt_fill_func_line_info(module, func, func->addr, &il) && + symt_get_func_line_next(module, &il)) + { + symt_add_function_point(module, func, SymTagFuncDebugStart, + il.Address - func->addr, NULL); + } +} + SYM_TYPE stabs_parse(struct module* module, const char* addr, unsigned long load_offset, unsigned int staboff, int stablen, unsigned int strtaboff, int strtablen) @@ -1267,7 +1291,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr, break; case N_LBRAC: block = symt_open_func_block(module, curr_func, block, - stab_ptr->n_value); + stab_ptr->n_value, 0); for (j = 0; j < num_pending_vars; j++) { symt_add_func_local(module, curr_func, pending_vars[j].regno, @@ -1284,9 +1308,13 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr, /* These are function parameters. */ if (curr_func != NULL) { + struct symt* param_type = stabs_parse_type(ptr); stab_strcpy(symname, sizeof(symname), ptr); symt_add_func_local(module, curr_func, 0, stab_ptr->n_value, - NULL, stabs_parse_type(ptr), symname); + NULL, param_type, symname); + symt_add_function_signature_parameter(module, + (struct symt_function_signature*)curr_func->type, + param_type); } break; case N_RSYM: @@ -1385,7 +1413,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr, break; case N_FUN: /* First, clean up the previous function we were working on. */ - symt_normalize_function(module, curr_func); + stabs_finalize_function(module, curr_func); /* * For now, just declare the various functions. Later @@ -1402,18 +1430,18 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr, stab_strcpy(symname, sizeof(symname), ptr); if (*symname) { - struct symt_function_signature* func_type; + struct symt_function_signature* func_type; func_type = symt_new_function_signature(module, stabs_parse_type(ptr)); #ifdef __ELF__ if ((public = lookup_public(module, compiland, symname))) - curr_func = symt_new_function(module, compiland, symname, - public->address, public->size, - stabs_parse_type(ptr)); + curr_func = symt_new_function(module, compiland, symname, + public->address, public->size, + &func_type->symt); #else curr_func = symt_new_function(module, compiland, symname, load_offset + stab_ptr->n_value, 0, - stabs_parse_type(ptr)); + &func_type->symt); #endif } else @@ -1431,7 +1459,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr, { /* Nuke old path. */ currpath[0] = '\0'; - symt_normalize_function(module, curr_func); + stabs_finalize_function(module, curr_func); curr_func = NULL; source_idx = -1; incl_stk = -1; @@ -1456,7 +1484,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr, case N_UNDF: strs += strtabinc; strtabinc = stab_ptr->n_value; - symt_normalize_function(module, curr_func); + stabs_finalize_function(module, curr_func); curr_func = NULL; break; case N_OPT: diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 21d562ecb90..4e78a66375a 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -20,6 +20,8 @@ */ +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "config.h" #include #include @@ -77,6 +79,61 @@ int symt_cmp_addr(const void* p1, const void* p2) return cmp_addr(a1, a2); } +static inline void re_append(char** mask, unsigned* len, char ch) +{ + *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len)); + (*mask)[*len - 2] = ch; +} + +/* transforms a dbghelp's regular expression into a POSIX one + * Here are the valid dbghelp reg ex characters: + * * 0 or more characters + * ? a single character + * [] list + * # 0 or more of preceding char + * + 1 or more of preceding char + * escapes \ on #, ?, [, ], *, +. don't work on - + */ +static void compile_regex(const char* str, regex_t* re) +{ + char* mask = HeapAlloc(GetProcessHeap(), 0, 1); + unsigned len = 1; + BOOL in_escape = FALSE; + + re_append(&mask, &len, '^'); + while (*str) + { + /* FIXME: this shouldn't be valid on '-' */ + if (in_escape) + { + re_append(&mask, &len, '\\'); + re_append(&mask, &len, *str); + in_escape = FALSE; + } + else switch (*str) + { + case '\\': in_escape = TRUE; break; + case '*': re_append(&mask, &len, '.'); re_append(&mask, &len, '*'); break; + case '?': re_append(&mask, &len, '.'); break; + case '#': re_append(&mask, &len, '*'); break; + /* escape some valid characters in dbghelp reg exp:s */ + case '$': re_append(&mask, &len, '\\'); re_append(&mask, &len, '$'); break; + /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */ + default: re_append(&mask, &len, *str); break; + } + str++; + } + if (in_escape) + { + re_append(&mask, &len, '\\'); + re_append(&mask, &len, '\\'); + } + re_append(&mask, &len, '$'); + mask[len - 1] = '\0'; + regcomp(re, mask, REG_NOSUB); + HeapFree(GetProcessHeap(), 0, mask); +} + struct symt_compiland* symt_new_compiland(struct module* module, const char* name) { struct symt_compiland* sym; @@ -158,13 +215,15 @@ struct symt_function* symt_new_function(struct module* module, struct symt_compiland* compiland, const char* name, unsigned long addr, unsigned long size, - struct symt* type) + struct symt* sig_type) { struct symt_function* sym; struct symt** p; TRACE_(dbghelp_symtype)("Adding global function %s:%s @%lx-%lx\n", module->module.ModuleName, name, addr, addr + size - 1); + + assert(!sig_type || sig_type->tag == SymTagFunctionType); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagFunction; @@ -173,7 +232,7 @@ struct symt_function* symt_new_function(struct module* module, module->sortlist_valid = FALSE; sym->container = &compiland->symt; sym->addr = addr; - sym->type = type; + sym->type = sig_type; sym->size = size; sym->addr = addr; vector_init(&sym->vlines, sizeof(struct line_info), 64); @@ -244,7 +303,7 @@ struct symt_data* symt_add_func_local(struct module* module, locsym->symt.tag = SymTagData; locsym->hash_elt.name = pool_strdup(&module->pool, name); locsym->hash_elt.next = NULL; - locsym->kind = DataIsLocal; + locsym->kind = (offset < 0) ? DataIsParam : DataIsLocal; locsym->container = &block->symt; locsym->type = type; if (regno) @@ -269,7 +328,7 @@ struct symt_data* symt_add_func_local(struct module* module, struct symt_block* symt_open_func_block(struct module* module, struct symt_function* func, struct symt_block* parent_block, - unsigned pc) + unsigned pc, unsigned len) { struct symt_block* block; struct symt** p; @@ -279,9 +338,9 @@ struct symt_block* symt_open_func_block(struct module* module, assert(!parent_block || parent_block->symt.tag == SymTagBlock); block = pool_alloc(&module->pool, sizeof(*block)); - block->symt.tag = SymTagBlock; - block->address = func->addr + pc; - block->size = 0; + block->symt.tag = SymTagBlock; + block->address = func->addr + pc; + block->size = len; block->container = parent_block ? &parent_block->symt : &func->symt; vector_init(&block->vchildren, sizeof(struct symt*), 4); if (parent_block) @@ -299,17 +358,37 @@ struct symt_block* symt_close_func_block(struct module* module, { assert(func->symt.tag == SymTagFunction); - block->size = func->addr + pc - block->address; + if (pc) block->size = func->addr + pc - block->address; return (block->container->tag == SymTagBlock) ? GET_ENTRY(block->container, struct symt_block, symt) : NULL; } +struct symt_function_point* symt_add_function_point(struct module* module, + struct symt_function* func, + enum SymTagEnum point, + unsigned offset, const char* name) +{ + struct symt_function_point* sym; + struct symt** p; + + if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) + { + sym->symt.tag = point; + sym->parent = func; + sym->offset = offset; + sym->name = name ? pool_strdup(&module->pool, name) : NULL; + p = vector_add(&func->vchildren, &module->pool); + *p = &sym->symt; + } + return sym; +} + BOOL symt_normalize_function(struct module* module, struct symt_function* func) { unsigned len; struct line_info* dli; - if (!func) return TRUE; + assert(func); /* We aren't adding any more locals or line numbers to this function. * Free any spare memory that we might have allocated. */ @@ -363,7 +442,17 @@ static void symt_fill_sym_info(const struct module* module, break; case LocIsConstant: sym_info->Flags |= SYMFLAG_VALUEPRESENT; - sym_info->Value = data->u.value; + switch (data->u.value.n1.n2.vt) + { + case VT_I4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.lVal; break; + case VT_I2: sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.iVal; break; + case VT_I1: sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.cVal; break; + case VT_UI4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.ulVal; break; + case VT_UI2: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.uiVal; break; + case VT_UI1: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.bVal; break; + default: + FIXME("Unsupported variant type (%u)\n", data->u.value.n1.n2.vt); + } break; default: FIXME("Unhandled loc (%u) in sym data\n", data->location); @@ -408,7 +497,7 @@ static BOOL symt_enum_module(struct module* module, const char* mask, assert(mask); assert(mask[0] != '!'); - regcomp(&preg, mask, REG_NOSUB); + compile_regex(mask, &preg); hash_table_iter_init(&module->ht_symbols, &hti, NULL); while ((ptr = hash_table_iter_up(&hti))) { @@ -550,6 +639,10 @@ static BOOL symt_enum_locals_helper(struct process* pcs, struct module* module, return FALSE; } break; + case SymTagLabel: + case SymTagFuncDebugStart: + case SymTagFuncDebugEnd: + break; default: FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag); assert(0); @@ -582,7 +675,7 @@ static BOOL symt_enum_locals(struct process* pcs, const char* mask, BOOL ret; regex_t preg; - regcomp(&preg, mask ? mask : ".*", REG_NOSUB); + compile_regex(mask ? mask : "*", &preg); ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback, UserContext, sym_info, &((struct symt_function*)sym)->vchildren); @@ -620,7 +713,7 @@ BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask, for (module = pcs->lmodules; module; module = module->next) { if (module->module.SymType != SymNone && - !symt_enum_module(module, ".*", EnumSymbolsCallback, UserContext)) + !symt_enum_module(module, "*", EnumSymbolsCallback, UserContext)) break; } return TRUE; @@ -641,9 +734,9 @@ BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask, FIXME("Strange call mode\n"); return FALSE; } - Mask = ".*"; + Mask = "*"; } - else if (!Mask) Mask = ".*"; + else if (!Mask) Mask = "*"; } if ((module = module_get_debug(pcs, module))) symt_enum_module(module, Mask, EnumSymbolsCallback, UserContext); @@ -792,12 +885,12 @@ BOOL WINAPI SymGetSymFromName(HANDLE hProcess, LPSTR Name, PIMAGEHLP_SYMBOL Symb } /****************************************************************** - * fill_line_info + * sym_fill_func_line_info * * fills information about a file */ -static BOOL fill_line_info(struct module* module, struct symt_function* func, - DWORD addr, IMAGEHLP_LINE* line) +BOOL symt_fill_func_line_info(struct module* module, struct symt_function* func, + DWORD addr, IMAGEHLP_LINE* line) { struct line_info* dli = NULL; BOOL found = FALSE; @@ -872,9 +965,9 @@ BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, if ((idx = symt_find_nearest(module, dwAddr)) == -1) return FALSE; if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE; - if (!fill_line_info(module, - (struct symt_function*)module->addr_sorttab[idx], - dwAddr, Line)) return FALSE; + if (!symt_fill_func_line_info(module, + (struct symt_function*)module->addr_sorttab[idx], + dwAddr, Line)) return FALSE; if (pdwDisplacement) *pdwDisplacement = dwAddr - Line->Address; return TRUE; } @@ -929,6 +1022,27 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) return FALSE; } +BOOL symt_get_func_line_next(struct module* module, PIMAGEHLP_LINE line) +{ + struct line_info* li; + + if (line->Key == 0) return FALSE; + li = (struct line_info*)line->Key; + while (!(li->cookie & DLIT_LAST)) + { + li++; + if (!(li->cookie & DLIT_SOURCEFILE)) + { + line->LineNumber = li->line_number; + line->Address = li->u.pc_offset; + line->Key = li; + return TRUE; + } + line->FileName = (char*)source_get(module, li->u.source_file); + } + return FALSE; +} + /****************************************************************** * SymGetLineNext (DBGHELP.@) * @@ -937,7 +1051,6 @@ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) { struct process* pcs = process_find_by_handle(hProcess); struct module* module; - struct line_info* li; TRACE("(%p %p)\n", hProcess, Line); @@ -946,20 +1059,7 @@ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN); if (!(module = module_get_debug(pcs, module))) return FALSE; - if (Line->Key == 0) return FALSE; - li = (struct line_info*)Line->Key; - while (!(li->cookie & DLIT_LAST)) - { - li++; - if (!(li->cookie & DLIT_SOURCEFILE)) - { - Line->LineNumber = li->line_number; - Line->Address = li->u.pc_offset; - Line->Key = li; - return TRUE; - } - Line->FileName = (char*)source_get(module, li->u.source_file); - } + if (symt_get_func_line_next(module, Line)) return TRUE; SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ return FALSE; } diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index 79e444ec7d4..8089dbc993b 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -84,6 +84,7 @@ const char* symt_get_name(const struct symt* sym) case SymTagFunction: return ((struct symt_function*)sym)->hash_elt.name; case SymTagPublicSymbol: return ((struct symt_public*)sym)->hash_elt.name; case SymTagBaseType: return ((struct symt_basic*)sym)->hash_elt.name; + case SymTagLabel: return ((struct symt_function_point*)sym)->name; /* hierarchy tree */ case SymTagEnum: return ((struct symt_enum*)sym)->name; case SymTagTypedef: return ((struct symt_typedef*)sym)->hash_elt.name; @@ -252,7 +253,7 @@ struct symt_enum* symt_new_enum(struct module* module, const char* typename) } BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type, - const char* name, unsigned value) + const char* name, int value) { struct symt_data* e; struct symt** p; @@ -269,7 +270,8 @@ BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type, /* CV defines the underlying type for the enumeration */ e->type = &symt_new_basic(module, btInt, "int", 4)->symt; e->location = LocIsConstant; - e->u.value = value; /* FIXME: use variant */ + e->u.value.n1.n2.vt = VT_I4; + e->u.value.n1.n2.n3.lVal = value; p = vector_add(&enum_type->vchildren, &module->pool); if (!p) return FALSE; /* FIXME we leak e */ @@ -296,16 +298,31 @@ struct symt_array* symt_new_array(struct module* module, int min, int max, struct symt_function_signature* symt_new_function_signature(struct module* module, struct symt* ret_type) { - struct symt_function_signature* sym; + struct symt_function_signature* sym; if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagFunctionType; sym->rettype = ret_type; + vector_init(&sym->vchildren, sizeof(struct symt*), 4); } return sym; } +BOOL symt_add_function_signature_parameter(struct module* module, + struct symt_function_signature* sig_type, + struct symt* param) +{ + struct symt** p; + + assert(sig_type->symt.tag == SymTagFunctionType); + p = vector_add(&sig_type->vchildren, &module->pool); + if (!p) return FALSE; /* FIXME we leak e */ + *p = param; + + return TRUE; +} + struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_type) { struct symt_pointer* sym; @@ -318,6 +335,21 @@ struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_ty return sym; } +struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, + const char* name) +{ + struct symt_typedef* sym; + + if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) + { + sym->symt.tag = SymTagTypedef; + sym->type = ref; + sym->hash_elt.name = pool_strdup(&module->pool, name); + hash_table_add(&module->ht_types, &sym->hash_elt); + } + return sym; +} + /****************************************************************** * SymEnumTypes (DBGHELP.@) * @@ -395,10 +427,13 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { - case SymTagUDT: v = &((struct symt_udt*)type)->vchildren; break; - case SymTagEnum: v = &((struct symt_enum*)type)->vchildren; break; + case SymTagUDT: v = &((struct symt_udt*)type)->vchildren; break; + case SymTagEnum: v = &((struct symt_enum*)type)->vchildren; break; + case SymTagFunctionType: v = &((struct symt_function_signature*)type)->vchildren; break; + case SymTagFunction: v = &((struct symt_function*)type)->vchildren; break; default: - FIXME("Unsupported sym-tag %s for find-children\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for find-children\n", + symt_get_tag_str(type->tag)); return FALSE; } for (i = 0; i < tifp->Count; i++) @@ -428,25 +463,31 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, case SymTagPublicSymbol: X(DWORD) = ((struct symt_public*)type)->address; break; + case SymTagFuncDebugStart: + case SymTagFuncDebugEnd: + case SymTagLabel: + X(DWORD) = ((struct symt_function_point*)type)->parent->addr + + ((struct symt_function_point*)type)->offset; + break; default: - FIXME("Unsupported sym-tag %s for get-address\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for get-address\n", + symt_get_tag_str(type->tag)); return FALSE; } break; -#if 0 - /* this is wrong, we should return the type of the index, not the - * type of the array[0] - */ - case TI_GET_ARRAYINDEXTYPEID: - if (type->tag != SymTagArrayType) return FALSE; - X(DWORD) = (DWORD)((struct symt_array*)type)->basetype; - break; -#endif - case TI_GET_BASETYPE: - if (type->tag != SymTagBaseType) return FALSE; - X(DWORD) = ((struct symt_basic*)type)->bt; + switch (type->tag) + { + case SymTagBaseType: + X(DWORD) = ((struct symt_basic*)type)->bt; + break; + case SymTagEnum: + X(DWORD) = btInt; + break; + default: + return FALSE; + } break; case TI_GET_BITPOSITION: @@ -464,17 +505,32 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, case SymTagEnum: X(DWORD) = vector_length(&((struct symt_enum*)type)->vchildren); break; + case SymTagFunctionType: + X(DWORD) = vector_length(&((struct symt_function_signature*)type)->vchildren); + break; + case SymTagFunction: + X(DWORD) = vector_length(&((struct symt_function*)type)->vchildren); + break; + case SymTagPointerType: /* MS does it that way */ + case SymTagArrayType: /* MS does it that way */ + X(DWORD) = 0; + break; default: - FIXME("Unsupported sym-tag %s for get-children-count\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for get-children-count\n", + symt_get_tag_str(type->tag)); /* fall through */ + case SymTagData: case SymTagPublicSymbol: - case SymTagPointerType: case SymTagBaseType: return FALSE; } break; case TI_GET_COUNT: + /* it seems that FunctionType also react to GET_COUNT (same value as + * GET_CHILDREN_COUNT ?, except for C++ methods, where it seems to + * also include 'this' (GET_CHILDREN_COUNT+1) + */ if (type->tag != SymTagArrayType) return FALSE; X(DWORD) = ((struct symt_array*)type)->end - ((struct symt_array*)type)->start; @@ -501,14 +557,13 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, X(DWORD) = ((struct symt_udt*)type)->size; break; case SymTagEnum: - X(DWORD) = sizeof(int); + X(DWORD) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */ break; case SymTagData: if (((struct symt_data*)type)->location == LocIsBitField) X(DWORD) = ((struct symt_data*)type)->u.bitfield.length; else - return symt_get_info(((struct symt_data*)type)->type, - TI_GET_LENGTH, pInfo); + return FALSE; break; case SymTagArrayType: if (!symt_get_info(((struct symt_array*)type)->basetype, @@ -520,8 +575,12 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, case SymTagPublicSymbol: X(DWORD) = ((struct symt_public*)type)->size; break; + case SymTagTypedef: + return symt_get_info(((struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); + break; default: - FIXME("Unsupported sym-tag %s for get-size\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for get-length\n", + symt_get_tag_str(type->tag)); return 0; } break; @@ -536,7 +595,20 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, X(DWORD) = (DWORD)((struct symt_data*)type)->container; break; default: - FIXME("Unsupported sym-tag %s for get-lexical-parent\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for get-lexical-parent\n", + symt_get_tag_str(type->tag)); + return FALSE; + } + break; + + case TI_GET_NESTED: + switch (type->tag) + { + case SymTagUDT: + case SymTagEnum: + X(DWORD) = 0; + break; + default: return FALSE; } break; @@ -545,23 +617,22 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { case SymTagData: - switch (((struct symt_data*)type)->location) + switch (((struct symt_data*)type)->kind) { - case LocIsRegRel: - case LocIsThisRel: + case DataIsParam: + case DataIsLocal: + case DataIsMember: X(ULONG) = ((struct symt_data*)type)->u.offset; break; - case LocIsConstant: - X(ULONG) = 0; /* FIXME ???? */ - break; default: - FIXME("Unknown location (%u) for get-offset\n", - ((struct symt_data*)type)->location); - break; + FIXME("Unknown kind (%u) for get-offset\n", + ((struct symt_data*)type)->kind); + return FALSE; } break; default: - FIXME("Unsupported sym-tag %s for get-offset\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for get-offset\n", + symt_get_tag_str(type->tag)); return FALSE; } break; @@ -582,8 +653,10 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, break; case TI_GET_TYPE: + case TI_GET_TYPEID: switch (type->tag) { + /* hierarchical => hierarchical */ case SymTagArrayType: X(DWORD) = (DWORD)((struct symt_array*)type)->basetype; break; @@ -593,34 +666,43 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, case SymTagFunctionType: X(DWORD) = (DWORD)((struct symt_function_signature*)type)->rettype; break; + case SymTagTypedef: + X(DWORD) = (DWORD)((struct symt_typedef*)type)->type; + break; + /* lexical => hierarchical */ case SymTagData: X(DWORD) = (DWORD)((struct symt_data*)type)->type; break; + case SymTagFunction: + X(DWORD) = (DWORD)((struct symt_function*)type)->type; + break; + /* FIXME: should also work for enums and FunctionArgType */ default: - FIXME("Unsupported sym-tag %s for get-type\n", symt_get_tag_str(type->tag)); + FIXME("Unsupported sym-tag %s for get-type\n", + symt_get_tag_str(type->tag)); return FALSE; } break; - case TI_GET_TYPEID: - X(DWORD) = (DWORD)type; - break; - case TI_GET_UDTKIND: if (type->tag != SymTagUDT) return FALSE; X(DWORD) = ((struct symt_udt*)type)->kind; break; + case TI_GET_VALUE: + if (type->tag != SymTagData || ((struct symt_data*)type)->kind != DataIsConstant) + return FALSE; + X(VARIANT) = ((struct symt_data*)type)->u.value; + break; + #undef X case TI_GET_ADDRESSOFFSET: case TI_GET_ARRAYINDEXTYPEID: case TI_GET_CALLING_CONVENTION: case TI_GET_CLASSPARENTID: - case TI_GET_NESTED: case TI_GET_SYMINDEX: case TI_GET_THISADJUST: - case TI_GET_VALUE: case TI_GET_VIRTUALBASECLASS: case TI_GET_VIRTUALBASEPOINTEROFFSET: case TI_GET_VIRTUALTABLESHAPEID: