diff --git a/debugger/msc.c b/debugger/msc.c index 9ff2964c1d27c426076818ba65792c434c6d2b69..d4869658947eff68d3325d8c543defbd63ea53d9 100644 --- a/debugger/msc.c +++ b/debugger/msc.c @@ -3,7 +3,7 @@ * from PDB files. * * Copyright (C) 1996, Eric Youngdale. - * Copyright (C) 1999, Ulrich Weigand. + * Copyright (C) 1999, 2000, Ulrich Weigand. * * Note - this handles reading debug information for 32 bit applications * that run under Windows-NT for example. I doubt that this would work well @@ -27,20 +27,37 @@ #include "neexe.h" #include "file.h" -typedef struct { - IMAGE_DEBUG_DIRECTORY dbgdir; - u_long sect_ofs; - int nsect; - char* dbg_info; - int dbg_size; + +typedef struct +{ + DWORD from; + DWORD to; + +} OMAP_DATA; + +typedef struct +{ + int nsect; + PIMAGE_SECTION_HEADER sectp; + + int nomap; + OMAP_DATA * omapp; + } MSC_DBG_INFO; #define MSC_INFO(module) ((MSC_DBG_INFO*)((module)->extra_info)) -static int DEBUG_ProcessMSCDebugInfo(DBG_MODULE* module); -/* - * dbg_filename must be at least MAX_PATHNAME_LEN bytes in size + +/*======================================================================== + * Debug file access helper routines + */ + + +/*********************************************************************** + * DEBUG_LocateDebugInfoFile + * + * NOTE: dbg_filename must be at least MAX_PATHNAME_LEN bytes in size */ static void DEBUG_LocateDebugInfoFile(const char *filename, char *dbg_filename) { @@ -112,386 +129,743 @@ static void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, void* addr) if (hFile) CloseHandle(hFile); } -union any_size + + +/*======================================================================== + * Process COFF debug information. + */ + +struct CoffDebug { - char * c; - short * s; - int * i; - unsigned int * ui; + unsigned int N_Sym; + unsigned int SymbolOffset; + unsigned int N_Linenum; + unsigned int LinenumberOffset; + unsigned int Unused[4]; }; -/* - * This is a convenience structure used to map portions of the - * line number table. - */ -struct startend +struct CoffLinenum { - unsigned int start; - unsigned int end; + unsigned int VirtualAddr; + unsigned short Linenum; }; -/* - * This is how we reference the various record types. - */ -union codeview_symbol +struct CoffFiles { - struct - { - short int len; - short int id; - } generic; + unsigned int startaddr; + unsigned int endaddr; + char *filename; + int linetab_offset; + int linecnt; + struct name_hash **entries; + int neps; + int neps_alloc; +}; - struct - { - short int len; - short int id; - unsigned int offset; - unsigned short seg; - unsigned short symtype; - unsigned char namelen; - unsigned char name[1]; - } data; +struct CoffSymbol +{ + union + { + char ShortName[8]; + struct + { + unsigned int NotLong; + unsigned int StrTaboff; + } Name; + } N; + unsigned int Value; + short SectionNumber; + short Type; + char StorageClass; + unsigned char NumberOfAuxSymbols; +}; - struct - { - short int len; - short int id; - unsigned int symtype; - unsigned int offset; - unsigned short seg; - unsigned char namelen; - unsigned char name[1]; - } data32; +struct CoffAuxSection +{ + unsigned int Length; + unsigned short NumberOfRelocations; + unsigned short NumberOfLinenumbers; + unsigned int CheckSum; + short Number; + char Selection; +}; - struct - { - short int len; - short int id; - unsigned int pparent; - unsigned int pend; - unsigned int next; - unsigned int offset; - unsigned short segment; - unsigned short thunk_len; - unsigned char thtype; - unsigned char namelen; - unsigned char name[1]; - } thunk; +static BOOL DEBUG_ProcessCoff( DBG_MODULE *module, LPBYTE root ) +{ + struct CoffAuxSection * aux; + struct CoffDebug * coff; + struct CoffFiles * coff_files = NULL; + struct CoffLinenum * coff_linetab; + char * coff_strtab; + struct CoffSymbol * coff_sym; + struct CoffSymbol * coff_symbol; + struct CoffFiles * curr_file = NULL; + int i; + int j; + int k; + struct CoffLinenum * linepnt; + int linetab_indx; + char namebuff[9]; + char * nampnt; + int naux; + DBG_VALUE new_value; + int nfiles = 0; + int nfiles_alloc = 0; + struct CoffFiles orig_file; + int rtn = FALSE; + char * this_file = NULL; - struct - { - short int len; - short int id; - unsigned int pparent; - unsigned int pend; - unsigned int next; - unsigned int proc_len; - unsigned int debug_start; - unsigned int debug_end; - unsigned int offset; - unsigned short segment; - unsigned short proctype; - unsigned char flags; - unsigned char namelen; - unsigned char name[1]; - } proc; - struct - { - short int len; - short int id; - unsigned int pparent; - unsigned int pend; - unsigned int next; - unsigned int proc_len; - unsigned int debug_start; - unsigned int debug_end; - unsigned int proctype; - unsigned int offset; - unsigned short segment; - unsigned char flags; - unsigned char namelen; - unsigned char name[1]; - } proc32; + DEBUG_Printf(DBG_CHN_TRACE, "Processing COFF symbols...\n"); - struct - { - short int len; /* Total length of this entry */ - short int id; /* Always S_BPREL32 */ - unsigned int offset; /* Stack offset relative to BP */ - unsigned short symtype; - unsigned char namelen; - unsigned char name[1]; - } stack; + coff = (struct CoffDebug *) root; - struct - { - short int len; /* Total length of this entry */ - short int id; /* Always S_BPREL32 */ - unsigned int offset; /* Stack offset relative to BP */ - unsigned int symtype; - unsigned char namelen; - unsigned char name[1]; - } stack32; + coff_symbol = (struct CoffSymbol *) ((unsigned int) coff + coff->SymbolOffset); + coff_linetab = (struct CoffLinenum *) ((unsigned int) coff + coff->LinenumberOffset); + coff_strtab = (char *) ((unsigned int) coff_symbol + 18*coff->N_Sym); -}; + linetab_indx = 0; -union codeview_type -{ - struct - { - short int len; - short int id; - } generic; + new_value.cookie = DV_TARGET; + new_value.type = NULL; - struct - { - short int len; - short int id; - short int attribute; - short int datatype; - unsigned char variant[1]; - } pointer; + for(i=0; i < coff->N_Sym; i++ ) + { + /* + * We do this because some compilers (i.e. gcc) incorrectly + * pad the structure up to a 4 byte boundary. The structure + * is really only 18 bytes long, so we have to manually make sure + * we get it right. + * + * FIXME - there must be a way to have autoconf figure out the + * correct compiler option for this. If it is always gcc, that + * makes life simpler, but I don't want to force this. + */ + coff_sym = (struct CoffSymbol *) ((unsigned int) coff_symbol + 18*i); + naux = coff_sym->NumberOfAuxSymbols; - struct - { - short int len; - short int id; - unsigned int datatype; - unsigned int attribute; - unsigned char variant[1]; - } pointer32; + if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE ) + { + if( nfiles + 1 >= nfiles_alloc ) + { + nfiles_alloc += 10; + coff_files = (struct CoffFiles *) DBG_realloc(coff_files, + nfiles_alloc * sizeof(struct CoffFiles)); + } + curr_file = coff_files + nfiles; + nfiles++; + curr_file->startaddr = 0xffffffff; + curr_file->endaddr = 0; + curr_file->filename = ((char *) coff_sym) + 18; + curr_file->linetab_offset = -1; + curr_file->linecnt = 0; + curr_file->entries = NULL; + curr_file->neps = curr_file->neps_alloc = 0; + DEBUG_Printf(DBG_CHN_TRACE,"New file %s\n", curr_file->filename); + i += naux; + continue; + } - struct - { - short int len; - short int id; - unsigned char nbits; - unsigned char bitoff; - unsigned short type; - } bitfield; + /* + * This guy marks the size and location of the text section + * for the current file. We need to keep track of this so + * we can figure out what file the different global functions + * go with. + */ + if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) + && (naux != 0) + && (coff_sym->Type == 0) + && (coff_sym->SectionNumber == 1) ) + { + aux = (struct CoffAuxSection *) ((unsigned int) coff_sym + 18); - struct - { - short int len; - short int id; - unsigned int type; - unsigned char nbits; - unsigned char bitoff; - } bitfield32; - - struct - { - short int len; - short int id; - short int elemtype; - short int idxtype; - unsigned short int arrlen; /* numeric leaf */ + if( curr_file->linetab_offset != -1 ) + { #if 0 - unsigned char name[1]; + DEBUG_Printf(DBG_CHN_TRACE, "Duplicating sect from %s: %x %x %x %d %d\n", + curr_file->filename, + aux->Length, + aux->NumberOfRelocations, + aux->NumberOfLinenumbers, + aux->Number, + aux->Selection); + DEBUG_Printf(DBG_CHN_TRACE, "More sect %d %x %d %d %d\n", + coff_sym->SectionNumber, + coff_sym->Value, + coff_sym->Type, + coff_sym->StorageClass, + coff_sym->NumberOfAuxSymbols); #endif - } array; - struct - { - short int len; - short int id; - unsigned int elemtype; - unsigned int idxtype; - unsigned short int arrlen; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } array32; + /* + * Save this so we can copy bits from it. + */ + orig_file = *curr_file; - struct - { - short int len; - short int id; - short int n_element; - short int fieldlist; - short int property; - short int derived; - short int vshape; - unsigned short int structlen; /* numeric leaf */ + /* + * Duplicate the file entry. We have no way to describe + * multiple text sections in our current way of handling things. + */ + if( nfiles + 1 >= nfiles_alloc ) + { + nfiles_alloc += 10; + coff_files = (struct CoffFiles *) DBG_realloc(coff_files, + nfiles_alloc * sizeof(struct CoffFiles)); + } + curr_file = coff_files + nfiles; + nfiles++; + curr_file->startaddr = 0xffffffff; + curr_file->endaddr = 0; + curr_file->filename = orig_file.filename; + curr_file->linetab_offset = -1; + curr_file->linecnt = 0; + curr_file->entries = NULL; + curr_file->neps = curr_file->neps_alloc = 0; + } #if 0 - unsigned char name[1]; + else + { + DEBUG_Printf(DBG_CHN_TRACE, "New text sect from %s: %x %x %x %d %d\n", + curr_file->filename, + aux->Length, + aux->NumberOfRelocations, + aux->NumberOfLinenumbers, + aux->Number, + aux->Selection); + } #endif - } structure; - struct - { - short int len; - short int id; - short int n_element; - short int property; - unsigned int fieldlist; - unsigned int derived; - unsigned int vshape; - unsigned short int structlen; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } structure32; + if( curr_file->startaddr > coff_sym->Value ) + { + curr_file->startaddr = coff_sym->Value; + } + + if( curr_file->startaddr > coff_sym->Value ) + { + curr_file->startaddr = coff_sym->Value; + } + + if( curr_file->endaddr < coff_sym->Value + aux->Length ) + { + curr_file->endaddr = coff_sym->Value + aux->Length; + } + + curr_file->linetab_offset = linetab_indx; + curr_file->linecnt = aux->NumberOfLinenumbers; + linetab_indx += aux->NumberOfLinenumbers; + i += naux; + continue; + } - struct - { - short int len; - short int id; - short int count; - short int fieldlist; - short int property; - unsigned short int un_len; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } t_union; + if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) + && (naux == 0) + && (coff_sym->SectionNumber == 1) ) + { + /* + * This is a normal static function when naux == 0. + * Just register it. The current file is the correct + * one in this instance. + */ + if( coff_sym->N.Name.NotLong ) + { + memcpy(namebuff, coff_sym->N.ShortName, 8); + namebuff[8] = '\0'; + nampnt = &namebuff[0]; + } + else + { + nampnt = coff_strtab + coff_sym->N.Name.StrTaboff; + } - struct - { - short int len; - short int id; - short int count; - short int property; - unsigned int fieldlist; - unsigned short int un_len; /* numeric leaf */ + if( nampnt[0] == '_' ) + { + nampnt++; + } + + new_value.addr.seg = 0; + new_value.addr.off = (int) ((char *)module->load_addr + coff_sym->Value); + + if( curr_file->neps + 1 >= curr_file->neps_alloc ) + { + curr_file->neps_alloc += 10; + curr_file->entries = (struct name_hash **) + DBG_realloc(curr_file->entries, + curr_file->neps_alloc * sizeof(struct name_hash *)); + } #if 0 - unsigned char name[1]; + DEBUG_Printf(DBG_CHN_TRACE,"\tAdding static symbol %s\n", nampnt); #endif - } t_union32; + curr_file->entries[curr_file->neps++] = + DEBUG_AddSymbol( nampnt, &new_value, this_file, SYM_WIN32 ); + i += naux; + continue; + } - struct - { - short int len; - short int id; - short int count; - short int type; - short int field; - short int property; - unsigned char name[1]; - } enumeration; + if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) + && ISFCN(coff_sym->Type) + && (coff_sym->SectionNumber > 0) ) + { + if( coff_sym->N.Name.NotLong ) + { + memcpy(namebuff, coff_sym->N.ShortName, 8); + namebuff[8] = '\0'; + nampnt = &namebuff[0]; + } + else + { + nampnt = coff_strtab + coff_sym->N.Name.StrTaboff; + } - struct - { - short int len; - short int id; - short int count; - short int property; - unsigned int type; - unsigned int field; - unsigned char name[1]; - } enumeration32; - struct - { - short int len; - short int id; - unsigned char list[1]; - } fieldlist; -}; + if( nampnt[0] == '_' ) + { + nampnt++; + } -union codeview_fieldtype -{ - struct - { - short int id; - } generic; + new_value.addr.seg = 0; + new_value.addr.off = (int) ((char *)module->load_addr + coff_sym->Value); - struct - { - short int id; - short int type; - short int attribute; - unsigned short int offset; /* numeric leaf */ - } bclass; +#if 0 + DEBUG_Printf(DBG_CHN_TRACE, "%d: %x %s\n", i, new_value.addr.off, nampnt); - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned short int offset; /* numeric leaf */ - } bclass32; + DEBUG_Printf(DBG_CHN_TRACE,"\tAdding global symbol %s\n", nampnt); +#endif + + /* + * Now we need to figure out which file this guy belongs to. + */ + this_file = NULL; + for(j=0; j < nfiles; j++) + { + if( coff_files[j].startaddr <= coff_sym->Value + && coff_files[j].endaddr > coff_sym->Value ) + { + this_file = coff_files[j].filename; + break; + } + } + if( coff_files[j].neps + 1 >= coff_files[j].neps_alloc ) + { + coff_files[j].neps_alloc += 10; + coff_files[j].entries = (struct name_hash **) + DBG_realloc(coff_files[j].entries, + coff_files[j].neps_alloc * sizeof(struct name_hash *)); + } + coff_files[j].entries[coff_files[j].neps++] = + DEBUG_AddSymbol( nampnt, &new_value, this_file, SYM_WIN32 ); + i += naux; + continue; + } + + if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) + && (coff_sym->SectionNumber > 0) ) + { + /* + * Similar to above, but for the case of data symbols. + * These aren't treated as entrypoints. + */ + if( coff_sym->N.Name.NotLong ) + { + memcpy(namebuff, coff_sym->N.ShortName, 8); + namebuff[8] = '\0'; + nampnt = &namebuff[0]; + } + else + { + nampnt = coff_strtab + coff_sym->N.Name.StrTaboff; + } + + + if( nampnt[0] == '_' ) + { + nampnt++; + } + + new_value.addr.seg = 0; + new_value.addr.off = (int) ((char *)module->load_addr + coff_sym->Value); - struct - { - short int id; - short int btype; - short int vbtype; - short int attribute; - unsigned short int vbpoff; /* numeric leaf */ #if 0 - unsigned short int vboff; /* numeric leaf */ + DEBUG_Printf(DBG_CHN_TRACE, "%d: %x %s\n", i, new_value.addr.off, nampnt); + + DEBUG_Printf(DBG_CHN_TRACE,"\tAdding global data symbol %s\n", nampnt); #endif - } vbclass; + + /* + * Now we need to figure out which file this guy belongs to. + */ + DEBUG_AddSymbol( nampnt, &new_value, NULL, SYM_WIN32 ); + i += naux; + continue; + } + + if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) + && (naux == 0) ) + { + /* + * Ignore these. They don't have anything to do with + * reality. + */ + i += naux; + continue; + } + +#if 0 + DEBUG_Printf(DBG_CHN_TRACE,"Skipping unknown entry %d %d %d\n", coff_sym->StorageClass, + coff_sym->SectionNumber, naux); +#endif + + /* + * For now, skip past the aux entries. + */ + i += naux; + + } + + /* + * OK, we now should have a list of files, and we should have a list + * of entrypoints. We need to sort the entrypoints so that we are + * able to tie the line numbers with the given functions within the + * file. + */ + if( coff_files != NULL ) + { + for(j=0; j < nfiles; j++) + { + if( coff_files[j].entries != NULL ) + { + qsort(coff_files[j].entries, coff_files[j].neps, + sizeof(struct name_hash *), DEBUG_cmp_sym); + } + } + + /* + * Now pick apart the line number tables, and attach the entries + * to the given functions. + */ + for(j=0; j < nfiles; j++) + { + i = 0; + if( coff_files[j].neps != 0 ) + for(k=0; k < coff_files[j].linecnt; k++) + { + /* + * Another monstrosity caused by the fact that we are using + * a 6 byte structure, and gcc wants to pad structures to 4 byte + * boundaries. Otherwise we could just index into an array. + */ + linepnt = (struct CoffLinenum *) + ((unsigned int) coff_linetab + + 6*(coff_files[j].linetab_offset + k)); + /* + * If we have spilled onto the next entrypoint, then + * bump the counter.. + */ + while(TRUE) + { + if (i+1 >= coff_files[j].neps) break; + DEBUG_GetSymbolAddr(coff_files[j].entries[i+1], &new_value.addr); + if( (((unsigned int)module->load_addr + + linepnt->VirtualAddr) >= new_value.addr.off) ) + { + i++; + } else break; + } + + /* + * Add the line number. This is always relative to the + * start of the function, so we need to subtract that offset + * first. + */ + DEBUG_GetSymbolAddr(coff_files[j].entries[i], &new_value.addr); + DEBUG_AddLineNumber(coff_files[j].entries[i], + linepnt->Linenum, + (unsigned int) module->load_addr + + linepnt->VirtualAddr + - new_value.addr.off); + } + } + } + + rtn = TRUE; + + if( coff_files != NULL ) + { + for(j=0; j < nfiles; j++) + { + if( coff_files[j].entries != NULL ) + { + DBG_free(coff_files[j].entries); + } + } + DBG_free(coff_files); + } + + return (rtn); + +} + + + +/*======================================================================== + * Process CodeView type information. + */ + +union codeview_type +{ + struct + { + short int len; + short int id; + } generic; struct { + short int len; short int id; short int attribute; - unsigned int btype; - unsigned int vbtype; - unsigned short int vbpoff; /* numeric leaf */ -#if 0 - unsigned short int vboff; /* numeric leaf */ -#endif - } vbclass32; + short int datatype; + unsigned char variant[1]; + } pointer; struct { + short int len; short int id; - short int attribute; - unsigned short int value; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } enumerate; + unsigned int datatype; + unsigned int attribute; + unsigned char variant[1]; + } pointer32; struct { + short int len; short int id; - short int type; - unsigned char name[1]; - } friendfcn; + unsigned char nbits; + unsigned char bitoff; + unsigned short type; + } bitfield; struct { + short int len; short int id; - short int _pad0; unsigned int type; - unsigned char name[1]; - } friendfcn32; + unsigned char nbits; + unsigned char bitoff; + } bitfield32; struct { + short int len; short int id; - short int type; - short int attribute; - unsigned short int offset; /* numeric leaf */ + short int elemtype; + short int idxtype; + unsigned short int arrlen; /* numeric leaf */ #if 0 unsigned char name[1]; #endif - } member; + } array; struct { + short int len; short int id; - short int attribute; - unsigned int type; - unsigned short int offset; /* numeric leaf */ + unsigned int elemtype; + unsigned int idxtype; + unsigned short int arrlen; /* numeric leaf */ #if 0 unsigned char name[1]; #endif - } member32; + } array32; struct { + short int len; short int id; - short int type; - short int attribute; + short int n_element; + short int fieldlist; + short int property; + short int derived; + short int vshape; + unsigned short int structlen; /* numeric leaf */ +#if 0 unsigned char name[1]; - } stmember; - +#endif + } structure; + + struct + { + short int len; + short int id; + short int n_element; + short int property; + unsigned int fieldlist; + unsigned int derived; + unsigned int vshape; + unsigned short int structlen; /* numeric leaf */ +#if 0 + unsigned char name[1]; +#endif + } structure32; + + struct + { + short int len; + short int id; + short int count; + short int fieldlist; + short int property; + unsigned short int un_len; /* numeric leaf */ +#if 0 + unsigned char name[1]; +#endif + } t_union; + + struct + { + short int len; + short int id; + short int count; + short int property; + unsigned int fieldlist; + unsigned short int un_len; /* numeric leaf */ +#if 0 + unsigned char name[1]; +#endif + } t_union32; + + struct + { + short int len; + short int id; + short int count; + short int type; + short int field; + short int property; + unsigned char name[1]; + } enumeration; + + struct + { + short int len; + short int id; + short int count; + short int property; + unsigned int type; + unsigned int field; + unsigned char name[1]; + } enumeration32; + + struct + { + short int len; + short int id; + unsigned char list[1]; + } fieldlist; +}; + +union codeview_fieldtype +{ + struct + { + short int id; + } generic; + + struct + { + short int id; + short int type; + short int attribute; + unsigned short int offset; /* numeric leaf */ + } bclass; + + struct + { + short int id; + short int attribute; + unsigned int type; + unsigned short int offset; /* numeric leaf */ + } bclass32; + + struct + { + short int id; + short int btype; + short int vbtype; + short int attribute; + unsigned short int vbpoff; /* numeric leaf */ +#if 0 + unsigned short int vboff; /* numeric leaf */ +#endif + } vbclass; + + struct + { + short int id; + short int attribute; + unsigned int btype; + unsigned int vbtype; + unsigned short int vbpoff; /* numeric leaf */ +#if 0 + unsigned short int vboff; /* numeric leaf */ +#endif + } vbclass32; + + struct + { + short int id; + short int attribute; + unsigned short int value; /* numeric leaf */ +#if 0 + unsigned char name[1]; +#endif + } enumerate; + + struct + { + short int id; + short int type; + unsigned char name[1]; + } friendfcn; + + struct + { + short int id; + short int _pad0; + unsigned int type; + unsigned char name[1]; + } friendfcn32; + + struct + { + short int id; + short int type; + short int attribute; + unsigned short int offset; /* numeric leaf */ +#if 0 + unsigned char name[1]; +#endif + } member; + + struct + { + short int id; + short int attribute; + unsigned int type; + unsigned short int offset; /* numeric leaf */ +#if 0 + unsigned char name[1]; +#endif + } member32; + + struct + { + short int id; + short int type; + short int attribute; + unsigned char name[1]; + } stmember; + struct { short int id; @@ -630,59 +1004,6 @@ union codeview_fieldtype } membermodify; }; -#define S_COMPILE 0x0001 -#define S_REGISTER 0x0002 -#define S_CONSTANT 0x0003 -#define S_UDT 0x0004 -#define S_SSEARCH 0x0005 -#define S_END 0x0006 -#define S_SKIP 0x0007 -#define S_CVRESERVE 0x0008 -#define S_OBJNAME 0x0009 -#define S_ENDARG 0x000a -#define S_COBOLUDT 0x000b -#define S_MANYREG 0x000c -#define S_RETURN 0x000d -#define S_ENTRYTHIS 0x000e - -#define S_BPREL 0x0200 -#define S_LDATA 0x0201 -#define S_GDATA 0x0202 -#define S_PUB 0x0203 -#define S_LPROC 0x0204 -#define S_GPROC 0x0205 -#define S_THUNK 0x0206 -#define S_BLOCK 0x0207 -#define S_WITH 0x0208 -#define S_LABEL 0x0209 -#define S_CEXMODEL 0x020a -#define S_VFTPATH 0x020b -#define S_REGREL 0x020c -#define S_LTHREAD 0x020d -#define S_GTHREAD 0x020e - -#define S_PROCREF 0x0400 -#define S_DATAREF 0x0401 -#define S_ALIGN 0x0402 -#define S_LPROCREF 0x0403 - -#define S_REGISTER_32 0x1001 /* Variants with new 32-bit type indices */ -#define S_CONSTANT_32 0x1002 -#define S_UDT_32 0x1003 -#define S_COBOLUDT_32 0x1004 -#define S_MANYREG_32 0x1005 - -#define S_BPREL_32 0x1006 -#define S_LDATA_32 0x1007 -#define S_GDATA_32 0x1008 -#define S_PUB_32 0x1009 -#define S_LPROC_32 0x100a -#define S_GPROC_32 0x100b -#define S_VFTTABLE_32 0x100c -#define S_REGREL_32 0x100d -#define S_LTHREAD_32 0x100e -#define S_GTHREAD_32 0x100f - /* * This covers the basic datatypes that VC++ seems to be using these days. @@ -725,6 +1046,7 @@ union codeview_fieldtype #define T_32PINT4 0x0474 /* 16:32 near pointer to int */ #define T_32PUINT4 0x0475 /* 16:32 near pointer to unsigned int */ + #define LF_MODIFIER 0x0001 #define LF_POINTER 0x0002 #define LF_ARRAY 0x0003 @@ -848,120 +1170,47 @@ static struct datatype * cv_basic_types[MAX_BUILTIN_TYPES]; static int num_cv_defined_types = 0; static struct datatype **cv_defined_types = NULL; -/* - * For the type CODEVIEW debug directory entries, the debug directory - * points to a structure like this. The cv_name field is the name - * of an external .PDB file. - */ -struct CodeViewDebug +void +DEBUG_InitCVDataTypes(void) { - char cv_nbtype[8]; - unsigned int cv_timestamp; - char cv_unknown[4]; - char cv_name[1]; -}; - -struct MiscDebug { - unsigned int DataType; - unsigned int Length; - char Unicode; - char Reserved[3]; - char Data[1]; -}; - -/* - * This is the header that the COFF variety of debug header points to. - */ -struct CoffDebug { - unsigned int N_Sym; - unsigned int SymbolOffset; - unsigned int N_Linenum; - unsigned int LinenumberOffset; - unsigned int Unused[4]; -}; - -struct CoffLinenum { - unsigned int VirtualAddr; - unsigned short int Linenum; -}; - -struct CoffFiles { - unsigned int startaddr; - unsigned int endaddr; - char * filename; - int linetab_offset; - int linecnt; - struct name_hash **entries; - int neps; - int neps_alloc; -}; - - -struct CoffSymbol { - union { - char ShortName[8]; - struct { - unsigned int NotLong; - unsigned int StrTaboff; - } Name; - } N; - unsigned int Value; - short SectionNumber; - short Type; - char StorageClass; - unsigned char NumberOfAuxSymbols; -}; - -struct CoffAuxSection{ - unsigned int Length; - unsigned short NumberOfRelocations; - unsigned short NumberOfLinenumbers; - unsigned int CheckSum; - short Number; - char Selection; -} Section; - -/* - * These two structures are used in the directory within a .DBG file - * to locate the individual important bits that we might want to see. - */ -struct CV4_DirHead { - short unsigned int dhsize; - short unsigned int desize; - unsigned int ndir; - unsigned int next_offset; - unsigned int flags; -}; - -struct CV4_DirEnt { - short unsigned int subsect_number; - short unsigned int module_number; - unsigned int offset; - unsigned int size; -}; - -/* - * These are the values of interest that the subsect_number field takes. - */ -#define sstAlignSym 0x125 -#define sstSrcModule 0x127 - -struct codeview_linetab_hdr -{ - unsigned int nline; - unsigned int segno; - unsigned int start; - unsigned int end; - char * sourcefile; - unsigned short * linetab; - unsigned int * offtab; -}; - + /* + * 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] = DEBUG_NewDataType(DT_BASIC, "void"); + cv_basic_types[T_CHAR] = DEBUG_NewDataType(DT_BASIC, "char"); + cv_basic_types[T_SHORT] = DEBUG_NewDataType(DT_BASIC, "short int"); + cv_basic_types[T_LONG] = DEBUG_NewDataType(DT_BASIC, "long int"); + cv_basic_types[T_QUAD] = DEBUG_NewDataType(DT_BASIC, "long long int"); + cv_basic_types[T_UCHAR] = DEBUG_NewDataType(DT_BASIC, "unsigned char"); + cv_basic_types[T_USHORT] = DEBUG_NewDataType(DT_BASIC, "short unsigned int"); + cv_basic_types[T_ULONG] = DEBUG_NewDataType(DT_BASIC, "long unsigned int"); + cv_basic_types[T_UQUAD] = DEBUG_NewDataType(DT_BASIC, "long long unsigned int"); + cv_basic_types[T_REAL32] = DEBUG_NewDataType(DT_BASIC, "float"); + cv_basic_types[T_REAL64] = DEBUG_NewDataType(DT_BASIC, "double"); + cv_basic_types[T_RCHAR] = DEBUG_NewDataType(DT_BASIC, "char"); + cv_basic_types[T_WCHAR] = DEBUG_NewDataType(DT_BASIC, "short"); + cv_basic_types[T_INT4] = DEBUG_NewDataType(DT_BASIC, "int"); + cv_basic_types[T_UINT4] = DEBUG_NewDataType(DT_BASIC, "unsigned int"); + cv_basic_types[T_32PVOID] = DEBUG_FindOrMakePointerType(cv_basic_types[T_VOID]); + cv_basic_types[T_32PCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_CHAR]); + cv_basic_types[T_32PSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_SHORT]); + cv_basic_types[T_32PLONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_LONG]); + cv_basic_types[T_32PQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_QUAD]); + cv_basic_types[T_32PUCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UCHAR]); + cv_basic_types[T_32PUSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_USHORT]); + cv_basic_types[T_32PULONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_ULONG]); + cv_basic_types[T_32PUQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UQUAD]); + cv_basic_types[T_32PREAL32] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL32]); + cv_basic_types[T_32PREAL64] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL64]); + cv_basic_types[T_32PRCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_RCHAR]); + cv_basic_types[T_32PWCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_WCHAR]); + cv_basic_types[T_32PINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_INT4]); + cv_basic_types[T_32PUINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UINT4]); +} -/* - * CodeView type information parsing - */ static int numeric_leaf( int *value, unsigned short int *leaf ) @@ -1544,642 +1793,49 @@ DEBUG_ParseTypeTable( char *table, int len ) break; } - if ( !retv ) - return FALSE; - - curr_type++; - ptr += type->generic.len + 2; - } - - return TRUE; -} - - -void -DEBUG_InitCVDataTypes(void) -{ - /* - * 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] = DEBUG_NewDataType(DT_BASIC, "void"); - cv_basic_types[T_CHAR] = DEBUG_NewDataType(DT_BASIC, "char"); - cv_basic_types[T_SHORT] = DEBUG_NewDataType(DT_BASIC, "short int"); - cv_basic_types[T_LONG] = DEBUG_NewDataType(DT_BASIC, "long int"); - cv_basic_types[T_QUAD] = DEBUG_NewDataType(DT_BASIC, "long long int"); - cv_basic_types[T_UCHAR] = DEBUG_NewDataType(DT_BASIC, "unsigned char"); - cv_basic_types[T_USHORT] = DEBUG_NewDataType(DT_BASIC, "short unsigned int"); - cv_basic_types[T_ULONG] = DEBUG_NewDataType(DT_BASIC, "long unsigned int"); - cv_basic_types[T_UQUAD] = DEBUG_NewDataType(DT_BASIC, "long long unsigned int"); - cv_basic_types[T_REAL32] = DEBUG_NewDataType(DT_BASIC, "float"); - cv_basic_types[T_REAL64] = DEBUG_NewDataType(DT_BASIC, "double"); - cv_basic_types[T_RCHAR] = DEBUG_NewDataType(DT_BASIC, "char"); - cv_basic_types[T_WCHAR] = DEBUG_NewDataType(DT_BASIC, "short"); - cv_basic_types[T_INT4] = DEBUG_NewDataType(DT_BASIC, "int"); - cv_basic_types[T_UINT4] = DEBUG_NewDataType(DT_BASIC, "unsigned int"); - - cv_basic_types[T_32PVOID] = DEBUG_FindOrMakePointerType(cv_basic_types[T_VOID]); - cv_basic_types[T_32PCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_CHAR]); - cv_basic_types[T_32PSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_SHORT]); - cv_basic_types[T_32PLONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_LONG]); - cv_basic_types[T_32PQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_QUAD]); - cv_basic_types[T_32PUCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UCHAR]); - cv_basic_types[T_32PUSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_USHORT]); - cv_basic_types[T_32PULONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_ULONG]); - cv_basic_types[T_32PUQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UQUAD]); - cv_basic_types[T_32PREAL32] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL32]); - cv_basic_types[T_32PREAL64] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL64]); - cv_basic_types[T_32PRCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_RCHAR]); - cv_basic_types[T_32PWCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_WCHAR]); - cv_basic_types[T_32PINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_INT4]); - cv_basic_types[T_32PUINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UINT4]); -} - -/* - * In this function, we keep track of deferred debugging information - * that we may need later if we were to need to use the internal debugger. - * We don't fully process it here for performance reasons. - */ -int -DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile, void* _nth, unsigned long nth_ofs) -{ - int has_codeview = FALSE; - int rtn = FALSE; - IMAGE_DEBUG_DIRECTORY dbg; - u_long v_addr, size, orig_size; - PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth; - - orig_size = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; - if (orig_size) { - v_addr = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; - for(size = orig_size; size >= sizeof(dbg); size -= sizeof(dbg)) - { - if (!DEBUG_READ_MEM_VERBOSE((void*)((char *) module->load_addr + v_addr), &dbg, sizeof(dbg))) continue; - - switch(dbg.Type) - { - case IMAGE_DEBUG_TYPE_CODEVIEW: - case IMAGE_DEBUG_TYPE_MISC: - has_codeview = TRUE; - break; - } - v_addr += sizeof(dbg); - } - - v_addr = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; - for(size = orig_size; size >= sizeof(dbg); size -= sizeof(dbg)) - { - if (!DEBUG_READ_MEM_VERBOSE((void*)((char *)module->load_addr + v_addr), &dbg, sizeof(dbg))) continue; - - switch(dbg.Type) - { - case IMAGE_DEBUG_TYPE_COFF: - /* - * If we have both codeview and COFF debug info, ignore the - * coff debug info as it would just confuse us, and it is - * less complete. - * - * FIXME - this is broken - if we cannot find the PDB file, then - * we end up with no debugging info at all. In this case, we - * should use the COFF info as a backup. - */ - if( has_codeview ) - { - break; - } - case IMAGE_DEBUG_TYPE_CODEVIEW: - case IMAGE_DEBUG_TYPE_MISC: - /* - * This is usually an indirection to a .DBG file. - * This is similar to (but a slightly older format) from the - * PDB file. - * - * First check to see if the image was 'stripped'. If so, it - * means that this entry points to a .DBG file. Otherwise, - * it just points to itself, and we can ignore this. - */ - - if( (dbg.Type != IMAGE_DEBUG_TYPE_MISC) || - (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) != 0 ) - { - /* - * Read the important bits. What we do after this depends - * upon the type, but this is always enough so we are able - * to proceed if we know what we need to do next. - */ - /* basically, the PE loader maps all sections (data, resources...), but doesn't map - * the DataDirectory array's content. One its entry contains the *beloved* - * debug information. (Note the DataDirectory is mapped, not its content) - */ - HANDLE hMap; - char* dbg_info; - - DEBUG_Printf(DBG_CHN_TRACE, "PE debugging info at %ld<%ld>\n", dbg.PointerToRawData, dbg.SizeOfData); - dbg_info = DEBUG_MapDebugInfoFile(NULL, dbg.PointerToRawData, dbg.SizeOfData, - &hFile, &hMap); - - if (dbg_info != NULL && - (module->extra_info = DBG_alloc(sizeof(MSC_DBG_INFO))) != NULL) { - MSC_INFO(module)->dbg_info = dbg_info; - MSC_INFO(module)->dbg_size = dbg.SizeOfData; - MSC_INFO(module)->dbgdir = dbg; - MSC_INFO(module)->sect_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) + - nth->FileHeader.SizeOfOptionalHeader; - MSC_INFO(module)->nsect = nth->FileHeader.NumberOfSections; - DEBUG_ProcessMSCDebugInfo(module); - DBG_free(MSC_INFO(module)); - MSC_INFO(module) = NULL; - } - DEBUG_UnmapDebugInfoFile(0, hMap, dbg_info); - } - break; -#if 0 - default: -#endif - } - v_addr += sizeof(dbg); - } - DEBUG_CurrProcess->next_index++; - } - - return rtn; -} - -/* look for stabs information in PE header (it's how mingw compiler provides its - * debugging information), and also wine PE <-> ELF linking thru .wsolnk sections - */ -int DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile, void* _nth, - unsigned long nth_ofs) -{ - IMAGE_SECTION_HEADER pe_seg; - unsigned long pe_seg_ofs; - int i, stabsize = 0, stabstrsize = 0; - unsigned int stabs = 0, stabstr = 0; - PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth; - - pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) + - nth->FileHeader.SizeOfOptionalHeader; - - for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) { - if (!DEBUG_READ_MEM_VERBOSE((void*)((char *)module->load_addr + pe_seg_ofs), - &pe_seg, sizeof(pe_seg))) - continue; - - if (!strcasecmp(pe_seg.Name, ".stab")) { - stabs = pe_seg.VirtualAddress; - stabsize = pe_seg.SizeOfRawData; - } else if (!strncasecmp(pe_seg.Name, ".stabstr", 8)) { - stabstr = pe_seg.VirtualAddress; - stabstrsize = pe_seg.SizeOfRawData; - } - } - - if (stabstrsize && stabsize) { - char* s1 = DBG_alloc(stabsize+stabstrsize); - - if (s1) { - if (DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabs, s1, stabsize) && - DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabstr, - s1 + stabsize, stabstrsize)) { - DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize); - } else { - DEBUG_Printf(DBG_CHN_MESG, "couldn't read data block\n"); - } - DBG_free(s1); - } else { - DEBUG_Printf(DBG_CHN_MESG, "couldn't alloc %d bytes\n", - stabsize + stabstrsize); - } - } - return TRUE; -} - -/* - * Process COFF debugging information embedded in a Win32 application. - * - */ -static -int -DEBUG_ProcessCoff(DBG_MODULE* module) -{ - struct CoffAuxSection * aux; - struct CoffDebug * coff; - struct CoffFiles * coff_files = NULL; - struct CoffLinenum * coff_linetab; - char * coff_strtab; - struct CoffSymbol * coff_sym; - struct CoffSymbol * coff_symbol; - struct CoffFiles * curr_file = NULL; - int i; - int j; - int k; - struct CoffLinenum * linepnt; - int linetab_indx; - char namebuff[9]; - char * nampnt; - int naux; - DBG_VALUE new_value; - int nfiles = 0; - int nfiles_alloc = 0; - struct CoffFiles orig_file; - int rtn = FALSE; - char * this_file = NULL; - - coff = (struct CoffDebug *) MSC_INFO(module)->dbg_info; - - coff_symbol = (struct CoffSymbol *) ((unsigned int) coff + coff->SymbolOffset); - coff_linetab = (struct CoffLinenum *) ((unsigned int) coff + coff->LinenumberOffset); - coff_strtab = (char *) ((unsigned int) coff_symbol + 18*coff->N_Sym); - - linetab_indx = 0; - - new_value.cookie = DV_TARGET; - new_value.type = NULL; - - for(i=0; i < coff->N_Sym; i++ ) - { - /* - * We do this because some compilers (i.e. gcc) incorrectly - * pad the structure up to a 4 byte boundary. The structure - * is really only 18 bytes long, so we have to manually make sure - * we get it right. - * - * FIXME - there must be a way to have autoconf figure out the - * correct compiler option for this. If it is always gcc, that - * makes life simpler, but I don't want to force this. - */ - coff_sym = (struct CoffSymbol *) ((unsigned int) coff_symbol + 18*i); - naux = coff_sym->NumberOfAuxSymbols; - - if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE ) - { - if( nfiles + 1 >= nfiles_alloc ) - { - nfiles_alloc += 10; - coff_files = (struct CoffFiles *) DBG_realloc(coff_files, - nfiles_alloc * sizeof(struct CoffFiles)); - } - curr_file = coff_files + nfiles; - nfiles++; - curr_file->startaddr = 0xffffffff; - curr_file->endaddr = 0; - curr_file->filename = ((char *) coff_sym) + 18; - curr_file->linetab_offset = -1; - curr_file->linecnt = 0; - curr_file->entries = NULL; - curr_file->neps = curr_file->neps_alloc = 0; - DEBUG_Printf(DBG_CHN_TRACE,"New file %s\n", curr_file->filename); - i += naux; - continue; - } - - /* - * This guy marks the size and location of the text section - * for the current file. We need to keep track of this so - * we can figure out what file the different global functions - * go with. - */ - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) - && (naux != 0) - && (coff_sym->Type == 0) - && (coff_sym->SectionNumber == 1) ) - { - aux = (struct CoffAuxSection *) ((unsigned int) coff_sym + 18); - - if( curr_file->linetab_offset != -1 ) - { -#if 0 - DEBUG_Printf(DBG_CHN_TRACE, "Duplicating sect from %s: %x %x %x %d %d\n", - curr_file->filename, - aux->Length, - aux->NumberOfRelocations, - aux->NumberOfLinenumbers, - aux->Number, - aux->Selection); - DEBUG_Printf(DBG_CHN_TRACE, "More sect %d %x %d %d %d\n", - coff_sym->SectionNumber, - coff_sym->Value, - coff_sym->Type, - coff_sym->StorageClass, - coff_sym->NumberOfAuxSymbols); -#endif - - /* - * Save this so we can copy bits from it. - */ - orig_file = *curr_file; - - /* - * Duplicate the file entry. We have no way to describe - * multiple text sections in our current way of handling things. - */ - if( nfiles + 1 >= nfiles_alloc ) - { - nfiles_alloc += 10; - coff_files = (struct CoffFiles *) DBG_realloc(coff_files, - nfiles_alloc * sizeof(struct CoffFiles)); - } - curr_file = coff_files + nfiles; - nfiles++; - curr_file->startaddr = 0xffffffff; - curr_file->endaddr = 0; - curr_file->filename = orig_file.filename; - curr_file->linetab_offset = -1; - curr_file->linecnt = 0; - curr_file->entries = NULL; - curr_file->neps = curr_file->neps_alloc = 0; - } -#if 0 - else - { - DEBUG_Printf(DBG_CHN_TRACE, "New text sect from %s: %x %x %x %d %d\n", - curr_file->filename, - aux->Length, - aux->NumberOfRelocations, - aux->NumberOfLinenumbers, - aux->Number, - aux->Selection); - } -#endif - - if( curr_file->startaddr > coff_sym->Value ) - { - curr_file->startaddr = coff_sym->Value; - } - - if( curr_file->startaddr > coff_sym->Value ) - { - curr_file->startaddr = coff_sym->Value; - } - - if( curr_file->endaddr < coff_sym->Value + aux->Length ) - { - curr_file->endaddr = coff_sym->Value + aux->Length; - } - - curr_file->linetab_offset = linetab_indx; - curr_file->linecnt = aux->NumberOfLinenumbers; - linetab_indx += aux->NumberOfLinenumbers; - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) - && (naux == 0) - && (coff_sym->SectionNumber == 1) ) - { - /* - * This is a normal static function when naux == 0. - * Just register it. The current file is the correct - * one in this instance. - */ - if( coff_sym->N.Name.NotLong ) - { - memcpy(namebuff, coff_sym->N.ShortName, 8); - namebuff[8] = '\0'; - nampnt = &namebuff[0]; - } - else - { - nampnt = coff_strtab + coff_sym->N.Name.StrTaboff; - } - - if( nampnt[0] == '_' ) - { - nampnt++; - } - - new_value.addr.seg = 0; - new_value.addr.off = (int) ((char *)module->load_addr + coff_sym->Value); - - if( curr_file->neps + 1 >= curr_file->neps_alloc ) - { - curr_file->neps_alloc += 10; - curr_file->entries = (struct name_hash **) - DBG_realloc(curr_file->entries, - curr_file->neps_alloc * sizeof(struct name_hash *)); - } -#if 0 - DEBUG_Printf(DBG_CHN_TRACE,"\tAdding static symbol %s\n", nampnt); -#endif - curr_file->entries[curr_file->neps++] = - DEBUG_AddSymbol( nampnt, &new_value, this_file, SYM_WIN32 ); - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) - && ISFCN(coff_sym->Type) - && (coff_sym->SectionNumber > 0) ) - { - if( coff_sym->N.Name.NotLong ) - { - memcpy(namebuff, coff_sym->N.ShortName, 8); - namebuff[8] = '\0'; - nampnt = &namebuff[0]; - } - else - { - nampnt = coff_strtab + coff_sym->N.Name.StrTaboff; - } - - - if( nampnt[0] == '_' ) - { - nampnt++; - } - - new_value.addr.seg = 0; - new_value.addr.off = (int) ((char *)module->load_addr + coff_sym->Value); - -#if 0 - DEBUG_Printf(DBG_CHN_TRACE, "%d: %x %s\n", i, new_value.addr.off, nampnt); - - DEBUG_Printf(DBG_CHN_TRACE,"\tAdding global symbol %s\n", nampnt); -#endif - - /* - * Now we need to figure out which file this guy belongs to. - */ - this_file = NULL; - for(j=0; j < nfiles; j++) - { - if( coff_files[j].startaddr <= coff_sym->Value - && coff_files[j].endaddr > coff_sym->Value ) - { - this_file = coff_files[j].filename; - break; - } - } - if( coff_files[j].neps + 1 >= coff_files[j].neps_alloc ) - { - coff_files[j].neps_alloc += 10; - coff_files[j].entries = (struct name_hash **) - DBG_realloc(coff_files[j].entries, - coff_files[j].neps_alloc * sizeof(struct name_hash *)); - } - coff_files[j].entries[coff_files[j].neps++] = - DEBUG_AddSymbol( nampnt, &new_value, this_file, SYM_WIN32 ); - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) - && (coff_sym->SectionNumber > 0) ) - { - /* - * Similar to above, but for the case of data symbols. - * These aren't treated as entrypoints. - */ - if( coff_sym->N.Name.NotLong ) - { - memcpy(namebuff, coff_sym->N.ShortName, 8); - namebuff[8] = '\0'; - nampnt = &namebuff[0]; - } - else - { - nampnt = coff_strtab + coff_sym->N.Name.StrTaboff; - } - - - if( nampnt[0] == '_' ) - { - nampnt++; - } - - new_value.addr.seg = 0; - new_value.addr.off = (int) ((char *)module->load_addr + coff_sym->Value); - -#if 0 - DEBUG_Printf(DBG_CHN_TRACE, "%d: %x %s\n", i, new_value.addr.off, nampnt); - - DEBUG_Printf(DBG_CHN_TRACE,"\tAdding global data symbol %s\n", nampnt); -#endif - - /* - * Now we need to figure out which file this guy belongs to. - */ - DEBUG_AddSymbol( nampnt, &new_value, NULL, SYM_WIN32 ); - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) - && (naux == 0) ) - { - /* - * Ignore these. They don't have anything to do with - * reality. - */ - i += naux; - continue; - } - -#if 0 - DEBUG_Printf(DBG_CHN_TRACE,"Skipping unknown entry %d %d %d\n", coff_sym->StorageClass, - coff_sym->SectionNumber, naux); -#endif - - /* - * For now, skip past the aux entries. - */ - i += naux; - - } - - /* - * OK, we now should have a list of files, and we should have a list - * of entrypoints. We need to sort the entrypoints so that we are - * able to tie the line numbers with the given functions within the - * file. - */ - if( coff_files != NULL ) - { - for(j=0; j < nfiles; j++) - { - if( coff_files[j].entries != NULL ) - { - qsort(coff_files[j].entries, coff_files[j].neps, - sizeof(struct name_hash *), DEBUG_cmp_sym); - } - } - - /* - * Now pick apart the line number tables, and attach the entries - * to the given functions. - */ - for(j=0; j < nfiles; j++) - { - i = 0; - if( coff_files[j].neps != 0 ) - for(k=0; k < coff_files[j].linecnt; k++) - { - /* - * Another monstrosity caused by the fact that we are using - * a 6 byte structure, and gcc wants to pad structures to 4 byte - * boundaries. Otherwise we could just index into an array. - */ - linepnt = (struct CoffLinenum *) - ((unsigned int) coff_linetab + - 6*(coff_files[j].linetab_offset + k)); - /* - * If we have spilled onto the next entrypoint, then - * bump the counter.. - */ - while(TRUE) - { - if (i+1 >= coff_files[j].neps) break; - DEBUG_GetSymbolAddr(coff_files[j].entries[i+1], &new_value.addr); - if( (((unsigned int)module->load_addr + - linepnt->VirtualAddr) >= new_value.addr.off) ) - { - i++; - } else break; - } - - /* - * Add the line number. This is always relative to the - * start of the function, so we need to subtract that offset - * first. - */ - DEBUG_GetSymbolAddr(coff_files[j].entries[i], &new_value.addr); - DEBUG_AddLineNumber(coff_files[j].entries[i], - linepnt->Linenum, - (unsigned int) module->load_addr - + linepnt->VirtualAddr - - new_value.addr.off); - } - } - } - - rtn = TRUE; - - if( coff_files != NULL ) - { - for(j=0; j < nfiles; j++) - { - if( coff_files[j].entries != NULL ) - { - DBG_free(coff_files[j].entries); - } - } - DBG_free(coff_files); - } - - return (rtn); + if ( !retv ) + return FALSE; + curr_type++; + ptr += type->generic.len + 2; + } + + return TRUE; } -/* - * Process a codeview line number table. Digestify the thing so that - * we can easily reference the thing when we process the rest of - * the information. + +/*======================================================================== + * Process CodeView line number information. */ + +union any_size +{ + char * c; + short * s; + int * i; + unsigned int * ui; +}; + +struct startend +{ + unsigned int start; + unsigned int end; +}; + +struct codeview_linetab_hdr +{ + unsigned int nline; + unsigned int segno; + unsigned int start; + unsigned int end; + char * sourcefile; + unsigned short * linetab; + unsigned int * offtab; +}; + static struct codeview_linetab_hdr * -DEBUG_SnarfLinetab(char * linetab, - int size) +DEBUG_SnarfLinetab(char * linetab, + int size) { int file_segcount; char filename[PATH_MAX]; @@ -2277,328 +1933,401 @@ leave: } -static int -DEBUG_SnarfCodeView( DBG_MODULE * module, - char * cv_data, - int size, - struct codeview_linetab_hdr * linetab) -{ - struct name_hash * curr_func = NULL; - struct wine_locals * curr_sym = NULL; - int i; - int j; - int len; - DBG_VALUE new_value; - int nsect; - union any_size ptr; - IMAGE_SECTION_HEADER * sectp; - union codeview_symbol * sym; - char symname[PATH_MAX]; - struct name_hash * thunk_sym = NULL; - - ptr.c = cv_data; - nsect = MSC_INFO(module)->nsect; - sectp = DBG_alloc(sizeof(*sectp) * nsect); - if (!sectp || - !DEBUG_READ_MEM_VERBOSE((char *)module->load_addr + MSC_INFO(module)->sect_ofs, - sectp, sizeof(*sectp) * nsect)) - return FALSE; - /* - * Loop over the different types of records and whenever we - * find something we are interested in, record it and move on. - */ - while( ptr.c - cv_data < size ) +/*======================================================================== + * Process CodeView symbol information. + */ + +union codeview_symbol +{ + struct + { + short int len; + short int id; + } generic; + + struct + { + short int len; + short int id; + unsigned int offset; + unsigned short seg; + unsigned short symtype; + unsigned char namelen; + unsigned char name[1]; + } data; + + struct + { + short int len; + short int id; + unsigned int symtype; + unsigned int offset; + unsigned short seg; + unsigned char namelen; + unsigned char name[1]; + } data32; + + struct + { + short int len; + short int id; + unsigned int pparent; + unsigned int pend; + unsigned int next; + unsigned int offset; + unsigned short segment; + unsigned short thunk_len; + unsigned char thtype; + unsigned char namelen; + unsigned char name[1]; + } thunk; + + struct + { + short int len; + short int id; + unsigned int pparent; + unsigned int pend; + unsigned int next; + unsigned int proc_len; + unsigned int debug_start; + unsigned int debug_end; + unsigned int offset; + unsigned short segment; + unsigned short proctype; + unsigned char flags; + unsigned char namelen; + unsigned char name[1]; + } proc; + + struct + { + short int len; + short int id; + unsigned int pparent; + unsigned int pend; + unsigned int next; + unsigned int proc_len; + unsigned int debug_start; + unsigned int debug_end; + unsigned int proctype; + unsigned int offset; + unsigned short segment; + unsigned char flags; + unsigned char namelen; + unsigned char name[1]; + } proc32; + + struct + { + short int len; /* Total length of this entry */ + short int id; /* Always S_BPREL32 */ + unsigned int offset; /* Stack offset relative to BP */ + unsigned short symtype; + unsigned char namelen; + unsigned char name[1]; + } stack; + + struct + { + short int len; /* Total length of this entry */ + short int id; /* Always S_BPREL32 */ + unsigned int offset; /* Stack offset relative to BP */ + unsigned int symtype; + unsigned char namelen; + unsigned char name[1]; + } stack32; + +}; + +#define S_COMPILE 0x0001 +#define S_REGISTER 0x0002 +#define S_CONSTANT 0x0003 +#define S_UDT 0x0004 +#define S_SSEARCH 0x0005 +#define S_END 0x0006 +#define S_SKIP 0x0007 +#define S_CVRESERVE 0x0008 +#define S_OBJNAME 0x0009 +#define S_ENDARG 0x000a +#define S_COBOLUDT 0x000b +#define S_MANYREG 0x000c +#define S_RETURN 0x000d +#define S_ENTRYTHIS 0x000e + +#define S_BPREL 0x0200 +#define S_LDATA 0x0201 +#define S_GDATA 0x0202 +#define S_PUB 0x0203 +#define S_LPROC 0x0204 +#define S_GPROC 0x0205 +#define S_THUNK 0x0206 +#define S_BLOCK 0x0207 +#define S_WITH 0x0208 +#define S_LABEL 0x0209 +#define S_CEXMODEL 0x020a +#define S_VFTPATH 0x020b +#define S_REGREL 0x020c +#define S_LTHREAD 0x020d +#define S_GTHREAD 0x020e + +#define S_PROCREF 0x0400 +#define S_DATAREF 0x0401 +#define S_ALIGN 0x0402 +#define S_LPROCREF 0x0403 + +#define S_REGISTER_32 0x1001 /* Variants with new 32-bit type indices */ +#define S_CONSTANT_32 0x1002 +#define S_UDT_32 0x1003 +#define S_COBOLUDT_32 0x1004 +#define S_MANYREG_32 0x1005 + +#define S_BPREL_32 0x1006 +#define S_LDATA_32 0x1007 +#define S_GDATA_32 0x1008 +#define S_PUB_32 0x1009 +#define S_LPROC_32 0x100a +#define S_GPROC_32 0x100b +#define S_VFTTABLE_32 0x100c +#define S_REGREL_32 0x100d +#define S_LTHREAD_32 0x100e +#define S_GTHREAD_32 0x100f + + + +static unsigned int +DEBUG_MapCVOffset( DBG_MODULE *module, unsigned int offset ) +{ + int nomap = MSC_INFO(module)->nomap; + OMAP_DATA *omapp = MSC_INFO(module)->omapp; + int i; + + if ( !nomap || !omapp ) + return offset; + + /* FIXME: use binary search */ + for ( i = 0; i < nomap-1; i++ ) + if ( omapp[i].from <= offset && omapp[i+1].from > offset ) + return !omapp[i].to? 0 : omapp[i].to + (offset - omapp[i].from); + + return 0; +} + +static struct name_hash * +DEBUG_AddCVSymbol( DBG_MODULE *module, char *name, int namelen, + int type, int seg, int offset, int size, int cookie, int flags, + struct codeview_linetab_hdr *linetab ) +{ + int nsect = MSC_INFO(module)->nsect; + PIMAGE_SECTION_HEADER sectp = MSC_INFO(module)->sectp; + + struct name_hash *symbol; + char symname[PATH_MAX]; + DBG_VALUE value; + + /* + * Some sanity checks + */ + + if ( !name || !namelen ) + return NULL; + + if ( !seg || seg > nsect ) + return NULL; + + /* + * Convert type, address, and symbol name + */ + value.type = type? DEBUG_GetCVType( type ) : NULL; + value.cookie = cookie; + + value.addr.seg = 0; + value.addr.off = (unsigned int) module->load_addr + + DEBUG_MapCVOffset( module, sectp[seg-1].VirtualAddress + offset ); + + memcpy( symname, name, namelen ); + symname[namelen] = '\0'; + + + /* + * Check whether we have line number information + */ + if ( linetab ) { - sym = (union codeview_symbol *) ptr.c; + for ( ; linetab->linetab; linetab++ ) + if ( linetab->segno == seg + && linetab->start <= offset + && linetab->end > offset ) + break; + + if ( !linetab->linetab ) + linetab = NULL; + } + + + /* + * Create Wine symbol record + */ + symbol = DEBUG_AddSymbol( symname, &value, + linetab? linetab->sourcefile : NULL, flags ); + + if ( size ) + DEBUG_SetSymbolSize( symbol, size ); + + + /* + * Add line numbers if found + */ + if ( linetab ) + { + int i; + for ( i = 0; i < linetab->nline; i++ ) + if ( linetab->offtab[i] >= offset + && linetab->offtab[i] < offset + size ) + { + DEBUG_AddLineNumber( symbol, linetab->linetab[i], + linetab->offtab[i] - offset ); + } + } + + return symbol; +} + +static struct wine_locals * +DEBUG_AddCVLocal( struct name_hash *func, char *name, int namelen, + int type, int offset ) +{ + struct wine_locals *local; + char symname[PATH_MAX]; + + memcpy( symname, name, namelen ); + symname[namelen] = '\0'; + + local = DEBUG_AddLocal( func, 0, offset, 0, 0, symname ); + DEBUG_SetLocalSymbolType( local, DEBUG_GetCVType( type ) ); + + return local; +} + +static int +DEBUG_SnarfCodeView( DBG_MODULE *module, LPBYTE root, int offset, int size, + struct codeview_linetab_hdr *linetab ) +{ + struct name_hash *curr_func = NULL; + int i, length; - if( sym->generic.len - sizeof(int) == (ptr.c - cv_data) ) - { - /* - * This happens when we have indirect symbols that VC++ 4.2 - * sometimes uses when there isn't a line number table. - * We ignore it - we will process and enter all of the - * symbols in the global symbol table anyways, so there - * isn't much point in keeping track of all of this crap. - */ - break; - } - memset(symname, 0, sizeof(symname)); - switch(sym->generic.id) - { + /* + * Loop over the different types of records and whenever we + * find something we are interested in, record it and move on. + */ + for ( i = offset; i < size; i += length ) + { + union codeview_symbol *sym = (union codeview_symbol *)(root + i); + length = sym->generic.len + 2; + + switch ( sym->generic.id ) + { + /* + * Global and local data symbols. We don't associate these + * with any given source file. + */ case S_GDATA: case S_LDATA: case S_PUB: - /* - * First, a couple of sanity checks. - */ - if( sym->data.namelen == 0 ) - { - break; - } - - if( sym->data.seg == 0 || sym->data.seg > nsect ) - { - break; - } - - /* - * Global and local data symbols. We don't associate these - * with any given source file. - */ - - memcpy(symname, sym->data.name, sym->data.namelen); - new_value.addr.seg = 0; - new_value.type = DEBUG_GetCVType(sym->data.symtype); - new_value.addr.off = (unsigned int) module->load_addr + - sectp[sym->data.seg - 1].VirtualAddress + - sym->data.offset; - new_value.cookie = DV_TARGET; - DEBUG_AddSymbol( symname, &new_value, NULL, SYM_WIN32 | SYM_DATA ); - break; + DEBUG_AddCVSymbol( module, sym->data.name, sym->data.namelen, + sym->data.symtype, sym->data.seg, + sym->data.offset, 0, + DV_TARGET, SYM_WIN32 | SYM_DATA, NULL ); + break; case S_GDATA_32: case S_LDATA_32: case S_PUB_32: - /* - * First, a couple of sanity checks. - */ - if( sym->data32.namelen == 0 ) - { - break; - } - - if( sym->data32.seg == 0 || sym->data32.seg > nsect ) - { - break; - } - - /* - * Global and local data symbols. We don't associate these - * with any given source file. - */ - - memcpy(symname, sym->data32.name, sym->data32.namelen); - new_value.addr.seg = 0; - new_value.type = DEBUG_GetCVType(sym->data32.symtype); - new_value.addr.off = (unsigned int) module->load_addr + - sectp[sym->data32.seg - 1].VirtualAddress + - sym->data32.offset; - new_value.cookie = DV_TARGET; - DEBUG_AddSymbol( symname, &new_value, NULL, SYM_WIN32 | SYM_DATA ); - break; + DEBUG_AddCVSymbol( module, sym->data32.name, sym->data32.namelen, + sym->data32.symtype, sym->data32.seg, + sym->data32.offset, 0, + DV_TARGET, SYM_WIN32 | SYM_DATA, NULL ); + break; + + /* + * Sort of like a global function, but it just points + * to a thunk, which is a stupid name for what amounts to + * a PLT slot in the normal jargon that everyone else uses. + */ case S_THUNK: - /* - * Sort of like a global function, but it just points - * to a thunk, which is a stupid name for what amounts to - * a PLT slot in the normal jargon that everyone else uses. - */ - memcpy(symname, sym->thunk.name, sym->thunk.namelen); - new_value.addr.seg = 0; - new_value.type = NULL; - new_value.addr.off = (unsigned int) module->load_addr + - sectp[sym->thunk.segment - 1].VirtualAddress + - sym->thunk.offset; - new_value.cookie = DV_TARGET; - thunk_sym = DEBUG_AddSymbol( symname, &new_value, NULL, - SYM_WIN32 | SYM_FUNC); - DEBUG_SetSymbolSize(thunk_sym, sym->thunk.thunk_len); - break; + DEBUG_AddCVSymbol( module, sym->thunk.name, sym->thunk.namelen, + 0, sym->thunk.segment, + sym->thunk.offset, sym->thunk.thunk_len, + DV_TARGET, SYM_WIN32 | SYM_FUNC, NULL ); + break; + + /* + * Global and static functions. + */ case S_GPROC: case S_LPROC: - /* - * Global and static functions. - */ - memcpy(symname, sym->proc.name, sym->proc.namelen); - new_value.addr.seg = 0; - new_value.type = DEBUG_GetCVType(sym->proc.proctype); - new_value.addr.off = (unsigned int) module->load_addr + - sectp[sym->proc.segment - 1].VirtualAddress + - sym->proc.offset; - new_value.cookie = DV_TARGET; - /* - * See if we can find a segment that this goes with. If so, - * it means that we also may have line number information - * for this function. - */ - for(i=0; linetab && linetab[i].linetab != NULL; i++) - { - if( ((unsigned int) module->load_addr - + sectp[linetab[i].segno - 1].VirtualAddress - + linetab[i].start <= new_value.addr.off) - && ((unsigned int) module->load_addr - + sectp[linetab[i].segno - 1].VirtualAddress - + linetab[i].end > new_value.addr.off) ) - { - break; - } - } - - DEBUG_Normalize(curr_func); - if( !linetab || linetab[i].linetab == NULL ) - { - curr_func = DEBUG_AddSymbol( symname, &new_value, NULL, - SYM_WIN32 | SYM_FUNC); - } - else - { - /* - * First, create the entry. Then dig through the linetab - * and add whatever line numbers are appropriate for this - * function. - */ - curr_func = DEBUG_AddSymbol( symname, &new_value, - linetab[i].sourcefile, - SYM_WIN32 | SYM_FUNC); - for(j=0; j < linetab[i].nline; j++) - { - if( linetab[i].offtab[j] >= sym->proc.offset - && linetab[i].offtab[j] < sym->proc.offset - + sym->proc.proc_len ) - { - DEBUG_AddLineNumber(curr_func, linetab[i].linetab[j], - linetab[i].offtab[j] - sym->proc.offset); - } - } + DEBUG_Normalize( curr_func ); - } + curr_func = DEBUG_AddCVSymbol( module, sym->proc.name, sym->proc.namelen, + sym->proc.proctype, sym->proc.segment, + sym->proc.offset, sym->proc.proc_len, + DV_TARGET, SYM_WIN32 | SYM_FUNC, linetab ); - /* - * Add information about where we should set breakpoints - * in this function. - */ - DEBUG_SetSymbolBPOff(curr_func, sym->proc.debug_start); - DEBUG_SetSymbolSize(curr_func, sym->proc.proc_len); - break; + DEBUG_SetSymbolBPOff( curr_func, sym->proc.debug_start ); + break; case S_GPROC_32: case S_LPROC_32: - /* - * Global and static functions. - */ - memcpy(symname, sym->proc32.name, sym->proc32.namelen); - new_value.addr.seg = 0; - new_value.type = DEBUG_GetCVType(sym->proc32.proctype); - new_value.addr.off = (unsigned int) module->load_addr + - sectp[sym->proc32.segment - 1].VirtualAddress + - sym->proc32.offset; - new_value.cookie = DV_TARGET; - /* - * See if we can find a segment that this goes with. If so, - * it means that we also may have line number information - * for this function. - */ - for(i=0; linetab && linetab[i].linetab != NULL; i++) - { - if( ((unsigned int) module->load_addr - + sectp[linetab[i].segno - 1].VirtualAddress - + linetab[i].start <= new_value.addr.off) - && ((unsigned int) module->load_addr - + sectp[linetab[i].segno - 1].VirtualAddress - + linetab[i].end > new_value.addr.off) ) - { - break; - } - } + DEBUG_Normalize( curr_func ); - DEBUG_Normalize(curr_func); - if( !linetab || linetab[i].linetab == NULL ) - { - curr_func = DEBUG_AddSymbol( symname, &new_value, NULL, - SYM_WIN32 | SYM_FUNC); - } - else - { - /* - * First, create the entry. Then dig through the linetab - * and add whatever line numbers are appropriate for this - * function. - */ - curr_func = DEBUG_AddSymbol( symname, &new_value, - linetab[i].sourcefile, - SYM_WIN32 | SYM_FUNC); - for(j=0; j < linetab[i].nline; j++) - { - if( linetab[i].offtab[j] >= sym->proc32.offset - && linetab[i].offtab[j] < sym->proc32.offset - + sym->proc32.proc_len ) - { - DEBUG_AddLineNumber(curr_func, linetab[i].linetab[j], - linetab[i].offtab[j] - sym->proc32.offset); - } - } + curr_func = DEBUG_AddCVSymbol( module, sym->proc32.name, sym->proc32.namelen, + sym->proc32.proctype, sym->proc32.segment, + sym->proc32.offset, sym->proc32.proc_len, + DV_TARGET, SYM_WIN32 | SYM_FUNC, linetab ); - } + DEBUG_SetSymbolBPOff( curr_func, sym->proc32.debug_start ); + break; - /* - * Add information about where we should set breakpoints - * in this function. - */ - DEBUG_SetSymbolBPOff(curr_func, sym->proc32.debug_start); - DEBUG_SetSymbolSize(curr_func, sym->proc32.proc_len); - break; + + /* + * Function parameters and stack variables. + */ case S_BPREL: - /* - * Function parameters and stack variables. - */ - memcpy(symname, sym->stack.name, sym->stack.namelen); - curr_sym = DEBUG_AddLocal(curr_func, - 0, - sym->stack.offset, - 0, - 0, - symname); - DEBUG_SetLocalSymbolType(curr_sym, DEBUG_GetCVType(sym->stack.symtype)); - - break; + DEBUG_AddCVLocal( curr_func, sym->stack.name, sym->stack.namelen, + sym->stack.symtype, sym->stack.offset ); + break; case S_BPREL_32: - /* - * Function parameters and stack variables. - */ - memcpy(symname, sym->stack32.name, sym->stack32.namelen); - curr_sym = DEBUG_AddLocal(curr_func, - 0, - sym->stack32.offset, - 0, - 0, - symname); - DEBUG_SetLocalSymbolType(curr_sym, DEBUG_GetCVType(sym->stack32.symtype)); - - break; - default: - break; - } + DEBUG_AddCVLocal( curr_func, sym->stack32.name, sym->stack32.namelen, + sym->stack32.symtype, sym->stack32.offset ); + break; - /* - * Adjust pointer to point to next entry, rounding up to a word - * boundary. MS preserving alignment? Stranger things have - * happened. - */ - if( sym->generic.id == S_PROCREF - || sym->generic.id == S_DATAREF - || sym->generic.id == S_LPROCREF ) - { - len = (sym->generic.len + 3) & ~3; - len += ptr.c[16] + 1; - ptr.c += (len + 3) & ~3; - } - else - { - ptr.c += (sym->generic.len + 3) & ~3; - } - } - if( linetab != NULL ) - { - DBG_free(linetab); + /* + * These are special, in that they are always followed by an + * additional length-prefixed string which is *not* included + * into the symbol length count. We need to skip it. + */ + case S_PROCREF: + case S_DATAREF: + case S_LPROCREF: + { + LPBYTE name = (LPBYTE)sym + length; + length += (*name + 1 + 3) & ~3; + break; + } + } } - DBG_free(sectp); - return TRUE; + DEBUG_Normalize( curr_func ); + + if ( linetab ) DBG_free(linetab); + return TRUE; } -/* - * Process PDB file which contains debug information. + +/*======================================================================== + * Process PDB file. */ #pragma pack(1) @@ -2869,7 +2598,7 @@ static void pdb_convert_symbols_header( PDB_SYMBOLS *symbols, } } -static int DEBUG_ProcessPDBFile( DBG_MODULE* module, const char *full_filename ) +static int DEBUG_ProcessPDBFile( DBG_MODULE *module, const char *filename, DWORD timestamp ) { HANDLE hFile, hMap; char *image = NULL; @@ -2883,14 +2612,16 @@ static int DEBUG_ProcessPDBFile( DBG_MODULE* module, const char *full_filename ) int header_size = 0; char *modimage, *file; - DEBUG_Printf(DBG_CHN_TRACE, "Processing PDB file %s\n", full_filename); + DEBUG_Printf( DBG_CHN_TRACE, "Processing PDB file %s\n", filename ); /* * Open and map() .PDB file */ - if ((image = DEBUG_MapDebugInfoFile(full_filename, 0, 0, &hFile, &hMap)) == NULL) { - DEBUG_Printf( DBG_CHN_ERR, "-Unable to peruse .PDB file %s\n", full_filename ); - goto leave; + image = DEBUG_MapDebugInfoFile( filename, 0, 0, &hFile, &hMap ); + if ( !image ) + { + DEBUG_Printf( DBG_CHN_ERR, "-Unable to peruse .PDB file %s\n", filename ); + goto leave; } /* @@ -2946,13 +2677,10 @@ static int DEBUG_ProcessPDBFile( DBG_MODULE* module, const char *full_filename ) * Check .PDB time stamp */ - if ( root->TimeDateStamp - != ((struct CodeViewDebug *)MSC_INFO(module)->dbg_info)->cv_timestamp ) + if ( root->TimeDateStamp != timestamp ) { - /* the timestamp seems to be wrong often (we may read the file wrong)*/ - DEBUG_Printf(DBG_CHN_MESG, "-Wrong time stamp of .PDB file %s (0x%08lx, 0x%08x)\n", - full_filename, root->TimeDateStamp, - ((struct CodeViewDebug *)MSC_INFO(module)->dbg_info)->cv_timestamp); + DEBUG_Printf( DBG_CHN_ERR, "-Wrong time stamp of .PDB file %s (0x%08lx, 0x%08lx)\n", + filename, root->TimeDateStamp, timestamp ); } /* @@ -2978,7 +2706,7 @@ static int DEBUG_ProcessPDBFile( DBG_MODULE* module, const char *full_filename ) modimage = pdb_read_file( image, toc, symbols.gsym_file ); if ( modimage ) { - DEBUG_SnarfCodeView( module, modimage, + DEBUG_SnarfCodeView( module, modimage, 0, toc->file[symbols.gsym_file].size, NULL ); pdb_free( modimage ); } @@ -3021,8 +2749,8 @@ static int DEBUG_ProcessPDBFile( DBG_MODULE* module, const char *full_filename ) linetab = DEBUG_SnarfLinetab( modimage + symbol_size, lineno_size ); if ( symbol_size ) - DEBUG_SnarfCodeView( module, modimage + sizeof(DWORD), - symbol_size - sizeof(DWORD), linetab ); + DEBUG_SnarfCodeView( module, modimage, sizeof(DWORD), + symbol_size, linetab ); pdb_free( modimage ); } @@ -3051,251 +2779,348 @@ static int DEBUG_ProcessPDBFile( DBG_MODULE* module, const char *full_filename ) } -/* - * Process DBG file which contains debug information. + + +/*======================================================================== + * Process CodeView debug information. */ -static -int -DEBUG_ProcessDBGFile(DBG_MODULE* module, const char* filename) -{ - HANDLE hFile, hMap; - char * addr; - PIMAGE_DEBUG_DIRECTORY dbghdr; - DBG_MODULE module2; - MSC_DBG_INFO extra_info2; - int i; - int j; - int nsect; - PIMAGE_SEPARATE_DEBUG_HEADER pdbg = NULL; - IMAGE_SECTION_HEADER * sectp; - - if ((addr = DEBUG_MapDebugInfoFile(filename, 0, 0, &hFile, &hMap)) == NULL) { - DEBUG_Printf(DBG_CHN_ERR, "-Unable to peruse .DBG file %s\n", filename); - goto leave; - } - - pdbg = (PIMAGE_SEPARATE_DEBUG_HEADER) addr; - - if( pdbg->TimeDateStamp != MSC_INFO(module)->dbgdir.TimeDateStamp ) + +#define CODEVIEW_NB09_SIG ( 'N' | ('B' << 8) | ('0' << 16) | ('9' << 24) ) +#define CODEVIEW_NB10_SIG ( 'N' | ('B' << 8) | ('1' << 16) | ('0' << 24) ) +#define CODEVIEW_NB11_SIG ( 'N' | ('B' << 8) | ('1' << 16) | ('1' << 24) ) + +typedef struct _CODEVIEW_HEADER +{ + DWORD dwSignature; + DWORD lfoDirectory; + +} CODEVIEW_HEADER, *PCODEVIEW_HEADER; + +typedef struct _CODEVIEW_PDB_DATA +{ + DWORD timestamp; + DWORD unknown; + CHAR name[ 1 ]; + +} CODEVIEW_PDB_DATA, *PCODEVIEW_PDB_DATA; + +typedef struct _CV_DIRECTORY_HEADER +{ + WORD cbDirHeader; + WORD cbDirEntry; + DWORD cDir; + DWORD lfoNextDir; + DWORD flags; + +} CV_DIRECTORY_HEADER, *PCV_DIRECTORY_HEADER; + +typedef struct _CV_DIRECTORY_ENTRY +{ + WORD subsection; + WORD iMod; + DWORD lfo; + DWORD cb; + +} CV_DIRECTORY_ENTRY, *PCV_DIRECTORY_ENTRY; + + +#define sstAlignSym 0x125 +#define sstSrcModule 0x127 + + +static BOOL DEBUG_ProcessCodeView( DBG_MODULE *module, LPBYTE root ) +{ + PCODEVIEW_HEADER cv = (PCODEVIEW_HEADER)root; + BOOL retv = FALSE; + + switch ( cv->dwSignature ) { - DEBUG_Printf(DBG_CHN_ERR, "Warning - %s has incorrect internal timestamp\n", - filename); -/* goto leave; */ -/* - Well, sometimes this happens to DBG files which ARE REALLY the right .DBG - files but nonetheless this check fails. Anyway, WINDBG (debugger for - Windows by Microsoft) loads debug symbols which have incorrect timestamps. -*/ - } + case CODEVIEW_NB09_SIG: + case CODEVIEW_NB11_SIG: + { + PCV_DIRECTORY_HEADER hdr = (PCV_DIRECTORY_HEADER)(root + cv->lfoDirectory); + PCV_DIRECTORY_ENTRY ent, prev, next; + int i; + + ent = (PCV_DIRECTORY_ENTRY)((LPBYTE)hdr + hdr->cbDirHeader); + for ( i = 0; i < hdr->cDir; i++, ent = next ) + { + next = (i == hdr->cDir-1)? NULL : + (PCV_DIRECTORY_ENTRY)((LPBYTE)ent + hdr->cbDirEntry); + prev = (i == 0)? NULL : + (PCV_DIRECTORY_ENTRY)((LPBYTE)ent - hdr->cbDirEntry); + + if ( ent->subsection == sstAlignSym ) + { + /* + * Check the next and previous entry. If either is a + * sstSrcModule, it contains the line number info for + * this file. + * + * FIXME: This is not a general solution! + */ + struct codeview_linetab_hdr *linetab = NULL; - DEBUG_Printf(DBG_CHN_MESG, "Processing symbols from %s...\n", filename); + if ( next && next->iMod == ent->iMod + && next->subsection == sstSrcModule ) + linetab = DEBUG_SnarfLinetab( root + next->lfo, next->cb ); - dbghdr = (PIMAGE_DEBUG_DIRECTORY) ( addr + sizeof(*pdbg) - + pdbg->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) - + pdbg->ExportedNamesSize); + if ( prev && prev->iMod == ent->iMod + && prev->subsection == sstSrcModule ) + linetab = DEBUG_SnarfLinetab( root + prev->lfo, prev->cb ); + - sectp = (PIMAGE_SECTION_HEADER) ((char *) pdbg + sizeof(*pdbg)); - nsect = pdbg->NumberOfSections; + DEBUG_SnarfCodeView( module, root + ent->lfo, sizeof(DWORD), + ent->cb, linetab ); + } + } - for( i=0; i < pdbg->DebugDirectorySize / sizeof(*pdbg); i++, dbghdr++ ) + retv = TRUE; + break; + } + + case CODEVIEW_NB10_SIG: { - switch(dbghdr->Type) - { - case IMAGE_DEBUG_TYPE_COFF: - /* - * Dummy up a deferred debug header to handle the - * COFF stuff embedded within the DBG file. - */ - memset((char *) &module2, 0, sizeof(module2)); - module2.extra_info = &extra_info2; - MSC_INFO(&module2)->dbg_info = (addr + dbghdr->PointerToRawData); - MSC_INFO(&module2)->dbg_size = dbghdr->SizeOfData; - module2.load_addr = module->load_addr; - - DEBUG_ProcessCoff(&module2); - break; - case IMAGE_DEBUG_TYPE_CODEVIEW: - { - char * codeview; - struct CV4_DirHead * codeview_dir; - struct CV4_DirEnt * codeview_dent; - struct codeview_linetab_hdr * linetab; - struct CodeViewDebug * cvd; - - cvd = (struct CodeViewDebug *) (addr + dbghdr->PointerToRawData); - - /* - * see msdn.microsoft.com/library/specs/S66EA.HTM - * for desriptions of more NBxx formats - */ - if( strcmp(cvd->cv_nbtype, "NB10") == 0 ) - { - /* - * The debug information resides in a seperate pdb file. - * This section contains only a filename. - */ - DEBUG_ProcessPDBFile(module, cvd->cv_name); - } - else if (strcmp(cvd->cv_nbtype, "NB09") == 0 ) - { - /* - * CodeView 4.10 - * This is the older format by which codeview stuff is - * stored, known as the 'NB09' format. Newer executables - * and dlls created by VC++ use PDB files instead, which - * have lots of internal similarities, but the overall - * format and structure is quite different. - */ - codeview = (addr + dbghdr->PointerToRawData); - - - /* - * We need to find the directory. This is easy too. - */ - codeview_dir = (struct CV4_DirHead *) - (codeview + ((unsigned int*) codeview)[1]); - - /* - * Some more sanity checks. Make sure that everything - * is as we expect it. - */ - if( codeview_dir->next_offset != 0 - || codeview_dir->dhsize != sizeof(*codeview_dir) - || codeview_dir->desize != sizeof(*codeview_dent) ) - { - break; - } - codeview_dent = (struct CV4_DirEnt *) (codeview_dir + 1); - - for(j=0; j < codeview_dir->ndir; j++, codeview_dent++) - { - if( codeview_dent->subsect_number == sstAlignSym ) - { - /* - * Check the previous entry. If it is a - * sstSrcModule, it contains the line number - * info for this file. - */ - linetab = NULL; - if( codeview_dent[1].module_number == codeview_dent[0].module_number - && codeview_dent[1].subsect_number == sstSrcModule ) - { - linetab = DEBUG_SnarfLinetab( - codeview + codeview_dent[1].offset, - codeview_dent[1].size); - } - - if( codeview_dent[-1].module_number == codeview_dent[0].module_number - && codeview_dent[-1].subsect_number == sstSrcModule ) - { - linetab = DEBUG_SnarfLinetab( - codeview + codeview_dent[-1].offset, - codeview_dent[-1].size); - } - /* - * Now process the CV stuff. - */ - DEBUG_SnarfCodeView(module, - codeview + codeview_dent->offset + sizeof(DWORD), - codeview_dent->size - sizeof(DWORD), - linetab); - } - } - } - else - { - DEBUG_Printf(DBG_CHN_ERR, "Unknown CODEVIEW type %s in module %s\n", - cvd->cv_nbtype, module->module_name); - } - } - break; - default: - break; - } + PCODEVIEW_PDB_DATA pdb = (PCODEVIEW_PDB_DATA)(cv + 1); + + retv = DEBUG_ProcessPDBFile( module, pdb->name, pdb->timestamp ); + break; } -leave: + + default: + DEBUG_Printf( DBG_CHN_ERR, "Unknown CODEVIEW signature %08lX in module %s\n", + cv->dwSignature, module->module_name ); + break; + } + + return retv; +} + + +/*======================================================================== + * Process debug directory. + */ +static BOOL DEBUG_ProcessDebugDirectory( DBG_MODULE *module, LPBYTE file_map, + PIMAGE_DEBUG_DIRECTORY dbg, int nDbg ) +{ + BOOL retv = FALSE; + int i; + + + /* First, watch out for OMAP data */ + for ( i = 0; i < nDbg; i++ ) + if ( dbg[i].Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC ) + { + MSC_INFO(module)->nomap = dbg[i].SizeOfData / sizeof(OMAP_DATA); + MSC_INFO(module)->omapp = (OMAP_DATA *)(file_map + dbg[i].PointerToRawData); + break; + } - DEBUG_UnmapDebugInfoFile(hFile, hMap, addr); - return TRUE; + /* Now, try to parse CodeView debug info */ + for ( i = 0; !retv && i < nDbg; i++ ) + if ( dbg[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW ) + retv = DEBUG_ProcessCodeView( module, file_map + dbg[i].PointerToRawData ); + + + /* If not found, try to parse COFF debug info */ + for ( i = 0; !retv && i < nDbg; i++ ) + if ( dbg[i].Type == IMAGE_DEBUG_TYPE_COFF ) + retv = DEBUG_ProcessCoff( module, file_map + dbg[i].PointerToRawData ); + + + return retv; } -static int -DEBUG_ProcessMSCDebugInfo(DBG_MODULE* module) + +/*======================================================================== + * Process DBG file. + */ +static BOOL DEBUG_ProcessDBGFile( DBG_MODULE *module, const char *filename, DWORD timestamp ) { - struct CodeViewDebug * cvd; - struct MiscDebug * misc; - char * filename; - int sts; - - switch (MSC_INFO(module)->dbgdir.Type) - { - case IMAGE_DEBUG_TYPE_COFF: - /* - * Standard COFF debug information that VC++ adds when you - * use /debugtype:both with the linker. - */ - DEBUG_Printf(DBG_CHN_TRACE, "Processing COFF symbols...\n"); - sts = DEBUG_ProcessCoff(module); - break; - case IMAGE_DEBUG_TYPE_CODEVIEW: - /* - * This is a pointer to a PDB file of some sort. - */ - cvd = (struct CodeViewDebug *) MSC_INFO(module)->dbg_info; - - if( strcmp(cvd->cv_nbtype, "NB10") != 0 ) - { - /* - * Whatever this is, we don't know how to deal with - * it yet. - */ - sts = FALSE; - DEBUG_Printf(DBG_CHN_ERR, "Unknown CODEVIEW type %s in module %s\n", - cvd->cv_nbtype, module->module_name); - break; - } - sts = DEBUG_ProcessPDBFile(module, cvd->cv_name); - break; - case IMAGE_DEBUG_TYPE_MISC: - /* - * A pointer to a .DBG file of some sort. These files - * can contain either CV4 or COFF information. Open - * the file, and try to do the right thing with it. - */ - misc = (struct MiscDebug *) MSC_INFO(module)->dbg_info; - - filename = strrchr((char *) &misc->Data, '.'); - - /* - * Ignore the file if it doesn't have a .DBG extension. - */ - if( (filename == NULL) - || ( (strcmp(filename, ".dbg") != 0) - && (strcmp(filename, ".DBG") != 0)) ) - { - sts = FALSE; - break; - } - - filename = (char *) &misc->Data; - - /* - * Do the dirty deed... - */ - sts = DEBUG_ProcessDBGFile(module, filename); - - break; - default: - /* - * We should never get here... - */ - sts = FALSE; - break; - } - module->status = (sts) ? DM_STATUS_LOADED : DM_STATUS_ERROR; - return sts; + BOOL retv = FALSE; + HANDLE hFile = 0, hMap = 0; + LPBYTE file_map = NULL; + PIMAGE_SEPARATE_DEBUG_HEADER hdr; + PIMAGE_DEBUG_DIRECTORY dbg; + int nDbg; + + + DEBUG_Printf( DBG_CHN_TRACE, "Processing DBG file %s\n", filename ); + + file_map = DEBUG_MapDebugInfoFile( filename, 0, 0, &hFile, &hMap ); + if ( !file_map ) + { + DEBUG_Printf( DBG_CHN_ERR, "-Unable to peruse .DBG file %s\n", filename ); + goto leave; + } + + hdr = (PIMAGE_SEPARATE_DEBUG_HEADER) file_map; + + if ( hdr->TimeDateStamp != timestamp ) + { + DEBUG_Printf( DBG_CHN_ERR, "Warning - %s has incorrect internal timestamp\n", + filename ); + /* + * Well, sometimes this happens to DBG files which ARE REALLY the right .DBG + * files but nonetheless this check fails. Anyway, WINDBG (debugger for + * Windows by Microsoft) loads debug symbols which have incorrect timestamps. + */ + } + + + dbg = (PIMAGE_DEBUG_DIRECTORY) ( file_map + sizeof(*hdr) + + hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + + hdr->ExportedNamesSize ); + + nDbg = hdr->DebugDirectorySize / sizeof(*dbg); + + retv = DEBUG_ProcessDebugDirectory( module, file_map, dbg, nDbg ); + + + leave: + DEBUG_UnmapDebugInfoFile( hFile, hMap, file_map ); + return retv; +} + + +/*======================================================================== + * Process MSC debug information in PE file. + */ +int DEBUG_RegisterMSCDebugInfo( DBG_MODULE *module, HANDLE hFile, + void *_nth, unsigned long nth_ofs ) +{ + BOOL retv = FALSE; + PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth; + PIMAGE_DATA_DIRECTORY dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG; + PIMAGE_DEBUG_DIRECTORY dbg = NULL; + int nDbg; + MSC_DBG_INFO extra_info = { 0, NULL, 0, NULL }; + HANDLE hMap = 0; + LPBYTE file_map = NULL; + + + /* Read in section data */ + + MSC_INFO(module) = &extra_info; + extra_info.nsect = nth->FileHeader.NumberOfSections; + extra_info.sectp = DBG_alloc( extra_info.nsect * sizeof(IMAGE_SECTION_HEADER) ); + if ( !extra_info.sectp ) + goto leave; + + if ( !DEBUG_READ_MEM_VERBOSE( (char *)module->load_addr + + nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) + + nth->FileHeader.SizeOfOptionalHeader, + extra_info.sectp, + extra_info.nsect * sizeof(IMAGE_SECTION_HEADER) ) ) + goto leave; + + + /* Read in debug directory */ + + nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY); + if ( !nDbg ) + goto leave; + + dbg = (PIMAGE_DEBUG_DIRECTORY) DBG_alloc( nDbg * sizeof(IMAGE_DEBUG_DIRECTORY) ); + if ( !dbg ) + goto leave; + + if ( !DEBUG_READ_MEM_VERBOSE( (char *)module->load_addr + dir->VirtualAddress, + dbg, nDbg * sizeof(IMAGE_DEBUG_DIRECTORY) ) ) + goto leave; + + + /* Map in PE file */ + file_map = DEBUG_MapDebugInfoFile( NULL, 0, 0, &hFile, &hMap ); + if ( !file_map ) + goto leave; + + + /* Parse debug directory */ + + if ( nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED ) + { + /* Debug info is stripped to .DBG file */ + + PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)(file_map + dbg->PointerToRawData); + + if ( nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC + || misc->DataType != IMAGE_DEBUG_MISC_EXENAME ) + { + DEBUG_Printf( DBG_CHN_ERR, "-Debug info stripped, but no .DBG file in module %s\n", + module->module_name ); + goto leave; + } + + retv = DEBUG_ProcessDBGFile( module, misc->Data, nth->FileHeader.TimeDateStamp ); + } + else + { + /* Debug info is embedded into PE module */ + + retv = DEBUG_ProcessDebugDirectory( module, file_map, dbg, nDbg ); + } + + + leave: + module->status = retv ? DM_STATUS_LOADED : DM_STATUS_ERROR; + MSC_INFO(module) = NULL; + + DEBUG_UnmapDebugInfoFile( 0, hMap, file_map ); + if ( extra_info.sectp ) DBG_free( extra_info.sectp ); + if ( dbg ) DBG_free( dbg ); + return retv; } +/*======================================================================== + * look for stabs information in PE header (it's how mingw compiler provides its + * debugging information), and also wine PE <-> ELF linking thru .wsolnk sections + */ +int DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile, void* _nth, + unsigned long nth_ofs) +{ + IMAGE_SECTION_HEADER pe_seg; + unsigned long pe_seg_ofs; + int i, stabsize = 0, stabstrsize = 0; + unsigned int stabs = 0, stabstr = 0; + PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth; + + pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) + + nth->FileHeader.SizeOfOptionalHeader; + + for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) { + if (!DEBUG_READ_MEM_VERBOSE((void*)((char *)module->load_addr + pe_seg_ofs), + &pe_seg, sizeof(pe_seg))) + continue; + + if (!strcasecmp(pe_seg.Name, ".stab")) { + stabs = pe_seg.VirtualAddress; + stabsize = pe_seg.SizeOfRawData; + } else if (!strncasecmp(pe_seg.Name, ".stabstr", 8)) { + stabstr = pe_seg.VirtualAddress; + stabstrsize = pe_seg.SizeOfRawData; + } + } + + if (stabstrsize && stabsize) { + char* s1 = DBG_alloc(stabsize+stabstrsize); + + if (s1) { + if (DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabs, s1, stabsize) && + DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabstr, + s1 + stabsize, stabstrsize)) { + DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize); + } else { + DEBUG_Printf(DBG_CHN_MESG, "couldn't read data block\n"); + } + DBG_free(s1); + } else { + DEBUG_Printf(DBG_CHN_MESG, "couldn't alloc %d bytes\n", + stabsize + stabstrsize); + } + } + return TRUE; +}