From 9e2ba2e8b3f80e582aeffd69042420b544b32a79 Mon Sep 17 00:00:00 2001 From: Jason Green Date: Thu, 17 Jan 2008 17:14:27 -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 From: Eric van Beurden (ericvb@transgaming.com) --- dlls/dbghelp/msc.c | 411 ++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 338 insertions(+), 73 deletions(-) diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 5e6f8a8..f0bd126 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) { @@ -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); @@ -2068,22 +2238,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; } @@ -2184,7 +2397,8 @@ static BOOL pdb_process_internal(const struct process* pcs, 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", @@ -2194,18 +2408,23 @@ static BOOL pdb_process_internal(const struct process* pcs, 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); + /* 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) { 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 */ 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; @@ -2231,6 +2450,20 @@ 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); @@ -2281,6 +2514,9 @@ static BOOL pdb_process_file(const struct process* pcs, msc_dbg->module->module.SourceIndexed = TRUE; msc_dbg->module->module.Publics = TRUE; } + else + TRACE("failed to load the PDB file\n"); + return ret; } @@ -2356,6 +2592,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]; @@ -2476,6 +2713,34 @@ 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); + + if (TRACE_ON(dbghelp_msc)) { + 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 */ for (i = 0; i < nDbg; i++) { -- 1.4.4.2