diff options
| author | Silvio Traversaro <silvio@traversaro.it> | 2021-02-03 18:33:32 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-03 18:33:32 +0100 |
| commit | 3ec513f9d9fec0cf52aa7e2f2050112499cac581 (patch) | |
| tree | 0d7060265ba3e8f4193e00260c9bc6293353e501 | |
| parent | a5af061ce1d1bb3f58e74c48c0698dad59d79937 (diff) | |
| parent | b46da88412444a7a22b7378402cabadf6689cea2 (diff) | |
| download | dlfcn-win32-3ec513f9d9fec0cf52aa7e2f2050112499cac581.tar.gz dlfcn-win32-3ec513f9d9fec0cf52aa7e2f2050112499cac581.tar.bz2 dlfcn-win32-3ec513f9d9fec0cf52aa7e2f2050112499cac581.zip | |
Merge pull request #94 from pali/dladdr
dladdr() - Retrieve symbol name and address from export table
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | src/dlfcn.c | 100 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | tests/test-dladdr.c | 23 |
4 files changed, 69 insertions, 65 deletions
| @@ -65,10 +65,10 @@ test-static.exe: tests/test.c $(TARGETS) | |||
| 65 | $(CC) $(CFLAGS) -o $@ $< libdl.a | 65 | $(CC) $(CFLAGS) -o $@ $< libdl.a |
| 66 | 66 | ||
| 67 | test-dladdr.exe: tests/test-dladdr.c $(TARGETS) | 67 | test-dladdr.exe: tests/test-dladdr.c $(TARGETS) |
| 68 | $(CC) $(CFLAGS) -DDLFCN_WIN32_SHARED -o $@ $< libdl.dll.a | 68 | $(CC) $(CFLAGS) -Wl,--export-all-symbols -DDLFCN_WIN32_SHARED -o $@ $< libdl.dll.a |
| 69 | 69 | ||
| 70 | test-dladdr-static.exe: tests/test-dladdr.c $(TARGETS) | 70 | test-dladdr-static.exe: tests/test-dladdr.c $(TARGETS) |
| 71 | $(CC) $(CFLAGS) -o $@ $< libdl.a | 71 | $(CC) $(CFLAGS) -Wl,--export-all-symbols -o $@ $< libdl.a |
| 72 | 72 | ||
| 73 | testdll.dll: tests/testdll.c | 73 | testdll.dll: tests/testdll.c |
| 74 | $(CC) $(CFLAGS) -shared -o $@ $^ | 74 | $(CC) $(CFLAGS) -shared -o $@ $^ |
diff --git a/src/dlfcn.c b/src/dlfcn.c index 5dd1ccf..abbd58d 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c | |||
| @@ -512,37 +512,38 @@ static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *siz | |||
| 512 | return TRUE; | 512 | return TRUE; |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | /* Return symbol name for a given address */ | 515 | /* Return symbol name for a given address from export table */ |
| 516 | static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address ) | 516 | static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, void *addr, void **func_address ) |
| 517 | { | 517 | { |
| 518 | int i; | 518 | DWORD i; |
| 519 | void *candidateAddr = NULL; | 519 | void *candidateAddr = NULL; |
| 520 | const char *candidateName = NULL; | 520 | int candidateIndex = -1; |
| 521 | BYTE *base = (BYTE *) module; /* Required to have correct calculations */ | 521 | BYTE *base = (BYTE *) module; |
| 522 | DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions); | ||
| 523 | DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames); | ||
| 524 | USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals); | ||
| 522 | 525 | ||
| 523 | for( i = 0; iid[i].Characteristics != 0 && iid[i].FirstThunk != 0; i++ ) | 526 | for( i = 0; i < ied->NumberOfFunctions; i++ ) |
| 524 | { | 527 | { |
| 525 | IMAGE_THUNK_DATA *thunkILT = (IMAGE_THUNK_DATA *)( base + iid[i].Characteristics ); | 528 | if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) ) |
| 526 | IMAGE_THUNK_DATA *thunkIAT = (IMAGE_THUNK_DATA *)( base + iid[i].FirstThunk ); | 529 | continue; |
| 527 | 530 | ||
| 528 | for( ; thunkILT->u1.AddressOfData != 0; thunkILT++, thunkIAT++ ) | 531 | candidateAddr = (void *) ( base + functionAddressesOffsets[i] ); |
| 529 | { | 532 | candidateIndex = i; |
| 530 | IMAGE_IMPORT_BY_NAME *nameData; | 533 | } |
| 531 | 534 | ||
| 532 | if( IMAGE_SNAP_BY_ORDINAL( thunkILT->u1.Ordinal ) ) | 535 | if( candidateIndex == -1 ) |
| 533 | continue; | 536 | return NULL; |
| 534 | 537 | ||
| 535 | if( (void *) thunkIAT->u1.Function > addr || candidateAddr >= (void *) thunkIAT->u1.Function ) | 538 | *func_address = candidateAddr; |
| 536 | continue; | ||
| 537 | 539 | ||
| 538 | candidateAddr = (void *) thunkIAT->u1.Function; | 540 | for( i = 0; i < ied->NumberOfNames; i++ ) |
| 539 | nameData = (IMAGE_IMPORT_BY_NAME *)( base + (ULONG_PTR) thunkILT->u1.AddressOfData ); | 541 | { |
| 540 | candidateName = (const char *) nameData->Name; | 542 | if( functionNameOrdinalsIndexes[i] == candidateIndex ) |
| 541 | } | 543 | return (const char *) ( base + functionNamesOffsets[i] ); |
| 542 | } | 544 | } |
| 543 | 545 | ||
| 544 | *func_address = candidateAddr; | 546 | return NULL; |
| 545 | return candidateName; | ||
| 546 | } | 547 | } |
| 547 | 548 | ||
| 548 | static BOOL is_valid_address( void *addr ) | 549 | static BOOL is_valid_address( void *addr ) |
| @@ -608,11 +609,14 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, v | |||
| 608 | /* Holds module filename */ | 609 | /* Holds module filename */ |
| 609 | static char module_filename[2*MAX_PATH]; | 610 | static char module_filename[2*MAX_PATH]; |
| 610 | 611 | ||
| 611 | static BOOL fill_module_info( void *addr, Dl_info *info ) | 612 | static BOOL fill_info( void *addr, Dl_info *info ) |
| 612 | { | 613 | { |
| 613 | HMODULE hModule; | 614 | HMODULE hModule; |
| 614 | DWORD dwSize; | 615 | DWORD dwSize; |
| 616 | IMAGE_EXPORT_DIRECTORY *ied; | ||
| 617 | void *funcAddress = NULL; | ||
| 615 | 618 | ||
| 619 | /* Get module of the specified address */ | ||
| 616 | if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) | 620 | if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) |
| 617 | return FALSE; | 621 | return FALSE; |
| 618 | 622 | ||
| @@ -621,8 +625,16 @@ static BOOL fill_module_info( void *addr, Dl_info *info ) | |||
| 621 | if( dwSize == 0 || dwSize == sizeof( module_filename ) ) | 625 | if( dwSize == 0 || dwSize == sizeof( module_filename ) ) |
| 622 | return FALSE; | 626 | return FALSE; |
| 623 | 627 | ||
| 624 | info->dli_fbase = (void *) hModule; | ||
| 625 | info->dli_fname = module_filename; | 628 | info->dli_fname = module_filename; |
| 629 | info->dli_fbase = (void *) hModule; | ||
| 630 | |||
| 631 | /* Find function name and function address in module's export table */ | ||
| 632 | if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) ) | ||
| 633 | info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress ); | ||
| 634 | else | ||
| 635 | info->dli_sname = NULL; | ||
| 636 | |||
| 637 | info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : addr; | ||
| 626 | 638 | ||
| 627 | return TRUE; | 639 | return TRUE; |
| 628 | } | 640 | } |
| @@ -630,36 +642,32 @@ static BOOL fill_module_info( void *addr, Dl_info *info ) | |||
| 630 | DLFCN_EXPORT | 642 | DLFCN_EXPORT |
| 631 | int dladdr( void *addr, Dl_info *info ) | 643 | int dladdr( void *addr, Dl_info *info ) |
| 632 | { | 644 | { |
| 633 | void *realAddr, *funcAddress = NULL; | 645 | if( info == NULL ) |
| 634 | HMODULE hModule; | ||
| 635 | IMAGE_IMPORT_DESCRIPTOR *iid; | ||
| 636 | DWORD iidSize = 0; | ||
| 637 | |||
| 638 | if( addr == NULL || info == NULL ) | ||
| 639 | return 0; | ||
| 640 | |||
| 641 | hModule = GetModuleHandleA( NULL ); | ||
| 642 | if( hModule == NULL ) | ||
| 643 | return 0; | 646 | return 0; |
| 644 | 647 | ||
| 645 | if( !is_valid_address( addr ) ) | 648 | if( !is_valid_address( addr ) ) |
| 646 | return 0; | 649 | return 0; |
| 647 | 650 | ||
| 648 | realAddr = addr; | ||
| 649 | |||
| 650 | if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) ) | ||
| 651 | return 0; | ||
| 652 | |||
| 653 | if( is_import_thunk( addr ) ) | 651 | if( is_import_thunk( addr ) ) |
| 654 | { | 652 | { |
| 655 | void *iat; | 653 | void *iat; |
| 656 | void *iatAddr = NULL; | 654 | DWORD iatSize; |
| 657 | DWORD iatSize = 0; | 655 | HMODULE hModule; |
| 656 | |||
| 657 | /* Get module of the import thunk address */ | ||
| 658 | if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) | ||
| 659 | return 0; | ||
| 658 | 660 | ||
| 659 | if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) | 661 | if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) |
| 660 | { | 662 | { |
| 661 | /* Fallback for cases where the iat is not defined, | 663 | /* Fallback for cases where the iat is not defined, |
| 662 | * for example i586-mingw32msvc-gcc */ | 664 | * for example i586-mingw32msvc-gcc */ |
| 665 | IMAGE_IMPORT_DESCRIPTOR *iid; | ||
| 666 | DWORD iidSize; | ||
| 667 | |||
| 668 | if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) ) | ||
| 669 | return 0; | ||
| 670 | |||
| 663 | if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) | 671 | if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) |
| 664 | return 0; | 672 | return 0; |
| 665 | 673 | ||
| @@ -668,19 +676,15 @@ int dladdr( void *addr, Dl_info *info ) | |||
| 668 | iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); | 676 | iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); |
| 669 | } | 677 | } |
| 670 | 678 | ||
| 671 | iatAddr = get_address_from_import_address_table( iat, iatSize, addr ); | 679 | addr = get_address_from_import_address_table( iat, iatSize, addr ); |
| 672 | if( iatAddr == NULL ) | ||
| 673 | return 0; | ||
| 674 | 680 | ||
| 675 | realAddr = iatAddr; | 681 | if( !is_valid_address( addr ) ) |
| 682 | return 0; | ||
| 676 | } | 683 | } |
| 677 | 684 | ||
| 678 | if( !fill_module_info( realAddr, info ) ) | 685 | if( !fill_info( addr, info ) ) |
| 679 | return 0; | 686 | return 0; |
| 680 | 687 | ||
| 681 | info->dli_sname = get_symbol_name( hModule, iid, realAddr, &funcAddress ); | ||
| 682 | |||
| 683 | info->dli_saddr = !info->dli_sname ? NULL : funcAddress ? funcAddress : realAddr; | ||
| 684 | return 1; | 688 | return 1; |
| 685 | } | 689 | } |
| 686 | 690 | ||
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 00b6647..47fef38 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt | |||
| @@ -25,6 +25,13 @@ target_link_libraries(test-dladdr dl) | |||
| 25 | if(UNIX) | 25 | if(UNIX) |
| 26 | set_target_properties(test-dladdr PROPERTIES COMPILE_FLAGS "-Wl,--export-dynamic -fpie") | 26 | set_target_properties(test-dladdr PROPERTIES COMPILE_FLAGS "-Wl,--export-dynamic -fpie") |
| 27 | endif() | 27 | endif() |
| 28 | if(WIN32 AND NOT BUILD_SHARED_LIBS) | ||
| 29 | if(MSVC) | ||
| 30 | set_property(TARGET test-dladdr APPEND_STRING PROPERTY LINK_FLAGS "/EXPORT:dlopen /EXPORT:dladdr") | ||
| 31 | else() | ||
| 32 | set_property(TARGET test-dladdr APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--export-all-symbols") | ||
| 33 | endif() | ||
| 34 | endif() | ||
| 28 | 35 | ||
| 29 | install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) | 36 | install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) |
| 30 | 37 | ||
diff --git a/tests/test-dladdr.c b/tests/test-dladdr.c index 57914cb..e2f6c01 100644 --- a/tests/test-dladdr.c +++ b/tests/test-dladdr.c | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | /* On Unix like os compile with "-Wl,--export-dynamic -fpie" (default with cmake) */ | 1 | /* On Unix like os compile with "-Wl,--export-dynamic -fpie" (default with cmake) */ |
| 2 | /* On Windows gcc compile with "-Wl,--export-all-symbols" (default with cmake) */ | ||
| 3 | /* On Windows msvc compile with "/EXPORT:dlopen /EXPORT:dladdr" (default with cmake) */ | ||
| 2 | 4 | ||
| 3 | /* required for non Windows builds, must be set in front of the first system include */ | 5 | /* required for non Windows builds, must be set in front of the first system include */ |
| 4 | #define _GNU_SOURCE | 6 | #define _GNU_SOURCE |
| @@ -131,20 +133,11 @@ __declspec(dllimport) int __cdecl atoi(const char *_Str); | |||
| 131 | #endif | 133 | #endif |
| 132 | #endif | 134 | #endif |
| 133 | 135 | ||
| 134 | #ifdef _WIN32 | ||
| 135 | #define FailOnWin Fail | ||
| 136 | #else | ||
| 137 | #define FailOnWin Pass | ||
| 138 | #endif | ||
| 139 | |||
| 140 | #if defined(_WIN32) && !defined(DLFCN_WIN32_SHARED) | ||
| 141 | #define PassOnSharedBuild Fail | ||
| 142 | #else | ||
| 143 | #define PassOnSharedBuild Pass | ||
| 144 | #endif | ||
| 145 | |||
| 146 | #define UNUSED(x) (void)x | 136 | #define UNUSED(x) (void)x |
| 147 | 137 | ||
| 138 | #ifdef _WIN32 | ||
| 139 | __declspec(dllexport) | ||
| 140 | #endif | ||
| 148 | int main(int argc, char **argv) | 141 | int main(int argc, char **argv) |
| 149 | { | 142 | { |
| 150 | /* points to non reachable address */ | 143 | /* points to non reachable address */ |
| @@ -161,10 +154,10 @@ int main(int argc, char **argv) | |||
| 161 | 154 | ||
| 162 | result = check_dladdr( "null pointer", (void*)0, NULL , NoInfo); | 155 | result = check_dladdr( "null pointer", (void*)0, NULL , NoInfo); |
| 163 | result |= check_dladdr( "invalid pointer", (void*)0x125, NULL , NoInfo); | 156 | result |= check_dladdr( "invalid pointer", (void*)0x125, NULL , NoInfo); |
| 164 | result |= check_dladdr( "function from dl library", (void*)dladdr, "dladdr" , PassOnSharedBuild ); | 157 | result |= check_dladdr( "function from dl library", (void*)dladdr, "dladdr" , Pass ); |
| 165 | result |= check_dladdr( "function from dl library", (void*)dlopen, "dlopen", PassOnSharedBuild ); | 158 | result |= check_dladdr( "function from dl library", (void*)dlopen, "dlopen", Pass ); |
| 166 | result |= check_dladdr( "function from glibc/msvcrt library", (void*)atoi, "atoi", Pass ); | 159 | result |= check_dladdr( "function from glibc/msvcrt library", (void*)atoi, "atoi", Pass ); |
| 167 | result |= check_dladdr( "function from executable", (void*)main, "main", FailOnWin ); | 160 | result |= check_dladdr( "function from executable", (void*)main, "main", Pass ); |
| 168 | result |= check_dladdr( "static function from executable", (void*)print_dl_info, "print_dl_info", Fail ); | 161 | result |= check_dladdr( "static function from executable", (void*)print_dl_info, "print_dl_info", Fail ); |
| 169 | result |= check_dladdr( "address with positive offset", ((char*)atoi)+1, "atoi", PassWithDifferentAddress ); | 162 | result |= check_dladdr( "address with positive offset", ((char*)atoi)+1, "atoi", PassWithDifferentAddress ); |
| 170 | result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo ); | 163 | result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo ); |
