aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/dlfcn.c214
-rw-r--r--src/dlfcn.h16
-rw-r--r--tests/CMakeLists.txt8
-rw-r--r--tests/test-dladdr.c184
6 files changed, 439 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index ab7279b..944358f 100644
--- a/Makefile
+++ b/Makefile
@@ -6,14 +6,14 @@ CFLAGS = -Wall -O3 -fomit-frame-pointer -Isrc
6 6
7ifeq ($(BUILD_SHARED),yes) 7ifeq ($(BUILD_SHARED),yes)
8 TARGETS += libdl.dll 8 TARGETS += libdl.dll
9 SHFLAGS += -Wl,--out-implib,libdl.dll.a -DSHARED 9 SHFLAGS += -Wl,--out-implib,libdl.dll.a
10 INSTALL += shared-install 10 INSTALL += shared-install
11 TESTS += test.exe 11 TESTS += test.exe test-dladdr.exe
12endif 12endif
13ifeq ($(BUILD_STATIC),yes) 13ifeq ($(BUILD_STATIC),yes)
14 TARGETS += libdl.a 14 TARGETS += libdl.a
15 INSTALL += static-install 15 INSTALL += static-install
16 TESTS += test-static.exe 16 TESTS += test-static.exe test-dladdr-static.exe
17endif 17endif
18ifeq ($(BUILD_MSVC),yes) 18ifeq ($(BUILD_MSVC),yes)
19 TARGETS += libdl.lib 19 TARGETS += libdl.lib
@@ -32,7 +32,7 @@ libdl.a: $(SOURCES)
32 $(RANLIB) $@ 32 $(RANLIB) $@
33 33
34libdl.dll: $(SOURCES) 34libdl.dll: $(SOURCES)
35 $(CC) $(CFLAGS) $(SHFLAGS) -shared -o $@ $^ 35 $(CC) $(CFLAGS) $(SHFLAGS) -DDLFCN_WIN32_SHARED -shared -o $@ $^
36 36
37libdl.lib: libdl.dll 37libdl.lib: libdl.dll
38 $(LIBCMD) /machine:i386 /def:libdl.def 38 $(LIBCMD) /machine:i386 /def:libdl.def
@@ -64,6 +64,12 @@ test.exe: tests/test.c $(TARGETS)
64test-static.exe: tests/test.c $(TARGETS) 64test-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)
68 $(CC) $(CFLAGS) -DDLFCN_WIN32_SHARED -o $@ $< libdl.dll.a
69
70test-dladdr-static.exe: tests/test-dladdr.c $(TARGETS)
71 $(CC) $(CFLAGS) -o $@ $< libdl.a
72
67testdll.dll: tests/testdll.c 73testdll.dll: tests/testdll.c
68 $(CC) $(CFLAGS) -shared -o $@ $^ 74 $(CC) $(CFLAGS) -shared -o $@ $^
69 75
@@ -81,6 +87,7 @@ clean::
81 src/dlfcn.o \ 87 src/dlfcn.o \
82 libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \ 88 libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \
83 tmptest.c tmptest.dll \ 89 tmptest.c tmptest.dll \
90 test-dladdr.exe test-dladdr-static.exe \
84 test.exe test-static.exe testdll.dll testdll2.dll testdll3.dll 91 test.exe test-static.exe testdll.dll testdll2.dll testdll3.dll
85 92
86distclean: clean 93distclean: clean
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d5296b1..27f9030 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,15 +1,20 @@
1set(headers dlfcn.h) 1set(headers dlfcn.h)
2set(sources dlfcn.c) 2set(sources dlfcn.c)
3 3
4if (BUILD_SHARED_LIBS)
5 add_definitions(-DSHARED)
6endif (BUILD_SHARED_LIBS)
7 4
8add_library(dl ${sources}) 5add_library(dl ${sources})
9 6
10# Correctly export the location of installed includes in the target 7# Correctly export the location of installed includes in the target
11target_include_directories(dl INTERFACE $<INSTALL_INTERFACE:include>) 8target_include_directories(dl INTERFACE $<INSTALL_INTERFACE:include>)
12 9
10# dot not add -D<target>_EXPORTS
11set_target_properties(dl PROPERTIES DEFINE_SYMBOL "")
12
13# set shared mode for compiling library and propagate mode to cmake clients
14if (BUILD_SHARED_LIBS)
15 target_compile_definitions(dl PUBLIC DLFCN_WIN32_SHARED)
16endif (BUILD_SHARED_LIBS)
17
13install (TARGETS dl EXPORT dlfcn-win32-targets 18install (TARGETS dl EXPORT dlfcn-win32-targets
14 RUNTIME DESTINATION bin 19 RUNTIME DESTINATION bin
15 LIBRARY DESTINATION lib${LIB_SUFFIX} 20 LIBRARY DESTINATION lib${LIB_SUFFIX}
diff --git a/src/dlfcn.c b/src/dlfcn.c
index 3251661..5dd1ccf 100644
--- a/src/dlfcn.c
+++ b/src/dlfcn.c
@@ -3,6 +3,7 @@
3 * Copyright (c) 2007 Ramiro Polla 3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2015 Tiancheng "Timothy" Gu 4 * Copyright (c) 2015 Tiancheng "Timothy" Gu
5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com> 5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
6 * Copyright (c) 2020 Ralf Habacker <ralf.habacker@freenet.de>
6 * 7 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal 9 * of this software and associated documentation files (the "Software"), to deal
@@ -45,7 +46,7 @@
45#endif 46#endif
46#endif 47#endif
47 48
48#ifdef SHARED 49#ifdef DLFCN_WIN32_SHARED
49#define DLFCN_WIN32_EXPORTS 50#define DLFCN_WIN32_EXPORTS
50#endif 51#endif
51#include "dlfcn.h" 52#include "dlfcn.h"
@@ -222,6 +223,7 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb,
222 return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); 223 return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
223} 224}
224 225
226DLFCN_EXPORT
225void *dlopen( const char *file, int mode ) 227void *dlopen( const char *file, int mode )
226{ 228{
227 HMODULE hModule; 229 HMODULE hModule;
@@ -329,6 +331,7 @@ void *dlopen( const char *file, int mode )
329 return (void *) hModule; 331 return (void *) hModule;
330} 332}
331 333
334DLFCN_EXPORT
332int dlclose( void *handle ) 335int dlclose( void *handle )
333{ 336{
334 HMODULE hModule = (HMODULE) handle; 337 HMODULE hModule = (HMODULE) handle;
@@ -353,6 +356,7 @@ int dlclose( void *handle )
353} 356}
354 357
355__declspec(noinline) /* Needed for _ReturnAddress() */ 358__declspec(noinline) /* Needed for _ReturnAddress() */
359DLFCN_EXPORT
356void *dlsym( void *handle, const char *name ) 360void *dlsym( void *handle, const char *name )
357{ 361{
358 FARPROC symbol; 362 FARPROC symbol;
@@ -460,6 +464,7 @@ end:
460 return *(void **) (&symbol); 464 return *(void **) (&symbol);
461} 465}
462 466
467DLFCN_EXPORT
463char *dlerror( void ) 468char *dlerror( void )
464{ 469{
465 /* If this is the second consecutive call to dlerror, return NULL */ 470 /* If this is the second consecutive call to dlerror, return NULL */
@@ -474,7 +479,212 @@ char *dlerror( void )
474 return error_buffer; 479 return error_buffer;
475} 480}
476 481
477#ifdef SHARED 482/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
483 * for details */
484
485/* Get specific image section */
486static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size )
487{
488 IMAGE_DOS_HEADER *dosHeader;
489 IMAGE_OPTIONAL_HEADER *optionalHeader;
490
491 dosHeader = (IMAGE_DOS_HEADER *) module;
492
493 if( dosHeader->e_magic != 0x5A4D )
494 return FALSE;
495
496 optionalHeader = (IMAGE_OPTIONAL_HEADER *) ( (BYTE *) module + dosHeader->e_lfanew + 24 );
497
498 if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC )
499 return FALSE;
500
501 if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
502 return FALSE;
503
504 if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 )
505 return FALSE;
506
507 if( size != NULL )
508 *size = optionalHeader->DataDirectory[index].Size;
509
510 *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress );
511
512 return TRUE;
513}
514
515/* Return symbol name for a given address */
516static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address )
517{
518 int i;
519 void *candidateAddr = NULL;
520 const char *candidateName = NULL;
521 BYTE *base = (BYTE *) module; /* Required to have correct calculations */
522
523 for( i = 0; iid[i].Characteristics != 0 && iid[i].FirstThunk != 0; i++ )
524 {
525 IMAGE_THUNK_DATA *thunkILT = (IMAGE_THUNK_DATA *)( base + iid[i].Characteristics );
526 IMAGE_THUNK_DATA *thunkIAT = (IMAGE_THUNK_DATA *)( base + iid[i].FirstThunk );
527
528 for( ; thunkILT->u1.AddressOfData != 0; thunkILT++, thunkIAT++ )
529 {
530 IMAGE_IMPORT_BY_NAME *nameData;
531
532 if( IMAGE_SNAP_BY_ORDINAL( thunkILT->u1.Ordinal ) )
533 continue;
534
535 if( (void *) thunkIAT->u1.Function > addr || candidateAddr >= (void *) thunkIAT->u1.Function )
536 continue;
537
538 candidateAddr = (void *) thunkIAT->u1.Function;
539 nameData = (IMAGE_IMPORT_BY_NAME *)( base + (ULONG_PTR) thunkILT->u1.AddressOfData );
540 candidateName = (const char *) nameData->Name;
541 }
542 }
543
544 *func_address = candidateAddr;
545 return candidateName;
546}
547
548static BOOL is_valid_address( void *addr )
549{
550 MEMORY_BASIC_INFORMATION info;
551 SIZE_T result;
552
553 if( addr == NULL )
554 return FALSE;
555
556 /* check valid pointer */
557 result = VirtualQuery( addr, &info, sizeof( info ) );
558
559 if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS )
560 return FALSE;
561
562 return TRUE;
563}
564
565/* Return state if address points to an import thunk
566 *
567 * An import thunk is setup with a 'jmp' instruction followed by an
568 * absolute address (32bit) or relative offset (64bit) pointing into
569 * the import address table (iat), which is partially maintained by
570 * the runtime linker.
571 */
572static BOOL is_import_thunk( void *addr )
573{
574 return *(short *) addr == 0x25ff ? TRUE : FALSE;
575}
576
577/* Return adress from the import address table (iat),
578 * if the original address points to a thunk table entry.
579 */
580static void *get_address_from_import_address_table( void *iat, DWORD iat_size, void *addr )
581{
582 BYTE *thkp = (BYTE *) addr;
583 /* Get offset from thunk table (after instruction 0xff 0x25)
584 * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00
585 */
586 ULONG offset = *(ULONG *)( thkp + 2 );
587#ifdef _WIN64
588 /* On 64 bit the offset is relative
589 * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery>
590 * And can be also negative (MSVC in WDK)
591 * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060
592 * So cast to signed LONG type
593 */
594 BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset );
595#else
596 /* On 32 bit the offset is absolute
597 * 4019b4: ff 25 90 71 40 00 jmp *0x40719
598 */
599 BYTE *ptr = (BYTE *) offset;
600#endif
601
602 if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size )
603 return NULL;
604
605 return *(void **) ptr;
606}
607
608/* Holds module filename */
609static char module_filename[2*MAX_PATH];
610
611static BOOL fill_module_info( void *addr, Dl_info *info )
612{
613 HMODULE hModule;
614 DWORD dwSize;
615
616 if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL )
617 return FALSE;
618
619 dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) );
620
621 if( dwSize == 0 || dwSize == sizeof( module_filename ) )
622 return FALSE;
623
624 info->dli_fbase = (void *) hModule;
625 info->dli_fname = module_filename;
626
627 return TRUE;
628}
629
630DLFCN_EXPORT
631int dladdr( void *addr, Dl_info *info )
632{
633 void *realAddr, *funcAddress = 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;
644
645 if( !is_valid_address( addr ) )
646 return 0;
647
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 ) )
654 {
655 void *iat;
656 void *iatAddr = NULL;
657 DWORD iatSize = 0;
658
659 if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) )
660 {
661 /* Fallback for cases where the iat is not defined,
662 * for example i586-mingw32msvc-gcc */
663 if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 )
664 return 0;
665
666 iat = (void *)( (BYTE *) hModule + iid->FirstThunk );
667 /* We assume that in this case iid and iat's are in linear order */
668 iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid );
669 }
670
671 iatAddr = get_address_from_import_address_table( iat, iatSize, addr );
672 if( iatAddr == NULL )
673 return 0;
674
675 realAddr = iatAddr;
676 }
677
678 if( !fill_module_info( realAddr, info ) )
679 return 0;
680
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;
685}
686
687#ifdef DLFCN_WIN32_SHARED
478BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) 688BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
479{ 689{
480 (void) hinstDLL; 690 (void) hinstDLL;
diff --git a/src/dlfcn.h b/src/dlfcn.h
index 9ddbba3..164216f 100644
--- a/src/dlfcn.h
+++ b/src/dlfcn.h
@@ -28,9 +28,13 @@
28extern "C" { 28extern "C" {
29#endif 29#endif
30 30
31#if defined(DLFCN_WIN32_SHARED)
31#if defined(DLFCN_WIN32_EXPORTS) 32#if defined(DLFCN_WIN32_EXPORTS)
32# define DLFCN_EXPORT __declspec(dllexport) 33# define DLFCN_EXPORT __declspec(dllexport)
33#else 34#else
35# define DLFCN_EXPORT __declspec(dllimport)
36#endif
37#else
34# define DLFCN_EXPORT 38# define DLFCN_EXPORT
35#endif 39#endif
36 40
@@ -59,6 +63,15 @@ extern "C" {
59/* Specifies the next object after this one that defines name. */ 63/* Specifies the next object after this one that defines name. */
60#define RTLD_NEXT ((void *)-1) 64#define RTLD_NEXT ((void *)-1)
61 65
66/* Structure filled in by dladdr() */
67typedef struct dl_info
68{
69 const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */
70 void *dli_fbase; /* Load address of that object */
71 const char *dli_sname; /* Name of nearest lower symbol */
72 void *dli_saddr; /* Exact value of nearest symbol */
73} Dl_info;
74
62/* Open a symbol table handle. */ 75/* Open a symbol table handle. */
63DLFCN_EXPORT void *dlopen(const char *file, int mode); 76DLFCN_EXPORT void *dlopen(const char *file, int mode);
64 77
@@ -71,6 +84,9 @@ DLFCN_EXPORT void *dlsym(void *handle, const char *name);
71/* Get diagnostic information. */ 84/* Get diagnostic information. */
72DLFCN_EXPORT char *dlerror(void); 85DLFCN_EXPORT char *dlerror(void);
73 86
87/* Translate address to symbolic information (no POSIX standard) */
88DLFCN_EXPORT int dladdr(void *addr, Dl_info *info);
89
74#ifdef __cplusplus 90#ifdef __cplusplus
75} 91}
76#endif 92#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5fc6c44..f0871e5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -9,9 +9,17 @@ target_link_libraries(testdll2 dl)
9 9
10add_library(testdll3 SHARED testdll3.c) 10add_library(testdll3 SHARED testdll3.c)
11set_target_properties(testdll3 PROPERTIES PREFIX "") 11set_target_properties(testdll3 PROPERTIES PREFIX "")
12add_executable(test-dladdr test-dladdr.c)
13target_link_libraries(test-dladdr dl)
14if(UNIX)
15 set_target_properties(test-dladdr PROPERTIES COMPILE_FLAGS "-Wl,--export-dynamic -fpie")
16endif()
17
18install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin)
12 19
13add_executable(t_dlfcn test.c) 20add_executable(t_dlfcn test.c)
14target_link_libraries(t_dlfcn dl) 21target_link_libraries(t_dlfcn dl)
15if(RUN_TESTS) 22if(RUN_TESTS)
16 add_test(NAME t_dlfcn COMMAND ${WRAPPER} $<TARGET_FILE:t_dlfcn> WORKING_DIRECTORY $<TARGET_FILE_DIR:t_dlfcn>) 23 add_test(NAME t_dlfcn COMMAND ${WRAPPER} $<TARGET_FILE:t_dlfcn> WORKING_DIRECTORY $<TARGET_FILE_DIR:t_dlfcn>)
24 add_test(NAME test-dladdr COMMAND ${WRAPPER} $<TARGET_FILE:test-dladdr> WORKING_DIRECTORY $<TARGET_FILE_DIR:test-dladdr>)
17endif() 25endif()
diff --git a/tests/test-dladdr.c b/tests/test-dladdr.c
new file mode 100644
index 0000000..57914cb
--- /dev/null
+++ b/tests/test-dladdr.c
@@ -0,0 +1,184 @@
1/* On Unix like os compile with "-Wl,--export-dynamic -fpie" (default with cmake) */
2
3/* required for non Windows builds, must be set in front of the first system include */
4#define _GNU_SOURCE
5
6#include <dlfcn.h>
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12static int verbose = 0;
13
14typedef enum {
15 Pass = 1,
16 PassWithoutSymbol = 2,
17 PassWithDifferentAddress = 3,
18 Fail = 0,
19 NoInfo = -1,
20} ExpectedResult;
21
22typedef void (* func) (void);
23
24static void print_dl_info( Dl_info *info, char *prefix, char *suffix )
25{
26 printf( "%sfilename: %s base: %p symbol name: '%s' addr: %p%s", prefix, info->dli_fname, info->dli_fbase, info->dli_sname, info->dli_saddr, suffix );
27}
28
29/**
30 * @brief check information returned by dladdr
31 * @param hint text describing what to test
32 * @param addr address to check
33 * @param addrsym
34 * @param expected check against expected result
35 * @return 0 check passed
36 * @return 1 check failed
37 */
38static int check_dladdr( const char *hint, void *addr, char *addrsym, ExpectedResult expected_result )
39{
40 Dl_info info;
41 int result = dladdr( addr, &info );
42 int passed = 0;
43 if (!result)
44 {
45 passed = expected_result == NoInfo || expected_result == Fail;
46 }
47 else
48 {
49 int sym_match = info.dli_sname && strcmp( addrsym, info.dli_sname ) == 0;
50 int addr_match = addr == info.dli_saddr;
51 passed = (expected_result == Pass && sym_match && addr_match)
52 || (expected_result == PassWithoutSymbol && addr_match && !info.dli_sname)
53 || (expected_result == PassWithDifferentAddress && sym_match && !addr_match)
54 || (expected_result == Fail && (!sym_match || !addr_match));
55 }
56 printf( "checking '%s' - address %p which should have symbol '%s' -> %s%s", hint, addr, addrsym, passed ? "passed" : "failed", verbose || !passed ? " " : "\n" );
57 if( verbose || !passed )
58 {
59 if( !result )
60 printf( "(could not get symbol information for address %p)\n", addr );
61 else
62 print_dl_info( &info, "(", ")\n");
63 }
64 return !passed;
65}
66
67#ifdef _WIN32
68/**
69 * @brief check address from a symbol located in a shared lilbrary
70 * @param hint text describing what to test
71 * @param libname libray to get the address from
72 * @param addrsym symbol to get the address for
73 * @param should_match result should match the given values
74 * @return 0 check passed
75 * @return 1 check failed
76 * @return 2 failed to open library
77 * @return 3 failed to get symbol address
78 */
79static int check_dladdr_by_dlopen( const char *hint, char *libname, char *sym, int should_match )
80{
81 void *library = NULL;
82 void *addr = NULL;
83 int result;
84
85 library = dlopen( libname, RTLD_GLOBAL );
86 if ( library == NULL )
87 {
88 fprintf( stderr, "could not open '%s'\n", libname );
89 return 2;
90 }
91
92 addr = dlsym( library, sym );
93 if ( !addr ) {
94 fprintf( stderr, "could not get address from library '%s' for symbol '%s'\n", libname, sym );
95 return 3;
96 }
97
98 result = check_dladdr( hint, addr, sym, should_match );
99 dlclose( library );
100
101 return result;
102}
103#endif
104
105#ifdef _WIN32
106#include <windows.h>
107#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
108/* hide warning "reclared without 'dllimport' attribute" */
109#pragma GCC diagnostic push
110#pragma GCC diagnostic ignored "-Wattributes"
111#elif defined(_MSC_VER)
112/* disable warning C4273 inconsistent dll linkage */
113#pragma warning(push)
114#pragma warning(disable: 4273)
115#endif
116/*
117 * Windows API functions decorated with WINBASEAPI are imported from iat.
118 * For testing force linking by import thunk for the following functions
119 */
120HMODULE WINAPI GetModuleHandleA (LPCSTR lpModuleName);
121SIZE_T WINAPI VirtualQuery (LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
122/* force linking by iat */
123/* WINBASEAPI, which is normally used here, can be overriden by compiler or application, so we cannot use it */
124__declspec(dllimport) HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
125__declspec(dllimport) int __cdecl atoi(const char *_Str);
126
127#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
128#pragma GCC diagnostic pop
129#elif defined(_MSC_VER)
130#pragma warning(pop)
131#endif
132#endif
133
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
147
148int main(int argc, char **argv)
149{
150 /* points to non reachable address */
151 unsigned char zero_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 };
152 /* points to executable base */
153 unsigned char invalid_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x40, 0x00 };
154 /* no import thunk */
155 unsigned char no_import_thunk[6] = { 0xFF, 0x26, 0x00, 0x00, 0x40, 0x00 };
156 int result = 0;
157 UNUSED(argv);
158
159 if (argc == 2)
160 verbose = 1;
161
162 result = check_dladdr( "null pointer", (void*)0, NULL , NoInfo);
163 result |= check_dladdr( "invalid pointer", (void*)0x125, NULL , NoInfo);
164 result |= check_dladdr( "function from dl library", (void*)dladdr, "dladdr" , PassOnSharedBuild );
165 result |= check_dladdr( "function from dl library", (void*)dlopen, "dlopen", PassOnSharedBuild );
166 result |= check_dladdr( "function from glibc/msvcrt library", (void*)atoi, "atoi", Pass );
167 result |= check_dladdr( "function from executable", (void*)main, "main", FailOnWin );
168 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 );
170 result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo );
171 result |= check_dladdr( "invalid address from import thunk", invalid_thunk_address, "", NoInfo );
172 result |= check_dladdr( "no import thunk", no_import_thunk, "", NoInfo );
173
174#ifdef _WIN32
175 result |= check_dladdr( "last entry in iat", (void*)VirtualQuery, "VirtualQuery", PassWithDifferentAddress );
176
177 result |= check_dladdr ( "address through import thunk", (void*)GetModuleHandleA, "GetModuleHandleA", PassWithDifferentAddress );
178 result |= check_dladdr_by_dlopen( "address by dlsym", "kernel32.dll", "GetModuleHandleA", Pass );
179
180 result |= check_dladdr ( "address by image allocation table", (void*)LoadLibraryExA, "LoadLibraryExA", Pass );
181 result |= check_dladdr_by_dlopen( "address by dlsym", "kernel32.dll", "LoadLibraryExA", Pass );
182#endif
183 return result;
184}