Author: tkreuzer
Date: Sun Jan 10 18:50:36 2016
New Revision: 70569
URL:
http://svn.reactos.org/svn/reactos?rev=70569&view=rev
Log:
[CREATESPEC]
- Implement retrieving export names from forwarders
- Add error() function to print errors
- Refactor image/symbol loading
- Fix some bugs and add some hacks, so that it compiles in out tree
- Add to build
Modified:
trunk/rosapps/applications/devutils/CMakeLists.txt
trunk/rosapps/applications/devutils/createspec/createspec.c
Modified: trunk/rosapps/applications/devutils/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rosapps/applications/devutils/CMak…
==============================================================================
--- trunk/rosapps/applications/devutils/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rosapps/applications/devutils/CMakeLists.txt [iso-8859-1] Sun Jan 10 18:50:36
2016
@@ -1,4 +1,5 @@
add_subdirectory(bootvid_font_generator)
+add_subdirectory(createspec)
add_subdirectory(gdb2)
add_subdirectory(gdihv)
add_subdirectory(genguid)
Modified: trunk/rosapps/applications/devutils/createspec/createspec.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rosapps/applications/devutils/crea…
==============================================================================
--- trunk/rosapps/applications/devutils/createspec/createspec.c [iso-8859-1] (original)
+++ trunk/rosapps/applications/devutils/createspec/createspec.c [iso-8859-1] Sun Jan 10
18:50:36 2016
@@ -8,18 +8,31 @@
- Resolve forwarders
*/
+#define MINGW_HAS_SECURE_API
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
+#ifdef __REACTOS__
+#include <dbghelp.h>
+#include <cvconst.h>
+
+// dirty hacks!
+#define sprintf_s(dst, size, format, ...) sprintf(dst, format, __VA_ARGS__)
+#define vsprintf_s(dst, size, format, ap) vsprintf(dst, format, ap)
+#define fopen_s(pfile, name, mode) ((*pfile = fopen(name, mode)), (*pfile != 0) ? 0 :
-1)
+#define strcpy_s(dst, size, src) strncpy(dst, src, size)
+#define strcat_s(dst, size, src) strncat(dst, src, size)
+
+#else
#ifdef _MSC_VER
#pragma warning(disable:4091)
#endif
#define _NO_CVCONST_H
#include <dbghelp.h>
-// doesn't seem to be defined anywhere
-enum BasicType {
+// This is from cvconst.h, but win sdk lacks this file
+enum BasicType {
btNoType = 0,
btVoid = 1,
btChar = 2,
@@ -40,7 +53,7 @@
btHresult = 31
};
-typedef enum CV_call_e {
+typedef enum CV_call_e {
CV_CALL_NEAR_C = 0x00,
CV_CALL_NEAR_FAST = 0x04,
CV_CALL_NEAR_STD = 0x07,
@@ -49,12 +62,20 @@
CV_CALL_CLRCALL = 0x16
} CV_call_e;
-#define MAX_SYMBOL_NAME 1024
+#endif // __REACTOS__
+
+#define MAX_SYMBOL_NAME 1024
typedef struct _SYMINFO_EX
{
SYMBOL_INFO si;
CHAR achName[MAX_SYMBOL_NAME];
} SYMINFO_EX;
+
+typedef struct _SYMBOL64_EX
+{
+ IMAGEHLP_SYMBOL64 sym64;
+ CHAR achName[MAX_SYMBOL_NAME];
+} SYMBOL64_EX, *PSYMBOL64_EX;
typedef enum _PARAM_TYPES
{
@@ -99,57 +120,203 @@
} 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());
+
+void
+error(
+ _In_ const char* pszFormat,
+ ...)
+{
+ CHAR szBuffer[512];
+ SIZE_T cchBuffer;
+ DWORD dwLastError;
+ va_list argptr;
+
+ /* Get last error */
+ dwLastError = GetLastError();
+
+ va_start(argptr, pszFormat);
+ cchBuffer = vsprintf_s(szBuffer, sizeof(szBuffer), pszFormat, argptr);
+ va_end(argptr);
+
+ /* Strip trailing newlines */
+ _Analysis_assume_(cchBuffer < sizeof(szBuffer));
+ while ((cchBuffer >= 1) &&
+ ((szBuffer[cchBuffer - 1] == '\r') ||
+ (szBuffer[cchBuffer - 1] == '\n')))
+ {
+ szBuffer[cchBuffer - 1] = '\0';
+ cchBuffer--;
+ }
+
+ /* Check if we have an error */
+ if (dwLastError != ERROR_SUCCESS)
+ {
+ /* Append error code */
+ cchBuffer += sprintf_s(szBuffer + cchBuffer,
+ sizeof(szBuffer) - cchBuffer,
+ " [error %lu: ", dwLastError);
+
+ /* Format the last error code */
+ cchBuffer += FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwLastError,
+ 0,
+ szBuffer + cchBuffer,
+ (DWORD)(sizeof(szBuffer) - cchBuffer),
+ NULL);
+
+ /* Strip trailing newlines */
+ _Analysis_assume_(cchBuffer < sizeof(szBuffer));
+ while ((cchBuffer >= 1) &&
+ ((szBuffer[cchBuffer - 1] == '\r') ||
+ (szBuffer[cchBuffer - 1] == '\n')))
+ {
+ szBuffer[cchBuffer - 1] = '\0';
+ cchBuffer--;
+ }
+
+ fprintf(stderr, "%s]\n", szBuffer);
+ }
+ else
+ {
+ fprintf(stderr, "%s\n", szBuffer);
+ }
+}
+
+BOOL
+InitDbgHelp(
+ VOID)
+{
+ static const char *pszMsSymbolServer =
"srv**symbols*http://msdl.microsoft.com/download/symbols";
+ DWORD Options;
+
+ /* Save current process ;-) */
+ ghProcess = GetCurrentProcess();
+
+ /* Initialize dbghelp */
+ if (!SymInitialize(ghProcess, 0, FALSE))
+ {
+ error("SymInitialize() failed.");
+ return FALSE;
+ }
+
+ /* Set options */
+ Options = SymGetOptions();
+ Options |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_INCLUDE_32BIT_MODULES |
SYMOPT_DEBUG;// | SYMOPT_NO_PROMPTS;
+ Options &= ~SYMOPT_DEFERRED_LOADS;
+ SymSetOptions(Options);
+
+ /* Test if we can reach the MS symbol server */
+ if (!SymSrvIsStore(ghProcess, pszMsSymbolServer))
+ {
+ error("Failed to connect to symbol server.");
+ return FALSE;
+ }
+
+ /* Set MS symbol server as symbol search path */
+ SymSetSearchPath(ghProcess, pszMsSymbolServer);
+
+ return TRUE;
+}
+
+HMODULE
+LoadModuleWithSymbolsFullPath(
+ _In_ PSTR pszFullModuleFileName)
+{
+ HMODULE hmod;
+ DWORD64 dwModuleBase;
+
+ /* Load the DLL */
+ hmod = LoadLibraryExA(pszFullModuleFileName,
+ NULL,
+ LOAD_IGNORE_CODE_AUTHZ_LEVEL |
+ DONT_RESOLVE_DLL_REFERENCES |
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (hmod == NULL)
+ {
+ return NULL;
+ }
+
+ /* Load symbols for this module */
+ dwModuleBase = SymLoadModule64(ghProcess,
+ NULL,
+ pszFullModuleFileName,
+ NULL,
+ (DWORD_PTR)hmod,
+ 0);
+ if (dwModuleBase == 0)
+ {
+ /* ERROR_SUCCESS means, we have symbols already */
+ if (GetLastError() != ERROR_SUCCESS)
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ printf("Successfully loaded symbols for '%s'\n",
+ pszFullModuleFileName);
+ }
+
+ return hmod;
+}
+
+HMODULE
+LoadModuleWithSymbols(
+ _In_ PSTR pszModuleName)
+{
+ CHAR szFullFileName[MAX_PATH];
+ HMODULE hmod;
+
+ /* Check if the file name has a path */
+ if (strchr(pszModuleName, '\\') != NULL)
+ {
+ /* Try as it is */
+ hmod = LoadModuleWithSymbolsFullPath(pszModuleName);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
+ }
+
+ /* Try current directory */
+ GetCurrentDirectoryA(MAX_PATH, szFullFileName);
+ strcat_s(szFullFileName, sizeof(szFullFileName), "\\");
+ strcat_s(szFullFileName, sizeof(szFullFileName), pszModuleName);
+ hmod = LoadModuleWithSymbolsFullPath(szFullFileName);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
+
+ /* Try system32 */
+ strcpy_s(szFullFileName, sizeof(szFullFileName),
"%systemroot%\\system32");
+ strcat_s(szFullFileName, sizeof(szFullFileName), pszModuleName);
+ hmod = LoadModuleWithSymbolsFullPath(szFullFileName);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
+
+#ifdef _WIN64
+ /* Try SysWoW64 */
+ strcpy_s(szFullFileName, sizeof(szFullFileName),
"%systemroot%\\system32");
+ strcat_s(szFullFileName, sizeof(szFullFileName), pszModuleName);
+ hmod = LoadModuleWithSymbolsFullPath(szFullFileName);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
+#endif // _WIN64
+
+ return NULL;
}
HRESULT
GetExportsFromFile(
- _In_ HANDLE hFile,
+ _In_ HMODULE hmod,
_Out_ PEXPORT_DATA* ppExportData)
{
- HANDLE hMap;
PBYTE pjImageBase;
PIMAGE_EXPORT_DIRECTORY pExportDir;
ULONG i, cjExportSize, cFunctions, cjTableSize;
@@ -157,28 +324,18 @@
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,
+ pjImageBase = (PBYTE)hmod;
+
+ /* Get the export directory */
+ pExportDir = ImageDirectoryEntryToData(pjImageBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&cjExportSize);
+ if (pExportDir == NULL)
+ {
+ fprintf(stderr, "Failed to get export directory\n");
+ return E_FAIL;
+ }
cFunctions = pExportDir->NumberOfFunctions;
cjTableSize = FIELD_OFFSET(EXPORT_DATA, aExports[cFunctions]);
@@ -186,6 +343,7 @@
pExportData = malloc(cjTableSize);
if (pExportData == NULL)
{
+ error("Failed to allocate %u bytes of memory for export table\n",
cjTableSize);
return E_OUTOFMEMORY;
}
@@ -199,7 +357,8 @@
for (i = 0; i < cFunctions; i++)
{
PVOID pvFunction = (pjImageBase + pulAddressTable[i]);
-
+
+ /* Check if this is a forwarder */
if ((ULONG_PTR)((PUCHAR)pvFunction - (PUCHAR)pExportDir) < cjExportSize)
{
pExportData->aExports[i].pszForwarder = _strdup(pvFunction);
@@ -223,8 +382,6 @@
}
*ppExportData = pExportData;
- UnmapViewOfFile(pjImageBase);
- CloseHandle(hMap);
return S_OK;
}
@@ -233,7 +390,7 @@
EnumParametersCallback(
_In_ PSYMBOL_INFO pSymInfo,
_In_ ULONG SymbolSize,
- _In_opt_ PVOID UserContext)
+ _In_ PVOID UserContext)
{
PEXPORT pExport = (PEXPORT)UserContext;
enum SymTagEnum eSymTag;
@@ -282,7 +439,8 @@
break;
}
}
- /* 'long' type */
+
+ /* Default to 'long' type */
pExport->aeParameters[pExport->cParameters - 1] = TYPE_LONG;
break;
@@ -309,12 +467,15 @@
TI_GET_BASETYPE,
&eBaseType))
{
+ /* Check for string types */
if (eBaseType == btChar)
{
+ /* 'str' type */
pExport->aeParameters[pExport->cParameters - 1] =
TYPE_STR;
}
else if (eBaseType == btWChar)
{
+ /* 'wstr' type */
pExport->aeParameters[pExport->cParameters - 1] =
TYPE_WSTR;
}
}
@@ -335,46 +496,92 @@
return TRUE;
}
+ULONG64
+GetFunctionFromForwarder(
+ _In_ PCSTR pszForwarder)
+{
+ CHAR szDllName[MAX_SYMBOL_NAME];
+ PCH pchDot, pszName;
+ ULONG64 ullFunction;
+ HMODULE hmod;
+
+ /* Copy the forwarder name */
+ strcpy_s(szDllName, sizeof(szDllName), pszForwarder);
+
+ /* Find the '.' */
+ pchDot = strchr(szDllName, '.');
+ if (pchDot == NULL)
+ {
+ error("Invalid name for forwarder '%s'!", pszForwarder);
+ return 0;
+ }
+
+ /* Terminate DLL name */
+ *pchDot = '\0';
+
+ /* Load the DLL */
+ hmod = LoadModuleWithSymbols(szDllName);
+ if (hmod == NULL)
+ {
+ error("Failed to load module for forwarder '%s'!",
pszForwarder);
+ return 0;
+ }
+
+ /* Get the function name and check for ordinal */
+ pszName = pchDot + 1;
+ if (pszName[0] == '#')
+ {
+ ULONG iOrdinal = strtoul(pszName + 1, NULL, 10);
+ if ((iOrdinal == 0) || (iOrdinal > 0xFFFF))
+ {
+ error("Got invalid ordinal %u for ''", iOrdinal,
pszForwarder);
+ return 0;
+ }
+
+ pszName = (PSTR)(ULONG_PTR)iOrdinal;
+ }
+
+ /* Get the function address */
+ ullFunction = (ULONG_PTR)GetProcAddress(hmod, pszName);
+ if (ullFunction == 0)
+ {
+ error("Failed to resolve '%s' in '%s'.", pchDot + 1,
szDllName);
+ return 0;
+ }
+
+ return ullFunction;
+}
+
HRESULT
-ParseExportSymbols(
- _In_ HANDLE hFile,
+ParseImageSymbols(
+ _In_ HMODULE hmod,
_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;
- }
-
-
+ dwModuleBase = (DWORD_PTR)hmod;
+
+ /* Loop through all exports */
for (i = 0; i < pExportData->cNumberOfExports; i++)
{
PEXPORT pExport = &pExportData->aExports[i];
ULONG64 ullFunction = dwModuleBase + pExportData->aExports[i].ulRva;
ULONG64 ullDisplacement;
- /* Skip forwarder */
+ /* Check if this is a forwarder */
if (pExport->pszForwarder != NULL)
- continue;
+ {
+ /* Load the module and get the function address */
+ ullFunction = GetFunctionFromForwarder(pExport->pszForwarder);
+ if (ullFunction == 0)
+ {
+ printf("Failed to get function for forwarder '%s'.
Skipping.\n", pExport->pszForwarder);
+ continue;
+ }
+ }
RtlZeroMemory(&sym, sizeof(sym));
sym.si.SizeOfStruct = sizeof(SYMBOL_INFO);
@@ -383,16 +590,16 @@
/* Try to find the symbol */
if (!SymFromAddr(ghProcess, ullFunction, &ullDisplacement, &sym.si))
{
- printf("Error: SymFromAddr() failed. Error code: %u \n",
GetLastError());
+ error("Error: SymFromAddr() failed.");
continue;
}
- /* Symbol found. Check if it is a function */
+ /* Get the symbol name */
+ pExport->pszSymbol = _strdup(sym.si.Name);
+
+ /* 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,
@@ -401,7 +608,7 @@
&pExport->dwCallingConvention))
{
/* Fall back to __stdcall */
- pExport->dwCallingConvention = 0x07; // CV_CALL_NEAR_STD
+ pExport->dwCallingConvention = CV_CALL_NEAR_STD;
}
/* Set the context to the function address */
@@ -409,8 +616,7 @@
StackFrame.InstructionOffset = ullFunction;
if (!SymSetContext(ghProcess, &StackFrame, NULL))
{
- DWORD dwLastError = GetLastError();
- __debugbreak();
+ error("SymSetContext failed for i = %u.", i);
continue;
}
@@ -421,10 +627,13 @@
EnumParametersCallback,
pExport))
{
- DWORD dwLastError = GetLastError();
- __debugbreak();
+ error("SymEnumSymbols failed for i = %u.", i);
continue;
}
+ }
+ else if (sym.si.Tag == SymTagPublicSymbol)
+ {
+ pExport->dwCallingConvention = CV_CALL_NEAR_STD;
}
else if (sym.si.Tag == SymTagData)
{
@@ -457,8 +666,6 @@
return "syscall";
case CV_CALL_THISCALL:
return "thiscall";
- case CV_CALL_CLRCALL:
- return "clrcall";
default:
__debugbreak();
}
@@ -478,7 +685,7 @@
/* Create the spec file */
if (fopen_s(&file, pszSpecFile, "w") != 0)
{
- fprintf(stderr, "Failed to open spec file: '%s'\n",
pszSpecFile);
+ error("Failed to open spec file: '%s'\n", pszSpecFile);
return E_FAIL;
}
@@ -487,7 +694,7 @@
{
pExport = &pExportData->aExports[i];
- fprintf(file, "%u %s ", i + 1, GetCallingConvention(pExport));
+ fprintf(file, "%lu %s ", i + 1, GetCallingConvention(pExport));
//if (pExport->fNoName)
if (pExport->pszName == NULL)
{
@@ -504,7 +711,7 @@
}
else
{
- fprintf(file, "NamelessExport_%u", i);
+ fprintf(file, "NamelessExport_%lu", i);
}
if (!pExport->fData)
@@ -539,43 +746,24 @@
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);
- }
-
+ HMODULE hmod;
+
+ /* Check parameters */
+ if ((argc < 2) || !strcmp(argv[1], "/?"))
+ {
+ printf("syntax: createspec <image file> [<spec file>]\n");
+ return 0;
+ }
+
+ /* Check if we have a spec file name */
if (argc > 2)
{
pszSpecFile = argv[2];
}
else
{
+ /* Create spec file name from image file name */
PSTR pszStart = strrchr(argv[1], '\\');
if (pszStart == 0)
pszStart = argv[1];
@@ -585,10 +773,41 @@
pszSpecFile = szSpecFile;
}
+ /* Initialize dbghelp.dll */
+ if (!InitDbgHelp())
+ {
+ error("Failed to init dbghelp!\n"
+ "Make sure you have dbghelp.dll and symsrv.dll in the same
folder.\n");
+ return E_FAIL;
+ }
+
+ /* Load the file including symbols */
+ printf("Loading symbols for '%s', please wait...\n", argv[1]);
+ hmod = LoadModuleWithSymbols(argv[1]);
+ if (hmod == NULL)
+ {
+ error("Failed to load module '%s'!", argv[1]);
+ return E_FAIL;
+ }
+
+ /* Get the exports */
+ hr = GetExportsFromFile(hmod, &pExportData);
+ if (!SUCCEEDED(hr))
+ {
+ error("Failed to get exports: %lx\n", hr);
+ return hr;
+ }
+
+ /* Get additional info from symbols */
+ hr = ParseImageSymbols(hmod, pExportData);
+ if (!SUCCEEDED(hr))
+ {
+ error("Failed to get symbol information: hr=%lx\n", hr);
+ }
+
+ /* Write the spec file */
hr = CreateSpecFile(pszSpecFile, pExportData);
- CloseHandle(hFile);
-
printf("Spec file '%s' was successfully written.\n", szSpecFile);
return hr;