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