NEURON
dlfcn.c
Go to the documentation of this file.
1 /*
2  * dlfcn-win32
3  * Copyright (c) 2007 Ramiro Polla
4  * Copyright (c) 2015 Tiancheng "Timothy" Gu
5  * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
6  * Copyright (c) 2020 Ralf Habacker <ralf.habacker@freenet.de>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 /*
28  * From https://github.com/dlfcn-win32/dlfcn-win32
29  * Filtered with dos2unix and clang-format.
30  */
31 
32 #ifdef _DEBUG
33 #define _CRTDBG_MAP_ALLOC
34 #include <stdlib.h>
35 #include <crtdbg.h>
36 #endif
37 #include <windows.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 
41 /* Older versions do not have this type */
42 #if _WIN32_WINNT < 0x0500
43 typedef ULONG ULONG_PTR;
44 #endif
45 
46 /* Older SDK versions do not have these macros */
47 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
48 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4
49 #endif
50 #ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
51 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2
52 #endif
53 
54 #ifdef _MSC_VER
55 /* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
56 #pragma intrinsic(_ReturnAddress)
57 #else
58 /* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
59 #ifndef _ReturnAddress
60 #define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0)))
61 #endif
62 #endif
63 
64 #ifdef DLFCN_WIN32_SHARED
65 #define DLFCN_WIN32_EXPORTS
66 #endif
67 #include "dlfcn.h"
68 
69 #if defined(_MSC_VER) && _MSC_VER >= 1300
70 /* https://docs.microsoft.com/en-us/cpp/cpp/noinline */
71 #define DLFCN_NOINLINE __declspec(noinline)
72 #elif defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
73 /* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */
74 #define DLFCN_NOINLINE __attribute__((noinline))
75 #else
76 #define DLFCN_NOINLINE
77 #endif
78 
79 /* Note:
80  * MSDN says these functions are not thread-safe. We make no efforts to have
81  * any kind of thread safety.
82  */
83 
84 typedef struct local_object {
85  HMODULE hModule;
87  struct local_object* next;
89 
91 
92 /* These functions implement a double linked list for the local objects. */
93 static local_object* local_search(HMODULE hModule) {
94  local_object* pobject;
95 
96  if (hModule == NULL)
97  return NULL;
98 
99  for (pobject = &first_object; pobject; pobject = pobject->next)
100  if (pobject->hModule == hModule)
101  return pobject;
102 
103  return NULL;
104 }
105 
106 static BOOL local_add(HMODULE hModule) {
107  local_object* pobject;
108  local_object* nobject;
109 
110  if (hModule == NULL)
111  return TRUE;
112 
113  pobject = local_search(hModule);
114 
115  /* Do not add object again if it's already on the list */
116  if (pobject != NULL)
117  return TRUE;
118 
119  for (pobject = &first_object; pobject->next; pobject = pobject->next)
120  ;
121 
122  nobject = (local_object*) malloc(sizeof(local_object));
123 
124  if (!nobject)
125  return FALSE;
126 
127  pobject->next = nobject;
128  nobject->next = NULL;
129  nobject->previous = pobject;
130  nobject->hModule = hModule;
131 
132  return TRUE;
133 }
134 
135 static void local_rem(HMODULE hModule) {
136  local_object* pobject;
137 
138  if (hModule == NULL)
139  return;
140 
141  pobject = local_search(hModule);
142 
143  if (pobject == NULL)
144  return;
145 
146  if (pobject->next)
147  pobject->next->previous = pobject->previous;
148  if (pobject->previous)
149  pobject->previous->next = pobject->next;
150 
151  free(pobject);
152 }
153 
154 /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
155  * static buffer.
156  * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
157  * the limit.
158  */
159 static char error_buffer[65535];
160 static BOOL error_occurred;
161 
162 static void save_err_str(const char* str, DWORD dwMessageId) {
163  DWORD ret;
164  size_t pos, len;
165 
166  len = strlen(str);
167  if (len > sizeof(error_buffer) - 5)
168  len = sizeof(error_buffer) - 5;
169 
170  /* Format error message to:
171  * "<argument to function that failed>": <Windows localized error message>
172  */
173  pos = 0;
174  error_buffer[pos++] = '"';
175  memcpy(error_buffer + pos, str, len);
176  pos += len;
177  error_buffer[pos++] = '"';
178  error_buffer[pos++] = ':';
179  error_buffer[pos++] = ' ';
180 
181  ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
182  NULL,
183  dwMessageId,
184  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
185  error_buffer + pos,
186  (DWORD) (sizeof(error_buffer) - pos),
187  NULL);
188  pos += ret;
189 
190  /* When FormatMessageA() fails it returns zero and does not touch buffer
191  * so add trailing null byte */
192  if (ret == 0)
193  error_buffer[pos] = '\0';
194 
195  if (pos > 1) {
196  /* POSIX says the string must not have trailing <newline> */
197  if (error_buffer[pos - 2] == '\r' && error_buffer[pos - 1] == '\n')
198  error_buffer[pos - 2] = '\0';
199  }
200 
202 }
203 
204 static void save_err_ptr_str(const void* ptr, DWORD dwMessageId) {
205  char ptr_buf[2 + 2 * sizeof(ptr) + 1];
206  char num;
207  size_t i;
208 
209  ptr_buf[0] = '0';
210  ptr_buf[1] = 'x';
211 
212  for (i = 0; i < 2 * sizeof(ptr); i++) {
213  num = (char) ((((ULONG_PTR) ptr) >> (8 * sizeof(ptr) - 4 * (i + 1))) & 0xF);
214  ptr_buf[2 + i] = num + ((num < 0xA) ? '0' : ('A' - 0xA));
215  }
216 
217  ptr_buf[2 + 2 * sizeof(ptr)] = 0;
218 
219  save_err_str(ptr_buf, dwMessageId);
220 }
221 
222 static UINT MySetErrorMode(UINT uMode) {
223  static BOOL(WINAPI * SetThreadErrorModePtr)(DWORD, DWORD*) = NULL;
224  static BOOL failed = FALSE;
225  HMODULE kernel32;
226  DWORD oldMode;
227 
228  if (!failed && SetThreadErrorModePtr == NULL) {
229  kernel32 = GetModuleHandleA("Kernel32.dll");
230  if (kernel32 != NULL)
231  SetThreadErrorModePtr = (BOOL(WINAPI*)(DWORD, DWORD*))(
232  LPVOID) GetProcAddress(kernel32, "SetThreadErrorMode");
233  if (SetThreadErrorModePtr == NULL)
234  failed = TRUE;
235  }
236 
237  if (!failed) {
238  if (!SetThreadErrorModePtr(uMode, &oldMode))
239  return 0;
240  else
241  return oldMode;
242  } else {
243  return SetErrorMode(uMode);
244  }
245 }
246 
247 static HMODULE MyGetModuleHandleFromAddress(const void* addr) {
248  static BOOL(WINAPI * GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE*) = NULL;
249  static BOOL failed = FALSE;
250  HMODULE kernel32;
251  HMODULE hModule;
252  MEMORY_BASIC_INFORMATION info;
253  SIZE_T sLen;
254 
255  if (!failed && GetModuleHandleExAPtr == NULL) {
256  kernel32 = GetModuleHandleA("Kernel32.dll");
257  if (kernel32 != NULL)
258  GetModuleHandleExAPtr = (BOOL(WINAPI*)(DWORD, LPCSTR, HMODULE*))(
259  LPVOID) GetProcAddress(kernel32, "GetModuleHandleExA");
260  if (GetModuleHandleExAPtr == NULL)
261  failed = TRUE;
262  }
263 
264  if (!failed) {
265  /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */
266  if (!GetModuleHandleExAPtr(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
268  addr,
269  &hModule))
270  return NULL;
271  } else {
272  /* To get HMODULE from address use undocumented hack from
273  * https://stackoverflow.com/a/2396380 The HMODULE of a DLL is the same value as the
274  * module's base address.
275  */
276  sLen = VirtualQuery(addr, &info, sizeof(info));
277  if (sLen != sizeof(info))
278  return NULL;
279  hModule = (HMODULE) info.AllocationBase;
280  }
281 
282  return hModule;
283 }
284 
285 /* Load Psapi.dll at runtime, this avoids linking caveat */
286 static BOOL MyEnumProcessModules(HANDLE hProcess,
287  HMODULE* lphModule,
288  DWORD cb,
289  LPDWORD lpcbNeeded) {
290  static BOOL(WINAPI * EnumProcessModulesPtr)(HANDLE, HMODULE*, DWORD, LPDWORD) = NULL;
291  static BOOL failed = FALSE;
292  UINT uMode;
293  HMODULE psapi;
294 
295  if (failed)
296  return FALSE;
297 
298  if (EnumProcessModulesPtr == NULL) {
299  /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always
300  * pre-loaded */
301  psapi = GetModuleHandleA("Kernel32.dll");
302  if (psapi != NULL)
303  EnumProcessModulesPtr = (BOOL(WINAPI*)(HANDLE, HMODULE*, DWORD, LPDWORD))(
304  LPVOID) GetProcAddress(psapi, "K32EnumProcessModules");
305 
306  /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be
307  * loaded */
308  if (EnumProcessModulesPtr == NULL) {
309  /* Do not let Windows display the critical-error-handler message box */
310  uMode = MySetErrorMode(SEM_FAILCRITICALERRORS);
311  psapi = LoadLibraryA("Psapi.dll");
312  if (psapi != NULL) {
313  EnumProcessModulesPtr = (BOOL(WINAPI*)(HANDLE, HMODULE*, DWORD, LPDWORD))(
314  LPVOID) GetProcAddress(psapi, "EnumProcessModules");
315  if (EnumProcessModulesPtr == NULL)
316  FreeLibrary(psapi);
317  }
318  MySetErrorMode(uMode);
319  }
320 
321  if (EnumProcessModulesPtr == NULL) {
322  failed = TRUE;
323  return FALSE;
324  }
325  }
326 
327  return EnumProcessModulesPtr(hProcess, lphModule, cb, lpcbNeeded);
328 }
329 
331 void* dlopen(const char* file, int mode) {
332  HMODULE hModule;
333  UINT uMode;
334 
336 
337  /* Do not let Windows display the critical-error-handler message box */
338  uMode = MySetErrorMode(SEM_FAILCRITICALERRORS);
339 
340  if (file == NULL) {
341  /* POSIX says that if the value of file is NULL, a handle on a global
342  * symbol object must be provided. That object must be able to access
343  * all symbols from the original program file, and any objects loaded
344  * with the RTLD_GLOBAL flag.
345  * The return value from GetModuleHandle( ) allows us to retrieve
346  * symbols only from the original program file. EnumProcessModules() is
347  * used to access symbols from other libraries. For objects loaded
348  * with the RTLD_LOCAL flag, we create our own list later on. They are
349  * excluded from EnumProcessModules() iteration.
350  */
351  hModule = GetModuleHandle(NULL);
352 
353  if (!hModule)
354  save_err_str("(null)", GetLastError());
355  } else {
356  HANDLE hCurrentProc;
357  DWORD dwProcModsBefore, dwProcModsAfter;
358  char lpFileName[MAX_PATH];
359  size_t i, len;
360 
361  len = strlen(file);
362 
363  if (len >= sizeof(lpFileName)) {
364  save_err_str(file, ERROR_FILENAME_EXCED_RANGE);
365  hModule = NULL;
366  } else {
367  /* MSDN says backslashes *must* be used instead of forward slashes. */
368  for (i = 0; i < len; i++) {
369  if (file[i] == '/')
370  lpFileName[i] = '\\';
371  else
372  lpFileName[i] = file[i];
373  }
374  lpFileName[len] = '\0';
375 
376  hCurrentProc = GetCurrentProcess();
377 
378  if (MyEnumProcessModules(hCurrentProc, NULL, 0, &dwProcModsBefore) == 0)
379  dwProcModsBefore = 0;
380 
381  /* POSIX says the search path is implementation-defined.
382  * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
383  * to UNIX's search paths (start with system folders instead of current
384  * folder).
385  */
386  hModule = LoadLibraryExA(lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
387 
388  if (!hModule) {
389  save_err_str(lpFileName, GetLastError());
390  } else {
391  if (MyEnumProcessModules(hCurrentProc, NULL, 0, &dwProcModsAfter) == 0)
392  dwProcModsAfter = 0;
393 
394  /* If the object was loaded with RTLD_LOCAL, add it to list of local
395  * objects, so that its symbols cannot be retrieved even if the handle for
396  * the original program file is passed. POSIX says that if the same
397  * file is specified in multiple invocations, and any of them are
398  * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
399  * symbols will remain global. If number of loaded modules was not
400  * changed after calling LoadLibraryEx(), it means that library was
401  * already loaded.
402  */
403  if ((mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter) {
404  if (!local_add(hModule)) {
405  save_err_str(lpFileName, ERROR_NOT_ENOUGH_MEMORY);
406  FreeLibrary(hModule);
407  hModule = NULL;
408  }
409  } else if (!(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter) {
411  }
412  }
413  }
414  }
415 
416  /* Return to previous state of the error-mode bit flags. */
417  MySetErrorMode(uMode);
418 
419  return (void*) hModule;
420 }
421 
423 int dlclose(void* handle) {
424  HMODULE hModule = (HMODULE) handle;
425  BOOL ret;
426 
428 
429  ret = FreeLibrary(hModule);
430 
431  /* If the object was loaded with RTLD_LOCAL, remove it from list of local
432  * objects.
433  */
434  if (ret)
436  else
437  save_err_ptr_str(handle, GetLastError());
438 
439  /* dlclose's return value in inverted in relation to FreeLibrary's. */
440  ret = !ret;
441 
442  return (int) ret;
443 }
444 
445 DLFCN_NOINLINE /* Needed for _ReturnAddress() */
446  DLFCN_EXPORT void*
447  dlsym(void* handle, const char* name) {
448  FARPROC symbol;
449  HMODULE hCaller;
450  HMODULE hModule;
451  DWORD dwMessageId;
452 
454 
455  symbol = NULL;
456  hCaller = NULL;
457  hModule = GetModuleHandle(NULL);
458  dwMessageId = 0;
459 
460  if (handle == RTLD_DEFAULT) {
461  /* The symbol lookup happens in the normal global scope; that is,
462  * a search for a symbol using this handle would find the same
463  * definition as a direct use of this symbol in the program code.
464  * So use same lookup procedure as when filename is NULL.
465  */
466  handle = hModule;
467  } else if (handle == RTLD_NEXT) {
468  /* Specifies the next object after this one that defines name.
469  * This one refers to the object containing the invocation of dlsym().
470  * The next object is the one found upon the application of a load
471  * order symbol resolution algorithm. To get caller function of dlsym()
472  * use _ReturnAddress() intrinsic. To get HMODULE of caller function
473  * use MyGetModuleHandleFromAddress() which calls either standard
474  * GetModuleHandleExA() function or hack via VirtualQuery().
475  */
477 
478  if (hCaller == NULL) {
479  dwMessageId = ERROR_INVALID_PARAMETER;
480  goto end;
481  }
482  }
483 
484  if (handle != RTLD_NEXT) {
485  symbol = GetProcAddress((HMODULE) handle, name);
486 
487  if (symbol != NULL)
488  goto end;
489  }
490 
491  /* If the handle for the original program file is passed, also search
492  * in all globally loaded objects.
493  */
494 
495  if (hModule == handle || handle == RTLD_NEXT) {
496  HANDLE hCurrentProc;
497  HMODULE* modules;
498  DWORD cbNeeded;
499  DWORD dwSize;
500  size_t i;
501 
502  hCurrentProc = GetCurrentProcess();
503 
504  /* GetModuleHandle( NULL ) only returns the current program file. So
505  * if we want to get ALL loaded module including those in linked DLLs,
506  * we have to use EnumProcessModules( ).
507  */
508  if (MyEnumProcessModules(hCurrentProc, NULL, 0, &dwSize) != 0) {
509  modules = malloc(dwSize);
510  if (modules) {
511  if (MyEnumProcessModules(hCurrentProc, modules, dwSize, &cbNeeded) != 0 &&
512  dwSize == cbNeeded) {
513  for (i = 0; i < dwSize / sizeof(HMODULE); i++) {
514  if (handle == RTLD_NEXT && hCaller) {
515  /* Next modules can be used for RTLD_NEXT */
516  if (hCaller == modules[i])
517  hCaller = NULL;
518  continue;
519  }
520  if (local_search(modules[i]))
521  continue;
522  symbol = GetProcAddress(modules[i], name);
523  if (symbol != NULL) {
524  free(modules);
525  goto end;
526  }
527  }
528  }
529  free(modules);
530  } else {
531  dwMessageId = ERROR_NOT_ENOUGH_MEMORY;
532  goto end;
533  }
534  }
535  }
536 
537 end:
538  if (symbol == NULL) {
539  if (!dwMessageId)
540  dwMessageId = ERROR_PROC_NOT_FOUND;
541  save_err_str(name, dwMessageId);
542  }
543 
544  return *(void**) (&symbol);
545 }
546 
548 char* dlerror(void) {
549  /* If this is the second consecutive call to dlerror, return NULL */
550  if (!error_occurred)
551  return NULL;
552 
553  /* POSIX says that invoking dlerror( ) a second time, immediately following
554  * a prior invocation, shall result in NULL being returned.
555  */
557 
558  return error_buffer;
559 }
560 
561 /* See
562  * 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
563  * for details */
564 
565 /* Get specific image section */
566 static BOOL get_image_section(HMODULE module, int index, void** ptr, DWORD* size) {
567  IMAGE_DOS_HEADER* dosHeader;
568  IMAGE_NT_HEADERS* ntHeaders;
569  IMAGE_OPTIONAL_HEADER* optionalHeader;
570 
571  dosHeader = (IMAGE_DOS_HEADER*) module;
572 
573  if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
574  return FALSE;
575 
576  ntHeaders = (IMAGE_NT_HEADERS*) ((BYTE*) dosHeader + dosHeader->e_lfanew);
577 
578  if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
579  return FALSE;
580 
581  optionalHeader = &ntHeaders->OptionalHeader;
582 
583  if (optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
584  return FALSE;
585 
586  if (index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
587  return FALSE;
588 
589  if (optionalHeader->DataDirectory[index].Size == 0 ||
590  optionalHeader->DataDirectory[index].VirtualAddress == 0)
591  return FALSE;
592 
593  if (size != NULL)
594  *size = optionalHeader->DataDirectory[index].Size;
595 
596  *ptr = (void*) ((BYTE*) module + optionalHeader->DataDirectory[index].VirtualAddress);
597 
598  return TRUE;
599 }
600 
601 /* Return symbol name for a given address from export table */
602 static const char* get_export_symbol_name(HMODULE module,
603  IMAGE_EXPORT_DIRECTORY* ied,
604  const void* addr,
605  void** func_address) {
606  DWORD i;
607  void* candidateAddr = NULL;
608  int candidateIndex = -1;
609  BYTE* base = (BYTE*) module;
610  DWORD* functionAddressesOffsets = (DWORD*) (base + ied->AddressOfFunctions);
611  DWORD* functionNamesOffsets = (DWORD*) (base + ied->AddressOfNames);
612  USHORT* functionNameOrdinalsIndexes = (USHORT*) (base + ied->AddressOfNameOrdinals);
613 
614  for (i = 0; i < ied->NumberOfFunctions; i++) {
615  if ((void*) (base + functionAddressesOffsets[i]) > addr ||
616  candidateAddr >= (void*) (base + functionAddressesOffsets[i]))
617  continue;
618 
619  candidateAddr = (void*) (base + functionAddressesOffsets[i]);
620  candidateIndex = i;
621  }
622 
623  if (candidateIndex == -1)
624  return NULL;
625 
626  *func_address = candidateAddr;
627 
628  for (i = 0; i < ied->NumberOfNames; i++) {
629  if (functionNameOrdinalsIndexes[i] == candidateIndex)
630  return (const char*) (base + functionNamesOffsets[i]);
631  }
632 
633  return NULL;
634 }
635 
636 static BOOL is_valid_address(const void* addr) {
637  MEMORY_BASIC_INFORMATION info;
638  SIZE_T result;
639 
640  if (addr == NULL)
641  return FALSE;
642 
643  /* check valid pointer */
644  result = VirtualQuery(addr, &info, sizeof(info));
645 
646  if (result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 ||
647  info.AllocationProtect == PAGE_NOACCESS)
648  return FALSE;
649 
650  return TRUE;
651 }
652 
653 /* Return state if address points to an import thunk
654  *
655  * An import thunk is setup with a 'jmp' instruction followed by an
656  * absolute address (32bit) or relative offset (64bit) pointing into
657  * the import address table (iat), which is partially maintained by
658  * the runtime linker.
659  */
660 static BOOL is_import_thunk(const void* addr) {
661  return *(short*) addr == 0x25ff ? TRUE : FALSE;
662 }
663 
664 /* Return adress from the import address table (iat),
665  * if the original address points to a thunk table entry.
666  */
667 static void* get_address_from_import_address_table(void* iat, DWORD iat_size, const void* addr) {
668  BYTE* thkp = (BYTE*) addr;
669  /* Get offset from thunk table (after instruction 0xff 0x25)
670  * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00
671  */
672  ULONG offset = *(ULONG*) (thkp + 2);
673 #ifdef _WIN64
674  /* On 64 bit the offset is relative
675  * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery>
676  * And can be also negative (MSVC in WDK)
677  * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060
678  * So cast to signed LONG type
679  */
680  BYTE* ptr = (BYTE*) (thkp + 6 + (LONG) offset);
681 #else
682  /* On 32 bit the offset is absolute
683  * 4019b4: ff 25 90 71 40 00 jmp *0x40719
684  */
685  BYTE* ptr = (BYTE*) offset;
686 #endif
687 
688  if (!is_valid_address(ptr) || ptr < (BYTE*) iat || ptr > (BYTE*) iat + iat_size)
689  return NULL;
690 
691  return *(void**) ptr;
692 }
693 
694 /* Holds module filename */
695 static char module_filename[2 * MAX_PATH];
696 
697 static BOOL fill_info(const void* addr, Dl_info* info) {
698  HMODULE hModule;
699  DWORD dwSize;
700  IMAGE_EXPORT_DIRECTORY* ied;
701  void* funcAddress = NULL;
702 
703  /* Get module of the specified address */
705 
706  if (hModule == NULL)
707  return FALSE;
708 
709  dwSize = GetModuleFileNameA(hModule, module_filename, sizeof(module_filename));
710 
711  if (dwSize == 0 || dwSize == sizeof(module_filename))
712  return FALSE;
713 
714  info->dli_fname = module_filename;
715  info->dli_fbase = (void*) hModule;
716 
717  /* Find function name and function address in module's export table */
718  if (get_image_section(hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void**) &ied, NULL))
719  info->dli_sname = get_export_symbol_name(hModule, ied, addr, &funcAddress);
720  else
721  info->dli_sname = NULL;
722 
723  info->dli_saddr = info->dli_sname == NULL ? NULL
724  : funcAddress != NULL ? funcAddress
725  : (void*) addr;
726 
727  return TRUE;
728 }
729 
731 int dladdr(const void* addr, Dl_info* info) {
732  if (info == NULL)
733  return 0;
734 
735  if (!is_valid_address(addr))
736  return 0;
737 
738  if (is_import_thunk(addr)) {
739  void* iat;
740  DWORD iatSize;
741  HMODULE hModule;
742 
743  /* Get module of the import thunk address */
745 
746  if (hModule == NULL)
747  return 0;
748 
749  if (!get_image_section(hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize)) {
750  /* Fallback for cases where the iat is not defined,
751  * for example i586-mingw32msvc-gcc */
752  IMAGE_IMPORT_DESCRIPTOR* iid;
753  DWORD iidSize;
754 
755  if (!get_image_section(hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void**) &iid, &iidSize))
756  return 0;
757 
758  if (iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0)
759  return 0;
760 
761  iat = (void*) ((BYTE*) hModule + iid->FirstThunk);
762  /* We assume that in this case iid and iat's are in linear order */
763  iatSize = iidSize - (DWORD) ((BYTE*) iat - (BYTE*) iid);
764  }
765 
766  addr = get_address_from_import_address_table(iat, iatSize, addr);
767 
768  if (!is_valid_address(addr))
769  return 0;
770  }
771 
772  if (!fill_info(addr, info))
773  return 0;
774 
775  return 1;
776 }
777 
778 #ifdef DLFCN_WIN32_SHARED
779 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
780  (void) hinstDLL;
781  (void) fdwReason;
782  (void) lpvReserved;
783  return TRUE;
784 }
785 #endif
#define i
Definition: md1redef.h:19
static void save_err_ptr_str(const void *ptr, DWORD dwMessageId)
Definition: dlfcn.c:204
static char error_buffer[65535]
Definition: dlfcn.c:159
static void * get_address_from_import_address_table(void *iat, DWORD iat_size, const void *addr)
Definition: dlfcn.c:667
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
Definition: dlfcn.c:48
struct local_object local_object
static BOOL fill_info(const void *addr, Dl_info *info)
Definition: dlfcn.c:697
#define _ReturnAddress()
Definition: dlfcn.c:60
static UINT MySetErrorMode(UINT uMode)
Definition: dlfcn.c:222
static void save_err_str(const char *str, DWORD dwMessageId)
Definition: dlfcn.c:162
static local_object * local_search(HMODULE hModule)
Definition: dlfcn.c:93
#define DLFCN_NOINLINE
Definition: dlfcn.c:76
DLFCN_EXPORT void * dlopen(const char *file, int mode)
Definition: dlfcn.c:331
static local_object first_object
Definition: dlfcn.c:90
DLFCN_EXPORT char * dlerror(void)
Definition: dlfcn.c:548
static const char * get_export_symbol_name(HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, const void *addr, void **func_address)
Definition: dlfcn.c:602
DLFCN_EXPORT int dlclose(void *handle)
Definition: dlfcn.c:423
static char module_filename[2 *MAX_PATH]
Definition: dlfcn.c:695
DLFCN_EXPORT int dladdr(const void *addr, Dl_info *info)
Definition: dlfcn.c:731
static BOOL local_add(HMODULE hModule)
Definition: dlfcn.c:106
static BOOL error_occurred
Definition: dlfcn.c:160
static HMODULE MyGetModuleHandleFromAddress(const void *addr)
Definition: dlfcn.c:247
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
Definition: dlfcn.c:51
ULONG ULONG_PTR
Definition: dlfcn.c:43
static BOOL is_import_thunk(const void *addr)
Definition: dlfcn.c:660
DLFCN_NOINLINE DLFCN_EXPORT void * dlsym(void *handle, const char *name)
Definition: dlfcn.c:447
static BOOL get_image_section(HMODULE module, int index, void **ptr, DWORD *size)
Definition: dlfcn.c:566
static BOOL MyEnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded)
Definition: dlfcn.c:286
static void local_rem(HMODULE hModule)
Definition: dlfcn.c:135
static BOOL is_valid_address(const void *addr)
Definition: dlfcn.c:636
#define RTLD_LOCAL
Definition: dlfcn.h:59
#define RTLD_NEXT
Definition: dlfcn.h:69
#define RTLD_DEFAULT
Definition: dlfcn.h:66
#define DLFCN_EXPORT
Definition: dlfcn.h:43
#define TRUE
Definition: grids.h:22
#define FALSE
Definition: grids.h:23
const char * name
Definition: init.cpp:16
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
static List * info
short index
Definition: cabvars.h:11
#define NULL
Definition: spdefs.h:105
Definition: dlfcn.h:72
struct local_object * previous
Definition: dlfcn.c:86
HMODULE hModule
Definition: dlfcn.c:85
struct local_object * next
Definition: dlfcn.c:87