diff options
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r-- | gdb/gdbserver/ChangeLog | 33 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 147 | ||||
-rw-r--r-- | gdb/gdbserver/lynx-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/remote-utils.c | 20 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 11 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 1 | ||||
-rw-r--r-- | gdb/gdbserver/target.h | 7 | ||||
-rw-r--r-- | gdb/gdbserver/win32-low.c | 1 |
8 files changed, 197 insertions, 24 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index c6e9e34..6e91222 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,36 @@ +2015-09-11 Don Breazeal <donb@codesourcery.com> + Luis Machado <lgustavo@codesourcery.com> + + * linux-low.c (linux_mourn): Static declaration. + (linux_arch_setup): Move in front of + handle_extended_wait. + (linux_arch_setup_thread): New function. + (handle_extended_wait): Handle exec events. Call + linux_arch_setup_thread. Make event_lwp argument a + pointer-to-a-pointer. + (check_zombie_leaders): Do not check stopped threads. + (linux_low_ptrace_options): Add PTRACE_O_TRACEEXEC. + (linux_low_filter_event): Add lwp and thread for exec'ing + non-leader thread if leader thread has been deleted. + Refactor code into linux_arch_setup_thread and call it. + Pass child lwp pointer by reference to handle_extended_wait. + (linux_wait_for_event_filtered): Update comment. + (linux_wait_1): Prevent clobbering exec event status. + (linux_supports_exec_events): New function. + (linux_target_ops) <supports_exec_events>: Initialize new member. + * lynx-low.c (lynx_target_ops) <supports_exec_events>: Initialize + new member. + * remote-utils.c (prepare_resume_reply): New stop reason 'exec'. + * server.c (report_exec_events): New global variable. + (handle_query): Handle qSupported query for exec-events feature. + (captured_main): Initialize report_exec_events. + * server.h (report_exec_events): Declare new global variable. + * target.h (struct target_ops) <supports_exec_events>: New + member. + (target_supports_exec_events): New macro. + * win32-low.c (win32_target_ops) <supports_exec_events>: + Initialize new member. + 2015-09-09 Markus Metzger <markus.t.metzger@intel.com> * linux-low.c (linux_low_enable_btrace): Remove. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 4256bc5..aa4c868 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -265,6 +265,7 @@ static int linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, int *wstat, int options); static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); static struct lwp_info *add_lwp (ptid_t ptid); +static void linux_mourn (struct process_info *process); static int linux_stopped_by_watchpoint (void); static void mark_lwp_dead (struct lwp_info *lwp, int wstat); static int lwp_is_marked_dead (struct lwp_info *lwp); @@ -419,13 +420,39 @@ linux_add_process (int pid, int attached) static CORE_ADDR get_pc (struct lwp_info *lwp); -/* Handle a GNU/Linux extended wait response. If we see a clone - event, we need to add the new LWP to our list (and return 0 so as - not to report the trap to higher layers). */ +/* Implement the arch_setup target_ops method. */ + +static void +linux_arch_setup (void) +{ + the_low_target.arch_setup (); +} + +/* Call the target arch_setup function on THREAD. */ + +static void +linux_arch_setup_thread (struct thread_info *thread) +{ + struct thread_info *saved_thread; + + saved_thread = current_thread; + current_thread = thread; + + linux_arch_setup (); + + current_thread = saved_thread; +} + +/* Handle a GNU/Linux extended wait response. If we see a clone, + fork, or vfork event, we need to add the new LWP to our list + (and return 0 so as not to report the trap to higher layers). + If we see an exec event, we will modify ORIG_EVENT_LWP to point + to a new LWP representing the new program. */ static int -handle_extended_wait (struct lwp_info *event_lwp, int wstat) +handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) { + struct lwp_info *event_lwp = *orig_event_lwp; int event = linux_ptrace_get_extended_event (wstat); struct thread_info *event_thr = get_lwp_thread (event_lwp); struct lwp_info *new_lwp; @@ -571,6 +598,50 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) /* Report the event. */ return 0; } + else if (event == PTRACE_EVENT_EXEC && report_exec_events) + { + struct process_info *proc; + ptid_t event_ptid; + pid_t event_pid; + + if (debug_threads) + { + debug_printf ("HEW: Got exec event from LWP %ld\n", + lwpid_of (event_thr)); + } + + /* Get the event ptid. */ + event_ptid = ptid_of (event_thr); + event_pid = ptid_get_pid (event_ptid); + + /* Delete the execing process and all its threads. */ + proc = get_thread_process (event_thr); + linux_mourn (proc); + current_thread = NULL; + + /* Create a new process/lwp/thread. */ + proc = linux_add_process (event_pid, 0); + event_lwp = add_lwp (event_ptid); + event_thr = get_lwp_thread (event_lwp); + gdb_assert (current_thread == event_thr); + linux_arch_setup_thread (event_thr); + + /* Set the event status. */ + event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD; + event_lwp->waitstatus.value.execd_pathname + = xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr))); + + /* Mark the exec status as pending. */ + event_lwp->stopped = 1; + event_lwp->status_pending_p = 1; + event_lwp->status_pending = wstat; + event_thr->last_resume_kind = resume_continue; + event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; + + /* Report the event. */ + *orig_event_lwp = event_lwp; + return 0; + } internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); } @@ -839,14 +910,6 @@ linux_create_inferior (char *program, char **allargs) return pid; } -/* Implement the arch_setup target_ops method. */ - -static void -linux_arch_setup (void) -{ - the_low_target.arch_setup (); -} - /* Attach to an inferior process. Returns 0 on success, ERRNO on error. */ @@ -1639,7 +1702,7 @@ check_zombie_leaders (void) leader_pid, leader_lp!= NULL, num_lwps (leader_pid), linux_proc_pid_is_zombie (leader_pid)); - if (leader_lp != NULL + if (leader_lp != NULL && !leader_lp->stopped /* Check if there are other threads in the group, as we may have raced with the inferior simply exiting. */ && !last_thread_of_process_p (leader_pid) @@ -2098,6 +2161,9 @@ linux_low_ptrace_options (int attached) if (report_vfork_events) options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE); + if (report_exec_events) + options |= PTRACE_O_TRACEEXEC; + return options; } @@ -2114,6 +2180,38 @@ linux_low_filter_event (int lwpid, int wstat) child = find_lwp_pid (pid_to_ptid (lwpid)); + /* Check for stop events reported by a process we didn't already + know about - anything not already in our LWP list. + + If we're expecting to receive stopped processes after + fork, vfork, and clone events, then we'll just add the + new one to our list and go back to waiting for the event + to be reported - the stopped process might be returned + from waitpid before or after the event is. + + But note the case of a non-leader thread exec'ing after the + leader having exited, and gone from our lists (because + check_zombie_leaders deleted it). The non-leader thread + changes its tid to the tgid. */ + + if (WIFSTOPPED (wstat) && child == NULL && WSTOPSIG (wstat) == SIGTRAP + && linux_ptrace_get_extended_event (wstat) == PTRACE_EVENT_EXEC) + { + ptid_t child_ptid; + + /* A multi-thread exec after we had seen the leader exiting. */ + if (debug_threads) + { + debug_printf ("LLW: Re-adding thread group leader LWP %d" + "after exec.\n", lwpid); + } + + child_ptid = ptid_build (lwpid, lwpid, 0); + child = add_lwp (child_ptid); + child->stopped = 1; + current_thread = child->thread; + } + /* If we didn't find a process, one of two things presumably happened: - A process we started and then detached from has exited. Ignore it. - A process we are controlling has forked and the new child's stop @@ -2171,17 +2269,10 @@ linux_low_filter_event (int lwpid, int wstat) { if (proc->attached) { - struct thread_info *saved_thread; - /* This needs to happen after we have attached to the inferior and it is stopped for the first time, but before we access any inferior registers. */ - saved_thread = current_thread; - current_thread = thread; - - the_low_target.arch_setup (); - - current_thread = saved_thread; + linux_arch_setup_thread (thread); } else { @@ -2210,7 +2301,7 @@ linux_low_filter_event (int lwpid, int wstat) && linux_is_extended_waitstatus (wstat)) { child->stop_pc = get_pc (child); - if (handle_extended_wait (child, wstat)) + if (handle_extended_wait (&child, wstat)) { /* The event has been handled, so just return without reporting it. */ @@ -2419,8 +2510,7 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, - When a non-leader thread execs, that thread just vanishes without reporting an exit (so we'd hang if we waited for it explicitly in that case). The exec event is reported to - the TGID pid (although we don't currently enable exec - events). */ + the TGID pid. */ errno = 0; ret = my_waitpid (-1, wstatp, options | WNOHANG); @@ -5801,6 +5891,14 @@ linux_supports_vfork_events (void) return linux_supports_tracefork (); } +/* Check if exec events are supported. */ + +static int +linux_supports_exec_events (void) +{ + return linux_supports_traceexec (); +} + /* Callback for 'find_inferior'. Set the (possibly changed) ptrace options for the specified lwp. */ @@ -6891,6 +6989,7 @@ static struct target_ops linux_target_ops = { linux_supports_multi_process, linux_supports_fork_events, linux_supports_vfork_events, + linux_supports_exec_events, linux_handle_new_gdb_connection, #ifdef USE_THREAD_DB thread_db_handle_monitor_command, diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c index 1a187c8..b722930 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -765,6 +765,7 @@ static struct target_ops lynx_target_ops = { NULL, /* supports_multi_process */ NULL, /* supports_fork_events */ NULL, /* supports_vfork_events */ + NULL, /* supports_exec_events */ NULL, /* handle_new_gdb_connection */ NULL, /* handle_monitor_command */ }; diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 0c4a693..ac86dd5 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1117,6 +1117,7 @@ prepare_resume_reply (char *buf, ptid_t ptid, case TARGET_WAITKIND_STOPPED: case TARGET_WAITKIND_FORKED: case TARGET_WAITKIND_VFORKED: + case TARGET_WAITKIND_EXECD: { struct thread_info *saved_thread; const char **regp; @@ -1134,6 +1135,25 @@ prepare_resume_reply (char *buf, ptid_t ptid, buf = write_ptid (buf, status->value.related_pid); strcat (buf, ";"); } + else if (status->kind == TARGET_WAITKIND_EXECD && multi_process) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = "exec"; + char hexified_pathname[PATH_MAX * 2]; + + sprintf (buf, "T%02x%s:", signal, event); + buf += strlen (buf); + + /* Encode pathname to hexified format. */ + bin2hex ((const gdb_byte *) status->value.execd_pathname, + hexified_pathname, + strlen (status->value.execd_pathname)); + + sprintf (buf, "%s;", hexified_pathname); + xfree (status->value.execd_pathname); + status->value.execd_pathname = NULL; + buf += strlen (buf); + } else sprintf (buf, "T%02x", status->value.sig); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index c52cf16..9aa8a3f 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -59,6 +59,7 @@ int run_once; int multi_process; int report_fork_events; int report_vfork_events; +int report_exec_events; int non_stop; int swbreak_feature; int hwbreak_feature; @@ -2111,6 +2112,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (target_supports_vfork_events ()) report_vfork_events = 1; } + if (strcmp (p, "exec-events+") == 0) + { + /* GDB supports and wants exec events if possible. */ + if (target_supports_exec_events ()) + report_exec_events = 1; + } else target_process_qsupported (p); @@ -2167,6 +2174,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (target_supports_vfork_events ()) strcat (own_buf, ";vfork-events+"); + if (target_supports_exec_events ()) + strcat (own_buf, ";exec-events+"); + if (target_supports_non_stop ()) strcat (own_buf, ";QNonStop+"); @@ -3544,6 +3554,7 @@ captured_main (int argc, char *argv[]) multi_process = 0; report_fork_events = 0; report_vfork_events = 0; + report_exec_events = 0; /* Be sure we're out of tfind mode. */ current_traceframe = -1; cont_thread = null_ptid; diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 6020d72..96ad4fa 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -86,6 +86,7 @@ extern int run_once; extern int multi_process; extern int report_fork_events; extern int report_vfork_events; +extern int report_exec_events; extern int non_stop; extern int extended_protocol; diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 3e3b80f..aea3d15 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -290,6 +290,9 @@ struct target_ops /* Returns true if vfork events are supported. */ int (*supports_vfork_events) (void); + /* Returns true if exec events are supported. */ + int (*supports_exec_events) (void); + /* Allows target to re-initialize connection-specific settings. */ void (*handle_new_gdb_connection) (void); @@ -468,6 +471,10 @@ int kill_inferior (int); (the_target->supports_vfork_events ? \ (*the_target->supports_vfork_events) () : 0) +#define target_supports_exec_events() \ + (the_target->supports_exec_events ? \ + (*the_target->supports_exec_events) () : 0) + #define target_handle_new_gdb_connection() \ do \ { \ diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 86386ce..85cc040 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1832,6 +1832,7 @@ static struct target_ops win32_target_ops = { NULL, /* supports_multi_process */ NULL, /* supports_fork_events */ NULL, /* supports_vfork_events */ + NULL, /* supports_exec_events */ NULL, /* handle_new_gdb_connection */ NULL, /* handle_monitor_command */ NULL, /* core_of_thread */ |