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/CMake... ============================================================================== --- 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/creat... ============================================================================== --- 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;