From 97f6a7e5888d7d4c62494672d3944e4617a609ea Mon Sep 17 00:00:00 2001 From: Jason Green Date: Tue, 20 Nov 2007 16:02:16 -0500 Subject: [PATCH] Added support for all types that can be stored in a PDB file to the PDB dumper utility. Also, more error checking, and support for newer versions of MSVC --- dlls/dbghelp/msc.c | 475 +++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 399 insertions(+), 76 deletions(-) diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index e6542e9..c7cdfc5 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -66,7 +66,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_msc); static void dump(const void* ptr, unsigned len) { - int i, j; + unsigned int i, j; char msg[128]; const char* hexof = "0123456789abcdef"; const BYTE* x = (const BYTE*)ptr; @@ -93,10 +93,26 @@ static void dump(const void* ptr, unsigned len) * Process CodeView type information. */ -#define MAX_BUILTIN_TYPES 0x0480 #define FIRST_DEFINABLE_TYPE 0x1000 -static struct symt* cv_basic_types[MAX_BUILTIN_TYPES]; +typedef struct{ + struct symt *basic; /* basic type (index < T_MAXBASICTYPE) */ +#ifdef USE_ALL_TYPES + struct symt *nearPtr; /* near pointer to basic type (index & 0x0100) == 0x0100 */ + struct symt *farPtr; /* far pointer to basic type (index & 0x0200) == 0x0200 */ + struct symt *hugePtr; /* huge pointer to basic type (index & 0x0300) == 0x0300 */ + struct symt *near32Ptr; /* 32-bit near pointer to basic type (index & 0x0400) == 0x0400 */ + struct symt *far32Ptr; /* 48-bit far pointer to basic type (index & 0x0500) == 0x0500 */ + struct symt *near64Ptr; /* 64-bit near pointer to basic type (index & 0x0600) == 0x0600 */ +#else + struct symt *near32Ptr; /* 32-bit near pointer to basic type (index & 0x0400) == 0x0400 */ +#endif +} CV_BasicTypes; + + +/* static struct symt* cv_basic_types[T_MAXPREDEFINEDTYPE]; */ +static CV_BasicTypes cv_basic_types[T_MAXBASICTYPE] = {{0}}; + struct cv_defined_module { @@ -111,42 +127,100 @@ static struct cv_defined_module*cv_current_module; static void codeview_init_basic_types(struct module* module) { +#ifdef USE_ALL_TYPES + int i; +#endif + /* * These are the common builtin types that are used by VC++. */ - cv_basic_types[T_NOTYPE] = NULL; - cv_basic_types[T_ABS] = NULL; - cv_basic_types[T_VOID] = &symt_new_basic(module, btVoid, "void", 0)->symt; - cv_basic_types[T_CHAR] = &symt_new_basic(module, btChar, "char", 1)->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_QUAD] = &symt_new_basic(module, btInt, "long long int", 8)->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; - cv_basic_types[T_REAL32] = &symt_new_basic(module, btFloat, "float", 4)->symt; - cv_basic_types[T_REAL64] = &symt_new_basic(module, btFloat, "double", 8)->symt; - cv_basic_types[T_RCHAR] = &symt_new_basic(module, btInt, "signed char", 1)->symt; - cv_basic_types[T_WCHAR] = &symt_new_basic(module, btWChar, "wchar_t", 2)->symt; - cv_basic_types[T_INT4] = &symt_new_basic(module, btInt, "INT4", 4)->symt; - cv_basic_types[T_UINT4] = &symt_new_basic(module, btUInt, "UINT4", 4)->symt; - - cv_basic_types[T_32PVOID] = &symt_new_pointer(module, cv_basic_types[T_VOID])->symt; - cv_basic_types[T_32PCHAR] = &symt_new_pointer(module, cv_basic_types[T_CHAR])->symt; - cv_basic_types[T_32PSHORT] = &symt_new_pointer(module, cv_basic_types[T_SHORT])->symt; - cv_basic_types[T_32PLONG] = &symt_new_pointer(module, cv_basic_types[T_LONG])->symt; - cv_basic_types[T_32PQUAD] = &symt_new_pointer(module, cv_basic_types[T_QUAD])->symt; - cv_basic_types[T_32PUCHAR] = &symt_new_pointer(module, cv_basic_types[T_UCHAR])->symt; - cv_basic_types[T_32PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT])->symt; - cv_basic_types[T_32PULONG] = &symt_new_pointer(module, cv_basic_types[T_ULONG])->symt; - cv_basic_types[T_32PUQUAD] = &symt_new_pointer(module, cv_basic_types[T_UQUAD])->symt; - cv_basic_types[T_32PREAL32] = &symt_new_pointer(module, cv_basic_types[T_REAL32])->symt; - cv_basic_types[T_32PREAL64] = &symt_new_pointer(module, cv_basic_types[T_REAL64])->symt; - cv_basic_types[T_32PRCHAR] = &symt_new_pointer(module, cv_basic_types[T_RCHAR])->symt; - cv_basic_types[T_32PWCHAR] = &symt_new_pointer(module, cv_basic_types[T_WCHAR])->symt; - cv_basic_types[T_32PINT4] = &symt_new_pointer(module, cv_basic_types[T_INT4])->symt; - cv_basic_types[T_32PUINT4] = &symt_new_pointer(module, cv_basic_types[T_UINT4])->symt; + + /* non-pointer basic types */ + cv_basic_types[T_NOTYPE].basic = NULL; + cv_basic_types[T_ABS].basic = NULL; + cv_basic_types[T_SEGMENT].basic = NULL; /* fixme! */ + cv_basic_types[T_VOID].basic = &symt_new_basic(module, btVoid, "void", 0)->symt; + cv_basic_types[T_CURRENCY].basic = &symt_new_basic(module, btCurrency, "currency", 4)->symt; /* fixme! This is a VB type... size and name are possibly incorrect */ + cv_basic_types[T_NBASICSTR].basic = NULL; /* fixme! VB type */ + cv_basic_types[T_FBASICSTR].basic = NULL; /* fixme! VB type */ + cv_basic_types[T_NOTTRANS].basic = NULL; /* error type */ + cv_basic_types[T_CHAR].basic = &symt_new_basic(module, btChar, "char", 1)->symt; + cv_basic_types[T_SHORT].basic = &symt_new_basic(module, btInt, "short int", 2)->symt; + cv_basic_types[T_LONG].basic = &symt_new_basic(module, btInt, "long int", 4)->symt; + cv_basic_types[T_QUAD].basic = &symt_new_basic(module, btInt, "long long int", 8)->symt; + cv_basic_types[T_UCHAR].basic = &symt_new_basic(module, btUInt, "unsigned char", 1)->symt; + cv_basic_types[T_USHORT].basic = &symt_new_basic(module, btUInt, "unsigned short", 2)->symt; + cv_basic_types[T_ULONG].basic = &symt_new_basic(module, btUInt, "unsigned long", 4)->symt; + cv_basic_types[T_UQUAD].basic = &symt_new_basic(module, btUInt, "unsigned long long", 8)->symt; + cv_basic_types[T_BOOL08].basic = &symt_new_basic(module, btBool, "bool", 1)->symt; + cv_basic_types[T_BOOL16].basic = &symt_new_basic(module, btBool, "bool16", 2)->symt; + cv_basic_types[T_BOOL32].basic = &symt_new_basic(module, btBool, "bool32", 4)->symt; + cv_basic_types[T_BOOL64].basic = &symt_new_basic(module, btBool, "bool64", 8)->symt; + cv_basic_types[T_REAL32].basic = &symt_new_basic(module, btFloat, "float", 4)->symt; + cv_basic_types[T_REAL64].basic = &symt_new_basic(module, btFloat, "double", 8)->symt; + cv_basic_types[T_REAL80].basic = &symt_new_basic(module, btFloat, "long double", 10)->symt; + cv_basic_types[T_REAL128].basic = &symt_new_basic(module, btFloat, "long long double", 16)->symt; + cv_basic_types[T_REAL48].basic = &symt_new_basic(module, btFloat, "long float", 6)->symt; + cv_basic_types[T_CPLX32].basic = &symt_new_basic(module, btComplex, "complex", 4)->symt; /* fixme! This is a VB type... name is possibly incorrect */ + cv_basic_types[T_CPLX64].basic = &symt_new_basic(module, btComplex, "complex64", 8)->symt; /* fixme! This is a VB type... name is possibly incorrect */ + cv_basic_types[T_CPLX80].basic = &symt_new_basic(module, btComplex, "complex80", 10)->symt; /* fixme! This is a VB type... name is possibly incorrect */ + cv_basic_types[T_CPLX128].basic = &symt_new_basic(module, btComplex, "complex128", 16)->symt; /* fixme! This is a VB type... name is possibly incorrect */ + cv_basic_types[T_BIT].basic = &symt_new_basic(module, btBit, "Bit", 1)->symt; /* fixme! This is a VB type... size and name are possibly incorrect */ + cv_basic_types[T_PASCHAR].basic = NULL; /* fixme! */ + cv_basic_types[T_RCHAR].basic = &symt_new_basic(module, btInt, "signed char", 1)->symt; + cv_basic_types[T_WCHAR].basic = &symt_new_basic(module, btWChar, "wchar_t", 2)->symt; + cv_basic_types[T_INT2].basic = &symt_new_basic(module, btInt, "INT2", 2)->symt; + cv_basic_types[T_UINT2].basic = &symt_new_basic(module, btUInt, "UINT2", 2)->symt; + cv_basic_types[T_INT4].basic = &symt_new_basic(module, btInt, "INT4", 4)->symt; + cv_basic_types[T_UINT4].basic = &symt_new_basic(module, btUInt, "UINT4", 4)->symt; + cv_basic_types[T_INT8].basic = &symt_new_basic(module, btInt, "INT8", 8)->symt; + cv_basic_types[T_UINT8].basic = &symt_new_basic(module, btUInt, "UINT8", 8)->symt; + + + /* add 32-bit near pointers to basic types */ + cv_basic_types[T_VOID].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_VOID].basic)->symt; + cv_basic_types[T_CHAR].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_CHAR].basic)->symt; + cv_basic_types[T_SHORT].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_SHORT].basic)->symt; + cv_basic_types[T_LONG].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_LONG].basic)->symt; + cv_basic_types[T_QUAD].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_QUAD].basic)->symt; + cv_basic_types[T_UCHAR].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_UCHAR].basic)->symt; + cv_basic_types[T_USHORT].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_USHORT].basic)->symt; + cv_basic_types[T_ULONG].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_ULONG].basic)->symt; + cv_basic_types[T_UQUAD].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_UQUAD].basic)->symt; + cv_basic_types[T_BOOL08].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_BOOL08].basic)->symt; + cv_basic_types[T_BOOL16].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_BOOL16].basic)->symt; + cv_basic_types[T_BOOL32].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_BOOL32].basic)->symt; + cv_basic_types[T_BOOL64].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_BOOL64].basic)->symt; + cv_basic_types[T_REAL32].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_REAL32].basic)->symt; + cv_basic_types[T_REAL64].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_REAL64].basic)->symt; + cv_basic_types[T_REAL80].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_REAL80].basic)->symt; + cv_basic_types[T_REAL128].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_REAL128].basic)->symt; + cv_basic_types[T_REAL48].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_REAL48].basic)->symt; + cv_basic_types[T_CPLX32].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_CPLX32].basic)->symt; + cv_basic_types[T_CPLX64].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_CPLX64].basic)->symt; + cv_basic_types[T_CPLX80].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_CPLX80].basic)->symt; + cv_basic_types[T_CPLX128].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_CPLX128].basic)->symt; + cv_basic_types[T_RCHAR].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_RCHAR].basic)->symt; + cv_basic_types[T_WCHAR].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_WCHAR].basic)->symt; + cv_basic_types[T_INT2].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_INT2].basic)->symt; + cv_basic_types[T_UINT2].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_UINT2].basic)->symt; + cv_basic_types[T_INT4].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_INT4].basic)->symt; + cv_basic_types[T_UINT4].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_UINT4].basic)->symt; + cv_basic_types[T_INT8].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_INT8].basic)->symt; + cv_basic_types[T_UINT8].near32Ptr = &symt_new_pointer(module, cv_basic_types[T_UINT8].basic)->symt; + +#ifdef USE_ALL_TYPES + /* the representation of a pointer is independant of its size. This means we can just reuse the same + symt object for the near, far, huge, and far32 pointers of each type. This isn't really necessary, + it's just done for completeness. */ + for (i = 0; i < T_MAXBASICTYPE; i++){ + cv_basic_types[i].near64Ptr = cv_basic_types[i].near32Ptr; + cv_basic_types[i].far32Ptr = cv_basic_types[i].near32Ptr; + cv_basic_types[i].farPtr = cv_basic_types[i].near32Ptr; + cv_basic_types[i].nearPtr = cv_basic_types[i].near32Ptr; + cv_basic_types[i].hugePtr = cv_basic_types[i].near32Ptr; + } +#endif } static int numeric_leaf(int* value, const unsigned short int* leaf) @@ -288,8 +362,35 @@ static struct symt* codeview_get_type(unsigned int typeno, BOOL quiet) */ if (typeno < FIRST_DEFINABLE_TYPE) { - if (typeno < MAX_BUILTIN_TYPES) - symt = cv_basic_types[typeno]; + /* invalid type index => fail */ + if (typeno >= T_MAXPREDEFINEDTYPE) + return NULL; + + /* type potentially points to a basic type => check if any of the pointer flags are set on the type */ + if ((typeno & T_BASICTYPE_MASK) < T_MAXBASICTYPE){ +#ifdef USE_ALL_TYPES + switch (typeno & T_MODE_MASK){ + case 0: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].basic; break; + case T_NEARPTR_BITS: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].nearPtr; break; + case T_FARPTR_BITS: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].farPtr; break; + case T_HUGEPTR_BITS: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].hugePtr; break; + case T_NEAR32PTR_BITS: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].near32Ptr; break; + case T_FAR32PTR_BITS: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].far32Ptr; break; + case T_NEAR64PTR_BITS: symt = cv_basic_types[typeno & T_BASICTYPE_MASK].near64Ptr; break; + default: + FIXME("unknown type mode: 0x%04x\n", typeno & T_MODE_MASK); + break; + } +#else + /* type is a pointer => return the pointer to the basic type */ + if (typeno & T_MODE_MASK) + symt = cv_basic_types[typeno & T_BASICTYPE_MASK].near32Ptr; + + /* type is just a basic type */ + else + symt = cv_basic_types[typeno & T_BASICTYPE_MASK].basic; +#endif + } } else { @@ -316,14 +417,28 @@ struct codeview_type_parse struct module* module; const BYTE* table; const DWORD* offset; + DWORD first; DWORD num; }; static inline const void* codeview_jump_to_type(const struct codeview_type_parse* ctp, DWORD idx) { - if (idx < FIRST_DEFINABLE_TYPE) return NULL; - idx -= FIRST_DEFINABLE_TYPE; - return (idx >= ctp->num) ? NULL : (ctp->table + ctp->offset[idx]); + if (idx < ctp->first){ /*FIRST_DEFINABLE_TYPE)*/ + WARN("type 0x%08x is potentially a built-in type. Returning NULL\n", idx); + + return NULL; + } + + + idx -= ctp->first; /*FIRST_DEFINABLE_TYPE;*/ + + if (idx >= ctp->num){ + ERR("out of range type number {idx = 0x%08x, first = 0x%08x, num = 0x%08x}\n", idx, ctp->first, ctp->num); + + return NULL; + } + + return ctp->table + ctp->offset[idx]; } static int codeview_add_type(unsigned int typeno, struct symt* dt) @@ -406,7 +521,9 @@ static struct symt* codeview_fetch_type(struct codeview_type_parse* ctp, return NULL; } symt = codeview_parse_one_type(ctp, typeno, p, FALSE); - if (!symt) FIXME("Couldn't load forward type %x\n", typeno); + if (!symt) + FIXME("Couldn't load forward type %x\n", typeno); + return symt; } @@ -778,7 +895,7 @@ static void codeview_add_func_signature_args(struct codeview_type_parse* ctp, sym->rettype = codeview_fetch_type(ctp, ret_type); if (args_list && (reftype = codeview_jump_to_type(ctp, args_list))) { - int i; + unsigned int i; switch (reftype->generic.id) { case LF_ARGLIST_V1: @@ -815,7 +932,7 @@ static struct symt* codeview_parse_one_type(struct codeview_type_parse* ctp, /* FIXME: we don't handle modifiers, * but readd previous type on the curr_type */ - WARN("Modifier on %x: %s%s%s%s\n", + WARN("Modifier on 0x%04x: %s%s%s%s\n", type->modifier_v1.type, type->modifier_v1.attribute & 0x01 ? "const " : "", type->modifier_v1.attribute & 0x02 ? "volatile " : "", @@ -827,7 +944,7 @@ static struct symt* codeview_parse_one_type(struct codeview_type_parse* ctp, break; case LF_MODIFIER_V2: /* FIXME: we don't handle modifiers, but readd previous type on the curr_type */ - WARN("Modifier on %x: %s%s%s%s\n", + WARN("Modifier on 0x%04x: %s%s%s%s\n", type->modifier_v2.type, type->modifier_v2.attribute & 0x01 ? "const " : "", type->modifier_v2.attribute & 0x02 ? "volatile " : "", @@ -1050,10 +1167,10 @@ static struct symt* codeview_parse_one_type(struct codeview_type_parse* ctp, static int codeview_parse_type_table(struct codeview_type_parse* ctp) { - unsigned int curr_type = FIRST_DEFINABLE_TYPE; + unsigned int curr_type; const union codeview_type* type; - for (curr_type = FIRST_DEFINABLE_TYPE; curr_type < FIRST_DEFINABLE_TYPE + ctp->num; curr_type++) + for (curr_type = ctp->first; curr_type < ctp->first + ctp->num; curr_type++) { type = codeview_jump_to_type(ctp, curr_type); @@ -1164,7 +1281,7 @@ static struct codeview_linetab* codeview_snarf_linetab(struct module* module, source = source_new(module, NULL, (const char*)(start + file_segcount)); for (k = 0; k < file_segcount; k++, this_seg++) - { + { pnt2.uc = linetab + lt_ptr[k]; lt_hdr[this_seg].start = start[k].start; lt_hdr[this_seg].end = start[k].end; @@ -1173,7 +1290,7 @@ static struct codeview_linetab* codeview_snarf_linetab(struct module* module, lt_hdr[this_seg].nline = *pnt2.s++; lt_hdr[this_seg].offtab = pnt2.ui; lt_hdr[this_seg].linetab = (const unsigned short*)(pnt2.ui + lt_hdr[this_seg].nline); - } + } } leave: @@ -1227,9 +1344,9 @@ static unsigned codeview_get_address(const struct msc_debug_info* msc_dbg, int nsect = msc_dbg->nsect; const IMAGE_SECTION_HEADER* sectp = msc_dbg->sectp; - if (!seg || seg > nsect) return 0; - return msc_dbg->module->module.BaseOfImage + - codeview_map_offset(msc_dbg, sectp[seg-1].VirtualAddress + offset); + if (!seg || seg > (unsigned)nsect) return 0; + return (unsigned int)(msc_dbg->module->module.BaseOfImage + + codeview_map_offset(msc_dbg, sectp[seg-1].VirtualAddress + offset)); } static void codeview_add_func_linenum(struct module* module, @@ -1485,6 +1602,9 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root TRACE("S-Compiland-V2 %s\n", terminate_string(&sym->compiland_v2.p_name)); if (TRACE_ON(dbghelp_msc)) { + /* !! not sure what this is for since this will never print anything out. + Note that *(str + strlen(str)) == 0 always. */ + const char* ptr1 = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen; const char* ptr2; while (*ptr1) @@ -1499,6 +1619,9 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root TRACE("S-Compiland-V3 %s\n", sym->compiland_v3.name); if (TRACE_ON(dbghelp_msc)) { + /* !! not sure what this is for since this will never print anything out. + Note that *(str + strlen(str)) == 0 always. */ + const char* ptr1 = sym->compiland_v3.name + strlen(sym->compiland_v3.name); const char* ptr2; while (*ptr1) @@ -1525,9 +1648,14 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root symt_add_function_point(msc_dbg->module, curr_func, SymTagLabel, &loc, terminate_string(&sym->label_v1.p_name)); } - else - FIXME("No current function for label %s\n", - terminate_string(&sym->label_v1.p_name)); + else{ + + /* this case doesn't need to be checked for length since the max length is 255 characters and + the terminate_string() function takes that into account */ + FIXME("No current function for V1 label %s\n", + terminate_string(&sym->label_v1.p_name)); + } + break; case S_LABEL_V3: if (curr_func) @@ -1537,8 +1665,29 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root symt_add_function_point(msc_dbg->module, curr_func, SymTagLabel, &loc, sym->label_v3.name); } - else - FIXME("No current function for label %s\n", sym->label_v3.name); + else if (TRACE_ON(dbghelp_msc)){ + + /* the compiler inserts a label before every function that uses C++ exception handling (try-catch). + The label's name always takes the form "__ehhandler$". Since these + labels being outside of a function is not actually an error, let's filter out those cases. The + function names can get really really long (think member functions of nested templates being passed + and returning many other nested templates), and the TRACE/FIXME/ERR macros will abort the process + if their buffers overflow (which they do for lots of function names). Because of all this, we'll + just prevent those names from being written out at all. */ + const char *ehName = "__ehhandler$"; + + + /* C++ EH wrapped function => just trace out an event */ + if (!strncmp(sym->label_v3.name, ehName, strlen(ehName))) + TRACE("found a C++ EH wrapped function label\n"); + + /* this is most often not an error or fixme case either. The function-less labels are generally + initializer labels for global or static variables. We'll trace these out for curiosity purposes + just in case some bad case sneaks through. */ + else + FIXME("No current function for V3 label %s. Possibly a global initializer label\n", sym->label_v3.name); + } + break; case S_CONSTANT_V1: @@ -1661,6 +1810,12 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root break; case S_MSTOOL_V3: /* just to silence a few warnings */ + /* compiler options and build settings + This is a sequence of strings starting with "Microsoft (R) Optimizing Compiler". After the + compiler string there is a sequence of string pairs. The first string of each pair describes + the purpose (ie: 'cwd', 'cl', 'cmd', 'src', 'pdb'). The second string is the value for the + first string. No real need to parse this block, just skip it. + */ break; case S_SSEARCH_V1: @@ -1746,7 +1901,10 @@ static void* pdb_read_ds_file(const struct PDB_DS_HEADER* pdb, const DWORD* block_list; DWORD i; - if (!toc || file_nr >= toc->num_files) return NULL; + if (!toc || file_nr >= toc->num_files){ + ERR("invalid TOC or file number {toc = %p, file_nr = %d, num_files = %d}\n", toc, file_nr, toc ? toc->num_files : -1); + return NULL; + } if (toc->file_size[file_nr] == 0 || toc->file_size[file_nr] == 0xFFFFFFFF) { @@ -1882,7 +2040,7 @@ static BOOL CALLBACK pdb_match(const char* file, void* user) { /* accept first file that exists */ HANDLE h = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - TRACE("match with %s returns %p\n", file, h); + TRACE("match with '%s' returns %p\n", file, h); if (INVALID_HANDLE_VALUE != h) { CloseHandle(h); return FALSE; @@ -1938,13 +2096,16 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg, pdb_convert_types_header(&types, types_image); + TRACE("type info version number is %d\n", types.version); + /* Check for unknown versions */ switch (types.version) { case 19950410: /* VC 4.0 */ case 19951122: case 19961031: /* VC 5.0 / 6.0 */ - case 19990903: + case 19990903: /* VC 7.1 */ + case 20040203: /* VC 8.0 */ break; default: ERR("-Unknown type info version %d\n", types.version); @@ -1964,6 +2125,15 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg, ptr += ((const union codeview_type*)ptr)->generic.len + 2; } ctp.offset = offset; + ctp.first = types.first_index; + + if (types.last_index != ctp.first + ctp.num) + FIXME("the type count doesn't match {first_index = 0x%08x, last_index = 0x%08x, num = 0x%08x}\n", ctp.first, types.last_index, ctp.num); + + /* sanity check -> there are still a number of places where we do not have access to a codeview_type_parse + object so we can't actually use the member for this value */ + if (ctp.first != FIRST_DEFINABLE_TYPE) + FIXME("this PDB has a first UDT index that is different from FIRST_DEFINABLE_TYPE! FIX IT FIX IT FIX IT FIX IT!\n"); /* Read type table */ codeview_parse_type_table(&ctp); @@ -2043,6 +2213,8 @@ static BOOL pdb_init(struct pdb_lookup* pdb_lookup, const char* image, BOOL do_f ERR("-Unable to get root from .PDB in %s\n", pdb_lookup->filename); return FALSE; } + + switch (root->Version) { case 20000404: @@ -2068,22 +2240,65 @@ static BOOL pdb_init(struct pdb_lookup* pdb_lookup, const char* image, BOOL do_f if (0) /* some tool to dump the internal files from a PDB file */ { - int i, num_files; + const struct PDB_DS_HEADER *pdbds = (const struct PDB_DS_HEADER*)image; + const struct PDB_JG_HEADER *pdbjg = (const struct PDB_JG_HEADER*)image; + int i, num_files; + int block_size; + FILE * fp; + char filename[MAX_PATH]; + int blockTotal = 0; + int numBlocks; - switch (pdb_lookup->kind) - { - case PDB_JG: num_files = pdb_lookup->u.jg.toc->num_files; break; - case PDB_DS: num_files = pdb_lookup->u.ds.toc->num_files; break; + + switch (pdb_lookup->kind){ + case PDB_JG: + num_files = pdb_lookup->u.jg.toc->num_files; + block_size = pdbjg->block_size; + numBlocks = pdbjg->total_alloc; + break; + + case PDB_DS: + num_files = pdb_lookup->u.ds.toc->num_files; + block_size = pdbds->block_size; + numBlocks = pdbds->num_pages; + break; } - for (i = 1; i < num_files; i++) + + for (i = 0; i < num_files; i++) { - unsigned char* x = pdb_read_file(image, pdb_lookup, i); - FIXME("********************** [%u]: size=%08x\n", - i, pdb_get_file_size(pdb_lookup, i)); - dump(x, pdb_get_file_size(pdb_lookup, i)); + unsigned char* x = pdb_read_file(image, pdb_lookup, i); + unsigned int size = pdb_get_file_size(pdb_lookup, i); + + + /* prevent this from reading NULL memory */ + if (x == NULL){ + WARN("********************** file %d is empty or missing {size = %u}\n", i, size); + + continue; + } + + + snprintf(filename, MAX_PATH, "pdbfile_%02d_%u_bytes_%d_blocks.bin", i, size, (size + block_size - 1) / block_size); + fp = fopen(filename, "wb"); + blockTotal += (size + block_size - 1) / block_size; + + if (fp){ + FIXME("********************** [file %d]: dumping to '%s' {size = %u}\n", i, filename, size); + fwrite(x, 1, size, fp); + + fclose(fp); + } + + else{ + FIXME("********************** [file %d]: ERROR-> could not open the file '%s' to dump the data to\n", i, filename); + dump(x, size); + } + pdb_free(x); } + + FIXME("********************** %d/%d blocks are used in the file\n", blockTotal, numBlocks); } return ret; } @@ -2134,7 +2349,7 @@ static void pdb_process_symbol_imports(const struct process* pcs, imp_pdb_lookup.kind = PDB_JG; imp_pdb_lookup.u.jg.timestamp = imp->TimeDateStamp; imp_pdb_lookup.age = imp->Age; - TRACE("got for %s: age=%u ts=%x\n", + TRACE("got for %s: age=%d ts=%x\n", imp->filename, imp->Age, imp->TimeDateStamp); pdb_process_internal(pcs, msc_dbg, &imp_pdb_lookup, i); } @@ -2168,9 +2383,13 @@ static BOOL pdb_process_internal(const struct process* pcs, WARN("Unable to open .PDB file: %s\n", pdb_lookup->filename); goto leave; } + + TRACE("initializing the PDB file '%s'\n", pdb_lookup->filename); pdb_init(pdb_lookup, image, FALSE); + TRACE("reading the symbols table\n"); symbols_image = pdb_read_file(image, pdb_lookup, 3); + if (symbols_image) { PDB_SYMBOLS symbols; @@ -2178,34 +2397,48 @@ static BOOL pdb_process_internal(const struct process* pcs, BYTE* file; int header_size = 0; + + TRACE("converting the symbols header\n"); pdb_convert_symbols_header(&symbols, &header_size, symbols_image); + + switch (symbols.version) { case 0: /* VC 4.0 */ case 19960307: /* VC 5.0 */ case 19970606: /* VC 6.0 */ - case 19990903: + case 19990903: /* VC 7.0 */ + case 20040203: /* VC 8.0 */ break; default: ERR("-Unknown symbol info version %d %08x\n", symbols.version, symbols.version); } + TRACE("processing symbol imports\n"); pdb_process_symbol_imports(pcs, msc_dbg, &symbols, symbols_image, image, pdb_lookup, module_index); /* Read global symbol table */ - modimage = pdb_read_file(image, pdb_lookup, symbols.gsym_file); + TRACE("reading global symbol table\n"); + /* NOTE: only the low word of the gsym_file value is the file number for the symbols file. On VC8 + PDBs the high word always seems to be 0x002a. On VC7 PDBs the high word is 0x0000 (which + is why this worked in those cases). Similarly for the hash1_file and hash2_file values - + VC7 always had the high word set to 0x38a0 and 0x0c05 respectively. VC8 always had the + high word set to 0x8800 and 0xc627 respectively. */ + modimage = pdb_read_file(image, pdb_lookup, symbols.gsym_file & 0x0000ffff); if (modimage) { + TRACE("dunno what this does\n"); codeview_snarf(msc_dbg, modimage, 0, - pdb_get_file_size(pdb_lookup, symbols.gsym_file), NULL); + pdb_get_file_size(pdb_lookup, symbols.gsym_file & 0x0000ffff), NULL); pdb_free(modimage); } /* Read per-module symbol / linenumber tables */ + TRACE("reading symbols and line numbers\n"); file = symbols_image + header_size; - while (file - symbols_image < header_size + symbols.module_size) + while ((size_t)(file - symbols_image) < (size_t)(header_size + symbols.module_size)) { PDB_SYMBOL_FILE_EX sfile; const char* file_name; @@ -2219,6 +2452,11 @@ static BOOL pdb_process_internal(const struct process* pcs, { struct codeview_linetab* linetab = NULL; + + TRACE("processing symbol file for '%s' {file = %d, symbolSize = %d, lineNoSize = %d, unknown2 = %d, nSrcFiles = %d}\n", + file + size, sfile.file, sfile.symbol_size, sfile.lineno_size, sfile.unknown2, sfile.nSrcFiles); + + if (sfile.lineno_size) linetab = codeview_snarf_linetab(msc_dbg->module, modimage + sfile.symbol_size, @@ -2231,14 +2469,32 @@ static BOOL pdb_process_internal(const struct process* pcs, pdb_free(modimage); } + + + /* PDB files generated through VC8 use a new format to store line number information. The + member of the PDB_SYMBOL_FILE_EX header is 0 in this case, but the + member (next member) has a value. It isn't clear if these two have changed to a single + 64-bit value, or if the member has been used as-is. In theory the line number + information for a very poorly laid out compile unit *could* exceed 4GB, but it's highly + unlikely. + Since the format of the new line number info isn't known yet (it's definitely different + from the VC7 line number info block), we'll just spew a fixme here and leave the line + number info blank */ + if (sfile.unknown2 && sfile.lineno_size == 0) + FIXME("line number information is missing, but the mystery information block is present instead\n"); + file_name = (const char*)file + size; file_name += strlen(file_name) + 1; file = (BYTE*)((DWORD)(file_name + strlen(file_name) + 1 + 3) & ~3); } } - else + else{ + ERR("could not read the PDB file. Loading imports instead\n"); + pdb_process_symbol_imports(pcs, msc_dbg, NULL, NULL, image, pdb_lookup, module_index); + } + ret = TRUE; leave: @@ -2259,10 +2515,23 @@ static BOOL pdb_process_file(const struct process* pcs, { BOOL ret; + + + + + memset(cv_zmodules, 0, sizeof(cv_zmodules)); + + TRACE("initializing basic types\n"); codeview_init_basic_types(msc_dbg->module); + + TRACE("processing the PDB file\n"); ret = pdb_process_internal(pcs, msc_dbg, pdb_lookup, -1); + + TRACE("clearing type table\n"); codeview_clear_type_table(); + + TRACE("checking status\n"); if (ret) { msc_dbg->module->module.SymType = SymCv; @@ -2280,7 +2549,13 @@ static BOOL pdb_process_file(const struct process* pcs, msc_dbg->module->module.TypeInfo = TRUE; msc_dbg->module->module.SourceIndexed = TRUE; msc_dbg->module->module.Publics = TRUE; + + TRACE("saved load results\n"); } + + else + TRACE("failed to load the PDB file\n"); + return ret; } @@ -2300,6 +2575,7 @@ BOOL pdb_fetch_file_info(struct pdb_lookup* pdb_lookup) } else { + TRACE("opened .PDB file '%s'\n", pdb_lookup->filename); pdb_init(pdb_lookup, image, TRUE); pdb_free_lookup(pdb_lookup); } @@ -2342,6 +2618,9 @@ static BOOL codeview_process_info(const struct process* pcs, const OMFDirEntry* next; unsigned int i; + + TRACE("found %.4s type of PDB file {filepos = %ld}\n", (const char *)signature, cv->filepos); + codeview_init_basic_types(msc_dbg->module); for (i = 0; i < hdr->cDir; i++) @@ -2356,6 +2635,7 @@ static BOOL codeview_process_info(const struct process* pcs, ctp.module = msc_dbg->module; ctp.offset = (const DWORD*)(types + 1); ctp.num = types->cTypes; + ctp.first = FIRST_DEFINABLE_TYPE; ctp.table = (const BYTE*)(ctp.offset + types->cTypes); cv_current_module = &cv_zmodules[0]; @@ -2418,6 +2698,10 @@ static BOOL codeview_process_info(const struct process* pcs, case CODEVIEW_NB10_SIG: { const CODEVIEW_PDB_DATA* pdb = (const CODEVIEW_PDB_DATA*)msc_dbg->root; + + TRACE("found NB10 type of PDB file {filePos = %ld, timestamp = %d, unknown = %d, name = '%s'}\n", + pdb->filepos, pdb->timestamp, pdb->unknown, pdb->name); + pdb_lookup.filename = pdb->name; pdb_lookup.kind = PDB_JG; pdb_lookup.u.jg.timestamp = pdb->timestamp; @@ -2466,6 +2750,7 @@ BOOL pe_load_debug_directory(const struct process* pcs, struct module* module, int i; struct msc_debug_info msc_dbg; + msc_dbg.module = module; msc_dbg.nsect = nsect; msc_dbg.sectp = sectp; @@ -2476,11 +2761,41 @@ BOOL pe_load_debug_directory(const struct process* pcs, struct module* module, { ret = FALSE; + + TRACE("{pcs = %p, module = %p, mapping = %p, sectp = %p, nsect = %d, dbg = %p, nDbg = %d}\n", + pcs, module, mapping, sectp, nsect, dbg, nDbg); + + for (i = 0; i < nDbg; i++){ + TRACE("debugDirectory[%d]:\n" + " Characteristics = 0x%08x\n" + " TimeDateStamp = %d\n" + " MajorVersion = %d\n" + " MinorVersion = %d\n" + " Type = %d\n" + " SizeOfData = %d\n" + " AddressOfRawData = 0x%08x\n" + " PointerToRawData = 0x%08x\n", + i, + dbg[i].Characteristics, + dbg[i].TimeDateStamp, + dbg[i].MajorVersion, + dbg[i].MinorVersion, + dbg[i].Type, + dbg[i].SizeOfData, + dbg[i].AddressOfRawData, + dbg[i].PointerToRawData); + } + + + /* First, watch out for OMAP data */ + TRACE("checking for OMAP data\n"); for (i = 0; i < nDbg; i++) { if (dbg[i].Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC) { + TRACE("found OMAP data in directory entry %d\n", i); + msc_dbg.nomap = dbg[i].SizeOfData / sizeof(OMAP_DATA); msc_dbg.omapp = (const OMAP_DATA*)(mapping + dbg[i].PointerToRawData); break; @@ -2488,24 +2803,32 @@ BOOL pe_load_debug_directory(const struct process* pcs, struct module* module, } /* Now, try to parse CodeView debug info */ + TRACE("checking for codeview debug info\n"); for (i = 0; i < nDbg; i++) { if (dbg[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW) { + TRACE("found codeview debug info in directory entry %d\n", i); + msc_dbg.root = mapping + dbg[i].PointerToRawData; if ((ret = codeview_process_info(pcs, &msc_dbg))) goto done; } } /* If not found, try to parse COFF debug info */ + TRACE("checking for COFF debug info\n"); for (i = 0; i < nDbg; i++) { if (dbg[i].Type == IMAGE_DEBUG_TYPE_COFF) { + TRACE("found COFF debug info in directory entry %d\n", i); + msc_dbg.root = mapping + dbg[i].PointerToRawData; if ((ret = coff_process_info(&msc_dbg))) goto done; } } + + TRACE("no other supported debug info!\n"); done: /* FIXME: this should be supported... this is the debug information for * functions compiled without a frame pointer (FPO = frame pointer omission) -- 1.4.4.2