aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--src/dlfcn.c106
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/test-dladdr.c23
4 files changed, 97 insertions, 43 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..b52b307 100644
--- a/src/dlfcn.c
+++ b/src/dlfcn.c
@@ -512,8 +512,8 @@ 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 import table */
516static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address ) 516static const char *get_import_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address )
517{ 517{
518 int i; 518 int i;
519 void *candidateAddr = NULL; 519 void *candidateAddr = NULL;
@@ -545,6 +545,40 @@ static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid
545 return candidateName; 545 return candidateName;
546} 546}
547 547
548/* Return symbol name for a given address from export table */
549static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, void *addr, void **func_address )
550{
551 DWORD i;
552 void *candidateAddr = NULL;
553 int candidateIndex = -1;
554 BYTE *base = (BYTE *) module;
555 DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions);
556 DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames);
557 USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals);
558
559 for( i = 0; i < ied->NumberOfFunctions; i++ )
560 {
561 if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) )
562 continue;
563
564 candidateAddr = (void *) ( base + functionAddressesOffsets[i] );
565 candidateIndex = i;
566 }
567
568 if( candidateIndex == -1 )
569 return NULL;
570
571 *func_address = candidateAddr;
572
573 for( i = 0; i < ied->NumberOfNames; i++ )
574 {
575 if( functionNameOrdinalsIndexes[i] == candidateIndex )
576 return (const char *) ( base + functionNamesOffsets[i] );
577 }
578
579 return NULL;
580}
581
548static BOOL is_valid_address( void *addr ) 582static BOOL is_valid_address( void *addr )
549{ 583{
550 MEMORY_BASIC_INFORMATION info; 584 MEMORY_BASIC_INFORMATION info;
@@ -608,11 +642,16 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, v
608/* Holds module filename */ 642/* Holds module filename */
609static char module_filename[2*MAX_PATH]; 643static char module_filename[2*MAX_PATH];
610 644
611static BOOL fill_module_info( void *addr, Dl_info *info ) 645static BOOL fill_info( HMODULE hModuleImport, void *addr, Dl_info *info )
612{ 646{
613 HMODULE hModule; 647 HMODULE hModule;
614 DWORD dwSize; 648 DWORD dwSize;
649 IMAGE_EXPORT_DIRECTORY *ied;
650 IMAGE_IMPORT_DESCRIPTOR *iid;
651 const char *name;
652 void *funcAddress = NULL;
615 653
654 /* 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 ) 655 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL )
617 return FALSE; 656 return FALSE;
618 657
@@ -621,8 +660,27 @@ static BOOL fill_module_info( void *addr, Dl_info *info )
621 if( dwSize == 0 || dwSize == sizeof( module_filename ) ) 660 if( dwSize == 0 || dwSize == sizeof( module_filename ) )
622 return FALSE; 661 return FALSE;
623 662
624 info->dli_fbase = (void *) hModule;
625 info->dli_fname = module_filename; 663 info->dli_fname = module_filename;
664 info->dli_fbase = (void *) hModule;
665 info->dli_sname = NULL;
666
667 /* First try to find function name and function address in module's export table */
668 if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) )
669 info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress );
670
671 /* If symbol name is not known and we know which module is importing this address
672 * then try to find symbol name in this module's import table as the last resort. */
673 if( info->dli_sname == NULL && hModuleImport != NULL )
674 {
675 if( get_image_section( hModuleImport, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, NULL ) )
676 {
677 name = get_import_symbol_name( hModuleImport, iid, addr, &funcAddress );
678 if( name != NULL )
679 info->dli_sname = name;
680 }
681 }
682
683 info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : addr;
626 684
627 return TRUE; 685 return TRUE;
628} 686}
@@ -630,36 +688,33 @@ static BOOL fill_module_info( void *addr, Dl_info *info )
630DLFCN_EXPORT 688DLFCN_EXPORT
631int dladdr( void *addr, Dl_info *info ) 689int dladdr( void *addr, Dl_info *info )
632{ 690{
633 void *realAddr, *funcAddress = NULL; 691 HMODULE hModule = NULL;
634 HMODULE hModule;
635 IMAGE_IMPORT_DESCRIPTOR *iid;
636 DWORD iidSize = 0;
637 692
638 if( addr == NULL || info == NULL ) 693 if( addr == NULL || info == NULL )
639 return 0; 694 return 0;
640 695
641 hModule = GetModuleHandleA( NULL );
642 if( hModule == NULL )
643 return 0;
644
645 if( !is_valid_address( addr ) ) 696 if( !is_valid_address( addr ) )
646 return 0; 697 return 0;
647 698
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 ) ) 699 if( is_import_thunk( addr ) )
654 { 700 {
655 void *iat; 701 void *iat;
656 void *iatAddr = NULL; 702 DWORD iatSize;
657 DWORD iatSize = 0; 703
704 /* Get module of the import thunk address */
705 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL )
706 return 0;
658 707
659 if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) 708 if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) )
660 { 709 {
661 /* Fallback for cases where the iat is not defined, 710 /* Fallback for cases where the iat is not defined,
662 * for example i586-mingw32msvc-gcc */ 711 * for example i586-mingw32msvc-gcc */
712 IMAGE_IMPORT_DESCRIPTOR *iid;
713 DWORD iidSize;
714
715 if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) )
716 return 0;
717
663 if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) 718 if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 )
664 return 0; 719 return 0;
665 720
@@ -668,19 +723,18 @@ int dladdr( void *addr, Dl_info *info )
668 iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); 723 iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid );
669 } 724 }
670 725
671 iatAddr = get_address_from_import_address_table( iat, iatSize, addr ); 726 addr = get_address_from_import_address_table( iat, iatSize, addr );
672 if( iatAddr == NULL ) 727
728 if( addr == NULL )
673 return 0; 729 return 0;
674 730
675 realAddr = iatAddr; 731 if( !is_valid_address( addr ) )
732 return 0;
676 } 733 }
677 734
678 if( !fill_module_info( realAddr, info ) ) 735 if( !fill_info( hModule, addr, info ) )
679 return 0; 736 return 0;
680 737
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; 738 return 1;
685} 739}
686 740
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 );