Commit 6011e98e authored by Ulrich Weigand's avatar Ulrich Weigand Committed by Alexandre Julliard

- Take OMAP records into account to correct symbol addresses.

- Understand CodeView data embedded in the PE file itself. - Understand NB11 signature CodeView data. - No more bogus 'timestamp mismatch' errors. - General cleanup / removal of duplicate code.
parent 1b4c7792
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment