* win32-nat.c (safe_symbol_file_add_cleanup): Ensure that gdb_stderr is flushed
before deleting and restoring it. (safe_symbol_file_add): Ensure that gdb_stderr is flushed before reassigning it. (handle_load_dll): Split into two functions so that WFI can handle shared library events. (child_solib_loaded_library_pathname): New function. (child_clear_solibs): New function. Clears shared library list. (child_solib_add): New function. Adds shared library symbols. (dll_symbol_command): New function. Handles "dll-symbol" command. (info_dll_command): New function. Handles info "sharedlibrary" command. (handle_exceptions): Eliminate 'ignore_trap' argument. (get_child_debug_event): Eliminate two arguments. Return "pid" when appropriate. Break out on most events to allow WFI to handle stuff. (child_wait): Accomodate get_child_debug_event changes. (child_attach): Clear thread list and list of loaded dlls. (child_create_inferior): Clear list of loaded dlls. Use wait_for_inferior in a loop to look for first "trap". (child_resume): Avoid accessing a possibly-freed thread pointer. (_initialize_inftarg): Add "dll-symbols", "sharedlibrary", and "info dll", and "info sharedlibrary" commands. * config/i386/tm-cygwin.h: Add some shared library (aka DLL) hooks.
This commit is contained in:
parent
969e1a7b86
commit
450005e7c2
|
@ -1,3 +1,29 @@
|
|||
2000-06-03 Christopher Faylor <cgf@cygnus.com>
|
||||
|
||||
* win32-nat.c (safe_symbol_file_add_cleanup): Ensure that gdb_stderr is
|
||||
flushed before deleting and restoring it.
|
||||
(safe_symbol_file_add): Ensure that gdb_stderr is flushed before
|
||||
reassigning it.
|
||||
(handle_load_dll): Split into two functions so that WFI can handle
|
||||
shared library events.
|
||||
(child_solib_loaded_library_pathname): New function.
|
||||
(child_clear_solibs): New function. Clears shared library list.
|
||||
(child_solib_add): New function. Adds shared library symbols.
|
||||
(dll_symbol_command): New function. Handles "dll-symbol" command.
|
||||
(info_dll_command): New function. Handles info
|
||||
"sharedlibrary" command.
|
||||
(handle_exceptions): Eliminate 'ignore_trap' argument.
|
||||
(get_child_debug_event): Eliminate two arguments. Return "pid" when
|
||||
appropriate. Break out on most events to allow WFI to handle stuff.
|
||||
(child_wait): Accomodate get_child_debug_event changes.
|
||||
(child_attach): Clear thread list and list of loaded dlls.
|
||||
(child_create_inferior): Clear list of loaded dlls. Use
|
||||
wait_for_inferior in a loop to look for first "trap".
|
||||
(child_resume): Avoid accessing a possibly-freed thread pointer.
|
||||
(_initialize_inftarg): Add "dll-symbols", "sharedlibrary", and "info
|
||||
sharedlibrary" commands.
|
||||
* config/i386/tm-cygwin.h: Add some shared library (aka DLL) hooks.
|
||||
|
||||
2000-06-02 Christopher Faylor <cgf@cygnus.com>
|
||||
|
||||
* win32-nat.c: Fix up gcc warnings throughout.
|
||||
|
|
|
@ -24,8 +24,20 @@
|
|||
|
||||
#include "i386/tm-i386v.h"
|
||||
|
||||
#if 0
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) skip_trampoline_code (pc, name)
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) skip_trampoline_code (pc, 0)
|
||||
extern CORE_ADDR skip_trampoline_code (CORE_ADDR pc, char *name);
|
||||
#endif
|
||||
|
||||
extern char *cygwin_pid_to_str (int pid);
|
||||
#define SOLIB_ADD(filename, from_tty, targ) child_solib_add(filename, from_tty, targ)
|
||||
#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) child_solib_loaded_library_pathname(pid)
|
||||
#define CLEAR_SOLIB child_clear_solib
|
||||
#define ADD_SHARED_SYMBOL_FILES dll_symbol_command
|
||||
|
||||
struct target_ops;
|
||||
char *cygwin_pid_to_str (int pid);
|
||||
void child_solib_add (char *, int, struct target_ops *);
|
||||
char *child_solib_loaded_library_pathname(int);
|
||||
void child_clear_solib (void);
|
||||
void dll_symbol_command (char *, int);
|
||||
|
|
218
gdb/win32-nat.c
218
gdb/win32-nat.c
|
@ -58,8 +58,6 @@ extern int (*ui_loop_hook) PARAMS ((int signo));
|
|||
#define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
|
||||
#endif
|
||||
|
||||
#define FIRST_EXCEPTION 0xffffffff
|
||||
|
||||
/* The string sent by cygwin when it processes a signal.
|
||||
FIXME: This should be in a cygwin include file. */
|
||||
#define CYGWIN_SIGNAL_STRING "cygwin: signal"
|
||||
|
@ -415,6 +413,8 @@ failed:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Encapsulate the information required in a call to
|
||||
symbol_file_add_args */
|
||||
struct safe_symbol_file_add_args
|
||||
{
|
||||
char *name;
|
||||
|
@ -425,6 +425,8 @@ struct safe_symbol_file_add_args
|
|||
struct objfile *ret;
|
||||
};
|
||||
|
||||
/* Call symbol_file_add with stderr redirected. We don't care if there
|
||||
are errors. */
|
||||
static int
|
||||
safe_symbol_file_add_stub (void *argv)
|
||||
{
|
||||
|
@ -434,13 +436,16 @@ safe_symbol_file_add_stub (void *argv)
|
|||
#undef p
|
||||
}
|
||||
|
||||
/* Restore gdb's stderr after calling symbol_file_add */
|
||||
static void
|
||||
safe_symbol_file_add_cleanup (void *gdb_stderrv)
|
||||
{
|
||||
gdb_flush (gdb_stderr);
|
||||
ui_file_delete (gdb_stderr);
|
||||
gdb_stderr = (struct ui_file *)gdb_stderrv;
|
||||
}
|
||||
|
||||
/* symbol_file_add wrapper that prevents errors from being displayed. */
|
||||
static struct objfile *
|
||||
safe_symbol_file_add (char *name, int from_tty,
|
||||
struct section_addr_info *addrs,
|
||||
|
@ -452,6 +457,7 @@ safe_symbol_file_add (char *name, int from_tty,
|
|||
|
||||
cleanup = make_cleanup (safe_symbol_file_add_cleanup, gdb_stderr);
|
||||
|
||||
gdb_flush (gdb_stderr);
|
||||
gdb_stderr = ui_file_new ();
|
||||
p.name = name;
|
||||
p.from_tty = from_tty;
|
||||
|
@ -464,9 +470,19 @@ safe_symbol_file_add (char *name, int from_tty,
|
|||
return p.ret;
|
||||
}
|
||||
|
||||
/* Maintain a linked list of "so" information. */
|
||||
struct so_stuff
|
||||
{
|
||||
struct so_stuff *next, **last;
|
||||
DWORD load_addr;
|
||||
char name[0];
|
||||
} solib_start, *solib_end;
|
||||
|
||||
/* Remember the maximum DLL length for printing in info dll command. */
|
||||
int max_dll_name_len;
|
||||
|
||||
/* Wait for child to do something. Return pid of child, or -1 in case
|
||||
of error; store status through argument pointer OURSTATUS. */
|
||||
|
||||
static int
|
||||
handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
|
||||
{
|
||||
|
@ -474,10 +490,12 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
|
|||
DWORD dll_name_ptr;
|
||||
DWORD done;
|
||||
char dll_buf[MAX_PATH + 1];
|
||||
char *p, *dll_name = NULL;
|
||||
struct section_addr_info section_addrs;
|
||||
struct so_stuff *so, *solast;
|
||||
char *dll_name = NULL;
|
||||
DWORD dll_base = 0;
|
||||
int len;
|
||||
char *p;
|
||||
|
||||
memset (§ion_addrs, 0, sizeof (section_addrs));
|
||||
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
|
||||
|
||||
if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
|
||||
|
@ -549,16 +567,94 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
|
|||
while ((p = strchr (dll_name, '\\')))
|
||||
*p = '/';
|
||||
|
||||
so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (dll_name) + 8 + 2);
|
||||
so->load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
|
||||
strcpy (so->name, dll_name);
|
||||
|
||||
solib_end->next = so;
|
||||
solib_end = so;
|
||||
so->next = NULL;
|
||||
|
||||
len = strlen (dll_name);
|
||||
if (len > max_dll_name_len)
|
||||
max_dll_name_len = len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return name of last loaded DLL. */
|
||||
char *
|
||||
child_solib_loaded_library_pathname (int pid)
|
||||
{
|
||||
return !solib_end || !solib_end->name[0]? NULL : solib_end->name;
|
||||
}
|
||||
|
||||
/* Clear list of loaded DLLs. */
|
||||
void
|
||||
child_clear_solibs (void)
|
||||
{
|
||||
struct so_stuff *so, *so1 = solib_start.next;
|
||||
|
||||
while ((so = so1) != NULL)
|
||||
{
|
||||
so1 = so->next;
|
||||
free (so);
|
||||
}
|
||||
|
||||
solib_start.next = NULL;
|
||||
solib_end = &solib_start;
|
||||
max_dll_name_len = sizeof ("DLL Name") - 1;
|
||||
}
|
||||
|
||||
/* Add DLL symbol information. */
|
||||
void
|
||||
child_solib_add (char *filename, int from_tty, struct target_ops *t)
|
||||
{
|
||||
struct section_addr_info section_addrs;
|
||||
|
||||
/* 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. */
|
||||
|
||||
section_addrs.other[0].name = ".text";
|
||||
section_addrs.other[0].addr = (int) event->lpBaseOfDll + 0x1000;
|
||||
safe_symbol_file_add (dll_name, 0, §ion_addrs, 0, OBJF_SHARED);
|
||||
printf_unfiltered ("%lx:%s\n", (DWORD) event->lpBaseOfDll, dll_name);
|
||||
if (!solib_end || !solib_end->name[0])
|
||||
return;
|
||||
|
||||
return 1;
|
||||
memset (§ion_addrs, 0, sizeof (section_addrs));
|
||||
section_addrs.other[0].name = ".text";
|
||||
section_addrs.other[0].addr = solib_end->load_addr;
|
||||
safe_symbol_file_add (solib_end->name, 0, §ion_addrs, 0, OBJF_SHARED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load DLL symbol info. */
|
||||
void
|
||||
dll_symbol_command (char *args, int from_tty)
|
||||
{
|
||||
struct section_addr_info section_addrs;
|
||||
|
||||
dont_repeat ();
|
||||
|
||||
if (args == NULL)
|
||||
error ("dll-symbols requires a file name");
|
||||
|
||||
safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED);
|
||||
}
|
||||
|
||||
/* List currently loaded DLLs. */
|
||||
void
|
||||
info_dll_command (char *ignore, int from_tty)
|
||||
{
|
||||
struct so_stuff *so = &solib_start;
|
||||
|
||||
if (!so->next)
|
||||
return;
|
||||
|
||||
printf ("%*s Load Address\n", -max_dll_name_len, "DLL Name");
|
||||
while ((so = so->next) != NULL)
|
||||
printf_unfiltered ("%*s %08lx\n", -max_dll_name_len, so->name, so->load_addr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle DEBUG_STRING output from child process.
|
||||
|
@ -595,14 +691,11 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
|
|||
}
|
||||
|
||||
static int
|
||||
handle_exception (struct target_waitstatus *ourstatus, int ignore_trap)
|
||||
handle_exception (struct target_waitstatus *ourstatus)
|
||||
{
|
||||
thread_info *th;
|
||||
DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
|
||||
|
||||
if (ignore_trap && code == EXCEPTION_BREAKPOINT)
|
||||
return 0;
|
||||
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
|
||||
/* Record the context of the current thread */
|
||||
|
@ -696,16 +789,15 @@ child_continue (DWORD continue_status, int id)
|
|||
handling by WFI (or whatever).
|
||||
*/
|
||||
static int
|
||||
get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus,
|
||||
DWORD target_event_code, int *retval)
|
||||
get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus)
|
||||
{
|
||||
int breakout = 0;
|
||||
BOOL debug_event;
|
||||
DWORD continue_status, event_code;
|
||||
thread_info *th = NULL;
|
||||
static thread_info dummy_thread_info;
|
||||
int retval = 0;
|
||||
|
||||
*retval = 0;
|
||||
if (!(debug_event = WaitForDebugEvent (¤t_event, 1000)))
|
||||
goto out;
|
||||
|
||||
|
@ -713,7 +805,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
continue_status = DBG_CONTINUE;
|
||||
|
||||
event_code = current_event.dwDebugEventCode;
|
||||
breakout = event_code == target_event_code;
|
||||
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
||||
|
||||
switch (event_code)
|
||||
{
|
||||
|
@ -728,6 +820,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
if (info_verbose)
|
||||
printf_unfiltered ("[New %s]\n",
|
||||
target_pid_to_str (current_event.dwThreadId));
|
||||
retval = current_event.dwThreadId;
|
||||
break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
|
@ -748,8 +841,11 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
|
||||
main_thread_id = inferior_pid = current_event.dwThreadId;
|
||||
/* Add the main thread */
|
||||
th = child_add_thread (current_event.dwProcessId,
|
||||
current_event.u.CreateProcessInfo.hProcess);
|
||||
th = child_add_thread (inferior_pid,
|
||||
current_event.u.CreateProcessInfo.hThread);
|
||||
retval = ourstatus->value.related_pid = current_event.dwProcessId;
|
||||
break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
|
@ -760,8 +856,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
ourstatus->kind = TARGET_WAITKIND_EXITED;
|
||||
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
|
||||
CloseHandle (current_process_handle);
|
||||
*retval = current_event.dwProcessId;
|
||||
breakout = 1;
|
||||
retval = current_event.dwProcessId;
|
||||
break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
|
@ -771,6 +866,9 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
"LOAD_DLL_DEBUG_EVENT"));
|
||||
catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
|
||||
registers_changed (); /* mark all regs invalid */
|
||||
ourstatus->kind = TARGET_WAITKIND_LOADED;
|
||||
ourstatus->value.integer = 0;
|
||||
retval = current_event.dwProcessId;
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
|
@ -785,10 +883,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
(unsigned) current_event.dwProcessId,
|
||||
(unsigned) current_event.dwThreadId,
|
||||
"EXCEPTION_DEBUG_EVENT"));
|
||||
if (handle_exception (ourstatus, target_event_code == FIRST_EXCEPTION))
|
||||
*retval = current_event.dwThreadId;
|
||||
else
|
||||
breakout = -1;
|
||||
handle_exception (ourstatus);
|
||||
retval = current_event.dwThreadId;
|
||||
break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
|
||||
|
@ -796,7 +892,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
(unsigned) current_event.dwProcessId,
|
||||
(unsigned) current_event.dwThreadId,
|
||||
"OUTPUT_DEBUG_STRING_EVENT"));
|
||||
handle_output_debug_string ( ourstatus);
|
||||
if (handle_output_debug_string ( ourstatus))
|
||||
retval = current_event.dwProcessId;
|
||||
break;
|
||||
default:
|
||||
printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n",
|
||||
|
@ -807,21 +904,19 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
break;
|
||||
}
|
||||
|
||||
if (breakout > 0)
|
||||
current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
|
||||
else if (!breakout)
|
||||
if (!retval)
|
||||
CHECK (child_continue (continue_status, -1));
|
||||
else
|
||||
current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
|
||||
|
||||
out:
|
||||
return breakout;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Wait for interesting events to occur in the target process. */
|
||||
static int
|
||||
child_wait (int pid, struct target_waitstatus *ourstatus)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* We loop when we get a non-standard exception rather than return
|
||||
with a SPURIOUS because resume can try and step or modify things,
|
||||
which needs a current_thread->h. But some of these exceptions mark
|
||||
|
@ -829,7 +924,9 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
|
|||
isn't necessarily what you think it is. */
|
||||
|
||||
while (1)
|
||||
if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
|
||||
{
|
||||
int retval = get_child_debug_event (pid, ourstatus);
|
||||
if (retval)
|
||||
return retval;
|
||||
else
|
||||
{
|
||||
|
@ -841,6 +938,7 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
|
|||
if (detach)
|
||||
child_kill_inferior ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attach to process PID, then initialize for debugging it. */
|
||||
|
@ -865,6 +963,9 @@ child_attach (args, from_tty)
|
|||
exception_count = 0;
|
||||
event_count = 0;
|
||||
|
||||
child_init_thread_list ();
|
||||
child_clear_solibs ();
|
||||
|
||||
if (from_tty)
|
||||
{
|
||||
char *exec_file = (char *) get_exec_file (0);
|
||||
|
@ -936,11 +1037,10 @@ child_create_inferior (exec_file, allargs, env)
|
|||
BOOL ret;
|
||||
DWORD flags;
|
||||
char *args;
|
||||
extern int stop_after_trap;
|
||||
|
||||
if (!exec_file)
|
||||
{
|
||||
error ("No executable specified, use `target exec'.\n");
|
||||
}
|
||||
|
||||
memset (&si, 0, sizeof (si));
|
||||
si.cb = sizeof (si);
|
||||
|
@ -1057,16 +1157,23 @@ child_create_inferior (exec_file, allargs, env)
|
|||
inferior_pid = current_event.dwThreadId = pi.dwThreadId;
|
||||
push_target (&child_ops);
|
||||
child_init_thread_list ();
|
||||
init_wait_for_inferior ();
|
||||
child_clear_solibs ();
|
||||
clear_proceed_status ();
|
||||
init_wait_for_inferior ();
|
||||
target_terminal_init ();
|
||||
target_terminal_inferior ();
|
||||
last_sig = 0;
|
||||
|
||||
/* Run until process and threads are loaded */
|
||||
while (!get_child_debug_event (inferior_pid, &dummy,
|
||||
FIRST_EXCEPTION, &ret))
|
||||
continue;
|
||||
while (1)
|
||||
{
|
||||
stop_after_trap = 1;
|
||||
wait_for_inferior ();
|
||||
if (stop_signal != TARGET_SIGNAL_TRAP)
|
||||
resume (0, stop_signal);
|
||||
else
|
||||
break;
|
||||
}
|
||||
stop_after_trap = 0;
|
||||
|
||||
/* child_continue (DBG_CONTINUE, -1);*/
|
||||
proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
|
||||
|
@ -1150,13 +1257,13 @@ child_resume (int pid, int step, enum target_signal sig)
|
|||
|
||||
/* Get context for currently selected thread */
|
||||
th = thread_rec (current_event.dwThreadId, FALSE);
|
||||
if (th)
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
#ifdef i386
|
||||
/* Single step by setting t bit */
|
||||
child_fetch_inferior_registers (PS_REGNUM);
|
||||
th->context.EFlags |= FLAG_TRACE_BIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (th->context.ContextFlags)
|
||||
|
@ -1164,6 +1271,7 @@ child_resume (int pid, int step, enum target_signal sig)
|
|||
CHECK (SetThreadContext (th->h, &th->context));
|
||||
th->context.ContextFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow continuing with the same signal that interrupted us.
|
||||
Otherwise complain. */
|
||||
|
@ -1242,48 +1350,50 @@ _initialize_inftarg ()
|
|||
{
|
||||
init_child_ops ();
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("new-console", class_support, var_boolean,
|
||||
add_com ("dll-symbols", class_files, dll_symbol_command,
|
||||
"Load dll library symbols from FILE.");
|
||||
|
||||
add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
|
||||
|
||||
add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
|
||||
(char *) &new_console,
|
||||
"Set creation of new console when creating child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("new-group", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
|
||||
(char *) &new_group,
|
||||
"Set creation of new group when creating child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugexec", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
|
||||
(char *) &debug_exec,
|
||||
"Set whether to display execution in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugevents", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
|
||||
(char *) &debug_events,
|
||||
"Set whether to display kernel events in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugmemory", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
|
||||
(char *) &debug_memory,
|
||||
"Set whether to display memory accesses in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugexceptions", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
|
||||
(char *) &debug_exceptions,
|
||||
"Set whether to display kernel exceptions in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_info ("dll", info_dll_command, "Status of loaded DLLs.");
|
||||
add_info_alias ("sharedlibrary", "dll", 1);
|
||||
|
||||
add_target (&child_ops);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,6 @@ extern int (*ui_loop_hook) PARAMS ((int signo));
|
|||
#define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
|
||||
#endif
|
||||
|
||||
#define FIRST_EXCEPTION 0xffffffff
|
||||
|
||||
/* The string sent by cygwin when it processes a signal.
|
||||
FIXME: This should be in a cygwin include file. */
|
||||
#define CYGWIN_SIGNAL_STRING "cygwin: signal"
|
||||
|
@ -415,6 +413,8 @@ failed:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Encapsulate the information required in a call to
|
||||
symbol_file_add_args */
|
||||
struct safe_symbol_file_add_args
|
||||
{
|
||||
char *name;
|
||||
|
@ -425,6 +425,8 @@ struct safe_symbol_file_add_args
|
|||
struct objfile *ret;
|
||||
};
|
||||
|
||||
/* Call symbol_file_add with stderr redirected. We don't care if there
|
||||
are errors. */
|
||||
static int
|
||||
safe_symbol_file_add_stub (void *argv)
|
||||
{
|
||||
|
@ -434,13 +436,16 @@ safe_symbol_file_add_stub (void *argv)
|
|||
#undef p
|
||||
}
|
||||
|
||||
/* Restore gdb's stderr after calling symbol_file_add */
|
||||
static void
|
||||
safe_symbol_file_add_cleanup (void *gdb_stderrv)
|
||||
{
|
||||
gdb_flush (gdb_stderr);
|
||||
ui_file_delete (gdb_stderr);
|
||||
gdb_stderr = (struct ui_file *)gdb_stderrv;
|
||||
}
|
||||
|
||||
/* symbol_file_add wrapper that prevents errors from being displayed. */
|
||||
static struct objfile *
|
||||
safe_symbol_file_add (char *name, int from_tty,
|
||||
struct section_addr_info *addrs,
|
||||
|
@ -452,6 +457,7 @@ safe_symbol_file_add (char *name, int from_tty,
|
|||
|
||||
cleanup = make_cleanup (safe_symbol_file_add_cleanup, gdb_stderr);
|
||||
|
||||
gdb_flush (gdb_stderr);
|
||||
gdb_stderr = ui_file_new ();
|
||||
p.name = name;
|
||||
p.from_tty = from_tty;
|
||||
|
@ -464,9 +470,19 @@ safe_symbol_file_add (char *name, int from_tty,
|
|||
return p.ret;
|
||||
}
|
||||
|
||||
/* Maintain a linked list of "so" information. */
|
||||
struct so_stuff
|
||||
{
|
||||
struct so_stuff *next, **last;
|
||||
DWORD load_addr;
|
||||
char name[0];
|
||||
} solib_start, *solib_end;
|
||||
|
||||
/* Remember the maximum DLL length for printing in info dll command. */
|
||||
int max_dll_name_len;
|
||||
|
||||
/* Wait for child to do something. Return pid of child, or -1 in case
|
||||
of error; store status through argument pointer OURSTATUS. */
|
||||
|
||||
static int
|
||||
handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
|
||||
{
|
||||
|
@ -474,10 +490,12 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
|
|||
DWORD dll_name_ptr;
|
||||
DWORD done;
|
||||
char dll_buf[MAX_PATH + 1];
|
||||
char *p, *dll_name = NULL;
|
||||
struct section_addr_info section_addrs;
|
||||
struct so_stuff *so, *solast;
|
||||
char *dll_name = NULL;
|
||||
DWORD dll_base = 0;
|
||||
int len;
|
||||
char *p;
|
||||
|
||||
memset (§ion_addrs, 0, sizeof (section_addrs));
|
||||
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
|
||||
|
||||
if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
|
||||
|
@ -549,16 +567,94 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
|
|||
while ((p = strchr (dll_name, '\\')))
|
||||
*p = '/';
|
||||
|
||||
so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (dll_name) + 8 + 2);
|
||||
so->load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
|
||||
strcpy (so->name, dll_name);
|
||||
|
||||
solib_end->next = so;
|
||||
solib_end = so;
|
||||
so->next = NULL;
|
||||
|
||||
len = strlen (dll_name);
|
||||
if (len > max_dll_name_len)
|
||||
max_dll_name_len = len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return name of last loaded DLL. */
|
||||
char *
|
||||
child_solib_loaded_library_pathname (int pid)
|
||||
{
|
||||
return !solib_end || !solib_end->name[0]? NULL : solib_end->name;
|
||||
}
|
||||
|
||||
/* Clear list of loaded DLLs. */
|
||||
void
|
||||
child_clear_solibs (void)
|
||||
{
|
||||
struct so_stuff *so, *so1 = solib_start.next;
|
||||
|
||||
while ((so = so1) != NULL)
|
||||
{
|
||||
so1 = so->next;
|
||||
free (so);
|
||||
}
|
||||
|
||||
solib_start.next = NULL;
|
||||
solib_end = &solib_start;
|
||||
max_dll_name_len = sizeof ("DLL Name") - 1;
|
||||
}
|
||||
|
||||
/* Add DLL symbol information. */
|
||||
void
|
||||
child_solib_add (char *filename, int from_tty, struct target_ops *t)
|
||||
{
|
||||
struct section_addr_info section_addrs;
|
||||
|
||||
/* 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. */
|
||||
|
||||
section_addrs.other[0].name = ".text";
|
||||
section_addrs.other[0].addr = (int) event->lpBaseOfDll + 0x1000;
|
||||
safe_symbol_file_add (dll_name, 0, §ion_addrs, 0, OBJF_SHARED);
|
||||
printf_unfiltered ("%lx:%s\n", (DWORD) event->lpBaseOfDll, dll_name);
|
||||
if (!solib_end || !solib_end->name[0])
|
||||
return;
|
||||
|
||||
return 1;
|
||||
memset (§ion_addrs, 0, sizeof (section_addrs));
|
||||
section_addrs.other[0].name = ".text";
|
||||
section_addrs.other[0].addr = solib_end->load_addr;
|
||||
safe_symbol_file_add (solib_end->name, 0, §ion_addrs, 0, OBJF_SHARED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load DLL symbol info. */
|
||||
void
|
||||
dll_symbol_command (char *args, int from_tty)
|
||||
{
|
||||
struct section_addr_info section_addrs;
|
||||
|
||||
dont_repeat ();
|
||||
|
||||
if (args == NULL)
|
||||
error ("dll-symbols requires a file name");
|
||||
|
||||
safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED);
|
||||
}
|
||||
|
||||
/* List currently loaded DLLs. */
|
||||
void
|
||||
info_dll_command (char *ignore, int from_tty)
|
||||
{
|
||||
struct so_stuff *so = &solib_start;
|
||||
|
||||
if (!so->next)
|
||||
return;
|
||||
|
||||
printf ("%*s Load Address\n", -max_dll_name_len, "DLL Name");
|
||||
while ((so = so->next) != NULL)
|
||||
printf_unfiltered ("%*s %08lx\n", -max_dll_name_len, so->name, so->load_addr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle DEBUG_STRING output from child process.
|
||||
|
@ -595,14 +691,11 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
|
|||
}
|
||||
|
||||
static int
|
||||
handle_exception (struct target_waitstatus *ourstatus, int ignore_trap)
|
||||
handle_exception (struct target_waitstatus *ourstatus)
|
||||
{
|
||||
thread_info *th;
|
||||
DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
|
||||
|
||||
if (ignore_trap && code == EXCEPTION_BREAKPOINT)
|
||||
return 0;
|
||||
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
|
||||
/* Record the context of the current thread */
|
||||
|
@ -696,16 +789,15 @@ child_continue (DWORD continue_status, int id)
|
|||
handling by WFI (or whatever).
|
||||
*/
|
||||
static int
|
||||
get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus,
|
||||
DWORD target_event_code, int *retval)
|
||||
get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus)
|
||||
{
|
||||
int breakout = 0;
|
||||
BOOL debug_event;
|
||||
DWORD continue_status, event_code;
|
||||
thread_info *th = NULL;
|
||||
static thread_info dummy_thread_info;
|
||||
int retval = 0;
|
||||
|
||||
*retval = 0;
|
||||
if (!(debug_event = WaitForDebugEvent (¤t_event, 1000)))
|
||||
goto out;
|
||||
|
||||
|
@ -713,7 +805,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
continue_status = DBG_CONTINUE;
|
||||
|
||||
event_code = current_event.dwDebugEventCode;
|
||||
breakout = event_code == target_event_code;
|
||||
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
||||
|
||||
switch (event_code)
|
||||
{
|
||||
|
@ -728,6 +820,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
if (info_verbose)
|
||||
printf_unfiltered ("[New %s]\n",
|
||||
target_pid_to_str (current_event.dwThreadId));
|
||||
retval = current_event.dwThreadId;
|
||||
break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
|
@ -748,8 +841,11 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
|
||||
main_thread_id = inferior_pid = current_event.dwThreadId;
|
||||
/* Add the main thread */
|
||||
th = child_add_thread (current_event.dwProcessId,
|
||||
current_event.u.CreateProcessInfo.hProcess);
|
||||
th = child_add_thread (inferior_pid,
|
||||
current_event.u.CreateProcessInfo.hThread);
|
||||
retval = ourstatus->value.related_pid = current_event.dwProcessId;
|
||||
break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
|
@ -760,8 +856,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
ourstatus->kind = TARGET_WAITKIND_EXITED;
|
||||
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
|
||||
CloseHandle (current_process_handle);
|
||||
*retval = current_event.dwProcessId;
|
||||
breakout = 1;
|
||||
retval = current_event.dwProcessId;
|
||||
break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
|
@ -771,6 +866,9 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
"LOAD_DLL_DEBUG_EVENT"));
|
||||
catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
|
||||
registers_changed (); /* mark all regs invalid */
|
||||
ourstatus->kind = TARGET_WAITKIND_LOADED;
|
||||
ourstatus->value.integer = 0;
|
||||
retval = current_event.dwProcessId;
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
|
@ -785,10 +883,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
(unsigned) current_event.dwProcessId,
|
||||
(unsigned) current_event.dwThreadId,
|
||||
"EXCEPTION_DEBUG_EVENT"));
|
||||
if (handle_exception (ourstatus, target_event_code == FIRST_EXCEPTION))
|
||||
*retval = current_event.dwThreadId;
|
||||
else
|
||||
breakout = -1;
|
||||
handle_exception (ourstatus);
|
||||
retval = current_event.dwThreadId;
|
||||
break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
|
||||
|
@ -796,7 +892,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
(unsigned) current_event.dwProcessId,
|
||||
(unsigned) current_event.dwThreadId,
|
||||
"OUTPUT_DEBUG_STRING_EVENT"));
|
||||
handle_output_debug_string ( ourstatus);
|
||||
if (handle_output_debug_string ( ourstatus))
|
||||
retval = current_event.dwProcessId;
|
||||
break;
|
||||
default:
|
||||
printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n",
|
||||
|
@ -807,21 +904,19 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
|
|||
break;
|
||||
}
|
||||
|
||||
if (breakout > 0)
|
||||
current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
|
||||
else if (!breakout)
|
||||
if (!retval)
|
||||
CHECK (child_continue (continue_status, -1));
|
||||
else
|
||||
current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
|
||||
|
||||
out:
|
||||
return breakout;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Wait for interesting events to occur in the target process. */
|
||||
static int
|
||||
child_wait (int pid, struct target_waitstatus *ourstatus)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* We loop when we get a non-standard exception rather than return
|
||||
with a SPURIOUS because resume can try and step or modify things,
|
||||
which needs a current_thread->h. But some of these exceptions mark
|
||||
|
@ -829,7 +924,9 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
|
|||
isn't necessarily what you think it is. */
|
||||
|
||||
while (1)
|
||||
if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval))
|
||||
{
|
||||
int retval = get_child_debug_event (pid, ourstatus);
|
||||
if (retval)
|
||||
return retval;
|
||||
else
|
||||
{
|
||||
|
@ -841,6 +938,7 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
|
|||
if (detach)
|
||||
child_kill_inferior ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attach to process PID, then initialize for debugging it. */
|
||||
|
@ -865,6 +963,9 @@ child_attach (args, from_tty)
|
|||
exception_count = 0;
|
||||
event_count = 0;
|
||||
|
||||
child_init_thread_list ();
|
||||
child_clear_solibs ();
|
||||
|
||||
if (from_tty)
|
||||
{
|
||||
char *exec_file = (char *) get_exec_file (0);
|
||||
|
@ -936,11 +1037,10 @@ child_create_inferior (exec_file, allargs, env)
|
|||
BOOL ret;
|
||||
DWORD flags;
|
||||
char *args;
|
||||
extern int stop_after_trap;
|
||||
|
||||
if (!exec_file)
|
||||
{
|
||||
error ("No executable specified, use `target exec'.\n");
|
||||
}
|
||||
|
||||
memset (&si, 0, sizeof (si));
|
||||
si.cb = sizeof (si);
|
||||
|
@ -1057,16 +1157,23 @@ child_create_inferior (exec_file, allargs, env)
|
|||
inferior_pid = current_event.dwThreadId = pi.dwThreadId;
|
||||
push_target (&child_ops);
|
||||
child_init_thread_list ();
|
||||
init_wait_for_inferior ();
|
||||
child_clear_solibs ();
|
||||
clear_proceed_status ();
|
||||
init_wait_for_inferior ();
|
||||
target_terminal_init ();
|
||||
target_terminal_inferior ();
|
||||
last_sig = 0;
|
||||
|
||||
/* Run until process and threads are loaded */
|
||||
while (!get_child_debug_event (inferior_pid, &dummy,
|
||||
FIRST_EXCEPTION, &ret))
|
||||
continue;
|
||||
while (1)
|
||||
{
|
||||
stop_after_trap = 1;
|
||||
wait_for_inferior ();
|
||||
if (stop_signal != TARGET_SIGNAL_TRAP)
|
||||
resume (0, stop_signal);
|
||||
else
|
||||
break;
|
||||
}
|
||||
stop_after_trap = 0;
|
||||
|
||||
/* child_continue (DBG_CONTINUE, -1);*/
|
||||
proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
|
||||
|
@ -1150,13 +1257,13 @@ child_resume (int pid, int step, enum target_signal sig)
|
|||
|
||||
/* Get context for currently selected thread */
|
||||
th = thread_rec (current_event.dwThreadId, FALSE);
|
||||
if (th)
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
#ifdef i386
|
||||
/* Single step by setting t bit */
|
||||
child_fetch_inferior_registers (PS_REGNUM);
|
||||
th->context.EFlags |= FLAG_TRACE_BIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (th->context.ContextFlags)
|
||||
|
@ -1164,6 +1271,7 @@ child_resume (int pid, int step, enum target_signal sig)
|
|||
CHECK (SetThreadContext (th->h, &th->context));
|
||||
th->context.ContextFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow continuing with the same signal that interrupted us.
|
||||
Otherwise complain. */
|
||||
|
@ -1242,48 +1350,50 @@ _initialize_inftarg ()
|
|||
{
|
||||
init_child_ops ();
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("new-console", class_support, var_boolean,
|
||||
add_com ("dll-symbols", class_files, dll_symbol_command,
|
||||
"Load dll library symbols from FILE.");
|
||||
|
||||
add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
|
||||
|
||||
add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
|
||||
(char *) &new_console,
|
||||
"Set creation of new console when creating child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("new-group", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
|
||||
(char *) &new_group,
|
||||
"Set creation of new group when creating child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugexec", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
|
||||
(char *) &debug_exec,
|
||||
"Set whether to display execution in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugevents", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
|
||||
(char *) &debug_events,
|
||||
"Set whether to display kernel events in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugmemory", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
|
||||
(char *) &debug_memory,
|
||||
"Set whether to display memory accesses in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("debugexceptions", class_support, var_boolean,
|
||||
add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
|
||||
(char *) &debug_exceptions,
|
||||
"Set whether to display kernel exceptions in child process.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_info ("dll", info_dll_command, "Status of loaded DLLs.");
|
||||
add_info_alias ("sharedlibrary", "dll", 1);
|
||||
|
||||
add_target (&child_ops);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue