- Make symdump and ctm msvc-aware
[reactos.git] / rosapps / applications / devutils / symdump / symdump.c
1 /*
2 * PE symbol dumper
3 *
4 * symdump.c
5 *
6 * Copyright (c) 2008 Timo Kreuzer <timo <dot> kreuzer <at> reactos <dot> org>
7 *
8 * This program is released under the terms of the GNU GPL.
9 *
10 * TODO:
11 * - fix GDILoObjType
12 * - fix UDTKind1
13 * - include the correct headers for some stuff
14 * - fix unions like LARGE_INTEGER
15 */
16
17 #include <stdio.h>
18 #define _WINVER 0x501
19 #include <windows.h>
20 #include <shlwapi.h>
21 #include <dbghelp.h>
22
23 HANDLE hCurrentProcess;
24 BOOL g_bShowPos = 0;
25
26 #define MAX_SYMBOL_NAME 1024
27
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
50
51 enum SymTagEnum
52 {
53 SymTagNull,
54 SymTagExe,
55 SymTagCompiland,
56 SymTagCompilandDetails,
57 SymTagCompilandEnv,
58 SymTagFunction,
59 SymTagBlock,
60 SymTagData,
61 SymTagAnnotation,
62 SymTagLabel,
63 SymTagPublicSymbol,
64 SymTagUDT,
65 SymTagEnum,
66 SymTagFunctionType,
67 SymTagPointerType,
68 SymTagArrayType,
69 SymTagBaseType,
70 SymTagTypedef,
71 SymTagBaseClass,
72 SymTagFriend,
73 SymTagFunctionArgType,
74 SymTagFuncDebugStart,
75 SymTagFuncDebugEnd,
76 SymTagUsingNamespace,
77 SymTagVTableShape,
78 SymTagVTable,
79 SymTagCustom,
80 SymTagThunk,
81 SymTagCustomType,
82 SymTagManagedType,
83 SymTagDimension,
84 SymTagMax
85 };
86
87 enum
88 {
89 UDTKind_Struct = 0,
90 UDTKind_Class = 1, /* ? */
91 UDTKind_Union = 2,
92 };
93
94 enum BasicType
95 {
96 btNoType = 0,
97 btVoid = 1,
98 btChar = 2,
99 btWChar = 3,
100 btInt = 6,
101 btUInt = 7,
102 btFloat = 8,
103 btBCD = 9,
104 btBool = 10,
105 btLong = 13,
106 btULong = 14,
107 btCurrency = 25,
108 btDate = 26,
109 btVariant = 27,
110 btComplex = 28,
111 btBit = 29,
112 btBSTR = 30,
113 btHresult = 31
114 };
115
116 typedef struct
117 {
118 HANDLE hProcess;
119 DWORD64 dwModuleBase;
120 LPSTR pszSymbolName;
121 BOOL bType;
122 } ENUMINFO, *PENUMINFO;
123
124 VOID DumpType(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers);
125
126 CHAR *SymTagString[] =
127 {
128 "SymTagNull",
129 "SymTagExe",
130 "SymTagCompiland",
131 "SymTagCompilandDetails",
132 "SymTagCompilandEnv",
133 "SymTagFunction",
134 "SymTagBlock",
135 "SymTagData",
136 "SymTagAnnotation",
137 "SymTagLabel",
138 "SymTagPublicSymbol",
139 "SymTagUDT",
140 "SymTagEnum",
141 "SymTagFunctionType",
142 "SymTagPointerType",
143 "SymTagArrayType",
144 "SymTagBaseType",
145 "SymTagTypedef",
146 "SymTagBaseClass",
147 "SymTagFriend",
148 "SymTagFunctionArgType",
149 "SymTagFuncDebugStart",
150 "SymTagFuncDebugEnd",
151 "SymTagUsingNamespace",
152 "SymTagVTableShape",
153 "SymTagVTable",
154 "SymTagCustom",
155 "SymTagThunk",
156 "SymTagCustomType",
157 "SymTagManagedType",
158 "SymTagDimension",
159 "SymTagMax"
160 };
161
162 void
163 IndentPrint(INT ind)
164 {
165 INT i;
166 for (i = 0; i < ind; i++)
167 {
168 printf(" ");
169 }
170 }
171
172 #define printfi \
173 IndentPrint(indent); printf
174
175 VOID
176 PrintUsage()
177 {
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");
186 printf("\n");
187 }
188
189 BOOL InitDbgHelp(HANDLE hProcess, LPSTR pszSymbolPath)
190 {
191 if (!SymInitialize(hProcess, 0, FALSE))
192 return FALSE;
193
194 SymSetOptions(SymGetOptions() | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
195 SymSetOptions(SymGetOptions() & (~SYMOPT_DEFERRED_LOADS));
196 SymSetSearchPath(hProcess, pszSymbolPath);
197 return TRUE;
198 }
199
200 VOID
201 DumpBaseType(DWORD dwTypeIndex, PENUMINFO pei, INT indent)
202 {
203 ULONG64 ulSize;
204 DWORD dwBaseType;
205
206 SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_LENGTH, &ulSize);
207 SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_BASETYPE, &dwBaseType);
208
209 switch (dwBaseType)
210 {
211 case btVoid:
212 printfi("VOID");
213 return;
214 case btChar:
215 printfi("CHAR");
216 return;
217 case btWChar:
218 printfi("WCHAR");
219 return;
220 case btInt:
221 switch (ulSize)
222 {
223 case 1:
224 printfi("CHAR");
225 return;
226 case 2:
227 printfi("SHORT");
228 return;
229 case 4:
230 printfi("INT");
231 return;
232 case 8:
233 printfi("INT64");
234 return;
235 default:
236 printfi("INT%ld", (ULONG)ulSize * 8);
237 return;
238 }
239 case btUInt:
240 switch (ulSize)
241 {
242 case 1:
243 printfi("UCHAR");
244 return;
245 case 2:
246 printfi("USHORT");
247 return;
248 case 4:
249 printfi("UINT");
250 return;
251 case 8:
252 printfi("UINT64");
253 return;
254 default:
255 printfi("UINT%ld", (ULONG)ulSize * 8);
256 return;
257 }
258 case btFloat:
259 switch (ulSize)
260 {
261 case 4:
262 printfi("FLOAT");
263 return;
264 case 8:
265 printfi("DOUBLE");
266 return;
267 default:
268 printfi("FLOAT%ld", (ULONG)ulSize * 8);
269 return;
270 }
271 case btBCD:
272 printfi("BCD%ld", (ULONG)ulSize * 8);
273 return;
274 case btBool:
275 switch (ulSize)
276 {
277 case 1:
278 printfi("BOOLEAN");
279 return;
280 case 4:
281 printfi("BOOL");
282 return;
283 default:
284 printfi("BOOL%ld", (ULONG)ulSize * 8);
285 return;
286 }
287 case btLong:
288 switch (ulSize)
289 {
290 case 1:
291 printfi("CHAR");
292 return;
293 case 2:
294 printfi("SHORT");
295 return;
296 case 4:
297 printfi("LONG");
298 return;
299 case 8:
300 printfi("LONGLONG");
301 return;
302 default:
303 printfi("LONG%ld", (ULONG)ulSize * 8);
304 return;
305 }
306 case btULong:
307 switch (ulSize)
308 {
309 case 1:
310 printfi("UCHAR");
311 return;
312 case 2:
313 printfi("USHORT");
314 return;
315 case 4:
316 printfi("ULONG");
317 return;
318 case 8:
319 printfi("ULONGLONG");
320 return;
321 default:
322 printfi("ULONG%ld", (ULONG)ulSize * 8);
323 return;
324 }
325 case btCurrency:
326 case btDate:
327 case btVariant:
328 case btComplex:
329 case btBit:
330 case btBSTR:
331 printfi("UNSUP_%ld_%ld", dwBaseType, (ULONG)ulSize);
332 return;
333 case btHresult:
334 if (ulSize == 4)
335 {
336 printfi("HRESULT");
337 return;
338 }
339 printfi("HRESULT%ld", (ULONG)ulSize);
340 return;
341 }
342
343 printfi("UNKNBASETYPE");
344 }
345
346 VOID
347 DumpArray(DWORD dwTypeIndex, PENUMINFO pei, INT indent)
348 {
349 DWORD dwTypeId;
350
351 SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_TYPE, &dwTypeId);
352 DumpType(dwTypeId, pei, indent, FALSE);
353 }
354
355 VOID
356 DumpPointer(DWORD dwTypeIndex, PENUMINFO pei, INT indent)
357 {
358 DWORD dwRefTypeId;
359 DWORD dwTag = 0;
360 ULONG64 ulSize;
361 DWORD dwBaseType;
362
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);
367
368 if (dwTag == SymTagFunctionType)
369 {
370 printfi("PPROC");
371 return;
372 }
373
374 switch (dwBaseType)
375 {
376 case btVoid:
377 switch (ulSize)
378 {
379 case 0:
380 printfi("PVOID");
381 return;
382 }
383 break;
384
385 case btChar:
386 switch (ulSize)
387 {
388 case 1:
389 printfi("PCHAR");
390 return;
391 }
392 break;
393 case btWChar:
394 switch (ulSize)
395 {
396 case 2:
397 printfi("PWCHAR");
398 return;
399 }
400 break;
401 case btInt:
402 switch (ulSize)
403 {
404 case 4:
405 printfi("PINT");
406 return;
407 }
408 break;
409 case btUInt:
410 switch (ulSize)
411 {
412 case 4:
413 printfi("PUINT");
414 return;
415 }
416 break;
417 case btFloat:
418 switch (ulSize)
419 {
420 case 4:
421 printfi("PFLOAT");
422 return;
423 case 8:
424 printfi("PDOUBLE");
425 return;
426 }
427 break;
428 case btBCD:
429 break;
430 case btBool:
431 switch (ulSize)
432 {
433 case 1:
434 printfi("PBOOLEAN");
435 return;
436 case 4:
437 printfi("PBOOL");
438 return;
439 }
440 break;
441 case btLong:
442 switch (ulSize)
443 {
444 case 4:
445 printfi("PLONG");
446 return;
447 case 8:
448 printfi("PLONGLONG");
449 return;
450 }
451 break;
452 case btULong:
453 switch (ulSize)
454 {
455 case 4:
456 printfi("PULONG");
457 return;
458 case 8:
459 printfi("PULONGLONG");
460 return;
461 }
462 break;
463 case btCurrency:
464 case btDate:
465 case btVariant:
466 case btComplex:
467 case btBit:
468 case btBSTR:
469 case btHresult:
470 break;
471 }
472
473 DumpType(dwRefTypeId, pei, indent, FALSE);
474 printf("*");
475 }
476
477 VOID
478 PrintVariant(VARIANT *v)
479 {
480 // printf("<vt%d>", v->n1.n2.vt);
481 switch (v->n1.n2.vt)
482 {
483 case VT_I1:
484 printf("%d", (INT)v->n1.n2.n3.cVal);
485 break;
486 case VT_UI1:
487 printf("0x%x", (UINT)v->n1.n2.n3.cVal);
488 break;
489 case VT_I2:
490 printf("%d", (UINT)v->n1.n2.n3.iVal);
491 break;
492 case VT_UI2:
493 printf("0x%x", (UINT)v->n1.n2.n3.iVal);
494 break;
495 case VT_INT:
496 case VT_I4:
497 printf("%d", (UINT)v->n1.n2.n3.lVal);
498 break;
499 case VT_UINT:
500 case VT_UI4:
501 printf("0x%x", (UINT)v->n1.n2.n3.lVal);
502 break;
503 }
504 }
505
506 BOOL
507 IsUnnamed(WCHAR *pszName)
508 {
509 if ((StrStrW(pszName, L"__unnamed") != NULL) ||
510 (StrStrW(pszName, L"<unnamed-tag>") != NULL))
511 {
512 return TRUE;
513 }
514 return FALSE;
515 }
516
517 VOID
518 DumpEnum(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers)
519 {
520 DWORD64 dwModuleBase = pei->dwModuleBase;
521 HANDLE hProcess = pei->hProcess;
522 INT i;
523 DWORD dwUDTKind;
524 WCHAR *pszName, *pszNameX;
525 struct
526 {
527 TI_FINDCHILDREN_PARAMS tfp;
528 ULONG TypeIds[200];
529 } tfpex;
530 VARIANT v;
531
532 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_SYMNAME, &pszNameX);
533 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_UDTKIND, &dwUDTKind);
534 pszName = pszNameX;
535 if (IsUnnamed(pszName))
536 {
537 if (bMembers)
538 {
539 LocalFree(pszNameX);
540 return;
541 }
542 bMembers = TRUE;
543 pszName = L"";
544 }
545 printfi("enum %ls", pszName);
546 LocalFree(pszNameX);
547
548 if (bMembers)
549 {
550 printf(" /* %03x */", 0);
551 printfi("\n{\n");
552
553 /* Get the children */
554 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &tfpex.tfp.Count);
555
556 tfpex.tfp.Start = 0;
557 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_FINDCHILDREN, &tfpex.tfp);
558
559 for (i = 0; i < tfpex.tfp.Count; i++)
560 {
561 pszName = L"";
562
563 SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_SYMNAME, &pszName);
564 SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_VALUE, &v);
565
566 indent++;
567 printfi("%ls = ", pszName);
568 PrintVariant(&v);
569 printf(",\n");
570 indent--;
571
572 LocalFree(pszName);
573 }
574 printfi("}");
575 }
576 }
577
578 VOID
579 DumpUDT(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers)
580 {
581 DWORD64 dwModuleBase = pei->dwModuleBase;
582 HANDLE hProcess = pei->hProcess;
583 INT i;
584 DWORD dwUDTKind;
585 WCHAR *pszName, *pszNameX;
586 struct
587 {
588 TI_FINDCHILDREN_PARAMS tfp;
589 ULONG TypeIds[200];
590 } tfpex;
591
592 DWORD dwDataKind;
593 DWORD dwTypeId;
594 DWORD dwCount;
595 WCHAR *pszTypeName;
596
597 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_SYMNAME, &pszNameX);
598 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_UDTKIND, &dwUDTKind);
599
600 pszName = pszNameX;
601 if (IsUnnamed(pszName))
602 {
603 if (bMembers)
604 {
605 LocalFree(pszNameX);
606 return;
607 }
608 bMembers = TRUE;
609 pszName = L"";
610 }
611 if (dwUDTKind == UDTKind_Struct)
612 {
613 printfi("struct %ls", pszName);
614 }
615 else if (dwUDTKind == UDTKind_Union)
616 {
617 printfi("union %ls", pszName);
618 }
619 else
620 {
621 printfi("UTDKind%ld %ls", dwUDTKind, pszName);
622 }
623 LocalFree(pszNameX);
624
625 if (bMembers)
626 {
627 ULONG64 ulLength;
628
629 printf("\n");
630 printfi("{\n");
631
632 /* Get the children */
633 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &tfpex.tfp.Count);
634
635 tfpex.tfp.Start = 0;
636 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_FINDCHILDREN, &tfpex.tfp);
637
638 for (i = 0; i < tfpex.tfp.Count; i++)
639 {
640 DWORD dwChildTag;
641 DWORD dwOffset;
642
643 pszName = L"";
644 pszTypeName = L"";
645
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);
652
653 printf(" /* %03lx */", dwOffset);
654 DumpType(dwTypeId, pei, indent + 1, FALSE);
655 printf(" %ls", pszName);
656 if (dwChildTag == SymTagArrayType)
657 {
658 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeId, TI_GET_COUNT, &dwCount);
659 printf("[%ld]", dwCount);
660 }
661 else
662 {
663 DWORD dwCurrentBitPos;
664 DWORD dwNextBitPos;
665
666 SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i], TI_GET_BITPOSITION, &dwCurrentBitPos);
667 if (i < tfpex.tfp.Count - 1)
668 {
669 SymGetTypeInfo(hProcess, dwModuleBase, tfpex.tfp.ChildId[i+1], TI_GET_BITPOSITION, &dwNextBitPos);
670 }
671 else
672 {
673 dwNextBitPos = 0;
674 }
675
676 if (dwNextBitPos == 0 && dwCurrentBitPos != 0)
677 {
678 dwNextBitPos = ulLength * 8;
679 }
680
681 if (dwNextBitPos != dwCurrentBitPos)
682 {
683 printf(":%ld", dwNextBitPos - dwCurrentBitPos);
684 }
685 }
686 printf(";\n");
687 LocalFree(pszName);
688 }
689 printfi("}");
690 }
691 }
692
693 VOID
694 DumpType(DWORD dwTypeIndex, PENUMINFO pei, INT indent, BOOL bMembers)
695 {
696 HANDLE hProcess = pei->hProcess;
697 DWORD64 dwModuleBase = pei->dwModuleBase;
698 DWORD dwTag = 0;
699
700 SymGetTypeInfo(hProcess, dwModuleBase, dwTypeIndex, TI_GET_SYMTAG, &dwTag);
701
702 switch (dwTag)
703 {
704 case SymTagEnum:
705 DumpEnum(dwTypeIndex, pei, indent, bMembers);
706 break;
707
708 case SymTagUDT:
709 DumpUDT(dwTypeIndex, pei, indent, bMembers);
710 break;
711
712 case SymTagPointerType:
713 DumpPointer(dwTypeIndex, pei, indent);
714 break;
715
716 case SymTagBaseType:
717 DumpBaseType(dwTypeIndex, pei, indent);
718 break;
719
720 case SymTagArrayType:
721 DumpArray(dwTypeIndex, pei, indent);
722 break;
723
724 case SymTagFunctionType:
725 printfi("function");
726 break;
727
728 default:
729 printfi("typeTag%ld", dwTag);
730 break;
731 }
732
733 }
734
735
736 VOID
737 DumpCV(DWORD dwTypeIndex, PENUMINFO pei)
738 {
739 DWORD cv = 0x20;
740
741 SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, dwTypeIndex, TI_GET_CALLING_CONVENTION, &cv);
742 switch (cv)
743 {
744 case CV_CALL_NEAR_C:
745 printf("CDECL");
746 return;
747 case CV_CALL_FAR_C:
748 printf("FAR CDECL");
749 return;
750 case CV_CALL_NEAR_PASCAL:
751 printf("PASCAL");
752 return;
753 case CV_CALL_FAR_PASCAL:
754 printf("FAR PASCAL");
755 return;
756 case CV_CALL_NEAR_FAST:
757 printf("FASTCALL");
758 return;
759 case CV_CALL_FAR_FAST:
760 printf("FAR FASTCALL");
761 return;
762 case CV_CALL_SKIPPED:
763 printf("SKIPPED");
764 return;
765 case CV_CALL_NEAR_STD:
766 printf("STDCALL");
767 return;
768 case CV_CALL_FAR_STD:
769 printf("FAR STDCALL");
770 return;
771 case CV_CALL_NEAR_SYS:
772 case CV_CALL_FAR_SYS:
773 case CV_CALL_THISCALL:
774 printf("THISCALL");
775 return;
776 case CV_CALL_MIPSCALL:
777 printf("MIPSCALL");
778 return;
779 case CV_CALL_GENERIC:
780 case CV_CALL_ALPHACALL:
781 case CV_CALL_PPCCALL:
782 case CV_CALL_SHCALL:
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:
788 default:
789 printf("UNKNOWNCV");
790 }
791
792 }
793
794 BOOL CALLBACK
795 EnumParamsProc(
796 PSYMBOL_INFO pSymInfo,
797 ULONG SymbolSize,
798 PVOID UserContext)
799 {
800 printf("x, ");
801 (*(INT*)UserContext)++;
802 return TRUE;
803 }
804
805 VOID
806 DumpParams(PSYMBOL_INFO pSymInfo, PENUMINFO pei)
807 {
808 IMAGEHLP_STACK_FRAME sf;
809 BOOL bRet;
810 INT NumLocals = 0; // the number of local variables found
811
812 sf.InstructionOffset = pSymInfo->Address;
813
814 printf("(");
815 bRet = SymSetContext(pei->hProcess, &sf, 0);
816
817 if (!bRet)
818 {
819 printf("\nError: SymSetContext() failed. Error code: %lu \n", GetLastError());
820 return;
821 }
822 printf("Address == 0x%x, ReturnOffset = 0x%x", (UINT)pSymInfo->Address, (UINT)sf.ReturnOffset);
823
824 // Enumerate local variables
825
826 bRet = SymEnumSymbols(pei->hProcess, 0, 0, EnumParamsProc, &NumLocals);
827
828 if (!bRet)
829 {
830 // printf("Error: SymEnumSymbols() failed. Error code: %lu \n", GetLastError());
831 printf("?)");
832 return;
833 }
834
835 if (NumLocals == 0)
836 {
837 // printf("The function does not have parameters and local variables.\n");
838 printf("void)");
839 }
840
841 printf(")");
842 }
843
844 VOID
845 DumpFunction(PSYMBOL_INFO pSymInfo, PENUMINFO pei)
846 {
847 DWORD dwTypeId;
848
849 //printf("Name=%s, Size=%ld, TypeId=0x%ld\n", pSymInfo->Name, pSymInfo->Size, pSymInfo->TypeIndex);
850
851 SymGetTypeInfo(pei->hProcess, pei->dwModuleBase, pSymInfo->TypeIndex, TI_GET_TYPEID, &dwTypeId);
852
853 // DumpCV(pSymInfo->TypeIndex, pei);
854 // printf("\n");
855 // DumpType(pSymInfo->TypeIndex, pei, 0, FALSE);
856 printf("%s", pSymInfo->Name);
857 DumpParams(pSymInfo, pei);
858 }
859
860 BOOL CALLBACK
861 EnumSymbolsProc(
862 PSYMBOL_INFO pSymInfo,
863 ULONG SymbolSize,
864 PVOID UserContext)
865 {
866 PENUMINFO pei = (PENUMINFO)UserContext;
867
868 if ((pei->pszSymbolName == NULL) ||
869 (strstr(pSymInfo->Name, pei->pszSymbolName) != 0))
870 {
871 if (pei->bType)
872 {
873 DumpType(pSymInfo->TypeIndex, pei, 0, TRUE);
874 printf("\n\n");
875 }
876 else
877 {
878 printf("Symbol: %s, TypeIndex=%ld, Flags=%lx, Value=0x%llx\n",
879 pSymInfo->Name, pSymInfo->TypeIndex, pSymInfo->Flags, pSymInfo->Value);
880 //if (pSymInfo->Flags & SYMFLAG_FUNCTION)
881 {
882 // DumpFunction(pSymInfo, pei);
883 // printf("\n\n");
884 }
885 }
886 }
887 return TRUE;
888 }
889
890 int main(int argc, char* argv[])
891 {
892 HANDLE hProcess;
893 CHAR szFullFileName[MAX_PATH+1];
894 DWORD64 dwModuleBase;
895 BOOL bRet;
896 LPSTR pszSymbolPath, pszSymbolName;
897 INT i;
898 ENUMINFO enuminfo;
899
900 printf("PE symbol dumper\n");
901 printf("Copyright (c) Timo Kreuzer 2008\n\n");
902
903 if (argc < 2)
904 {
905 PrintUsage();
906 return 0;
907 }
908
909 /* Get the full path name of the PE file from first argument */
910 GetFullPathName(argv[1], MAX_PATH, szFullFileName, NULL);
911
912 /* Default Symbol Name (all) */
913 pszSymbolName = NULL;
914
915 /* Default to ms symbol server */
916 pszSymbolPath = "srv**symbols*http://msdl.microsoft.com/download/symbols";
917
918 /* Check other command line arguments */
919 for (i = 2; i < argc; i++)
920 {
921 if (*argv[i] == '-')
922 {
923 if (strncmp(argv[i], "-sp=", 4) == 0)
924 {
925 pszSymbolPath = argv[i] + 4;
926 }
927 else if (strcmp(argv[i], "-p") == 0)
928 {
929 g_bShowPos = 1;
930 }
931 else
932 {
933 printf("Invalid argument: %s\n", argv[i]);
934 PrintUsage();
935 return 0;
936 }
937 }
938 else
939 {
940 pszSymbolName = argv[i];
941 }
942 }
943
944 hProcess = GetCurrentProcess();
945
946 printf("Trying to get symbols from: %s\n", pszSymbolPath);
947
948 if (!InitDbgHelp(hProcess, pszSymbolPath))
949 {
950 printf("SymInitialize() failed\n");
951 goto cleanup;
952 }
953
954 printf("Loading symbols for %s, please wait...\n", szFullFileName);
955 dwModuleBase = SymLoadModule64(hProcess, 0, szFullFileName, 0, 0, 0);
956 if (dwModuleBase == 0)
957 {
958 printf("SymLoadModule64() failed: %ld\n", GetLastError());
959 goto cleanup;
960 }
961
962 printf("\nSymbols:\n");
963 enuminfo.hProcess = hProcess;
964 enuminfo.pszSymbolName = pszSymbolName;
965 enuminfo.bType = FALSE;
966 SetLastError(ERROR_SUCCESS);
967 bRet = SymEnumSymbols(hProcess, dwModuleBase, NULL, EnumSymbolsProc, &enuminfo);
968 if (!bRet)
969 {
970 printf("SymEnumSymbols failed: %ld\n", GetLastError());
971 }
972
973 printf("\nTypes:\n");
974 enuminfo.bType = TRUE;
975 enuminfo.dwModuleBase = dwModuleBase;
976 SetLastError(ERROR_SUCCESS);
977 bRet = SymEnumTypes(hProcess, dwModuleBase, EnumSymbolsProc, &enuminfo);
978 if (!bRet)
979 {
980 printf("SymEnumTypes failed: %ld\n", GetLastError());
981 }
982
983 cleanup:
984
985 return 0;
986 }