- implemented support for function debug start/stop and labels (msc.c

and stabs.c)
- started implementing typedef support
- functions now have a real function signature (only in stabs.c, still
  to be done in msc.c)
- small enhancements to TI_GET_TYPE for functions
- added support for functions' block and local variables in registers
  (msc.c)
- fixed some bugs in StackWalk
- constants are now stored as variants (instead of unsigned ints)
- fixed regular expression management (dbghelp's RE are not the same
  as POSIX ones)
This commit is contained in:
Eric Pouech 2004-04-19 02:58:27 +00:00 committed by Alexandre Julliard
parent 9509912e41
commit eb80f29350
6 changed files with 537 additions and 130 deletions

View File

@ -29,22 +29,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/* TODO /* TODO
* - support for symbols' types is still partly missing * - support for symbols' types is still partly missing
* + debug start/stop in functions
* + parameters in function prototype...
* + C++ support * + 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, * - most options (dbghelp_options) are not used (loading lines, decoration,
* deferring reading of module symbols, public symbols...) * deferring reading of module symbols, public symbols...)
* - (un)decoration is not handled (should make winedump's code a (.a) library * - (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 * and link it to winedump, and potentially to msvcrt and dbghelp (check best
* way not to duplicate code in msvcrt & dbghelp) * way not to duplicate code in msvcrt & dbghelp)
* - msc: * - 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) * + get rid of MSC reading FIXME:s (lots of types are not defined)
* + C++ management * + C++ management
* - stabs: * - 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 * + should identify the relay code in Wine and mark it as thunk type
* + C++ management * + C++ management
* - implement the callback notification mechanism * - implement the callback notification mechanism

View File

@ -26,6 +26,7 @@
#include "winbase.h" #include "winbase.h"
#include "winver.h" #include "winver.h"
#include "dbghelp.h" #include "dbghelp.h"
#include "oaidl.h"
#include "cvconst.h" #include "cvconst.h"
@ -142,11 +143,7 @@ struct symt_data
unsigned position; unsigned position;
unsigned length; unsigned length;
} bitfield; /* used by BitField */ } bitfield; /* used by BitField */
#if 1
unsigned value; /* LocIsConstant */
#else
VARIANT value; /* LocIsConstant */ VARIANT value; /* LocIsConstant */
#endif
} u; } u;
}; };
@ -159,7 +156,15 @@ struct symt_function
struct symt* type; /* points to function_signature */ struct symt* type; /* points to function_signature */
unsigned long size; unsigned long size;
struct vector vlines; 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 struct symt_public
@ -201,6 +206,7 @@ struct symt_function_signature
{ {
struct symt symt; struct symt symt;
struct symt* rettype; struct symt* rettype;
struct vector vchildren;
}; };
struct symt_pointer struct symt_pointer
@ -367,11 +373,21 @@ extern struct symt_data*
extern struct symt_block* extern struct symt_block*
symt_open_func_block(struct module* module, symt_open_func_block(struct module* module,
struct symt_function* func, struct symt_function* func,
struct symt_block* block, unsigned pc); struct symt_block* block,
unsigned pc, unsigned len);
extern struct symt_block* extern struct symt_block*
symt_close_func_block(struct module* module, symt_close_func_block(struct module* module,
struct symt_function* func, struct symt_function* func,
struct symt_block* block, unsigned pc); 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 */ /* type.c */
extern void symt_init_basic(struct module* module); 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); symt_new_enum(struct module* module, const char* typename);
extern BOOL symt_add_enum_element(struct module* module, extern BOOL symt_add_enum_element(struct module* module,
struct symt_enum* enum_type, struct symt_enum* enum_type,
const char* name, unsigned value); const char* name, int value);
extern struct symt_array* extern struct symt_array*
symt_new_array(struct module* module, int min, int max, symt_new_array(struct module* module, int min, int max,
struct symt* base); struct symt* base);
extern struct symt_function_signature* extern struct symt_function_signature*
symt_new_function_signature(struct module* module, symt_new_function_signature(struct module* module,
struct symt* ret_type); 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* extern struct symt_pointer*
symt_new_pointer(struct module* module, symt_new_pointer(struct module* module,
struct symt* ref_type); struct symt* ref_type);
extern struct symt_typedef*
symt_new_typedef(struct module* module, struct symt* ref,
const char* name);

View File

@ -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_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_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_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_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_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; cv_basic_types[T_UQUAD] = &symt_new_basic(module, btUInt, "unsigned long long", 8)->symt;
@ -1937,9 +1937,9 @@ union codeview_symbol
struct struct
{ {
short int len; /* Total length of this entry */ short int len; /* Total length of this entry */
short int id; /* Always S_BPREL32 */ short int id; /* Always S_BPREL */
unsigned int offset; /* Stack offset relative to BP */ unsigned int offset; /* Stack offset relative to BP */
unsigned short symtype; unsigned short symtype;
unsigned char namelen; unsigned char namelen;
unsigned char name[1]; unsigned char name[1];
@ -1947,13 +1947,101 @@ union codeview_symbol
struct struct
{ {
short int len; /* Total length of this entry */ short int len; /* Total length of this entry */
short int id; /* Always S_BPREL32 */ short int id; /* Always S_BPREL_32 */
unsigned int offset; /* Stack offset relative to BP */ unsigned int offset; /* Stack offset relative to EBP */
unsigned int symtype; unsigned int symtype;
unsigned char namelen; unsigned char namelen;
unsigned char name[1]; unsigned char name[1];
} stack32; } 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 #define S_COMPILE 0x0001
@ -1997,7 +2085,6 @@ union codeview_symbol
#define S_UDT_32 0x1003 #define S_UDT_32 0x1003
#define S_COBOLUDT_32 0x1004 #define S_COBOLUDT_32 0x1004
#define S_MANYREG_32 0x1005 #define S_MANYREG_32 0x1005
#define S_BPREL_32 0x1006 #define S_BPREL_32 0x1006
#define S_LDATA_32 0x1007 #define S_LDATA_32 0x1007
#define S_GDATA_32 0x1008 #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; int i, length;
char symname[PATH_MAX]; char symname[PATH_MAX];
const struct codeview_linetab* flt; const struct codeview_linetab* flt;
struct symt_block* block = NULL;
struct symt* symt;
/* /*
* Loop over the different types of records and whenever we * 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); memcpy(symname, sym->data.name, sym->data.namelen);
symname[sym->data.namelen] = '\0'; symname[sym->data.namelen] = '\0';
flt = codeview_get_linetab(linetab, sym->data.seg, sym->data.offset); 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, symt_new_global_variable(msc_dbg->module,
flt ? flt->compiland : NULL, 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), codeview_get_address(msc_dbg, sym->data.seg, sym->data.offset),
0, 0,
codeview_get_type(sym->data.symtype, FALSE)); 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); memcpy(symname, sym->data32.name, sym->data32.namelen);
symname[sym->data32.namelen] = '\0'; symname[sym->data32.namelen] = '\0';
flt = codeview_get_linetab(linetab, sym->data32.seg, sym->data32.offset); 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, 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), codeview_get_address(msc_dbg, sym->data32.seg, sym->data32.offset),
0, 0,
codeview_get_type(sym->data32.symtype, FALSE)); 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_GPROC:
case S_LPROC: case S_LPROC:
if (curr_func) symt_normalize_function(msc_dbg->module, curr_func);
memcpy(symname, sym->proc.name, sym->proc.namelen); memcpy(symname, sym->proc.name, sym->proc.namelen);
symname[sym->proc.namelen] = '\0'; symname[sym->proc.namelen] = '\0';
flt = codeview_get_linetab(linetab, sym->proc.segment, sym->proc.offset); 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), codeview_get_address(msc_dbg, sym->proc.segment, sym->proc.offset),
sym->proc.proc_len, sym->proc.proc_len,
codeview_get_type(sym->proc.proctype, FALSE)); codeview_get_type(sym->proc.proctype, FALSE));
codeview_add_func_linenum(msc_dbg->module, curr_func, flt, codeview_add_func_linenum(msc_dbg->module, curr_func, flt,
sym->proc.offset, sym->proc.proc_len); 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; break;
case S_GPROC_32: case S_GPROC_32:
case S_LPROC_32: case S_LPROC_32:
if (curr_func) symt_normalize_function(msc_dbg->module, curr_func);
memcpy(symname, sym->proc32.name, sym->proc32.namelen); memcpy(symname, sym->proc32.name, sym->proc32.namelen);
symname[sym->proc32.namelen] = '\0'; symname[sym->proc32.namelen] = '\0';
flt = codeview_get_linetab(linetab, sym->proc32.segment, sym->proc32.offset); 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), codeview_get_address(msc_dbg, sym->proc32.segment, sym->proc32.offset),
sym->proc32.proc_len, sym->proc32.proc_len,
codeview_get_type(sym->proc32.proctype, FALSE)); codeview_get_type(sym->proc32.proctype, FALSE));
codeview_add_func_linenum(msc_dbg->module, curr_func, flt, codeview_add_func_linenum(msc_dbg->module, curr_func, flt,
sym->proc32.offset, sym->proc32.proc_len); 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; 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); memcpy(symname, sym->stack.name, sym->stack.namelen);
symname[sym->stack.namelen] = '\0'; symname[sym->stack.namelen] = '\0';
symt_add_func_local(msc_dbg->module, curr_func, 0, sym->stack.offset, 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); symname);
break; break;
case S_BPREL_32: case S_BPREL_32:
memcpy(symname, sym->stack32.name, sym->stack32.namelen); memcpy(symname, sym->stack32.name, sym->stack32.namelen);
symname[sym->stack32.namelen] = '\0'; symname[sym->stack32.namelen] = '\0';
symt_add_func_local(msc_dbg->module, curr_func, 0, sym->stack32.offset, 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); symname);
break; 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 * These are special, in that they are always followed by an
* additional length-prefixed string which is *not* included * additional length-prefixed string which is *not* included

View File

@ -1112,6 +1112,30 @@ struct symt_public* lookup_public(const struct module* module,
return found; 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, SYM_TYPE stabs_parse(struct module* module, const char* addr,
unsigned long load_offset, unsigned int staboff, int stablen, unsigned long load_offset, unsigned int staboff, int stablen,
unsigned int strtaboff, int strtablen) unsigned int strtaboff, int strtablen)
@ -1267,7 +1291,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr,
break; break;
case N_LBRAC: case N_LBRAC:
block = symt_open_func_block(module, curr_func, block, 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++) for (j = 0; j < num_pending_vars; j++)
{ {
symt_add_func_local(module, curr_func, pending_vars[j].regno, 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. */ /* These are function parameters. */
if (curr_func != NULL) if (curr_func != NULL)
{ {
struct symt* param_type = stabs_parse_type(ptr);
stab_strcpy(symname, sizeof(symname), ptr); stab_strcpy(symname, sizeof(symname), ptr);
symt_add_func_local(module, curr_func, 0, stab_ptr->n_value, 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; break;
case N_RSYM: case N_RSYM:
@ -1385,7 +1413,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr,
break; break;
case N_FUN: case N_FUN:
/* First, clean up the previous function we were working on. */ /* 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 * 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); stab_strcpy(symname, sizeof(symname), ptr);
if (*symname) if (*symname)
{ {
struct symt_function_signature* func_type; struct symt_function_signature* func_type;
func_type = symt_new_function_signature(module, func_type = symt_new_function_signature(module,
stabs_parse_type(ptr)); stabs_parse_type(ptr));
#ifdef __ELF__ #ifdef __ELF__
if ((public = lookup_public(module, compiland, symname))) if ((public = lookup_public(module, compiland, symname)))
curr_func = symt_new_function(module, compiland, symname, curr_func = symt_new_function(module, compiland, symname,
public->address, public->size, public->address, public->size,
stabs_parse_type(ptr)); &func_type->symt);
#else #else
curr_func = symt_new_function(module, compiland, symname, curr_func = symt_new_function(module, compiland, symname,
load_offset + stab_ptr->n_value, 0, load_offset + stab_ptr->n_value, 0,
stabs_parse_type(ptr)); &func_type->symt);
#endif #endif
} }
else else
@ -1431,7 +1459,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr,
{ {
/* Nuke old path. */ /* Nuke old path. */
currpath[0] = '\0'; currpath[0] = '\0';
symt_normalize_function(module, curr_func); stabs_finalize_function(module, curr_func);
curr_func = NULL; curr_func = NULL;
source_idx = -1; source_idx = -1;
incl_stk = -1; incl_stk = -1;
@ -1456,7 +1484,7 @@ SYM_TYPE stabs_parse(struct module* module, const char* addr,
case N_UNDF: case N_UNDF:
strs += strtabinc; strs += strtabinc;
strtabinc = stab_ptr->n_value; strtabinc = stab_ptr->n_value;
symt_normalize_function(module, curr_func); stabs_finalize_function(module, curr_func);
curr_func = NULL; curr_func = NULL;
break; break;
case N_OPT: case N_OPT:

View File

@ -20,6 +20,8 @@
*/ */
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "config.h" #include "config.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -77,6 +79,61 @@ int symt_cmp_addr(const void* p1, const void* p2)
return cmp_addr(a1, a2); 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* symt_new_compiland(struct module* module, const char* name)
{ {
struct symt_compiland* sym; struct symt_compiland* sym;
@ -158,13 +215,15 @@ struct symt_function* symt_new_function(struct module* module,
struct symt_compiland* compiland, struct symt_compiland* compiland,
const char* name, const char* name,
unsigned long addr, unsigned long size, unsigned long addr, unsigned long size,
struct symt* type) struct symt* sig_type)
{ {
struct symt_function* sym; struct symt_function* sym;
struct symt** p; struct symt** p;
TRACE_(dbghelp_symtype)("Adding global function %s:%s @%lx-%lx\n", TRACE_(dbghelp_symtype)("Adding global function %s:%s @%lx-%lx\n",
module->module.ModuleName, name, addr, addr + size - 1); module->module.ModuleName, name, addr, addr + size - 1);
assert(!sig_type || sig_type->tag == SymTagFunctionType);
if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{ {
sym->symt.tag = SymTagFunction; sym->symt.tag = SymTagFunction;
@ -173,7 +232,7 @@ struct symt_function* symt_new_function(struct module* module,
module->sortlist_valid = FALSE; module->sortlist_valid = FALSE;
sym->container = &compiland->symt; sym->container = &compiland->symt;
sym->addr = addr; sym->addr = addr;
sym->type = type; sym->type = sig_type;
sym->size = size; sym->size = size;
sym->addr = addr; sym->addr = addr;
vector_init(&sym->vlines, sizeof(struct line_info), 64); 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->symt.tag = SymTagData;
locsym->hash_elt.name = pool_strdup(&module->pool, name); locsym->hash_elt.name = pool_strdup(&module->pool, name);
locsym->hash_elt.next = NULL; locsym->hash_elt.next = NULL;
locsym->kind = DataIsLocal; locsym->kind = (offset < 0) ? DataIsParam : DataIsLocal;
locsym->container = &block->symt; locsym->container = &block->symt;
locsym->type = type; locsym->type = type;
if (regno) 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_block* symt_open_func_block(struct module* module,
struct symt_function* func, struct symt_function* func,
struct symt_block* parent_block, struct symt_block* parent_block,
unsigned pc) unsigned pc, unsigned len)
{ {
struct symt_block* block; struct symt_block* block;
struct symt** p; 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); assert(!parent_block || parent_block->symt.tag == SymTagBlock);
block = pool_alloc(&module->pool, sizeof(*block)); block = pool_alloc(&module->pool, sizeof(*block));
block->symt.tag = SymTagBlock; block->symt.tag = SymTagBlock;
block->address = func->addr + pc; block->address = func->addr + pc;
block->size = 0; block->size = len;
block->container = parent_block ? &parent_block->symt : &func->symt; block->container = parent_block ? &parent_block->symt : &func->symt;
vector_init(&block->vchildren, sizeof(struct symt*), 4); vector_init(&block->vchildren, sizeof(struct symt*), 4);
if (parent_block) if (parent_block)
@ -299,17 +358,37 @@ struct symt_block* symt_close_func_block(struct module* module,
{ {
assert(func->symt.tag == SymTagFunction); 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) ? return (block->container->tag == SymTagBlock) ?
GET_ENTRY(block->container, struct symt_block, symt) : NULL; 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) BOOL symt_normalize_function(struct module* module, struct symt_function* func)
{ {
unsigned len; unsigned len;
struct line_info* dli; struct line_info* dli;
if (!func) return TRUE; assert(func);
/* We aren't adding any more locals or line numbers to this function. /* We aren't adding any more locals or line numbers to this function.
* Free any spare memory that we might have allocated. * Free any spare memory that we might have allocated.
*/ */
@ -363,7 +442,17 @@ static void symt_fill_sym_info(const struct module* module,
break; break;
case LocIsConstant: case LocIsConstant:
sym_info->Flags |= SYMFLAG_VALUEPRESENT; 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; break;
default: default:
FIXME("Unhandled loc (%u) in sym data\n", data->location); 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);
assert(mask[0] != '!'); assert(mask[0] != '!');
regcomp(&preg, mask, REG_NOSUB); compile_regex(mask, &preg);
hash_table_iter_init(&module->ht_symbols, &hti, NULL); hash_table_iter_init(&module->ht_symbols, &hti, NULL);
while ((ptr = hash_table_iter_up(&hti))) 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; return FALSE;
} }
break; break;
case SymTagLabel:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
break;
default: default:
FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag); FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
assert(0); assert(0);
@ -582,7 +675,7 @@ static BOOL symt_enum_locals(struct process* pcs, const char* mask,
BOOL ret; BOOL ret;
regex_t preg; regex_t preg;
regcomp(&preg, mask ? mask : ".*", REG_NOSUB); compile_regex(mask ? mask : "*", &preg);
ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback, ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback,
UserContext, sym_info, UserContext, sym_info,
&((struct symt_function*)sym)->vchildren); &((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) for (module = pcs->lmodules; module; module = module->next)
{ {
if (module->module.SymType != SymNone && if (module->module.SymType != SymNone &&
!symt_enum_module(module, ".*", EnumSymbolsCallback, UserContext)) !symt_enum_module(module, "*", EnumSymbolsCallback, UserContext))
break; break;
} }
return TRUE; return TRUE;
@ -641,9 +734,9 @@ BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask,
FIXME("Strange call mode\n"); FIXME("Strange call mode\n");
return FALSE; return FALSE;
} }
Mask = ".*"; Mask = "*";
} }
else if (!Mask) Mask = ".*"; else if (!Mask) Mask = "*";
} }
if ((module = module_get_debug(pcs, module))) if ((module = module_get_debug(pcs, module)))
symt_enum_module(module, Mask, EnumSymbolsCallback, UserContext); 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 * fills information about a file
*/ */
static BOOL fill_line_info(struct module* module, struct symt_function* func, BOOL symt_fill_func_line_info(struct module* module, struct symt_function* func,
DWORD addr, IMAGEHLP_LINE* line) DWORD addr, IMAGEHLP_LINE* line)
{ {
struct line_info* dli = NULL; struct line_info* dli = NULL;
BOOL found = FALSE; 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 ((idx = symt_find_nearest(module, dwAddr)) == -1) return FALSE;
if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE; if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE;
if (!fill_line_info(module, if (!symt_fill_func_line_info(module,
(struct symt_function*)module->addr_sorttab[idx], (struct symt_function*)module->addr_sorttab[idx],
dwAddr, Line)) return FALSE; dwAddr, Line)) return FALSE;
if (pdwDisplacement) *pdwDisplacement = dwAddr - Line->Address; if (pdwDisplacement) *pdwDisplacement = dwAddr - Line->Address;
return TRUE; return TRUE;
} }
@ -929,6 +1022,27 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
return FALSE; 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.@) * SymGetLineNext (DBGHELP.@)
* *
@ -937,7 +1051,6 @@ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
{ {
struct process* pcs = process_find_by_handle(hProcess); struct process* pcs = process_find_by_handle(hProcess);
struct module* module; struct module* module;
struct line_info* li;
TRACE("(%p %p)\n", hProcess, Line); 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); module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE; if (!(module = module_get_debug(pcs, module))) return FALSE;
if (Line->Key == 0) return FALSE; if (symt_get_func_line_next(module, Line)) return TRUE;
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);
}
SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
return FALSE; return FALSE;
} }

View File

@ -84,6 +84,7 @@ const char* symt_get_name(const struct symt* sym)
case SymTagFunction: return ((struct symt_function*)sym)->hash_elt.name; case SymTagFunction: return ((struct symt_function*)sym)->hash_elt.name;
case SymTagPublicSymbol: return ((struct symt_public*)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 SymTagBaseType: return ((struct symt_basic*)sym)->hash_elt.name;
case SymTagLabel: return ((struct symt_function_point*)sym)->name;
/* hierarchy tree */ /* hierarchy tree */
case SymTagEnum: return ((struct symt_enum*)sym)->name; case SymTagEnum: return ((struct symt_enum*)sym)->name;
case SymTagTypedef: return ((struct symt_typedef*)sym)->hash_elt.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, 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_data* e;
struct symt** p; 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 */ /* CV defines the underlying type for the enumeration */
e->type = &symt_new_basic(module, btInt, "int", 4)->symt; e->type = &symt_new_basic(module, btInt, "int", 4)->symt;
e->location = LocIsConstant; 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); p = vector_add(&enum_type->vchildren, &module->pool);
if (!p) return FALSE; /* FIXME we leak e */ 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_function_signature* symt_new_function_signature(struct module* module,
struct symt* ret_type) struct symt* ret_type)
{ {
struct symt_function_signature* sym; struct symt_function_signature* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{ {
sym->symt.tag = SymTagFunctionType; sym->symt.tag = SymTagFunctionType;
sym->rettype = ret_type; sym->rettype = ret_type;
vector_init(&sym->vchildren, sizeof(struct symt*), 4);
} }
return sym; 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* symt_new_pointer(struct module* module, struct symt* ref_type)
{ {
struct symt_pointer* sym; struct symt_pointer* sym;
@ -318,6 +335,21 @@ struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_ty
return sym; 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.@) * SymEnumTypes (DBGHELP.@)
* *
@ -395,10 +427,13 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
switch (type->tag) switch (type->tag)
{ {
case SymTagUDT: v = &((struct symt_udt*)type)->vchildren; break; case SymTagUDT: v = &((struct symt_udt*)type)->vchildren; break;
case SymTagEnum: v = &((struct symt_enum*)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: 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; return FALSE;
} }
for (i = 0; i < tifp->Count; i++) 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: case SymTagPublicSymbol:
X(DWORD) = ((struct symt_public*)type)->address; X(DWORD) = ((struct symt_public*)type)->address;
break; break;
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:
X(DWORD) = ((struct symt_function_point*)type)->parent->addr +
((struct symt_function_point*)type)->offset;
break;
default: 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; return FALSE;
} }
break; 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: case TI_GET_BASETYPE:
if (type->tag != SymTagBaseType) return FALSE; switch (type->tag)
X(DWORD) = ((struct symt_basic*)type)->bt; {
case SymTagBaseType:
X(DWORD) = ((struct symt_basic*)type)->bt;
break;
case SymTagEnum:
X(DWORD) = btInt;
break;
default:
return FALSE;
}
break; break;
case TI_GET_BITPOSITION: case TI_GET_BITPOSITION:
@ -464,17 +505,32 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
case SymTagEnum: case SymTagEnum:
X(DWORD) = vector_length(&((struct symt_enum*)type)->vchildren); X(DWORD) = vector_length(&((struct symt_enum*)type)->vchildren);
break; 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: 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 */ /* fall through */
case SymTagData:
case SymTagPublicSymbol: case SymTagPublicSymbol:
case SymTagPointerType:
case SymTagBaseType: case SymTagBaseType:
return FALSE; return FALSE;
} }
break; break;
case TI_GET_COUNT: 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; if (type->tag != SymTagArrayType) return FALSE;
X(DWORD) = ((struct symt_array*)type)->end - X(DWORD) = ((struct symt_array*)type)->end -
((struct symt_array*)type)->start; ((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; X(DWORD) = ((struct symt_udt*)type)->size;
break; break;
case SymTagEnum: case SymTagEnum:
X(DWORD) = sizeof(int); X(DWORD) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */
break; break;
case SymTagData: case SymTagData:
if (((struct symt_data*)type)->location == LocIsBitField) if (((struct symt_data*)type)->location == LocIsBitField)
X(DWORD) = ((struct symt_data*)type)->u.bitfield.length; X(DWORD) = ((struct symt_data*)type)->u.bitfield.length;
else else
return symt_get_info(((struct symt_data*)type)->type, return FALSE;
TI_GET_LENGTH, pInfo);
break; break;
case SymTagArrayType: case SymTagArrayType:
if (!symt_get_info(((struct symt_array*)type)->basetype, 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: case SymTagPublicSymbol:
X(DWORD) = ((struct symt_public*)type)->size; X(DWORD) = ((struct symt_public*)type)->size;
break; break;
case SymTagTypedef:
return symt_get_info(((struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo);
break;
default: 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; return 0;
} }
break; 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; X(DWORD) = (DWORD)((struct symt_data*)type)->container;
break; break;
default: 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; return FALSE;
} }
break; break;
@ -545,23 +617,22 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
switch (type->tag) switch (type->tag)
{ {
case SymTagData: case SymTagData:
switch (((struct symt_data*)type)->location) switch (((struct symt_data*)type)->kind)
{ {
case LocIsRegRel: case DataIsParam:
case LocIsThisRel: case DataIsLocal:
case DataIsMember:
X(ULONG) = ((struct symt_data*)type)->u.offset; X(ULONG) = ((struct symt_data*)type)->u.offset;
break; break;
case LocIsConstant:
X(ULONG) = 0; /* FIXME ???? */
break;
default: default:
FIXME("Unknown location (%u) for get-offset\n", FIXME("Unknown kind (%u) for get-offset\n",
((struct symt_data*)type)->location); ((struct symt_data*)type)->kind);
break; return FALSE;
} }
break; break;
default: 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; return FALSE;
} }
break; break;
@ -582,8 +653,10 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
break; break;
case TI_GET_TYPE: case TI_GET_TYPE:
case TI_GET_TYPEID:
switch (type->tag) switch (type->tag)
{ {
/* hierarchical => hierarchical */
case SymTagArrayType: case SymTagArrayType:
X(DWORD) = (DWORD)((struct symt_array*)type)->basetype; X(DWORD) = (DWORD)((struct symt_array*)type)->basetype;
break; break;
@ -593,34 +666,43 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
case SymTagFunctionType: case SymTagFunctionType:
X(DWORD) = (DWORD)((struct symt_function_signature*)type)->rettype; X(DWORD) = (DWORD)((struct symt_function_signature*)type)->rettype;
break; break;
case SymTagTypedef:
X(DWORD) = (DWORD)((struct symt_typedef*)type)->type;
break;
/* lexical => hierarchical */
case SymTagData: case SymTagData:
X(DWORD) = (DWORD)((struct symt_data*)type)->type; X(DWORD) = (DWORD)((struct symt_data*)type)->type;
break; break;
case SymTagFunction:
X(DWORD) = (DWORD)((struct symt_function*)type)->type;
break;
/* FIXME: should also work for enums and FunctionArgType */
default: 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; return FALSE;
} }
break; break;
case TI_GET_TYPEID:
X(DWORD) = (DWORD)type;
break;
case TI_GET_UDTKIND: case TI_GET_UDTKIND:
if (type->tag != SymTagUDT) return FALSE; if (type->tag != SymTagUDT) return FALSE;
X(DWORD) = ((struct symt_udt*)type)->kind; X(DWORD) = ((struct symt_udt*)type)->kind;
break; 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 #undef X
case TI_GET_ADDRESSOFFSET: case TI_GET_ADDRESSOFFSET:
case TI_GET_ARRAYINDEXTYPEID: case TI_GET_ARRAYINDEXTYPEID:
case TI_GET_CALLING_CONVENTION: case TI_GET_CALLING_CONVENTION:
case TI_GET_CLASSPARENTID: case TI_GET_CLASSPARENTID:
case TI_GET_NESTED:
case TI_GET_SYMINDEX: case TI_GET_SYMINDEX:
case TI_GET_THISADJUST: case TI_GET_THISADJUST:
case TI_GET_VALUE:
case TI_GET_VIRTUALBASECLASS: case TI_GET_VIRTUALBASECLASS:
case TI_GET_VIRTUALBASEPOINTEROFFSET: case TI_GET_VIRTUALBASEPOINTEROFFSET:
case TI_GET_VIRTUALTABLESHAPEID: case TI_GET_VIRTUALTABLESHAPEID: