diff options
author | Ralf Habacker <ralf.habacker@freenet.de> | 2020-12-11 14:32:52 +0100 |
---|---|---|
committer | Ralf Habacker <ralf.habacker@freenet.de> | 2021-01-17 12:51:39 +0100 |
commit | 0ea2334d46ca84c1a27bd086700f620a06401f94 (patch) | |
tree | 89e768d6c77492dee9cf6b520d562b8e35a7cee5 /tests | |
parent | 06ffb62a31f8986d1cda864bb8c3a8967d5a65fa (diff) | |
download | dlfcn-win32-0ea2334d46ca84c1a27bd086700f620a06401f94.tar.gz dlfcn-win32-0ea2334d46ca84c1a27bd086700f620a06401f94.tar.bz2 dlfcn-win32-0ea2334d46ca84c1a27bd086700f620a06401f94.zip |
Add function dladdr() and associated test application test-dladdr
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 8 | ||||
-rw-r--r-- | tests/test-dladdr.c | 184 |
2 files changed, 192 insertions, 0 deletions
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 | ||
10 | add_library(testdll3 SHARED testdll3.c) | 10 | add_library(testdll3 SHARED testdll3.c) |
11 | set_target_properties(testdll3 PROPERTIES PREFIX "") | 11 | set_target_properties(testdll3 PROPERTIES PREFIX "") |
12 | add_executable(test-dladdr test-dladdr.c) | ||
13 | target_link_libraries(test-dladdr dl) | ||
14 | if(UNIX) | ||
15 | set_target_properties(test-dladdr PROPERTIES COMPILE_FLAGS "-Wl,--export-dynamic -fpie") | ||
16 | endif() | ||
17 | |||
18 | install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) | ||
12 | 19 | ||
13 | add_executable(t_dlfcn test.c) | 20 | add_executable(t_dlfcn test.c) |
14 | target_link_libraries(t_dlfcn dl) | 21 | target_link_libraries(t_dlfcn dl) |
15 | if(RUN_TESTS) | 22 | if(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>) | ||
17 | endif() | 25 | endif() |
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 | |||
12 | static int verbose = 0; | ||
13 | |||
14 | typedef enum { | ||
15 | Pass = 1, | ||
16 | PassWithoutSymbol = 2, | ||
17 | PassWithDifferentAddress = 3, | ||
18 | Fail = 0, | ||
19 | NoInfo = -1, | ||
20 | } ExpectedResult; | ||
21 | |||
22 | typedef void (* func) (void); | ||
23 | |||
24 | static 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 | */ | ||
38 | static 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 | */ | ||
79 | static 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 | */ | ||
120 | HMODULE WINAPI GetModuleHandleA (LPCSTR lpModuleName); | ||
121 | SIZE_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 | |||
148 | int 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 | } | ||