mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[CREATESPEC]
Small utility to auto-create spec files. Uses MS symbol server to evaluate data not available in the export table. Features: - Parse export table for export names and forwarders - Find function name for nameless exports - Recognize calling convention / data exports - Analyze function parameters svn path=/trunk/; revision=70559
This commit is contained in:
parent
6ed0a4c6b2
commit
2a5c5c0c76
2 changed files with 601 additions and 0 deletions
6
rosapps/applications/devutils/createspec/CMakeLists.txt
Normal file
6
rosapps/applications/devutils/createspec/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
add_executable(createspec createspec.c)
|
||||||
|
set_module_type(createspec win32cui)
|
||||||
|
target_link_libraries(createspec wine)
|
||||||
|
add_importlibs(createspec dbghelp msvcrt kernel32)
|
||||||
|
add_cd_file(TARGET createspec DESTINATION reactos/system32 FOR all)
|
595
rosapps/applications/devutils/createspec/createspec.c
Normal file
595
rosapps/applications/devutils/createspec/createspec.c
Normal file
|
@ -0,0 +1,595 @@
|
||||||
|
/*
|
||||||
|
- Info:
|
||||||
|
- http://stackoverflow.com/questions/32251638/dbghelp-get-full-symbol-signature-function-name-parameters-types
|
||||||
|
- http://www.debuginfo.com/articles/dbghelptypeinfo.html
|
||||||
|
- TODO:
|
||||||
|
- Dump usage
|
||||||
|
- Test for dbghelp + symsrv and warn if not working
|
||||||
|
- Resolve forwarders
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable:4091)
|
||||||
|
#endif
|
||||||
|
#define _NO_CVCONST_H
|
||||||
|
#include <dbghelp.h>
|
||||||
|
|
||||||
|
// doesn't seem to be defined anywhere
|
||||||
|
enum BasicType {
|
||||||
|
btNoType = 0,
|
||||||
|
btVoid = 1,
|
||||||
|
btChar = 2,
|
||||||
|
btWChar = 3,
|
||||||
|
btInt = 6,
|
||||||
|
btUInt = 7,
|
||||||
|
btFloat = 8,
|
||||||
|
btBCD = 9,
|
||||||
|
btBool = 10,
|
||||||
|
btLong = 13,
|
||||||
|
btULong = 14,
|
||||||
|
btCurrency = 25,
|
||||||
|
btDate = 26,
|
||||||
|
btVariant = 27,
|
||||||
|
btComplex = 28,
|
||||||
|
btBit = 29,
|
||||||
|
btBSTR = 30,
|
||||||
|
btHresult = 31
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum CV_call_e {
|
||||||
|
CV_CALL_NEAR_C = 0x00,
|
||||||
|
CV_CALL_NEAR_FAST = 0x04,
|
||||||
|
CV_CALL_NEAR_STD = 0x07,
|
||||||
|
CV_CALL_NEAR_SYS = 0x09,
|
||||||
|
CV_CALL_THISCALL = 0x0b,
|
||||||
|
CV_CALL_CLRCALL = 0x16
|
||||||
|
} CV_call_e;
|
||||||
|
|
||||||
|
#define MAX_SYMBOL_NAME 1024
|
||||||
|
typedef struct _SYMINFO_EX
|
||||||
|
{
|
||||||
|
SYMBOL_INFO si;
|
||||||
|
CHAR achName[MAX_SYMBOL_NAME];
|
||||||
|
} SYMINFO_EX;
|
||||||
|
|
||||||
|
typedef enum _PARAM_TYPES
|
||||||
|
{
|
||||||
|
TYPE_NONE,
|
||||||
|
TYPE_LONG,
|
||||||
|
TYPE_DOUBLE,
|
||||||
|
TYPE_PTR,
|
||||||
|
TYPE_STR,
|
||||||
|
TYPE_WSTR
|
||||||
|
} PARAM_TYPES, *PPARAM_TYPES;
|
||||||
|
|
||||||
|
const char*
|
||||||
|
gapszTypeStrings[] =
|
||||||
|
{
|
||||||
|
"???",
|
||||||
|
"long",
|
||||||
|
"double",
|
||||||
|
"ptr",
|
||||||
|
"str",
|
||||||
|
"wstr"
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_PARAMETERS 64
|
||||||
|
typedef struct _EXPORT
|
||||||
|
{
|
||||||
|
PSTR pszName;
|
||||||
|
PSTR pszSymbol;
|
||||||
|
PSTR pszForwarder;
|
||||||
|
ULONG ulRva;
|
||||||
|
DWORD dwCallingConvention;
|
||||||
|
ULONG fForwarder : 1;
|
||||||
|
ULONG fNoName : 1;
|
||||||
|
ULONG fData : 1;
|
||||||
|
ULONG cParameters;
|
||||||
|
PARAM_TYPES aeParameters[MAX_PARAMETERS];
|
||||||
|
} EXPORT, *PEXPORT;
|
||||||
|
|
||||||
|
typedef struct _EXPORT_DATA
|
||||||
|
{
|
||||||
|
ULONG cNumberOfExports;
|
||||||
|
EXPORT aExports[1];
|
||||||
|
} EXPORT_DATA, *PEXPORT_DATA;
|
||||||
|
|
||||||
|
HANDLE ghProcess;
|
||||||
|
CHAR gszModuleFileName[MAX_PATH+1];
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
OpenFileFromName(
|
||||||
|
_In_ PCSTR pszDllName,
|
||||||
|
_Out_ PHANDLE phFile)
|
||||||
|
{
|
||||||
|
HANDLE hFile;
|
||||||
|
|
||||||
|
/* Try current directory */
|
||||||
|
GetCurrentDirectoryA(MAX_PATH, gszModuleFileName);
|
||||||
|
strcat_s(gszModuleFileName, sizeof(gszModuleFileName), "\\");
|
||||||
|
strcat_s(gszModuleFileName, sizeof(gszModuleFileName), pszDllName);
|
||||||
|
hFile = CreateFileA(gszModuleFileName,
|
||||||
|
FILE_READ_DATA,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
*phFile = hFile;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try system32 directory */
|
||||||
|
strcat_s(gszModuleFileName, sizeof(gszModuleFileName), "%systemroot%\\system32\\");
|
||||||
|
strcat_s(gszModuleFileName, sizeof(gszModuleFileName), pszDllName);
|
||||||
|
hFile = CreateFileA(gszModuleFileName,
|
||||||
|
FILE_READ_DATA,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
*phFile = hFile;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
GetExportsFromFile(
|
||||||
|
_In_ HANDLE hFile,
|
||||||
|
_Out_ PEXPORT_DATA* ppExportData)
|
||||||
|
{
|
||||||
|
HANDLE hMap;
|
||||||
|
PBYTE pjImageBase;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
||||||
|
ULONG i, cjExportSize, cFunctions, cjTableSize;
|
||||||
|
PEXPORT_DATA pExportData;
|
||||||
|
PULONG pulAddressTable, pulNameTable;
|
||||||
|
PUSHORT pusOrdinalTable;
|
||||||
|
|
||||||
|
/* Create an image file mapping */
|
||||||
|
hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
|
||||||
|
if (!hMap)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "CreateFileMapping() failed: %ld\n", GetLastError());
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the file */
|
||||||
|
pjImageBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
||||||
|
if(pjImageBase == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "MapViewOfFile() failed: %ld\n", GetLastError());
|
||||||
|
CloseHandle(hMap);
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the export directory */
|
||||||
|
pExportDir = ImageDirectoryEntryToData(pjImageBase,
|
||||||
|
TRUE,
|
||||||
|
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||||
|
&cjExportSize);
|
||||||
|
|
||||||
|
cFunctions = pExportDir->NumberOfFunctions;
|
||||||
|
cjTableSize = FIELD_OFFSET(EXPORT_DATA, aExports[cFunctions]);
|
||||||
|
|
||||||
|
pExportData = malloc(cjTableSize);
|
||||||
|
if (pExportData == NULL)
|
||||||
|
{
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlZeroMemory(pExportData, cjTableSize);
|
||||||
|
|
||||||
|
pulAddressTable = (PULONG)(pjImageBase + pExportDir->AddressOfFunctions);
|
||||||
|
|
||||||
|
pExportData->cNumberOfExports = cFunctions;
|
||||||
|
|
||||||
|
/* Loop through the function table */
|
||||||
|
for (i = 0; i < cFunctions; i++)
|
||||||
|
{
|
||||||
|
PVOID pvFunction = (pjImageBase + pulAddressTable[i]);
|
||||||
|
|
||||||
|
if ((ULONG_PTR)((PUCHAR)pvFunction - (PUCHAR)pExportDir) < cjExportSize)
|
||||||
|
{
|
||||||
|
pExportData->aExports[i].pszForwarder = _strdup(pvFunction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pExportData->aExports[i].ulRva = pulAddressTable[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pulNameTable = (PULONG)(pjImageBase + pExportDir->AddressOfNames);
|
||||||
|
pusOrdinalTable = (PUSHORT)(pjImageBase + pExportDir->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
/* Loop through the name table */
|
||||||
|
for (i = 0; i < pExportDir->NumberOfNames; i++)
|
||||||
|
{
|
||||||
|
ULONG iIndex = pusOrdinalTable[i];
|
||||||
|
PSTR pszName = (PSTR)(pjImageBase + pulNameTable[i]);
|
||||||
|
|
||||||
|
pExportData->aExports[iIndex].pszName = _strdup(pszName);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppExportData = pExportData;
|
||||||
|
UnmapViewOfFile(pjImageBase);
|
||||||
|
CloseHandle(hMap);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CALLBACK
|
||||||
|
EnumParametersCallback(
|
||||||
|
_In_ PSYMBOL_INFO pSymInfo,
|
||||||
|
_In_ ULONG SymbolSize,
|
||||||
|
_In_opt_ PVOID UserContext)
|
||||||
|
{
|
||||||
|
PEXPORT pExport = (PEXPORT)UserContext;
|
||||||
|
enum SymTagEnum eSymTag;
|
||||||
|
enum BasicType eBaseType;
|
||||||
|
DWORD dwTypeIndex;
|
||||||
|
ULONG64 ullLength;
|
||||||
|
|
||||||
|
/* If it's not a parameter, skip it */
|
||||||
|
if (!(pSymInfo->Flags & SYMFLAG_PARAMETER))
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count this parameter */
|
||||||
|
pExport->cParameters++;
|
||||||
|
|
||||||
|
/* Get the type for the parameter */
|
||||||
|
if (SymGetTypeInfo(ghProcess,
|
||||||
|
pSymInfo->ModBase,
|
||||||
|
pSymInfo->TypeIndex,
|
||||||
|
TI_GET_SYMTAG,
|
||||||
|
&eSymTag))
|
||||||
|
{
|
||||||
|
switch (eSymTag)
|
||||||
|
{
|
||||||
|
case SymTagUDT:
|
||||||
|
case SymTagBaseType:
|
||||||
|
|
||||||
|
/* Try to get the size */
|
||||||
|
if (SymGetTypeInfo(ghProcess,
|
||||||
|
pSymInfo->ModBase,
|
||||||
|
pSymInfo->TypeIndex,
|
||||||
|
TI_GET_LENGTH,
|
||||||
|
&ullLength))
|
||||||
|
{
|
||||||
|
if (ullLength > 8)
|
||||||
|
{
|
||||||
|
/* That is probably not possible */
|
||||||
|
__debugbreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ullLength > 4)
|
||||||
|
{
|
||||||
|
/* 'double' type */
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_DOUBLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 'long' type */
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_LONG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SymTagEnum:
|
||||||
|
/* 'long' type */
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_LONG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SymTagPointerType:
|
||||||
|
/* 'ptr' type */
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_PTR;
|
||||||
|
|
||||||
|
/* Try to get the underlying type */
|
||||||
|
if (SymGetTypeInfo(ghProcess,
|
||||||
|
pSymInfo->ModBase,
|
||||||
|
pSymInfo->TypeIndex,
|
||||||
|
TI_GET_TYPEID,
|
||||||
|
&dwTypeIndex))
|
||||||
|
{
|
||||||
|
/* Try to get the base type */
|
||||||
|
if (SymGetTypeInfo(ghProcess,
|
||||||
|
pSymInfo->ModBase,
|
||||||
|
dwTypeIndex,
|
||||||
|
TI_GET_BASETYPE,
|
||||||
|
&eBaseType))
|
||||||
|
{
|
||||||
|
if (eBaseType == btChar)
|
||||||
|
{
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_STR;
|
||||||
|
}
|
||||||
|
else if (eBaseType == btWChar)
|
||||||
|
{
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_WSTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("Unhandled eSymTag: %u\n", eSymTag);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Could not get type info. Fallig back to ptr\n");
|
||||||
|
pExport->aeParameters[pExport->cParameters - 1] = TYPE_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
ParseExportSymbols(
|
||||||
|
_In_ HANDLE hFile,
|
||||||
|
_Inout_ PEXPORT_DATA pExportData)
|
||||||
|
{
|
||||||
|
DWORD Options;
|
||||||
|
DWORD64 dwModuleBase;
|
||||||
|
ULONG i;
|
||||||
|
IMAGEHLP_STACK_FRAME StackFrame;
|
||||||
|
SYMINFO_EX sym;
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize dbghelp */
|
||||||
|
if (!SymInitialize(ghProcess, 0, FALSE))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
Options = SymGetOptions();
|
||||||
|
Options |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_DEBUG;// | SYMOPT_NO_PROMPTS;
|
||||||
|
Options &= ~SYMOPT_DEFERRED_LOADS;
|
||||||
|
SymSetOptions(Options);
|
||||||
|
SymSetSearchPath(ghProcess, "srv**symbols*http://msdl.microsoft.com/download/symbols");
|
||||||
|
|
||||||
|
printf("Loading symbols, please wait...\n");
|
||||||
|
dwModuleBase = SymLoadModule64(ghProcess, 0, gszModuleFileName, 0, 0, 0);
|
||||||
|
if (dwModuleBase == 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SymLoadModule64() failed: %ld\n", GetLastError());
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < pExportData->cNumberOfExports; i++)
|
||||||
|
{
|
||||||
|
PEXPORT pExport = &pExportData->aExports[i];
|
||||||
|
ULONG64 ullFunction = dwModuleBase + pExportData->aExports[i].ulRva;
|
||||||
|
ULONG64 ullDisplacement;
|
||||||
|
|
||||||
|
/* Skip forwarder */
|
||||||
|
if (pExport->pszForwarder != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RtlZeroMemory(&sym, sizeof(sym));
|
||||||
|
sym.si.SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
|
sym.si.MaxNameLen = MAX_SYMBOL_NAME;
|
||||||
|
|
||||||
|
/* Try to find the symbol */
|
||||||
|
if (!SymFromAddr(ghProcess, ullFunction, &ullDisplacement, &sym.si))
|
||||||
|
{
|
||||||
|
printf("Error: SymFromAddr() failed. Error code: %u \n", GetLastError());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Symbol found. Check if it is a function */
|
||||||
|
if (sym.si.Tag == SymTagFunction)
|
||||||
|
{
|
||||||
|
/* If we don't have a name yet, get one */
|
||||||
|
pExport->pszSymbol = _strdup(sym.si.Name);
|
||||||
|
|
||||||
|
/* Get the calling convention */
|
||||||
|
if (!SymGetTypeInfo(ghProcess,
|
||||||
|
dwModuleBase,
|
||||||
|
sym.si.TypeIndex,
|
||||||
|
TI_GET_CALLING_CONVENTION,
|
||||||
|
&pExport->dwCallingConvention))
|
||||||
|
{
|
||||||
|
/* Fall back to __stdcall */
|
||||||
|
pExport->dwCallingConvention = 0x07; // CV_CALL_NEAR_STD
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the context to the function address */
|
||||||
|
RtlZeroMemory(&StackFrame, sizeof(StackFrame));
|
||||||
|
StackFrame.InstructionOffset = ullFunction;
|
||||||
|
if (!SymSetContext(ghProcess, &StackFrame, NULL))
|
||||||
|
{
|
||||||
|
DWORD dwLastError = GetLastError();
|
||||||
|
__debugbreak();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enumerate all symbols for this function */
|
||||||
|
if (!SymEnumSymbols(ghProcess,
|
||||||
|
0, // use SymSetContext
|
||||||
|
NULL,
|
||||||
|
EnumParametersCallback,
|
||||||
|
pExport))
|
||||||
|
{
|
||||||
|
DWORD dwLastError = GetLastError();
|
||||||
|
__debugbreak();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sym.si.Tag == SymTagData)
|
||||||
|
{
|
||||||
|
pExport->fData = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHAR*
|
||||||
|
GetCallingConvention(
|
||||||
|
_In_ PEXPORT pExport)
|
||||||
|
{
|
||||||
|
if (pExport->fData)
|
||||||
|
{
|
||||||
|
return "extern";
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _M_AMD64
|
||||||
|
switch (pExport->dwCallingConvention)
|
||||||
|
{
|
||||||
|
case CV_CALL_NEAR_C:
|
||||||
|
return "cdecl";
|
||||||
|
case CV_CALL_NEAR_FAST:
|
||||||
|
return "fastcall";
|
||||||
|
case CV_CALL_NEAR_STD:
|
||||||
|
return "stdcall";
|
||||||
|
case CV_CALL_NEAR_SYS:
|
||||||
|
return "syscall";
|
||||||
|
case CV_CALL_THISCALL:
|
||||||
|
return "thiscall";
|
||||||
|
case CV_CALL_CLRCALL:
|
||||||
|
return "clrcall";
|
||||||
|
default:
|
||||||
|
__debugbreak();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return "stdcall";
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
CreateSpecFile(
|
||||||
|
_In_ PCSTR pszSpecFile,
|
||||||
|
_In_ PEXPORT_DATA pExportData)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
ULONG i, p;
|
||||||
|
PEXPORT pExport;
|
||||||
|
|
||||||
|
/* Create the spec file */
|
||||||
|
if (fopen_s(&file, pszSpecFile, "w") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to open spec file: '%s'\n", pszSpecFile);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop all exports */
|
||||||
|
for (i = 0; i < pExportData->cNumberOfExports; i++)
|
||||||
|
{
|
||||||
|
pExport = &pExportData->aExports[i];
|
||||||
|
|
||||||
|
fprintf(file, "%u %s ", i + 1, GetCallingConvention(pExport));
|
||||||
|
//if (pExport->fNoName)
|
||||||
|
if (pExport->pszName == NULL)
|
||||||
|
{
|
||||||
|
fprintf(file, "-noname ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pExport->pszName != NULL)
|
||||||
|
{
|
||||||
|
fprintf(file, "%s", pExport->pszName);
|
||||||
|
}
|
||||||
|
else if (pExport->pszSymbol != NULL)
|
||||||
|
{
|
||||||
|
fprintf(file, "%s", pExport->pszSymbol);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(file, "NamelessExport_%u", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pExport->fData)
|
||||||
|
{
|
||||||
|
fprintf(file, "(");
|
||||||
|
for (p = 0; p < pExport->cParameters; p++)
|
||||||
|
{
|
||||||
|
fprintf(file, "%s", gapszTypeStrings[pExport->aeParameters[p]]);
|
||||||
|
if ((p + 1) < pExport->cParameters)
|
||||||
|
{
|
||||||
|
fprintf(file, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(file, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pExport->pszForwarder != NULL)
|
||||||
|
{
|
||||||
|
fprintf(file, " %s", pExport->pszForwarder);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(file, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
CHAR szSpecFile[MAX_PATH];
|
||||||
|
PSTR pszSpecFile;
|
||||||
|
HANDLE hFile;
|
||||||
|
PEXPORT_DATA pExportData;
|
||||||
|
|
||||||
|
// check params
|
||||||
|
// help
|
||||||
|
|
||||||
|
ghProcess = GetCurrentProcess();
|
||||||
|
|
||||||
|
/* Open the file */
|
||||||
|
hr = OpenFileFromName(argv[1], &hFile);
|
||||||
|
if (!SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to open file: %lx\n", hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the exports */
|
||||||
|
hr = GetExportsFromFile(hFile, &pExportData);
|
||||||
|
if (!SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to get exports: %lx\n", hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get additional info from symbols */
|
||||||
|
hr = ParseExportSymbols(hFile, pExportData);
|
||||||
|
if (!SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to get symbol information: %lx\n", hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 2)
|
||||||
|
{
|
||||||
|
pszSpecFile = argv[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PSTR pszStart = strrchr(argv[1], '\\');
|
||||||
|
if (pszStart == 0)
|
||||||
|
pszStart = argv[1];
|
||||||
|
|
||||||
|
strcpy_s(szSpecFile, sizeof(szSpecFile), pszStart);
|
||||||
|
strcat_s(szSpecFile, sizeof(szSpecFile), ".spec");
|
||||||
|
pszSpecFile = szSpecFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = CreateSpecFile(pszSpecFile, pExportData);
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
|
||||||
|
printf("Spec file '%s' was successfully written.\n", szSpecFile);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
Loading…
Reference in a new issue