diff options
author | Pali Rohár <pali.rohar@gmail.com> | 2021-01-25 23:27:22 +0100 |
---|---|---|
committer | Pali Rohár <pali.rohar@gmail.com> | 2021-01-27 18:58:21 +0100 |
commit | 86a41b921ca5c4bad1d0d7e54f9276046a25e319 (patch) | |
tree | a8b64ba1d9a4cf2432d1f65333a1de1dd6a9299e /src | |
parent | a5af061ce1d1bb3f58e74c48c0698dad59d79937 (diff) | |
download | dlfcn-win32-86a41b921ca5c4bad1d0d7e54f9276046a25e319.tar.gz dlfcn-win32-86a41b921ca5c4bad1d0d7e54f9276046a25e319.tar.bz2 dlfcn-win32-86a41b921ca5c4bad1d0d7e54f9276046a25e319.zip |
Function dladdr() now retrieve symbol name and symbol address from both export and import tables
dladdr tests for Windows now should always pass like on other systems.
Diffstat (limited to 'src')
-rw-r--r-- | src/dlfcn.c | 106 |
1 files changed, 80 insertions, 26 deletions
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 */ |
516 | static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address ) | 516 | static 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 */ | ||
549 | static 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 | |||
548 | static BOOL is_valid_address( void *addr ) | 582 | static 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 */ |
609 | static char module_filename[2*MAX_PATH]; | 643 | static char module_filename[2*MAX_PATH]; |
610 | 644 | ||
611 | static BOOL fill_module_info( void *addr, Dl_info *info ) | 645 | static 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 ) | |||
630 | DLFCN_EXPORT | 688 | DLFCN_EXPORT |
631 | int dladdr( void *addr, Dl_info *info ) | 689 | int 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 | ||