mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
894 lines
24 KiB
894 lines
24 KiB
// PDBDUMP -- Sample Debug Information API application
|
|
// VC++4.0 Read-Only OEM Edition
|
|
// Copyright (C) 1993-1995, Microsoft Corp. All Rights Reserved.
|
|
//
|
|
// Unfinished but still interesting.
|
|
// Pardon the Hungarian...
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <afx.h>
|
|
#include "oemdbi.h"
|
|
|
|
typedef SYMTYPE* PSYM;
|
|
typedef TYPTYPE* PTYPE;
|
|
typedef char* ST; // length prefixed string
|
|
|
|
BOOL dumpFileInfo(DBI* pdbi);
|
|
BOOL dumpGlobals(DBI* pdbi);
|
|
BOOL dumpPublics(DBI* pdbi);
|
|
BOOL dumpGSI(GSI* pgsi);
|
|
void dumpSymsSz(DBI* pdbi, char* sz);
|
|
void dumpLinesSz(DBI* pdbi, char* sz);
|
|
BOOL dumpSymbols(PB pb, CB cb);
|
|
void dumpSymbol(PSYM psym);
|
|
void dumpTpiSz(TPI* ptpi, char* sz);
|
|
void dumpTypes(TPI* ptpi);
|
|
void dumpType(TI ti);
|
|
void dumpMod(Mod* pmod);
|
|
BOOL dumpLines(PB pb, CB cb);
|
|
void dump(PB pb, CB cb, SZ szFmt, ...);
|
|
|
|
enum Bind { bindPtr, bindArray, bindProc, bindNone };
|
|
|
|
PDB* ppdb;
|
|
TPI* ptpi;
|
|
DBI* pdbi;
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (argc != 2) {
|
|
fprintf(stderr, "usage: %s <pdb>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
SZ szPDB = argv[1];
|
|
|
|
EC ec;
|
|
char szErr[cbErrMax];
|
|
if (!PDBOpen(szPDB, pdbRead, 0, &ec, szErr, &ppdb))
|
|
goto fail1;
|
|
|
|
if (!PDBOpenTpi(ppdb, pdbRead, &ptpi))
|
|
goto fail2;
|
|
// dumpTypes(ptpi);
|
|
|
|
if (!PDBOpenDBI(ppdb, pdbRead, "<target>.exe", &pdbi))
|
|
goto fail3;
|
|
dumpFileInfo(pdbi);
|
|
dumpGlobals(pdbi);
|
|
dumpPublics(pdbi);
|
|
|
|
Mod* pmod;
|
|
printf("\nmodules:\nimod name\n");
|
|
for (pmod = 0; DBIQueryNextMod(pdbi, pmod, &pmod) && pmod; ) {
|
|
char szMod[_MAX_PATH];
|
|
CB cb = sizeof(szMod);
|
|
IMOD imod;
|
|
if (ModQueryName(pmod, szMod, &cb) &&
|
|
ModQueryImod(pmod, &imod))
|
|
printf("%4d %s\n", imod, szMod);
|
|
}
|
|
putchar('\n');
|
|
for (pmod = 0; DBIQueryNextMod(pdbi, pmod, &pmod) && pmod; ) {
|
|
// note it's OK to 'QueryNextMod' an open mod
|
|
dumpMod(pmod);
|
|
ModClose(pmod);
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail3:
|
|
DBIClose(pdbi);
|
|
fail2:
|
|
TypesClose(ptpi);
|
|
fail1:
|
|
PDBClose(ppdb);
|
|
return 1;
|
|
}
|
|
|
|
void dumpTypes(TPI* ptpi) {
|
|
TI tiMin = TypesQueryTiMin(ptpi);
|
|
TI tiMac = TypesQueryTiMac(ptpi);
|
|
for (TI ti = tiMin; ti < tiMac; ti++)
|
|
dumpType(ti);
|
|
}
|
|
|
|
BOOL dumpFileInfo(DBI* pdbi) {
|
|
printf("file info:\n");
|
|
CB cb;
|
|
PB pb, pbAlloc;
|
|
if (!DBIQueryFileInfo(pdbi, 0, &cb) ||
|
|
!(pbAlloc = pb = new BYTE[cb]) ||
|
|
!DBIQueryFileInfo(pdbi, pb, &cb))
|
|
return FALSE;
|
|
|
|
IMOD imodMac = *((IMOD*&)pb)++;
|
|
USHORT cRefs = *((USHORT*&)pb)++;
|
|
printf("imodMac:%d cRefs:%d\n", imodMac, cRefs);
|
|
|
|
typedef char* PCH;
|
|
typedef long ICH;
|
|
USHORT* mpimodiref = (USHORT*)pb;
|
|
USHORT* mpimodcref = (USHORT*)((PB)mpimodiref + sizeof(USHORT)*imodMac);
|
|
ICH* mpirefichFile = (ICH*) ((PB)mpimodcref + sizeof(USHORT)*imodMac);
|
|
PCH rgchNames = (PCH) ((PB)mpirefichFile + sizeof(ICH)*cRefs);
|
|
|
|
printf("imod irefS ifile iref ich szFile\n");
|
|
for (IMOD imod = 0; imod < imodMac; imod++) {
|
|
for (UINT diref = 0; diref < mpimodcref[imod]; diref++) {
|
|
char rgch[256];
|
|
UINT iref = mpimodiref[imod] + diref;
|
|
ICH ich = mpirefichFile[iref];
|
|
ICH cch = (BYTE)rgchNames[ich];
|
|
memcpy(rgch, &rgchNames[ich+1], cch);
|
|
rgch[cch] = 0;
|
|
printf("%4d %5d %5d %4d %5d %s\n",
|
|
imod, mpimodiref[imod], diref, iref, ich, rgch);
|
|
}
|
|
}
|
|
|
|
delete [] pbAlloc;
|
|
putchar('\n');
|
|
return TRUE;
|
|
}
|
|
|
|
void dumpMod(Mod* pmod) {
|
|
IMOD imod;
|
|
char szMod[_MAX_PATH];
|
|
CB cbMod = sizeof(szMod);
|
|
CB cbSyms, cbLines;
|
|
PB pbSyms = 0, pbLines = 0;
|
|
if (ModQueryImod(pmod, &imod) &&
|
|
ModQueryName(pmod, szMod, &cbMod) &&
|
|
ModQuerySymbols(pmod, 0, &cbSyms) &&
|
|
(pbSyms = new BYTE[cbSyms]) &&
|
|
ModQuerySymbols(pmod, pbSyms, &cbSyms) &&
|
|
ModQueryLines(pmod, 0, &cbLines) &&
|
|
(pbLines = new BYTE[cbLines]) &&
|
|
ModQueryLines(pmod, pbLines, &cbLines))
|
|
{
|
|
dump(pbSyms, cbSyms, "symbol records for mod %d (%s)", imod, szMod);
|
|
dumpSymbols(pbSyms, cbSyms);
|
|
|
|
dump(pbLines, cbLines, "line numbers for mod %d (%s)", imod, szMod);
|
|
dumpLines(pbLines, cbLines);
|
|
}
|
|
if (pbSyms)
|
|
delete [] pbSyms;
|
|
if (pbLines)
|
|
delete [] pbLines;
|
|
}
|
|
|
|
BOOL dumpGlobals(DBI* pdbi) {
|
|
printf("globals:\n");
|
|
GSI* pgsi;
|
|
return DBIOpenGlobals(pdbi, &pgsi) && dumpGSI(pgsi);
|
|
}
|
|
|
|
BOOL dumpPublics(DBI* pdbi) {
|
|
printf("publics:\n");
|
|
GSI* pgsi;
|
|
return DBIOpenPublics(pdbi, &pgsi) && dumpGSI(pgsi);
|
|
}
|
|
|
|
BOOL dumpGSI(GSI* pgsi) {
|
|
PB pbSym = 0;
|
|
while (pbSym = GSINextSym(pgsi, pbSym))
|
|
dumpSymbol((PSYM)pbSym);
|
|
putchar('\n');
|
|
return GSIClose(pgsi);
|
|
}
|
|
|
|
inline PB pbEndSym(PSYM psym);
|
|
|
|
BOOL dumpSymbols(PB pb, CB cb) {
|
|
if (cb == 0)
|
|
return TRUE;
|
|
printf("symbols:\n");
|
|
PSYM psymMac = (PSYM)(pb + cb);
|
|
for (PSYM psym = (PSYM)(pb + sizeof(ULONG)); psym < psymMac; psym = (PSYM)pbEndSym(psym))
|
|
dumpSymbol(psym);
|
|
putchar('\n');
|
|
return TRUE;
|
|
}
|
|
|
|
typedef SYMTYPE UNALIGNED * PSYMUNALIGNED;
|
|
|
|
// Return the number of bytes in an ST
|
|
inline CB cbForSt(ST st)
|
|
{
|
|
return *(PB)st + 1;
|
|
}
|
|
|
|
// Return the number of bytes the type record occupies.
|
|
inline CB cbForType(PTYPE ptype)
|
|
{
|
|
return ptype->len + sizeof(ptype->len);
|
|
}
|
|
|
|
// Return a pointer to the byte just past the end of the type record.
|
|
inline PB pbEndType(PTYPE ptype)
|
|
{
|
|
return (PB)ptype + cbForType(ptype);
|
|
}
|
|
|
|
// Return the number of bytes the symbol record occupies.
|
|
#define MDALIGNTYPE_ DWORD
|
|
|
|
inline CB cbAlign_(CB cb)
|
|
{
|
|
return ((cb + sizeof(MDALIGNTYPE_) - 1)) & ~(sizeof(MDALIGNTYPE_) - 1);
|
|
}
|
|
|
|
inline CB cbForSym(PSYMUNALIGNED psym)
|
|
{
|
|
CB cb = psym->reclen + sizeof(psym->reclen);
|
|
// procrefs also have a hidden length preceeded name following the record
|
|
if ((psym->rectyp == S_PROCREF) || (psym->rectyp == S_LPROCREF))
|
|
cb += cbAlign_(cbForSt((ST)((PB)psym + cb)));
|
|
return cb;
|
|
}
|
|
|
|
// Return a pointer to the byte just past the end of the symbol record.
|
|
inline PB pbEndSym(PSYM psym) {
|
|
return (PB)psym + cbForSym(psym);
|
|
}
|
|
|
|
inline CString strFmt(SZ szFmt, ...) {
|
|
// sigh, there's not CString::VFormat...
|
|
va_list va;
|
|
va_start(va, szFmt);
|
|
char buf[2048];
|
|
_vsnprintf(buf, sizeof(buf), szFmt, va);
|
|
va_end(va);
|
|
buf[sizeof(buf)-1] = 0;
|
|
return buf;
|
|
}
|
|
|
|
inline CString strInt(int i) {
|
|
return strFmt("%d", i);
|
|
}
|
|
|
|
inline CString strHex(int i) {
|
|
return strFmt("%X", i);
|
|
}
|
|
|
|
inline CString strJoin(const CString& s1, const CString& s2) {
|
|
if (s1.GetLength() == 0)
|
|
return s2;
|
|
else if (s2.GetLength() == 0)
|
|
return s1;
|
|
else if (isalnum(s1.Right(1)[0]) && (isalnum(s2[0]) || !!strchr("?_", s2[0])))
|
|
return s1 + " " + s2;
|
|
else
|
|
return s1 + s2;
|
|
}
|
|
|
|
inline CString strForSt(ST st) {
|
|
CString ret;
|
|
LPTSTR sz = ret.GetBuffer(cbForSt(st));
|
|
memcpy(sz, st+1, cbForSt(st)-1);
|
|
sz[cbForSt(st)-1] = 0;
|
|
ret.ReleaseBuffer();
|
|
return ret;
|
|
}
|
|
|
|
CString strForTypeTi(TI ti, CString str = "", Bind bind = bindNone, BOOL recursed = TRUE);
|
|
|
|
CString strForDATASYM32(PSYM psym);
|
|
CString strForPROCSYM32(PSYM psym);
|
|
CString strForREFSYM(PSYM psym);
|
|
CString strForUDTSYM(PSYM psym);
|
|
CString strForCONSTSYM(PSYM psym);
|
|
CString strForLABELSYM32(PSYM psym);
|
|
CString strForBPRELSYM32(PSYM psym);
|
|
CString strForSymNYI(PSYM psym);
|
|
CString strForSymType(unsigned short type);
|
|
|
|
void dumpSymbol(PSYM psym) {
|
|
CString str;
|
|
|
|
switch (psym->rectyp) {
|
|
case S_CONSTANT: str = strForCONSTSYM(psym); break;
|
|
case S_UDT: str = strForUDTSYM(psym); break;
|
|
case S_BPREL32: str = strForBPRELSYM32(psym); break;
|
|
case S_LDATA32: str = strForDATASYM32(psym); break;
|
|
case S_GDATA32: str = strForDATASYM32(psym); break;
|
|
case S_PUB32: str = strForDATASYM32(psym); break;
|
|
case S_LPROC32: str = strForPROCSYM32(psym); break;
|
|
case S_GPROC32: str = strForPROCSYM32(psym); break;
|
|
case S_LABEL32: str = strForLABELSYM32(psym); break;
|
|
case S_PROCREF: /* no point displaying these */ return;
|
|
case S_DATAREF: /* no point displaying these */ return;
|
|
case S_LPROCREF: /* no point displaying these */ return;
|
|
case S_END: str = "end"; break;
|
|
default: str = strForSymNYI(psym); break;
|
|
}
|
|
|
|
printf("%-10s: %s;\n", (LPCTSTR)strForSymType(psym->rectyp), (LPCTSTR)str);
|
|
}
|
|
|
|
CString strForSymType(unsigned short type) {
|
|
SZ sz = "???";
|
|
switch (type) {
|
|
#define s(x) case x: sz = #x; break;
|
|
s(S_COMPILE)
|
|
s(S_REGISTER)
|
|
s(S_CONSTANT)
|
|
s(S_UDT)
|
|
s(S_SSEARCH)
|
|
s(S_END)
|
|
s(S_SKIP)
|
|
s(S_CVRESERVE)
|
|
s(S_OBJNAME)
|
|
s(S_ENDARG)
|
|
s(S_COBOLUDT)
|
|
s(S_MANYREG)
|
|
s(S_RETURN)
|
|
s(S_ENTRYTHIS)
|
|
|
|
s(S_BPREL16)
|
|
s(S_LDATA16)
|
|
s(S_GDATA16)
|
|
s(S_PUB16)
|
|
s(S_LPROC16)
|
|
s(S_GPROC16)
|
|
s(S_THUNK16)
|
|
s(S_BLOCK16)
|
|
s(S_WITH16)
|
|
s(S_LABEL16)
|
|
s(S_CEXMODEL16)
|
|
s(S_VFTABLE16)
|
|
s(S_REGREL16)
|
|
|
|
s(S_BPREL32)
|
|
s(S_LDATA32)
|
|
s(S_GDATA32)
|
|
s(S_PUB32)
|
|
s(S_LPROC32)
|
|
s(S_GPROC32)
|
|
s(S_THUNK32)
|
|
s(S_BLOCK32)
|
|
s(S_WITH32)
|
|
s(S_LABEL32)
|
|
s(S_CEXMODEL32)
|
|
s(S_VFTABLE32)
|
|
s(S_REGREL32)
|
|
s(S_LTHREAD32)
|
|
s(S_GTHREAD32)
|
|
s(S_SLINK32)
|
|
|
|
s(S_LPROCMIPS)
|
|
s(S_GPROCMIPS)
|
|
s(S_PROCREF)
|
|
s(S_DATAREF)
|
|
s(S_ALIGN)
|
|
s(S_LPROCREF)
|
|
}
|
|
|
|
return sz;
|
|
}
|
|
|
|
CString strForDATASYM32(PSYM psym)
|
|
{
|
|
DATASYM32* p = (DATASYM32*)psym;
|
|
return strForTypeTi(p->typind, strForSt((ST)p->name), bindNone, FALSE);
|
|
}
|
|
|
|
CString strForPROCSYM32(PSYM psym) {
|
|
PROCSYM32* p = (PROCSYM32*)psym;
|
|
return strForTypeTi(p->typind, strForSt((ST)p->name), bindNone, FALSE);
|
|
}
|
|
|
|
CString strForUDTSYM(PSYM psym) {
|
|
UDTSYM* p = (UDTSYM*)psym;
|
|
return strForTypeTi(p->typind, strForSt((ST)p->name), bindNone, FALSE);
|
|
}
|
|
|
|
CString strForREFSYM(PSYM psym) {
|
|
REFSYM* p = (REFSYM*)psym;
|
|
return strFmt("(sumName:%lx ibSym:%lx imod:%d usFill:%x)",
|
|
p->sumName, p->ibSym, p->imod, p->usFill);
|
|
}
|
|
|
|
CString strForCONSTSYM(PSYM psym) {
|
|
CONSTSYM* p = (CONSTSYM*)psym;
|
|
return strForTypeTi(p->typind, strForSt((ST)p->name), bindNone, FALSE);
|
|
}
|
|
|
|
CString strForLABELSYM32(PSYM psym) {
|
|
LABELSYM32* p = (LABELSYM32*)psym;
|
|
return strForSt((ST)p->name);
|
|
}
|
|
|
|
CString strForBPRELSYM32(PSYM psym) {
|
|
BPRELSYM32* p = (BPRELSYM32*)psym;
|
|
return strForTypeTi(p->typind, strForSt((ST)p->name), bindNone, FALSE);
|
|
}
|
|
|
|
CString strForSymNYI(PSYM psym) {
|
|
return "...";
|
|
}
|
|
|
|
void dumpTpiTi(void* p, int i);
|
|
CString strForTI(TI ti);
|
|
CString strForPrimitiveTi(TI ti);
|
|
CString strForNYI(void* pleaf, CString strBase, Bind bind);
|
|
CString strForModifier(lfModifier* pm, CString str);
|
|
CString strForPtr(lfPointer* pp, CString strBase, Bind bind);
|
|
CString strForArray(lfArray* pa, CString strBase, Bind bind);
|
|
CString strForClassStruct(lfStructure* ps, CString strBase, BOOL recursed);
|
|
CString strForUnion(lfUnion* pu, CString strBase, BOOL recursed);
|
|
CString strForEnum(lfEnum* pe, CString strBase);
|
|
CString strForProc(lfProc* pp, CString str, Bind bind);
|
|
CString strForMFunc(lfMFunc* pf, CString strBase, Bind bind);
|
|
CString strForArgList(lfArgList* pa);
|
|
CString strForFieldList(lfFieldList* pf, CB cb);
|
|
CString strForMember(lfMember*pdata, CB *pcb);
|
|
CString strForBClass(lfBClass* pb, CB* pcb);
|
|
CString strForVBClass(lfVBClass* pb, CB* pcb);
|
|
CString strForTagTi(TI ti);
|
|
CString strForAttr(struct CV_fldattr_t a);
|
|
CString strForMember(lfMember* pm, CB *pcb);
|
|
CString strForEnumerate(lfEnumerate* pe, CB *pcb);
|
|
CString strSep(BOOL& fFirst, char* szFirst = "", char* szRest = ",");
|
|
|
|
CString strForTI(TI ti) {
|
|
return strHex(ti);
|
|
}
|
|
|
|
void dumpType(TI ti) {
|
|
printf("%s: %s;\n", (LPCTSTR)strForTI(ti),
|
|
(LPCTSTR)strForTypeTi(ti, CString("T") + strForTI(ti), bindNone, FALSE));
|
|
}
|
|
|
|
CString strForTypeTi(TI ti, CString str, Bind bind, BOOL recursed) {
|
|
if (ti < TypesQueryTiMin(ptpi)) {
|
|
CString strPrim = strForPrimitiveTi(ti);
|
|
return strJoin(strPrim, str);
|
|
}
|
|
|
|
PB pb;
|
|
if (!TypesQueryPbCVRecordForTi(ptpi, ti, &pb))
|
|
return CString("!?!");
|
|
TYPTYPE*ptype = (TYPTYPE*)pb;
|
|
void* pleaf = &ptype->leaf;
|
|
|
|
switch (ptype->leaf) {
|
|
case LF_MODIFIER: return strForModifier((lfModifier*)pleaf, str);
|
|
case LF_POINTER: return strForPtr((lfPointer*)pleaf, str, bind);
|
|
case LF_ARRAY: return strForArray((lfArray*)pleaf, str, bind);
|
|
case LF_CLASS: return strForClassStruct((lfStructure*)pleaf, str, recursed);
|
|
case LF_STRUCTURE: return strForClassStruct((lfStructure*)pleaf, str, recursed);
|
|
case LF_UNION: return strForUnion((lfUnion*)pleaf, str, recursed);
|
|
case LF_ENUM: return strForEnum((lfEnum*)pleaf, str);
|
|
case LF_PROCEDURE: return strForProc((lfProc*)pleaf, str, bind);
|
|
case LF_MFUNCTION: return strForMFunc((lfMFunc*)pleaf, str, bind);
|
|
case LF_ARGLIST: return strForArgList((lfArgList*)pleaf);
|
|
case LF_FIELDLIST: return strForFieldList((lfFieldList*)pleaf, ptype->len);
|
|
default:
|
|
return strForNYI(pleaf, str, bind);
|
|
}
|
|
}
|
|
|
|
CString strForPrimitiveTi(TI ti) {
|
|
char* szPrim = 0;
|
|
switch (ti) {
|
|
#define P(X) case X: szPrim = #X; break;
|
|
#define PS(X,S) case X: szPrim = #S; break;
|
|
P(T_NOTYPE) P(T_ABS) P(T_SEGMENT) PS(T_VOID,void) PS(T_PVOID,void near*)
|
|
PS(T_PFVOID,void far*) PS(T_PHVOID,void huge*) PS(T_32PVOID,void*)
|
|
P(T_32PFVOID) P(T_NOTTRANS)
|
|
PS(T_CHAR,signed char) PS(T_UCHAR,unsigned char) PS(T_PCHAR,signed char near*)
|
|
PS(T_PUCHAR,unsigned char near*) PS(T_PFCHAR,char far*)
|
|
PS(T_PFUCHAR,unsigned char far*) PS(T_PHCHAR,char huge*)
|
|
PS(T_PHUCHAR,unsigned char huge*) PS(T_32PCHAR,char*)
|
|
PS(T_32PUCHAR,unsigned char*) P(T_32PFCHAR) P(T_32PFUCHAR)
|
|
PS(T_RCHAR,char) PS(T_PRCHAR,char near*) PS(T_PFRCHAR,char far*)
|
|
PS(T_PHRCHAR,char huge*) PS(T_32PRCHAR,char*) P(T_32PFRCHAR)
|
|
PS(T_WCHAR,wchar_t) PS(T_PWCHAR,wchar_t near*) PS(T_PFWCHAR,wchar far*)
|
|
PS(T_PHWCHAR,wchar_t huge*) PS(T_32PWCHAR,wchar_t*)
|
|
P(T_32PFWCHAR) PS(T_SHORT,short) PS(T_USHORT,unsigned)
|
|
PS(T_PSHORT,short near*) PS(T_PUSHORT,unsigned short near*)
|
|
PS(T_PFSHORT,short far*) PS(T_PFUSHORT,unsigned short far*)
|
|
PS(T_PHSHORT,short huge*) PS(T_PHUSHORT,unsigned short huge*)
|
|
P(T_32PSHORT) P(T_32PUSHORT) P(T_32PFSHORT)
|
|
P(T_32PFUSHORT) PS(T_INT2,int16) PS(T_UINT2,unsigned int16)
|
|
PS(T_PINT2,int16 near*) PS(T_PUINT2,unsigned int16 near*)
|
|
PS(T_PFINT2,int16 far*) PS(T_PFUINT2,unsigned int16 far*)
|
|
PS(T_PHINT2,int16 huge*) PS(T_PHUINT2,unsigned int16 huge*) P(T_32PINT2)
|
|
P(T_32PUINT2) P(T_32PFINT2) P(T_32PFUINT2) PS(T_LONG,long)
|
|
PS(T_ULONG,unsigned long) PS(T_PLONG,long near*)
|
|
PS(T_PULONG,unsigned long near*) PS(T_PFLONG,long far*)
|
|
PS(T_PFULONG,unsigned long far*) PS(T_PHLONG,long huge*)
|
|
PS(T_PHULONG,unsigned long huge*) PS(T_32PLONG, long*)
|
|
PS(T_32PULONG, unsigned long*) P(T_32PFLONG)
|
|
P(T_32PFULONG) PS(T_INT4,int) PS(T_UINT4,unsigned)
|
|
P(T_PINT4) P(T_PUINT4) P(T_PFINT4) P(T_PFUINT4) P(T_PHINT4) P(T_PHUINT4)
|
|
PS(T_32PINT4,int *) PS(T_32PUINT4,unsigned*)
|
|
P(T_32PFINT4) P(T_32PFUINT4)
|
|
//
|
|
// The following were added for BIGINT support
|
|
//
|
|
PS(T_QUAD,quad) PS(T_UQUAD,unsigned quad) PS(T_PQUAD,quad near*)
|
|
PS(T_PUQUAD,unsigned quad near*) PS(T_PFQUAD,quad far*)
|
|
PS(T_PFUQUAD,unsigned quad far*) PS(T_PHQUAD,quad huge*)
|
|
PS(T_PHUQUAD,unsigned quad huge*) P(T_32PQUAD) P(T_32PUQUAD) P(T_32PFQUAD)
|
|
P(T_32PFUQUAD)
|
|
|
|
PS(T_INT8,int64) PS(T_UINT8,unsigned int64) PS(T_PINT8,int64 near*)
|
|
PS(T_PUINT8,unsigned int64 near*) PS(T_PFINT8,int64 far*)
|
|
PS(T_PFUINT8,unsigned int64 far*) PS(T_PHINT8,int64 huge*)
|
|
PS(T_PHUINT8,unsigned int64 huge*) P(T_32PINT8) P(T_32PUINT8) P(T_32PFINT8)
|
|
P(T_32PFUINT8)
|
|
|
|
PS(T_REAL32,float) PS(T_PREAL32,float near*)
|
|
PS(T_PFREAL32,float far*) PS(T_PHREAL32,float huge*)
|
|
PS(T_32PREAL32,float*) P(T_32PFREAL32) PS(T_REAL64,double)
|
|
PS(T_PREAL64,double near*) PS(T_PFREAL64,double far*)
|
|
PS(T_PHREAL64,double huge*) PS(T_32PREAL64,double*)
|
|
P(T_32PFREAL64) PS(T_REAL80,long double) PS(T_PREAL80,long double near*)
|
|
PS(T_PFREAL80,long double far*) PS(T_PHREAL80,long double huge*)
|
|
PS(T_32PREAL80,long double*) P(T_32PFREAL80)
|
|
}
|
|
return szPrim ? CString(szPrim) : CString("<") + strForTI(ti) + ">";
|
|
}
|
|
|
|
CString strForNYI(void* pleaf, CString strBase, Bind bind) {
|
|
return "<<" + strBase + ">>";
|
|
}
|
|
|
|
CString strForModifier(lfModifier* pm, CString str) {
|
|
CString strMod;
|
|
if (pm->attr.MOD_const)
|
|
strMod += "const ";
|
|
if (pm->attr.MOD_volatile)
|
|
strMod += "volatile ";
|
|
return strMod + strForTypeTi(pm->type) + str;
|
|
}
|
|
|
|
CString strForPtr(lfPointer* pp, CString strBase, Bind bind) {
|
|
static char* mppmenumsz[] = {
|
|
"pdm16_nonvirt", "pdm16_vfcn", "pdm16_vbase", "pdm32_nvvfcn",
|
|
"pdm32_vbase", "pmf16_nearnvsa", "pmf16_nearnvma", "pmf16_nearvbase",
|
|
"pmf16_farnvsa", "pmf16_farnvma", "pmf16_farvbase", "pmf32_nvsa",
|
|
"pmf32_nvma", "pmf32_vbase"
|
|
};
|
|
static char* mpptrtypesz[] = {
|
|
"near", "far", "huge", "base(seg)",
|
|
"base(val)", "base(segval)", "base(addr)", "base(segaddr)",
|
|
"base(type)", "base(self)", "", "far32"
|
|
};
|
|
CString str;
|
|
if (pp->attr.isflat32)
|
|
str = "flat ";
|
|
switch (pp->attr.ptrmode) {
|
|
case CV_PTR_MODE_PTR:
|
|
str += CString(mpptrtypesz[pp->attr.ptrtype]) + "*";
|
|
break;
|
|
case CV_PTR_MODE_REF:
|
|
str += CString(mpptrtypesz[pp->attr.ptrtype]) + "&";
|
|
break;
|
|
case CV_PTR_MODE_PMEM:
|
|
case CV_PTR_MODE_PMFUNC:
|
|
str = strForTypeTi(pp->pbase.pm.pmclass) + "::*";
|
|
break;
|
|
}
|
|
if (pp->attr.isconst)
|
|
str += "const";
|
|
if (pp->attr.isvolatile)
|
|
str += "volatile";
|
|
|
|
// TODO: exotic based modes
|
|
|
|
return strForTypeTi(pp->utype, strJoin(str, strBase), bindPtr);
|
|
}
|
|
|
|
CB CbExtractNumeric(BYTE* pb, ULONG* pul);
|
|
|
|
CString strForArray(lfArray* pa, CString strBase, Bind bind) {
|
|
if (bind < bindArray)
|
|
strBase = "(" + strBase + ")";
|
|
|
|
ULONG size;
|
|
CbExtractNumeric(pa->data, &size);
|
|
|
|
CString str = strBase + "[" + strInt(size) + "]";
|
|
|
|
// TODO: exotic subscript types
|
|
|
|
return strForTypeTi(pa->elemtype, str, bindArray);
|
|
}
|
|
|
|
CString strForClassStruct(lfStructure* ps, CString strBase, BOOL recursed) {
|
|
ULONG size;
|
|
CB dcb = CbExtractNumeric(ps->data, &size);
|
|
|
|
CString str;
|
|
if (!recursed)
|
|
str += (ps->leaf == LF_STRUCTURE) ? "struct " : "class ";
|
|
str += strForSt((char*)ps->data + dcb);
|
|
if (ps->field)
|
|
str += strForTypeTi(ps->field);
|
|
return strJoin(str, strBase);
|
|
}
|
|
|
|
CString strForUnion(lfUnion* pu, CString strBase, BOOL recursed) {
|
|
ULONG size;
|
|
CB dcb = CbExtractNumeric(pu->data, &size);
|
|
|
|
CString str;
|
|
if (!recursed)
|
|
str += "union ";
|
|
str += strForSt((char*)pu->data + dcb);
|
|
if (pu->field)
|
|
str += strForTypeTi(pu->field);
|
|
return strJoin(str, strBase);
|
|
}
|
|
|
|
CString strForEnum(lfEnum* pe, CString strBase) {
|
|
CString str = "enum ";
|
|
str += strForSt((char*)pe->Name);
|
|
if (pe->field)
|
|
str += strForTypeTi(pe->field);
|
|
return strJoin(str, strBase);
|
|
}
|
|
|
|
CString strForFieldList(lfFieldList* pfl, CB cbList) {
|
|
CString str;
|
|
PB pdata;
|
|
CB cb = 0;
|
|
BOOL fBases = TRUE;
|
|
BOOL fMembers = TRUE;
|
|
|
|
while (cb < cbList) {
|
|
// skip pad bytes
|
|
for (;;) {
|
|
pdata = (PB)pfl->data + cb;
|
|
if (*(BYTE*)pdata < LF_PAD0)
|
|
break;
|
|
cb++;
|
|
}
|
|
|
|
switch (*(USHORT*)pdata) {
|
|
case LF_BCLASS:
|
|
str += strSep(fBases, " : ", ", ");
|
|
str += strForBClass((lfBClass*)pdata, &cb);
|
|
break;
|
|
case LF_VBCLASS:
|
|
case LF_IVBCLASS:
|
|
str += strSep(fBases, " : ", ", ");
|
|
str += strForVBClass((lfVBClass*)pdata, &cb);
|
|
break;
|
|
case LF_MEMBER:
|
|
str += strSep(fMembers, " { ", " ");
|
|
str += strForMember((lfMember*)pdata, &cb);
|
|
str += ";";
|
|
break;
|
|
case LF_ENUMERATE:
|
|
str += strSep(fMembers, " { ", " ");
|
|
str += strForEnumerate((lfEnumerate*)pdata, &cb);
|
|
str += ",";
|
|
default:
|
|
str += "...";
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
str += strSep(fMembers, " {}", " }");
|
|
return str;
|
|
}
|
|
|
|
CString strForBClass(lfBClass* pb, CB* pcb) {
|
|
ULONG offset;
|
|
*pcb += sizeof(lfBClass) + CbExtractNumeric(pb->offset, &offset);
|
|
return strJoin(strForAttr(pb->attr), strForTypeTi(pb->index));
|
|
}
|
|
|
|
CString strForVBClass(lfVBClass* pb, CB* pcb) {
|
|
BOOL fInd = (pb->leaf == LF_IVBCLASS);
|
|
CString str;
|
|
ULONG offVbp;
|
|
ULONG offVbte;
|
|
|
|
CB cb = CbExtractNumeric(pb->vbpoff, &offVbp);
|
|
*pcb += sizeof(lfVBClass) + cb +
|
|
CbExtractNumeric(pb->vbpoff + cb, &offVbte);
|
|
|
|
if (fInd)
|
|
str = "< indirect ";
|
|
str += strJoin(strForAttr(pb->attr), strForTagTi(pb->index));
|
|
if (!fInd)
|
|
str += "< ";
|
|
str += strForTypeTi(pb->vbptr, "vbp") + ";";
|
|
str += CString("offVbp=") + strInt(offVbp) + "; offVbte=" + strInt(offVbte) + ";";
|
|
str += " >";
|
|
|
|
return str;
|
|
}
|
|
|
|
CString strForTagTi(TI ti) {
|
|
PB pb;
|
|
if (!TypesQueryPbCVRecordForTi(ptpi, ti, &pb))
|
|
return CString("!?!");
|
|
TYPTYPE* ptype = (TYPTYPE*)pb;
|
|
if (!(ptype->leaf == LF_STRUCTURE || ptype->leaf == LF_CLASS))
|
|
return CString("!?!");
|
|
|
|
lfStructure* ps = (lfStructure*)&ptype->leaf;
|
|
ULONG size;
|
|
CB dcb = CbExtractNumeric(ps->data, &size);
|
|
return strForSt((char*)ps->data + dcb);
|
|
}
|
|
|
|
CString strForMember(lfMember* pm, CB *pcb) {
|
|
ULONG offset;
|
|
CB cbOffset = CbExtractNumeric(pm->offset, &offset);
|
|
CString str = /* strForAttr(pm->attr) + ": " + */
|
|
strForTypeTi(pm->index, strForSt((char*)pm->offset + cbOffset));
|
|
*pcb += sizeof(lfMember) + cbOffset + pm->offset[cbOffset] + 1;
|
|
return str;
|
|
}
|
|
|
|
CString strForAttr(struct CV_fldattr_t a) {
|
|
static char* mpaccesssz[] = { "", "private", "protected", "public" };
|
|
static char* mpmpropsz[] = { "", "virtual", "static", "friend",
|
|
"", "<pure>", "<pure>" };
|
|
CString str = CString(mpaccesssz[a.access]) + CString(mpmpropsz[a.mprop]);
|
|
return str;
|
|
}
|
|
|
|
CString strForProc(lfProc* pp, CString strBase, Bind bind) {
|
|
if (bind < bindProc)
|
|
strBase = "(" + strBase + ")";
|
|
strBase += strForTypeTi(pp->arglist);
|
|
return strForTypeTi(pp->rvtype, CString(" ") + strBase, bindProc);
|
|
}
|
|
|
|
CString strForMFunc(lfMFunc* pf, CString strBase, Bind bind) {
|
|
if (bind < bindProc)
|
|
strBase = "(" + strBase + ")";
|
|
CString str;
|
|
str = CString(" ") + strForTypeTi(pf->classtype) + "::";
|
|
str += strBase + strForTypeTi(pf->arglist);
|
|
str += CString("<") + strForTypeTi(pf->thistype, "this") + ">";
|
|
return strForTypeTi(pf->rvtype, str, bindProc);
|
|
}
|
|
|
|
CString strForArgList(lfArgList* pa) {
|
|
CString str = "(";
|
|
for (int i = 0; i < pa->count; i++) {
|
|
if (i > 0)
|
|
str += ", ";
|
|
str += strForTypeTi(pa->arg[i]);
|
|
}
|
|
str += ")";
|
|
return str;
|
|
}
|
|
|
|
CString strForEnumerate(lfEnumerate* pe, CB *pcb) {
|
|
ULONG value;
|
|
CB cb = CbExtractNumeric(pe->value, &value);
|
|
return strForSt((char*)pe->value + cb) + "=" + strInt(value);
|
|
*pcb += sizeof(lfEnumerate) + cb + pe->value[cb] + 1;
|
|
}
|
|
|
|
CString strSep(BOOL& fFirst, char* szFirst, char* szRest) {
|
|
CString str = fFirst ? szFirst : szRest;
|
|
fFirst = FALSE;
|
|
return str;
|
|
}
|
|
|
|
CB CbExtractNumeric(BYTE* pb, ULONG* pul) {
|
|
USHORT leaf = *(USHORT*)pb;
|
|
if (leaf < LF_NUMERIC) {
|
|
*pul = leaf;
|
|
return sizeof(leaf);
|
|
} else switch (leaf) {
|
|
case LF_CHAR:
|
|
*pul = *((char*)pb);
|
|
return sizeof(leaf) + sizeof(char);
|
|
case LF_SHORT:
|
|
*pul = *(short*)pb;
|
|
return sizeof(leaf) + sizeof(short);
|
|
case LF_USHORT:
|
|
*pul = *(USHORT*)pb;
|
|
return sizeof(leaf) + sizeof(USHORT);
|
|
case LF_LONG:
|
|
*pul = *(long*)pb;
|
|
return sizeof(leaf) + sizeof(long);
|
|
case LF_ULONG:
|
|
*pul = *(ULONG*)pb;
|
|
return sizeof(leaf) + sizeof(ULONG);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL dumpLines(PB pb, CB cb) {
|
|
if (cb == 0)
|
|
return TRUE;
|
|
|
|
PB pbLines = pb;
|
|
struct FSB { short cFile; short cSeg; long baseSrcFile[]; };
|
|
FSB* pfsb = (FSB*)pb;
|
|
pb += sizeof(FSB) + sizeof(long)*pfsb->cFile;
|
|
struct SE { long start, end; };
|
|
SE* pse = (SE*)pb;
|
|
pb += sizeof(SE)*pfsb->cSeg;
|
|
short* seg = (short*)pb;
|
|
pb += sizeof(short)*pfsb->cSeg;
|
|
printf("lines: cFile=%u cSeg=%u\n", pfsb->cFile, pfsb->cSeg);
|
|
for (int ifile = 0; ifile < pfsb->cFile; ifile++)
|
|
printf("baseSrcFile[%d]=%04lx\n", ifile, pfsb->baseSrcFile[ifile]);
|
|
for (int iseg = 0; iseg < pfsb->cSeg; iseg++)
|
|
printf("%d: start=%04lx end=%04lx seg=%02x\n",
|
|
iseg, pse[iseg].start, pse[iseg].end, seg[iseg]);
|
|
|
|
for (ifile = 0; ifile < pfsb->cFile; ifile++) {
|
|
PB pb = pbLines + pfsb->baseSrcFile[ifile];
|
|
struct SPB { short cSeg; short pad; long baseSrcLn[]; };
|
|
SPB* pspb = (SPB*)pb;
|
|
pb += sizeof SPB + sizeof(long)*pspb->cSeg;
|
|
SE* pse = (SE*)pb;
|
|
pb += sizeof(SE)*pspb->cSeg;
|
|
unsigned char cbName = *pb++;
|
|
unsigned char* Name = pb;
|
|
printf(" file[%d]: cSeg=%u pad=%02x cbName=%u, Name=%s\n",
|
|
ifile, pspb->cSeg, pspb->pad, cbName, Name);
|
|
for (int iseg = 0; iseg < pspb->cSeg; iseg++)
|
|
printf(" %d: baseSrcLn=%04lx start=%04lx end=%04lx\n",
|
|
iseg, pspb->baseSrcLn[iseg], pse[iseg].start, pse[iseg].end);
|
|
for (iseg = 0; iseg < pspb->cSeg; iseg++) {
|
|
PB pb = pbLines + pspb->baseSrcLn[iseg];
|
|
struct SPO { short Seg; short cPair; long offset[]; };
|
|
SPO* pspo = (SPO*)pb;
|
|
pb += sizeof(SPO) + sizeof(long)*pspo->cPair;
|
|
short* linenumber = (short*)pb;
|
|
printf(" seg[%d]: Seg=%02x cPair=%u\n", iseg, pspo->Seg, pspo->cPair);
|
|
printf(" ");
|
|
for (int ipair = 0; ipair < pspo->cPair; ipair++) {
|
|
printf(" %4u:%04lx", linenumber[ipair], pspo->offset[ipair]);
|
|
if (ipair < pspo->cPair - 1 && (ipair & 3) == 3)
|
|
printf("\n ");
|
|
}
|
|
putchar('\n');
|
|
}
|
|
}
|
|
putchar('\n');
|
|
return TRUE;
|
|
}
|
|
|
|
void dump(PB pb, CB cb, SZ szFmt, ...) {
|
|
va_list va;
|
|
|
|
printf("raw hex dump of ");
|
|
va_start(va, szFmt);
|
|
vprintf(szFmt, va);
|
|
va_end(va);
|
|
if (cb > 0)
|
|
printf(":\n");
|
|
else {
|
|
printf(": (none)\n\n");
|
|
return;
|
|
}
|
|
|
|
PB pbStart = pb;
|
|
PB pbEnd = pbStart + cb;
|
|
const int n = 16;
|
|
for ( ; pb < pbEnd; pb += n) {
|
|
printf("%06X: ", pb - pbStart);
|
|
for (int i = 0; i < n; i++) {
|
|
if (i == n/2)
|
|
putchar(' ');
|
|
if (&pb[i] < pbEnd)
|
|
printf("%02X ", pb[i]);
|
|
else
|
|
printf(" ");
|
|
}
|
|
putchar(' ');
|
|
for (i = 0; i < n && &pb[i] < pbEnd; i++)
|
|
putchar(isprint(pb[i]) ? pb[i] : '.');
|
|
putchar('\n');
|
|
}
|
|
putchar('\n');
|
|
}
|