3 - http://stackoverflow.com/questions/32251638/dbghelp-get-full-symbol-signature-function-name-parameters-types
4 - http://www.debuginfo.com/articles/dbghelptypeinfo.html
7 - Test for dbghelp + symsrv and warn if not working
16 #pragma warning(disable:4091)
21 // doesn't seem to be defined anywhere
43 typedef enum CV_call_e
{
44 CV_CALL_NEAR_C
= 0x00,
45 CV_CALL_NEAR_FAST
= 0x04,
46 CV_CALL_NEAR_STD
= 0x07,
47 CV_CALL_NEAR_SYS
= 0x09,
48 CV_CALL_THISCALL
= 0x0b,
49 CV_CALL_CLRCALL
= 0x16
52 #define MAX_SYMBOL_NAME 1024
53 typedef struct _SYMINFO_EX
56 CHAR achName
[MAX_SYMBOL_NAME
];
59 typedef enum _PARAM_TYPES
67 } PARAM_TYPES
, *PPARAM_TYPES
;
80 #define MAX_PARAMETERS 64
81 typedef struct _EXPORT
87 DWORD dwCallingConvention
;
92 PARAM_TYPES aeParameters
[MAX_PARAMETERS
];
95 typedef struct _EXPORT_DATA
97 ULONG cNumberOfExports
;
99 } EXPORT_DATA
, *PEXPORT_DATA
;
102 CHAR gszModuleFileName
[MAX_PATH
+1];
106 _In_ PCSTR pszDllName
,
107 _Out_ PHANDLE phFile
)
111 /* Try current directory */
112 GetCurrentDirectoryA(MAX_PATH
, gszModuleFileName
);
113 strcat_s(gszModuleFileName
, sizeof(gszModuleFileName
), "\\");
114 strcat_s(gszModuleFileName
, sizeof(gszModuleFileName
), pszDllName
);
115 hFile
= CreateFileA(gszModuleFileName
,
120 FILE_ATTRIBUTE_NORMAL
,
122 if (hFile
!= INVALID_HANDLE_VALUE
)
128 /* Try system32 directory */
129 strcat_s(gszModuleFileName
, sizeof(gszModuleFileName
), "%systemroot%\\system32\\");
130 strcat_s(gszModuleFileName
, sizeof(gszModuleFileName
), pszDllName
);
131 hFile
= CreateFileA(gszModuleFileName
,
136 FILE_ATTRIBUTE_NORMAL
,
138 if (hFile
!= INVALID_HANDLE_VALUE
)
144 return HRESULT_FROM_WIN32(GetLastError());
150 _Out_ PEXPORT_DATA
* ppExportData
)
154 PIMAGE_EXPORT_DIRECTORY pExportDir
;
155 ULONG i
, cjExportSize
, cFunctions
, cjTableSize
;
156 PEXPORT_DATA pExportData
;
157 PULONG pulAddressTable
, pulNameTable
;
158 PUSHORT pusOrdinalTable
;
160 /* Create an image file mapping */
161 hMap
= CreateFileMappingA(hFile
, NULL
, PAGE_READONLY
| SEC_IMAGE
, 0, 0, NULL
);
164 fprintf(stderr
, "CreateFileMapping() failed: %ld\n", GetLastError());
165 return HRESULT_FROM_WIN32(GetLastError());
169 pjImageBase
= MapViewOfFile(hMap
, FILE_MAP_READ
, 0, 0, 0);
170 if(pjImageBase
== NULL
)
172 fprintf(stderr
, "MapViewOfFile() failed: %ld\n", GetLastError());
174 return HRESULT_FROM_WIN32(GetLastError());
177 /* Get the export directory */
178 pExportDir
= ImageDirectoryEntryToData(pjImageBase
,
180 IMAGE_DIRECTORY_ENTRY_EXPORT
,
183 cFunctions
= pExportDir
->NumberOfFunctions
;
184 cjTableSize
= FIELD_OFFSET(EXPORT_DATA
, aExports
[cFunctions
]);
186 pExportData
= malloc(cjTableSize
);
187 if (pExportData
== NULL
)
189 return E_OUTOFMEMORY
;
192 RtlZeroMemory(pExportData
, cjTableSize
);
194 pulAddressTable
= (PULONG
)(pjImageBase
+ pExportDir
->AddressOfFunctions
);
196 pExportData
->cNumberOfExports
= cFunctions
;
198 /* Loop through the function table */
199 for (i
= 0; i
< cFunctions
; i
++)
201 PVOID pvFunction
= (pjImageBase
+ pulAddressTable
[i
]);
203 if ((ULONG_PTR
)((PUCHAR
)pvFunction
- (PUCHAR
)pExportDir
) < cjExportSize
)
205 pExportData
->aExports
[i
].pszForwarder
= _strdup(pvFunction
);
209 pExportData
->aExports
[i
].ulRva
= pulAddressTable
[i
];
213 pulNameTable
= (PULONG
)(pjImageBase
+ pExportDir
->AddressOfNames
);
214 pusOrdinalTable
= (PUSHORT
)(pjImageBase
+ pExportDir
->AddressOfNameOrdinals
);
216 /* Loop through the name table */
217 for (i
= 0; i
< pExportDir
->NumberOfNames
; i
++)
219 ULONG iIndex
= pusOrdinalTable
[i
];
220 PSTR pszName
= (PSTR
)(pjImageBase
+ pulNameTable
[i
]);
222 pExportData
->aExports
[iIndex
].pszName
= _strdup(pszName
);
225 *ppExportData
= pExportData
;
226 UnmapViewOfFile(pjImageBase
);
233 EnumParametersCallback(
234 _In_ PSYMBOL_INFO pSymInfo
,
235 _In_ ULONG SymbolSize
,
236 _In_opt_ PVOID UserContext
)
238 PEXPORT pExport
= (PEXPORT
)UserContext
;
239 enum SymTagEnum eSymTag
;
240 enum BasicType eBaseType
;
244 /* If it's not a parameter, skip it */
245 if (!(pSymInfo
->Flags
& SYMFLAG_PARAMETER
))
250 /* Count this parameter */
251 pExport
->cParameters
++;
253 /* Get the type for the parameter */
254 if (SymGetTypeInfo(ghProcess
,
265 /* Try to get the size */
266 if (SymGetTypeInfo(ghProcess
,
274 /* That is probably not possible */
281 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_DOUBLE
;
286 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_LONG
;
291 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_LONG
;
294 case SymTagPointerType
:
296 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_PTR
;
298 /* Try to get the underlying type */
299 if (SymGetTypeInfo(ghProcess
,
305 /* Try to get the base type */
306 if (SymGetTypeInfo(ghProcess
,
312 if (eBaseType
== btChar
)
314 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_STR
;
316 else if (eBaseType
== btWChar
)
318 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_WSTR
;
325 printf("Unhandled eSymTag: %u\n", eSymTag
);
331 printf("Could not get type info. Fallig back to ptr\n");
332 pExport
->aeParameters
[pExport
->cParameters
- 1] = TYPE_PTR
;
341 _Inout_ PEXPORT_DATA pExportData
)
344 DWORD64 dwModuleBase
;
346 IMAGEHLP_STACK_FRAME StackFrame
;
350 /* Initialize dbghelp */
351 if (!SymInitialize(ghProcess
, 0, FALSE
))
354 Options
= SymGetOptions();
355 Options
|= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS
| SYMOPT_DEBUG
;// | SYMOPT_NO_PROMPTS;
356 Options
&= ~SYMOPT_DEFERRED_LOADS
;
357 SymSetOptions(Options
);
358 SymSetSearchPath(ghProcess
, "srv**symbols*http://msdl.microsoft.com/download/symbols");
360 printf("Loading symbols, please wait...\n");
361 dwModuleBase
= SymLoadModule64(ghProcess
, 0, gszModuleFileName
, 0, 0, 0);
362 if (dwModuleBase
== 0)
364 fprintf(stderr
, "SymLoadModule64() failed: %ld\n", GetLastError());
369 for (i
= 0; i
< pExportData
->cNumberOfExports
; i
++)
371 PEXPORT pExport
= &pExportData
->aExports
[i
];
372 ULONG64 ullFunction
= dwModuleBase
+ pExportData
->aExports
[i
].ulRva
;
373 ULONG64 ullDisplacement
;
376 if (pExport
->pszForwarder
!= NULL
)
379 RtlZeroMemory(&sym
, sizeof(sym
));
380 sym
.si
.SizeOfStruct
= sizeof(SYMBOL_INFO
);
381 sym
.si
.MaxNameLen
= MAX_SYMBOL_NAME
;
383 /* Try to find the symbol */
384 if (!SymFromAddr(ghProcess
, ullFunction
, &ullDisplacement
, &sym
.si
))
386 printf("Error: SymFromAddr() failed. Error code: %u \n", GetLastError());
390 /* Symbol found. Check if it is a function */
391 if (sym
.si
.Tag
== SymTagFunction
)
393 /* If we don't have a name yet, get one */
394 pExport
->pszSymbol
= _strdup(sym
.si
.Name
);
396 /* Get the calling convention */
397 if (!SymGetTypeInfo(ghProcess
,
400 TI_GET_CALLING_CONVENTION
,
401 &pExport
->dwCallingConvention
))
403 /* Fall back to __stdcall */
404 pExport
->dwCallingConvention
= 0x07; // CV_CALL_NEAR_STD
407 /* Set the context to the function address */
408 RtlZeroMemory(&StackFrame
, sizeof(StackFrame
));
409 StackFrame
.InstructionOffset
= ullFunction
;
410 if (!SymSetContext(ghProcess
, &StackFrame
, NULL
))
412 DWORD dwLastError
= GetLastError();
417 /* Enumerate all symbols for this function */
418 if (!SymEnumSymbols(ghProcess
,
419 0, // use SymSetContext
421 EnumParametersCallback
,
424 DWORD dwLastError
= GetLastError();
429 else if (sym
.si
.Tag
== SymTagData
)
431 pExport
->fData
= TRUE
;
439 GetCallingConvention(
440 _In_ PEXPORT pExport
)
448 switch (pExport
->dwCallingConvention
)
452 case CV_CALL_NEAR_FAST
:
454 case CV_CALL_NEAR_STD
:
456 case CV_CALL_NEAR_SYS
:
458 case CV_CALL_THISCALL
:
460 case CV_CALL_CLRCALL
:
471 _In_ PCSTR pszSpecFile
,
472 _In_ PEXPORT_DATA pExportData
)
478 /* Create the spec file */
479 if (fopen_s(&file
, pszSpecFile
, "w") != 0)
481 fprintf(stderr
, "Failed to open spec file: '%s'\n", pszSpecFile
);
485 /* Loop all exports */
486 for (i
= 0; i
< pExportData
->cNumberOfExports
; i
++)
488 pExport
= &pExportData
->aExports
[i
];
490 fprintf(file
, "%u %s ", i
+ 1, GetCallingConvention(pExport
));
491 //if (pExport->fNoName)
492 if (pExport
->pszName
== NULL
)
494 fprintf(file
, "-noname ");
497 if (pExport
->pszName
!= NULL
)
499 fprintf(file
, "%s", pExport
->pszName
);
501 else if (pExport
->pszSymbol
!= NULL
)
503 fprintf(file
, "%s", pExport
->pszSymbol
);
507 fprintf(file
, "NamelessExport_%u", i
);
513 for (p
= 0; p
< pExport
->cParameters
; p
++)
515 fprintf(file
, "%s", gapszTypeStrings
[pExport
->aeParameters
[p
]]);
516 if ((p
+ 1) < pExport
->cParameters
)
524 if (pExport
->pszForwarder
!= NULL
)
526 fprintf(file
, " %s", pExport
->pszForwarder
);
537 int main(int argc
, char* argv
[])
540 CHAR szSpecFile
[MAX_PATH
];
543 PEXPORT_DATA pExportData
;
548 ghProcess
= GetCurrentProcess();
551 hr
= OpenFileFromName(argv
[1], &hFile
);
554 fprintf(stderr
, "Failed to open file: %lx\n", hr
);
558 /* Get the exports */
559 hr
= GetExportsFromFile(hFile
, &pExportData
);
562 fprintf(stderr
, "Failed to get exports: %lx\n", hr
);
566 /* Get additional info from symbols */
567 hr
= ParseExportSymbols(hFile
, pExportData
);
570 fprintf(stderr
, "Failed to get symbol information: %lx\n", hr
);
575 pszSpecFile
= argv
[2];
579 PSTR pszStart
= strrchr(argv
[1], '\\');
583 strcpy_s(szSpecFile
, sizeof(szSpecFile
), pszStart
);
584 strcat_s(szSpecFile
, sizeof(szSpecFile
), ".spec");
585 pszSpecFile
= szSpecFile
;
588 hr
= CreateSpecFile(pszSpecFile
, pExportData
);
592 printf("Spec file '%s' was successfully written.\n", szSpecFile
);