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 }
993