mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 07:08:19 +00:00
986 lines
18 KiB
C
986 lines
18 KiB
C
/*
|
|
* PE symbol dumper
|
|
*
|
|
* symdump.c
|
|
*
|
|
* Copyright (c) 2008 Timo Kreuzer <timo <dot> kreuzer <at> reactos <dot> org>
|
|
*
|
|
* This program is released under the terms of the GNU GPL.
|
|
*
|
|
* TODO:
|
|
* - fix GDILoObjType
|
|
* - fix UDTKind1
|
|
* - include the correct headers for some stuff
|
|
* - fix unions like LARGE_INTEGER
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#define _WINVER 0x501
|
|
#include <windows.h>
|
|
#include <shlwapi.h>
|
|
#include <dbghelp.h>
|
|
|
|
HANDLE hCurrentProcess;
|
|
BOOL g_bShowPos = 0;
|
|
|
|
#define MAX_SYMBOL_NAME 1024
|
|
|
|
#define CV_CALL_NEAR_C 0x00
|
|
#define CV_CALL_FAR_C 0x01
|
|
#define CV_CALL_NEAR_PASCAL 0x02
|
|
#define CV_CALL_FAR_PASCAL 0x03
|
|
#define CV_CALL_NEAR_FAST 0x04
|
|
#define CV_CALL_FAR_FAST 0x05
|
|
#define CV_CALL_SKIPPED 0x06
|
|
#define CV_CALL_NEAR_STD 0x07
|
|
#define CV_CALL_FAR_STD 0x08
|
|
#define CV_CALL_NEAR_SYS 0x09
|
|
#define CV_CALL_FAR_SYS 0x0a
|
|
#define CV_CALL_THISCALL 0x0b
|
|
#define CV_CALL_MIPSCALL 0x0c
|
|
#define CV_CALL_GENERIC 0x0d
|
|
#define CV_CALL_ALPHACALL 0x0e
|
|
#define CV_CALL_PPCCALL 0x0f
|
|
#define CV_CALL_SHCALL 0x10
|
|
#define CV_CALL_ARMCALL 0x11
|
|
#define CV_CALL_AM33CALL 0x12
|
|
#define CV_CALL_TRICALL 0x13
|
|
#define CV_CALL_SH5CALL 0x14
|
|
#define CV_CALL_M32RCALL 0x15
|
|
|
|
enum SymTagEnum
|
|
{
|
|
SymTagNull,
|
|
SymTagExe,
|
|
SymTagCompiland,
|
|
SymTagCompilandDetails,
|
|
SymTagCompilandEnv,
|
|
SymTagFunction,
|
|
SymTagBlock,
|
|
SymTagData,
|
|
SymTagAnnotation,
|
|
SymTagLabel,
|
|
SymTagPublicSymbol,
|
|
SymTagUDT,
|
|
SymTagEnum,
|
|
SymTagFunctionType,
|
|
SymTagPointerType,
|
|
SymTagArrayType,
|
|
SymTagBaseType,
|
|
SymTagTypedef,
|
|
SymTagBaseClass,
|
|
SymTagFriend,
|
|
SymTagFunctionArgType,
|
|
SymTagFuncDebugStart,
|
|
SymTagFuncDebugEnd,
|
|
SymTagUsingNamespace,
|
|
SymTagVTableShape,
|
|
SymTagVTable,
|
|
SymTagCustom,
|
|
SymTagThunk,
|
|
SymTagCustomType,
|
|
SymTagManagedType,
|
|
SymTagDimension,
|
|
SymTagMax
|
|
};
|
|
|
|
enum
|
|
{
|
|
UDTKind_Struct = 0,
|
|
UDTKind_Class = 1, /* ? */
|
|
UDTKind_Union = 2,
|
|
};
|
|
|
|
enum BasicType
|
|
{
|
|
btNoType = 0,
|
|
btVoid = 1,
|
|
btChar = 2,
|
|
btWChar = 3,
|
|
btInt = 6,
|
|
btUInt = 7,
|
|
btFloat = 8,
|
|
btBCD = 9,
|
|
btBool = 10,
|
|
btLong = 13,
|
|
btULong = 14,
|
|
btCurrency = 25,
|
|
btDate = 26,
|
|
btVariant = 27,
|
|
btComplex = 28,
|
|
btBit = 29,
|
|
btBSTR = 30,
|
|
btHresult = 31
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
HANDLE hProcess;
|
|
DWORD64 dwModuleBase;
|
|
LPSTR pszSymbolName;
|
|
BOOL bType;
|
|
} ENUMINFO, *PENUMINFO;
|
|
|
|
VOID DumpType(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers);
|
|
|
|
CHAR *SymTagString[] =
|
|
{
|
|
"SymTagNull",
|
|
"SymTagExe",
|
|
"SymTagCompiland",
|
|
"SymTagCompilandDetails",
|
|
"SymTagCompilandEnv",
|
|
"SymTagFunction",
|
|
"SymTagBlock",
|
|
"SymTagData",
|
|
"SymTagAnnotation",
|
|
"SymTagLabel",
|
|
"SymTagPublicSymbol",
|
|
"SymTagUDT",
|
|
"SymTagEnum",
|
|
"SymTagFunctionType",
|
|
"SymTagPointerType",
|
|
"SymTagArrayType",
|
|
"SymTagBaseType",
|
|
"SymTagTypedef",
|
|
"SymTagBaseClass",
|
|
"SymTagFriend",
|
|
"SymTagFunctionArgType",
|
|
"SymTagFuncDebugStart",
|
|
"SymTagFuncDebugEnd",
|
|
"SymTagUsingNamespace",
|
|
"SymTagVTableShape",
|
|
"SymTagVTable",
|
|
"SymTagCustom",
|
|
"SymTagThunk",
|
|
"SymTagCustomType",
|
|
"SymTagManagedType",
|
|
"SymTagDimension",
|
|
"SymTagMax"
|
|
};
|
|
|
|
void
|
|
IndentPrint(INT ind)
|
|
{
|
|
INT i;
|
|
for (i = 0; i < ind; i++)
|
|
{
|
|
printf(" ");
|
|
}
|
|
}
|
|
|
|
#define printfi \
|
|
IndentPrint(indent); printf
|
|
|
|
VOID
|
|
PrintUsage()
|
|
{
|
|
printf("Syntax:\n\n");
|
|
printf("dumpsym <file> [-sp=<symbolpath>] [-p] [<symname>]\n\n");
|
|
printf("<file> The PE file you want to dump the symbols of\n");
|
|
printf("-sp=<symbolpath> Path to your symbol files.\n");
|
|
printf(" Default is MS symbol server.\n");
|
|
printf("-p Enable struct positions.\n");
|
|
printf("<symname> A name of a Symbol, you want to dump\n");
|
|
printf(" Default is all symbols.\n");
|
|
printf("\n");
|
|
}
|
|
|
|
BOOL InitDbgHelp(HANDLE hProcess, LPSTR pszSymbolPath)
|
|
{
|
|
if (!SymInitialize(hProcess, 0, FALSE))
|
|
return FALSE;
|
|
|
|
SymSetOptions(SymGetOptions() | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
|
|
SymSetOptions(SymGetOptions() & (~SYMOPT_DEFERRED_LOADS));
|
|
SymSetSearchPath(hProcess, pszSymbolPath);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
DumpBaseType(DWORD dwTypeIndex, PENUMINFO pei, INT indent)
|
|
{
|
|
ULONG64 ulSize;
|
|
DWORD dwBaseType;
|
|
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_LENGTH, &ulSize);
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_BASETYPE, &dwBaseType);
|
|
|
|
switch (dwBaseType)
|
|
{
|
|
case btVoid:
|
|
printfi("VOID");
|
|
return;
|
|
case btChar:
|
|
printfi("CHAR");
|
|
return;
|
|
case btWChar:
|
|
printfi("WCHAR");
|
|
return;
|
|
case btInt:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("CHAR");
|
|
return;
|
|
case 2:
|
|
printfi("SHORT");
|
|
return;
|
|
case 4:
|
|
printfi("INT");
|
|
return;
|
|
case 8:
|
|
printfi("INT64");
|
|
return;
|
|
default:
|
|
printfi("INT%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
}
|
|
case btUInt:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("UCHAR");
|
|
return;
|
|
case 2:
|
|
printfi("USHORT");
|
|
return;
|
|
case 4:
|
|
printfi("UINT");
|
|
return;
|
|
case 8:
|
|
printfi("UINT64");
|
|
return;
|
|
default:
|
|
printfi("UINT%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
}
|
|
case btFloat:
|
|
switch (ulSize)
|
|
{
|
|
case 4:
|
|
printfi("FLOAT");
|
|
return;
|
|
case 8:
|
|
printfi("DOUBLE");
|
|
return;
|
|
default:
|
|
printfi("FLOAT%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
}
|
|
case btBCD:
|
|
printfi("BCD%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
case btBool:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("BOOLEAN");
|
|
return;
|
|
case 4:
|
|
printfi("BOOL");
|
|
return;
|
|
default:
|
|
printfi("BOOL%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
}
|
|
case btLong:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("CHAR");
|
|
return;
|
|
case 2:
|
|
printfi("SHORT");
|
|
return;
|
|
case 4:
|
|
printfi("LONG");
|
|
return;
|
|
case 8:
|
|
printfi("LONGLONG");
|
|
return;
|
|
default:
|
|
printfi("LONG%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
}
|
|
case btULong:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("UCHAR");
|
|
return;
|
|
case 2:
|
|
printfi("USHORT");
|
|
return;
|
|
case 4:
|
|
printfi("ULONG");
|
|
return;
|
|
case 8:
|
|
printfi("ULONGLONG");
|
|
return;
|
|
default:
|
|
printfi("ULONG%ld", (ULONG)ulSize * 8);
|
|
return;
|
|
}
|
|
case btCurrency:
|
|
case btDate:
|
|
case btVariant:
|
|
case btComplex:
|
|
case btBit:
|
|
case btBSTR:
|
|
printfi("UNSUP_%ld_%ld", dwBaseType, (ULONG)ulSize);
|
|
return;
|
|
case btHresult:
|
|
if (ulSize == 4)
|
|
{
|
|
printfi("HRESULT");
|
|
return;
|
|
}
|
|
printfi("HRESULT%ld", (ULONG)ulSize);
|
|
return;
|
|
}
|
|
|
|
printfi("UNKNBASETYPE");
|
|
}
|
|
|
|
VOID
|
|
DumpArray(DWORD dwTypeIndex, PENUMINFO pei, INT indent)
|
|
{
|
|
DWORD dwTypeId;
|
|
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_TYPE, &dwTypeId);
|
|
DumpType(dwTypeId, pei, indent, FALSE);
|
|
}
|
|
|
|
VOID
|
|
DumpPointer(DWORD dwTypeIndex, PENUMINFO pei, INT indent)
|
|
{
|
|
DWORD dwRefTypeId;
|
|
DWORD dwTag = 0;
|
|
ULONG64 ulSize;
|
|
DWORD dwBaseType;
|
|
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_TYPE, &dwRefTypeId);
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwRefTypeId, TI_GET_BASETYPE, &dwBaseType);
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwRefTypeId, TI_GET_LENGTH, &ulSize);
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwRefTypeId, TI_GET_SYMTAG, &dwTag);
|
|
|
|
if (dwTag == SymTagFunctionType)
|
|
{
|
|
printfi("PPROC");
|
|
return;
|
|
}
|
|
|
|
switch (dwBaseType)
|
|
{
|
|
case btVoid:
|
|
switch (ulSize)
|
|
{
|
|
case 0:
|
|
printfi("PVOID");
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case btChar:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("PCHAR");
|
|
return;
|
|
}
|
|
break;
|
|
case btWChar:
|
|
switch (ulSize)
|
|
{
|
|
case 2:
|
|
printfi("PWCHAR");
|
|
return;
|
|
}
|
|
break;
|
|
case btInt:
|
|
switch (ulSize)
|
|
{
|
|
case 4:
|
|
printfi("PINT");
|
|
return;
|
|
}
|
|
break;
|
|
case btUInt:
|
|
switch (ulSize)
|
|
{
|
|
case 4:
|
|
printfi("PUINT");
|
|
return;
|
|
}
|
|
break;
|
|
case btFloat:
|
|
switch (ulSize)
|
|
{
|
|
case 4:
|
|
printfi("PFLOAT");
|
|
return;
|
|
case 8:
|
|
printfi("PDOUBLE");
|
|
return;
|
|
}
|
|
break;
|
|
case btBCD:
|
|
break;
|
|
case btBool:
|
|
switch (ulSize)
|
|
{
|
|
case 1:
|
|
printfi("PBOOLEAN");
|
|
return;
|
|
case 4:
|
|
printfi("PBOOL");
|
|
return;
|
|
}
|
|
break;
|
|
case btLong:
|
|
switch (ulSize)
|
|
{
|
|
case 4:
|
|
printfi("PLONG");
|
|
return;
|
|
case 8:
|
|
printfi("PLONGLONG");
|
|
return;
|
|
}
|
|
break;
|
|
case btULong:
|
|
switch (ulSize)
|
|
{
|
|
case 4:
|
|
printfi("PULONG");
|
|
return;
|
|
case 8:
|
|
printfi("PULONGLONG");
|
|
return;
|
|
}
|
|
break;
|
|
case btCurrency:
|
|
case btDate:
|
|
case btVariant:
|
|
case btComplex:
|
|
case btBit:
|
|
case btBSTR:
|
|
case btHresult:
|
|
break;
|
|
}
|
|
|
|
DumpType(dwRefTypeId, pei, indent, FALSE);
|
|
printf("*");
|
|
}
|
|
|
|
VOID
|
|
PrintVariant(VARIANT *v)
|
|
{
|
|
// printf("<vt%d>", v->n1.n2.vt);
|
|
switch (v->n1.n2.vt)
|
|
{
|
|
case VT_I1:
|
|
printf("%d", (INT)v->n1.n2.n3.cVal);
|
|
break;
|
|
case VT_UI1:
|
|
printf("0x%x", (UINT)v->n1.n2.n3.cVal);
|
|
break;
|
|
case VT_I2:
|
|
printf("%d", (UINT)v->n1.n2.n3.iVal);
|
|
break;
|
|
case VT_UI2:
|
|
printf("0x%x", (UINT)v->n1.n2.n3.iVal);
|
|
break;
|
|
case VT_INT:
|
|
case VT_I4:
|
|
printf("%d", (UINT)v->n1.n2.n3.lVal);
|
|
break;
|
|
case VT_UINT:
|
|
case VT_UI4:
|
|
printf("0x%x", (UINT)v->n1.n2.n3.lVal);
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
IsUnnamed(WCHAR *pszName)
|
|
{
|
|
if ((StrStrW(pszName, L"__unnamed") != NULL) ||
|
|
(StrStrW(pszName, L"<unnamed-tag>") != NULL))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
DumpEnum(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers)
|
|
{
|
|
DWORD64 dwModuleBase = pei->dwModuleBase;
|
|
HANDLE hProcess = pei->hProcess;
|
|
INT i;
|
|
DWORD dwUDTKind;
|
|
WCHAR *pszName, *pszNameX;
|
|
struct
|
|
{
|
|
TI_FINDCHILDREN_PARAMS tfp;
|
|
ULONG TypeIds[200];
|
|
} tfpex;
|
|
VARIANT v;
|
|
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_SYMNAME, &pszNameX);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_UDTKIND, &dwUDTKind);
|
|
pszName = pszNameX;
|
|
if (IsUnnamed(pszName))
|
|
{
|
|
if (bMembers)
|
|
{
|
|
LocalFree(pszNameX);
|
|
return;
|
|
}
|
|
bMembers = TRUE;
|
|
pszName = L"";
|
|
}
|
|
printfi("enum %ls", pszName);
|
|
LocalFree(pszNameX);
|
|
|
|
if (bMembers)
|
|
{
|
|
printf(" /* %03x */", 0);
|
|
printfi("\n{\n");
|
|
|
|
/* Get the children */
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &tfpex.tfp.Count);
|
|
|
|
tfpex.tfp.Start = 0;
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_FINDCHILDREN, &tfpex.tfp);
|
|
|
|
for (i = 0; i < tfpex.tfp.Count; i++)
|
|
{
|
|
pszName = L"";
|
|
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_SYMNAME, &pszName);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_VALUE, &v);
|
|
|
|
indent++;
|
|
printfi("%ls = ", pszName);
|
|
PrintVariant(&v);
|
|
printf(",\n");
|
|
indent--;
|
|
|
|
LocalFree(pszName);
|
|
}
|
|
printfi("}");
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpUDT(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers)
|
|
{
|
|
DWORD64 dwModuleBase = pei->dwModuleBase;
|
|
HANDLE hProcess = pei->hProcess;
|
|
INT i;
|
|
DWORD dwUDTKind;
|
|
WCHAR *pszName, *pszNameX;
|
|
struct
|
|
{
|
|
TI_FINDCHILDREN_PARAMS tfp;
|
|
ULONG TypeIds[200];
|
|
} tfpex;
|
|
|
|
DWORD dwDataKind;
|
|
DWORD dwTypeId;
|
|
DWORD dwCount;
|
|
WCHAR *pszTypeName;
|
|
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_SYMNAME, &pszNameX);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_UDTKIND, &dwUDTKind);
|
|
|
|
pszName = pszNameX;
|
|
if (IsUnnamed(pszName))
|
|
{
|
|
if (bMembers)
|
|
{
|
|
LocalFree(pszNameX);
|
|
return;
|
|
}
|
|
bMembers = TRUE;
|
|
pszName = L"";
|
|
}
|
|
if (dwUDTKind == UDTKind_Struct)
|
|
{
|
|
printfi("struct %ls", pszName);
|
|
}
|
|
else if (dwUDTKind == UDTKind_Union)
|
|
{
|
|
printfi("union %ls", pszName);
|
|
}
|
|
else
|
|
{
|
|
printfi("UTDKind%ld %ls", dwUDTKind, pszName);
|
|
}
|
|
LocalFree(pszNameX);
|
|
|
|
if (bMembers)
|
|
{
|
|
ULONG64 ulLength;
|
|
|
|
printf("\n");
|
|
printfi("{\n");
|
|
|
|
/* Get the children */
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &tfpex.tfp.Count);
|
|
|
|
tfpex.tfp.Start = 0;
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_FINDCHILDREN, &tfpex.tfp);
|
|
|
|
for (i = 0; i < tfpex.tfp.Count; i++)
|
|
{
|
|
DWORD dwChildTag;
|
|
DWORD dwOffset;
|
|
|
|
pszName = L"";
|
|
pszTypeName = L"";
|
|
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_SYMNAME, &pszName);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_DATAKIND, &dwDataKind);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_TYPE, &dwTypeId);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_OFFSET, &dwOffset);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeId, TI_GET_SYMTAG, &dwChildTag);
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeId, TI_GET_LENGTH, &ulLength);
|
|
|
|
printf(" /* %03lx */", dwOffset);
|
|
DumpType(dwTypeId, pei, indent + 1, FALSE);
|
|
printf(" %ls", pszName);
|
|
if (dwChildTag == SymTagArrayType)
|
|
{
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeId, TI_GET_COUNT, &dwCount);
|
|
printf("[%ld]", dwCount);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwCurrentBitPos;
|
|
DWORD dwNextBitPos;
|
|
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_BITPOSITION, &dwCurrentBitPos);
|
|
if (i < tfpex.tfp.Count - 1)
|
|
{
|
|
SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i+1], TI_GET_BITPOSITION, &dwNextBitPos);
|
|
}
|
|
else
|
|
{
|
|
dwNextBitPos = 0;
|
|
}
|
|
|
|
if (dwNextBitPos == 0 && dwCurrentBitPos != 0)
|
|
{
|
|
dwNextBitPos = ulLength * 8;
|
|
}
|
|
|
|
if (dwNextBitPos != dwCurrentBitPos)
|
|
{
|
|
printf(":%ld", dwNextBitPos - dwCurrentBitPos);
|
|
}
|
|
}
|
|
printf(";\n");
|
|
LocalFree(pszName);
|
|
}
|
|
printfi("}");
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpType(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers)
|
|
{
|
|
HANDLE hProcess = pei->hProcess;
|
|
DWORD64 dwModuleBase = pei->dwModuleBase;
|
|
DWORD dwTag = 0;
|
|
|
|
SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_SYMTAG, &dwTag);
|
|
|
|
switch (dwTag)
|
|
{
|
|
case SymTagEnum:
|
|
DumpEnum(dwTypeIndex, pei, indent, bMembers);
|
|
break;
|
|
|
|
case SymTagUDT:
|
|
DumpUDT(dwTypeIndex, pei, indent, bMembers);
|
|
break;
|
|
|
|
case SymTagPointerType:
|
|
DumpPointer(dwTypeIndex, pei, indent);
|
|
break;
|
|
|
|
case SymTagBaseType:
|
|
DumpBaseType(dwTypeIndex, pei, indent);
|
|
break;
|
|
|
|
case SymTagArrayType:
|
|
DumpArray(dwTypeIndex, pei, indent);
|
|
break;
|
|
|
|
case SymTagFunctionType:
|
|
printfi("function");
|
|
break;
|
|
|
|
default:
|
|
printfi("typeTag%ld", dwTag);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpCV(DWORD dwTypeIndex, PENUMINFO pei)
|
|
{
|
|
DWORD cv = 0x20;
|
|
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_CALLING_CONVENTION, &cv);
|
|
switch (cv)
|
|
{
|
|
case CV_CALL_NEAR_C:
|
|
printf("CDECL");
|
|
return;
|
|
case CV_CALL_FAR_C:
|
|
printf("FAR CDECL");
|
|
return;
|
|
case CV_CALL_NEAR_PASCAL:
|
|
printf("PASCAL");
|
|
return;
|
|
case CV_CALL_FAR_PASCAL:
|
|
printf("FAR PASCAL");
|
|
return;
|
|
case CV_CALL_NEAR_FAST:
|
|
printf("FASTCALL");
|
|
return;
|
|
case CV_CALL_FAR_FAST:
|
|
printf("FAR FASTCALL");
|
|
return;
|
|
case CV_CALL_SKIPPED:
|
|
printf("SKIPPED");
|
|
return;
|
|
case CV_CALL_NEAR_STD:
|
|
printf("STDCALL");
|
|
return;
|
|
case CV_CALL_FAR_STD:
|
|
printf("FAR STDCALL");
|
|
return;
|
|
case CV_CALL_NEAR_SYS:
|
|
case CV_CALL_FAR_SYS:
|
|
case CV_CALL_THISCALL:
|
|
printf("THISCALL");
|
|
return;
|
|
case CV_CALL_MIPSCALL:
|
|
printf("MIPSCALL");
|
|
return;
|
|
case CV_CALL_GENERIC:
|
|
case CV_CALL_ALPHACALL:
|
|
case CV_CALL_PPCCALL:
|
|
case CV_CALL_SHCALL:
|
|
case CV_CALL_ARMCALL:
|
|
case CV_CALL_AM33CALL:
|
|
case CV_CALL_TRICALL:
|
|
case CV_CALL_SH5CALL:
|
|
case CV_CALL_M32RCALL:
|
|
default:
|
|
printf("UNKNOWNCV");
|
|
}
|
|
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
EnumParamsProc(
|
|
PSYMBOL_INFO pSymInfo,
|
|
ULONG SymbolSize,
|
|
PVOID UserContext)
|
|
{
|
|
printf("x, ");
|
|
(*(INT*)UserContext)++;
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
DumpParams(PSYMBOL_INFO pSymInfo, PENUMINFO pei)
|
|
{
|
|
IMAGEHLP_STACK_FRAME sf;
|
|
BOOL bRet;
|
|
|
|
sf.InstructionOffset = pSymInfo->Address;
|
|
|
|
printf("(");
|
|
bRet = SymSetContext(pei->hProcess, &sf, 0);
|
|
|
|
if (!bRet)
|
|
{
|
|
printf("\nError: SymSetContext() failed. Error code: %lu \n", GetLastError());
|
|
return;
|
|
}
|
|
printf("Address == 0x%x, ReturnOffset = 0x%x", (UINT)pSymInfo->Address, (UINT)sf.ReturnOffset);
|
|
|
|
// Enumerate local variables
|
|
|
|
INT NumLocals = 0; // the number of local variables found
|
|
|
|
bRet = SymEnumSymbols(pei->hProcess, 0, 0, EnumParamsProc, &NumLocals);
|
|
|
|
if (!bRet)
|
|
{
|
|
// printf("Error: SymEnumSymbols() failed. Error code: %lu \n", GetLastError());
|
|
printf("?)");
|
|
return;
|
|
}
|
|
|
|
if (NumLocals == 0)
|
|
{
|
|
// printf("The function does not have parameters and local variables.\n");
|
|
printf("void)");
|
|
}
|
|
|
|
printf(")");
|
|
}
|
|
|
|
VOID
|
|
DumpFunction(PSYMBOL_INFO pSymInfo, PENUMINFO pei)
|
|
{
|
|
DWORD dwTypeId;
|
|
|
|
//printf("Name=%s, Size=%ld, TypeId=0x%ld\n", pSymInfo->Name, pSymInfo->Size, pSymInfo->TypeIndex);
|
|
|
|
SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, pSymInfo->TypeIndex, TI_GET_TYPEID, &dwTypeId);
|
|
|
|
// DumpCV(pSymInfo->TypeIndex, pei);
|
|
// printf("\n");
|
|
// DumpType(pSymInfo->TypeIndex, pei, 0, FALSE);
|
|
printf("%s", pSymInfo->Name);
|
|
DumpParams(pSymInfo, pei);
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
EnumSymbolsProc(
|
|
PSYMBOL_INFO pSymInfo,
|
|
ULONG SymbolSize,
|
|
PVOID UserContext)
|
|
{
|
|
PENUMINFO pei = (PENUMINFO)UserContext;
|
|
|
|
if ((pei->pszSymbolName == NULL) ||
|
|
(strstr(pSymInfo->Name, pei->pszSymbolName) != 0))
|
|
{
|
|
if (pei->bType)
|
|
{
|
|
DumpType(pSymInfo->TypeIndex, pei, 0, TRUE);
|
|
printf("\n\n");
|
|
}
|
|
else
|
|
{
|
|
//if (pSymInfo->Flags & SYMFLAG_FUNCTION)
|
|
{
|
|
// DumpFunction(pSymInfo, pei);
|
|
// printf("\n\n");
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
HANDLE hProcess;
|
|
CHAR szFullFileName[MAX_PATH+1];
|
|
DWORD64 dwModuleBase;
|
|
BOOL bRet;
|
|
LPSTR pszSymbolPath, pszSymbolName;
|
|
INT i;
|
|
ENUMINFO enuminfo;
|
|
|
|
printf("PE symbol dumper\n");
|
|
printf("Copyright (c) Timo Kreuzer 2008\n\n");
|
|
|
|
if (argc < 2)
|
|
{
|
|
PrintUsage();
|
|
return 0;
|
|
}
|
|
|
|
/* Get the full path name of the PE file from first argument */
|
|
GetFullPathName(argv[1], MAX_PATH, szFullFileName, NULL);
|
|
|
|
/* Default Symbol Name (all) */
|
|
pszSymbolName = NULL;
|
|
|
|
/* Default to ms symbol server */
|
|
pszSymbolPath = "srv**symbols*http://msdl.microsoft.com/download/symbols";
|
|
|
|
/* Check other command line arguments */
|
|
for (i = 2; i < argc; i++)
|
|
{
|
|
if (*argv[i] == '-')
|
|
{
|
|
if (strncmp(argv[i], "-sp=", 4) == 0)
|
|
{
|
|
pszSymbolPath = argv[i] + 4;
|
|
}
|
|
else if (strcmp(argv[i], "-p") == 0)
|
|
{
|
|
g_bShowPos = 1;
|
|
}
|
|
else
|
|
{
|
|
printf("Invalid argument: %s\n", argv[i]);
|
|
PrintUsage();
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszSymbolName = argv[i];
|
|
}
|
|
}
|
|
|
|
hProcess = GetCurrentProcess();
|
|
|
|
printf("Trying to get symbols from: %s\n", pszSymbolPath);
|
|
|
|
if (!InitDbgHelp(hProcess, pszSymbolPath))
|
|
{
|
|
printf("SymInitialize() failed\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
printf("Loading symbols for %s, please wait...\n", szFullFileName);
|
|
dwModuleBase = SymLoadModule64(hProcess, 0, szFullFileName, 0, 0, 0);
|
|
if (dwModuleBase == 0)
|
|
{
|
|
printf("SymLoadModule64() failed: %ld\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
printf("\nSymbols:\n");
|
|
enuminfo.hProcess = hProcess;
|
|
enuminfo.pszSymbolName = pszSymbolName;
|
|
enuminfo.bType = FALSE;
|
|
SetLastError(ERROR_SUCCESS);
|
|
bRet = SymEnumSymbols(hProcess, dwModuleBase, NULL, EnumSymbolsProc, &enuminfo);
|
|
if (!bRet)
|
|
{
|
|
printf("SymEnumSymbols failed: %ld\n", GetLastError());
|
|
}
|
|
|
|
printf("\nTypes:\n");
|
|
enuminfo.bType = TRUE;
|
|
enuminfo.dwModuleBase = dwModuleBase;
|
|
SetLastError(ERROR_SUCCESS);
|
|
bRet = SymEnumTypes(hProcess, dwModuleBase, EnumSymbolsProc, &enuminfo);
|
|
if (!bRet)
|
|
{
|
|
printf("SymEnumTypes failed: %ld\n", GetLastError());
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return 0;
|
|
}
|