* [rfc] DLL support for gdbserver
@ 2007-07-02 22:12 Daniel Jacobowitz
2007-07-04 9:39 ` Pedro Alves
2007-07-04 17:27 ` Joel Brobecker
0 siblings, 2 replies; 7+ messages in thread
From: Daniel Jacobowitz @ 2007-07-02 22:12 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
Here's a final version of gdbserver support for Windows DLLs.
It works for me testing with Cygwin. Pedro, would you like to test
this on Windows CE to see what I've broken?
--
Daniel Jacobowitz
CodeSourcery
2007-07-02 Pedro Alves <pedro_alves@portugalmail.pt>
Daniel Jacobowitz <dan@codesourcery.com>
* config/i386/cygwin.mt (TDEPFILES): Add solib-target.o.
* coff-pe-read.c (read_pe_exported_syms): Delete verbose
printf.
* NEWS: Mention gdbserver DLL support.
2007-07-02 Pedro Alves <pedro_alves@portugalmail.pt>
Daniel Jacobowitz <dan@codesourcery.com>
* gdb.base/unload.c (dlopen, dlsym, dlclose, dlerror): Define
for __WIN32__.
(SHLIB_NAME): Delete definition. Always pass dlerror to fprintf.
* gdb.base/unload.exp: Use shared library test routines.
2007-07-02 Pedro Alves <pedro_alves@portugalmail.pt>
Daniel Jacobowitz <dan@codesourcery.com>
* inferiors.c (all_dlls, dlls_changed, get_dll): New.
(add_thread): Minor cleanups.
(clear_inferiors): Move lower in the file. Clear the DLL
list.
(free_one_dll, match_dll, loaded_dll, unloaded_dll, clear_list): New.
* remote-utils.c (prepare_resume_reply): Check dlls_changed.
(xml_escape_text): New.
* server.c (handle_query): Handle qXfer:libraries:read. Report it
for qSupported.
(handle_v_cont): Report errors.
(gdbserver_version): Update.
(main): Correct size of own_buf. Do not report initial DLL events.
* server.h (struct dll_info, all_dlls, dlls_changed, loaded_dll)
(unloaded_dll, xml_escape_text): New.
* win32-low.c (enum target_waitkind): Update comments.
(win32_add_one_solib, get_image_name, winapi_EnumProcessModules)
(winapi_GetModuleInformation, winapi_GetModuleFileNameExA)
(win32_EnumProcessModules, win32_GetModuleInformation)
(win32_GetModuleFileNameExA, load_psapi, psapi_get_dll_name)
(winapi_CreateToolhelp32Snapshot, winapi_Module32First)
(winapi_Module32Next, win32_CreateToolhelp32Snapshot)
(win32_Module32First, win32_Module32Next, load_toolhelp)
(toolhelp_get_dll_name, handle_load_dll, handle_unload_dll): New.
(get_child_debug_event): Handle DLL events.
(win32_wait): Likewise.
---
gdb/NEWS | 3
gdb/coff-pe-read.c | 3
gdb/config/i386/cygwin.mt | 3
gdb/gdbserver/inferiors.c | 93 +++++++++-
gdb/gdbserver/remote-utils.c | 69 +++++++
gdb/gdbserver/server.c | 79 ++++++++-
gdb/gdbserver/server.h | 15 +
gdb/gdbserver/win32-low.c | 332 +++++++++++++++++++++++++++++++++++++-
gdb/testsuite/gdb.base/unload.c | 14 +
gdb/testsuite/gdb.base/unload.exp | 23 --
10 files changed, 591 insertions(+), 43 deletions(-)
Index: src/gdb/config/i386/cygwin.mt
===================================================================
--- src.orig/gdb/config/i386/cygwin.mt 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/config/i386/cygwin.mt 2007-07-02 15:28:55.000000000 -0400
@@ -1,2 +1,3 @@
# Target: Intel 386 run win32
-TDEPFILES= i386-tdep.o i386-cygwin-tdep.o i387-tdep.o
+TDEPFILES= i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \
+ solib-target.o
Index: src/gdb/gdbserver/inferiors.c
===================================================================
--- src.orig/gdb/gdbserver/inferiors.c 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/gdbserver/inferiors.c 2007-07-02 16:15:10.000000000 -0400
@@ -33,10 +33,13 @@ struct thread_info
};
struct inferior_list all_threads;
+struct inferior_list all_dlls;
+int dlls_changed;
struct thread_info *current_inferior;
#define get_thread(inf) ((struct thread_info *)(inf))
+#define get_dll(inf) ((struct dll_info *)(inf))
void
add_inferior_to_list (struct inferior_list *list,
@@ -109,15 +112,14 @@ remove_inferior (struct inferior_list *l
void
add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
{
- struct thread_info *new_thread
- = (struct thread_info *) malloc (sizeof (*new_thread));
+ struct thread_info *new_thread = malloc (sizeof (*new_thread));
memset (new_thread, 0, sizeof (*new_thread));
new_thread->entry.id = thread_id;
add_inferior_to_list (&all_threads, & new_thread->entry);
-
+
if (current_inferior == NULL)
current_inferior = new_thread;
@@ -187,14 +189,6 @@ remove_thread (struct thread_info *threa
free_one_thread (&thread->entry);
}
-void
-clear_inferiors (void)
-{
- for_each_inferior (&all_threads, free_one_thread);
-
- all_threads.head = all_threads.tail = NULL;
-}
-
struct inferior_list_entry *
find_inferior (struct inferior_list *list,
int (*func) (struct inferior_list_entry *, void *), void *arg)
@@ -249,3 +243,80 @@ set_inferior_regcache_data (struct threa
{
inferior->regcache_data = data;
}
+
+static void
+free_one_dll (struct inferior_list_entry *inf)
+{
+ struct dll_info *dll = get_dll (inf);
+ if (dll->name != NULL)
+ free (dll->name);
+ free (dll);
+}
+
+/* Find a DLL with the same name and/or base address. A NULL name in
+ the key is ignored; so is an all-ones base address. */
+
+static int
+match_dll (struct inferior_list_entry *inf, void *arg)
+{
+ struct dll_info *iter = (void *) inf;
+ struct dll_info *key = arg;
+
+ if (key->base_addr != ~(CORE_ADDR) 0
+ && iter->base_addr == key->base_addr)
+ return 1;
+ else if (key->name != NULL
+ && iter->name != NULL
+ && strcmp (key->name, iter->name) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Record a newly loaded DLL at BASE_ADDR. */
+
+void
+loaded_dll (const char *name, CORE_ADDR base_addr)
+{
+ struct dll_info *new_dll = malloc (sizeof (*new_dll));
+ memset (new_dll, 0, sizeof (*new_dll));
+
+ new_dll->entry.id = -1;
+
+ new_dll->name = strdup (name);
+ new_dll->base_addr = base_addr;
+
+ add_inferior_to_list (&all_dlls, &new_dll->entry);
+ dlls_changed = 1;
+}
+
+/* Record that the DLL with NAME and BASE_ADDR has been unloaded. */
+
+void
+unloaded_dll (const char *name, CORE_ADDR base_addr)
+{
+ struct dll_info *dll;
+ struct dll_info key_dll;
+
+ /* Be careful not to put the key DLL in any list. */
+ key_dll.name = (char *) name;
+ key_dll.base_addr = base_addr;
+
+ dll = (void *) find_inferior (&all_dlls, match_dll, &key_dll);
+ remove_inferior (&all_dlls, &dll->entry);
+ free_one_dll (&dll->entry);
+ dlls_changed = 1;
+}
+
+#define clear_list(LIST) \
+ do { (LIST)->head = (LIST)->tail = NULL; } while (0)
+
+void
+clear_inferiors (void)
+{
+ for_each_inferior (&all_threads, free_one_thread);
+ for_each_inferior (&all_dlls, free_one_dll);
+
+ clear_list (&all_threads);
+ clear_list (&all_dlls);
+}
Index: src/gdb/gdbserver/remote-utils.c
===================================================================
--- src.orig/gdb/gdbserver/remote-utils.c 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/gdbserver/remote-utils.c 2007-07-02 16:03:27.000000000 -0400
@@ -965,6 +965,13 @@ prepare_resume_reply (char *buf, char st
old_thread_from_wait = thread_from_wait;
}
}
+
+ if (dlls_changed)
+ {
+ strcpy (buf, "library:;");
+ buf += strlen (buf);
+ dlls_changed = 0;
+ }
}
/* For W and X, we're done. */
*buf++ = 0;
@@ -1153,3 +1160,65 @@ monitor_output (const char *msg)
putpkt (buf);
free (buf);
}
+
+/* Return a malloc allocated string with special characters from TEXT
+ replaced by entity references. */
+
+char *
+xml_escape_text (const char *text)
+{
+ char *result;
+ int i, special;
+
+ /* Compute the length of the result. */
+ for (i = 0, special = 0; text[i] != '\0'; i++)
+ switch (text[i])
+ {
+ case '\'':
+ case '\"':
+ special += 5;
+ break;
+ case '&':
+ special += 4;
+ break;
+ case '<':
+ case '>':
+ special += 3;
+ break;
+ default:
+ break;
+ }
+
+ /* Expand the result. */
+ result = malloc (i + special + 1);
+ for (i = 0, special = 0; text[i] != '\0'; i++)
+ switch (text[i])
+ {
+ case '\'':
+ strcpy (result + i + special, "'");
+ special += 5;
+ break;
+ case '\"':
+ strcpy (result + i + special, """);
+ special += 5;
+ break;
+ case '&':
+ strcpy (result + i + special, "&");
+ special += 4;
+ break;
+ case '<':
+ strcpy (result + i + special, "<");
+ special += 3;
+ break;
+ case '>':
+ strcpy (result + i + special, ">");
+ special += 3;
+ break;
+ default:
+ result[i + special] = text[i];
+ break;
+ }
+ result[i + special] = '\0';
+
+ return result;
+}
Index: src/gdb/gdbserver/server.c
===================================================================
--- src.orig/gdb/gdbserver/server.c 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/gdbserver/server.c 2007-07-02 16:10:31.000000000 -0400
@@ -458,12 +458,80 @@ handle_query (char *own_buf, int packet_
return;
}
+ if (strncmp ("qXfer:libraries:read:", own_buf, 21) == 0)
+ {
+ CORE_ADDR ofs;
+ unsigned int len, total_len;
+ char *document, *p;
+ struct inferior_list_entry *dll_ptr;
+ char *annex;
+
+ /* Reject any annex; grab the offset and length. */
+ if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0
+ || annex[0] != '\0')
+ {
+ strcpy (own_buf, "E00");
+ return;
+ }
+
+ /* Over-estimate the necessary memory. Assume that every character
+ in the library name must be escaped. */
+ total_len = 64;
+ for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
+ total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name);
+
+ document = malloc (total_len);
+ strcpy (document, "<library-list>\n");
+ p = document + strlen (document);
+
+ for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
+ {
+ struct dll_info *dll = (struct dll_info *) dll_ptr;
+ char *name;
+
+ strcpy (p, " <library name=\"");
+ p = p + strlen (p);
+ name = xml_escape_text (dll->name);
+ strcpy (p, name);
+ free (name);
+ p = p + strlen (p);
+ strcpy (p, "\"><segment address=\"");
+ p = p + strlen (p);
+ sprintf (p, "0x%lx", (long) dll->base_addr);
+ p = p + strlen (p);
+ strcpy (p, "\"/></library>\n");
+ p = p + strlen (p);
+ }
+
+ strcpy (p, "</library-list>\n");
+
+ total_len = strlen (document);
+ if (len > PBUFSIZ - 2)
+ len = PBUFSIZ - 2;
+
+ if (ofs > total_len)
+ write_enn (own_buf);
+ else if (len < total_len - ofs)
+ *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
+ len, 1);
+ else
+ *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
+ total_len - ofs, 0);
+
+ free (document);
+ return;
+ }
+
/* Protocol features query. */
if (strncmp ("qSupported", own_buf, 10) == 0
&& (own_buf[10] == ':' || own_buf[10] == '\0'))
{
sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
+ /* We do not have any hook to indicate whether the target backend
+ supports qXfer:libraries:read, so always report it. */
+ strcat (own_buf, ";qXfer:libraries:read+");
+
if (the_target->read_auxv != NULL)
strcat (own_buf, ";qXfer:auxv:read+");
@@ -696,8 +764,7 @@ handle_v_cont (char *own_buf, char *stat
return;
err:
- /* No other way to report an error... */
- strcpy (own_buf, "");
+ write_enn (own_buf);
free (resume_info);
return;
}
@@ -753,7 +820,7 @@ static void
gdbserver_version (void)
{
printf ("GNU gdbserver %s\n"
- "Copyright (C) 2006 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2007 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
version, host_name);
@@ -824,7 +891,7 @@ main (int argc, char *argv[])
initialize_low ();
- own_buf = malloc (PBUFSIZ);
+ own_buf = malloc (PBUFSIZ + 1);
mem_buf = malloc (PBUFSIZ);
if (pid == 0)
@@ -833,6 +900,10 @@ main (int argc, char *argv[])
signal = start_inferior (&argv[2], &status);
/* We are now stopped at the first instruction of the target process */
+
+ /* Don't report shared library events on the initial connection,
+ even if some libraries are preloaded. */
+ dlls_changed = 0;
}
else
{
Index: src/gdb/gdbserver/server.h
===================================================================
--- src.orig/gdb/gdbserver/server.h 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/gdbserver/server.h 2007-07-02 16:15:02.000000000 -0400
@@ -91,6 +91,13 @@ struct inferior_list_entry
/* Opaque type for user-visible threads. */
struct thread_info;
+struct dll_info
+{
+ struct inferior_list_entry entry;
+ char *name;
+ CORE_ADDR base_addr;
+};
+
#include "regcache.h"
#include "gdb/signals.h"
@@ -104,6 +111,9 @@ void initialize_low ();
/* From inferiors.c. */
extern struct inferior_list all_threads;
+extern struct inferior_list all_dlls;
+extern int dlls_changed;
+
void add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior);
void for_each_inferior (struct inferior_list *list,
@@ -132,6 +142,9 @@ void set_inferior_regcache_data (struct
void change_inferior_id (struct inferior_list *list,
unsigned long new_id);
+void loaded_dll (const char *name, CORE_ADDR base_addr);
+void unloaded_dll (const char *name, CORE_ADDR base_addr);
+
/* Public variables in server.c */
extern unsigned long cont_thread;
@@ -190,6 +203,8 @@ int look_up_one_symbol (const char *name
void monitor_output (const char *msg);
+char *xml_escape_text (const char *text);
+
/* Functions from ``signals.c''. */
enum target_signal target_signal_from_host (int hostsig);
int target_signal_to_host_p (enum target_signal oursig);
Index: src/gdb/gdbserver/win32-low.c
===================================================================
--- src.orig/gdb/gdbserver/win32-low.c 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/gdbserver/win32-low.c 2007-07-02 15:28:39.000000000 -0400
@@ -29,6 +29,7 @@
#include <windows.h>
#include <winnt.h>
#include <imagehlp.h>
+#include <tlhelp32.h>
#include <psapi.h>
#include <sys/param.h>
#include <malloc.h>
@@ -202,8 +203,8 @@ enum target_waitkind
value.sig. */
TARGET_WAITKIND_STOPPED,
- /* The program is letting us know that it dynamically loaded something
- (e.g. it called load(2) on AIX). */
+ /* The program is letting us know that it dynamically loaded
+ or unloaded something. */
TARGET_WAITKIND_LOADED,
/* The program has exec'ed a new executable file. The new file's
@@ -765,6 +766,316 @@ win32_resume (struct thread_resume *resu
}
static void
+win32_add_one_solib (const char *name, CORE_ADDR load_addr)
+{
+ char buf[MAX_PATH + 1];
+ char buf2[MAX_PATH + 1];
+
+#ifdef _WIN32_WCE
+ WIN32_FIND_DATA w32_fd;
+ WCHAR wname[MAX_PATH + 1];
+ mbstowcs (wname, name, MAX_PATH);
+ HANDLE h = FindFirstFile (wname, &w32_fd);
+#else
+ WIN32_FIND_DATAA w32_fd;
+ HANDLE h = FindFirstFileA (name, &w32_fd);
+#endif
+
+ if (h == INVALID_HANDLE_VALUE)
+ strcpy (buf, name);
+ else
+ {
+ FindClose (h);
+ strcpy (buf, name);
+#ifndef _WIN32_WCE
+ {
+ char cwd[MAX_PATH + 1];
+ char *p;
+ if (GetCurrentDirectoryA (MAX_PATH + 1, cwd))
+ {
+ p = strrchr (buf, '\\');
+ if (p)
+ p[1] = '\0';
+ SetCurrentDirectoryA (buf);
+ GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p);
+ SetCurrentDirectoryA (cwd);
+ }
+ }
+#endif
+ }
+
+#ifdef __CYGWIN__
+ cygwin_conv_to_posix_path (buf, buf2);
+#else
+ strcpy (buf2, buf);
+#endif
+
+ loaded_dll (buf2, load_addr);
+}
+
+static char *
+get_image_name (HANDLE h, void *address, int unicode)
+{
+ static char buf[(2 * MAX_PATH) + 1];
+ DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
+ char *address_ptr;
+ int len = 0;
+ char b[2];
+ DWORD done;
+
+ /* Attempt to read the name of the dll that was detected.
+ This is documented to work only when actively debugging
+ a program. It will not work for attached processes. */
+ if (address == NULL)
+ return NULL;
+
+#ifdef _WIN32_WCE
+ /* Windows CE reports the address of the image name,
+ instead of an address of a pointer into the image name. */
+ address_ptr = address;
+#else
+ /* See if we could read the address of a string, and that the
+ address isn't null. */
+ if (!ReadProcessMemory (h, address, &address_ptr,
+ sizeof (address_ptr), &done)
+ || done != sizeof (address_ptr)
+ || !address_ptr)
+ return NULL;
+#endif
+
+ /* Find the length of the string */
+ while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
+ && (b[0] != 0 || b[size - 1] != 0) && done == size)
+ continue;
+
+ if (!unicode)
+ ReadProcessMemory (h, address_ptr, buf, len, &done);
+ else
+ {
+ WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
+ ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
+ &done);
+
+ WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0);
+ }
+
+ return buf;
+}
+
+typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *,
+ DWORD, LPDWORD);
+typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE,
+ LPMODULEINFO, DWORD);
+typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE,
+ LPSTR, DWORD);
+
+static winapi_EnumProcessModules win32_EnumProcessModules;
+static winapi_GetModuleInformation win32_GetModuleInformation;
+static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA;
+
+static BOOL
+load_psapi (void)
+{
+ static int psapi_loaded = 0;
+ static HMODULE dll = NULL;
+
+ if (!psapi_loaded)
+ {
+ psapi_loaded = 1;
+ dll = LoadLibrary (TEXT("psapi.dll"));
+ if (!dll)
+ return FALSE;
+ win32_EnumProcessModules =
+ GETPROCADDRESS (dll, EnumProcessModules);
+ win32_GetModuleInformation =
+ GETPROCADDRESS (dll, GetModuleInformation);
+ win32_GetModuleFileNameExA =
+ GETPROCADDRESS (dll, GetModuleFileNameExA);
+ }
+
+ return (win32_EnumProcessModules != NULL
+ && win32_GetModuleInformation != NULL
+ && win32_GetModuleFileNameExA != NULL);
+}
+
+static int
+psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+{
+ DWORD len;
+ MODULEINFO mi;
+ size_t i;
+ HMODULE dh_buf[1];
+ HMODULE *DllHandle = dh_buf;
+ DWORD cbNeeded;
+ BOOL ok;
+
+ if (!load_psapi ())
+ goto failed;
+
+ cbNeeded = 0;
+ ok = (*win32_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ sizeof (HMODULE),
+ &cbNeeded);
+
+ if (!ok || !cbNeeded)
+ goto failed;
+
+ DllHandle = (HMODULE *) alloca (cbNeeded);
+ if (!DllHandle)
+ goto failed;
+
+ ok = (*win32_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ cbNeeded,
+ &cbNeeded);
+ if (!ok)
+ goto failed;
+
+ for (i = 0; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
+ {
+ if (!(*win32_GetModuleInformation) (current_process_handle,
+ DllHandle[i],
+ &mi,
+ sizeof (mi)))
+ {
+ DWORD err = GetLastError ();
+ error ("Can't get module info: (error %d): %s\n",
+ (int) err, strwinerror (err));
+ }
+
+ if ((DWORD) (mi.lpBaseOfDll) == BaseAddress)
+ {
+ len = (*win32_GetModuleFileNameExA) (current_process_handle,
+ DllHandle[i],
+ dll_name_ret,
+ MAX_PATH);
+ if (len == 0)
+ {
+ DWORD err = GetLastError ();
+ error ("Error getting dll name: (error %d): %s\n",
+ (int) err, strwinerror (err));
+ }
+ return 1;
+ }
+ }
+
+failed:
+ dll_name_ret[0] = '\0';
+ return 0;
+}
+
+typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD);
+typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
+typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
+
+static winapi_CreateToolhelp32Snapshot win32_CreateToolhelp32Snapshot;
+static winapi_Module32First win32_Module32First;
+static winapi_Module32Next win32_Module32Next;
+
+static BOOL
+load_toolhelp (void)
+{
+ static int toolhelp_loaded = 0;
+ static HMODULE dll = NULL;
+
+ if (!toolhelp_loaded)
+ {
+ toolhelp_loaded = 1;
+#ifndef _WIN32_WCE
+ dll = GetModuleHandle (_T("KERNEL32.DLL"));
+#else
+ dll = GetModuleHandle (_T("COREDLL.DLL"));
+#endif
+ if (!dll)
+ return FALSE;
+
+ win32_CreateToolhelp32Snapshot =
+ GETPROCADDRESS (dll, CreateToolhelp32Snapshot);
+ win32_Module32First = GETPROCADDRESS (dll, Module32First);
+ win32_Module32Next = GETPROCADDRESS (dll, Module32Next);
+ }
+
+ return (win32_CreateToolhelp32Snapshot != NULL
+ && win32_Module32First != NULL
+ && win32_Module32Next != NULL);
+}
+
+static int
+toolhelp_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+{
+ HANDLE snapshot_module;
+ MODULEENTRY32 modEntry = { sizeof (MODULEENTRY32) };
+
+ if (!load_toolhelp ())
+ return 0;
+
+ snapshot_module = win32_CreateToolhelp32Snapshot (TH32CS_SNAPMODULE,
+ current_event.dwProcessId);
+ if (snapshot_module == INVALID_HANDLE_VALUE)
+ return 0;
+
+ /* Ignore the first module, which is the exe. */
+ if (!win32_Module32First (snapshot_module, &modEntry))
+ goto failed;
+
+ while (win32_Module32Next (snapshot_module, &modEntry))
+ if ((DWORD) modEntry.modBaseAddr == BaseAddress)
+ {
+#ifdef UNICODE
+ wcstombs (dll_name_ret, modEntry.szExePath, MAX_PATH + 1);
+#else
+ strcpy (dll_name_ret, modEntry.szExePath);
+#endif
+ CloseHandle (snapshot_module);
+ return 1;
+ }
+
+failed:
+ CloseHandle (snapshot_module);
+ return 0;
+}
+
+static void
+handle_load_dll (void)
+{
+ LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
+ char dll_buf[MAX_PATH + 1];
+ char *dll_name = NULL;
+ DWORD load_addr;
+
+ dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+
+ if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf)
+ && !toolhelp_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
+ dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+
+ dll_name = dll_buf;
+
+ if (*dll_name == '\0')
+ dll_name = get_image_name (current_process_handle,
+ event->lpImageName, event->fUnicode);
+ if (!dll_name)
+ return;
+
+ /* The symbols in a dll are offset by 0x1000, which is the
+ the offset from 0 of the first byte in an image - because
+ of the file header and the section alignment. */
+
+ load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
+ win32_add_one_solib (dll_name, load_addr);
+}
+
+static void
+handle_unload_dll (void)
+{
+ CORE_ADDR load_addr =
+ (CORE_ADDR) (DWORD) current_event.u.UnloadDll.lpBaseOfDll;
+ load_addr += 0x1000;
+ unloaded_dll (NULL, load_addr);
+}
+
+static void
handle_exception (struct target_waitstatus *ourstatus)
{
DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
@@ -955,9 +1266,10 @@ get_child_debug_event (struct target_wai
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
CloseHandle (current_event.u.LoadDll.hFile);
+ handle_load_dll ();
ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.integer = 0;
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
break;
case UNLOAD_DLL_DEBUG_EVENT:
@@ -965,6 +1277,9 @@ get_child_debug_event (struct target_wai
"for pid=%d tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
+ handle_unload_dll ();
+ ourstatus->kind = TARGET_WAITKIND_LOADED;
+ ourstatus->value.sig = TARGET_SIGNAL_TRAP;
break;
case EXCEPTION_DEBUG_EVENT:
@@ -1027,6 +1342,7 @@ win32_wait (char *status)
return our_status.value.integer;
case TARGET_WAITKIND_STOPPED:
+ case TARGET_WAITKIND_LOADED:
OUTMSG2 (("Child Stopped with signal = %d \n",
our_status.value.sig));
@@ -1034,12 +1350,20 @@ win32_wait (char *status)
child_fetch_inferior_registers (-1);
+ if (our_status.kind == TARGET_WAITKIND_LOADED
+ && !server_waiting)
+ {
+ /* When gdb connects, we want to be stopped at the
+ initial breakpoint, not in some dll load event. */
+ child_continue (DBG_CONTINUE, -1);
+ break;
+ }
+
return our_status.value.sig;
default:
OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
/* fall-through */
case TARGET_WAITKIND_SPURIOUS:
- case TARGET_WAITKIND_LOADED:
case TARGET_WAITKIND_EXECD:
/* do nothing, just continue */
child_continue (DBG_CONTINUE, -1);
Index: src/gdb/coff-pe-read.c
===================================================================
--- src.orig/gdb/coff-pe-read.c 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/coff-pe-read.c 2007-07-02 15:28:39.000000000 -0400
@@ -309,9 +309,6 @@ read_pe_exported_syms (struct objfile *o
+= ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
}
- printf_filtered (_("Minimal symbols from %s..."), dll_name);
- wrap_here ("");
-
/* Truncate name at first dot. Should maybe also convert to all
lower case for convenience on Windows. */
read_pe_truncate_name (dll_name);
Index: src/gdb/testsuite/gdb.base/unload.c
===================================================================
--- src.orig/gdb/testsuite/gdb.base/unload.c 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/testsuite/gdb.base/unload.c 2007-07-02 15:28:39.000000000 -0400
@@ -18,12 +18,19 @@
#include <stdio.h>
#include <stdlib.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#define dlopen(name, mode) LoadLibrary (name)
+#define dlsym(handle, func) GetProcAddress (handle, func)
+#define dlclose(handle) FreeLibrary (handle)
+#define dlerror() "error %d occurred", GetLastError ()
+#else
#include <dlfcn.h>
+#endif
int k = 0;
-#define SHLIB_NAME SHLIB_DIR "/unloadshr.sl"
-
int main()
{
void *handle;
@@ -32,11 +39,10 @@ int main()
const char *msg;
handle = dlopen (SHLIB_NAME, RTLD_LAZY);
- msg = dlerror ();
if (!handle)
{
- fprintf (stderr, msg);
+ fprintf (stderr, dlerror ());
exit (1);
}
Index: src/gdb/testsuite/gdb.base/unload.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/unload.exp 2007-07-02 15:28:31.000000000 -0400
+++ src/gdb/testsuite/gdb.base/unload.exp 2007-07-02 15:28:39.000000000 -0400
@@ -30,37 +30,28 @@ if {[skip_shlib_tests]} {
return 0
}
-# TODO: Use LoadLibrary on these targets instead of dlopen.
-if {([istarget arm*-*-symbianelf*]
- || [istarget *-*-mingw*]
- || [istarget *-*-cygwin*]
- || [istarget *-*-pe*])} {
+# TODO: Use LoadLibrary on this target instead of dlopen.
+if {[istarget arm*-*-symbianelf*]} {
return 0
}
set testfile "unload"
set libfile "unloadshr"
+set libname "${libfile}.sl"
set libsrcfile ${libfile}.c
set srcfile $srcdir/$subdir/$testfile.c
set binfile $objdir/$subdir/$testfile
set shlibdir ${objdir}/${subdir}
set libsrc $srcdir/$subdir/$libfile.c
-set lib_sl $objdir/$subdir/$libfile.sl
-
-set lib_opts debug
-set exec_opts [list debug additional_flags=-DSHLIB_DIR\=\"${shlibdir}\"]
-
-switch -glob [istarget] {
- "hppa*-hp-hpux*" { }
- "*-*-linux*" { lappend exec_opts "libs=-ldl" }
- "*-*-solaris*" { lappend exec_opts "libs=-ldl" }
- default { }
-}
+set lib_sl $objdir/$subdir/$libname
if [get_compiler_info ${binfile}] {
return -1
}
+set lib_opts debug
+set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${libname}\"]
+
if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
|| [gdb_compile $srcfile $binfile executable $exec_opts] != ""} {
untested "Couldn't compile $libsrc or $srcfile."
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS 2007-07-02 16:18:41.000000000 -0400
+++ src/gdb/NEWS 2007-07-02 16:22:41.000000000 -0400
@@ -50,6 +50,9 @@ packet, this response allows GDB to debu
where the operating system manages the list of loaded libraries (e.g.
Windows and SymbianOS).
+* The GDB remote stub, gdbserver, now supports dynamic link libraries
+(DLLs) on Windows and Windows CE targets.
+
* New commands
set remoteflow
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [rfc] DLL support for gdbserver
2007-07-02 22:12 [rfc] DLL support for gdbserver Daniel Jacobowitz
@ 2007-07-04 9:39 ` Pedro Alves
2007-07-08 1:21 ` Pedro Alves
2007-07-17 12:54 ` Daniel Jacobowitz
2007-07-04 17:27 ` Joel Brobecker
1 sibling, 2 replies; 7+ messages in thread
From: Pedro Alves @ 2007-07-04 9:39 UTC (permalink / raw)
To: gdb-patches
Hi Daniel,
Daniel Jacobowitz wrote:
> Here's a final version of gdbserver support for Windows DLLs.
> It works for me testing with Cygwin. Pedro, would you like to test
> this on Windows CE to see what I've broken?
>
It looks alright, except that gdb/config/arm/wince.mt and gdb/arm-wince-tdep.c
(to add solib-target.c, and remove the svr4 copy/paste thinko) hunks
got left out.
I'll find time to test it this weekend, but don't let me hold you.
Many thanks,
Cheers,
Pedro Alves
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [rfc] DLL support for gdbserver
2007-07-04 9:39 ` Pedro Alves
@ 2007-07-08 1:21 ` Pedro Alves
2007-07-08 14:46 ` Pedro Alves
2007-07-17 12:54 ` Daniel Jacobowitz
1 sibling, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2007-07-08 1:21 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1053 bytes --]
Pedro Alves wrote:
> Daniel Jacobowitz wrote:
>> Here's a final version of gdbserver support for Windows DLLs.
>> It works for me testing with Cygwin. Pedro, would you like to test
>> this on Windows CE to see what I've broken?
>>
>
> It looks alright, except that gdb/config/arm/wince.mt and
> gdb/arm-wince-tdep.c
> (to add solib-target.c, and remove the svr4 copy/paste thinko) hunks
> got left out.
>
Testing on Windows CE didn't show up any new problems.
Attached are the patches to use solib-target.c on WinCE, and a small fix to
gdbserver/win32-low.c to get toolhelp from toolhelp.dll instead
of coredll.dll - not your fault, the version I sent you had it wrong.
I had a problem building solib-target.c that I'm reporting in
another thread.
gdb/
* arm-wince-tdep.c (arm_wince_init_abi): Remove svr4 related calls.
* config/arm/wince.mt (TDEPFILES): Remove solib-legacy.o and
solib-svr4.o, and add solib-target.o
gdb/gdbserver/
* win32-low.c (load_toolhelp) [_WIN32_WCE]: Load functions from
TOOLHELP.DLL.
--
Cheers,
Pedro Alves
[-- Attachment #2: wince_solib-target.diff --]
[-- Type: text/x-diff, Size: 1353 bytes --]
* arm-wince-tdep.c (arm_wince_init_abi): Remove svr4 related calls.
* config/arm/wince.mt (TDEPFILES): Remove solib-legacy.o and
solib-svr4.o, and add solib-target.o
---
gdb/arm-wince-tdep.c | 3 ---
gdb/config/arm/wince.mt | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
Index: src/gdb/arm-wince-tdep.c
===================================================================
--- src.orig/gdb/arm-wince-tdep.c 2007-07-03 20:49:54.000000000 +0100
+++ src/gdb/arm-wince-tdep.c 2007-07-04 00:56:52.000000000 +0100
@@ -55,9 +55,6 @@ arm_wince_init_abi (struct gdbarch_info
/* On ARM WinCE char defaults to signed. */
set_gdbarch_char_signed (gdbarch, 1);
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, svr4_ilp32_fetch_link_map_offsets);
-
/* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
Index: src/gdb/config/arm/wince.mt
===================================================================
--- src.orig/gdb/config/arm/wince.mt 2007-07-03 20:49:54.000000000 +0100
+++ src/gdb/config/arm/wince.mt 2007-07-04 00:55:54.000000000 +0100
@@ -1,4 +1,4 @@
# Target: ARM based machine running Windows CE (win32)
DEPRECATED_TM_FILE= tm-arm.h
TDEPFILES= arm-tdep.o arm-wince-tdep.o corelow.o \
- solib.o solib-legacy.o solib-svr4.o
+ solib.o solib-target.o
[-- Attachment #3: gdbserver_wince.diff --]
[-- Type: text/x-diff, Size: 679 bytes --]
* win32-low.c (load_toolhelp) [_WIN32_WCE]: Load functions from
TOOLHELP.DLL.
---
gdb/gdbserver/win32-low.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: src/gdb/gdbserver/win32-low.c
===================================================================
--- src.orig/gdb/gdbserver/win32-low.c 2007-07-08 00:49:34.000000000 +0100
+++ src/gdb/gdbserver/win32-low.c 2007-07-08 00:52:44.000000000 +0100
@@ -985,7 +985,7 @@ load_toolhelp (void)
#ifndef _WIN32_WCE
dll = GetModuleHandle (_T("KERNEL32.DLL"));
#else
- dll = GetModuleHandle (_T("COREDLL.DLL"));
+ dll = LoadLibrary (_T("TOOLHELP.DLL"));
#endif
if (!dll)
return FALSE;
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [rfc] DLL support for gdbserver
2007-07-08 1:21 ` Pedro Alves
@ 2007-07-08 14:46 ` Pedro Alves
0 siblings, 0 replies; 7+ messages in thread
From: Pedro Alves @ 2007-07-08 14:46 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
Pedro Alves wrote:
> Attached are the patches to use solib-target.c on WinCE, and a small fix to
> gdbserver/win32-low.c to get toolhelp from toolhelp.dll instead
> of coredll.dll - not your fault, the version I sent you had it wrong.
>
And testing on a different device showed up something I never
noticed before. On WinCE a toolhelp snapshot is closed with
CloseToolhelp32Snapshot, while on desktop Windows, one closes
it with CloseHandle. It is documented as producing a leak if the
wrong Close function is used, but I found it crashing on this
device ...
Sorry, I'm starting to hijack the thread. It would be less work
for both of us to keep the patches separate. I can post the
WinCE parts again in a new thread after this has gone in.
Cheers,
Pedro Alves
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [rfc] DLL support for gdbserver
2007-07-04 9:39 ` Pedro Alves
2007-07-08 1:21 ` Pedro Alves
@ 2007-07-17 12:54 ` Daniel Jacobowitz
2007-07-20 14:35 ` Pedro Alves
1 sibling, 1 reply; 7+ messages in thread
From: Daniel Jacobowitz @ 2007-07-17 12:54 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Wed, Jul 04, 2007 at 10:38:56AM +0100, Pedro Alves wrote:
> It looks alright, except that gdb/config/arm/wince.mt and gdb/arm-wince-tdep.c
> (to add solib-target.c, and remove the svr4 copy/paste thinko) hunks
> got left out.
Hi Pedro,
I've checked this in, since we're still sorting out GPLv3 issues for
the branch. If you can post the WinCE fixups in the next couple of
weeks, I'm sure we can get them included in GDB 6.7. Thanks for all
your help with this.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [rfc] DLL support for gdbserver
2007-07-17 12:54 ` Daniel Jacobowitz
@ 2007-07-20 14:35 ` Pedro Alves
0 siblings, 0 replies; 7+ messages in thread
From: Pedro Alves @ 2007-07-20 14:35 UTC (permalink / raw)
To: gdb-patches
Daniel Jacobowitz wrote:
> On Wed, Jul 04, 2007 at 10:38:56AM +0100, Pedro Alves wrote:
>> It looks alright, except that gdb/config/arm/wince.mt and gdb/arm-wince-tdep.c
>> (to add solib-target.c, and remove the svr4 copy/paste thinko) hunks
>> got left out.
>
> Hi Pedro,
>
> I've checked this in, since we're still sorting out GPLv3 issues for
> the branch. If you can post the WinCE fixups in the next couple of
> weeks, I'm sure we can get them included in GDB 6.7. Thanks for all
> your help with this.
>
OK.
I'll post it in a week, when I get back from vacation.
Thanks.
Cheers,
Pedro Alves
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [rfc] DLL support for gdbserver
2007-07-02 22:12 [rfc] DLL support for gdbserver Daniel Jacobowitz
2007-07-04 9:39 ` Pedro Alves
@ 2007-07-04 17:27 ` Joel Brobecker
1 sibling, 0 replies; 7+ messages in thread
From: Joel Brobecker @ 2007-07-04 17:27 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
> Here's a final version of gdbserver support for Windows DLLs.
> It works for me testing with Cygwin. Pedro, would you like to test
> this on Windows CE to see what I've broken?
Looks like we're very close to have DLL support with gdbserver.
Should we delay the branch to try to get this in, or is the change
considered a bit risky? I feel like 6.7 will be packed with new
features no matter what, but this would probably be nice to have
regardless of that.
--
Joel
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-07-20 13:50 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-02 22:12 [rfc] DLL support for gdbserver Daniel Jacobowitz
2007-07-04 9:39 ` Pedro Alves
2007-07-08 1:21 ` Pedro Alves
2007-07-08 14:46 ` Pedro Alves
2007-07-17 12:54 ` Daniel Jacobowitz
2007-07-20 14:35 ` Pedro Alves
2007-07-04 17:27 ` Joel Brobecker
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox