diff options
| author | Eli Zaretskii | 2015-11-24 21:04:56 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2015-11-24 21:04:56 +0200 |
| commit | 146f361a1389bca308e3fba52f2d40edd7365aef (patch) | |
| tree | 921f2087500fc3093c530c98b5229d78d8196bf8 /src/dynlib.c | |
| parent | 8766ea49b62c82eb775b0810ae191af5a92cabee (diff) | |
| download | emacs-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.c | 116 |
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 | ||
| 40 | static BOOL g_b_init_get_module_handle_ex; | ||
| 39 | static DWORD dynlib_last_err; | 41 | static 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. */ | ||
| 45 | typedef 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. */ |
| 43 | void | 55 | void |
| 44 | dynlib_reset_last_error (void) | 56 | dynlib_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 | ||
| 109 | bool | 122 | bool |
| 110 | dynlib_addr (void *ptr, const char **path, const char **sym) | 123 | dynlib_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 | ||
| 115 | const char * | 227 | const char * |