6 * Copyright (c) 2008 Timo Kreuzer <timo <dot> kreuzer <at> reactos <dot> org>
8 * This program is released under the terms of the GNU GPL.
13 * - include the correct headers for some stuff
14 * - fix unions like LARGE_INTEGER
23 HANDLE hCurrentProcess
;
26 #define MAX_SYMBOL_NAME 1024
28 #define CV_CALL_NEAR_C 0x00
29 #define CV_CALL_FAR_C 0x01
30 #define CV_CALL_NEAR_PASCAL 0x02
31 #define CV_CALL_FAR_PASCAL 0x03
32 #define CV_CALL_NEAR_FAST 0x04
33 #define CV_CALL_FAR_FAST 0x05
34 #define CV_CALL_SKIPPED 0x06
35 #define CV_CALL_NEAR_STD 0x07
36 #define CV_CALL_FAR_STD 0x08
37 #define CV_CALL_NEAR_SYS 0x09
38 #define CV_CALL_FAR_SYS 0x0a
39 #define CV_CALL_THISCALL 0x0b
40 #define CV_CALL_MIPSCALL 0x0c
41 #define CV_CALL_GENERIC 0x0d
42 #define CV_CALL_ALPHACALL 0x0e
43 #define CV_CALL_PPCCALL 0x0f
44 #define CV_CALL_SHCALL 0x10
45 #define CV_CALL_ARMCALL 0x11
46 #define CV_CALL_AM33CALL 0x12
47 #define CV_CALL_TRICALL 0x13
48 #define CV_CALL_SH5CALL 0x14
49 #define CV_CALL_M32RCALL 0x15
56 SymTagCompilandDetails
,
73 SymTagFunctionArgType
,
90 UDTKind_Class
= 1, /* ? */
119 DWORD64 dwModuleBase
;
122 } ENUMINFO
, *PENUMINFO
;
124 VOID
DumpType(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
);
126 CHAR
*SymTagString
[] =
131 "SymTagCompilandDetails",
132 "SymTagCompilandEnv",
138 "SymTagPublicSymbol",
141 "SymTagFunctionType",
148 "SymTagFunctionArgType",
149 "SymTagFuncDebugStart",
150 "SymTagFuncDebugEnd",
151 "SymTagUsingNamespace",
166 for (i
= 0; i
< ind
; i
++)
173 IndentPrint(indent); printf
178 printf("Syntax:\n\n");
179 printf("dumpsym <file> [-sp=<symbolpath>] [-p] [<symname>]\n\n");
180 printf("<file> The PE file you want to dump the symbols of\n");
181 printf("-sp=<symbolpath> Path to your symbol files.\n");
182 printf(" Default is MS symbol server.\n");
183 printf("-p Enable struct positions.\n");
184 printf("<symname> A name of a Symbol, you want to dump\n");
185 printf(" Default is all symbols.\n");
189 BOOL
InitDbgHelp(HANDLE hProcess
, LPSTR pszSymbolPath
)
191 if (!SymInitialize(hProcess
, 0, FALSE
))
194 SymSetOptions(SymGetOptions() | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS
);
195 SymSetOptions(SymGetOptions() & (~SYMOPT_DEFERRED_LOADS
));
196 SymSetSearchPath(hProcess
, pszSymbolPath
);
201 DumpBaseType(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
)
206 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_LENGTH
, &ulSize
);
207 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_BASETYPE
, &dwBaseType
);
236 printfi("INT%ld", (ULONG
)ulSize
* 8);
255 printfi("UINT%ld", (ULONG
)ulSize
* 8);
268 printfi("FLOAT%ld", (ULONG
)ulSize
* 8);
272 printfi("BCD%ld", (ULONG
)ulSize
* 8);
284 printfi("BOOL%ld", (ULONG
)ulSize
* 8);
303 printfi("LONG%ld", (ULONG
)ulSize
* 8);
319 printfi("ULONGLONG");
322 printfi("ULONG%ld", (ULONG
)ulSize
* 8);
331 printfi("UNSUP_%ld_%ld", dwBaseType
, (ULONG
)ulSize
);
339 printfi("HRESULT%ld", (ULONG
)ulSize
);
343 printfi("UNKNBASETYPE");
347 DumpArray(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
)
351 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_TYPE
, &dwTypeId
);
352 DumpType(dwTypeId
, pei
, indent
, FALSE
);
356 DumpPointer(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
)
363 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_TYPE
, &dwRefTypeId
);
364 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwRefTypeId
, TI_GET_BASETYPE
, &dwBaseType
);
365 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwRefTypeId
, TI_GET_LENGTH
, &ulSize
);
366 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwRefTypeId
, TI_GET_SYMTAG
, &dwTag
);
368 if (dwTag
== SymTagFunctionType
)
448 printfi("PLONGLONG");
459 printfi("PULONGLONG");
473 DumpType(dwRefTypeId
, pei
, indent
, FALSE
);
478 PrintVariant(VARIANT
*v
)
480 // printf("<vt%d>", v->n1.n2.vt);
484 printf("%d", (INT
)v
->n1
.n2
.n3
.cVal
);
487 printf("0x%x", (UINT
)v
->n1
.n2
.n3
.cVal
);
490 printf("%d", (UINT
)v
->n1
.n2
.n3
.iVal
);
493 printf("0x%x", (UINT
)v
->n1
.n2
.n3
.iVal
);
497 printf("%d", (UINT
)v
->n1
.n2
.n3
.lVal
);
501 printf("0x%x", (UINT
)v
->n1
.n2
.n3
.lVal
);
507 IsUnnamed(WCHAR
*pszName
)
509 if ((StrStrW(pszName
, L
"__unnamed") != NULL
) ||
510 (StrStrW(pszName
, L
"<unnamed-tag>") != NULL
))
518 DumpEnum(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
)
520 DWORD64 dwModuleBase
= pei
->dwModuleBase
;
521 HANDLE hProcess
= pei
->hProcess
;
524 WCHAR
*pszName
, *pszNameX
;
527 TI_FINDCHILDREN_PARAMS tfp
;
532 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_SYMNAME
, &pszNameX
);
533 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_UDTKIND
, &dwUDTKind
);
535 if (IsUnnamed(pszName
))
545 printfi("enum %ls", pszName
);
550 printf(" /* %03x */", 0);
553 /* Get the children */
554 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_CHILDRENCOUNT
, &tfpex
.tfp
.Count
);
557 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_FINDCHILDREN
, &tfpex
.tfp
);
559 for (i
= 0; i
< tfpex
.tfp
.Count
; i
++)
563 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_SYMNAME
, &pszName
);
564 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_VALUE
, &v
);
567 printfi("%ls = ", pszName
);
579 DumpUDT(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
)
581 DWORD64 dwModuleBase
= pei
->dwModuleBase
;
582 HANDLE hProcess
= pei
->hProcess
;
585 WCHAR
*pszName
, *pszNameX
;
588 TI_FINDCHILDREN_PARAMS tfp
;
597 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_SYMNAME
, &pszNameX
);
598 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_UDTKIND
, &dwUDTKind
);
601 if (IsUnnamed(pszName
))
611 if (dwUDTKind
== UDTKind_Struct
)
613 printfi("struct %ls", pszName
);
615 else if (dwUDTKind
== UDTKind_Union
)
617 printfi("union %ls", pszName
);
621 printfi("UTDKind%ld %ls", dwUDTKind
, pszName
);
632 /* Get the children */
633 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_CHILDRENCOUNT
, &tfpex
.tfp
.Count
);
636 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_FINDCHILDREN
, &tfpex
.tfp
);
638 for (i
= 0; i
< tfpex
.tfp
.Count
; i
++)
646 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_SYMNAME
, &pszName
);
647 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_DATAKIND
, &dwDataKind
);
648 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_TYPE
, &dwTypeId
);
649 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_OFFSET
, &dwOffset
);
650 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeId
, TI_GET_SYMTAG
, &dwChildTag
);
651 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeId
, TI_GET_LENGTH
, &ulLength
);
653 printf(" /* %03lx */", dwOffset
);
654 DumpType(dwTypeId
, pei
, indent
+ 1, FALSE
);
655 printf(" %ls", pszName
);
656 if (dwChildTag
== SymTagArrayType
)
658 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeId
, TI_GET_COUNT
, &dwCount
);
659 printf("[%ld]", dwCount
);
663 DWORD dwCurrentBitPos
;
666 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_BITPOSITION
, &dwCurrentBitPos
);
667 if (i
< tfpex
.tfp
.Count
- 1)
669 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
+1], TI_GET_BITPOSITION
, &dwNextBitPos
);
676 if (dwNextBitPos
== 0 && dwCurrentBitPos
!= 0)
678 dwNextBitPos
= ulLength
* 8;
681 if (dwNextBitPos
!= dwCurrentBitPos
)
683 printf(":%ld", dwNextBitPos
- dwCurrentBitPos
);
694 DumpType(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
)
696 HANDLE hProcess
= pei
->hProcess
;
697 DWORD64 dwModuleBase
= pei
->dwModuleBase
;
700 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_SYMTAG
, &dwTag
);
705 DumpEnum(dwTypeIndex
, pei
, indent
, bMembers
);
709 DumpUDT(dwTypeIndex
, pei
, indent
, bMembers
);
712 case SymTagPointerType
:
713 DumpPointer(dwTypeIndex
, pei
, indent
);
717 DumpBaseType(dwTypeIndex
, pei
, indent
);
720 case SymTagArrayType
:
721 DumpArray(dwTypeIndex
, pei
, indent
);
724 case SymTagFunctionType
:
729 printfi("typeTag%ld", dwTag
);
737 DumpCV(DWORD dwTypeIndex
, PENUMINFO pei
)
741 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_CALLING_CONVENTION
, &cv
);
750 case CV_CALL_NEAR_PASCAL
:
753 case CV_CALL_FAR_PASCAL
:
754 printf("FAR PASCAL");
756 case CV_CALL_NEAR_FAST
:
759 case CV_CALL_FAR_FAST
:
760 printf("FAR FASTCALL");
762 case CV_CALL_SKIPPED
:
765 case CV_CALL_NEAR_STD
:
768 case CV_CALL_FAR_STD
:
769 printf("FAR STDCALL");
771 case CV_CALL_NEAR_SYS
:
772 case CV_CALL_FAR_SYS
:
773 case CV_CALL_THISCALL
:
776 case CV_CALL_MIPSCALL
:
779 case CV_CALL_GENERIC
:
780 case CV_CALL_ALPHACALL
:
781 case CV_CALL_PPCCALL
:
783 case CV_CALL_ARMCALL
:
784 case CV_CALL_AM33CALL
:
785 case CV_CALL_TRICALL
:
786 case CV_CALL_SH5CALL
:
787 case CV_CALL_M32RCALL
:
796 PSYMBOL_INFO pSymInfo
,
801 (*(INT
*)UserContext
)++;
806 DumpParams(PSYMBOL_INFO pSymInfo
, PENUMINFO pei
)
808 IMAGEHLP_STACK_FRAME sf
;
811 sf
.InstructionOffset
= pSymInfo
->Address
;
814 bRet
= SymSetContext(pei
->hProcess
, &sf
, 0);
818 printf("\nError: SymSetContext() failed. Error code: %lu \n", GetLastError());
821 printf("Address == 0x%x, ReturnOffset = 0x%x", (UINT
)pSymInfo
->Address
, (UINT
)sf
.ReturnOffset
);
823 // Enumerate local variables
825 INT NumLocals
= 0; // the number of local variables found
827 bRet
= SymEnumSymbols(pei
->hProcess
, 0, 0, EnumParamsProc
, &NumLocals
);
831 // printf("Error: SymEnumSymbols() failed. Error code: %lu \n", GetLastError());
838 // printf("The function does not have parameters and local variables.\n");
846 DumpFunction(PSYMBOL_INFO pSymInfo
, PENUMINFO pei
)
850 //printf("Name=%s, Size=%ld, TypeId=0x%ld\n", pSymInfo->Name, pSymInfo->Size, pSymInfo->TypeIndex);
852 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, pSymInfo
->TypeIndex
, TI_GET_TYPEID
, &dwTypeId
);
854 // DumpCV(pSymInfo->TypeIndex, pei);
856 // DumpType(pSymInfo->TypeIndex, pei, 0, FALSE);
857 printf("%s", pSymInfo
->Name
);
858 DumpParams(pSymInfo
, pei
);
863 PSYMBOL_INFO pSymInfo
,
867 PENUMINFO pei
= (PENUMINFO
)UserContext
;
869 if ((pei
->pszSymbolName
== NULL
) ||
870 (strstr(pSymInfo
->Name
, pei
->pszSymbolName
) != 0))
874 DumpType(pSymInfo
->TypeIndex
, pei
, 0, TRUE
);
879 //if (pSymInfo->Flags & SYMFLAG_FUNCTION)
881 // DumpFunction(pSymInfo, pei);
889 int main(int argc
, char* argv
[])
892 CHAR szFullFileName
[MAX_PATH
+1];
893 DWORD64 dwModuleBase
;
895 LPSTR pszSymbolPath
, pszSymbolName
;
899 printf("PE symbol dumper\n");
900 printf("Copyright (c) Timo Kreuzer 2008\n\n");
908 /* Get the full path name of the PE file from first argument */
909 GetFullPathName(argv
[1], MAX_PATH
, szFullFileName
, NULL
);
911 /* Default Symbol Name (all) */
912 pszSymbolName
= NULL
;
914 /* Default to ms symbol server */
915 pszSymbolPath
= "srv**symbols*http://msdl.microsoft.com/download/symbols";
917 /* Check other command line arguments */
918 for (i
= 2; i
< argc
; i
++)
922 if (strncmp(argv
[i
], "-sp=", 4) == 0)
924 pszSymbolPath
= argv
[i
] + 4;
926 else if (strcmp(argv
[i
], "-p") == 0)
932 printf("Invalid argument: %s\n", argv
[i
]);
939 pszSymbolName
= argv
[i
];
943 hProcess
= GetCurrentProcess();
945 printf("Trying to get symbols from: %s\n", pszSymbolPath
);
947 if (!InitDbgHelp(hProcess
, pszSymbolPath
))
949 printf("SymInitialize() failed\n");
953 printf("Loading symbols for %s, please wait...\n", szFullFileName
);
954 dwModuleBase
= SymLoadModule64(hProcess
, 0, szFullFileName
, 0, 0, 0);
955 if (dwModuleBase
== 0)
957 printf("SymLoadModule64() failed: %ld\n", GetLastError());
961 printf("\nSymbols:\n");
962 enuminfo
.hProcess
= hProcess
;
963 enuminfo
.pszSymbolName
= pszSymbolName
;
964 enuminfo
.bType
= FALSE
;
965 SetLastError(ERROR_SUCCESS
);
966 bRet
= SymEnumSymbols(hProcess
, dwModuleBase
, NULL
, EnumSymbolsProc
, &enuminfo
);
969 printf("SymEnumSymbols failed: %ld\n", GetLastError());
972 printf("\nTypes:\n");
973 enuminfo
.bType
= TRUE
;
974 enuminfo
.dwModuleBase
= dwModuleBase
;
975 SetLastError(ERROR_SUCCESS
);
976 bRet
= SymEnumTypes(hProcess
, dwModuleBase
, EnumSymbolsProc
, &enuminfo
);
979 printf("SymEnumTypes failed: %ld\n", GetLastError());