emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] emacs-25 146f361: Implement dynlib_addr for MS-Windows


From: Eli Zaretskii
Subject: [Emacs-diffs] emacs-25 146f361: Implement dynlib_addr for MS-Windows
Date: Tue, 24 Nov 2015 19:05:46 +0000

branch: emacs-25
commit 146f361a1389bca308e3fba52f2d40edd7365aef
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    Implement dynlib_addr for MS-Windows
    
    * src/dynlib.c [WINDOWSNT]: Include w32common.h.
    <g_b_init_get_module_handle_ex> [WINDOWSNT]: New static variable.
    (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
    (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) [WINDOWSNT]: Define
    if undefined.
    (dynlib_reset_last_error): Reset g_b_init_get_module_handle_ex to
    zero.
    (dynlib_addr) [WINDOWSNT]: Non-trivial implementation to report
    the full file name of the module for a given address.
---
 src/dynlib.c |  116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 114 insertions(+), 2 deletions(-)

diff --git a/src/dynlib.c b/src/dynlib.c
index a41bed8..190f183 100644
--- a/src/dynlib.c
+++ b/src/dynlib.c
@@ -34,15 +34,28 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
 #include "lisp.h"
+#include "w32common.h" /* for os_subtype */
 #include "w32.h"
 
+static BOOL g_b_init_get_module_handle_ex;
 static DWORD dynlib_last_err;
 
+/* Some versions of w32api headers only expose the following when
+   _WIN32_WINNT is set to higher values that we use.  */
+typedef BOOL (WINAPI *GetModuleHandleExA_Proc) (DWORD,LPCSTR,HMODULE*);
+#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
+#endif
+#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
+# define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
+#endif
+
 /* This needs to be called at startup to countermand any non-zero
    values recorded by temacs.  */
 void
 dynlib_reset_last_error (void)
 {
+  g_b_init_get_module_handle_ex = 0;
   dynlib_last_err = 0;
 }
 
@@ -107,9 +120,108 @@ dynlib_sym (dynlib_handle_ptr h, const char *sym)
 }
 
 bool
-dynlib_addr (void *ptr, const char **path, const char **sym)
+dynlib_addr (void *addr, const char **fname, const char **symname)
 {
-  return false;  /* Not implemented yet.  */
+  static char dll_filename[MAX_UTF8_PATH];
+  static char addr_str[22];
+  static GetModuleHandleExA_Proc s_pfn_Get_Module_HandleExA = NULL;
+  char *dll_fn = NULL;
+  HMODULE hm_kernel32 = NULL;
+  bool result = false;
+  HMODULE hm_dll = NULL;
+  wchar_t mfn_w[MAX_PATH];
+  char mfn_a[MAX_PATH];
+
+  /* Step 1: Find the handle of the module where ADDR lives.  */
+  if (os_subtype == OS_9X
+      /* Windows NT family version before XP (v5.1).  */
+      || ((w32_major_version + (w32_minor_version > 0)) < 6))
+    {
+      MEMORY_BASIC_INFORMATION mbi;
+
+      /* According to Matt Pietrek, the module handle is just the base
+        address where it's loaded in memory.  */
+      if (VirtualQuery (addr, &mbi, sizeof(mbi)))
+       hm_dll = (HMODULE)mbi.AllocationBase;
+    }
+  else
+    {
+      /* Use the documented API when available (XP and later).  */
+      if (g_b_init_get_module_handle_ex == 0)
+       {
+         g_b_init_get_module_handle_ex = 1;
+         hm_kernel32 = LoadLibrary ("kernel32.dll");
+         /* We load the ANSI version of the function because the
+            address we pass to it is not an address of a string, but
+            an address of a function.  So we don't care about the
+            Unicode version.  */
+         s_pfn_Get_Module_HandleExA =
+           (GetModuleHandleExA_Proc) GetProcAddress (hm_kernel32,
+                                                     "GetModuleHandleExA");
+       }
+      if (s_pfn_Get_Module_HandleExA)
+       {
+         DWORD flags = (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+                        /* We don't want to call FreeLibrary at the
+                           end, because then we'd need to remember
+                           whether we obtained the handle by this
+                           method or the above one.  */
+                        | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT);
+
+         if (!s_pfn_Get_Module_HandleExA (flags, addr, &hm_dll))
+           {
+             dynlib_last_err = GetLastError ();
+             hm_dll = NULL;
+           }
+       }
+    }
+
+  /* Step 2: Find the absolute file name of the module corresponding
+     to the hm_dll handle.  */
+  if (hm_dll)
+    {
+      DWORD retval;
+
+      if (w32_unicode_filenames)
+       {
+         retval = GetModuleFileNameW (hm_dll, mfn_w, MAX_PATH);
+         if (retval > 0 && retval < MAX_PATH
+             && filename_from_utf16 (mfn_w, dll_filename) == 0)
+           dll_fn = dll_filename;
+         else if (retval == MAX_PATH)
+           dynlib_last_err = ERROR_INSUFFICIENT_BUFFER;
+         else
+           dynlib_last_err = GetLastError ();
+       }
+      else
+       {
+         retval = GetModuleFileNameA (hm_dll, mfn_a, MAX_PATH);
+         if (retval > 0 && retval < MAX_PATH
+             && filename_from_ansi (mfn_a, dll_filename) == 0)
+           dll_fn = dll_filename;
+         else if (retval == MAX_PATH)
+           dynlib_last_err = ERROR_INSUFFICIENT_BUFFER;
+         else
+           dynlib_last_err = GetLastError ();
+       }
+      if (dll_fn)
+       {
+         dostounix_filename (dll_fn);
+         /* We cannot easily produce the function name, since
+            typically all of the module functions will be unexported,
+            and probably even static, which means the symbols can be
+            obtained only if we link against libbfd (and the DLL can
+            be stripped anyway).  So we just show the address and the
+            file name; they can use that with addr2line or GDB to
+            recover the symbolic name.  */
+         sprintf (addr_str, "at 0x%x", (DWORD_PTR)addr);
+         *symname = addr_str;
+         result = true;
+       }
+    }
+
+  *fname = dll_fn;
+  return result;
 }
 
 const char *



reply via email to

[Prev in Thread] Current Thread [Next in Thread]