From: Bernhard Reiter Subject: imagehlp: Implement (parts of) BindImageEx (try 4) Message-Id: <53578BE1.1060903@raz.or.at> Date: Wed, 23 Apr 2014 11:46:09 +0200 Added a basic test case, a NOTES section; use ImageDirectoryEntryToDataEx instead of ImageDirectoryEntryToData, and change some // to /* ... */ comments. From 854192c9e7a744718a10c28ead064c29fac441b8 Mon Sep 17 00:00:00 2001 From: Bernhard Reiter Date: Wed, 9 Apr 2014 00:52:31 +0200 Subject: Implement parts of BindImageEx so at least freezing Python scripts works. Fixes http://bugs.winehq.org/show_bug.cgi?id=3591 --- dlls/imagehlp/modify.c | 71 ++++++++++++++++++++++++++++++++++++++- dlls/imagehlp/tests/image.c | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/dlls/imagehlp/modify.c b/dlls/imagehlp/modify.c index debccc0..8d5c49b 100644 --- a/dlls/imagehlp/modify.c +++ b/dlls/imagehlp/modify.c @@ -34,6 +34,9 @@ static WORD CalcCheckSum(DWORD StartValue, LPVOID BaseAddress, DWORD WordCount); /*********************************************************************** * BindImage (IMAGEHLP.@) + * + * NOTES + * See BindImageEx */ BOOL WINAPI BindImage( PCSTR ImageName, PCSTR DllPath, PCSTR SymbolPath) @@ -43,15 +46,81 @@ BOOL WINAPI BindImage( /*********************************************************************** * BindImageEx (IMAGEHLP.@) + * + * Compute the virtual address of each function imported by a PE image + * + * PARAMS + * + * Flags [in] Bind options + * ImageName [in] File name of the image to be bound + * DllPath [in] Root of the fallback search path in case the ImageName file cannot be opened + * SymbolPath [in] Symbol file root search path + * StatusRoutine [in] Pointer to a status routine which will be called during the binding process + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * This is currently only a stub that invokes StatusRoutine with the + * BindImportModule and BindImportProcedure statuses to allow listing an + * image's imported modules and procedures, but does not perform any actual + * binding yet! The main purpose of this implementation is fixing + * http://bugs.winehq.org/show_bug.cgi?id=3591 -- i.e. to allow "freezing" of + * Python packages (as performed by cx_Freeze or py2exe) which usually invoke + * BindImageEx to determine what DLLs to add to the frozen package. */ BOOL WINAPI BindImageEx( DWORD Flags, PCSTR ImageName, PCSTR DllPath, PCSTR SymbolPath, PIMAGEHLP_STATUS_ROUTINE StatusRoutine) { - FIXME("(%d, %s, %s, %s, %p): stub\n", + TRACE("(%d, %s, %s, %s, %p)\n", Flags, debugstr_a(ImageName), debugstr_a(DllPath), debugstr_a(SymbolPath), StatusRoutine ); + + LOADED_IMAGE loadedImage; + const IMAGE_IMPORT_DESCRIPTOR *importDesc; + ULONG size; + + if (!(MapAndLoad( ImageName, DllPath, &loadedImage, TRUE, TRUE ))) return FALSE; + + if (!(importDesc = (PIMAGE_IMPORT_DESCRIPTOR) + ImageDirectoryEntryToDataEx( loadedImage.MappedAddress, FALSE, + IMAGE_DIRECTORY_ENTRY_IMPORT, &size, + NULL))) + return FALSE; + + for (; importDesc->Name && importDesc->FirstThunk; ++importDesc) { + PSTR DllName = ImageRvaToVa( loadedImage.FileHeader, + loadedImage.MappedAddress, + importDesc->Name, + NULL ); + (*StatusRoutine)( BindImportModule, ImageName, DllName, + (ULONG_PTR) NULL, (ULONG_PTR) NULL ); + + PIMAGE_THUNK_DATA thunk = ImageRvaToVa( loadedImage.FileHeader, + loadedImage.MappedAddress, + importDesc->OriginalFirstThunk, + NULL ); + + for (; thunk->u1.Function; ++thunk) { + if(thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { + /* Ordinal, i.e. unnamed function. Not sure if/how to properly pass this + * on to StatusRoutine... */ + /* DWORD ordinal = (DWORD) (thunk->u1.Ordinal & (~IMAGE_ORDINAL_FLAG)); */ + } else { + PIMAGE_IMPORT_BY_NAME funcNameStruct = + ImageRvaToVa( loadedImage.FileHeader, loadedImage.MappedAddress, + thunk->u1.AddressOfData, NULL ); + (*StatusRoutine)( BindImportProcedure, ImageName, DllName, + (ULONG_PTR) NULL, (ULONG_PTR) funcNameStruct->Name ); + } + + } + } + + UnMapAndLoad( &loadedImage ); return TRUE; } diff --git a/dlls/imagehlp/tests/image.c b/dlls/imagehlp/tests/image.c index e008b0b..d2a82ab 100644 --- a/dlls/imagehlp/tests/image.c +++ b/dlls/imagehlp/tests/image.c @@ -31,6 +31,9 @@ static HMODULE hImageHlp; static BOOL (WINAPI *pImageGetDigestStream)(HANDLE, DWORD, DIGEST_FUNCTION, DIGEST_HANDLE); +static BOOL (WINAPI *pBindImageEx)(DWORD Flags, PCSTR ImageName, + PCSTR DllPath, PCSTR SymbolPath, + PIMAGEHLP_STATUS_ROUTINE StatusRoutine); /* minimal PE file image */ #define VA_START 0x400000 @@ -273,6 +276,41 @@ static void update_checksum(void) bin.nt_headers.OptionalHeader.CheckSum = sum; } +BOOL WINAPI TestStatusRoutine(IMAGEHLP_STATUS_REASON reason, + PSTR ImageName, + PSTR DllName, + ULONG_PTR Va, + ULONG_PTR Parameter) +{ + switch(reason) + { + case BindOutOfMemory: + case BindRvaToVaFailed: + case BindNoRoomInImage: + case BindImportModuleFailed: + case BindImportProcedureFailed: + break; + + case BindImportProcedure: + ok(!strcmp((LPSTR)Parameter, "ExitProcess"), + "expected Parameter to be ExitProcess, got %s\n", (LPSTR)Parameter); + case BindImportModule: + ok(!strcmp(DllName, "KERNEL32.DLL"), + "expected DllName to be KERNEL32.DLL, got %s\n", DllName); + break; + + case BindForwarder: + case BindForwarderNOT: + case BindImageModified: + case BindExpandFileHeaders: + case BindImageComplete: + case BindMismatchedSymbols: + case BindSymbolsNotUpdated: + break; + } + return TRUE; +} + static void test_get_digest_stream(void) { BOOL ret; @@ -329,6 +367,40 @@ static void test_get_digest_stream(void) DeleteFileA(temp_file); } +static void test_bind_image_ex(void) +{ + BOOL ret; + HANDLE file; + char temp_file[MAX_PATH]; + DWORD count; + + /* Call with a non-existant file */ + SetLastError(0xdeadbeef); + ret = pBindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES, + (PSTR)temp_file, NULL, NULL, + (PIMAGEHLP_STATUS_ROUTINE)TestStatusRoutine); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + file = create_temp_file(temp_file); + if (file == INVALID_HANDLE_VALUE) + { + skip("couldn't create temp file\n"); + return; + } + + WriteFile(file, &bin, sizeof(bin), &count, NULL); + FlushFileBuffers(file); + CloseHandle(file); + + SetLastError(0xdeadbeef); + ret = pBindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES, + (PSTR)temp_file, NULL, NULL, + (PIMAGEHLP_STATUS_ROUTINE)TestStatusRoutine); + ok(ret, "BindImageEx failed: %d\n", GetLastError()); + DeleteFileA(temp_file); +} + START_TEST(image) { hImageHlp = LoadLibraryA("imagehlp.dll"); @@ -349,5 +421,15 @@ START_TEST(image) test_get_digest_stream(); } + pBindImageEx = (void *) GetProcAddress(hImageHlp, "BindImageEx"); + + if (!pBindImageEx) + { + win_skip("BindImageEx function is not available\n"); + } else + { + test_bind_image_ex(); + } + FreeLibrary(hImageHlp); } -- 1.9.1