aboutsummaryrefslogtreecommitdiffstats
path: root/src/dynlib.c
diff options
context:
space:
mode:
authorEli Zaretskii2015-11-24 21:04:56 +0200
committerEli Zaretskii2015-11-24 21:04:56 +0200
commit146f361a1389bca308e3fba52f2d40edd7365aef (patch)
tree921f2087500fc3093c530c98b5229d78d8196bf8 /src/dynlib.c
parent8766ea49b62c82eb775b0810ae191af5a92cabee (diff)
downloademacs-146f361a1389bca308e3fba52f2d40edd7365aef.tar.gz
emacs-146f361a1389bca308e3fba52f2d40edd7365aef.zip
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.
Diffstat (limited to 'src/dynlib.c')
-rw-r--r--src/dynlib.c116
1 files changed, 114 insertions, 2 deletions
diff --git a/src/dynlib.c b/src/dynlib.c
index a41bed847bb..190f183fa61 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/>. */
34 34
35#include <errno.h> 35#include <errno.h>
36#include "lisp.h" 36#include "lisp.h"
37#include "w32common.h" /* for os_subtype */
37#include "w32.h" 38#include "w32.h"
38 39
40static BOOL g_b_init_get_module_handle_ex;
39static DWORD dynlib_last_err; 41static DWORD dynlib_last_err;
40 42
43/* Some versions of w32api headers only expose the following when
44 _WIN32_WINNT is set to higher values that we use. */
45typedef BOOL (WINAPI *GetModuleHandleExA_Proc) (DWORD,LPCSTR,HMODULE*);
46#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
47# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
48#endif
49#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
50# define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
51#endif
52
41/* This needs to be called at startup to countermand any non-zero 53/* This needs to be called at startup to countermand any non-zero
42 values recorded by temacs. */ 54 values recorded by temacs. */
43void 55void
44dynlib_reset_last_error (void) 56dynlib_reset_last_error (void)
45{ 57{
58 g_b_init_get_module_handle_ex = 0;
46 dynlib_last_err = 0; 59 dynlib_last_err = 0;
47} 60}
48 61
@@ -107,9 +120,108 @@ dynlib_sym (dynlib_handle_ptr h, const char *sym)
107} 120}
108 121
109bool 122bool
110dynlib_addr (void *ptr, const char **path, const char **sym) 123dynlib_addr (void *addr, const char **fname, const char **symname)
111{ 124{
112 return false; /* Not implemented yet. */ 125 static char dll_filename[MAX_UTF8_PATH];
126 static char addr_str[22];
127 static GetModuleHandleExA_Proc s_pfn_Get_Module_HandleExA = NULL;
128 char *dll_fn = NULL;
129 HMODULE hm_kernel32 = NULL;
130 bool result = false;
131 HMODULE hm_dll = NULL;
132 wchar_t mfn_w[MAX_PATH];
133 char mfn_a[MAX_PATH];
134
135 /* Step 1: Find the handle of the module where ADDR lives. */
136 if (os_subtype == OS_9X
137 /* Windows NT family version before XP (v5.1). */
138 || ((w32_major_version + (w32_minor_version > 0)) < 6))
139 {
140 MEMORY_BASIC_INFORMATION mbi;
141
142 /* According to Matt Pietrek, the module handle is just the base
143 address where it's loaded in memory. */
144 if (VirtualQuery (addr, &mbi, sizeof(mbi)))
145 hm_dll = (HMODULE)mbi.AllocationBase;
146 }
147 else
148 {
149 /* Use the documented API when available (XP and later). */
150 if (g_b_init_get_module_handle_ex == 0)
151 {
152 g_b_init_get_module_handle_ex = 1;
153 hm_kernel32 = LoadLibrary ("kernel32.dll");
154 /* We load the ANSI version of the function because the
155 address we pass to it is not an address of a string, but
156 an address of a function. So we don't care about the
157 Unicode version. */
158 s_pfn_Get_Module_HandleExA =
159 (GetModuleHandleExA_Proc) GetProcAddress (hm_kernel32,
160 "GetModuleHandleExA");
161 }
162 if (s_pfn_Get_Module_HandleExA)
163 {
164 DWORD flags = (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
165 /* We don't want to call FreeLibrary at the
166 end, because then we'd need to remember
167 whether we obtained the handle by this
168 method or the above one. */
169 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT);
170
171 if (!s_pfn_Get_Module_HandleExA (flags, addr, &hm_dll))
172 {
173 dynlib_last_err = GetLastError ();
174 hm_dll = NULL;
175 }
176 }
177 }
178
179 /* Step 2: Find the absolute file name of the module corresponding
180 to the hm_dll handle. */
181 if (hm_dll)
182 {
183 DWORD retval;
184
185 if (w32_unicode_filenames)
186 {
187 retval = GetModuleFileNameW (hm_dll, mfn_w, MAX_PATH);
188 if (retval > 0 && retval < MAX_PATH
189 && filename_from_utf16 (mfn_w, dll_filename) == 0)
190 dll_fn = dll_filename;
191 else if (retval == MAX_PATH)
192 dynlib_last_err = ERROR_INSUFFICIENT_BUFFER;
193 else
194 dynlib_last_err = GetLastError ();
195 }
196 else
197 {
198 retval = GetModuleFileNameA (hm_dll, mfn_a, MAX_PATH);
199 if (retval > 0 && retval < MAX_PATH
200 && filename_from_ansi (mfn_a, dll_filename) == 0)
201 dll_fn = dll_filename;
202 else if (retval == MAX_PATH)
203 dynlib_last_err = ERROR_INSUFFICIENT_BUFFER;
204 else
205 dynlib_last_err = GetLastError ();
206 }
207 if (dll_fn)
208 {
209 dostounix_filename (dll_fn);
210 /* We cannot easily produce the function name, since
211 typically all of the module functions will be unexported,
212 and probably even static, which means the symbols can be
213 obtained only if we link against libbfd (and the DLL can
214 be stripped anyway). So we just show the address and the
215 file name; they can use that with addr2line or GDB to
216 recover the symbolic name. */
217 sprintf (addr_str, "at 0x%x", (DWORD_PTR)addr);
218 *symname = addr_str;
219 result = true;
220 }
221 }
222
223 *fname = dll_fn;
224 return result;
113} 225}
114 226
115const char * 227const char *