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
19 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
24 HANDLE hCurrentProcess
;
27 #define MAX_SYMBOL_NAME 1024
29 #define CV_CALL_NEAR_C 0x00
30 #define CV_CALL_FAR_C 0x01
31 #define CV_CALL_NEAR_PASCAL 0x02
32 #define CV_CALL_FAR_PASCAL 0x03
33 #define CV_CALL_NEAR_FAST 0x04
34 #define CV_CALL_FAR_FAST 0x05
35 #define CV_CALL_SKIPPED 0x06
36 #define CV_CALL_NEAR_STD 0x07
37 #define CV_CALL_FAR_STD 0x08
38 #define CV_CALL_NEAR_SYS 0x09
39 #define CV_CALL_FAR_SYS 0x0a
40 #define CV_CALL_THISCALL 0x0b
41 #define CV_CALL_MIPSCALL 0x0c
42 #define CV_CALL_GENERIC 0x0d
43 #define CV_CALL_ALPHACALL 0x0e
44 #define CV_CALL_PPCCALL 0x0f
45 #define CV_CALL_SHCALL 0x10
46 #define CV_CALL_ARMCALL 0x11
47 #define CV_CALL_AM33CALL 0x12
48 #define CV_CALL_TRICALL 0x13
49 #define CV_CALL_SH5CALL 0x14
50 #define CV_CALL_M32RCALL 0x15
57 SymTagCompilandDetails
,
74 SymTagFunctionArgType
,
91 UDTKind_Class
= 1, /* ? */
120 DWORD64 dwModuleBase
;
123 } ENUMINFO
, *PENUMINFO
;
125 VOID
DumpType(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
);
127 CHAR
*SymTagString
[] =
132 "SymTagCompilandDetails",
133 "SymTagCompilandEnv",
139 "SymTagPublicSymbol",
142 "SymTagFunctionType",
149 "SymTagFunctionArgType",
150 "SymTagFuncDebugStart",
151 "SymTagFuncDebugEnd",
152 "SymTagUsingNamespace",
167 for (i
= 0; i
< ind
; i
++)
174 IndentPrint(indent); printf
179 printf("Syntax:\n\n");
180 printf("dumpsym <file> [-sp=<symbolpath>] [-p] [<symname>]\n\n");
181 printf("<file> The PE file you want to dump the symbols of\n");
182 printf("-sp=<symbolpath> Path to your symbol files.\n");
183 printf(" Default is MS symbol server.\n");
184 printf("-p Enable struct positions.\n");
185 printf("<symname> A name of a Symbol, you want to dump\n");
186 printf(" Default is all symbols.\n");
190 BOOL
InitDbgHelp(HANDLE hProcess
, LPSTR pszSymbolPath
)
192 if (!SymInitialize(hProcess
, 0, FALSE
))
195 SymSetOptions(SymGetOptions() | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS
);
196 SymSetOptions(SymGetOptions() & (~SYMOPT_DEFERRED_LOADS
));
197 SymSetSearchPath(hProcess
, pszSymbolPath
);
202 DumpBaseType(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
)
207 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_LENGTH
, &ulSize
);
208 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_BASETYPE
, &dwBaseType
);
237 printfi("INT%ld", (ULONG
)ulSize
* 8);
256 printfi("UINT%ld", (ULONG
)ulSize
* 8);
269 printfi("FLOAT%ld", (ULONG
)ulSize
* 8);
273 printfi("BCD%ld", (ULONG
)ulSize
* 8);
285 printfi("BOOL%ld", (ULONG
)ulSize
* 8);
304 printfi("LONG%ld", (ULONG
)ulSize
* 8);
320 printfi("ULONGLONG");
323 printfi("ULONG%ld", (ULONG
)ulSize
* 8);
332 printfi("UNSUP_%ld_%ld", dwBaseType
, (ULONG
)ulSize
);
340 printfi("HRESULT%ld", (ULONG
)ulSize
);
344 printfi("UNKNBASETYPE");
348 DumpArray(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
)
352 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_TYPE
, &dwTypeId
);
353 DumpType(dwTypeId
, pei
, indent
, FALSE
);
357 DumpPointer(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
)
364 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_TYPE
, &dwRefTypeId
);
365 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwRefTypeId
, TI_GET_BASETYPE
, &dwBaseType
);
366 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwRefTypeId
, TI_GET_LENGTH
, &ulSize
);
367 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwRefTypeId
, TI_GET_SYMTAG
, &dwTag
);
369 if (dwTag
== SymTagFunctionType
)
449 printfi("PLONGLONG");
460 printfi("PULONGLONG");
474 DumpType(dwRefTypeId
, pei
, indent
, FALSE
);
479 PrintVariant(VARIANT
*v
)
481 // printf("<vt%d>", v->n1.n2.vt);
485 printf("%d", (INT
)v
->n1
.n2
.n3
.cVal
);
488 printf("0x%x", (UINT
)v
->n1
.n2
.n3
.cVal
);
491 printf("%d", (UINT
)v
->n1
.n2
.n3
.iVal
);
494 printf("0x%x", (UINT
)v
->n1
.n2
.n3
.iVal
);
498 printf("%d", (UINT
)v
->n1
.n2
.n3
.lVal
);
502 printf("0x%x", (UINT
)v
->n1
.n2
.n3
.lVal
);
508 IsUnnamed(WCHAR
*pszName
)
510 if ((StrStrW(pszName
, L
"__unnamed") != NULL
) ||
511 (StrStrW(pszName
, L
"<unnamed-tag>") != NULL
))
519 DumpEnum(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
)
521 DWORD64 dwModuleBase
= pei
->dwModuleBase
;
522 HANDLE hProcess
= pei
->hProcess
;
525 WCHAR
*pszName
, *pszNameX
;
528 TI_FINDCHILDREN_PARAMS tfp
;
533 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_SYMNAME
, &pszNameX
);
534 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_UDTKIND
, &dwUDTKind
);
536 if (IsUnnamed(pszName
))
546 printfi("enum %ls", pszName
);
551 printf(" /* %03x */", 0);
554 /* Get the children */
555 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_CHILDRENCOUNT
, &tfpex
.tfp
.Count
);
558 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_FINDCHILDREN
, &tfpex
.tfp
);
560 for (i
= 0; i
< tfpex
.tfp
.Count
; i
++)
564 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_SYMNAME
, &pszName
);
565 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_VALUE
, &v
);
568 printfi("%ls = ", pszName
);
580 DumpUDT(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
)
582 DWORD64 dwModuleBase
= pei
->dwModuleBase
;
583 HANDLE hProcess
= pei
->hProcess
;
586 WCHAR
*pszName
, *pszNameX
;
589 TI_FINDCHILDREN_PARAMS tfp
;
598 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_SYMNAME
, &pszNameX
);
599 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_UDTKIND
, &dwUDTKind
);
602 if (IsUnnamed(pszName
))
612 if (dwUDTKind
== UDTKind_Struct
)
614 printfi("struct %ls", pszName
);
616 else if (dwUDTKind
== UDTKind_Union
)
618 printfi("union %ls", pszName
);
622 printfi("UTDKind%ld %ls", dwUDTKind
, pszName
);
633 /* Get the children */
634 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_CHILDRENCOUNT
, &tfpex
.tfp
.Count
);
637 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_FINDCHILDREN
, &tfpex
.tfp
);
639 for (i
= 0; i
< tfpex
.tfp
.Count
; i
++)
647 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_SYMNAME
, &pszName
);
648 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_DATAKIND
, &dwDataKind
);
649 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_TYPE
, &dwTypeId
);
650 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_OFFSET
, &dwOffset
);
651 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeId
, TI_GET_SYMTAG
, &dwChildTag
);
652 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeId
, TI_GET_LENGTH
, &ulLength
);
654 printf(" /* %03lx */", dwOffset
);
655 DumpType(dwTypeId
, pei
, indent
+ 1, FALSE
);
656 printf(" %ls", pszName
);
657 if (dwChildTag
== SymTagArrayType
)
659 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeId
, TI_GET_COUNT
, &dwCount
);
660 printf("[%ld]", dwCount
);
664 DWORD dwCurrentBitPos
;
667 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
], TI_GET_BITPOSITION
, &dwCurrentBitPos
);
668 if (i
< tfpex
.tfp
.Count
- 1)
670 SymGetTypeInfo(hProcess
, dwModuleBase
, tfpex
.tfp
.ChildId
[i
+1], TI_GET_BITPOSITION
, &dwNextBitPos
);
677 if (dwNextBitPos
== 0 && dwCurrentBitPos
!= 0)
679 dwNextBitPos
= ulLength
* 8;
682 if (dwNextBitPos
!= dwCurrentBitPos
)
684 printf(":%ld", dwNextBitPos
- dwCurrentBitPos
);
695 DumpType(DWORD dwTypeIndex
, PENUMINFO pei
, INT indent
, BOOL bMembers
)
697 HANDLE hProcess
= pei
->hProcess
;
698 DWORD64 dwModuleBase
= pei
->dwModuleBase
;
701 SymGetTypeInfo(hProcess
, dwModuleBase
, dwTypeIndex
, TI_GET_SYMTAG
, &dwTag
);
706 DumpEnum(dwTypeIndex
, pei
, indent
, bMembers
);
710 DumpUDT(dwTypeIndex
, pei
, indent
, bMembers
);
713 case SymTagPointerType
:
714 DumpPointer(dwTypeIndex
, pei
, indent
);
718 DumpBaseType(dwTypeIndex
, pei
, indent
);
721 case SymTagArrayType
:
722 DumpArray(dwTypeIndex
, pei
, indent
);
725 case SymTagFunctionType
:
730 printfi("typeTag%ld", dwTag
);
738 DumpCV(DWORD dwTypeIndex
, PENUMINFO pei
)
742 SymGetTypeInfo(pei
->hProcess
, pei
->dwModuleBase
, dwTypeIndex
, TI_GET_CALLING_CONVENTION
, &cv
);
751 case CV_CALL_NEAR_PASCAL
:
754 case CV_CALL_FAR_PASCAL
:
755 printf("FAR PASCAL");
757 case CV_CALL_NEAR_FAST
:
760 case CV_CALL_FAR_FAST
:
761 printf("FAR FASTCALL");
763 case CV_CALL_SKIPPED
:
766 case CV_CALL_NEAR_STD
:
769 case CV_CALL_FAR_STD
:
770 printf("FAR STDCALL");
772 case CV_CALL_NEAR_SYS
:
773 case CV_CALL_FAR_SYS
:
774 case CV_CALL_THISCALL
:
777 case CV_CALL_MIPSCALL
:
780 case CV_CALL_GENERIC
:
781 case CV_CALL_ALPHACALL
:
782 case CV_CALL_PPCCALL
:
784 case CV_CALL_ARMCALL
:
785 case CV_CALL_AM33CALL
:
786 case CV_CALL_TRICALL
:
787 case CV_CALL_SH5CALL
:
788 case CV_CALL_M32RCALL
:
797 PSYMBOL_INFO pSymInfo
,
802 (*(INT
*)UserContext
)++;
807 DumpParams(PSYMBOL_INFO pSymInfo
, PENUMINFO pei
)
809 IMAGEHLP_STACK_FRAME sf
;
811 INT NumLocals
= 0; // the number of local variables found
813 sf
.InstructionOffset
= pSymInfo
->Address
;
816 bRet
= SymSetContext(pei
->hProcess
, &sf
, 0);
820 printf("\nError: SymSetContext() failed. Error code: %lu \n", GetLastError());
823 printf("Address == 0x%x, ReturnOffset = 0x%x", (UINT
)pSymInfo
->Address
, (UINT
)sf
.ReturnOffset
);
825 // Enumerate local variables
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 defined(__GNUC__) && \
880 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400)
881 printf("Symbol: %s, TypeIndex=%ld, Flags=%lx, Value=0x%llx\n",
883 printf("Symbol: %s, TypeIndex=%ld, Flags=%lx, Value=0x%I64x\n",
885 pSymInfo
->Name
, pSymInfo
->TypeIndex
, pSymInfo
->Flags
, pSymInfo
->Value
);
886 //if (pSymInfo->Flags & SYMFLAG_FUNCTION)
888 // DumpFunction(pSymInfo, pei);
896 int main(int argc
, char* argv
[])
899 CHAR szFullFileName
[MAX_PATH
+1];
900 DWORD64 dwModuleBase
;
902 LPSTR pszSymbolPath
, pszSymbolName
;
906 printf("PE symbol dumper\n");
907 printf("Copyright (c) Timo Kreuzer 2008\n\n");
915 /* Get the full path name of the PE file from first argument */
916 GetFullPathName(argv
[1], MAX_PATH
, szFullFileName
, NULL
);
918 /* Default Symbol Name (all) */
919 pszSymbolName
= NULL
;
921 /* Default to ms symbol server */
922 pszSymbolPath
= "srv**symbols*http://msdl.microsoft.com/download/symbols";
924 /* Check other command line arguments */
925 for (i
= 2; i
< argc
; i
++)
929 if (strncmp(argv
[i
], "-sp=", 4) == 0)
931 pszSymbolPath
= argv
[i
] + 4;
933 else if (strcmp(argv
[i
], "-p") == 0)
939 printf("Invalid argument: %s\n", argv
[i
]);
946 pszSymbolName
= argv
[i
];
950 hProcess
= GetCurrentProcess();
952 printf("Trying to get symbols from: %s\n", pszSymbolPath
);
954 if (!InitDbgHelp(hProcess
, pszSymbolPath
))
956 printf("SymInitialize() failed\n");
960 printf("Loading symbols for %s, please wait...\n", szFullFileName
);
961 dwModuleBase
= SymLoadModule64(hProcess
, 0, szFullFileName
, 0, 0, 0);
962 if (dwModuleBase
== 0)
964 printf("SymLoadModule64() failed: %ld\n", GetLastError());
968 printf("\nSymbols:\n");
969 enuminfo
.hProcess
= hProcess
;
970 enuminfo
.pszSymbolName
= pszSymbolName
;
971 enuminfo
.bType
= FALSE
;
972 SetLastError(ERROR_SUCCESS
);
973 bRet
= SymEnumSymbols(hProcess
, dwModuleBase
, NULL
, EnumSymbolsProc
, &enuminfo
);
976 printf("SymEnumSymbols failed: %ld\n", GetLastError());
979 printf("\nTypes:\n");
980 enuminfo
.bType
= TRUE
;
981 enuminfo
.dwModuleBase
= dwModuleBase
;
982 SetLastError(ERROR_SUCCESS
);
983 bRet
= SymEnumTypes(hProcess
, dwModuleBase
, EnumSymbolsProc
, &enuminfo
);
986 printf("SymEnumTypes failed: %ld\n", GetLastError());