2007-07-17 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. * 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. * 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.
This commit is contained in:
parent
a8c50c1f55
commit
255e7678a9
13 changed files with 636 additions and 43 deletions
|
@ -1,3 +1,11 @@
|
|||
2007-07-17 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-17 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* dwarf2read.c (dwarf_decode_lines): Detect address size mismatches.
|
||||
|
|
3
gdb/NEWS
3
gdb/NEWS
|
@ -54,6 +54,9 @@ packet, this response allows GDB to debug shared libraries on targets
|
|||
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
|
||||
|
|
|
@ -309,9 +309,6 @@ read_pe_exported_syms (struct objfile *objfile)
|
|||
+= 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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,32 @@
|
|||
2007-07-17 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.
|
||||
|
||||
2007-07-12 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* configure.srv: Set srv_linux_regsets for sh*-*-linux*.
|
||||
|
|
|
@ -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 *list,
|
|||
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 *thread)
|
|||
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 thread_info *inferior, void *data)
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -965,6 +965,13 @@ prepare_resume_reply (char *buf, char status, unsigned char sig)
|
|||
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;
|
||||
|
@ -1172,3 +1179,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;
|
||||
}
|
||||
|
|
|
@ -458,12 +458,80 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
|||
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 *status, int *signal)
|
|||
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
|
||||
{
|
||||
|
|
|
@ -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 thread_info *, void *);
|
|||
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, CORE_ADDR *addrp);
|
|||
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
@ -772,6 +773,316 @@ win32_resume (struct thread_resume *resume_info)
|
|||
child_continue (continue_status, tid);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -963,9 +1274,10 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
|
|||
(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:
|
||||
|
@ -973,6 +1285,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
|
|||
"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:
|
||||
|
@ -1035,6 +1350,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));
|
||||
|
||||
|
@ -1042,12 +1358,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);
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2007-07-17 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-03 Markus Deuling <deuling@de.ibm.com>
|
||||
|
||||
* gdb.base/solib-symbol.exp: New file (testcase multiple symbol lookup).
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
Loading…
Reference in a new issue