root/src/dynlib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dynlib_reset_last_error
  2. dynlib_open
  3. dynlib_open_for_eln
  4. dynlib_sym
  5. dynlib_addr
  6. dynlib_error
  7. dynlib_close
  8. dynlib_open
  9. dynlib_open_for_eln
  10. dynlib_sym
  11. dynlib_addr
  12. dynlib_error
  13. dynlib_close
  14. dynlib_func

     1 /* Portable API for dynamic loading.
     2 
     3 Copyright 2015-2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 
    21 /* Assume modules are enabled on modern systems...  *Yes*, the
    22    preprocessor macro checks could be more precise.  I don't care.
    23 
    24    If you think the abstraction is too leaky use libltdl (libtool),
    25    don't reinvent the wheel by fixing this one.  */
    26 
    27 #include <config.h>
    28 
    29 #include "dynlib.h"
    30 
    31 #include <stddef.h>
    32 
    33 #ifdef WINDOWSNT
    34 
    35 /* MS-Windows systems.  */
    36 
    37 #include <errno.h>
    38 #include "lisp.h"
    39 #include "w32common.h"  /* for os_subtype */
    40 #include "w32.h"
    41 
    42 static BOOL g_b_init_get_module_handle_ex;
    43 static DWORD dynlib_last_err;
    44 
    45 /* Some versions of w32api headers only expose the following when
    46    _WIN32_WINNT is set to higher values that we use.  */
    47 typedef BOOL (WINAPI *GetModuleHandleExA_Proc) (DWORD,LPCSTR,HMODULE*);
    48 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
    49 # define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
    50 #endif
    51 #ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
    52 # define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
    53 #endif
    54 
    55 /* This needs to be called at startup to countermand any non-zero
    56    values recorded by temacs.  */
    57 void dynlib_reset_last_error (void);
    58 void
    59 dynlib_reset_last_error (void)
    60 {
    61   g_b_init_get_module_handle_ex = 0;
    62   dynlib_last_err = 0;
    63 }
    64 
    65 dynlib_handle_ptr
    66 dynlib_open (const char *dll_fname)
    67 {
    68   HMODULE hdll;
    69   char dll_fname_local[MAX_UTF8_PATH];
    70 
    71   if (!dll_fname)
    72     {
    73       errno = ENOTSUP;
    74       return NULL;
    75     }
    76 
    77   if (!dll_fname)
    78     hdll = GetModuleHandle (NULL);
    79   else
    80     {
    81       /* LoadLibrary wants backslashes.  */
    82       strcpy (dll_fname_local, dll_fname);
    83       unixtodos_filename (dll_fname_local);
    84 
    85       if (w32_unicode_filenames)
    86         {
    87           wchar_t dll_fname_w[MAX_PATH];
    88 
    89           filename_to_utf16 (dll_fname_local, dll_fname_w);
    90           hdll = LoadLibraryW (dll_fname_w);
    91         }
    92       else
    93         {
    94           char dll_fname_a[MAX_PATH];
    95 
    96           filename_to_ansi (dll_fname_local, dll_fname_a);
    97           hdll = LoadLibraryA (dll_fname_a);
    98         }
    99     }
   100 
   101   if (!hdll)
   102     dynlib_last_err = GetLastError ();
   103 
   104   return (dynlib_handle_ptr) hdll;
   105 }
   106 
   107 dynlib_handle_ptr
   108 dynlib_open_for_eln (const char *dll_fname)
   109 {
   110   return dynlib_open (dll_fname);
   111 }
   112 
   113 void *
   114 dynlib_sym (dynlib_handle_ptr h, const char *sym)
   115 {
   116   FARPROC sym_addr = NULL;
   117 
   118   if (!h || h == INVALID_HANDLE_VALUE || !sym)
   119     {
   120       dynlib_last_err = ERROR_INVALID_PARAMETER;
   121       return NULL;
   122     }
   123 
   124   sym_addr = GetProcAddress ((HMODULE) h, sym);
   125   if (!sym_addr)
   126     dynlib_last_err = GetLastError ();
   127 
   128   return (void *)sym_addr;
   129 }
   130 
   131 void
   132 dynlib_addr (void (*funcptr) (void), const char **fname, const char **symname)
   133 {
   134   static char dll_filename[MAX_UTF8_PATH];
   135   static GetModuleHandleExA_Proc s_pfn_Get_Module_HandleExA = NULL;
   136   char *dll_fn = NULL;
   137   HMODULE hm_kernel32 = NULL;
   138   HMODULE hm_dll = NULL;
   139   wchar_t mfn_w[MAX_PATH];
   140   char mfn_a[MAX_PATH];
   141   void *addr = (void *) funcptr;
   142 
   143   /* Step 1: Find the handle of the module where ADDR lives.  */
   144   if (os_subtype == OS_SUBTYPE_9X
   145       /* Windows NT family version before XP (v5.1).  */
   146       || ((w32_major_version + (w32_minor_version > 0)) < 6))
   147     {
   148       MEMORY_BASIC_INFORMATION mbi;
   149 
   150       /* According to Matt Pietrek, the module handle is just the base
   151          address where it's loaded in memory.  */
   152       if (VirtualQuery (addr, &mbi, sizeof(mbi)))
   153         hm_dll = (HMODULE)mbi.AllocationBase;
   154     }
   155   else
   156     {
   157       /* Use the documented API when available (XP and later).  */
   158       if (g_b_init_get_module_handle_ex == 0)
   159         {
   160           g_b_init_get_module_handle_ex = 1;
   161           hm_kernel32 = LoadLibrary ("kernel32.dll");
   162           /* We load the ANSI version of the function because the
   163              address we pass to it is not an address of a string, but
   164              an address of a function.  So we don't care about the
   165              Unicode version.  */
   166           s_pfn_Get_Module_HandleExA = (GetModuleHandleExA_Proc)
   167             get_proc_addr (hm_kernel32, "GetModuleHandleExA");
   168         }
   169       if (s_pfn_Get_Module_HandleExA)
   170         {
   171           DWORD flags = (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
   172                          /* We don't want to call FreeLibrary at the
   173                             end, because then we'd need to remember
   174                             whether we obtained the handle by this
   175                             method or the above one.  */
   176                          | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT);
   177 
   178           if (!s_pfn_Get_Module_HandleExA (flags, addr, &hm_dll))
   179             {
   180               dynlib_last_err = GetLastError ();
   181               hm_dll = NULL;
   182             }
   183         }
   184     }
   185 
   186   /* Step 2: Find the absolute file name of the module corresponding
   187      to the hm_dll handle.  */
   188   if (hm_dll)
   189     {
   190       DWORD retval;
   191 
   192       if (w32_unicode_filenames)
   193         {
   194           retval = GetModuleFileNameW (hm_dll, mfn_w, MAX_PATH);
   195           if (retval > 0 && retval < MAX_PATH
   196               && filename_from_utf16 (mfn_w, dll_filename) == 0)
   197             dll_fn = dll_filename;
   198           else if (retval == MAX_PATH)
   199             dynlib_last_err = ERROR_INSUFFICIENT_BUFFER;
   200           else
   201             dynlib_last_err = GetLastError ();
   202         }
   203       else
   204         {
   205           retval = GetModuleFileNameA (hm_dll, mfn_a, MAX_PATH);
   206           if (retval > 0 && retval < MAX_PATH
   207               && filename_from_ansi (mfn_a, dll_filename) == 0)
   208             dll_fn = dll_filename;
   209           else if (retval == MAX_PATH)
   210             dynlib_last_err = ERROR_INSUFFICIENT_BUFFER;
   211           else
   212             dynlib_last_err = GetLastError ();
   213         }
   214       if (dll_fn)
   215         dostounix_filename (dll_fn);
   216     }
   217 
   218   *fname = dll_fn;
   219 
   220   /* We cannot easily produce the function name, since typically all
   221      of the module functions will be unexported, and probably even
   222      static, which means the symbols can be obtained only if we link
   223      against libbfd (and the DLL can be stripped anyway).  So we just
   224      show the address and the file name (see print_vectorlike in
   225      print.c); they can use that with addr2line or GDB to recover the
   226      symbolic name.  */
   227   *symname = NULL;
   228 }
   229 
   230 const char *
   231 dynlib_error (void)
   232 {
   233   char *error_string = NULL;
   234 
   235   if (dynlib_last_err)
   236     {
   237       error_string = w32_strerror (dynlib_last_err);
   238       dynlib_last_err = 0;
   239     }
   240 
   241   return error_string;
   242 }
   243 
   244 int
   245 dynlib_close (dynlib_handle_ptr h)
   246 {
   247   if (!h || h == INVALID_HANDLE_VALUE)
   248     {
   249       dynlib_last_err = ERROR_INVALID_PARAMETER;
   250       return -1;
   251     }
   252   /* If the handle is for the main module (the .exe file), it
   253      shouldn't be passed to FreeLibrary, because GetModuleHandle
   254      doesn't increment the refcount, but FreeLibrary does decrement
   255      it.  I don't think this should matter for the main module, but
   256      just in case, we avoid the call here, relying on another call to
   257      GetModuleHandle to return the same value.  */
   258   if (h == GetModuleHandle (NULL))
   259     return 0;
   260 
   261   if (!FreeLibrary ((HMODULE) h))
   262     {
   263       dynlib_last_err = GetLastError ();
   264       return -1;
   265     }
   266 
   267   return 0;
   268 }
   269 
   270 #elif defined HAVE_UNISTD_H
   271 
   272 /* POSIX systems.  */
   273 
   274 #include <dlfcn.h>
   275 
   276 dynlib_handle_ptr
   277 dynlib_open (const char *path)
   278 {
   279   return dlopen (path, RTLD_LAZY | RTLD_GLOBAL);
   280 }
   281 
   282 # ifdef HAVE_NATIVE_COMP
   283 dynlib_handle_ptr
   284 dynlib_open_for_eln (const char *path)
   285 {
   286   return dlopen (path, RTLD_LAZY);
   287 }
   288 # endif
   289 
   290 void *
   291 dynlib_sym (dynlib_handle_ptr h, const char *sym)
   292 {
   293   return dlsym (h, sym);
   294 }
   295 
   296 void
   297 dynlib_addr (void (*funcptr) (void), const char **path, const char **sym)
   298 {
   299   *path = NULL;
   300   *sym = NULL;
   301 #ifdef HAVE_DLADDR
   302   void *ptr = (void *) funcptr;
   303   Dl_info info;
   304   if (dladdr (ptr, &info) && info.dli_fname && info.dli_sname)
   305     {
   306       *path = info.dli_fname;
   307       *sym = info.dli_sname;
   308     }
   309 #endif
   310 }
   311 
   312 const char *
   313 dynlib_error (void)
   314 {
   315   return dlerror ();
   316 }
   317 
   318 # ifdef HAVE_NATIVE_COMP
   319 int
   320 dynlib_close (dynlib_handle_ptr h)
   321 {
   322   return dlclose (h) == 0;
   323 }
   324 # endif
   325 
   326 #else
   327 
   328 #error "No dynamic loading for this system"
   329 
   330 #endif
   331 
   332 #if !HAVE_DLFUNC
   333 # define dlfunc dynlib_sym
   334 #endif
   335 
   336 dynlib_function_ptr
   337 dynlib_func (dynlib_handle_ptr h, const char *sym)
   338 {
   339   return (dynlib_function_ptr) dlfunc (h, sym);
   340 }

/* [<][>][^][v][top][bottom][index][help] */