aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSilvio Traversaro <silvio@traversaro.it>2021-02-03 18:33:32 +0100
committerGitHub <noreply@github.com>2021-02-03 18:33:32 +0100
commit3ec513f9d9fec0cf52aa7e2f2050112499cac581 (patch)
tree0d7060265ba3e8f4193e00260c9bc6293353e501
parenta5af061ce1d1bb3f58e74c48c0698dad59d79937 (diff)
parentb46da88412444a7a22b7378402cabadf6689cea2 (diff)
downloaddlfcn-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--Makefile4
-rw-r--r--src/dlfcn.c100
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/test-dladdr.c23
4 files changed, 69 insertions, 65 deletions
diff --git a/Makefile b/Makefile
index 944358f..899334a 100644
--- a/Makefile
+++ b/Makefile
@@ -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
67test-dladdr.exe: tests/test-dladdr.c $(TARGETS) 67test-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
70test-dladdr-static.exe: tests/test-dladdr.c $(TARGETS) 70test-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
73testdll.dll: tests/testdll.c 73testdll.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 */
516static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address ) 516static 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
548static BOOL is_valid_address( void *addr ) 549static 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 */
609static char module_filename[2*MAX_PATH]; 610static char module_filename[2*MAX_PATH];
610 611
611static BOOL fill_module_info( void *addr, Dl_info *info ) 612static 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 )
630DLFCN_EXPORT 642DLFCN_EXPORT
631int dladdr( void *addr, Dl_info *info ) 643int 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)
25if(UNIX) 25if(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")
27endif() 27endif()
28if(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()
34endif()
28 35
29install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) 36install(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
148int main(int argc, char **argv) 141int 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 );