* [PATCH 0/5] Extended-remote follow exec @ 2015-07-15 21:49 Don Breazeal 2015-07-15 21:50 ` [PATCH 2/5] Extended-remote exec catchpoints Don Breazeal ` (5 more replies) 0 siblings, 6 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-15 21:49 UTC (permalink / raw) To: gdb-patches, palves This patch series is the latest version that implements exec events for extended-remote Linux targets. It provides exec event notification, follow-exec functionality, and exec catchpoints. Several tests related to exec event features have been modified to work with the native-extended-gdbserver target. It is part of the larger effort to implement "remote follow fork". This work has been divided into three parts: 1) Extended-remote fork events, providing follow-fork-mode, detach-on-fork, and fork catchpoints. This was pushed earlier this year: https://sourceware.org/ml/gdb-patches/2015-05/msg00278.html 2) Extended-remote exec events, this patchset. 3) Fork and exec events for native-gdbserver target. This patchset derives from part of a patch series submitted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00868.html The primary difference between this patchset and that one is that this one does not use ptrace exit events (PTRACE_O_TRACEEXIT) for notification of thread exit. In addition, a number of changes were made to conform to to the final version of the extended-remote fork event patchset (#1 above). Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. The contents of this patchset are as follows: Patch 1/5: Extended-remote exec event support. Patch 2/5: Extended-remote exec catchpoints. Patch 3/5: Extended-remote exec-related test updates. Patch 4/5: Eliminates some spurious warnings related to solib load events that are emitted after an extended-remote exec event. Patch 5/5: Extended-remote exec event documentation. Thanks, --Don ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH 2/5] Extended-remote exec catchpoints 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal @ 2015-07-15 21:50 ` Don Breazeal 2015-08-13 15:00 ` Pedro Alves 2015-07-15 21:50 ` [PATCH 1/5] Extended-remote exec events Don Breazeal ` (4 subsequent siblings) 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-15 21:50 UTC (permalink / raw) To: gdb-patches, palves This patch implements exec catchpoints for extended-remote Linux targets. The implementation follows the same approach used for fork catchpoints, implementing extended-remote target routines for inserting and removing the catchpoints by just checking if exec events are supported. Existing host-side code and previous support for extended-remote exec events takes care of the rest. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. Thanks --Don 2015-07-15 Don Breazeal <donb@codesourcery.com> * gdb/remote.c (remote_exec_event_p): New function. (remote_insert_exec_catchpoint): New function. (remote_remove_exec_catchpoint): New function. (init_extended_remote_ops): Initialize extended_remote_ops members to_insert_exec_catchpoint and to_remove_exec_catchpoint. --- gdb/remote.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/gdb/remote.c b/gdb/remote.c index c0b3423..153b183 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1499,6 +1499,14 @@ remote_vfork_event_p (struct remote_state *rs) return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE; } +/* Returns true if exec events are supported. */ + +static int +remote_exec_event_p (struct remote_state *rs) +{ + return packet_support (PACKET_exec_event_feature) == PACKET_ENABLE; +} + /* Insert fork catchpoint target routine. If fork events are enabled then return success, nothing more to do. */ @@ -1539,6 +1547,26 @@ remote_remove_vfork_catchpoint (struct target_ops *ops, int pid) return 0; } +/* Insert exec catchpoint target routine. If exec events are + enabled, just return success. */ + +static int +remote_insert_exec_catchpoint (struct target_ops *ops, int pid) +{ + struct remote_state *rs = get_remote_state (); + + return !remote_exec_event_p (rs); +} + +/* Remove exec catchpoint target routine. Nothing to do, just + return success. */ + +static int +remote_remove_exec_catchpoint (struct target_ops *ops, int pid) +{ + return 0; +} + /* Tokens for use by the asynchronous signal handlers for SIGINT. */ static struct async_signal_handler *async_sigint_remote_twice_token; static struct async_signal_handler *async_sigint_remote_token; @@ -12388,6 +12416,10 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; = remote_insert_vfork_catchpoint; extended_remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint; + extended_remote_ops.to_insert_exec_catchpoint + = remote_insert_exec_catchpoint; + extended_remote_ops.to_remove_exec_catchpoint + = remote_remove_exec_catchpoint; } static int -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 2/5] Extended-remote exec catchpoints 2015-07-15 21:50 ` [PATCH 2/5] Extended-remote exec catchpoints Don Breazeal @ 2015-08-13 15:00 ` Pedro Alves 0 siblings, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-08-13 15:00 UTC (permalink / raw) To: Don Breazeal, gdb-patches On 07/15/2015 10:49 PM, Don Breazeal wrote: > 2015-07-15 Don Breazeal <donb@codesourcery.com> > > * gdb/remote.c (remote_exec_event_p): New function. No "gdb/". > (remote_insert_exec_catchpoint): New function. > (remote_remove_exec_catchpoint): New function. > (init_extended_remote_ops): Initialize extended_remote_ops > members to_insert_exec_catchpoint and > to_remove_exec_catchpoint. Otherwise seems fine. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH 1/5] Extended-remote exec events 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal 2015-07-15 21:50 ` [PATCH 2/5] Extended-remote exec catchpoints Don Breazeal @ 2015-07-15 21:50 ` Don Breazeal 2015-07-16 14:01 ` Yao Qi 2015-07-15 21:50 ` [PATCH 3/5] Extended-remote support for exec event tests Don Breazeal ` (3 subsequent siblings) 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-15 21:50 UTC (permalink / raw) To: gdb-patches, palves This patch is the latest version implementing support for exec events on extended-remote Linux targets. Follow-exec-mode and rerun behave as expected. Catchpoints and test updates are implemented in subsequent patches. This patch was most recently derived from a patch posted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00877.html. It was originally based on some work done by Luis Machado in 2013. IMPLEMENTATION ---------------- Support for exec events in single-threaded programs was a fairly straightforward replication of the implementation in native GDB: 1) Enable exec events via ptrace options. 2) Add support for handling the exec events to the handle_extended_wait and linux_wait_for_event_filtered. Detect the exec event, then find and save the pathname of the executable file being exec'd and set event status flags. 3) Implement an additional "stop reason", "exec", in the RSP stop reply packet "T". Existing GDB code takes care of handling the exec event on the host side without modification. Support for exec events in multi-threaded programs required some additional work. When exec is called, the Linux kernel destroys all of the threads except the execing one. If the execing thread was not the thread group leader, the kernel resets the execing thread's tid to the tgid, and no exit notification is sent for the execing thread -- from the ptracer's perspective, it appears as though the execing thread just vanishes. The non-leader exec leaves gdbserver with one or more of several potential scenarios which require it to bring its thread lists (e.g. struct thread_info, struct lwp_info) in sync with reality. - The leader thread exited before the exec event was reported, and the execing thread cannot re-use its data structures. In this case gdbserver must recognize that an exec event occurred and there are no thread structures for the leader thread, so it must add new structures to the lists for the 'new' leader thread. 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; } - The execing thread can re-use the previous leader thread's data structures, and the old data structures used for the execing thread prior to the exec are left with a running status and no actual thread associated with it. When a non-leader execing thread re-uses the previous leader's thread_info structure, it inherits the old thread's register cache. If this is left as-is it will eventually be flushed to the target, clobbering the valid register values with those from the old thread. So when an EXEC event occurs we always invalidate the register cache. Note that we can't call regcache_invalidate, since that flushes the cache to the target. else if (event == PTRACE_EVENT_EXEC && report_exec_events) { struct regcache *regcache; ---snip snip--- regcache = (struct regcache *) inferior_regcache_data (event_thr); free_register_cache (regcache); set_inferior_regcache_data (event_thr, NULL); event_lwp->stop_pc = get_pc (event_lwp); In this case (stale thread data structures for execing thread) when in all-stop mode, gdbserver must clean up any stale thread/lwp structures before it tries to stop all the threads and hangs in sigsuspend, waiting for an event from a non-existent thread. We do this by checking the return value from kill_lwp in send_sigstop, eventually called after calling stop_all_lwps, which is used to stop the threads in all-stop mode. If kill_lwp returns an error and errno is ESRCH, we know that the lwp with that pid is gone, and we delete the associated data structures. - kill_lwp (pid, SIGSTOP); + errno = 0; + ret = kill_lwp (pid, SIGSTOP); + if (ret == -1 && errno == ESRCH) + { + /* If the kill fails with "No such process", on GNU/Linux we know + that the LWP has vanished - it is not a zombie, it is gone. + This is because a thread that was not the thread group leader + called exec and took over the leader's lwp. */ + delete_lwp (lwp); + set_desired_thread (0); In the same case in non-stop mode, we don't need to stop all the lwps, but in order to utilize the same mechanism used in all-stop mode, we call stop_all_lwps/unstop_all_lwps in succession, just to check for ESRCH errors and to delete any stale thread structures. if (non_stop && stopping_threads == NOT_STOPPING_THREADS) { /* In non-stop mode, make sure we delete the lwp entry for a non-leader exec'ing thread, which will have vanished. We do this by sending a signal to all the other threads in the lwp list, deleting any that are not found. Note that in all-stop mode this will happen when we stop all the threads. */ stop_all_lwps (0, event_lwp); unstop_all_lwps (0, event_lwp); } Note that the native implementation uses a different mechanism for identifying the stale data structure scenario. It determines that the execing thread has "vanished" by calling waitpid(PID) and checking for a return value of ECHILD, which means that the thread is gone. We don't want to use waitpid(PID) in gdbserver, based on the discussion in: https://www.sourceware.org/ml/gdb-patches/2014-02/msg00828.html so we use the send_sigstop method described above instead. TESTING -------- x86_64 GNU/Linux for native, native-gdbserver, and native-extended-gdbserver targets. Most of the exec-related tests fail due to the lack of catchpoints and extended-remote support in the tests. Thanks --Don gdb/gdbserver/ 2015-07-15 Don Breazeal <donb@codesourcery.com> Luis Machado <lgustavo@codesourcery.com> * linux-low.c (handle_extended_wait): Handle exec events. (check_zombie_leaders): Do not check stopped threads. (linux_low_ptrace_options): Add PTRACE_O_TRACEEXEC. (linux_low_filter_event): Add thread structures for exec'ing non-leader thread after leader thread had been deleted. (linux_wait_for_event_filtered): Fix comment saying exec events are not supported in remote. (extended_event_reported): Add TARGET_WAITKIND_EXECD. (linux_wait_1): Prevent clobbering extended event status. (send_sigstop): Check return from kill_lwp, and if ESRCH then call delete_lwp. (linux_supports_exec_events): New function. * lynx-low.c (lynx_target_ops): Initialize new structure member 'supports_exec_events'. * 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): Initialize new structure member 'supports_exec_events'. gdb/ 2015-07-15 Don Breazeal <donb@codesourcery.com> Luis Machado <lgustavo@codesourcery.com> * nat/linux-ptrace.c (linux_supports_tracefork): Delete out-of-date comment verbiage. (linux_supports_traceexec): New function. * nat/linux-ptrace.h (linux_supports_traceexec): Declare. * remote.c (anonymous enum) <PACKET_exec_event_feature> New enumeration constant. (remote_protocol_features): Add entry for exec-events feature. (remote_query_supported): Add client side of qSupported query for exec-events feature. (_initialize_remote): Call add_packet_config_cmd for remote exec-events feature. --- gdb/gdbserver/linux-low.c | 117 ++++++++++++++++++++++++++++++++++++++++--- gdb/gdbserver/lynx-low.c | 1 + gdb/gdbserver/remote-utils.c | 20 ++++++++ gdb/gdbserver/server.c | 11 ++++ gdb/gdbserver/server.h | 1 + gdb/gdbserver/target.h | 7 +++ gdb/gdbserver/win32-low.c | 1 + gdb/nat/linux-ptrace.c | 13 +++-- gdb/nat/linux-ptrace.h | 1 + gdb/remote.c | 30 +++++++++++ 10 files changed, 193 insertions(+), 9 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 2dafb03..47d8bc3 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -557,6 +557,52 @@ 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 regcache *regcache; + + if (debug_threads) + { + debug_printf ("HEW: Got exec event from LWP %ld\n", + lwpid_of (event_thr)); + } + + /* If the exec was not called by the thread group leader, then + the lwp_info and thread_info structures are out-of-date, + containing information about the original leader thread and + not the new exec'ing leader thread. Invalidate the register + cache without flushing it to the target, and reset the stop + pc value in the lwp. */ + regcache = (struct regcache *) inferior_regcache_data (event_thr); + free_register_cache (regcache); + set_inferior_regcache_data (event_thr, NULL); + event_lwp->stop_pc = get_pc (event_lwp); + + 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_stop; + event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; + + if (non_stop && stopping_threads == NOT_STOPPING_THREADS) + { + /* In non-stop mode, make sure we delete the lwp entry for a + non-leader exec'ing thread, which will have vanished. We + do this by sending a signal to all the other threads in the + lwp list, deleting any that are not found. Note that in + all-stop mode this will happen when we stop all the threads. */ + stop_all_lwps (0, event_lwp); + unstop_all_lwps (0, event_lwp); + } + + /* Report the event. */ + return 0; + } internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); } @@ -1609,7 +1655,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) @@ -2035,6 +2081,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; } @@ -2051,6 +2100,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 @@ -2342,8 +2423,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); @@ -2741,7 +2821,8 @@ extended_event_reported (const struct target_waitstatus *waitstatus) return (waitstatus->kind == TARGET_WAITKIND_FORKED || waitstatus->kind == TARGET_WAITKIND_VFORKED - || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE); + || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE + || waitstatus->kind == TARGET_WAITKIND_EXECD); } /* Wait for process, returns status. */ @@ -3286,7 +3367,8 @@ linux_wait_1 (ptid_t ptid, ourstatus->value.sig = GDB_SIGNAL_0; } else if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) != SIGSTOP) + && WSTOPSIG (w) != SIGSTOP + && !extended_event_reported (ourstatus)) { /* A thread that has been requested to stop by GDB with vCont;t, but, it stopped for other reasons. */ @@ -3404,6 +3486,7 @@ static void send_sigstop (struct lwp_info *lwp) { int pid; + int ret; pid = lwpid_of (get_lwp_thread (lwp)); @@ -3421,7 +3504,20 @@ send_sigstop (struct lwp_info *lwp) debug_printf ("Sending sigstop to lwp %d\n", pid); lwp->stop_expected = 1; - kill_lwp (pid, SIGSTOP); + errno = 0; + ret = kill_lwp (pid, SIGSTOP); + if (ret == -1 && errno == ESRCH) + { + /* If the kill fails with "No such process", on GNU/Linux we know + that the LWP has vanished - it is not a zombie, it is gone. + This is because a thread that was not the thread group leader + called exec and took over the leader's lwp. */ + delete_lwp (lwp); + set_desired_thread (0); + + if (debug_threads) + debug_printf ("send_sigstop: lwp %d has vanished\n", pid); + } } static int @@ -5594,6 +5690,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. */ @@ -6681,6 +6785,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 ee7b28a..fd89869 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -764,6 +764,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 bb31456..79d5ee8 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1116,6 +1116,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; @@ -1133,6 +1134,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]; + + 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 7e388dd..2b98d7c 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; @@ -2107,6 +2108,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); @@ -2163,6 +2170,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+"); @@ -3545,6 +3555,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 09a5624..258909d 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; /* True if the "swbreak+" feature is active. In that case, GDB wants diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 9a40867..dd5eb3e 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -287,6 +287,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); @@ -458,6 +461,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 64caf24..f7a3c0b 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1831,6 +1831,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 */ diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index 1a926f9..db3c4ce 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -527,9 +527,7 @@ ptrace_supports_feature (int ptrace_options) } /* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace, - 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is - PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, - since they were all added to the kernel at the same time. */ + 0 otherwise. */ int linux_supports_tracefork (void) @@ -537,6 +535,15 @@ linux_supports_tracefork (void) return ptrace_supports_feature (PTRACE_O_TRACEFORK); } +/* Returns non-zero if PTRACE_EVENT_EXEC is supported by ptrace, + 0 otherwise. */ + +int +linux_supports_traceexec (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEEXEC); +} + /* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace, 0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h index be6c395..6d534ee 100644 --- a/gdb/nat/linux-ptrace.h +++ b/gdb/nat/linux-ptrace.h @@ -161,6 +161,7 @@ extern void linux_check_ptrace_features (void); extern void linux_enable_event_reporting (pid_t pid, int attached); extern void linux_disable_event_reporting (pid_t pid); extern int linux_supports_tracefork (void); +extern int linux_supports_traceexec (void); extern int linux_supports_traceclone (void); extern int linux_supports_tracevforkdone (void); extern int linux_supports_tracesysgood (void); diff --git a/gdb/remote.c b/gdb/remote.c index 9d97f6b..c0b3423 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1366,6 +1366,9 @@ enum { /* Support for the Qbtrace-conf:pt:size packet. */ PACKET_Qbtrace_conf_pt_size, + /* Support for exec events. */ + PACKET_exec_event_feature, + PACKET_MAX }; @@ -4162,6 +4165,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_fork_event_feature }, { "vfork-events", PACKET_DISABLE, remote_supported_packet, PACKET_vfork_event_feature }, + { "exec-events", PACKET_DISABLE, remote_supported_packet, + PACKET_exec_event_feature }, { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_conf_pt_size } }; @@ -4250,6 +4255,9 @@ remote_query_supported (void) if (packet_set_cmd_state (PACKET_vfork_event_feature) != AUTO_BOOLEAN_FALSE) q = remote_query_supported_append (q, "vfork-events+"); + if (packet_set_cmd_state (PACKET_exec_event_feature) + != AUTO_BOOLEAN_FALSE) + q = remote_query_supported_append (q, "exec-events+"); } q = reconcat (q, "qSupported:", q, (char *) NULL); @@ -5909,6 +5917,25 @@ Packet: '%s'\n"), event->ws.kind = TARGET_WAITKIND_VFORK_DONE; p = skip_to_semicolon (p1 + 1); } + else if (strncmp (p, "exec", p1 - p) == 0) + { + ULONGEST pid; + char pathname[PATH_MAX]; + + p = unpack_varlen_hex (++p1, &pid); + + /* Save the pathname for event reporting and for + the next run command. */ + hex2bin (p1, (gdb_byte *) pathname, (p - p1)/2); + /* Add the null terminator. */ + pathname[(p - p1)/2] = '\0'; + /* This is freed during event handling. */ + event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.kind = TARGET_WAITKIND_EXECD; + /* Save the pathname for the next run command. */ + xfree (remote_exec_file); + remote_exec_file = xstrdup (pathname); + } else { ULONGEST pnum; @@ -12960,6 +12987,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size], "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature], + "exec-event-feature", "exec-event-feature", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 1/5] Extended-remote exec events 2015-07-15 21:50 ` [PATCH 1/5] Extended-remote exec events Don Breazeal @ 2015-07-16 14:01 ` Yao Qi 2015-07-16 15:52 ` Don Breazeal 0 siblings, 1 reply; 55+ messages in thread From: Yao Qi @ 2015-07-16 14:01 UTC (permalink / raw) To: Don Breazeal; +Cc: gdb-patches, palves Don Breazeal <donb@codesourcery.com> writes: > IMPLEMENTATION > ---------------- > Support for exec events in single-threaded programs was a fairly > straightforward replication of the implementation in native GDB: > > 1) Enable exec events via ptrace options. > > 2) Add support for handling the exec events to the handle_extended_wait and > linux_wait_for_event_filtered. Detect the exec event, then find and save > the pathname of the executable file being exec'd and set event status flags. > > 3) Implement an additional "stop reason", "exec", in the RSP stop reply > packet "T". > > Existing GDB code takes care of handling the exec event on the host side > without modification. Hi Don, How does GDBserver handle the multi-arch case? say, 64-bit process call exec to a 32-bit program. At least, the target description of that process in GDBserver should be updated. -- Yao (齐尧) ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 1/5] Extended-remote exec events 2015-07-16 14:01 ` Yao Qi @ 2015-07-16 15:52 ` Don Breazeal 2015-07-16 16:35 ` Yao Qi 0 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-16 15:52 UTC (permalink / raw) To: Yao Qi, Breazeal, Don; +Cc: gdb-patches, palves On 7/16/2015 7:00 AM, Yao Qi wrote: > Don Breazeal <donb@codesourcery.com> writes: > >> IMPLEMENTATION >> ---------------- >> Support for exec events in single-threaded programs was a fairly >> straightforward replication of the implementation in native GDB: >> >> 1) Enable exec events via ptrace options. >> >> 2) Add support for handling the exec events to the handle_extended_wait and >> linux_wait_for_event_filtered. Detect the exec event, then find and save >> the pathname of the executable file being exec'd and set event status flags. >> >> 3) Implement an additional "stop reason", "exec", in the RSP stop reply >> packet "T". >> >> Existing GDB code takes care of handling the exec event on the host side >> without modification. > > Hi Don, > How does GDBserver handle the multi-arch case? say, 64-bit process call > exec to a 32-bit program. At least, the target description of that > process in GDBserver should be updated. > Hi Yao, You make a good point, GDBserver doesn't handle that case. I assume that's what this is about: --- warning: Selected architecture i386 is not compatible with reported target architecture i386:x86-64 --- I'll investigate. thanks --Don ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 1/5] Extended-remote exec events 2015-07-16 15:52 ` Don Breazeal @ 2015-07-16 16:35 ` Yao Qi 2015-07-16 17:06 ` Don Breazeal 0 siblings, 1 reply; 55+ messages in thread From: Yao Qi @ 2015-07-16 16:35 UTC (permalink / raw) To: Don Breazeal, Breazeal, Don; +Cc: gdb-patches, palves On 16/07/15 16:51, Don Breazeal wrote: > You make a good point, GDBserver doesn't handle that case. I assume > that's what this is about: > --- > warning: Selected architecture i386 is not compatible with reported > target architecture i386:x86-64 > --- > I'll investigate. This messages shows that GDB (rather than GDBserver) doesn't handle that case. AFAIK, GDBserver doesn't handle that case either. I am working on patches create target description at the right time in GDBserver, derived from this patch https://sourceware.org/ml/gdb-patches/2015-07/msg00403.html Current GDBserver creates target description too early, if we use --wrapper option, GDBserver created target description according to wrapper program, instead of the program we want to debug, which is wrong. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 1/5] Extended-remote exec events 2015-07-16 16:35 ` Yao Qi @ 2015-07-16 17:06 ` Don Breazeal 2015-07-17 11:55 ` Yao Qi 0 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-16 17:06 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches, palves On 7/16/2015 9:35 AM, Yao Qi wrote: > On 16/07/15 16:51, Don Breazeal wrote: >> You make a good point, GDBserver doesn't handle that case. I assume >> that's what this is about: >> --- >> warning: Selected architecture i386 is not compatible with reported >> target architecture i386:x86-64 >> --- >> I'll investigate. > > This messages shows that GDB (rather than GDBserver) doesn't handle > that case. AFAIK, GDBserver doesn't handle that case either. > > I am working on patches create target description at the right time > in GDBserver, derived from this patch > https://sourceware.org/ml/gdb-patches/2015-07/msg00403.html > Current GDBserver creates target description too early, if we use > --wrapper option, GDBserver created target description according > to wrapper program, instead of the program we want to debug, which > is wrong. > There is a difference between the native and gdbserver behavior with multi-arch exec. Native seems to handle multi-arch exec events: ------------------------------------------------------------------- Reading symbols from ./execler64...done. (gdb) b main Breakpoint 1 at 0x4006a4: file execler.c, line 19. (gdb) r Starting program: /home/dbreazea/junk/execler64 Breakpoint 1, main (argc=1, argv=0x7fffffffe848) at execler.c:19 19 printf ("starting %s\n", argv[0]); (gdb) info reg rax 0x7ffff7dd9ea8 140737351884456 rbx 0x0 0 rcx 0x0 0 ---etc--- (gdb) catch exec Catchpoint 2 (exec) (gdb) c Continuing. starting /home/dbreazea/junk/execler64 in execler process 5588 is executing new program: /home/dbreazea/junk/execee32 warning: the debug information found in "/lib/ld-2.11.1.so" does not match "/lib/ld-linux.so.2" (CRC mismatch). Catchpoint 2 (exec'd /home/dbreazea/junk/execee32), 0xf7fe0850 in ?? () from /lib/ld-linux.so.2 (gdb) info reg eax 0x0 0 ecx 0x0 0 ---etc--- --------------------------------------------------------------------- While the gdbserver case looks like this, unfortunately: --------------------------------------------------------------------- Reading symbols from ./execler64...done. (gdb) tar ext localhost:51111 Remote debugging using localhost:51111 Reading symbols from target:/lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. 0x00007ffff7dddaf0 in ?? () from target:/lib64/ld-linux-x86-64.so.2 (gdb) b main Breakpoint 1 at 0x4006a4: file execler.c, line 19. (gdb) c Continuing. Breakpoint 1, main (argc=1, argv=0x7fffffffe9d8) at execler.c:19 19 printf ("starting %s\n", argv[0]); (gdb) info reg rax 0x7ffff7dd9ea8 140737351884456 rbx 0x0 0 rcx 0x0 0 ---etc--- (gdb) catch exec Catchpoint 2 (exec) (gdb) c Continuing. Thread 5561.5561 is executing new program: /home/dbreazea/junk/execee32 warning: Selected architecture i386 is not compatible with reported target architecture i386:x86-64 warning: the debug information found in "target:/lib/ld-2.11.1.so" does not match "target:/lib/ld-linux.so.2" (CRC mismatch). Remote 'g' packet reply is too long: 000000000000000000000000000000... ---several 'g' packet errors (gdb) q A debugging session is active. Inferior 1 [process 5561] will be killed. Quit anyway? (y or n) y warning: Selected architecture i386 is not compatible with reported target architecture i386:x86-64 -------------------------------------------------------------------- At first glance it looks like in linux_low_filter_event, the execing inferior needs to be marked as a 'new_inferior' (proc->priv->new_inferior) in order to do the right thing and call the_low_target.arch_setup (). That may require some re-ordering of things in linux-low.c:linux_low_filter_event, since handle_extended_wait and the exec event handling happen after the arch setup. Do you think the work you are doing will address this, or should I continue looking at a fix for the problem above? They seem like they are related, but separate issues. thanks --Don ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 1/5] Extended-remote exec events 2015-07-16 17:06 ` Don Breazeal @ 2015-07-17 11:55 ` Yao Qi 0 siblings, 0 replies; 55+ messages in thread From: Yao Qi @ 2015-07-17 11:55 UTC (permalink / raw) To: Don Breazeal; +Cc: Yao Qi, gdb-patches, palves Don Breazeal <donb@codesourcery.com> writes: > While the gdbserver case looks like this, unfortunately: > > --------------------------------------------------------------------- > Reading symbols from ./execler64...done. > (gdb) tar ext localhost:51111 > Remote debugging using localhost:51111 > Reading symbols from target:/lib64/ld-linux-x86-64.so.2...(no debugging > symbols found)...done. > 0x00007ffff7dddaf0 in ?? () from target:/lib64/ld-linux-x86-64.so.2 > (gdb) b main > Breakpoint 1 at 0x4006a4: file execler.c, line 19. > (gdb) c > Continuing. > > Breakpoint 1, main (argc=1, argv=0x7fffffffe9d8) at execler.c:19 > 19 printf ("starting %s\n", argv[0]); > (gdb) info reg > rax 0x7ffff7dd9ea8 140737351884456 > rbx 0x0 0 > rcx 0x0 0 > ---etc--- > (gdb) catch exec > Catchpoint 2 (exec) > (gdb) c > Continuing. > Thread 5561.5561 is executing new program: /home/dbreazea/junk/execee32 > warning: Selected architecture i386 is not compatible with reported > target architecture i386:x86-64 > warning: the debug information found in "target:/lib/ld-2.11.1.so" does > not match "target:/lib/ld-linux.so.2" (CRC mismatch). > > Remote 'g' packet reply is too long: 000000000000000000000000000000... > ---several 'g' packet errors > (gdb) q > A debugging session is active. > > Inferior 1 [process 5561] will be killed. > > Quit anyway? (y or n) y > warning: Selected architecture i386 is not compatible with reported > target architecture i386:x86-64 > -------------------------------------------------------------------- > I thought gdb.multi/multi-arch-exec.exp has already covered the case above. It fails in my clean GDB build. If it doesn't cover, we need to improve it or write a new one to cover the case. > At first glance it looks like in linux_low_filter_event, the execing > inferior needs to be marked as a 'new_inferior' > (proc->priv->new_inferior) in order to do the right thing and call > the_low_target.arch_setup (). That may require some re-ordering of > things in linux-low.c:linux_low_filter_event, since handle_extended_wait > and the exec event handling happen after the arch setup. Yes, this needs some re-ordering... > > Do you think the work you are doing will address this, or should I > continue looking at a fix for the problem above? They seem like they > are related, but separate issues. I think my patch series will address this, and I am testing them. In the mean time, I don't think this multi-arch issue blocks the review to this patch series. As you said, they are related, but separated issues. -- Yao (齐尧) ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH 3/5] Extended-remote support for exec event tests 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal 2015-07-15 21:50 ` [PATCH 2/5] Extended-remote exec catchpoints Don Breazeal 2015-07-15 21:50 ` [PATCH 1/5] Extended-remote exec events Don Breazeal @ 2015-07-15 21:50 ` Don Breazeal 2015-07-15 21:51 ` [PATCH 5/5] Extended-remote exec event docs Don Breazeal ` (2 subsequent siblings) 5 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-15 21:50 UTC (permalink / raw) To: gdb-patches, palves This patch updates several exec-related tests and some of the library functions in order to get them running with extended-remote. There were three changes that were required, as follows: In gdb.base/foll-exec.exp, the proc 'zap_session' is used repeatedly to reset the state of the debugger before the next test. Part of that procedure is to 'set exec-file'. For remote targets, it is necessary to also 'set remote exec-file' to achieve the same effect (and execute the correct binary file in the subsequent test). In gdb.base/pie-execl.exp, there is an expect statement with an expression that is used to match output from both gdb and the program under debug. For the remote target, this had to be split into two expressions, using $inferior_spawn_id to match the output from the program. Because I had encountered problems with extended-remote exec events in non-stop mode in my manual testing, I added non-stop testing to the non-ldr-exc-[1234].exp tests. In order to set non-stop mode for remote targets, it is necessary to 'set non-stop on' after gdb has started, but before it connects to gdbserver. The non-ldr-... tests call 'clean_restart' in between tests, and it eventually calls 'gdb_start' which starts gdb and gdbserver and connects them. By adding a stop mode argument to clean_restart and gdb_start (in both lib/gdb.exp and boards/native-extended-gdbserver.exp), it was possible to set non-stop mode for remote targets. Since the arguments have a default value "all-stop", and only have an effect when "non-stop" is passed, these changes do not affect any existing test behavior. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. Thanks, --Don gdb/testsuite/ 2015-07-15 Don Breazeal <donb@codesourcery.com> * boards/native-extended-gdbserver.exp (gdb_start): Add argument 'mode' and set the stop mode before connecting. * gdb.base/foll-exec.exp (zap_session): For remote targets, set 'remote exec-file' as well as 'exec-file'. * gdb.base/pie-execl.exp (main): Use 'inferior_spawn_id' in an expect statement to match an expression with output from the program under debug. * gdb.threads/non-ldr-exc-1.exp (do_test, main): Add non-stop tests and pass stop mode argument to clean_restart. * gdb.threads/non-ldr-exc-2.exp: Likewise. * gdb.threads/non-ldr-exc-3.exp: Likewise. * gdb.threads/non-ldr-exc-4.exp: Likewise. * lib/gdb.exp (gdb_start): Add argument 'stop_mode', and set stop mode to non-stop if requested. (clean_restart): Add argument 'stop_mode' and pass to gdb_start. --- gdb/testsuite/boards/native-extended-gdbserver.exp | 8 +++++++- gdb/testsuite/gdb.base/foll-exec.exp | 7 +++++++ gdb/testsuite/gdb.base/pie-execl.exp | 20 ++++++++++++++++++-- gdb/testsuite/gdb.threads/non-ldr-exc-1.exp | 16 +++++++++++----- gdb/testsuite/gdb.threads/non-ldr-exc-2.exp | 22 ++++++++++++++++------ gdb/testsuite/gdb.threads/non-ldr-exc-3.exp | 22 ++++++++++++++++------ gdb/testsuite/gdb.threads/non-ldr-exc-4.exp | 16 +++++++++++----- gdb/testsuite/lib/gdb.exp | 12 ++++++++---- 8 files changed, 94 insertions(+), 29 deletions(-) diff --git a/gdb/testsuite/boards/native-extended-gdbserver.exp b/gdb/testsuite/boards/native-extended-gdbserver.exp index 744e044..4f43601 100644 --- a/gdb/testsuite/boards/native-extended-gdbserver.exp +++ b/gdb/testsuite/boards/native-extended-gdbserver.exp @@ -48,10 +48,16 @@ load_lib mi-support.exp # GDB is started. Note nothing is needed for gdb_exit, since # gdbserver is started with --once, causing it to exit once GDB # disconnects. -proc gdb_start { } { +proc gdb_start { {stop_mode "all-stop"} } { # Spawn GDB. default_gdb_start + # Non-stop mode must be set before connecting to gdbserver for it + # to be enabled in gdbserver, so we set non-stop here. + if { $stop_mode == "non-stop" } then { + gdb_test_no_output "set non-stop on" "enable non-stop mode" + } + # And then GDBserver, ready for extended-remote mode. gdbserver_start_multi diff --git a/gdb/testsuite/gdb.base/foll-exec.exp b/gdb/testsuite/gdb.base/foll-exec.exp index 5bea3ba..8b2eae0 100644 --- a/gdb/testsuite/gdb.base/foll-exec.exp +++ b/gdb/testsuite/gdb.base/foll-exec.exp @@ -68,6 +68,13 @@ proc zap_session {} { -re ".*$gdb_prompt $" {} timeout { fail "killing inferior (timeout)" ; return } } + + # For remote targets the 'file' command doesn't change the exec-file, + # as it does for native targets. In the remote case we must also use + # 'set remote exec-file'. + if [gdb_is_target_remote] then { + gdb_test_no_output "set remote exec-file $binfile" "reset remote exec-file to original file" + } } proc do_exec_tests {} { diff --git a/gdb/testsuite/gdb.base/pie-execl.exp b/gdb/testsuite/gdb.base/pie-execl.exp index 41411d5..56cd94e 100644 --- a/gdb/testsuite/gdb.base/pie-execl.exp +++ b/gdb/testsuite/gdb.base/pie-execl.exp @@ -16,6 +16,8 @@ # The problem was due to amd64_skip_prologue attempting to access inferior # memory before the PIE (Position Independent Executable) gets relocated. +global inferior_spawn_id + if ![istarget *-linux*] { continue } @@ -67,6 +69,7 @@ gdb_test_multiple "p/x &pie_execl_marker" $test { verbose -log "addr1 is $addr1" set test "continue" +set matches_found 0 gdb_test_multiple $test $test { -re "Error in re-setting breakpoint" { fail $test @@ -74,8 +77,21 @@ gdb_test_multiple $test $test { -re "Cannot access memory" { fail $test } - -re "pie-execl: re-exec.*executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { - pass $test + -re ".*executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } + } + -i "$inferior_spawn_id" -re "pie-execl: re-exec" { + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } } } diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp index 69e5cc6..147e7f3 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp @@ -28,11 +28,11 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 @@ -48,11 +48,17 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp index 9386153..748ff11 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp @@ -29,18 +29,26 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_continue_to_breakpoint "break-here" ".* break-here .*" + gdb_test_multiple "continue" "continue to breakpoint" { + -re ".*Breakpoint.*break-here.*" { + pass "continue to breakpoint" + } + } + + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } gdb_test "info threads" \ "\r\n\[ \t\]*Id\[ \t\]+Target\[ \t\]+Id\[ \t\]+Frame\[ \t\]*\r\n\\* 2 *Thread \[^\r\n\]* at \[^\r\n\]*" \ @@ -59,5 +67,7 @@ proc do_test { lock_sched } { } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp index cc7da1a..2dbcd81 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp @@ -31,18 +31,22 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_continue_to_breakpoint "break-here" ".* break-here .*" + gdb_test_multiple "continue" "continue to breakpoint" { + -re ".*Breakpoint.*break-here.*" { + pass "continue to breakpoint" + } + } # Also test with sched-lock to make sure we can follow the # non-leader thread execing even though the main thread wasn't @@ -51,11 +55,17 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp index a89b818..a9e5c5a 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp @@ -30,11 +30,11 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 @@ -50,11 +50,17 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 0805de9..4ef72d1 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -3601,8 +3601,11 @@ proc gdb_spawn_with_cmdline_opts { cmdline_flags } { # Overridable function -- you can override this function in your # baseboard file. -proc gdb_start { } { +proc gdb_start { {stop_mode "all-stop"} } { default_gdb_start + if { $stop_mode == "non-stop" } { + gdb_test_no_output "set non-stop on" "enable non-stop mode" + } } proc gdb_exit { } { @@ -4870,15 +4873,16 @@ proc build_executable { testname executable {sources ""} {options {debug}} } { } # Starts fresh GDB binary and loads EXECUTABLE into GDB. EXECUTABLE is -# the basename of the binary. +# the basename of the binary. If MODE is "non-stop", then non-stop +# mode will be enabled. # The return value is 0 for success, -1 for failure. -proc clean_restart { executable } { +proc clean_restart { executable {stop_mode "all-stop"} } { global srcdir global subdir set binfile [standard_output_file ${executable}] gdb_exit - gdb_start + gdb_start $stop_mode gdb_reinitialize_dir $srcdir/$subdir return [gdb_load ${binfile}] } -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH 5/5] Extended-remote exec event docs 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal ` (2 preceding siblings ...) 2015-07-15 21:50 ` [PATCH 3/5] Extended-remote support for exec event tests Don Breazeal @ 2015-07-15 21:51 ` Don Breazeal 2015-07-16 2:39 ` Eli Zaretskii 2015-07-15 21:51 ` [PATCH 4/5] Eliminate spurious warnings from remote exec Don Breazeal 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-15 21:51 UTC (permalink / raw) To: gdb-patches, palves This patch adds documentation of support for exec events on extended-remote Linux targets. Thanks, --Don 2015-07-15 Don Breazeal <donb@codesourcery.com> * gdb/NEWS: Announce new remote packets for the exec-events feature and the exec-events feature. * gdb/doc/gdb.texinfo (Remote Configuration): Add exec event feature to table of packet settings. (Stop Reply Packets): Add exec events to the list of stop reasons. (General Query Packets): Add exec events to tables of 'gdbfeatures' and 'stub features' supported in the qSupported packet, as well as to the list containing stub feature details. --- gdb/NEWS | 17 +++++++++++++++++ gdb/doc/gdb.texinfo | 30 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index 7ce9758..87e1ad4 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -5,6 +5,23 @@ * Support for tracepoints on aarch64-linux was added in GDBserver. +* New remote packets + +exec stop reason + Indicates that an exec system call was executed. + +exec-events feature in qSupported + The qSupported packet allows GDB to request support for exec + events using the new 'gdbfeature' exec-event, and the qSupported + response can contain the corresponding 'stubfeature'. Set and + show commands can be used to display whether these features are enabled. + +* Extended-remote exec events + + ** GDB now has support for exec events on extended-remote Linux targets. + For such targets with Linux kernels 2.5.46 and later, this enables + follow-exec-mode and exec catchpoints. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 9e2ecd1..5970782 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20022,6 +20022,10 @@ are: @tab @code{vfork stop reason} @tab @code{vfork} +@item @code{exec-event-feature} +@tab @code{exec stop reason} +@tab @code{exec} + @end multitable @node Remote Stub @@ -35655,6 +35659,18 @@ appropriate @samp{qSupported} feature (@pxref{qSupported}). The remote stub must also supply the appropriate @samp{qSupported} feature indicating support. +@cindex exec events, remote reply +@item exec +The packet indicates that @code{execve} was called, and @var{r} +is the absolute pathname of the file that was executed, in hex. +This packet is only applicable to targets that support exec events. + +This packet should not be sent by default; older @value{GDBN} versions +did not support it. @value{GDBN} requests it, by supplying an +appropriate @samp{qSupported} feature (@pxref{qSupported}). The +remote stub must also supply the appropriate @samp{qSupported} feature +indicating support. + @end table @item W @var{AA} @@ -36259,6 +36275,12 @@ This feature indicates whether @value{GDBN} supports vfork event extensions to the remote protocol. @value{GDBN} does not use such extensions unless the stub also reports that it supports them by including @samp{vfork-events+} in its @samp{qSupported} reply. + +@item exec-events +This feature indicates whether @value{GDBN} supports exec event +extensions to the remote protocol. @value{GDBN} does not use such +extensions unless the stub also reports that it supports them by +including @samp{exec-events+} in its @samp{qSupported} reply. @end table Stubs should ignore any unknown values for @@ -36522,6 +36544,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{exec-events} +@tab No +@tab @samp{-} +@tab No + @end multitable These are the currently defined stub features, in more detail: @@ -36727,6 +36754,9 @@ The remote stub reports the @samp{fork} stop reason for fork events. The remote stub reports the @samp{vfork} stop reason for vfork events and vforkdone events. +@item exec-events +The remote stub reports the @samp{exec} stop reason for exec events. + @end table @item qSymbol:: -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH 5/5] Extended-remote exec event docs 2015-07-15 21:51 ` [PATCH 5/5] Extended-remote exec event docs Don Breazeal @ 2015-07-16 2:39 ` Eli Zaretskii 0 siblings, 0 replies; 55+ messages in thread From: Eli Zaretskii @ 2015-07-16 2:39 UTC (permalink / raw) To: Don Breazeal; +Cc: gdb-patches, palves > From: Don Breazeal <donb@codesourcery.com> > Date: Wed, 15 Jul 2015 14:49:39 -0700 > > This patch adds documentation of support for exec events on > extended-remote Linux targets. > > Thanks, > --Don > > 2015-07-15 Don Breazeal <donb@codesourcery.com> > > * gdb/NEWS: Announce new remote packets for the exec-events > feature and the exec-events feature. > * gdb/doc/gdb.texinfo (Remote Configuration): Add exec event > feature to table of packet settings. > (Stop Reply Packets): Add exec events to the list of stop > reasons. > (General Query Packets): Add exec events to tables of > 'gdbfeatures' and 'stub features' supported in the qSupported > packet, as well as to the list containing stub feature > details. This is OK, thanks. ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH 4/5] Eliminate spurious warnings from remote exec 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal ` (3 preceding siblings ...) 2015-07-15 21:51 ` [PATCH 5/5] Extended-remote exec event docs Don Breazeal @ 2015-07-15 21:51 ` Don Breazeal 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal 5 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-15 21:51 UTC (permalink / raw) To: gdb-patches, palves This patch eliminates some spurious gdbserver warnings that occur when following an exec event on extended-remote Linux targets. When gdbserver on Linux sets up the hook for shared library load detection, an initial step is to read the version number field of the r_debug structure from memory. In the current implementation, if the version number is not equal to one, a warning is printed by gdbserver. However, the number can be zero if the structure has not been initialized yet. This seems to happen most of the time after an exec. To suppress the warnings the error check was changed so that if the version number is not equal to one the function silently returns -1. Subsequent calls to the routine find an initialized r_debug structure. Tested on x86_64 GNU/Linux, both GDB tests and manual testing which followed an exec, then debugged a shared library loaded by the exec'd program to ensure that there were no warnings and that debugging shared libs was not adversely affected. Thanks --Don 2015-07-15 Don Breazeal <donb@codesourcery.com> * gdb/gdbserver/linux-low.c (linux_qxfer_libraries_svr4): Return silently on r_debug version error instead of printing a warning. --- gdb/gdbserver/linux-low.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 47d8bc3..37eceb5 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -6421,10 +6421,16 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, { if (linux_read_memory (priv->r_debug + lmo->r_version_offset, (unsigned char *) &r_version, - sizeof (r_version)) != 0 - || r_version != 1) + sizeof (r_version)) != 0) + warning ("error reading r_debug version from memory"); + else if (r_version != 1) { - warning ("unexpected r_debug version %d", r_version); + /* If the version is incorrect, it probably means that + r_debug hasn't been initialized yet. Just silently + return an error. We will try again in a subsequent + pass through here, e.g. at the next library load + event. */ + return -1; } else if (read_one_ptr (priv->r_debug + lmo->r_map_offset, &lm_addr, ptr_size) != 0) -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 0/5] Extended-remote exec events 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal ` (4 preceding siblings ...) 2015-07-15 21:51 ` [PATCH 4/5] Eliminate spurious warnings from remote exec Don Breazeal @ 2015-07-30 23:19 ` Don Breazeal 2015-07-30 23:19 ` [PATCH v2 2/5] Extended-remote exec catchpoints Don Breazeal ` (5 more replies) 5 siblings, 6 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-30 23:19 UTC (permalink / raw) To: gdb-patches, palves This is an update to the extended-remote exec event patchset. The differences from the previous version include: 1) support for the multi-arch case (e.g. 64-bit executable execs a 32-bit executable). This is mainly accomplished by re-initializing the target architecture on both the remote and client sides after an exec event. 2) fixing the exec event message to use a process-style ptid to match the message for the native case (same as was done for fork events). 3) fixing intermittent failure introduced in gdb.base/pie-execl.exp in the previous version. Original description is mostly unchanged below. Thanks --Don -------------- This patch series implements exec events for extended-remote Linux targets. It provides exec event notification, follow-exec functionality, and exec catchpoints. Several tests related to exec event features have been modified to work with the native-extended-gdbserver target. It is part of the larger effort to implement "remote follow fork". This work has been divided into three parts: 1) Extended-remote fork events, providing follow-fork-mode, detach-on-fork, and fork catchpoints. This was pushed earlier this year: https://sourceware.org/ml/gdb-patches/2015-05/msg00278.html 2) Extended-remote exec events, this patchset. 3) Fork and exec events for native-gdbserver target. This patchset derives from part of a patch series submitted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00868.html The primary difference between this patchset and that one is that this one does not use ptrace exit events (PTRACE_O_TRACEEXIT) for notification of thread exit. In addition, a number of changes were made to conform to to the final version of the extended-remote fork event patchset (#1 above). Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. The contents of this patchset are as follows: Patch 1/5: Extended-remote exec event support. Patch 2/5: Extended-remote exec catchpoints. Patch 3/5: Extended-remote exec-related test updates. Patch 4/5: Eliminates some spurious warnings related to the solib event hook that are emitted after an extended-remote exec event. Patch 5/5: Extended-remote exec event documentation. ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 2/5] Extended-remote exec catchpoints 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal @ 2015-07-30 23:19 ` Don Breazeal 2015-07-30 23:19 ` [PATCH v2 1/5] Extended-remote follow exec Don Breazeal ` (4 subsequent siblings) 5 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-30 23:19 UTC (permalink / raw) To: gdb-patches, palves This patch is unchanged from v1 of this patchset. ----- This patch implements exec catchpoints for extended-remote Linux targets. The implementation follows the same approach used for fork catchpoints, implementing extended-remote target routines for inserting and removing the catchpoints by just checking if exec events are supported. Existing host-side code and previous support for extended-remote exec events takes care of the rest. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. Thanks --Don gdb/ 2015-07-30 Don Breazeal <donb@codesourcery.com> * remote.c (remote_exec_event_p): New function. (remote_insert_exec_catchpoint): New function. (remote_remove_exec_catchpoint): New function. (init_extended_remote_ops): Initialize extended_remote_ops members to_insert_exec_catchpoint and to_remove_exec_catchpoint. --- gdb/remote.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/gdb/remote.c b/gdb/remote.c index 1aeba30..bfde892 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1500,6 +1500,14 @@ remote_vfork_event_p (struct remote_state *rs) return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE; } +/* Returns true if exec events are supported. */ + +static int +remote_exec_event_p (struct remote_state *rs) +{ + return packet_support (PACKET_exec_event_feature) == PACKET_ENABLE; +} + /* Insert fork catchpoint target routine. If fork events are enabled then return success, nothing more to do. */ @@ -1540,6 +1548,26 @@ remote_remove_vfork_catchpoint (struct target_ops *ops, int pid) return 0; } +/* Insert exec catchpoint target routine. If exec events are + enabled, just return success. */ + +static int +remote_insert_exec_catchpoint (struct target_ops *ops, int pid) +{ + struct remote_state *rs = get_remote_state (); + + return !remote_exec_event_p (rs); +} + +/* Remove exec catchpoint target routine. Nothing to do, just + return success. */ + +static int +remote_remove_exec_catchpoint (struct target_ops *ops, int pid) +{ + return 0; +} + /* Tokens for use by the asynchronous signal handlers for SIGINT. */ static struct async_signal_handler *async_sigint_remote_twice_token; static struct async_signal_handler *async_sigint_remote_token; @@ -12417,6 +12445,10 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; = remote_insert_vfork_catchpoint; extended_remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint; + extended_remote_ops.to_insert_exec_catchpoint + = remote_insert_exec_catchpoint; + extended_remote_ops.to_remove_exec_catchpoint + = remote_remove_exec_catchpoint; } static int -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 1/5] Extended-remote follow exec 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal 2015-07-30 23:19 ` [PATCH v2 2/5] Extended-remote exec catchpoints Don Breazeal @ 2015-07-30 23:19 ` Don Breazeal 2015-08-13 14:50 ` Pedro Alves 2015-07-30 23:20 ` [PATCH v2 4/5] Eliminate spurious warnings from remote exec Don Breazeal ` (3 subsequent siblings) 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-30 23:19 UTC (permalink / raw) To: gdb-patches, palves This is an updated patch that implements support for multi-arch exec (e.g. a 64-bit executable execs a 32-bit executable). The changes from the previous version reinitialize the target architecture in both gdbserver and gdb when an exec event is first reported. The architecture re-init is done unconditionally for simplicity's sake, rather than only doing it if the architecture of the new executable is different from the existing target architecture. In addition we make sure that the exec event message uses a process-style ptid, so as to match the message emitted in the native case. This is the same change that was done for fork event messages. Updated commit message, ChangeLog, and patch follow. Thanks --Don ---- This patch implements support for exec events on extended-remote Linux targets. Follow-exec-mode and rerun behave as expected. Catchpoints and test updates are implemented in subsequent patches. This patch was derived from a patch posted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00877.html. It was originally based on some work done by Luis Machado in 2013. IMPLEMENTATION ---------------- I. Basic Exec Events Basic support for exec events in single-threaded programs was a fairly straightforward replication of the implementation in native GDB: 1) Enable exec events via ptrace options. 2) Add support for handling the exec events to the handle_extended_wait and linux_wait_for_event_filtered. Detect the exec event, then find and save the pathname of the executable file being exec'd and set event status flags. 3) Implement an additional "stop reason", "exec", in the RSP stop reply packet "T". Existing GDB code takes care of handling the exec event on the host side without modification. II. Multi-Arch Support We re-use the lwp, thread, and process data structures of the original execing inferior for the exec'd program. However, we don't know if the architecture of the new executable is the same as that of the original program. In order to ensure that the architecture is updated correctly, we unconditionally update it after every exec event. In gdbserver, we call a new wrapper function that call the target's arch_update function for the specified thread. We also update the previously-invalidated register cache, now that we know we will access the registers correctly with the updated architecture, and we clear the process's r_debug pointer to force a reset of the address of the solib event hook for the (possibly) new architecture. The old solib breakpoint itself is deleted in infrun.c:follow_exec. linux_arch_setup_thread (event_thr); event_lwp->stop_pc = get_pc (event_lwp); proc = get_thread_process (event_thr); proc->priv->r_debug = 0; We also need to update the target architecture on the GDB side. This must be done before it has a chance to try to access the registers, so we do this in remote.c:remote_parse_stop_reply as soon as we see the "exec" stop reason. else if (strncmp (p, "exec", p1 - p) == 0) { ---snip--- target_clear_description (); exec_file_attach (remote_exec_file, 0); III. Multi-Thread Support Support for exec events in multi-threaded programs required some additional work. When exec is called, the Linux kernel destroys all of the threads except the execing one. If the execing thread was not the thread group leader, the kernel resets the execing thread's tid to the tgid, and no exit notification is sent for the execing thread -- from the ptracer's perspective, it appears as though the execing thread just vanishes. The non-leader exec leaves gdbserver with one or more of several potential scenarios which require it to bring its thread lists (e.g. struct thread_info, struct lwp_info) in sync with reality. - The leader thread exited before the exec event was reported, and the execing thread cannot re-use its data structures. In this case gdbserver must recognize that an exec event occurred and there are no thread structures for the leader thread, so it must add new structures to the lists for the 'new' leader thread. 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; } - The execing thread can re-use the previous leader thread's data structures, and the old data structures used for the execing thread prior to the exec are left with a running status and no actual thread associated with it. There are two major issues to address because of this. First, when a non-leader execing thread re-uses the previous leader's thread_info structure, it inherits the old thread's register cache. If this is left as-is it will eventually be flushed to the target, clobbering the valid register values with those from the old thread. So when an EXEC event occurs we always invalidate the register cache. Note that we can't call regcache_invalidate, since that flushes the cache to the target, clobbering all the registers. else if (event == PTRACE_EVENT_EXEC && report_exec_events) { struct regcache *regcache; ---snip snip--- regcache = (struct regcache *) inferior_regcache_data (event_thr); free_register_cache (regcache); set_inferior_regcache_data (event_thr, NULL); The second issue is that gdbserver must clean up any stale thread/lwp structures before it eventually tries to stop all the threads. If it doesn't, it will hang in sigsuspend, waiting for an event from a non-existent thread. For all-stop mode We do this by checking the return value from kill_lwp in send_sigstop, eventually called after calling stop_all_lwps, which is used to stop the threads in all-stop mode. If kill_lwp returns an error and errno is ESRCH, we know that the lwp with that pid is gone, and we delete the associated data structures. - kill_lwp (pid, SIGSTOP); + errno = 0; + ret = kill_lwp (pid, SIGSTOP); + if (ret == -1 && errno == ESRCH) + { + /* If the kill fails with "No such process", on GNU/Linux we know + that the LWP has vanished - it is not a zombie, it is gone. + This is because a thread that was not the thread group leader + called exec and took over the leader's lwp. */ + delete_lwp (lwp); + set_desired_thread (0); In the same case in non-stop mode, we aren't going to stop all the lwps. In order to utilize the same mechanism used in all-stop mode, we call stop_all_lwps/unstop_all_lwps in succession, just to check for ESRCH errors and to delete any stale thread structures. if (non_stop && stopping_threads == NOT_STOPPING_THREADS) { /* In non-stop mode, make sure we delete the lwp entry for a non-leader exec'ing thread, which will have vanished. We do this by sending a signal to all the other threads in the lwp list, deleting any that are not found. Note that in all-stop mode this will happen when we stop all the threads. */ stop_all_lwps (0, event_lwp); unstop_all_lwps (0, event_lwp); } Note that the native implementation uses a different mechanism for identifying the stale data structure scenario. It determines that the execing thread has "vanished" by calling waitpid(PID) and checking for a return value of ECHILD, which means that the thread is gone. We don't want to use waitpid(PID) in gdbserver, based on the discussion in: https://www.sourceware.org/ml/gdb-patches/2014-02/msg00828.html so we use the send_sigstop method described above instead. TESTING -------- x86_64 GNU/Linux for native, native-gdbserver, and native-extended-gdbserver targets. Most of the exec-related tests fail due to the lack of catchpoints and extended-remote support in the tests, both of which are resolved in subsequent patches in this patchset. gdb/gdbserver/ 2015-07-30 Don Breazeal <donb@codesourcery.com> Luis Machado <lgustavo@codesourcery.com> * linux-low.c (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. (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. (linux_wait_for_event_filtered): Update comment. (extended_event_reported): Add TARGET_WAITKIND_EXECD. (linux_wait_1): Prevent clobbering extended event status. (send_sigstop): Check return from kill_lwp and delete non- existent lwps. (linux_supports_exec_events): New function. * lynx-low.c (lynx_target_ops) <supports_exec_events>: Initialize new member. * remote-utils.c (prepare_resume_reply): New stop reason 'exec'. * server.c (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. * win32-low.c (win32_target_ops) <supports_exec_events>: Initialize new member. gdb/ 2015-07-30 Don Breazeal <donb@codesourcery.com> Luis Machado <lgustavo@codesourcery.com> * infrun.c (follow_exec): Use process-style ptid for exec message. * nat/linux-ptrace.c (linux_supports_traceexec): New function. * nat/linux-ptrace.h (linux_supports_traceexec): Declare. * remote.c (anonymous enum) <PACKET_exec_event_feature> New enumeration constant. (remote_protocol_features): Add entry for exec-events feature. (remote_query_supported): Add client side of qSupported query for exec-events feature. (remote_parse_stop_reply): Handle 'exec' stop reason. (_initialize_remote): Call add_packet_config_cmd for remote exec-events feature. --- gdb/gdbserver/linux-low.c | 161 +++++++++++++++++++++++++++++++++++++------ gdb/gdbserver/lynx-low.c | 1 + gdb/gdbserver/remote-utils.c | 20 ++++++ gdb/gdbserver/server.c | 11 +++ gdb/gdbserver/server.h | 1 + gdb/gdbserver/target.h | 7 ++ gdb/gdbserver/win32-low.c | 1 + gdb/infrun.c | 4 +- gdb/nat/linux-ptrace.c | 13 +++- gdb/nat/linux-ptrace.h | 1 + gdb/remote.c | 36 ++++++++++ 11 files changed, 230 insertions(+), 26 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 9bc9fa3..af4619f 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -413,6 +413,29 @@ linux_add_process (int pid, int attached) static CORE_ADDR get_pc (struct lwp_info *lwp); +/* 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 event, we need to add the new LWP to our list (and return 0 so as not to report the trap to higher layers). */ @@ -554,6 +577,56 @@ 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 regcache *regcache; + + if (debug_threads) + { + debug_printf ("HEW: Got exec event from LWP %ld\n", + lwpid_of (event_thr)); + } + + /* If the exec was not called by the thread group leader, then + the lwp_info and thread_info structures are out-of-date, + containing information about the original leader thread and + not the new exec'ing leader thread. Invalidate the register + cache without flushing it to the target. */ + regcache = (struct regcache *) inferior_regcache_data (event_thr); + free_register_cache (regcache); + set_inferior_regcache_data (event_thr, NULL); + + /* The new executable may be for a different architecture than + that of the execing process, so re-initialize the architecture. + The call to get_pc will refill the register cache. */ + linux_arch_setup_thread (event_thr); + event_lwp->stop_pc = get_pc (event_lwp); + + 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_stop; + event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; + + if (non_stop && stopping_threads == NOT_STOPPING_THREADS) + { + /* In non-stop mode, make sure we delete the lwp entry for a + non-leader exec'ing thread, which will have vanished. We + do this by sending a signal to all the other threads in the + lwp list, deleting any that are not found. Note that in + all-stop mode this will happen when we stop all the threads. */ + stop_all_lwps (0, event_lwp); + unstop_all_lwps (0, event_lwp); + } + + /* Report the event. */ + return 0; + } internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); } @@ -819,14 +892,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. */ @@ -1614,7 +1679,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) @@ -2040,6 +2105,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; } @@ -2056,6 +2124,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 @@ -2113,17 +2213,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 { @@ -2357,8 +2450,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); @@ -2756,7 +2848,8 @@ extended_event_reported (const struct target_waitstatus *waitstatus) return (waitstatus->kind == TARGET_WAITKIND_FORKED || waitstatus->kind == TARGET_WAITKIND_VFORKED - || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE); + || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE + || waitstatus->kind == TARGET_WAITKIND_EXECD); } /* Wait for process, returns status. */ @@ -3301,7 +3394,8 @@ linux_wait_1 (ptid_t ptid, ourstatus->value.sig = GDB_SIGNAL_0; } else if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) != SIGSTOP) + && WSTOPSIG (w) != SIGSTOP + && !extended_event_reported (ourstatus)) { /* A thread that has been requested to stop by GDB with vCont;t, but, it stopped for other reasons. */ @@ -3419,6 +3513,7 @@ static void send_sigstop (struct lwp_info *lwp) { int pid; + int ret; pid = lwpid_of (get_lwp_thread (lwp)); @@ -3436,7 +3531,20 @@ send_sigstop (struct lwp_info *lwp) debug_printf ("Sending sigstop to lwp %d\n", pid); lwp->stop_expected = 1; - kill_lwp (pid, SIGSTOP); + errno = 0; + ret = kill_lwp (pid, SIGSTOP); + if (ret == -1 && errno == ESRCH) + { + /* If the kill fails with "No such process", on GNU/Linux we know + that the LWP has vanished - it is not a zombie, it is gone. + This is because a thread that was not the thread group leader + called exec and took over the leader's lwp. */ + delete_lwp (lwp); + set_desired_thread (0); + + if (debug_threads) + debug_printf ("send_sigstop: lwp %d has vanished\n", pid); + } } static int @@ -5623,6 +5731,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. */ @@ -6711,6 +6827,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 5cf03be..f56d982 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 bb31456..79d5ee8 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1116,6 +1116,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; @@ -1133,6 +1134,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]; + + 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 2918770..ee0a044 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; @@ -2109,6 +2110,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); @@ -2165,6 +2172,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+"); @@ -3547,6 +3557,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 09a5624..258909d 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; /* True if the "swbreak+" feature is active. In that case, GDB wants diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index fefd8d1..83a55cd 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 7ccb3dd..53f6696 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 */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 445a612..249d867 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1056,6 +1056,7 @@ follow_exec (ptid_t ptid, char *execd_pathname) struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); int pid = ptid_get_pid (ptid); + ptid_t process_ptid; /* This is an exec event that we actually wish to pay attention to. Refresh our symbol table to the newly exec'd program, remove any @@ -1122,8 +1123,9 @@ follow_exec (ptid_t ptid, char *execd_pathname) update_breakpoints_after_exec (); /* What is this a.out's name? */ + process_ptid = pid_to_ptid (pid); printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (inferior_ptid), + target_pid_to_str (process_ptid), execd_pathname); /* We've followed the inferior through an exec. Therefore, the diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index f097c8a..235dfba 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -528,9 +528,7 @@ ptrace_supports_feature (int ptrace_options) } /* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace, - 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is - PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, - since they were all added to the kernel at the same time. */ + 0 otherwise. */ int linux_supports_tracefork (void) @@ -538,6 +536,15 @@ linux_supports_tracefork (void) return ptrace_supports_feature (PTRACE_O_TRACEFORK); } +/* Returns non-zero if PTRACE_EVENT_EXEC is supported by ptrace, + 0 otherwise. */ + +int +linux_supports_traceexec (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEEXEC); +} + /* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace, 0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h index 41f668c..c2ecf3c 100644 --- a/gdb/nat/linux-ptrace.h +++ b/gdb/nat/linux-ptrace.h @@ -161,6 +161,7 @@ extern void linux_check_ptrace_features (void); extern void linux_enable_event_reporting (pid_t pid, int attached); extern void linux_disable_event_reporting (pid_t pid); extern int linux_supports_tracefork (void); +extern int linux_supports_traceexec (void); extern int linux_supports_traceclone (void); extern int linux_supports_tracevforkdone (void); extern int linux_supports_tracesysgood (void); diff --git a/gdb/remote.c b/gdb/remote.c index 4ac393b..1aeba30 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1367,6 +1367,9 @@ enum { /* Support for the Qbtrace-conf:pt:size packet. */ PACKET_Qbtrace_conf_pt_size, + /* Support for exec events. */ + PACKET_exec_event_feature, + PACKET_MAX }; @@ -4187,6 +4190,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_fork_event_feature }, { "vfork-events", PACKET_DISABLE, remote_supported_packet, PACKET_vfork_event_feature }, + { "exec-events", PACKET_DISABLE, remote_supported_packet, + PACKET_exec_event_feature }, { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_conf_pt_size } }; @@ -4275,6 +4280,9 @@ remote_query_supported (void) if (packet_set_cmd_state (PACKET_vfork_event_feature) != AUTO_BOOLEAN_FALSE) q = remote_query_supported_append (q, "vfork-events+"); + if (packet_set_cmd_state (PACKET_exec_event_feature) + != AUTO_BOOLEAN_FALSE) + q = remote_query_supported_append (q, "exec-events+"); } q = reconcat (q, "qSupported:", q, (char *) NULL); @@ -5934,6 +5942,31 @@ Packet: '%s'\n"), event->ws.kind = TARGET_WAITKIND_VFORK_DONE; p = skip_to_semicolon (p1 + 1); } + else if (strncmp (p, "exec", p1 - p) == 0) + { + ULONGEST pid; + char pathname[PATH_MAX]; + + p = unpack_varlen_hex (++p1, &pid); + + /* Save the pathname for event reporting and for + the next run command. */ + hex2bin (p1, (gdb_byte *) pathname, (p - p1)/2); + /* Add the null terminator. */ + pathname[(p - p1)/2] = '\0'; + /* This is freed during event handling. */ + event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.kind = TARGET_WAITKIND_EXECD; + /* Save the pathname for the next run command. */ + xfree (remote_exec_file); + remote_exec_file = xstrdup (pathname); + /* Reset the architecture in case the new executable is + different from the execing executable. We need to + do this right now, before any register access, to + keep the client and remote architectures in sync. */ + target_clear_description (); + exec_file_attach (remote_exec_file, 0); + } else { ULONGEST pnum; @@ -12983,6 +13016,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size], "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature], + "exec-event-feature", "exec-event-feature", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 1/5] Extended-remote follow exec 2015-07-30 23:19 ` [PATCH v2 1/5] Extended-remote follow exec Don Breazeal @ 2015-08-13 14:50 ` Pedro Alves 0 siblings, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-08-13 14:50 UTC (permalink / raw) To: Don Breazeal, gdb-patches Hi Don, Starting to look at this. See questions/comments below. > The second issue is that gdbserver must clean up any stale thread/lwp > structures before it eventually tries to stop all the threads. If it > doesn't, it will hang in sigsuspend, waiting for an event from a > non-existent thread. > > For all-stop mode We do this by checking the return value from > kill_lwp in send_sigstop, eventually called after calling > stop_all_lwps, which is used to stop the threads in all-stop mode. If > kill_lwp returns an error and errno is ESRCH, we know that the lwp > with that pid is gone, and we delete the associated data structures. > > - kill_lwp (pid, SIGSTOP); > + errno = 0; > + ret = kill_lwp (pid, SIGSTOP); > + if (ret == -1 && errno == ESRCH) > + { > + /* If the kill fails with "No such process", on GNU/Linux we know > + that the LWP has vanished - it is not a zombie, it is gone. > + This is because a thread that was not the thread group leader > + called exec and took over the leader's lwp. */ > + delete_lwp (lwp); > + set_desired_thread (0); I can't see how this fixes the issue completely. A thread may well exec just _after_ you did a successfully did kill_lwp(pid, SIGSTOP), and then we'll still hang waiting for pid. Seems to me this must be handled on the wait side. Alternatively, how about just requiring Linux >= 3.0 for this feature, and retrieve the ID of the thread that execed with PTRACE_GETEVENTMSG? > + else if (event == PTRACE_EVENT_EXEC && report_exec_events) > + { > + struct regcache *regcache; > + > + if (debug_threads) > + { > + debug_printf ("HEW: Got exec event from LWP %ld\n", > + lwpid_of (event_thr)); > + } > + > + /* If the exec was not called by the thread group leader, then > + the lwp_info and thread_info structures are out-of-date, > + containing information about the original leader thread and > + not the new exec'ing leader thread. Invalidate the register > + cache without flushing it to the target. */ > + regcache = (struct regcache *) inferior_regcache_data (event_thr); The cast is no longer necessary. inferior_regcache_data now returns a struct regcache * already. > + free_register_cache (regcache); > + set_inferior_regcache_data (event_thr, NULL); > + > + /* The new executable may be for a different architecture than > + that of the execing process, so re-initialize the architecture. > + The call to get_pc will refill the register cache. */ > + linux_arch_setup_thread (event_thr); > + event_lwp->stop_pc = get_pc (event_lwp); > + > + 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_stop; Shouldn't this be resume_continue? > + event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; > + > > @@ -2056,6 +2124,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)) Please remove the redundant parenthesis. > @@ -1133,6 +1134,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) More unnecessary parens. > + { > + enum gdb_signal signal = GDB_SIGNAL_TRAP; > + const char *event = "exec"; > + char hexified_pathname[PATH_MAX]; PATH_MAX would be the max size if it weren't for hexification. An hexified string can occupy double that. > /* We've followed the inferior through an exec. Therefore, the > diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c > index f097c8a..235dfba 100644 > --- a/gdb/nat/linux-ptrace.c > +++ b/gdb/nat/linux-ptrace.c > @@ -528,9 +528,7 @@ ptrace_supports_feature (int ptrace_options) > } > > /* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace, > - 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is > - PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, > - since they were all added to the kernel at the same time. */ > + 0 otherwise. */ Why remove this info? > > q = reconcat (q, "qSupported:", q, (char *) NULL); > @@ -5934,6 +5942,31 @@ Packet: '%s'\n"), > event->ws.kind = TARGET_WAITKIND_VFORK_DONE; > p = skip_to_semicolon (p1 + 1); > } > + else if (strncmp (p, "exec", p1 - p) == 0) > + { > + ULONGEST pid; > + char pathname[PATH_MAX]; > + > + p = unpack_varlen_hex (++p1, &pid); > + > + /* Save the pathname for event reporting and for > + the next run command. */ > + hex2bin (p1, (gdb_byte *) pathname, (p - p1)/2); Missing spaces around /. > + /* Add the null terminator. */ > + pathname[(p - p1)/2] = '\0'; Ditto. > + /* This is freed during event handling. */ > + event->ws.value.execd_pathname = xstrdup (pathname); > + event->ws.kind = TARGET_WAITKIND_EXECD; > + /* Save the pathname for the next run command. */ > + xfree (remote_exec_file); > + remote_exec_file = xstrdup (pathname); > + /* Reset the architecture in case the new executable is > + different from the execing executable. We need to > + do this right now, before any register access, to > + keep the client and remote architectures in sync. */ > + target_clear_description (); Each inferior has a description. Is there anything that makes sure this is clearing the description of the right inferior? > + exec_file_attach (remote_exec_file, 0); Ditto. It seems wrong to do this here -- infrun.c:follow_exec will do this, and more. E.g., this will cause breakpoints to be reset, but we haven't yet marked the old locations as wiped/uninserted. infrun.c:follow_exec does that (the mark_breakpoints_out call). Another example, this doesn't handle "set follow-exec-mode new". Seems like we need to find another way to handle the issue you saw. What were the register accesses you saw? Is that the expedited registers parsing just below, or something else? Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 4/5] Eliminate spurious warnings from remote exec 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal 2015-07-30 23:19 ` [PATCH v2 2/5] Extended-remote exec catchpoints Don Breazeal 2015-07-30 23:19 ` [PATCH v2 1/5] Extended-remote follow exec Don Breazeal @ 2015-07-30 23:20 ` Don Breazeal 2015-08-13 15:38 ` Pedro Alves 2015-07-30 23:20 ` [PATCH v2 5/5] Extended-remote exec event docs Don Breazeal ` (2 subsequent siblings) 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-30 23:20 UTC (permalink / raw) To: gdb-patches, palves This patch is unchanged from the previous version. ----- This patch eliminates some spurious gdbserver warnings that occur when following an exec event on extended-remote Linux targets. When gdbserver on Linux sets up the hook for shared library load detection, an initial step is to read the version number field of the r_debug structure from memory. In the current implementation, if the version number is not equal to one, a warning is printed by gdbserver. However, the number can be zero if the structure has not been initialized yet. This seems to happen most of the time after an exec. To suppress the warnings the error check was changed so that if the version number is not equal to one the function silently returns -1. Subsequent calls to the routine find an initialized r_debug structure. Tested on x86_64 GNU/Linux, both GDB tests and manual testing which followed an exec, then debugged a shared library loaded by the exec'd program to ensure that there were no warnings and that debugging shared libs was not adversely affected. Thanks --Don gdb/gdbserver/ 2015-07-30 Don Breazeal <donb@codesourcery.com> * linux-low.c (linux_qxfer_libraries_svr4): Return silently on r_debug version error instead of printing a warning. --- gdb/gdbserver/linux-low.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index af4619f..c0770b8 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -580,6 +580,7 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) else if (event == PTRACE_EVENT_EXEC && report_exec_events) { struct regcache *regcache; + struct process_info *proc; if (debug_threads) { @@ -598,10 +599,15 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) /* The new executable may be for a different architecture than that of the execing process, so re-initialize the architecture. - The call to get_pc will refill the register cache. */ + The call to get_pc will refill the register cache. Force re- + initialization of r_debug from the (possibly) different dynamic + loader. */ linux_arch_setup_thread (event_thr); event_lwp->stop_pc = get_pc (event_lwp); + proc = get_thread_process (event_thr); + proc->priv->r_debug = 0; + /* Save the event for reporting. */ event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD; event_lwp->waitstatus.value.execd_pathname = xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr))); @@ -6462,10 +6468,16 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, { if (linux_read_memory (priv->r_debug + lmo->r_version_offset, (unsigned char *) &r_version, - sizeof (r_version)) != 0 - || r_version != 1) + sizeof (r_version)) != 0) + warning ("error reading r_debug version from memory"); + else if (r_version != 1) { - warning ("unexpected r_debug version %d", r_version); + /* We expect version 1 for glibc. If the version is incorrect, + it probably means that r_debug hasn't been initialized yet. + Just silently return an error. We will try again in a + subsequent pass through here, e.g. at the next library load + event. */ + return -1; } else if (read_one_ptr (priv->r_debug + lmo->r_map_offset, &lm_addr, ptr_size) != 0) -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 4/5] Eliminate spurious warnings from remote exec 2015-07-30 23:20 ` [PATCH v2 4/5] Eliminate spurious warnings from remote exec Don Breazeal @ 2015-08-13 15:38 ` Pedro Alves 0 siblings, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-08-13 15:38 UTC (permalink / raw) To: Don Breazeal, gdb-patches On 07/31/2015 12:19 AM, Don Breazeal wrote: > This patch is unchanged from the previous version. > > ----- > > This patch eliminates some spurious gdbserver warnings that occur when > following an exec event on extended-remote Linux targets. > > When gdbserver on Linux sets up the hook for shared library load > detection, an initial step is to read the version number field of the > r_debug structure from memory. In the current implementation, if the > version number is not equal to one, a warning is printed by gdbserver. > However, the number can be zero if the structure has not been > initialized yet. This seems to happen most of the time after an exec. I wonder how come this doesn't trigger right after connection with "target remote"? > > To suppress the warnings the error check was changed so that if > the version number is not equal to one the function silently returns > -1. Subsequent calls to the routine find an initialized r_debug > structure. > > Tested on x86_64 GNU/Linux, both GDB tests and manual testing which > followed an exec, then debugged a shared library loaded by the exec'd > program to ensure that there were no warnings and that debugging shared > libs was not adversely affected. > > Thanks > --Don > > gdb/gdbserver/ > 2015-07-30 Don Breazeal <donb@codesourcery.com> > > * linux-low.c (linux_qxfer_libraries_svr4): > Return silently on r_debug version error instead of > printing a warning. > > --- > gdb/gdbserver/linux-low.c | 20 ++++++++++++++++---- > 1 file changed, 16 insertions(+), 4 deletions(-) > > diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c > index af4619f..c0770b8 100644 > --- a/gdb/gdbserver/linux-low.c > +++ b/gdb/gdbserver/linux-low.c > @@ -580,6 +580,7 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) > else if (event == PTRACE_EVENT_EXEC && report_exec_events) > { > struct regcache *regcache; > + struct process_info *proc; > > if (debug_threads) > { > @@ -598,10 +599,15 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) > > /* The new executable may be for a different architecture than > that of the execing process, so re-initialize the architecture. > - The call to get_pc will refill the register cache. */ > + The call to get_pc will refill the register cache. Force re- > + initialization of r_debug from the (possibly) different dynamic > + loader. */ > linux_arch_setup_thread (event_thr); > event_lwp->stop_pc = get_pc (event_lwp); > + proc = get_thread_process (event_thr); > + proc->priv->r_debug = 0; (you only mentioned doing this in an earlier patch, I believe. The changelog and commit logs of this patch don't mention this, only the warning.) Seems to be we should reset everything, not just r_debug. E.g., priv->thread_db. After the exec, the new program might not even be threaded. Thus we should probably call thread_db_mourn. Also, the priv->arch_private bits -- those will hold debug registers things, for watchpoints/hw-breakpoints. So what happens if a process that has watchpoints set, execs? It would seem to me that we should completely forget about the previous debug registers mirrors, etc.? Also, what about breakpoints managed by gdbserver? If they were inserted at the time of the exec, mem-break.c will continue believing they are still inserted. That means that if GDB tries to insert another breakpoint at the same address, gdbserver won't actually insert it. And also, if gdb reads code where an old breakpoint is still marked inserted, gdb reads back the old breakpoint's shadow, which doesn't make sense any longer after the exec. This comment in follow_exec in gdb puts it best: /* We've followed the inferior through an exec. Therefore, the inferior has essentially been killed & reborn. */ > > + /* Save the event for reporting. */ (this hunk also seems to belong in some other earlier patch.) > event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD; > event_lwp->waitstatus.value.execd_pathname > = xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr))); > @@ -6462,10 +6468,16 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, > { > if (linux_read_memory (priv->r_debug + lmo->r_version_offset, > (unsigned char *) &r_version, > - sizeof (r_version)) != 0 > - || r_version != 1) > + sizeof (r_version)) != 0) > + warning ("error reading r_debug version from memory"); > + else if (r_version != 1) > { > - warning ("unexpected r_debug version %d", r_version); > + /* We expect version 1 for glibc. If the version is incorrect, > + it probably means that r_debug hasn't been initialized yet. > + Just silently return an error. We will try again in a > + subsequent pass through here, e.g. at the next library load > + event. */ > + return -1; > } > else if (read_one_ptr (priv->r_debug + lmo->r_map_offset, > &lm_addr, ptr_size) != 0) > Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 5/5] Extended-remote exec event docs 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal ` (2 preceding siblings ...) 2015-07-30 23:20 ` [PATCH v2 4/5] Eliminate spurious warnings from remote exec Don Breazeal @ 2015-07-30 23:20 ` Don Breazeal 2015-07-31 6:36 ` Eli Zaretskii 2015-08-13 15:43 ` Pedro Alves 2015-07-30 23:20 ` [PATCH v2 3/5] Extended-remote support for exec event tests Don Breazeal 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal 5 siblings, 2 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-30 23:20 UTC (permalink / raw) To: gdb-patches, palves This patch is unchanged from the previous version. It was reviewed and approved by Eli here: https://sourceware.org/ml/gdb-patches/2015-07/msg00466.html ----- This patch adds documentation of support for exec events on extended-remote Linux targets. Thanks, --Don gdb/ 2015-07-30 Don Breazeal <donb@codesourcery.com> * NEWS: Announce new remote packets for the exec-events feature and the exec-events feature. gdb/doc/ 2015-07-30 Don Breazeal <donb@codesourcery.com> * gdb.texinfo (Remote Configuration): Add exec event feature to table of packet settings. (Stop Reply Packets): Add exec events to the list of stop reasons. (General Query Packets): Add exec events to tables of 'gdbfeatures' and 'stub features' supported in the qSupported packet, as well as to the list containing stub feature details. --- gdb/NEWS | 17 +++++++++++++++++ gdb/doc/gdb.texinfo | 30 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index 7ce9758..87e1ad4 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -5,6 +5,23 @@ * Support for tracepoints on aarch64-linux was added in GDBserver. +* New remote packets + +exec stop reason + Indicates that an exec system call was executed. + +exec-events feature in qSupported + The qSupported packet allows GDB to request support for exec + events using the new 'gdbfeature' exec-event, and the qSupported + response can contain the corresponding 'stubfeature'. Set and + show commands can be used to display whether these features are enabled. + +* Extended-remote exec events + + ** GDB now has support for exec events on extended-remote Linux targets. + For such targets with Linux kernels 2.5.46 and later, this enables + follow-exec-mode and exec catchpoints. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 9e2ecd1..5970782 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20022,6 +20022,10 @@ are: @tab @code{vfork stop reason} @tab @code{vfork} +@item @code{exec-event-feature} +@tab @code{exec stop reason} +@tab @code{exec} + @end multitable @node Remote Stub @@ -35655,6 +35659,18 @@ appropriate @samp{qSupported} feature (@pxref{qSupported}). The remote stub must also supply the appropriate @samp{qSupported} feature indicating support. +@cindex exec events, remote reply +@item exec +The packet indicates that @code{execve} was called, and @var{r} +is the absolute pathname of the file that was executed, in hex. +This packet is only applicable to targets that support exec events. + +This packet should not be sent by default; older @value{GDBN} versions +did not support it. @value{GDBN} requests it, by supplying an +appropriate @samp{qSupported} feature (@pxref{qSupported}). The +remote stub must also supply the appropriate @samp{qSupported} feature +indicating support. + @end table @item W @var{AA} @@ -36259,6 +36275,12 @@ This feature indicates whether @value{GDBN} supports vfork event extensions to the remote protocol. @value{GDBN} does not use such extensions unless the stub also reports that it supports them by including @samp{vfork-events+} in its @samp{qSupported} reply. + +@item exec-events +This feature indicates whether @value{GDBN} supports exec event +extensions to the remote protocol. @value{GDBN} does not use such +extensions unless the stub also reports that it supports them by +including @samp{exec-events+} in its @samp{qSupported} reply. @end table Stubs should ignore any unknown values for @@ -36522,6 +36544,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{exec-events} +@tab No +@tab @samp{-} +@tab No + @end multitable These are the currently defined stub features, in more detail: @@ -36727,6 +36754,9 @@ The remote stub reports the @samp{fork} stop reason for fork events. The remote stub reports the @samp{vfork} stop reason for vfork events and vforkdone events. +@item exec-events +The remote stub reports the @samp{exec} stop reason for exec events. + @end table @item qSymbol:: -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 5/5] Extended-remote exec event docs 2015-07-30 23:20 ` [PATCH v2 5/5] Extended-remote exec event docs Don Breazeal @ 2015-07-31 6:36 ` Eli Zaretskii 2015-07-31 17:06 ` Don Breazeal 2015-08-13 15:43 ` Pedro Alves 1 sibling, 1 reply; 55+ messages in thread From: Eli Zaretskii @ 2015-07-31 6:36 UTC (permalink / raw) To: Don Breazeal; +Cc: gdb-patches, palves > From: Don Breazeal <donb@codesourcery.com> > Date: Thu, 30 Jul 2015 16:19:20 -0700 > > This patch is unchanged from the previous version. It was > reviewed and approved by Eli here: > https://sourceware.org/ml/gdb-patches/2015-07/msg00466.html > ----- > > This patch adds documentation of support for exec events on > extended-remote Linux targets. > > Thanks, > --Don > > gdb/ > 2015-07-30 Don Breazeal <donb@codesourcery.com> > > * NEWS: Announce new remote packets for the exec-events > feature and the exec-events feature. > > gdb/doc/ > 2015-07-30 Don Breazeal <donb@codesourcery.com> > > * gdb.texinfo (Remote Configuration): Add exec event > feature to table of packet settings. > (Stop Reply Packets): Add exec events to the list of stop > reasons. > (General Query Packets): Add exec events to tables of > 'gdbfeatures' and 'stub features' supported in the qSupported > packet, as well as to the list containing stub feature > details. OK, with a single comment: > +@cindex exec events, remote reply > +@item exec > +The packet indicates that @code{execve} was called, and @var{r} > +is the absolute pathname of the file that was executed, in hex. GNU coding standards frown on using "pathname" in this context; please use "file name" instead. Thanks. ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 5/5] Extended-remote exec event docs 2015-07-31 6:36 ` Eli Zaretskii @ 2015-07-31 17:06 ` Don Breazeal 0 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-07-31 17:06 UTC (permalink / raw) To: Eli Zaretskii, Breazeal, Don; +Cc: gdb-patches, palves On 7/30/2015 11:36 PM, Eli Zaretskii wrote: >> From: Don Breazeal <donb@codesourcery.com> >> Date: Thu, 30 Jul 2015 16:19:20 -0700 >> >> This patch is unchanged from the previous version. It was >> reviewed and approved by Eli here: >> https://sourceware.org/ml/gdb-patches/2015-07/msg00466.html >> ----- >> >> This patch adds documentation of support for exec events on >> extended-remote Linux targets. >> >> Thanks, >> --Don >> >> gdb/ >> 2015-07-30 Don Breazeal <donb@codesourcery.com> >> >> * NEWS: Announce new remote packets for the exec-events >> feature and the exec-events feature. >> >> gdb/doc/ >> 2015-07-30 Don Breazeal <donb@codesourcery.com> >> >> * gdb.texinfo (Remote Configuration): Add exec event >> feature to table of packet settings. >> (Stop Reply Packets): Add exec events to the list of stop >> reasons. >> (General Query Packets): Add exec events to tables of >> 'gdbfeatures' and 'stub features' supported in the qSupported >> packet, as well as to the list containing stub feature >> details. > > OK, with a single comment: > >> +@cindex exec events, remote reply >> +@item exec >> +The packet indicates that @code{execve} was called, and @var{r} >> +is the absolute pathname of the file that was executed, in hex. > > GNU coding standards frown on using "pathname" in this context; please > use "file name" instead. > > Thanks. > Thanks Eli. I have made this change in my local copy. --Don ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 5/5] Extended-remote exec event docs 2015-07-30 23:20 ` [PATCH v2 5/5] Extended-remote exec event docs Don Breazeal 2015-07-31 6:36 ` Eli Zaretskii @ 2015-08-13 15:43 ` Pedro Alves 1 sibling, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-08-13 15:43 UTC (permalink / raw) To: Don Breazeal, gdb-patches On 07/31/2015 12:19 AM, Don Breazeal wrote: > diff --git a/gdb/NEWS b/gdb/NEWS > index 7ce9758..87e1ad4 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -5,6 +5,23 @@ > > * Support for tracepoints on aarch64-linux was added in GDBserver. > > +* New remote packets > + > +exec stop reason > + Indicates that an exec system call was executed. > + > +exec-events feature in qSupported > + The qSupported packet allows GDB to request support for exec > + events using the new 'gdbfeature' exec-event, and the qSupported > + response can contain the corresponding 'stubfeature'. Set and > + show commands can be used to display whether these features are enabled. Could you please mention the new commands as well? Look for "set remote " in the NEWS file for examples. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v2 3/5] Extended-remote support for exec event tests 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal ` (3 preceding siblings ...) 2015-07-30 23:20 ` [PATCH v2 5/5] Extended-remote exec event docs Don Breazeal @ 2015-07-30 23:20 ` Don Breazeal 2015-08-13 15:22 ` Pedro Alves 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-07-30 23:20 UTC (permalink / raw) To: gdb-patches, palves This updated patch includes changes to gdb.base/pie_execl.exp to correct the use of $inferior_spawn_id. The previous version caused intermittent errors with native targets. Thanks, --Don ----- This patch updates several exec-related tests and some of the library functions in order to get them running with extended-remote. There were three changes that were required, as follows: In gdb.base/foll-exec.exp, the proc 'zap_session' is used repeatedly to reset the state of the debugger before the next test. Part of that procedure is to 'set exec-file'. For remote targets, it is necessary to also 'set remote exec-file' to achieve the same effect (and execute the correct binary file in the subsequent test). In gdb.base/pie-execl.exp, there is an expect statement with an expression that is used to match output from both gdb and the program under debug. For the remote target, this had to be split into two expressions, using $inferior_spawn_id to match the output from the program. Because I had encountered problems with extended-remote exec events in non-stop mode in my manual testing, I added non-stop testing to the non-ldr-exc-[1234].exp tests. In order to set non-stop mode for remote targets, it is necessary to 'set non-stop on' after gdb has started, but before it connects to gdbserver. The non-ldr-... tests call 'clean_restart' in between tests, and it eventually calls 'gdb_start' which starts gdb and gdbserver and connects them. By adding a stop mode argument to clean_restart and gdb_start (in both lib/gdb.exp and boards/native-extended-gdbserver.exp), it was possible to set non-stop mode for remote targets. Since the arguments have a default value "all-stop", and only have an effect when "non-stop" is passed, these changes do not affect any existing test behavior. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. gdb/testsuite/ 2015-07-30 Don Breazeal <donb@codesourcery.com> * boards/native-extended-gdbserver.exp (gdb_start): Add argument 'mode' and set the stop mode before connecting. * gdb.base/foll-exec.exp (zap_session): For remote targets, set 'remote exec-file' as well as 'exec-file'. * gdb.base/pie-execl.exp (main): Use 'inferior_spawn_id' in an expect statement to match an expression with output from the program under debug. * gdb.threads/non-ldr-exc-1.exp (do_test, main): Add non-stop tests and pass stop mode argument to clean_restart. * gdb.threads/non-ldr-exc-2.exp: Likewise. * gdb.threads/non-ldr-exc-3.exp: Likewise. * gdb.threads/non-ldr-exc-4.exp: Likewise. * lib/gdb.exp (gdb_start): Add argument 'stop_mode', and set stop mode to non-stop if requested. (clean_restart): Add argument 'stop_mode' and pass to gdb_start. --- gdb/testsuite/boards/native-extended-gdbserver.exp | 8 +++++++- gdb/testsuite/gdb.base/foll-exec.exp | 7 +++++++ gdb/testsuite/gdb.base/pie-execl.exp | 24 ++++++++++++++++++++-- gdb/testsuite/gdb.threads/non-ldr-exc-1.exp | 16 ++++++++++----- gdb/testsuite/gdb.threads/non-ldr-exc-2.exp | 22 ++++++++++++++------ gdb/testsuite/gdb.threads/non-ldr-exc-3.exp | 22 ++++++++++++++------ gdb/testsuite/gdb.threads/non-ldr-exc-4.exp | 16 ++++++++++----- gdb/testsuite/lib/gdb.exp | 19 ++++++++--------- 8 files changed, 99 insertions(+), 35 deletions(-) diff --git a/gdb/testsuite/boards/native-extended-gdbserver.exp b/gdb/testsuite/boards/native-extended-gdbserver.exp index 744e044..4f43601 100644 --- a/gdb/testsuite/boards/native-extended-gdbserver.exp +++ b/gdb/testsuite/boards/native-extended-gdbserver.exp @@ -48,10 +48,16 @@ load_lib mi-support.exp # GDB is started. Note nothing is needed for gdb_exit, since # gdbserver is started with --once, causing it to exit once GDB # disconnects. -proc gdb_start { } { +proc gdb_start { {stop_mode "all-stop"} } { # Spawn GDB. default_gdb_start + # Non-stop mode must be set before connecting to gdbserver for it + # to be enabled in gdbserver, so we set non-stop here. + if { $stop_mode == "non-stop" } then { + gdb_test_no_output "set non-stop on" "enable non-stop mode" + } + # And then GDBserver, ready for extended-remote mode. gdbserver_start_multi diff --git a/gdb/testsuite/gdb.base/foll-exec.exp b/gdb/testsuite/gdb.base/foll-exec.exp index 5bea3ba..8b2eae0 100644 --- a/gdb/testsuite/gdb.base/foll-exec.exp +++ b/gdb/testsuite/gdb.base/foll-exec.exp @@ -68,6 +68,13 @@ proc zap_session {} { -re ".*$gdb_prompt $" {} timeout { fail "killing inferior (timeout)" ; return } } + + # For remote targets the 'file' command doesn't change the exec-file, + # as it does for native targets. In the remote case we must also use + # 'set remote exec-file'. + if [gdb_is_target_remote] then { + gdb_test_no_output "set remote exec-file $binfile" "reset remote exec-file to original file" + } } proc do_exec_tests {} { diff --git a/gdb/testsuite/gdb.base/pie-execl.exp b/gdb/testsuite/gdb.base/pie-execl.exp index 41411d5..b13299c 100644 --- a/gdb/testsuite/gdb.base/pie-execl.exp +++ b/gdb/testsuite/gdb.base/pie-execl.exp @@ -16,6 +16,9 @@ # The problem was due to amd64_skip_prologue attempting to access inferior # memory before the PIE (Position Independent Executable) gets relocated. +global inferior_spawn_id +global gdb_spawn_id + if ![istarget *-linux*] { continue } @@ -67,6 +70,7 @@ gdb_test_multiple "p/x &pie_execl_marker" $test { verbose -log "addr1 is $addr1" set test "continue" +set matches_found 0 gdb_test_multiple $test $test { -re "Error in re-setting breakpoint" { fail $test @@ -74,8 +78,24 @@ gdb_test_multiple $test $test { -re "Cannot access memory" { fail $test } - -re "pie-execl: re-exec.*executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { - pass $test + -i "$inferior_spawn_id" -re "pie-execl: re-exec" { + # output from inferior + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } + } + -i "$gdb_spawn_id" + -re "executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { + # output from gdb + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } } } diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp index 69e5cc6..147e7f3 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp @@ -28,11 +28,11 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 @@ -48,11 +48,17 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp index 9386153..748ff11 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp @@ -29,18 +29,26 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_continue_to_breakpoint "break-here" ".* break-here .*" + gdb_test_multiple "continue" "continue to breakpoint" { + -re ".*Breakpoint.*break-here.*" { + pass "continue to breakpoint" + } + } + + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } gdb_test "info threads" \ "\r\n\[ \t\]*Id\[ \t\]+Target\[ \t\]+Id\[ \t\]+Frame\[ \t\]*\r\n\\* 2 *Thread \[^\r\n\]* at \[^\r\n\]*" \ @@ -59,5 +67,7 @@ proc do_test { lock_sched } { } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp index cc7da1a..2dbcd81 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp @@ -31,18 +31,22 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_continue_to_breakpoint "break-here" ".* break-here .*" + gdb_test_multiple "continue" "continue to breakpoint" { + -re ".*Breakpoint.*break-here.*" { + pass "continue to breakpoint" + } + } # Also test with sched-lock to make sure we can follow the # non-leader thread execing even though the main thread wasn't @@ -51,11 +55,17 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp index a89b818..a9e5c5a 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp @@ -30,11 +30,11 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched stop_mode } { + with_test_prefix "lock-sched$lock_sched,$stop_mode" { global executable - clean_restart ${executable} + clean_restart ${executable} $stop_mode if ![runto_main] { return -1 @@ -50,11 +50,17 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $stop_mode == "non-stop" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +do_test 0 "all-stop" +do_test 1 "all-stop" +do_test 0 "non-stop" +do_test 1 "non-stop" diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index e3faf18..901a088 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -3694,8 +3694,11 @@ proc gdb_spawn_with_cmdline_opts { cmdline_flags } { # Overridable function -- you can override this function in your # baseboard file. -proc gdb_start { } { +proc gdb_start { {stop_mode "all-stop"} } { default_gdb_start + if { $stop_mode == "non-stop" } { + gdb_test_no_output "set non-stop on" "enable non-stop mode" + } } proc gdb_exit { } { @@ -4963,23 +4966,19 @@ proc build_executable { testname executable {sources ""} {options {debug}} } { } # Starts fresh GDB binary and loads an optional executable into GDB. -# Usage: clean_restart [executable] +# Usage: clean_restart [executable [mode]] # EXECUTABLE is the basename of the binary. +# If MODE is "non-stop", then non-stop mode will be enabled. -proc clean_restart { args } { +proc clean_restart { {executable ""} {stop_mode "all-stop"} } { global srcdir global subdir - if { [llength $args] > 1 } { - error "bad number of args: [llength $args]" - } - gdb_exit - gdb_start + gdb_start $stop_mode gdb_reinitialize_dir $srcdir/$subdir - if { [llength $args] >= 1 } { - set executable [lindex $args 0] + if { $executable != "" } { set binfile [standard_output_file ${executable}] gdb_load ${binfile} } -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v2 3/5] Extended-remote support for exec event tests 2015-07-30 23:20 ` [PATCH v2 3/5] Extended-remote support for exec event tests Don Breazeal @ 2015-08-13 15:22 ` Pedro Alves 0 siblings, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-08-13 15:22 UTC (permalink / raw) To: Don Breazeal, gdb-patches On 07/31/2015 12:19 AM, Don Breazeal wrote: > This patch updates several exec-related tests and some of the > library functions in order to get them running with extended-remote. > There were three changes that were required, as follows: > > In gdb.base/foll-exec.exp, the proc 'zap_session' is used repeatedly > to reset the state of the debugger before the next test. Part of > that procedure is to 'set exec-file'. For remote targets, it is > necessary to also 'set remote exec-file' to achieve the same > effect (and execute the correct binary file in the subsequent test). This assumes local gdbserver testing. This is something that should be done in the target board. Look for exec-file in gdb/testsuite/boards/native-extended-gdbserver.exp. Maybe we should just clean_restart instead ? > > In gdb.base/pie-execl.exp, there is an expect statement with an > expression that is used to match output from both gdb and the > program under debug. For the remote target, this had to be > split into two expressions, using $inferior_spawn_id to match > the output from the program. > > Because I had encountered problems with extended-remote exec events > in non-stop mode in my manual testing, I added non-stop testing to > the non-ldr-exc-[1234].exp tests. In order to set non-stop mode > for remote targets, it is necessary to 'set non-stop on' after gdb > has started, but before it connects to gdbserver. The non-ldr-... > tests call 'clean_restart' in between tests, and it eventually calls > 'gdb_start' which starts gdb and gdbserver and connects them. By > adding a stop mode argument to clean_restart and gdb_start (in > both lib/gdb.exp and boards/native-extended-gdbserver.exp), it was > possible to set non-stop mode for remote targets. Since the > arguments have a default value "all-stop", and only have an effect > when "non-stop" is passed, these changes do not affect any existing > test behavior. I don't think we can do this, because gdb_start is an overridable function (see comment above it). You can instead append set non-stop on to GDBFLAGS. E.g.,: save_vars { GDBFLAGS } { append GDBFLAGS " -ex \"set non-stop $nonstop\"" clean_restart } > diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp > index 69e5cc6..147e7f3 100644 > --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp > +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp > @@ -28,11 +28,11 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab > return -1 > } > > -proc do_test { lock_sched } { > - with_test_prefix "lock-sched$lock_sched" { > +proc do_test { lock_sched stop_mode } { > + with_test_prefix "lock-sched$lock_sched,$stop_mode" { > global executable > > - clean_restart ${executable} > + clean_restart ${executable} $stop_mode > > if ![runto_main] { > return -1 > @@ -48,11 +48,17 @@ proc do_test { lock_sched } { > gdb_test_no_output "set scheduler-locking on" > } > > + if { $stop_mode == "non-stop" } { > + gdb_test "thread 2" "Switching.*" > + } > + > gdb_test "continue" \ > ".*is executing new program.*Breakpoint 1, main.* at .*" \ > "continue over exec" > } > } > > -do_test 0 > -do_test 1 > +do_test 0 "all-stop" > +do_test 1 "all-stop" > +do_test 0 "non-stop" > +do_test 1 "non-stop" Please use foreach. E.g., foreach nonstop {"on" "off"} { foreach schedlock {"on" "off"} { do_test ... } } Note that schedlock on has no effect in non-stop mode. Maybe if !lock_sched && nonstop, we could issue "continue -a" instead of continue. > diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp > index 9386153..748ff11 100644 > --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp > +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp > @@ -29,18 +29,26 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab > return -1 > } > > -proc do_test { lock_sched } { > - with_test_prefix "lock-sched$lock_sched" { > +proc do_test { lock_sched stop_mode } { > + with_test_prefix "lock-sched$lock_sched,$stop_mode" { > global executable > > - clean_restart ${executable} > + clean_restart ${executable} $stop_mode > > if ![runto_main] { > return -1 > } > > gdb_breakpoint [gdb_get_line_number "break-here"] > - gdb_continue_to_breakpoint "break-here" ".* break-here .*" > + gdb_test_multiple "continue" "continue to breakpoint" { > + -re ".*Breakpoint.*break-here.*" { This doesn't expect the prompt, which is going to be racy -- the following gdb_test may fail if this test manages to leave the prompt in the expect buffer. What motivated this change? Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 0/4] Extended-remote exec events 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal ` (4 preceding siblings ...) 2015-07-30 23:20 ` [PATCH v2 3/5] Extended-remote support for exec event tests Don Breazeal @ 2015-09-09 23:05 ` Don Breazeal 2015-09-09 23:06 ` [PATCH v3 3/4] Extended-remote support for exec event tests Don Breazeal ` (3 more replies) 5 siblings, 4 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-09 23:05 UTC (permalink / raw) To: gdb-patches, palves Hi Pedro, Thanks for the previous review(s). This is an update to version 2 of the extended-remote exec event patchset. The most significant differences from the previous version include: 1) Gdbserver always creates a new inferior for an execing process. 2) GDB's 'remote exec-file' is now per-inferior instead off a static string. 3) There is a new GDB target hook 'target_follow_exec'. 4) Elimination of patch #4, which eliminated spurious warnings when setting up the solib event hook after an exec. The patch was no longer needed after change #1 above. 5) Test and documentation updates per review comments. Original description is unchanged below, except for eliminating patch #4. Thanks --Don -------------- This patch series implements exec events for extended-remote Linux targets. It provides exec event notification, follow-exec functionality, and exec catchpoints. Several tests related to exec event features have been modified to work with the native-extended-gdbserver target. It is part of the larger effort to implement "remote follow fork". This work has been divided into three parts: 1) Extended-remote fork events, providing follow-fork-mode, detach-on-fork, and fork catchpoints. This was pushed earlier this year: https://sourceware.org/ml/gdb-patches/2015-05/msg00278.html 2) Extended-remote exec events, this patchset. 3) Fork and exec events for native-gdbserver target. This patchset derives from part of a patch series submitted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00868.html The primary difference between this patchset and that one is that this one does not use ptrace exit events (PTRACE_O_TRACEEXIT) for notification of thread exit. In addition, a number of changes were made to conform to to the final version of the extended-remote fork event patchset (#1 above). Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. The contents of this patchset are as follows: Patch 1/4: Extended-remote exec event support. Patch 2/4: Extended-remote exec catchpoints. Patch 3/4: Extended-remote exec-related test updates. Patch 4/4: Extended-remote exec event documentation. ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 3/4] Extended-remote support for exec event tests 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal @ 2015-09-09 23:06 ` Don Breazeal 2015-09-10 13:26 ` Pedro Alves 2015-09-09 23:06 ` [PATCH v3 4/4] Extended-remote exec event docs Don Breazeal ` (2 subsequent siblings) 3 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-09-09 23:06 UTC (permalink / raw) To: gdb-patches, palves Hi Pedro, This updated patch addresses issues raised in the review of the previous version, as outlined below. It also includes the following: * gdb.base/foll-exec.exp: Copyright, formatting, and error handling changes that had been requested for follow-exec-mode.exp here: https://sourceware.org/ml/gdb-patches/2015-08/msg00753.html, since that test had been derived from this one, which contained most of the same issues. * gdb.base/foll-vfork.exp: Enabled exec-related tests that had been disabled with the implementation of extended-remote vfork event support. On 8/13/2015 8:22 AM, Pedro Alves wrote: > On 07/31/2015 12:19 AM, Don Breazeal wrote: > >> This patch updates several exec-related tests and some of the >> library functions in order to get them running with extended-remote. >> There were three changes that were required, as follows: >> >> In gdb.base/foll-exec.exp, the proc 'zap_session' is used repeatedly >> to reset the state of the debugger before the next test. Part of >> that procedure is to 'set exec-file'. For remote targets, it is >> necessary to also 'set remote exec-file' to achieve the same >> effect (and execute the correct binary file in the subsequent test). > > This assumes local gdbserver testing. This is something that > should be done in the target board. Look for exec-file in > gdb/testsuite/boards/native-extended-gdbserver.exp. > Maybe we should just clean_restart instead ? Eliminated proc zap_session and used clean_restart instead. > >> >> In gdb.base/pie-execl.exp, there is an expect statement with an >> expression that is used to match output from both gdb and the >> program under debug. For the remote target, this had to be >> split into two expressions, using $inferior_spawn_id to match >> the output from the program. >> >> Because I had encountered problems with extended-remote exec events >> in non-stop mode in my manual testing, I added non-stop testing to >> the non-ldr-exc-[1234].exp tests. In order to set non-stop mode >> for remote targets, it is necessary to 'set non-stop on' after gdb >> has started, but before it connects to gdbserver. The non-ldr-... >> tests call 'clean_restart' in between tests, and it eventually calls >> 'gdb_start' which starts gdb and gdbserver and connects them. By >> adding a stop mode argument to clean_restart and gdb_start (in >> both lib/gdb.exp and boards/native-extended-gdbserver.exp), it was >> possible to set non-stop mode for remote targets. Since the >> arguments have a default value "all-stop", and only have an effect >> when "non-stop" is passed, these changes do not affect any existing >> test behavior. > > I don't think we can do this, because gdb_start is an overridable > function (see comment above it). You can instead append > set non-stop on to GDBFLAGS. E.g.,: > > save_vars { GDBFLAGS } { > append GDBFLAGS " -ex \"set non-stop $nonstop\"" > clean_restart > } Restored clean_restart, gdb_start, etc to their original implementations, and used the save_vars approach above in gdb.threads/non-ldr-exc-[1234].exp. Thanks. > >> diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp >> index 69e5cc6..147e7f3 100644 >> --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp >> +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp >> @@ -28,11 +28,11 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab >> return -1 >> } >> >> -proc do_test { lock_sched } { >> - with_test_prefix "lock-sched$lock_sched" { >> +proc do_test { lock_sched stop_mode } { >> + with_test_prefix "lock-sched$lock_sched,$stop_mode" { >> global executable >> >> - clean_restart ${executable} >> + clean_restart ${executable} $stop_mode >> >> if ![runto_main] { >> return -1 >> @@ -48,11 +48,17 @@ proc do_test { lock_sched } { >> gdb_test_no_output "set scheduler-locking on" >> } >> >> + if { $stop_mode == "non-stop" } { >> + gdb_test "thread 2" "Switching.*" >> + } >> + >> gdb_test "continue" \ >> ".*is executing new program.*Breakpoint 1, main.* at .*" \ >> "continue over exec" >> } >> } >> >> -do_test 0 >> -do_test 1 >> +do_test 0 "all-stop" >> +do_test 1 "all-stop" >> +do_test 0 "non-stop" >> +do_test 1 "non-stop" > > Please use foreach. E.g., > > foreach nonstop {"on" "off"} { > foreach schedlock {"on" "off"} { > do_test ... > } > } > > Note that schedlock on has no effect in non-stop mode. > Maybe if !lock_sched && nonstop, we could issue "continue -a" > instead of continue. I couldn't find any documentation of 'continue -a'. (?) I just used a conditional to prevent running the lock_sched/nonstop tests. foreach nonstop {"on" "off"} { foreach schedlock {"on" "off"} { if {$schedlock == "on" && $nonstop == "on"} { # Schedule locking has no effect in nonstop mode. continue } do_test $schedlock $nonstop } } > >> diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp >> index 9386153..748ff11 100644 >> --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp >> +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp >> @@ -29,18 +29,26 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab >> return -1 >> } >> >> -proc do_test { lock_sched } { >> - with_test_prefix "lock-sched$lock_sched" { >> +proc do_test { lock_sched stop_mode } { >> + with_test_prefix "lock-sched$lock_sched,$stop_mode" { >> global executable >> >> - clean_restart ${executable} >> + clean_restart ${executable} $stop_mode >> >> if ![runto_main] { >> return -1 >> } >> >> gdb_breakpoint [gdb_get_line_number "break-here"] >> - gdb_continue_to_breakpoint "break-here" ".* break-here .*" >> + gdb_test_multiple "continue" "continue to breakpoint" { >> + -re ".*Breakpoint.*break-here.*" { > > This doesn't expect the prompt, which is going to be > racy -- the following gdb_test may fail if this test manages > to leave the prompt in the expect buffer. What motivated this change? This was a leftover from a change that was reverted, sorry. This has been restored to the original. Thanks, --Don ----- This patch updates several exec-related tests and some of the library functions in order to get them running with extended-remote. There were three changes that were required, as follows: In gdb.base/foll-exec.exp, use 'clean_start' in place of proc 'zap_session' to reset the state of the debugger between tests. This sets 'remote exec-file' to execute the correct binary file in each subsequent test. In gdb.base/pie-execl.exp, there is an expect statement with an expression that is used to match output from both gdb and the program under debug. For the remote target, this had to be split into two expressions, using $inferior_spawn_id to match the output from the program. Because I had encountered problems with extended-remote exec events in non-stop mode in my manual testing, I added non-stop testing to the non-ldr-exc-[1234].exp tests. In order to set non-stop mode for remote targets, it is necessary to 'set non-stop on' after gdb has started, but before it connects to gdbserver. This is done using 'save_vars' to set non-stop mode in GDBFLAGS, so GDB sets non-stop mode on startup. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. gdb/testsuite/ 2015-09-09 Don Breazeal <donb@codesourcery.com> * gdb.base/foll-exec.c: Add copyright header. Fix formatting issues. * gdb.base/foll-exec.exp (zap_session): Delete proc. (do_exec_tests): Use clean_restart in place of zap_session, and for test initialization. Fix formatting issues. Use fail in place of perror. * gdb.base/pie-execl.exp (main): Use 'inferior_spawn_id' in an expect statement to match an expression with output from the program under debug. * gdb.threads/non-ldr-exc-1.exp (do_test, main): Add non-stop tests and pass stop mode argument to clean_restart. Use save_vars to enable non-stop in GDBFLAGS. * gdb.threads/non-ldr-exc-2.exp: Likewise. * gdb.threads/non-ldr-exc-3.exp: Likewise. * gdb.threads/non-ldr-exc-4.exp: Likewise. --- gdb/testsuite/gdb.base/foll-exec.c | 44 ++++++++++++------- gdb/testsuite/gdb.base/foll-exec.exp | 65 +++++++---------------------- gdb/testsuite/gdb.base/foll-vfork.exp | 29 ++++++------- gdb/testsuite/gdb.base/pie-execl.exp | 24 ++++++++++- gdb/testsuite/gdb.threads/non-ldr-exc-1.exp | 24 ++++++++--- gdb/testsuite/gdb.threads/non-ldr-exc-2.exp | 24 ++++++++--- gdb/testsuite/gdb.threads/non-ldr-exc-3.exp | 30 ++++++++++--- gdb/testsuite/gdb.threads/non-ldr-exc-4.exp | 24 ++++++++--- 8 files changed, 161 insertions(+), 103 deletions(-) diff --git a/gdb/testsuite/gdb.base/foll-exec.c b/gdb/testsuite/gdb.base/foll-exec.c index 6e302bb..77287a4 100644 --- a/gdb/testsuite/gdb.base/foll-exec.c +++ b/gdb/testsuite/gdb.base/foll-exec.c @@ -1,36 +1,52 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 1997-2015 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> - -int global_i = 100; +int global_i = 100; int main (void) { - int local_j = global_i+1; - int local_k = local_j+1; + int local_j = global_i + 1; + int local_k = local_j + 1; printf ("foll-exec is about to execlp(execd-prog)...\n"); execlp (BASEDIR "/execd-prog", - BASEDIR "/execd-prog", - "execlp arg1 from foll-exec", - (char *)0); + BASEDIR "/execd-prog", + "execlp arg1 from foll-exec", + (char *) 0); printf ("foll-exec is about to execl(execd-prog)...\n"); execl (BASEDIR "/execd-prog", /* tbreak-execl */ - BASEDIR "/execd-prog", - "execl arg1 from foll-exec", - "execl arg2 from foll-exec", - (char *)0); + BASEDIR "/execd-prog", + "execl arg1 from foll-exec", + "execl arg2 from foll-exec", + (char *) 0); { static char * argv[] = { - (char *)BASEDIR "/execd-prog", - (char *)"execv arg1 from foll-exec", - (char *)0}; + (char *) BASEDIR "/execd-prog", + (char *) "execv arg1 from foll-exec", + (char *) 0}; printf ("foll-exec is about to execv(execd-prog)...\n"); diff --git a/gdb/testsuite/gdb.base/foll-exec.exp b/gdb/testsuite/gdb.base/foll-exec.exp index 5bea3ba..0a6347c 100644 --- a/gdb/testsuite/gdb.base/foll-exec.exp +++ b/gdb/testsuite/gdb.base/foll-exec.exp @@ -13,6 +13,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +# This is a test of gdb's ability to follow a process through a +# Unix exec() system call. + if { [is_remote target] || ![isnative] } then { continue } @@ -44,44 +47,14 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $com return -1 } -proc zap_session {} { - global gdb_prompt - global binfile - - send_gdb "kill\n" - gdb_expect { - -re ".*Kill the program being debugged.*y or n. $" { - gdb_test_no_output "y" "" - send_gdb "file $binfile\n" - gdb_expect { - -re ".*Load new symbol table from.*y or n. $" { - send_gdb "y\n" - gdb_expect { - -re "Reading symbols from.*$gdb_prompt $" {} - timeout { fail "loading symbols (timeout)"; return } - } - } - -re ".*gdb_prompt $" {} - timeout { fail "loading symbols (timeout)"; return } - } - } - -re ".*$gdb_prompt $" {} - timeout { fail "killing inferior (timeout)" ; return } - } -} - proc do_exec_tests {} { + global binfile srcfile srcfile2 testfile testfile2 global gdb_prompt - global binfile - global srcfile - global srcfile2 - global testfile - global testfile2 # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile}" + fail "Couldn't run ${testfile}" return } @@ -103,12 +76,12 @@ proc do_exec_tests {} { return } - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile}" + fail "Couldn't run ${testfile}" return } @@ -192,12 +165,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (2nd try)" + fail "Couldn't run ${testfile} (2nd try)" return } @@ -265,12 +238,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (3rd try)" + fail "Couldn't run ${testfile} (3rd try)" return } @@ -326,12 +299,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (4th try)" + fail "Couldn't run ${testfile} (4th try)" return } @@ -381,12 +354,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (5th try)" + fail "Couldn't run ${testfile} (5th try)" return } @@ -406,14 +379,8 @@ proc do_exec_tests {} { # Start with a fresh gdb gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} - +clean_restart $binfile -# This is a test of gdb's ability to follow a process through a -# Unix exec() system call. -# do_exec_tests return 0 diff --git a/gdb/testsuite/gdb.base/foll-vfork.exp b/gdb/testsuite/gdb.base/foll-vfork.exp index b94b7ea..78c5cc8 100644 --- a/gdb/testsuite/gdb.base/foll-vfork.exp +++ b/gdb/testsuite/gdb.base/foll-vfork.exp @@ -524,23 +524,18 @@ with_test_prefix "check vfork support" { check_vfork_catchpoints } -# There is no support for exec events in the RSP yet. -if { ![gdb_is_target_remote] } { - # Follow parent and follow child vfork tests with a child that execs. - with_test_prefix "exec" { - # These are tests of gdb's ability to follow the parent of a Unix - # vfork system call. The child will subsequently call a variant - # of the Unix exec system call. - do_vfork_and_follow_parent_tests - - # These are tests of gdb's ability to follow the child of a Unix - # vfork system call. The child will subsequently call a variant - # of a Unix exec system call. - # - do_vfork_and_follow_child_tests_exec - } -} else { - unsupported "vfork with exec: exec events not supported for remote" +# Follow parent and follow child vfork tests with a child that execs. +with_test_prefix "exec" { + # These are tests of gdb's ability to follow the parent of a Unix + # vfork system call. The child will subsequently call a variant + # of the Unix exec system call. + do_vfork_and_follow_parent_tests + + # These are tests of gdb's ability to follow the child of a Unix + # vfork system call. The child will subsequently call a variant + # of a Unix exec system call. + # + do_vfork_and_follow_child_tests_exec } # Switch to test the case of the child exiting. We can't use diff --git a/gdb/testsuite/gdb.base/pie-execl.exp b/gdb/testsuite/gdb.base/pie-execl.exp index 182f96f..51edc82 100644 --- a/gdb/testsuite/gdb.base/pie-execl.exp +++ b/gdb/testsuite/gdb.base/pie-execl.exp @@ -16,6 +16,9 @@ # The problem was due to amd64_skip_prologue attempting to access inferior # memory before the PIE (Position Independent Executable) gets relocated. +global inferior_spawn_id +global gdb_spawn_id + if ![istarget *-linux*] { continue } @@ -67,6 +70,7 @@ gdb_test_multiple "p/x &pie_execl_marker" $test { verbose -log "addr1 is $addr1" set test "continue" +set matches_found 0 gdb_test_multiple $test $test { -re "Error in re-setting breakpoint" { fail $test @@ -74,8 +78,24 @@ gdb_test_multiple $test $test { -re "Cannot access memory" { fail $test } - -re "pie-execl: re-exec.*executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { - pass $test + -i "$inferior_spawn_id" -re "pie-execl: re-exec" { + # output from inferior + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } + } + -i "$gdb_spawn_id" + -re "executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { + # output from gdb + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } } } diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp index 69e5cc6..3e5c902 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp @@ -28,11 +28,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched$lock_sched,non-stop$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 @@ -48,11 +51,22 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp index 9386153..5e25f22 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp @@ -29,11 +29,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched$lock_sched,non-stop$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 @@ -42,6 +45,10 @@ proc do_test { lock_sched } { gdb_breakpoint [gdb_get_line_number "break-here"] gdb_continue_to_breakpoint "break-here" ".* break-here .*" + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "info threads" \ "\r\n\[ \t\]*Id\[ \t\]+Target\[ \t\]+Id\[ \t\]+Frame\[ \t\]*\r\n\\* 2 *Thread \[^\r\n\]* at \[^\r\n\]*" \ "single thread left" @@ -59,5 +66,12 @@ proc do_test { lock_sched } { } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp index cc7da1a..8778471 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp @@ -31,18 +31,25 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched$lock_sched,non-stop$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_continue_to_breakpoint "break-here" ".* break-here .*" + gdb_test_multiple "continue" "continue to breakpoint" { + -re ".*Breakpoint.*break-here.*" { + pass "continue to breakpoint" + } + } # Also test with sched-lock to make sure we can follow the # non-leader thread execing even though the main thread wasn't @@ -51,11 +58,22 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp index a89b818..5723348 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp @@ -30,11 +30,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched$lock_sched,non-stop$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 @@ -50,11 +53,22 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 3/4] Extended-remote support for exec event tests 2015-09-09 23:06 ` [PATCH v3 3/4] Extended-remote support for exec event tests Don Breazeal @ 2015-09-10 13:26 ` Pedro Alves 0 siblings, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-09-10 13:26 UTC (permalink / raw) To: Don Breazeal, gdb-patches Hi Don, This is OK. One nit below. On 09/10/2015 12:05 AM, Don Breazeal wrote: >> Note that schedlock on has no effect in non-stop mode. >> Maybe if !lock_sched && nonstop, we could issue "continue -a" >> instead of continue. > > I couldn't find any documentation of 'continue -a'. (?) I just used > a conditional to prevent running the lock_sched/nonstop tests. I see that the "Continuing and Stepping" section doesn't mention it. It's mentioned in "help continue", and here in the manual: In non-stop mode, all execution commands apply only to the current thread by default. That is, @code{continue} only continues one thread. To continue all threads, issue @code{continue -a} or @code{c -a}. > diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp > index 69e5cc6..3e5c902 100644 > --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp > +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp > @@ -28,11 +28,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab > return -1 > } > > -proc do_test { lock_sched } { > - with_test_prefix "lock-sched$lock_sched" { > +proc do_test { lock_sched nonstop } { > + with_test_prefix "lock-sched$lock_sched,non-stop$nonstop" { AFAICS, this will render as: lock-schedoff,non-stopon etc. I suggest adding a '=': with_test_prefix "lock-sched=$lock_sched,non-stop=$nonstop" { (in the other files too, of course.) Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 4/4] Extended-remote exec event docs 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal 2015-09-09 23:06 ` [PATCH v3 3/4] Extended-remote support for exec event tests Don Breazeal @ 2015-09-09 23:06 ` Don Breazeal 2015-09-10 15:23 ` Eli Zaretskii 2015-09-09 23:06 ` [PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal 2015-09-09 23:06 ` [PATCH v3 1/4] Extended-remote follow exec Don Breazeal 3 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-09-09 23:06 UTC (permalink / raw) To: gdb-patches, palves This patch is an update to extended-remote exec event documentation. The only change from the previous version is to document the 'set/show remote exec-event-feature-packet' commands in the NEWS file. ----- This patch adds documentation of support for exec events on extended-remote Linux targets. Thanks, --Don gdb/ 2015-09-09 Don Breazeal <donb@codesourcery.com> * NEWS: Announce new remote packets for the exec-events feature and the exec-events feature and associated commands. gdb/doc/ 2015-09-09 Don Breazeal <donb@codesourcery.com> * gdb.texinfo (Remote Configuration): Add exec event feature to table of packet settings. (Stop Reply Packets): Add exec events to the list of stop reasons. (General Query Packets): Add exec events to tables of 'gdbfeatures' and 'stub features' supported in the qSupported packet, as well as to the list containing stub feature details. --- gdb/NEWS | 21 +++++++++++++++++++++ gdb/doc/gdb.texinfo | 30 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index 0cf51e1..bb1c8d9 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -55,6 +55,27 @@ show remote multiprocess-extensions-packet * Support for reading/writing memory and extracting values on architectures whose memory is addressable in units of any integral multiple of 8 bits. +* New remote packets + +exec stop reason + Indicates that an exec system call was executed. + +exec-events feature in qSupported + The qSupported packet allows GDB to request support for exec + events using the new 'gdbfeature' exec-event, and the qSupported + response can contain the corresponding 'stubfeature'. Set and + show commands can be used to display whether these features are enabled. + +* Extended-remote exec events + + ** GDB now has support for exec events on extended-remote Linux targets. + For such targets with Linux kernels 2.5.46 and later, this enables + follow-exec-mode and exec catchpoints. + +set remote exec-event-feature-packet +show remote exec-event-feature-packet + Set/show the use of the remote exec event feature. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index cd0abad..395f0d4 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20225,6 +20225,10 @@ are: @tab @code{vfork stop reason} @tab @code{vfork} +@item @code{exec-event-feature} +@tab @code{exec stop reason} +@tab @code{exec} + @end multitable @node Remote Stub @@ -35506,6 +35510,18 @@ appropriate @samp{qSupported} feature (@pxref{qSupported}). The remote stub must also supply the appropriate @samp{qSupported} feature indicating support. +@cindex exec events, remote reply +@item exec +The packet indicates that @code{execve} was called, and @var{r} +is the absolute pathname of the file that was executed, in hex. +This packet is only applicable to targets that support exec events. + +This packet should not be sent by default; older @value{GDBN} versions +did not support it. @value{GDBN} requests it, by supplying an +appropriate @samp{qSupported} feature (@pxref{qSupported}). The +remote stub must also supply the appropriate @samp{qSupported} feature +indicating support. + @end table @item W @var{AA} @@ -36110,6 +36126,12 @@ This feature indicates whether @value{GDBN} supports vfork event extensions to the remote protocol. @value{GDBN} does not use such extensions unless the stub also reports that it supports them by including @samp{vfork-events+} in its @samp{qSupported} reply. + +@item exec-events +This feature indicates whether @value{GDBN} supports exec event +extensions to the remote protocol. @value{GDBN} does not use such +extensions unless the stub also reports that it supports them by +including @samp{exec-events+} in its @samp{qSupported} reply. @end table Stubs should ignore any unknown values for @@ -36373,6 +36395,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{exec-events} +@tab No +@tab @samp{-} +@tab No + @end multitable These are the currently defined stub features, in more detail: @@ -36578,6 +36605,9 @@ The remote stub reports the @samp{fork} stop reason for fork events. The remote stub reports the @samp{vfork} stop reason for vfork events and vforkdone events. +@item exec-events +The remote stub reports the @samp{exec} stop reason for exec events. + @end table @item qSymbol:: -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 4/4] Extended-remote exec event docs 2015-09-09 23:06 ` [PATCH v3 4/4] Extended-remote exec event docs Don Breazeal @ 2015-09-10 15:23 ` Eli Zaretskii 0 siblings, 0 replies; 55+ messages in thread From: Eli Zaretskii @ 2015-09-10 15:23 UTC (permalink / raw) To: Don Breazeal; +Cc: gdb-patches, palves > From: Don Breazeal <donb@codesourcery.com> > Date: Wed, 9 Sep 2015 16:05:37 -0700 > > This patch is an update to extended-remote exec event documentation. > The only change from the previous version is to document the > 'set/show remote exec-event-feature-packet' commands in the NEWS > file. > > ----- > > This patch adds documentation of support for exec events on > extended-remote Linux targets. > > Thanks, > --Don > > gdb/ > 2015-09-09 Don Breazeal <donb@codesourcery.com> > > * NEWS: Announce new remote packets for the exec-events > feature and the exec-events feature and associated commands. > > gdb/doc/ > 2015-09-09 Don Breazeal <donb@codesourcery.com> > > * gdb.texinfo (Remote Configuration): Add exec event > feature to table of packet settings. > (Stop Reply Packets): Add exec events to the list of stop > reasons. > (General Query Packets): Add exec events to tables of > 'gdbfeatures' and 'stub features' supported in the qSupported > packet, as well as to the list containing stub feature > details. OK, thanks. ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 2/4] Extended-remote exec catchpoints 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal 2015-09-09 23:06 ` [PATCH v3 3/4] Extended-remote support for exec event tests Don Breazeal 2015-09-09 23:06 ` [PATCH v3 4/4] Extended-remote exec event docs Don Breazeal @ 2015-09-09 23:06 ` Don Breazeal 2015-09-09 23:06 ` [PATCH v3 1/4] Extended-remote follow exec Don Breazeal 3 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-09 23:06 UTC (permalink / raw) To: gdb-patches, palves This patch is unchanged from the previous version, about which the review said "...seems fine." Thanks --Don ----- This patch implements exec catchpoints for extended-remote Linux targets. The implementation follows the same approach used for fork catchpoints, implementing extended-remote target routines for inserting and removing the catchpoints by just checking if exec events are supported. Existing host-side code and previous support for extended-remote exec events takes care of the rest. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. gdb/ 2015-09-09 Don Breazeal <donb@codesourcery.com> * remote.c (remote_exec_event_p): New function. (remote_insert_exec_catchpoint): New function. (remote_remove_exec_catchpoint): New function. (init_extended_remote_ops): Initialize extended_remote_ops members to_insert_exec_catchpoint and to_remove_exec_catchpoint. --- gdb/remote.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/gdb/remote.c b/gdb/remote.c index 9765161..17d4b11 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1589,6 +1589,14 @@ remote_vfork_event_p (struct remote_state *rs) return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE; } +/* Returns true if exec events are supported. */ + +static int +remote_exec_event_p (struct remote_state *rs) +{ + return packet_support (PACKET_exec_event_feature) == PACKET_ENABLE; +} + /* Insert fork catchpoint target routine. If fork events are enabled then return success, nothing more to do. */ @@ -1629,6 +1637,26 @@ remote_remove_vfork_catchpoint (struct target_ops *ops, int pid) return 0; } +/* Insert exec catchpoint target routine. If exec events are + enabled, just return success. */ + +static int +remote_insert_exec_catchpoint (struct target_ops *ops, int pid) +{ + struct remote_state *rs = get_remote_state (); + + return !remote_exec_event_p (rs); +} + +/* Remove exec catchpoint target routine. Nothing to do, just + return success. */ + +static int +remote_remove_exec_catchpoint (struct target_ops *ops, int pid) +{ + return 0; +} + /* Tokens for use by the asynchronous signal handlers for SIGINT. */ static struct async_signal_handler *async_sigint_remote_twice_token; static struct async_signal_handler *async_sigint_remote_token; @@ -12802,6 +12830,10 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; = remote_insert_vfork_catchpoint; extended_remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint; + extended_remote_ops.to_insert_exec_catchpoint + = remote_insert_exec_catchpoint; + extended_remote_ops.to_remove_exec_catchpoint + = remote_remove_exec_catchpoint; } static int -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 1/4] Extended-remote follow exec 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal ` (2 preceding siblings ...) 2015-09-09 23:06 ` [PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal @ 2015-09-09 23:06 ` Don Breazeal 2015-09-10 12:43 ` Pedro Alves 3 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-09-09 23:06 UTC (permalink / raw) To: gdb-patches, palves Hi Pedro, This is an updated version of the patch previously submitted here: https://sourceware.org/ml/gdb-patches/2015-07/msg00924.html. Changes from the previous version include: * In gdbserver, when an exec event occurs, gdbserver deletes all of the data (inferior, lwps, threads) associated with the execing process and replaces it with a new set of data. * In GDB, the remote exec-file is now stored per-inferior in the inferior's program space as a REGISTRY field. * In GDB, a new target hook, target_follow_exec, is used to enable storing the remote exec-file as per-inferior data. * In GDB, follow_exec now calls add_inferior_with_spaces for mode "new" in place of add_inferior and the calls to set up the program and address spaces. Some of the things that were part of the previous patchset were eliminated as a result of these changes, including: * Deleting "vanished" lwps in gdbserver/linux-low.c:send_sigstop. * Fiddling with the regcache and r_debug in gdbserver/linux-low.c:handle_extended_wait. * Fiddling with the inferior's architecture in remote.c:remote_parse_stop_reply. A couple of your questions about the previous version of the patch still apply, in spite of the rework. Regarding the handling of the exec event in linux-low.c:handle_extended_wait: > > + /* 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_stop; > > Shouldn't this be resume_continue? My thinking here is that as far as gdbserver is concerned, we *do* want to use resume_stop, so that we stop and report the event to GDB. It will be up to GDB whether to continue from this point. Does that make sense? Another question you had: > > diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index > > f097c8a..235dfba 100644 > > --- a/gdb/nat/linux-ptrace.c > > +++ b/gdb/nat/linux-ptrace.c > > @@ -528,9 +528,7 @@ ptrace_supports_feature (int ptrace_options) } > > > > /* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace, > > - 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is > > - PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, > > - since they were all added to the kernel at the same time. */ > > + 0 otherwise. */ > > Why remove this info? This had a very thin relation to a long-ago comment you made about not using linux_supports_tracefork to determine if exec is supported. I've restored the original content of the comment. I've fixed the formatting issues you had pointed out. A rewritten commit message with updated ChangeLog and patch follow. Thanks --Don ---- This patch implements support for exec events on extended-remote Linux targets. Follow-exec-mode and rerun behave as expected. Catchpoints and test updates are implemented in subsequent patches. This patch was derived from a patch posted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00877.html. It was originally based on some work done by Luis Machado in 2013. IMPLEMENTATION ---------------- Exec events are enabled via ptrace options. When an exec event is detected by gdbserver, the existing process data, along with all its associated lwp and thread data, is deleted and replaced by data for a new single-threaded process. The new process data is initialized with the appropriate parts of the state of the execing process. This approach takes care of several potential pitfalls, including: * deleting the data for an execing non-leader thread before any wait/sigsuspend occurs * correctly initializing the architecture of the execed process We then report the exec event using a new RSP stop reason, "exec". When GDB receives an "exec" event, it saves the status in the event structure's target_waitstatus field, like what is done for remote fork events. Because the original and execed programs may have different architectures, we skip parsing the section of the stop reply packet that contains register data. The register data will be retrieved later after the inferior's architecture has been set up by infrun.c:follow_exec. At that point the exec event is handled by the existing event handling in GDB. However, a few changes were necessary so that infrun.c:follow_exec could accommodate the remote target. * Where follow-exec-mode "new" is handled, we now call add_inferior_with_spaces instead of add_inferior with separate calls to set up the program and address spaces. The motivation for this is that add_inferior_with_spaces also sets up the initial architecture for the inferior, which is needed later by target_find_description when it calls target_gdbarch. * We call a new target function, target_follow_exec. This function allows us to store the execd_pathname in the inferior, instead of using the static string remote_exec_file from remote.c. The static string didn't work for follow-exec-mode "new", since once you switched to the execed program, the original remote exec-file was lost. The execd_pathname is now stored in the inferior's program space as a REGISTRY field. All of the requisite mechanisms for this are defined in remote.c. And that is basically it. TESTING -------- x86_64 GNU/Linux for native, native-gdbserver, and native-extended-gdbserver targets. Most of the exec-related tests fail due to the lack of catchpoints and extended-remote support in the tests, both of which are resolved in subsequent patches in this patchset. gdb/gdbserver/ 2015-09-09 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. gdb/ 2015-09-09 Don Breazeal <donb@codesourcery.com> Luis Machado <lgustavo@codesourcery.com> * infrun.c (follow_exec): Use process-style ptid for exec message. Call add_inferior_with_spaces and target_follow_exec. * nat/linux-ptrace.c (linux_supports_traceexec): New function. * nat/linux-ptrace.h (linux_supports_traceexec): Declare. * remote.c (remote_pspace_data): New static variable. (remote_pspace_data_cleanup): New function. (get_remote_exec_file): New function. (set_remote_exec_file_1): New function. (set_remote_exec_file): New function. (show_remote_exec_file): New function. (remote_exec_file): Delete static variable. (anonymous enum) <PACKET_exec_event_feature> New enumeration constant. (remote_protocol_features): Add entry for exec-events feature. (remote_query_supported): Add client side of qSupported query for exec-events feature. (remote_follow_exec): New function. (remote_parse_stop_reply): Handle 'exec' stop reason. (extended_remote_run, extended_remote_create_inferior): Call get_remote_exec_file and set_remote_exec_file_1. (init_extended_remote_ops) <to_follow_exec>: Initialize new member. (_initialize_remote): Call register_program_space_data_with_cleanup. Call add_packet_config_cmd for remote exec-events feature. Modify call to add_setshow_string_noescape_cmd for exec-file to use new functions set_remote_exec_file and show_remote_exec_file. * target-debug.h, target-delegates.c: Regenerated. * target.c (target_follow_exec): New function. * target.h (struct target_ops) <to_follow_exec>: New member. (target_follow_exec): Declare new function. --- gdb/gdbserver/linux-low.c | 150 +++++++++++++++++++++++++++++++------- gdb/gdbserver/lynx-low.c | 1 + gdb/gdbserver/remote-utils.c | 20 ++++++ gdb/gdbserver/server.c | 11 +++ gdb/gdbserver/server.h | 1 + gdb/gdbserver/target.h | 7 ++ gdb/gdbserver/win32-low.c | 1 + gdb/infrun.c | 17 +++-- gdb/nat/linux-ptrace.c | 11 +++ gdb/nat/linux-ptrace.h | 1 + gdb/remote.c | 166 ++++++++++++++++++++++++++++++++++++++++--- gdb/target-debug.h | 2 + gdb/target-delegates.c | 30 ++++++++ gdb/target.c | 8 +++ gdb/target.h | 7 ++ 15 files changed, 390 insertions(+), 43 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 4256bc5..942c5f3 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 = event_thr->entry.id; + 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_stop; + 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); @@ -3373,7 +3463,8 @@ linux_wait_1 (ptid_t ptid, ourstatus->value.sig = GDB_SIGNAL_0; } else if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) != SIGSTOP) + && WSTOPSIG (w) != SIGSTOP + && ourstatus->kind != TARGET_WAITKIND_EXECD) { /* A thread that has been requested to stop by GDB with vCont;t, but, it stopped for other reasons. */ @@ -5801,6 +5892,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 +6990,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..1baae1d 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 */ diff --git a/gdb/infrun.c b/gdb/infrun.c index e89e02a..84890b4 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1095,6 +1095,7 @@ follow_exec (ptid_t ptid, char *execd_pathname) struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); int pid = ptid_get_pid (ptid); + ptid_t process_ptid; /* This is an exec event that we actually wish to pay attention to. Refresh our symbol table to the newly exec'd program, remove any @@ -1161,8 +1162,9 @@ follow_exec (ptid_t ptid, char *execd_pathname) update_breakpoints_after_exec (); /* What is this a.out's name? */ + process_ptid = pid_to_ptid (pid); printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (inferior_ptid), + target_pid_to_str (process_ptid), execd_pathname); /* We've followed the inferior through an exec. Therefore, the @@ -1191,8 +1193,6 @@ follow_exec (ptid_t ptid, char *execd_pathname) if (follow_exec_mode_string == follow_exec_mode_new) { - struct program_space *pspace; - /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ @@ -1201,14 +1201,13 @@ follow_exec (ptid_t ptid, char *execd_pathname) the same ptid, which can confuse find_inferior_ptid. */ exit_inferior_num_silent (current_inferior ()->num); - inf = add_inferior (pid); - pspace = add_program_space (maybe_new_address_space ()); - inf->pspace = pspace; - inf->aspace = pspace->aspace; - add_thread (ptid); + inf = add_inferior_with_spaces (); + inf->pid = pid; + target_follow_exec (inf, execd_pathname); set_current_inferior (inf); - set_current_program_space (pspace); + set_current_program_space (inf->pspace); + add_thread (ptid); } else { diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index f097c8a..4222df5 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -538,6 +538,17 @@ linux_supports_tracefork (void) return ptrace_supports_feature (PTRACE_O_TRACEFORK); } +/* Returns non-zero if PTRACE_EVENT_EXEC is supported by ptrace, + 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is + PTRACE_EVENT_CLONE, PTRACE_EVENT_FORK and PTRACE_EVENT_VFORK, + since they were all added to the kernel at the same time. */ + +int +linux_supports_traceexec (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEEXEC); +} + /* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace, 0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h index 8bff908..1be38fe 100644 --- a/gdb/nat/linux-ptrace.h +++ b/gdb/nat/linux-ptrace.h @@ -168,6 +168,7 @@ extern void linux_check_ptrace_features (void); extern void linux_enable_event_reporting (pid_t pid, int attached); extern void linux_disable_event_reporting (pid_t pid); extern int linux_supports_tracefork (void); +extern int linux_supports_traceexec (void); extern int linux_supports_traceclone (void); extern int linux_supports_tracevforkdone (void); extern int linux_supports_tracesysgood (void); diff --git a/gdb/remote.c b/gdb/remote.c index e4d3edf..9765161 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -75,6 +75,9 @@ static char *target_buf; static long target_buf_size; +/* Per-program-space data key. */ +static const struct program_space_data *remote_pspace_data; + /* The size to align memory write packets, when practical. The protocol does not guarantee any alignment, and gdb will generate short writes and unaligned writes, but even as a best-effort attempt this @@ -619,6 +622,62 @@ get_remote_state (void) return get_remote_state_raw (); } +/* Cleanup routine for the remote module's pspace data. */ + +static void +remote_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + char *remote_exec_file = arg; + + if (remote_exec_file != NULL) + xfree (remote_exec_file); +} + +/* Fetch the remote exec-file from the current program space. */ + +static char * +get_remote_exec_file (void) +{ + char *remote_exec_file; + + remote_exec_file = program_space_data (current_program_space, + remote_pspace_data); + return remote_exec_file; +} + +/* Set the remote exec file for the current program space. */ + +static void +set_remote_exec_file_1 (char *remote_exec_file) +{ + char *old_file = get_remote_exec_file (); + + if (old_file != NULL) + xfree (old_file); + + set_program_space_data (current_program_space, remote_pspace_data, + xstrdup (remote_exec_file)); +} + +/* The "set/show remote exec-file" set hook. */ + +static void +set_remote_exec_file (char *ignored, int from_tty, + struct cmd_list_element *c) +{ + gdb_assert (*(char **) c->var != NULL); + set_remote_exec_file_1 (*(char **) c->var); +} + +/* The "set/show remote exec-file" show hook. */ + +static void +show_remote_exec_file (struct ui_file *file, int from_tty, + struct cmd_list_element *cmd, const char *value) +{ + fprintf_filtered (file, "%s\n", get_remote_exec_file ()); +} + static int compare_pnums (const void *lhs_, const void *rhs_) { @@ -901,10 +960,6 @@ static unsigned int remote_address_size; static int remote_async_terminal_ours_p; -/* The executable file to use for "run" on the remote side. */ - -static char *remote_exec_file = ""; - \f /* User configurable variables for the number of characters in a memory read/write packet. MIN (rsa->remote_packet_size, @@ -1401,6 +1456,9 @@ enum { /* Support for the Qbtrace-conf:pt:size packet. */ PACKET_Qbtrace_conf_pt_size, + /* Support for exec events. */ + PACKET_exec_event_feature, + PACKET_MAX }; @@ -4279,6 +4337,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_fork_event_feature }, { "vfork-events", PACKET_DISABLE, remote_supported_packet, PACKET_vfork_event_feature }, + { "exec-events", PACKET_DISABLE, remote_supported_packet, + PACKET_exec_event_feature }, { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_conf_pt_size } }; @@ -4368,6 +4428,9 @@ remote_query_supported (void) if (packet_set_cmd_state (PACKET_vfork_event_feature) != AUTO_BOOLEAN_FALSE) q = remote_query_supported_append (q, "vfork-events+"); + if (packet_set_cmd_state (PACKET_exec_event_feature) + != AUTO_BOOLEAN_FALSE) + q = remote_query_supported_append (q, "exec-events+"); } q = reconcat (q, "qSupported:", q, (char *) NULL); @@ -4779,6 +4842,28 @@ remote_follow_fork (struct target_ops *ops, int follow_child, return 0; } +/* Target follow-exec function for remote targets. Save EXECD_PATHNAME + in the program space of the new inferior. On entry and at return the + current inferior is the exec'ing inferior. INF is the new exec'd + inferior, which may be the same as the exec'ing inferior unless + follow-exec-mode is "new". */ + +static void +remote_follow_exec (struct target_ops *ops, + struct inferior *inf, char *execd_pathname) +{ + struct cleanup *old_chain = save_current_program_space (); + + /* We know that this is a target file name, so if it has the "target:" + prefix we strip it off before saving it in the program space. */ + if (is_target_filename (execd_pathname)) + execd_pathname += strlen (TARGET_SYSROOT_PREFIX); + + set_current_program_space (inf->pspace); + set_remote_exec_file_1 (execd_pathname); + do_cleanups (old_chain); +} + /* Same as remote_detach, but don't send the "D" packet; just disconnect. */ static void @@ -5977,6 +6062,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event) struct remote_arch_state *rsa = get_remote_arch_state (); ULONGEST addr; char *p; + int skipregs = 0; event->ptid = null_ptid; event->rs = get_remote_state (); @@ -6089,11 +6175,42 @@ Packet: '%s'\n"), event->ws.kind = TARGET_WAITKIND_VFORK_DONE; p = skip_to_semicolon (p1 + 1); } + else if (strncmp (p, "exec", p1 - p) == 0) + { + ULONGEST ignored; + char pathname[PATH_MAX]; + int pathlen; + + /* Determine the length of the execd pathname. */ + p = unpack_varlen_hex (++p1, &ignored); + pathlen = (p - p1) / 2; + + /* Save the pathname for event reporting and for + the next run command. */ + hex2bin (p1, (gdb_byte *) pathname, pathlen); + pathname[pathlen] = '\0'; + + /* This is freed during event handling. */ + event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.kind = TARGET_WAITKIND_EXECD; + + /* Skip the registers included in this packet, since + they may be for an architecture different from the + one used by the original program. */ + skipregs = 1; + } else { ULONGEST pnum; char *p_temp; + if (skipregs) + { + p = skip_to_semicolon (p1 + 1); + p++; + continue; + } + /* Maybe a real ``P'' register number. */ p_temp = unpack_varlen_hex (p, &pnum); /* If the first invalid character is the colon, we got a @@ -8593,6 +8710,13 @@ extended_remote_run (char *args) { struct remote_state *rs = get_remote_state (); int len; + char *remote_exec_file = get_remote_exec_file (); + + /* If there is no remote exec-file associated with the current inferior, + set it to an empty string as a placeholder so it can be sent to + the remote. */ + if (remote_exec_file == NULL) + set_remote_exec_file_1 (""); /* If the user has disabled vRun support, or we have detected that support is not available, do not try it. */ @@ -8665,6 +8789,13 @@ extended_remote_create_inferior (struct target_ops *ops, int run_worked; char *stop_reply; struct remote_state *rs = get_remote_state (); + char *remote_exec_file = get_remote_exec_file (); + + /* If there is no remote exec-file associated with the current inferior, + set it to an empty string as a placeholder so it can be sent to + the remote. */ + if (remote_exec_file == NULL) + set_remote_exec_file_1 (""); /* If running asynchronously, register the target file descriptor with the event loop. */ @@ -12662,6 +12793,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; extended_remote_ops.to_supports_disable_randomization = extended_remote_supports_disable_randomization; extended_remote_ops.to_follow_fork = remote_follow_fork; + extended_remote_ops.to_follow_exec = remote_follow_exec; extended_remote_ops.to_insert_fork_catchpoint = remote_insert_fork_catchpoint; extended_remote_ops.to_remove_fork_catchpoint @@ -12893,6 +13025,10 @@ _initialize_remote (void) remote_g_packet_data_handle = gdbarch_data_register_pre_init (remote_g_packet_data_init); + remote_pspace_data + = register_program_space_data_with_cleanup (NULL, + remote_pspace_data_cleanup); + /* Initialize the per-target state. At the moment there is only one of these, not one per target. Only one target is active at a time. */ @@ -13272,6 +13408,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size], "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature], + "exec-event-feature", "exec-event-feature", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { @@ -13340,12 +13479,21 @@ Transfer files to and from the remote target system."), _("Delete a remote file."), &remote_cmdlist); - remote_exec_file = xstrdup (""); - add_setshow_string_noescape_cmd ("exec-file", class_files, - &remote_exec_file, _("\ + { + /* Pass a NULL (by reference) as the 'var' argument, since we do + not have a single variable in which to store the value. The + value is set per-inferior, stored in the program space. */ + char *nullptr = NULL; + + add_setshow_string_noescape_cmd ("exec-file", class_files, + &nullptr, _("\ Set the remote pathname for \"run\""), _("\ -Show the remote pathname for \"run\""), NULL, NULL, NULL, - &remote_set_cmdlist, &remote_show_cmdlist); +Show the remote pathname for \"run\""), NULL, + set_remote_exec_file, + show_remote_exec_file, + &remote_set_cmdlist, + &remote_show_cmdlist); + } add_setshow_boolean_cmd ("range-stepping", class_run, &use_range_stepping, _("\ diff --git a/gdb/target-debug.h b/gdb/target-debug.h index ddbdfd1..470d6f3 100644 --- a/gdb/target-debug.h +++ b/gdb/target-debug.h @@ -156,6 +156,8 @@ target_debug_do_print (plongest (X)) #define target_debug_print_enum_bptype(X) \ target_debug_do_print (plongest (X)) +#define target_debug_print_struct_inferior_p(X) \ + target_debug_do_print (host_address_to_string (X)) static void target_debug_print_struct_target_waitstatus_p (struct target_waitstatus *status) diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c index 8d51b6c..87197f8 100644 --- a/gdb/target-delegates.c +++ b/gdb/target-delegates.c @@ -1208,6 +1208,32 @@ debug_remove_exec_catchpoint (struct target_ops *self, int arg1) return result; } +static void +delegate_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ + self = self->beneath; + self->to_follow_exec (self, arg1, arg2); +} + +static void +tdefault_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ +} + +static void +debug_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ + fprintf_unfiltered (gdb_stdlog, "-> %s->to_follow_exec (...)\n", debug_target.to_shortname); + debug_target.to_follow_exec (&debug_target, arg1, arg2); + fprintf_unfiltered (gdb_stdlog, "<- %s->to_follow_exec (", debug_target.to_shortname); + target_debug_print_struct_target_ops_p (&debug_target); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_struct_inferior_p (arg1); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_char_p (arg2); + fputs_unfiltered (")\n", gdb_stdlog); +} + static int delegate_set_syscall_catchpoint (struct target_ops *self, int arg1, int arg2, int arg3, int arg4, int *arg5) { @@ -4032,6 +4058,8 @@ install_delegators (struct target_ops *ops) ops->to_insert_exec_catchpoint = delegate_insert_exec_catchpoint; if (ops->to_remove_exec_catchpoint == NULL) ops->to_remove_exec_catchpoint = delegate_remove_exec_catchpoint; + if (ops->to_follow_exec == NULL) + ops->to_follow_exec = delegate_follow_exec; if (ops->to_set_syscall_catchpoint == NULL) ops->to_set_syscall_catchpoint = delegate_set_syscall_catchpoint; if (ops->to_has_exited == NULL) @@ -4285,6 +4313,7 @@ install_dummy_methods (struct target_ops *ops) ops->to_follow_fork = default_follow_fork; ops->to_insert_exec_catchpoint = tdefault_insert_exec_catchpoint; ops->to_remove_exec_catchpoint = tdefault_remove_exec_catchpoint; + ops->to_follow_exec = tdefault_follow_exec; ops->to_set_syscall_catchpoint = tdefault_set_syscall_catchpoint; ops->to_has_exited = tdefault_has_exited; ops->to_mourn_inferior = default_mourn_inferior; @@ -4436,6 +4465,7 @@ init_debug_target (struct target_ops *ops) ops->to_follow_fork = debug_follow_fork; ops->to_insert_exec_catchpoint = debug_insert_exec_catchpoint; ops->to_remove_exec_catchpoint = debug_remove_exec_catchpoint; + ops->to_follow_exec = debug_follow_exec; ops->to_set_syscall_catchpoint = debug_set_syscall_catchpoint; ops->to_has_exited = debug_has_exited; ops->to_mourn_inferior = debug_mourn_inferior; diff --git a/gdb/target.c b/gdb/target.c index 3da984e..f425fbc 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2304,6 +2304,14 @@ target_follow_fork (int follow_child, int detach_fork) follow_child, detach_fork); } +/* Target wrapper for follow exec hook. */ + +void +target_follow_exec (struct inferior *inf, char *execd_pathname) +{ + current_target.to_follow_exec (¤t_target, inf, execd_pathname); +} + static void default_mourn_inferior (struct target_ops *self) { diff --git a/gdb/target.h b/gdb/target.h index da18f99..5f05b56 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -596,6 +596,8 @@ struct target_ops TARGET_DEFAULT_RETURN (1); int (*to_remove_exec_catchpoint) (struct target_ops *, int) TARGET_DEFAULT_RETURN (1); + void (*to_follow_exec) (struct target_ops *, struct inferior *, char *) + TARGET_DEFAULT_IGNORE (); int (*to_set_syscall_catchpoint) (struct target_ops *, int, int, int, int, int *) TARGET_DEFAULT_RETURN (1); @@ -1577,6 +1579,11 @@ extern void target_load (const char *arg, int from_tty); int target_follow_fork (int follow_child, int detach_fork); +/* Handle the target-specific bookkeeping required when the inferior + makes an exec call. INF is the exec'd inferior. */ + +void target_follow_exec (struct inferior *inf, char *execd_pathname); + /* On some targets, we can catch an inferior exec event when it occurs. These functions insert/remove an already-created catchpoint for such events. They return 0 for success, 1 if the -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 1/4] Extended-remote follow exec 2015-09-09 23:06 ` [PATCH v3 1/4] Extended-remote follow exec Don Breazeal @ 2015-09-10 12:43 ` Pedro Alves 2015-09-10 22:56 ` Don Breazeal 0 siblings, 1 reply; 55+ messages in thread From: Pedro Alves @ 2015-09-10 12:43 UTC (permalink / raw) To: Don Breazeal, gdb-patches On 09/10/2015 12:05 AM, Don Breazeal wrote: > Hi Pedro, > > This is an updated version of the patch previously submitted here: > https://sourceware.org/ml/gdb-patches/2015-07/msg00924.html. Changes > from the previous version include: > > * In gdbserver, when an exec event occurs, gdbserver deletes all > of the data (inferior, lwps, threads) associated with the execing > process and replaces it with a new set of data. > > * In GDB, the remote exec-file is now stored per-inferior in the > inferior's program space as a REGISTRY field. > > * In GDB, a new target hook, target_follow_exec, is used to enable > storing the remote exec-file as per-inferior data. > > * In GDB, follow_exec now calls add_inferior_with_spaces for mode > "new" in place of add_inferior and the calls to set up the program > and address spaces. > > Some of the things that were part of the previous patchset were > eliminated as a result of these changes, including: > > * Deleting "vanished" lwps in gdbserver/linux-low.c:send_sigstop. > > * Fiddling with the regcache and r_debug in > gdbserver/linux-low.c:handle_extended_wait. > > * Fiddling with the inferior's architecture in > remote.c:remote_parse_stop_reply. > > A couple of your questions about the previous version of the patch still > apply, in spite of the rework. Regarding the handling of the exec event > in linux-low.c:handle_extended_wait: > >>> + /* 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_stop; >> >> Shouldn't this be resume_continue? > > My thinking here is that as far as gdbserver is concerned, we *do* want > to use resume_stop, so that we stop and report the event to GDB. It will > be up to GDB whether to continue from this point. Does that make sense? Not really -- putting exec events out of the picture, consider: If you simply continue a thread (vCont;c) and it hits a breakpoint, it'll have last_resume_kind==resume_continue, and we still report the event to gdb, and it's still up to GDB whether to continue past the breakpoint. So if you set last_resume_kind to resume_continue, and drop this hunk: > @@ -3373,7 +3463,8 @@ linux_wait_1 (ptid_t ptid, > ourstatus->value.sig = GDB_SIGNAL_0; > } > else if (current_thread->last_resume_kind == resume_stop > - && WSTOPSIG (w) != SIGSTOP) > + && WSTOPSIG (w) != SIGSTOP > + && ourstatus->kind != TARGET_WAITKIND_EXECD) > { > /* A thread that has been requested to stop by GDB with vCont;t, > but, it stopped for other reasons. */ > @@ -5801,6 +5892,14 @@ linux_supports_vfork_events (void) > return linux_supports_tracefork (); > } ... what doesn't work? > @@ -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 = event_thr->entry.id; 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*/ Uppercase, period at end, double space. > + 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_stop; > + 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); > } > @@ -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]; Spaces around *. > + > + 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); > > @@ -619,6 +622,62 @@ get_remote_state (void) > return get_remote_state_raw (); > } > > +/* Cleanup routine for the remote module's pspace data. */ > + > +static void > +remote_pspace_data_cleanup (struct program_space *pspace, void *arg) > +{ > + char *remote_exec_file = arg; > + > + if (remote_exec_file != NULL) > + xfree (remote_exec_file); No need to check for NULL before calling xfree. > +} > + > +/* Fetch the remote exec-file from the current program space. */ > + > +static char * Can this be const char * ? > +get_remote_exec_file (void) > +{ > + char *remote_exec_file; > + > + remote_exec_file = program_space_data (current_program_space, > + remote_pspace_data); How about adding: if (remote_exec_file == NULL) return ""; > + return remote_exec_file; avoiding callers having to do it. > +} > + > +/* Set the remote exec file for the current program space. */ > + > +static void > +set_remote_exec_file_1 (char *remote_exec_file) > +{ > + char *old_file = get_remote_exec_file (); > + Here's you'd use old_file = program_space_data (current_program_space, remote_pspace_data); directly. It would seem super fine to me given the set_program_space_data just below. > + if (old_file != NULL) > + xfree (old_file); No need for NULL check. > + > + set_program_space_data (current_program_space, remote_pspace_data, > + xstrdup (remote_exec_file)); > +} > + > +/* The "set/show remote exec-file" set hook. */ > + > +static void > +set_remote_exec_file (char *ignored, int from_tty, > + struct cmd_list_element *c) > +{ > + gdb_assert (*(char **) c->var != NULL); > + set_remote_exec_file_1 (*(char **) c->var); Use temp var please. E.g.: char *file = *(char **) c->var; gdb_assert (file != NULL); set_remote_exec_file_1 (file); Or see another suggestion below. > +} > + > +/* The "set/show remote exec-file" show hook. */ > + > +static void > +show_remote_exec_file (struct ui_file *file, int from_tty, > + struct cmd_list_element *cmd, const char *value) > +{ > + fprintf_filtered (file, "%s\n", get_remote_exec_file ()); > +} > + > static int > compare_pnums (const void *lhs_, const void *rhs_) > { > @@ -4779,6 +4842,28 @@ remote_follow_fork (struct target_ops *ops, int follow_child, > return 0; > } > > +/* Target follow-exec function for remote targets. Save EXECD_PATHNAME > + in the program space of the new inferior. On entry and at return the > + current inferior is the exec'ing inferior. INF is the new exec'd > + inferior, which may be the same as the exec'ing inferior unless > + follow-exec-mode is "new". */ > + > +static void > +remote_follow_exec (struct target_ops *ops, > + struct inferior *inf, char *execd_pathname) > +{ > + struct cleanup *old_chain = save_current_program_space (); > + > + /* We know that this is a target file name, so if it has the "target:" > + prefix we strip it off before saving it in the program space. */ > + if (is_target_filename (execd_pathname)) > + execd_pathname += strlen (TARGET_SYSROOT_PREFIX); > + > + set_current_program_space (inf->pspace); Why not pass down the pspace as parameter to set_remote_exec_file_1 etc., avoiding this? > + set_remote_exec_file_1 (execd_pathname); > + do_cleanups (old_chain); > +} > + > /* Same as remote_detach, but don't send the "D" packet; just disconnect. */ > > static void > @@ -5977,6 +6062,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event) > struct remote_arch_state *rsa = get_remote_arch_state (); > ULONGEST addr; > char *p; > + int skipregs = 0; > > event->ptid = null_ptid; > event->rs = get_remote_state (); > @@ -13340,12 +13479,21 @@ Transfer files to and from the remote target system."), > _("Delete a remote file."), > &remote_cmdlist); > > - remote_exec_file = xstrdup (""); > - add_setshow_string_noescape_cmd ("exec-file", class_files, > - &remote_exec_file, _("\ > + { > + /* Pass a NULL (by reference) as the 'var' argument, since we do > + not have a single variable in which to store the value. The > + value is set per-inferior, stored in the program space. */ > + char *nullptr = NULL; Passing the address of a local variable can't be good. In: > +static void > +set_remote_exec_file (char *ignored, int from_tty, > + struct cmd_list_element *c) > +{ > + gdb_assert (*(char **) c->var != NULL); > + set_remote_exec_file_1 (*(char **) c->var); c->var points to nullptr. So this set command ends up poking memory to something random on the stack. I'd prefer leaving the old command variable global, but rename it remote_exec_file_var, like: /* The variable registered as control variable the set/show remote exec-file commands. Necessary because ... */ static char *remote_exec_file_var = ""; There's some precedent for that, in e.g., record_insn_history_size_setshow_var and history_size_setshow_var. Note that that way, referencing remote_exec_file_var directly in set_remote_exec_file avoids the casts. > + > + add_setshow_string_noescape_cmd ("exec-file", class_files, > + &nullptr, _("\ > Set the remote pathname for \"run\""), _("\ > -Show the remote pathname for \"run\""), NULL, NULL, NULL, > - &remote_set_cmdlist, &remote_show_cmdlist); > +Show the remote pathname for \"run\""), NULL, > + set_remote_exec_file, > + show_remote_exec_file, > + &remote_set_cmdlist, > + &remote_show_cmdlist); > + } Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 1/4] Extended-remote follow exec 2015-09-10 12:43 ` Pedro Alves @ 2015-09-10 22:56 ` Don Breazeal 2015-09-10 23:00 ` Don Breazeal 2015-09-11 8:34 ` Pedro Alves 0 siblings, 2 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-10 22:56 UTC (permalink / raw) To: Pedro Alves, gdb-patches On 9/10/2015 5:43 AM, Pedro Alves wrote: > On 09/10/2015 12:05 AM, Don Breazeal wrote: >> Hi Pedro, >> >> This is an updated version of the patch previously submitted here: >> https://sourceware.org/ml/gdb-patches/2015-07/msg00924.html. Changes >> from the previous version include: >> >> * In gdbserver, when an exec event occurs, gdbserver deletes all >> of the data (inferior, lwps, threads) associated with the execing >> process and replaces it with a new set of data. >> >> * In GDB, the remote exec-file is now stored per-inferior in the >> inferior's program space as a REGISTRY field. >> >> * In GDB, a new target hook, target_follow_exec, is used to enable >> storing the remote exec-file as per-inferior data. >> >> * In GDB, follow_exec now calls add_inferior_with_spaces for mode >> "new" in place of add_inferior and the calls to set up the program >> and address spaces. >> >> Some of the things that were part of the previous patchset were >> eliminated as a result of these changes, including: >> >> * Deleting "vanished" lwps in gdbserver/linux-low.c:send_sigstop. >> >> * Fiddling with the regcache and r_debug in >> gdbserver/linux-low.c:handle_extended_wait. >> >> * Fiddling with the inferior's architecture in >> remote.c:remote_parse_stop_reply. >> >> A couple of your questions about the previous version of the patch still >> apply, in spite of the rework. Regarding the handling of the exec event >> in linux-low.c:handle_extended_wait: >> >>>> + /* 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_stop; >>> >>> Shouldn't this be resume_continue? >> >> My thinking here is that as far as gdbserver is concerned, we *do* want >> to use resume_stop, so that we stop and report the event to GDB. It will >> be up to GDB whether to continue from this point. Does that make sense? > > Not really -- putting exec events out of the picture, consider: > > If you simply continue a thread (vCont;c) and it hits a breakpoint, it'll > have last_resume_kind==resume_continue, and we still report the event > to gdb, and it's still up to GDB whether to continue past the breakpoint. > > So if you set last_resume_kind to resume_continue, and drop this hunk: > >> @@ -3373,7 +3463,8 @@ linux_wait_1 (ptid_t ptid, >> ourstatus->value.sig = GDB_SIGNAL_0; >> } >> else if (current_thread->last_resume_kind == resume_stop >> - && WSTOPSIG (w) != SIGSTOP) >> + && WSTOPSIG (w) != SIGSTOP >> + && ourstatus->kind != TARGET_WAITKIND_EXECD) >> { >> /* A thread that has been requested to stop by GDB with vCont;t, >> but, it stopped for other reasons. */ >> @@ -5801,6 +5892,14 @@ linux_supports_vfork_events (void) >> return linux_supports_tracefork (); >> } > > ... what doesn't work? That works just fine. I've made that change. Clearly I didn't understand the purpose of resume_stop. Is that only used when GDB requests a stop, and/or when an inferior is just starting up or being attached? As opposed to when the inferior is stopped by an event? > > >> @@ -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 = event_thr->entry.id; > > event_ptid = ptid_of (event_thr); > Made this change. > >> + 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*/ > > Uppercase, period at end, double space. Done. > >> + 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_stop; >> + 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); >> } > > > >> @@ -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]; > > Spaces around *. Done. > >> + >> + 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); >> > > > > >> @@ -619,6 +622,62 @@ get_remote_state (void) >> return get_remote_state_raw (); >> } >> >> +/* Cleanup routine for the remote module's pspace data. */ >> + >> +static void >> +remote_pspace_data_cleanup (struct program_space *pspace, void *arg) >> +{ >> + char *remote_exec_file = arg; >> + >> + if (remote_exec_file != NULL) >> + xfree (remote_exec_file); > > No need to check for NULL before calling xfree. Done. > >> +} >> + >> +/* Fetch the remote exec-file from the current program space. */ >> + >> +static char * > > Can this be const char * ? > >> +get_remote_exec_file (void) >> +{ >> + char *remote_exec_file; >> + >> + remote_exec_file = program_space_data (current_program_space, >> + remote_pspace_data); > > How about adding: > > if (remote_exec_file == NULL) > return ""; > >> + return remote_exec_file; > > avoiding callers having to do it. > Done. >> +} >> + >> +/* Set the remote exec file for the current program space. */ >> + >> +static void >> +set_remote_exec_file_1 (char *remote_exec_file) >> +{ >> + char *old_file = get_remote_exec_file (); >> + > > Here's you'd use > old_file = program_space_data (current_program_space, > remote_pspace_data); > > directly. It would seem super fine to me given the > set_program_space_data just below. Done. > >> + if (old_file != NULL) >> + xfree (old_file); > > No need for NULL check. Done. > >> + >> + set_program_space_data (current_program_space, remote_pspace_data, >> + xstrdup (remote_exec_file)); >> +} >> + >> +/* The "set/show remote exec-file" set hook. */ >> + >> +static void >> +set_remote_exec_file (char *ignored, int from_tty, >> + struct cmd_list_element *c) >> +{ >> + gdb_assert (*(char **) c->var != NULL); >> + set_remote_exec_file_1 (*(char **) c->var); > > Use temp var please. E.g.: > > char *file = *(char **) c->var; > > gdb_assert (file != NULL); > set_remote_exec_file_1 (file); > > Or see another suggestion below. > >> +} >> + >> +/* The "set/show remote exec-file" show hook. */ >> + >> +static void >> +show_remote_exec_file (struct ui_file *file, int from_tty, >> + struct cmd_list_element *cmd, const char *value) >> +{ >> + fprintf_filtered (file, "%s\n", get_remote_exec_file ()); >> +} >> + >> static int >> compare_pnums (const void *lhs_, const void *rhs_) >> { > > > > > >> @@ -4779,6 +4842,28 @@ remote_follow_fork (struct target_ops *ops, int follow_child, >> return 0; >> } >> >> +/* Target follow-exec function for remote targets. Save EXECD_PATHNAME >> + in the program space of the new inferior. On entry and at return the >> + current inferior is the exec'ing inferior. INF is the new exec'd >> + inferior, which may be the same as the exec'ing inferior unless >> + follow-exec-mode is "new". */ >> + >> +static void >> +remote_follow_exec (struct target_ops *ops, >> + struct inferior *inf, char *execd_pathname) >> +{ >> + struct cleanup *old_chain = save_current_program_space (); >> + >> + /* We know that this is a target file name, so if it has the "target:" >> + prefix we strip it off before saving it in the program space. */ >> + if (is_target_filename (execd_pathname)) >> + execd_pathname += strlen (TARGET_SYSROOT_PREFIX); >> + >> + set_current_program_space (inf->pspace); > > Why not pass down the pspace as parameter to set_remote_exec_file_1 > etc., avoiding this? > Done. >> + set_remote_exec_file_1 (execd_pathname); >> + do_cleanups (old_chain); >> +} >> + >> /* Same as remote_detach, but don't send the "D" packet; just disconnect. */ >> >> static void >> @@ -5977,6 +6062,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event) >> struct remote_arch_state *rsa = get_remote_arch_state (); >> ULONGEST addr; >> char *p; >> + int skipregs = 0; >> >> event->ptid = null_ptid; >> event->rs = get_remote_state (); > > > > >> @@ -13340,12 +13479,21 @@ Transfer files to and from the remote target system."), >> _("Delete a remote file."), >> &remote_cmdlist); >> >> - remote_exec_file = xstrdup (""); >> - add_setshow_string_noescape_cmd ("exec-file", class_files, >> - &remote_exec_file, _("\ >> + { >> + /* Pass a NULL (by reference) as the 'var' argument, since we do >> + not have a single variable in which to store the value. The >> + value is set per-inferior, stored in the program space. */ >> + char *nullptr = NULL; > > Passing the address of a local variable can't be good. In: > >> +static void >> +set_remote_exec_file (char *ignored, int from_tty, >> + struct cmd_list_element *c) >> +{ >> + gdb_assert (*(char **) c->var != NULL); >> + set_remote_exec_file_1 (*(char **) c->var); > > c->var points to nullptr. So this set command ends up poking > memory to something random on the stack. Oh, ugh. :-P > > I'd prefer leaving the old command variable global, but rename it > remote_exec_file_var, like: > > /* The variable registered as control variable the set/show > remote exec-file commands. Necessary because ... */ > static char *remote_exec_file_var = ""; > > There's some precedent for that, in e.g., record_insn_history_size_setshow_var > and history_size_setshow_var. > > Note that that way, referencing remote_exec_file_var directly in > set_remote_exec_file avoids the casts. I've made these changes. > >> + >> + add_setshow_string_noescape_cmd ("exec-file", class_files, >> + &nullptr, _("\ >> Set the remote pathname for \"run\""), _("\ >> -Show the remote pathname for \"run\""), NULL, NULL, NULL, >> - &remote_set_cmdlist, &remote_show_cmdlist); >> +Show the remote pathname for \"run\""), NULL, >> + set_remote_exec_file, >> + show_remote_exec_file, >> + &remote_set_cmdlist, >> + &remote_show_cmdlist); >> + } Thanks for the review, Pedro. An updated patch follows below. I tested the changes by running the exec-related tests on Linux x86_64 with extended-remote. How does this look? --Don --- gdb/gdbserver/linux-low.c | 147 ++++++++++++++++++++++++++++++++++++------- gdb/gdbserver/lynx-low.c | 1 + gdb/gdbserver/remote-utils.c | 20 ++++++ gdb/gdbserver/server.c | 11 ++++ gdb/gdbserver/server.h | 1 + gdb/gdbserver/target.h | 7 +++ gdb/gdbserver/win32-low.c | 1 + gdb/infrun.c | 17 +++-- gdb/nat/linux-ptrace.c | 11 ++++ gdb/nat/linux-ptrace.h | 1 + gdb/remote.c | 147 ++++++++++++++++++++++++++++++++++++++++--- gdb/target-debug.h | 2 + gdb/target-delegates.c | 30 +++++++++ gdb/target.c | 8 +++ gdb/target.h | 7 +++ 15 files changed, 370 insertions(+), 41 deletions(-) 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 */ diff --git a/gdb/infrun.c b/gdb/infrun.c index e89e02a..84890b4 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1095,6 +1095,7 @@ follow_exec (ptid_t ptid, char *execd_pathname) struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); int pid = ptid_get_pid (ptid); + ptid_t process_ptid; /* This is an exec event that we actually wish to pay attention to. Refresh our symbol table to the newly exec'd program, remove any @@ -1161,8 +1162,9 @@ follow_exec (ptid_t ptid, char *execd_pathname) update_breakpoints_after_exec (); /* What is this a.out's name? */ + process_ptid = pid_to_ptid (pid); printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (inferior_ptid), + target_pid_to_str (process_ptid), execd_pathname); /* We've followed the inferior through an exec. Therefore, the @@ -1191,8 +1193,6 @@ follow_exec (ptid_t ptid, char *execd_pathname) if (follow_exec_mode_string == follow_exec_mode_new) { - struct program_space *pspace; - /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ @@ -1201,14 +1201,13 @@ follow_exec (ptid_t ptid, char *execd_pathname) the same ptid, which can confuse find_inferior_ptid. */ exit_inferior_num_silent (current_inferior ()->num); - inf = add_inferior (pid); - pspace = add_program_space (maybe_new_address_space ()); - inf->pspace = pspace; - inf->aspace = pspace->aspace; - add_thread (ptid); + inf = add_inferior_with_spaces (); + inf->pid = pid; + target_follow_exec (inf, execd_pathname); set_current_inferior (inf); - set_current_program_space (pspace); + set_current_program_space (inf->pspace); + add_thread (ptid); } else { diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index f097c8a..4222df5 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -538,6 +538,17 @@ linux_supports_tracefork (void) return ptrace_supports_feature (PTRACE_O_TRACEFORK); } +/* Returns non-zero if PTRACE_EVENT_EXEC is supported by ptrace, + 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is + PTRACE_EVENT_CLONE, PTRACE_EVENT_FORK and PTRACE_EVENT_VFORK, + since they were all added to the kernel at the same time. */ + +int +linux_supports_traceexec (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEEXEC); +} + /* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace, 0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h index 8bff908..1be38fe 100644 --- a/gdb/nat/linux-ptrace.h +++ b/gdb/nat/linux-ptrace.h @@ -168,6 +168,7 @@ extern void linux_check_ptrace_features (void); extern void linux_enable_event_reporting (pid_t pid, int attached); extern void linux_disable_event_reporting (pid_t pid); extern int linux_supports_tracefork (void); +extern int linux_supports_traceexec (void); extern int linux_supports_traceclone (void); extern int linux_supports_tracevforkdone (void); extern int linux_supports_tracesysgood (void); diff --git a/gdb/remote.c b/gdb/remote.c index e4d3edf..25def33 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -75,6 +75,14 @@ static char *target_buf; static long target_buf_size; +/* Per-program-space data key. */ +static const struct program_space_data *remote_pspace_data; + +/* The variable registered as the control variable used by the + remote exec-file commands. Used by the set/show machinery + as the location of the remote exec-file value. */ +static char *remote_exec_file_var; + /* The size to align memory write packets, when practical. The protocol does not guarantee any alignment, and gdb will generate short writes and unaligned writes, but even as a best-effort attempt this @@ -619,6 +627,63 @@ get_remote_state (void) return get_remote_state_raw (); } +/* Cleanup routine for the remote module's pspace data. */ + +static void +remote_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + char *remote_exec_file = arg; + + xfree (remote_exec_file); +} + +/* Fetch the remote exec-file from the current program space. */ + +static const char * +get_remote_exec_file (void) +{ + char *remote_exec_file; + + remote_exec_file = program_space_data (current_program_space, + remote_pspace_data); + if (remote_exec_file == NULL) + return ""; + + return remote_exec_file; +} + +/* Set the remote exec file for the current program space. */ + +static void +set_remote_exec_file_1 (struct program_space *pspace, + char *remote_exec_file) +{ + char *old_file = program_space_data (pspace, remote_pspace_data); + + xfree (old_file); + set_program_space_data (pspace, remote_pspace_data, + xstrdup (remote_exec_file)); +} + +/* The "set/show remote exec-file" set command hook. */ + +static void +set_remote_exec_file (char *ignored, int from_tty, + struct cmd_list_element *c) +{ + gdb_assert (remote_exec_file_var != NULL); + set_remote_exec_file_1 (current_program_space, remote_exec_file_var); +} + +/* The "set/show remote exec-file" show command hook. */ + +static void +show_remote_exec_file (struct ui_file *file, int from_tty, + struct cmd_list_element *cmd, const char *value) +{ + fprintf_filtered (file, "%s\n", remote_exec_file_var); +} + static int compare_pnums (const void *lhs_, const void *rhs_) { @@ -901,10 +966,6 @@ static unsigned int remote_address_size; static int remote_async_terminal_ours_p; -/* The executable file to use for "run" on the remote side. */ - -static char *remote_exec_file = ""; - \f /* User configurable variables for the number of characters in a memory read/write packet. MIN (rsa->remote_packet_size, @@ -1401,6 +1462,9 @@ enum { /* Support for the Qbtrace-conf:pt:size packet. */ PACKET_Qbtrace_conf_pt_size, + /* Support for exec events. */ + PACKET_exec_event_feature, + PACKET_MAX }; @@ -4279,6 +4343,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_fork_event_feature }, { "vfork-events", PACKET_DISABLE, remote_supported_packet, PACKET_vfork_event_feature }, + { "exec-events", PACKET_DISABLE, remote_supported_packet, + PACKET_exec_event_feature }, { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_conf_pt_size } }; @@ -4368,6 +4434,9 @@ remote_query_supported (void) if (packet_set_cmd_state (PACKET_vfork_event_feature) != AUTO_BOOLEAN_FALSE) q = remote_query_supported_append (q, "vfork-events+"); + if (packet_set_cmd_state (PACKET_exec_event_feature) + != AUTO_BOOLEAN_FALSE) + q = remote_query_supported_append (q, "exec-events+"); } q = reconcat (q, "qSupported:", q, (char *) NULL); @@ -4779,6 +4848,24 @@ remote_follow_fork (struct target_ops *ops, int follow_child, return 0; } +/* Target follow-exec function for remote targets. Save EXECD_PATHNAME + in the program space of the new inferior. On entry and at return the + current inferior is the exec'ing inferior. INF is the new exec'd + inferior, which may be the same as the exec'ing inferior unless + follow-exec-mode is "new". */ + +static void +remote_follow_exec (struct target_ops *ops, + struct inferior *inf, char *execd_pathname) +{ + /* We know that this is a target file name, so if it has the "target:" + prefix we strip it off before saving it in the program space. */ + if (is_target_filename (execd_pathname)) + execd_pathname += strlen (TARGET_SYSROOT_PREFIX); + + set_remote_exec_file_1 (inf->pspace, execd_pathname); +} + /* Same as remote_detach, but don't send the "D" packet; just disconnect. */ static void @@ -5977,6 +6064,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event) struct remote_arch_state *rsa = get_remote_arch_state (); ULONGEST addr; char *p; + int skipregs = 0; event->ptid = null_ptid; event->rs = get_remote_state (); @@ -6089,11 +6177,42 @@ Packet: '%s'\n"), event->ws.kind = TARGET_WAITKIND_VFORK_DONE; p = skip_to_semicolon (p1 + 1); } + else if (strncmp (p, "exec", p1 - p) == 0) + { + ULONGEST ignored; + char pathname[PATH_MAX]; + int pathlen; + + /* Determine the length of the execd pathname. */ + p = unpack_varlen_hex (++p1, &ignored); + pathlen = (p - p1) / 2; + + /* Save the pathname for event reporting and for + the next run command. */ + hex2bin (p1, (gdb_byte *) pathname, pathlen); + pathname[pathlen] = '\0'; + + /* This is freed during event handling. */ + event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.kind = TARGET_WAITKIND_EXECD; + + /* Skip the registers included in this packet, since + they may be for an architecture different from the + one used by the original program. */ + skipregs = 1; + } else { ULONGEST pnum; char *p_temp; + if (skipregs) + { + p = skip_to_semicolon (p1 + 1); + p++; + continue; + } + /* Maybe a real ``P'' register number. */ p_temp = unpack_varlen_hex (p, &pnum); /* If the first invalid character is the colon, we got a @@ -8593,6 +8712,7 @@ extended_remote_run (char *args) { struct remote_state *rs = get_remote_state (); int len; + const char *remote_exec_file = get_remote_exec_file (); /* If the user has disabled vRun support, or we have detected that support is not available, do not try it. */ @@ -8665,6 +8785,7 @@ extended_remote_create_inferior (struct target_ops *ops, int run_worked; char *stop_reply; struct remote_state *rs = get_remote_state (); + const char *remote_exec_file = get_remote_exec_file (); /* If running asynchronously, register the target file descriptor with the event loop. */ @@ -12662,6 +12783,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; extended_remote_ops.to_supports_disable_randomization = extended_remote_supports_disable_randomization; extended_remote_ops.to_follow_fork = remote_follow_fork; + extended_remote_ops.to_follow_exec = remote_follow_exec; extended_remote_ops.to_insert_fork_catchpoint = remote_insert_fork_catchpoint; extended_remote_ops.to_remove_fork_catchpoint @@ -12893,6 +13015,10 @@ _initialize_remote (void) remote_g_packet_data_handle = gdbarch_data_register_pre_init (remote_g_packet_data_init); + remote_pspace_data + = register_program_space_data_with_cleanup (NULL, + remote_pspace_data_cleanup); + /* Initialize the per-target state. At the moment there is only one of these, not one per target. Only one target is active at a time. */ @@ -13272,6 +13398,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size], "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature], + "exec-event-feature", "exec-event-feature", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { @@ -13340,12 +13469,14 @@ Transfer files to and from the remote target system."), _("Delete a remote file."), &remote_cmdlist); - remote_exec_file = xstrdup (""); add_setshow_string_noescape_cmd ("exec-file", class_files, - &remote_exec_file, _("\ + &remote_exec_file_var, _("\ Set the remote pathname for \"run\""), _("\ -Show the remote pathname for \"run\""), NULL, NULL, NULL, - &remote_set_cmdlist, &remote_show_cmdlist); +Show the remote pathname for \"run\""), NULL, + set_remote_exec_file, + show_remote_exec_file, + &remote_set_cmdlist, + &remote_show_cmdlist); add_setshow_boolean_cmd ("range-stepping", class_run, &use_range_stepping, _("\ diff --git a/gdb/target-debug.h b/gdb/target-debug.h index ddbdfd1..470d6f3 100644 --- a/gdb/target-debug.h +++ b/gdb/target-debug.h @@ -156,6 +156,8 @@ target_debug_do_print (plongest (X)) #define target_debug_print_enum_bptype(X) \ target_debug_do_print (plongest (X)) +#define target_debug_print_struct_inferior_p(X) \ + target_debug_do_print (host_address_to_string (X)) static void target_debug_print_struct_target_waitstatus_p (struct target_waitstatus *status) diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c index 8d51b6c..87197f8 100644 --- a/gdb/target-delegates.c +++ b/gdb/target-delegates.c @@ -1208,6 +1208,32 @@ debug_remove_exec_catchpoint (struct target_ops *self, int arg1) return result; } +static void +delegate_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ + self = self->beneath; + self->to_follow_exec (self, arg1, arg2); +} + +static void +tdefault_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ +} + +static void +debug_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ + fprintf_unfiltered (gdb_stdlog, "-> %s->to_follow_exec (...)\n", debug_target.to_shortname); + debug_target.to_follow_exec (&debug_target, arg1, arg2); + fprintf_unfiltered (gdb_stdlog, "<- %s->to_follow_exec (", debug_target.to_shortname); + target_debug_print_struct_target_ops_p (&debug_target); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_struct_inferior_p (arg1); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_char_p (arg2); + fputs_unfiltered (")\n", gdb_stdlog); +} + static int delegate_set_syscall_catchpoint (struct target_ops *self, int arg1, int arg2, int arg3, int arg4, int *arg5) { @@ -4032,6 +4058,8 @@ install_delegators (struct target_ops *ops) ops->to_insert_exec_catchpoint = delegate_insert_exec_catchpoint; if (ops->to_remove_exec_catchpoint == NULL) ops->to_remove_exec_catchpoint = delegate_remove_exec_catchpoint; + if (ops->to_follow_exec == NULL) + ops->to_follow_exec = delegate_follow_exec; if (ops->to_set_syscall_catchpoint == NULL) ops->to_set_syscall_catchpoint = delegate_set_syscall_catchpoint; if (ops->to_has_exited == NULL) @@ -4285,6 +4313,7 @@ install_dummy_methods (struct target_ops *ops) ops->to_follow_fork = default_follow_fork; ops->to_insert_exec_catchpoint = tdefault_insert_exec_catchpoint; ops->to_remove_exec_catchpoint = tdefault_remove_exec_catchpoint; + ops->to_follow_exec = tdefault_follow_exec; ops->to_set_syscall_catchpoint = tdefault_set_syscall_catchpoint; ops->to_has_exited = tdefault_has_exited; ops->to_mourn_inferior = default_mourn_inferior; @@ -4436,6 +4465,7 @@ init_debug_target (struct target_ops *ops) ops->to_follow_fork = debug_follow_fork; ops->to_insert_exec_catchpoint = debug_insert_exec_catchpoint; ops->to_remove_exec_catchpoint = debug_remove_exec_catchpoint; + ops->to_follow_exec = debug_follow_exec; ops->to_set_syscall_catchpoint = debug_set_syscall_catchpoint; ops->to_has_exited = debug_has_exited; ops->to_mourn_inferior = debug_mourn_inferior; diff --git a/gdb/target.c b/gdb/target.c index 3da984e..f425fbc 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2304,6 +2304,14 @@ target_follow_fork (int follow_child, int detach_fork) follow_child, detach_fork); } +/* Target wrapper for follow exec hook. */ + +void +target_follow_exec (struct inferior *inf, char *execd_pathname) +{ + current_target.to_follow_exec (¤t_target, inf, execd_pathname); +} + static void default_mourn_inferior (struct target_ops *self) { diff --git a/gdb/target.h b/gdb/target.h index da18f99..5f05b56 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -596,6 +596,8 @@ struct target_ops TARGET_DEFAULT_RETURN (1); int (*to_remove_exec_catchpoint) (struct target_ops *, int) TARGET_DEFAULT_RETURN (1); + void (*to_follow_exec) (struct target_ops *, struct inferior *, char *) + TARGET_DEFAULT_IGNORE (); int (*to_set_syscall_catchpoint) (struct target_ops *, int, int, int, int, int *) TARGET_DEFAULT_RETURN (1); @@ -1577,6 +1579,11 @@ extern void target_load (const char *arg, int from_tty); int target_follow_fork (int follow_child, int detach_fork); +/* Handle the target-specific bookkeeping required when the inferior + makes an exec call. INF is the exec'd inferior. */ + +void target_follow_exec (struct inferior *inf, char *execd_pathname); + /* On some targets, we can catch an inferior exec event when it occurs. These functions insert/remove an already-created catchpoint for such events. They return 0 for success, 1 if the -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 1/4] Extended-remote follow exec 2015-09-10 22:56 ` Don Breazeal @ 2015-09-10 23:00 ` Don Breazeal 2015-09-11 8:34 ` Pedro Alves 1 sibling, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-10 23:00 UTC (permalink / raw) To: Pedro Alves, gdb-patches > > I tested the changes by running the exec-related tests on Linux x86_64 > with extended-remote. > Correction - I ran all the tests on Linux x86_64 with extended-remote. --Don ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 1/4] Extended-remote follow exec 2015-09-10 22:56 ` Don Breazeal 2015-09-10 23:00 ` Don Breazeal @ 2015-09-11 8:34 ` Pedro Alves 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal 1 sibling, 1 reply; 55+ messages in thread From: Pedro Alves @ 2015-09-11 8:34 UTC (permalink / raw) To: Don Breazeal, gdb-patches Hi Don, Other than the nits below, it LGTM. Fix those and you're good to go. Please push. On 09/10/2015 11:56 PM, Don Breazeal wrote: > On 9/10/2015 5:43 AM, Pedro Alves wrote: >> On 09/10/2015 12:05 AM, Don Breazeal wrote: >>> Hi Pedro, >>> >>> This is an updated version of the patch previously submitted here: >>> https://sourceware.org/ml/gdb-patches/2015-07/msg00924.html. Changes >>> from the previous version include: >>> >>> * In gdbserver, when an exec event occurs, gdbserver deletes all >>> of the data (inferior, lwps, threads) associated with the execing >>> process and replaces it with a new set of data. >>> >>> * In GDB, the remote exec-file is now stored per-inferior in the >>> inferior's program space as a REGISTRY field. >>> >>> * In GDB, a new target hook, target_follow_exec, is used to enable >>> storing the remote exec-file as per-inferior data. >>> >>> * In GDB, follow_exec now calls add_inferior_with_spaces for mode >>> "new" in place of add_inferior and the calls to set up the program >>> and address spaces. >>> >>> Some of the things that were part of the previous patchset were >>> eliminated as a result of these changes, including: >>> >>> * Deleting "vanished" lwps in gdbserver/linux-low.c:send_sigstop. >>> >>> * Fiddling with the regcache and r_debug in >>> gdbserver/linux-low.c:handle_extended_wait. >>> >>> * Fiddling with the inferior's architecture in >>> remote.c:remote_parse_stop_reply. >>> >>> A couple of your questions about the previous version of the patch still >>> apply, in spite of the rework. Regarding the handling of the exec event >>> in linux-low.c:handle_extended_wait: >>> >>>>> + /* 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_stop; >>>> >>>> Shouldn't this be resume_continue? >>> >>> My thinking here is that as far as gdbserver is concerned, we *do* want >>> to use resume_stop, so that we stop and report the event to GDB. It will >>> be up to GDB whether to continue from this point. Does that make sense? >> >> Not really -- putting exec events out of the picture, consider: >> >> If you simply continue a thread (vCont;c) and it hits a breakpoint, it'll >> have last_resume_kind==resume_continue, and we still report the event >> to gdb, and it's still up to GDB whether to continue past the breakpoint. >> >> So if you set last_resume_kind to resume_continue, and drop this hunk: >> >>> @@ -3373,7 +3463,8 @@ linux_wait_1 (ptid_t ptid, >>> ourstatus->value.sig = GDB_SIGNAL_0; >>> } >>> else if (current_thread->last_resume_kind == resume_stop >>> - && WSTOPSIG (w) != SIGSTOP) >>> + && WSTOPSIG (w) != SIGSTOP >>> + && ourstatus->kind != TARGET_WAITKIND_EXECD) >>> { >>> /* A thread that has been requested to stop by GDB with vCont;t, >>> but, it stopped for other reasons. */ >>> @@ -5801,6 +5892,14 @@ linux_supports_vfork_events (void) >>> return linux_supports_tracefork (); >>> } >> >> ... what doesn't work? > > That works just fine. I've made that change. > > Clearly I didn't understand the purpose of resume_stop. Is that only > used when GDB requests a stop, and/or when an inferior is just starting > up or being attached? As opposed to when the inferior is stopped by an > event? Yeah, lots of different state flags, and several layers of state machines involved. gdb's, core gdbserver's, and linux-low's. The flags we have today have come into being through code evolution, rather than design... Probably, we could probably merge/simplify them, but it'd require lots of careful analysis. Anyway, from a high level, thread->last_resume_kind indicates the last resume state from _gdb_'s perspective. So resume_stop is used: - when GDB requests an explicit stop with vCont;t. The thread gets set to resume_stop even if it is still running. - when a thread that was last continued/stepped (resume_continue/resume_step) hits an event and _after_ gdbserver reports the stop to gdb, _then_ it's last resume kind is set to resume_stop. > --- a/gdb/remote.c > +++ b/gdb/remote.c > @@ -75,6 +75,14 @@ > static char *target_buf; > static long target_buf_size; > > +/* Per-program-space data key. */ > +static const struct program_space_data *remote_pspace_data; > + > +/* The variable registered as the control variable used by the > + remote exec-file commands. Used by the set/show machinery > + as the location of the remote exec-file value. */ > +static char *remote_exec_file_var; I think we should mention the per-program-space aspect. Something like: /* The variable registered as the control variable used by the remote exec-file commands. While the remote exec-file setting is per-program-space, the set/show machinery uses this as location of the remote exec-file value. */ > +/* Fetch the remote exec-file from the current program space. */ > + > +static const char * > +get_remote_exec_file (void) > +{ > + char *remote_exec_file; > + > + remote_exec_file = program_space_data (current_program_space, > + remote_pspace_data); > + if (remote_exec_file == NULL) > + return ""; > + > + return remote_exec_file; > +} > + > +/* Set the remote exec file for the current program space. */ /* Set the remote exec file for PSPACE. */ > + > +static void > +set_remote_exec_file_1 (struct program_space *pspace, > + char *remote_exec_file) I think we can now rename this for clarity. E.g., set_program_space_remote_exec_file / set_pspace_remote_exec_file. > +{ > + char *old_file = program_space_data (pspace, remote_pspace_data); > + > + xfree (old_file); > + set_program_space_data (pspace, remote_pspace_data, > + xstrdup (remote_exec_file)); > +} Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-11 8:34 ` Pedro Alves @ 2015-09-11 18:38 ` Don Breazeal 2015-09-11 18:38 ` [pushed][PATCH v3 3/4] Extended-remote exec test Don Breazeal ` (5 more replies) 0 siblings, 6 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-11 18:38 UTC (permalink / raw) To: gdb-patches Here is what I pushed. Thanks, --Don This patch implements support for exec events on extended-remote Linux targets. Follow-exec-mode and rerun behave as expected. Catchpoints and test updates are implemented in subsequent patches. This patch was derived from a patch posted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00877.html. It was originally based on some work done by Luis Machado in 2013. IMPLEMENTATION ---------------- Exec events are enabled via ptrace options. When an exec event is detected by gdbserver, the existing process data, along with all its associated lwp and thread data, is deleted and replaced by data for a new single-threaded process. The new process data is initialized with the appropriate parts of the state of the execing process. This approach takes care of several potential pitfalls, including: * deleting the data for an execing non-leader thread before any wait/sigsuspend occurs * correctly initializing the architecture of the execed process We then report the exec event using a new RSP stop reason, "exec". When GDB receives an "exec" event, it saves the status in the event structure's target_waitstatus field, like what is done for remote fork events. Because the original and execed programs may have different architectures, we skip parsing the section of the stop reply packet that contains register data. The register data will be retrieved later after the inferior's architecture has been set up by infrun.c:follow_exec. At that point the exec event is handled by the existing event handling in GDB. However, a few changes were necessary so that infrun.c:follow_exec could accommodate the remote target. * Where follow-exec-mode "new" is handled, we now call add_inferior_with_spaces instead of add_inferior with separate calls to set up the program and address spaces. The motivation for this is that add_inferior_with_spaces also sets up the initial architecture for the inferior, which is needed later by target_find_description when it calls target_gdbarch. * We call a new target function, target_follow_exec. This function allows us to store the execd_pathname in the inferior, instead of using the static string remote_exec_file from remote.c. The static string didn't work for follow-exec-mode "new", since once you switched to the execed program, the original remote exec-file was lost. The execd_pathname is now stored in the inferior's program space as a REGISTRY field. All of the requisite mechanisms for this are defined in remote.c. And that is basically it. TESTING -------- x86_64 GNU/Linux for native, native-gdbserver, and native-extended-gdbserver targets. Most of the exec-related tests fail due to the lack of catchpoints and extended-remote support in the tests, both of which are resolved in subsequent patches in this patchset. gdb/gdbserver/ 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. gdb/ 2015-09-11 Don Breazeal <donb@codesourcery.com> Luis Machado <lgustavo@codesourcery.com> * infrun.c (follow_exec): Use process-style ptid for exec message. Call add_inferior_with_spaces and target_follow_exec. * nat/linux-ptrace.c (linux_supports_traceexec): New function. * nat/linux-ptrace.h (linux_supports_traceexec): Declare. * remote.c (remote_pspace_data): New static variable. (remote_pspace_data_cleanup): New function. (get_remote_exec_file): New function. (set_remote_exec_file_1): New function. (set_remote_exec_file): New function. (show_remote_exec_file): New function. (remote_exec_file): Delete static variable. (anonymous enum) <PACKET_exec_event_feature> New enumeration constant. (remote_protocol_features): Add entry for exec-events feature. (remote_query_supported): Add client side of qSupported query for exec-events feature. (remote_follow_exec): New function. (remote_parse_stop_reply): Handle 'exec' stop reason. (extended_remote_run, extended_remote_create_inferior): Call get_remote_exec_file and set_remote_exec_file_1. (init_extended_remote_ops) <to_follow_exec>: Initialize new member. (_initialize_remote): Call register_program_space_data_with_cleanup. Call add_packet_config_cmd for remote exec-events feature. Modify call to add_setshow_string_noescape_cmd for exec-file to use new functions set_remote_exec_file and show_remote_exec_file. * target-debug.h, target-delegates.c: Regenerated. * target.c (target_follow_exec): New function. * target.h (struct target_ops) <to_follow_exec>: New member. (target_follow_exec): Declare new function. --- gdb/gdbserver/linux-low.c | 147 +++++++++++++++++++++++++++++++++++------- gdb/gdbserver/lynx-low.c | 1 + gdb/gdbserver/remote-utils.c | 20 ++++++ gdb/gdbserver/server.c | 11 ++++ gdb/gdbserver/server.h | 1 + gdb/gdbserver/target.h | 7 ++ gdb/gdbserver/win32-low.c | 1 + gdb/infrun.c | 17 +++-- gdb/nat/linux-ptrace.c | 11 ++++ gdb/nat/linux-ptrace.h | 1 + gdb/remote.c | 148 ++++++++++++++++++++++++++++++++++++++++--- gdb/target-debug.h | 2 + gdb/target-delegates.c | 30 +++++++++ gdb/target.c | 8 +++ gdb/target.h | 7 ++ 15 files changed, 371 insertions(+), 41 deletions(-) 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 */ diff --git a/gdb/infrun.c b/gdb/infrun.c index e89e02a..84890b4 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1095,6 +1095,7 @@ follow_exec (ptid_t ptid, char *execd_pathname) struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); int pid = ptid_get_pid (ptid); + ptid_t process_ptid; /* This is an exec event that we actually wish to pay attention to. Refresh our symbol table to the newly exec'd program, remove any @@ -1161,8 +1162,9 @@ follow_exec (ptid_t ptid, char *execd_pathname) update_breakpoints_after_exec (); /* What is this a.out's name? */ + process_ptid = pid_to_ptid (pid); printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (inferior_ptid), + target_pid_to_str (process_ptid), execd_pathname); /* We've followed the inferior through an exec. Therefore, the @@ -1191,8 +1193,6 @@ follow_exec (ptid_t ptid, char *execd_pathname) if (follow_exec_mode_string == follow_exec_mode_new) { - struct program_space *pspace; - /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ @@ -1201,14 +1201,13 @@ follow_exec (ptid_t ptid, char *execd_pathname) the same ptid, which can confuse find_inferior_ptid. */ exit_inferior_num_silent (current_inferior ()->num); - inf = add_inferior (pid); - pspace = add_program_space (maybe_new_address_space ()); - inf->pspace = pspace; - inf->aspace = pspace->aspace; - add_thread (ptid); + inf = add_inferior_with_spaces (); + inf->pid = pid; + target_follow_exec (inf, execd_pathname); set_current_inferior (inf); - set_current_program_space (pspace); + set_current_program_space (inf->pspace); + add_thread (ptid); } else { diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index f097c8a..4222df5 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -538,6 +538,17 @@ linux_supports_tracefork (void) return ptrace_supports_feature (PTRACE_O_TRACEFORK); } +/* Returns non-zero if PTRACE_EVENT_EXEC is supported by ptrace, + 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is + PTRACE_EVENT_CLONE, PTRACE_EVENT_FORK and PTRACE_EVENT_VFORK, + since they were all added to the kernel at the same time. */ + +int +linux_supports_traceexec (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEEXEC); +} + /* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace, 0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h index 8bff908..1be38fe 100644 --- a/gdb/nat/linux-ptrace.h +++ b/gdb/nat/linux-ptrace.h @@ -168,6 +168,7 @@ extern void linux_check_ptrace_features (void); extern void linux_enable_event_reporting (pid_t pid, int attached); extern void linux_disable_event_reporting (pid_t pid); extern int linux_supports_tracefork (void); +extern int linux_supports_traceexec (void); extern int linux_supports_traceclone (void); extern int linux_supports_tracevforkdone (void); extern int linux_supports_tracesysgood (void); diff --git a/gdb/remote.c b/gdb/remote.c index e4d3edf..59004f9 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -75,6 +75,15 @@ static char *target_buf; static long target_buf_size; +/* Per-program-space data key. */ +static const struct program_space_data *remote_pspace_data; + +/* The variable registered as the control variable used by the + remote exec-file commands. While the remote exec-file setting is + per-program-space, the set/show machinery uses this as the + location of the remote exec-file value. */ +static char *remote_exec_file_var; + /* The size to align memory write packets, when practical. The protocol does not guarantee any alignment, and gdb will generate short writes and unaligned writes, but even as a best-effort attempt this @@ -619,6 +628,63 @@ get_remote_state (void) return get_remote_state_raw (); } +/* Cleanup routine for the remote module's pspace data. */ + +static void +remote_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + char *remote_exec_file = arg; + + xfree (remote_exec_file); +} + +/* Fetch the remote exec-file from the current program space. */ + +static const char * +get_remote_exec_file (void) +{ + char *remote_exec_file; + + remote_exec_file = program_space_data (current_program_space, + remote_pspace_data); + if (remote_exec_file == NULL) + return ""; + + return remote_exec_file; +} + +/* Set the remote exec file for PSPACE. */ + +static void +set_pspace_remote_exec_file (struct program_space *pspace, + char *remote_exec_file) +{ + char *old_file = program_space_data (pspace, remote_pspace_data); + + xfree (old_file); + set_program_space_data (pspace, remote_pspace_data, + xstrdup (remote_exec_file)); +} + +/* The "set/show remote exec-file" set command hook. */ + +static void +set_remote_exec_file (char *ignored, int from_tty, + struct cmd_list_element *c) +{ + gdb_assert (remote_exec_file_var != NULL); + set_pspace_remote_exec_file (current_program_space, remote_exec_file_var); +} + +/* The "set/show remote exec-file" show command hook. */ + +static void +show_remote_exec_file (struct ui_file *file, int from_tty, + struct cmd_list_element *cmd, const char *value) +{ + fprintf_filtered (file, "%s\n", remote_exec_file_var); +} + static int compare_pnums (const void *lhs_, const void *rhs_) { @@ -901,10 +967,6 @@ static unsigned int remote_address_size; static int remote_async_terminal_ours_p; -/* The executable file to use for "run" on the remote side. */ - -static char *remote_exec_file = ""; - \f /* User configurable variables for the number of characters in a memory read/write packet. MIN (rsa->remote_packet_size, @@ -1401,6 +1463,9 @@ enum { /* Support for the Qbtrace-conf:pt:size packet. */ PACKET_Qbtrace_conf_pt_size, + /* Support for exec events. */ + PACKET_exec_event_feature, + PACKET_MAX }; @@ -4279,6 +4344,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_fork_event_feature }, { "vfork-events", PACKET_DISABLE, remote_supported_packet, PACKET_vfork_event_feature }, + { "exec-events", PACKET_DISABLE, remote_supported_packet, + PACKET_exec_event_feature }, { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_conf_pt_size } }; @@ -4368,6 +4435,9 @@ remote_query_supported (void) if (packet_set_cmd_state (PACKET_vfork_event_feature) != AUTO_BOOLEAN_FALSE) q = remote_query_supported_append (q, "vfork-events+"); + if (packet_set_cmd_state (PACKET_exec_event_feature) + != AUTO_BOOLEAN_FALSE) + q = remote_query_supported_append (q, "exec-events+"); } q = reconcat (q, "qSupported:", q, (char *) NULL); @@ -4779,6 +4849,24 @@ remote_follow_fork (struct target_ops *ops, int follow_child, return 0; } +/* Target follow-exec function for remote targets. Save EXECD_PATHNAME + in the program space of the new inferior. On entry and at return the + current inferior is the exec'ing inferior. INF is the new exec'd + inferior, which may be the same as the exec'ing inferior unless + follow-exec-mode is "new". */ + +static void +remote_follow_exec (struct target_ops *ops, + struct inferior *inf, char *execd_pathname) +{ + /* We know that this is a target file name, so if it has the "target:" + prefix we strip it off before saving it in the program space. */ + if (is_target_filename (execd_pathname)) + execd_pathname += strlen (TARGET_SYSROOT_PREFIX); + + set_pspace_remote_exec_file (inf->pspace, execd_pathname); +} + /* Same as remote_detach, but don't send the "D" packet; just disconnect. */ static void @@ -5977,6 +6065,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event) struct remote_arch_state *rsa = get_remote_arch_state (); ULONGEST addr; char *p; + int skipregs = 0; event->ptid = null_ptid; event->rs = get_remote_state (); @@ -6089,11 +6178,42 @@ Packet: '%s'\n"), event->ws.kind = TARGET_WAITKIND_VFORK_DONE; p = skip_to_semicolon (p1 + 1); } + else if (strncmp (p, "exec", p1 - p) == 0) + { + ULONGEST ignored; + char pathname[PATH_MAX]; + int pathlen; + + /* Determine the length of the execd pathname. */ + p = unpack_varlen_hex (++p1, &ignored); + pathlen = (p - p1) / 2; + + /* Save the pathname for event reporting and for + the next run command. */ + hex2bin (p1, (gdb_byte *) pathname, pathlen); + pathname[pathlen] = '\0'; + + /* This is freed during event handling. */ + event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.kind = TARGET_WAITKIND_EXECD; + + /* Skip the registers included in this packet, since + they may be for an architecture different from the + one used by the original program. */ + skipregs = 1; + } else { ULONGEST pnum; char *p_temp; + if (skipregs) + { + p = skip_to_semicolon (p1 + 1); + p++; + continue; + } + /* Maybe a real ``P'' register number. */ p_temp = unpack_varlen_hex (p, &pnum); /* If the first invalid character is the colon, we got a @@ -8593,6 +8713,7 @@ extended_remote_run (char *args) { struct remote_state *rs = get_remote_state (); int len; + const char *remote_exec_file = get_remote_exec_file (); /* If the user has disabled vRun support, or we have detected that support is not available, do not try it. */ @@ -8665,6 +8786,7 @@ extended_remote_create_inferior (struct target_ops *ops, int run_worked; char *stop_reply; struct remote_state *rs = get_remote_state (); + const char *remote_exec_file = get_remote_exec_file (); /* If running asynchronously, register the target file descriptor with the event loop. */ @@ -12662,6 +12784,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; extended_remote_ops.to_supports_disable_randomization = extended_remote_supports_disable_randomization; extended_remote_ops.to_follow_fork = remote_follow_fork; + extended_remote_ops.to_follow_exec = remote_follow_exec; extended_remote_ops.to_insert_fork_catchpoint = remote_insert_fork_catchpoint; extended_remote_ops.to_remove_fork_catchpoint @@ -12893,6 +13016,10 @@ _initialize_remote (void) remote_g_packet_data_handle = gdbarch_data_register_pre_init (remote_g_packet_data_init); + remote_pspace_data + = register_program_space_data_with_cleanup (NULL, + remote_pspace_data_cleanup); + /* Initialize the per-target state. At the moment there is only one of these, not one per target. Only one target is active at a time. */ @@ -13272,6 +13399,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size], "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature], + "exec-event-feature", "exec-event-feature", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { @@ -13340,12 +13470,14 @@ Transfer files to and from the remote target system."), _("Delete a remote file."), &remote_cmdlist); - remote_exec_file = xstrdup (""); add_setshow_string_noescape_cmd ("exec-file", class_files, - &remote_exec_file, _("\ + &remote_exec_file_var, _("\ Set the remote pathname for \"run\""), _("\ -Show the remote pathname for \"run\""), NULL, NULL, NULL, - &remote_set_cmdlist, &remote_show_cmdlist); +Show the remote pathname for \"run\""), NULL, + set_remote_exec_file, + show_remote_exec_file, + &remote_set_cmdlist, + &remote_show_cmdlist); add_setshow_boolean_cmd ("range-stepping", class_run, &use_range_stepping, _("\ diff --git a/gdb/target-debug.h b/gdb/target-debug.h index ddbdfd1..470d6f3 100644 --- a/gdb/target-debug.h +++ b/gdb/target-debug.h @@ -156,6 +156,8 @@ target_debug_do_print (plongest (X)) #define target_debug_print_enum_bptype(X) \ target_debug_do_print (plongest (X)) +#define target_debug_print_struct_inferior_p(X) \ + target_debug_do_print (host_address_to_string (X)) static void target_debug_print_struct_target_waitstatus_p (struct target_waitstatus *status) diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c index 8d51b6c..87197f8 100644 --- a/gdb/target-delegates.c +++ b/gdb/target-delegates.c @@ -1208,6 +1208,32 @@ debug_remove_exec_catchpoint (struct target_ops *self, int arg1) return result; } +static void +delegate_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ + self = self->beneath; + self->to_follow_exec (self, arg1, arg2); +} + +static void +tdefault_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ +} + +static void +debug_follow_exec (struct target_ops *self, struct inferior *arg1, char *arg2) +{ + fprintf_unfiltered (gdb_stdlog, "-> %s->to_follow_exec (...)\n", debug_target.to_shortname); + debug_target.to_follow_exec (&debug_target, arg1, arg2); + fprintf_unfiltered (gdb_stdlog, "<- %s->to_follow_exec (", debug_target.to_shortname); + target_debug_print_struct_target_ops_p (&debug_target); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_struct_inferior_p (arg1); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_char_p (arg2); + fputs_unfiltered (")\n", gdb_stdlog); +} + static int delegate_set_syscall_catchpoint (struct target_ops *self, int arg1, int arg2, int arg3, int arg4, int *arg5) { @@ -4032,6 +4058,8 @@ install_delegators (struct target_ops *ops) ops->to_insert_exec_catchpoint = delegate_insert_exec_catchpoint; if (ops->to_remove_exec_catchpoint == NULL) ops->to_remove_exec_catchpoint = delegate_remove_exec_catchpoint; + if (ops->to_follow_exec == NULL) + ops->to_follow_exec = delegate_follow_exec; if (ops->to_set_syscall_catchpoint == NULL) ops->to_set_syscall_catchpoint = delegate_set_syscall_catchpoint; if (ops->to_has_exited == NULL) @@ -4285,6 +4313,7 @@ install_dummy_methods (struct target_ops *ops) ops->to_follow_fork = default_follow_fork; ops->to_insert_exec_catchpoint = tdefault_insert_exec_catchpoint; ops->to_remove_exec_catchpoint = tdefault_remove_exec_catchpoint; + ops->to_follow_exec = tdefault_follow_exec; ops->to_set_syscall_catchpoint = tdefault_set_syscall_catchpoint; ops->to_has_exited = tdefault_has_exited; ops->to_mourn_inferior = default_mourn_inferior; @@ -4436,6 +4465,7 @@ init_debug_target (struct target_ops *ops) ops->to_follow_fork = debug_follow_fork; ops->to_insert_exec_catchpoint = debug_insert_exec_catchpoint; ops->to_remove_exec_catchpoint = debug_remove_exec_catchpoint; + ops->to_follow_exec = debug_follow_exec; ops->to_set_syscall_catchpoint = debug_set_syscall_catchpoint; ops->to_has_exited = debug_has_exited; ops->to_mourn_inferior = debug_mourn_inferior; diff --git a/gdb/target.c b/gdb/target.c index 3da984e..f425fbc 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2304,6 +2304,14 @@ target_follow_fork (int follow_child, int detach_fork) follow_child, detach_fork); } +/* Target wrapper for follow exec hook. */ + +void +target_follow_exec (struct inferior *inf, char *execd_pathname) +{ + current_target.to_follow_exec (¤t_target, inf, execd_pathname); +} + static void default_mourn_inferior (struct target_ops *self) { diff --git a/gdb/target.h b/gdb/target.h index da18f99..5f05b56 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -596,6 +596,8 @@ struct target_ops TARGET_DEFAULT_RETURN (1); int (*to_remove_exec_catchpoint) (struct target_ops *, int) TARGET_DEFAULT_RETURN (1); + void (*to_follow_exec) (struct target_ops *, struct inferior *, char *) + TARGET_DEFAULT_IGNORE (); int (*to_set_syscall_catchpoint) (struct target_ops *, int, int, int, int, int *) TARGET_DEFAULT_RETURN (1); @@ -1577,6 +1579,11 @@ extern void target_load (const char *arg, int from_tty); int target_follow_fork (int follow_child, int detach_fork); +/* Handle the target-specific bookkeeping required when the inferior + makes an exec call. INF is the exec'd inferior. */ + +void target_follow_exec (struct inferior *inf, char *execd_pathname); + /* On some targets, we can catch an inferior exec event when it occurs. These functions insert/remove an already-created catchpoint for such events. They return 0 for success, 1 if the -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [pushed][PATCH v3 3/4] Extended-remote exec test 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal @ 2015-09-11 18:38 ` Don Breazeal 2015-09-15 15:45 ` Pedro Alves 2015-09-11 18:38 ` [pushed][PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal ` (4 subsequent siblings) 5 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-09-11 18:38 UTC (permalink / raw) To: gdb-patches Here is what I pushed. Thanks, --Don This patch updates several exec-related tests and some of the library functions in order to get them running with extended-remote. There were three changes that were required, as follows: In gdb.base/foll-exec.exp, use 'clean_start' in place of proc 'zap_session' to reset the state of the debugger between tests. This sets 'remote exec-file' to execute the correct binary file in each subsequent test. In gdb.base/pie-execl.exp, there is an expect statement with an expression that is used to match output from both gdb and the program under debug. For the remote target, this had to be split into two expressions, using $inferior_spawn_id to match the output from the program. Because I had encountered problems with extended-remote exec events in non-stop mode in my manual testing, I added non-stop testing to the non-ldr-exc-[1234].exp tests. In order to set non-stop mode for remote targets, it is necessary to 'set non-stop on' after gdb has started, but before it connects to gdbserver. This is done using 'save_vars' to set non-stop mode in GDBFLAGS, so GDB sets non-stop mode on startup. 2015-09-11 Don Breazeal <donb@codesourcery.com> * gdb.base/foll-exec.c: Add copyright header. Fix formatting issues. * gdb.base/foll-exec.exp (zap_session): Delete proc. (do_exec_tests): Use clean_restart in place of zap_session, and for test initialization. Fix formatting issues. Use fail in place of perror. * gdb.base/pie-execl.exp (main): Use 'inferior_spawn_id' in an expect statement to match an expression with output from the program under debug. * gdb.threads/non-ldr-exc-1.exp (do_test, main): Add non-stop tests and pass stop mode argument to clean_restart. Use save_vars to enable non-stop in GDBFLAGS. * gdb.threads/non-ldr-exc-2.exp: Likewise. * gdb.threads/non-ldr-exc-3.exp: Likewise. * gdb.threads/non-ldr-exc-4.exp: Likewise. --- gdb/testsuite/gdb.base/foll-exec.c | 44 ++++++++++++------- gdb/testsuite/gdb.base/foll-exec.exp | 65 +++++++---------------------- gdb/testsuite/gdb.base/foll-vfork.exp | 29 ++++++------- gdb/testsuite/gdb.base/pie-execl.exp | 24 ++++++++++- gdb/testsuite/gdb.threads/non-ldr-exc-1.exp | 24 ++++++++--- gdb/testsuite/gdb.threads/non-ldr-exc-2.exp | 24 ++++++++--- gdb/testsuite/gdb.threads/non-ldr-exc-3.exp | 30 ++++++++++--- gdb/testsuite/gdb.threads/non-ldr-exc-4.exp | 24 ++++++++--- 8 files changed, 161 insertions(+), 103 deletions(-) diff --git a/gdb/testsuite/gdb.base/foll-exec.c b/gdb/testsuite/gdb.base/foll-exec.c index 6e302bb..77287a4 100644 --- a/gdb/testsuite/gdb.base/foll-exec.c +++ b/gdb/testsuite/gdb.base/foll-exec.c @@ -1,36 +1,52 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 1997-2015 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> - -int global_i = 100; +int global_i = 100; int main (void) { - int local_j = global_i+1; - int local_k = local_j+1; + int local_j = global_i + 1; + int local_k = local_j + 1; printf ("foll-exec is about to execlp(execd-prog)...\n"); execlp (BASEDIR "/execd-prog", - BASEDIR "/execd-prog", - "execlp arg1 from foll-exec", - (char *)0); + BASEDIR "/execd-prog", + "execlp arg1 from foll-exec", + (char *) 0); printf ("foll-exec is about to execl(execd-prog)...\n"); execl (BASEDIR "/execd-prog", /* tbreak-execl */ - BASEDIR "/execd-prog", - "execl arg1 from foll-exec", - "execl arg2 from foll-exec", - (char *)0); + BASEDIR "/execd-prog", + "execl arg1 from foll-exec", + "execl arg2 from foll-exec", + (char *) 0); { static char * argv[] = { - (char *)BASEDIR "/execd-prog", - (char *)"execv arg1 from foll-exec", - (char *)0}; + (char *) BASEDIR "/execd-prog", + (char *) "execv arg1 from foll-exec", + (char *) 0}; printf ("foll-exec is about to execv(execd-prog)...\n"); diff --git a/gdb/testsuite/gdb.base/foll-exec.exp b/gdb/testsuite/gdb.base/foll-exec.exp index 5bea3ba..0a6347c 100644 --- a/gdb/testsuite/gdb.base/foll-exec.exp +++ b/gdb/testsuite/gdb.base/foll-exec.exp @@ -13,6 +13,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +# This is a test of gdb's ability to follow a process through a +# Unix exec() system call. + if { [is_remote target] || ![isnative] } then { continue } @@ -44,44 +47,14 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $com return -1 } -proc zap_session {} { - global gdb_prompt - global binfile - - send_gdb "kill\n" - gdb_expect { - -re ".*Kill the program being debugged.*y or n. $" { - gdb_test_no_output "y" "" - send_gdb "file $binfile\n" - gdb_expect { - -re ".*Load new symbol table from.*y or n. $" { - send_gdb "y\n" - gdb_expect { - -re "Reading symbols from.*$gdb_prompt $" {} - timeout { fail "loading symbols (timeout)"; return } - } - } - -re ".*gdb_prompt $" {} - timeout { fail "loading symbols (timeout)"; return } - } - } - -re ".*$gdb_prompt $" {} - timeout { fail "killing inferior (timeout)" ; return } - } -} - proc do_exec_tests {} { + global binfile srcfile srcfile2 testfile testfile2 global gdb_prompt - global binfile - global srcfile - global srcfile2 - global testfile - global testfile2 # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile}" + fail "Couldn't run ${testfile}" return } @@ -103,12 +76,12 @@ proc do_exec_tests {} { return } - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile}" + fail "Couldn't run ${testfile}" return } @@ -192,12 +165,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (2nd try)" + fail "Couldn't run ${testfile} (2nd try)" return } @@ -265,12 +238,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (3rd try)" + fail "Couldn't run ${testfile} (3rd try)" return } @@ -326,12 +299,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (4th try)" + fail "Couldn't run ${testfile} (4th try)" return } @@ -381,12 +354,12 @@ proc do_exec_tests {} { # Explicitly kill this program, or a subsequent rerun actually runs # the exec'd program, not the original program... - zap_session + clean_restart $binfile # Start the program running, and stop at main. # if ![runto_main] then { - perror "Couldn't run ${testfile} (5th try)" + fail "Couldn't run ${testfile} (5th try)" return } @@ -406,14 +379,8 @@ proc do_exec_tests {} { # Start with a fresh gdb gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} - +clean_restart $binfile -# This is a test of gdb's ability to follow a process through a -# Unix exec() system call. -# do_exec_tests return 0 diff --git a/gdb/testsuite/gdb.base/foll-vfork.exp b/gdb/testsuite/gdb.base/foll-vfork.exp index b94b7ea..78c5cc8 100644 --- a/gdb/testsuite/gdb.base/foll-vfork.exp +++ b/gdb/testsuite/gdb.base/foll-vfork.exp @@ -524,23 +524,18 @@ with_test_prefix "check vfork support" { check_vfork_catchpoints } -# There is no support for exec events in the RSP yet. -if { ![gdb_is_target_remote] } { - # Follow parent and follow child vfork tests with a child that execs. - with_test_prefix "exec" { - # These are tests of gdb's ability to follow the parent of a Unix - # vfork system call. The child will subsequently call a variant - # of the Unix exec system call. - do_vfork_and_follow_parent_tests - - # These are tests of gdb's ability to follow the child of a Unix - # vfork system call. The child will subsequently call a variant - # of a Unix exec system call. - # - do_vfork_and_follow_child_tests_exec - } -} else { - unsupported "vfork with exec: exec events not supported for remote" +# Follow parent and follow child vfork tests with a child that execs. +with_test_prefix "exec" { + # These are tests of gdb's ability to follow the parent of a Unix + # vfork system call. The child will subsequently call a variant + # of the Unix exec system call. + do_vfork_and_follow_parent_tests + + # These are tests of gdb's ability to follow the child of a Unix + # vfork system call. The child will subsequently call a variant + # of a Unix exec system call. + # + do_vfork_and_follow_child_tests_exec } # Switch to test the case of the child exiting. We can't use diff --git a/gdb/testsuite/gdb.base/pie-execl.exp b/gdb/testsuite/gdb.base/pie-execl.exp index 182f96f..51edc82 100644 --- a/gdb/testsuite/gdb.base/pie-execl.exp +++ b/gdb/testsuite/gdb.base/pie-execl.exp @@ -16,6 +16,9 @@ # The problem was due to amd64_skip_prologue attempting to access inferior # memory before the PIE (Position Independent Executable) gets relocated. +global inferior_spawn_id +global gdb_spawn_id + if ![istarget *-linux*] { continue } @@ -67,6 +70,7 @@ gdb_test_multiple "p/x &pie_execl_marker" $test { verbose -log "addr1 is $addr1" set test "continue" +set matches_found 0 gdb_test_multiple $test $test { -re "Error in re-setting breakpoint" { fail $test @@ -74,8 +78,24 @@ gdb_test_multiple $test $test { -re "Cannot access memory" { fail $test } - -re "pie-execl: re-exec.*executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { - pass $test + -i "$inferior_spawn_id" -re "pie-execl: re-exec" { + # output from inferior + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } + } + -i "$gdb_spawn_id" + -re "executing new program.*\r\nBreakpoint \[0-9\]+,\[^\r\n\]* pie_execl_marker .*\r\n$gdb_prompt $" { + # output from gdb + incr matches_found + if { $matches_found == 2 } { + pass $test + } else { + exp_continue + } } } diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp index 69e5cc6..d3a9601 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-1.exp @@ -28,11 +28,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched=$lock_sched,non-stop=$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 @@ -48,11 +51,22 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp index 9386153..8b170ec 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp @@ -29,11 +29,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched=$lock_sched,non-stop=$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 @@ -42,6 +45,10 @@ proc do_test { lock_sched } { gdb_breakpoint [gdb_get_line_number "break-here"] gdb_continue_to_breakpoint "break-here" ".* break-here .*" + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "info threads" \ "\r\n\[ \t\]*Id\[ \t\]+Target\[ \t\]+Id\[ \t\]+Frame\[ \t\]*\r\n\\* 2 *Thread \[^\r\n\]* at \[^\r\n\]*" \ "single thread left" @@ -59,5 +66,12 @@ proc do_test { lock_sched } { } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp index cc7da1a..3e7a3a1 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp @@ -31,18 +31,25 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched=$lock_sched,non-stop=$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_continue_to_breakpoint "break-here" ".* break-here .*" + gdb_test_multiple "continue" "continue to breakpoint" { + -re ".*Breakpoint.*break-here.*" { + pass "continue to breakpoint" + } + } # Also test with sched-lock to make sure we can follow the # non-leader thread execing even though the main thread wasn't @@ -51,11 +58,22 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp index a89b818..4d7e97a 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-4.exp @@ -30,11 +30,14 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -proc do_test { lock_sched } { - with_test_prefix "lock-sched$lock_sched" { +proc do_test { lock_sched nonstop } { + with_test_prefix "lock-sched=$lock_sched,non-stop=$nonstop" { global executable - clean_restart ${executable} + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $nonstop\"" + clean_restart ${executable} + } if ![runto_main] { return -1 @@ -50,11 +53,22 @@ proc do_test { lock_sched } { gdb_test_no_output "set scheduler-locking on" } + if { $nonstop == "on" } { + gdb_test "thread 2" "Switching.*" + } + gdb_test "continue" \ ".*is executing new program.*Breakpoint 1, main.* at .*" \ "continue over exec" } } -do_test 0 -do_test 1 +foreach nonstop {"on" "off"} { + foreach schedlock {"on" "off"} { + if {$schedlock == "on" && $nonstop == "on"} { + # Schedule locking has no effect in nonstop mode. + continue + } + do_test $schedlock $nonstop + } +} -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 3/4] Extended-remote exec test 2015-09-11 18:38 ` [pushed][PATCH v3 3/4] Extended-remote exec test Don Breazeal @ 2015-09-15 15:45 ` Pedro Alves 2015-09-15 15:53 ` Don Breazeal 0 siblings, 1 reply; 55+ messages in thread From: Pedro Alves @ 2015-09-15 15:45 UTC (permalink / raw) To: Don Breazeal, gdb-patches Hi Don, On 09/11/2015 07:38 PM, Don Breazeal wrote: > gdb_breakpoint [gdb_get_line_number "break-here"] > - gdb_continue_to_breakpoint "break-here" ".* break-here .*" > + gdb_test_multiple "continue" "continue to breakpoint" { > + -re ".*Breakpoint.*break-here.*" { > + pass "continue to breakpoint" > + } > + } > This change is causing a regression. Was there a reason for it? AFAICS, none of the other non-ldr-exc-*.exp files got this change. Fix below. From 5cd484be64e40d0423cc7fe8d8355421e4da1fff Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Tue, 15 Sep 2015 16:32:19 +0100 Subject: [PATCH] Fix gdb.threads/non-ldr-exc-3.exp race gdb.threads/non-ldr-exc-3.exp is sometimes failing like this: [Switching to Thread 6831.6832] Breakpoint 2, thread_execler (arg=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/testsuite/gdb.threads/non-ldr-exc-3.c:41 41 if (execl (image, image, argv1, NULL) == -1) /* break-here */ PASS: gdb.threads/non-ldr-exc-3.exp: lock-sched=on,non-stop=off: continue to breakpoint (gdb) set scheduler-locking on (gdb) FAIL: gdb.threads/non-ldr-exc-3.exp: lock-sched=on,non-stop=off: set scheduler-locking on The problem is that the gdb_test_multiple is missing the prompt anchor. The problem was introduced by 2fd33e9448. This reverts the hunk that introduced the problem, reverting back to gdb_continue_to_breakpoint. gdb/testsuite/ChangeLog: 2015-09-15 Pedro Alves <palves@redhat.com> * gdb.threads/non-ldr-exc-3.exp (do_test): Use gdb_continue_to_breakpoint instead of gdb_test_multiple. --- gdb/testsuite/gdb.threads/non-ldr-exc-3.exp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp index 3e7a3a1..188b825 100644 --- a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp @@ -45,11 +45,7 @@ proc do_test { lock_sched nonstop } { } gdb_breakpoint [gdb_get_line_number "break-here"] - gdb_test_multiple "continue" "continue to breakpoint" { - -re ".*Breakpoint.*break-here.*" { - pass "continue to breakpoint" - } - } + gdb_continue_to_breakpoint "break-here" ".* break-here .*" # Also test with sched-lock to make sure we can follow the # non-leader thread execing even though the main thread wasn't -- 1.9.3 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 3/4] Extended-remote exec test 2015-09-15 15:45 ` Pedro Alves @ 2015-09-15 15:53 ` Don Breazeal 2015-09-15 15:58 ` Pedro Alves 0 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-09-15 15:53 UTC (permalink / raw) To: Pedro Alves, Breazeal, Don, gdb-patches On 9/15/2015 8:45 AM, Pedro Alves wrote: > Hi Don, > > On 09/11/2015 07:38 PM, Don Breazeal wrote: >> gdb_breakpoint [gdb_get_line_number "break-here"] >> - gdb_continue_to_breakpoint "break-here" ".* break-here .*" >> + gdb_test_multiple "continue" "continue to breakpoint" { >> + -re ".*Breakpoint.*break-here.*" { >> + pass "continue to breakpoint" >> + } >> + } >> > > This change is causing a regression. Was there a reason for it? > AFAICS, none of the other non-ldr-exc-*.exp files got this change. No, I intended to revert that change, which I did for the other non-ldr-exc-* files. You had pointed out that the change introduced a race. > > Fix below. > > From 5cd484be64e40d0423cc7fe8d8355421e4da1fff Mon Sep 17 00:00:00 2001 > From: Pedro Alves <palves@redhat.com> > Date: Tue, 15 Sep 2015 16:32:19 +0100 > Subject: [PATCH] Fix gdb.threads/non-ldr-exc-3.exp race > > gdb.threads/non-ldr-exc-3.exp is sometimes failing like this: > > [Switching to Thread 6831.6832] > > Breakpoint 2, thread_execler (arg=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/testsuite/gdb.threads/non-ldr-exc-3.c:41 > 41 if (execl (image, image, argv1, NULL) == -1) /* break-here */ > PASS: gdb.threads/non-ldr-exc-3.exp: lock-sched=on,non-stop=off: continue to breakpoint > (gdb) set scheduler-locking on > (gdb) FAIL: gdb.threads/non-ldr-exc-3.exp: lock-sched=on,non-stop=off: set scheduler-locking on > > The problem is that the gdb_test_multiple is missing the prompt > anchor. The problem was introduced by 2fd33e9448. This reverts the > hunk that introduced the problem, reverting back to > gdb_continue_to_breakpoint. > > gdb/testsuite/ChangeLog: > 2015-09-15 Pedro Alves <palves@redhat.com> > > * gdb.threads/non-ldr-exc-3.exp (do_test): Use > gdb_continue_to_breakpoint instead of gdb_test_multiple. > --- > gdb/testsuite/gdb.threads/non-ldr-exc-3.exp | 6 +----- > 1 file changed, 1 insertion(+), 5 deletions(-) > > diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp > index 3e7a3a1..188b825 100644 > --- a/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp > +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-3.exp > @@ -45,11 +45,7 @@ proc do_test { lock_sched nonstop } { > } > > gdb_breakpoint [gdb_get_line_number "break-here"] > - gdb_test_multiple "continue" "continue to breakpoint" { > - -re ".*Breakpoint.*break-here.*" { > - pass "continue to breakpoint" > - } > - } > + gdb_continue_to_breakpoint "break-here" ".* break-here .*" > > # Also test with sched-lock to make sure we can follow the > # non-leader thread execing even though the main thread wasn't > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 3/4] Extended-remote exec test 2015-09-15 15:53 ` Don Breazeal @ 2015-09-15 15:58 ` Pedro Alves 2015-09-15 16:00 ` Breazeal, Don 0 siblings, 1 reply; 55+ messages in thread From: Pedro Alves @ 2015-09-15 15:58 UTC (permalink / raw) To: Don Breazeal, Breazeal, Don, gdb-patches On 09/15/2015 04:53 PM, Don Breazeal wrote: > On 9/15/2015 8:45 AM, Pedro Alves wrote: >> This change is causing a regression. Was there a reason for it? >> AFAICS, none of the other non-ldr-exc-*.exp files got this change. > > No, I intended to revert that change, which I did for the other > non-ldr-exc-* files. You had pointed out that the change introduced > a race. Eh, indeed I did. :-) Alright, I'll push it in in a bit. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [pushed][PATCH v3 3/4] Extended-remote exec test 2015-09-15 15:58 ` Pedro Alves @ 2015-09-15 16:00 ` Breazeal, Don 2015-09-15 16:28 ` Pedro Alves 0 siblings, 1 reply; 55+ messages in thread From: Breazeal, Don @ 2015-09-15 16:00 UTC (permalink / raw) To: Pedro Alves, gdb-patches > -----Original Message----- > From: Pedro Alves [mailto:palves@redhat.com] > Sent: Tuesday, September 15, 2015 8:59 AM > To: Breazeal, Don; Breazeal, Don; gdb-patches@sourceware.org > Subject: Re: [pushed][PATCH v3 3/4] Extended-remote exec test > > On 09/15/2015 04:53 PM, Don Breazeal wrote: > > On 9/15/2015 8:45 AM, Pedro Alves wrote: > > >> This change is causing a regression. Was there a reason for it? > >> AFAICS, none of the other non-ldr-exc-*.exp files got this change. > > > > No, I intended to revert that change, which I did for the other > > non-ldr-exc-* files. You had pointed out that the change introduced > a > > race. > > Eh, indeed I did. :-) Alright, I'll push it in in a bit. > > Thanks, > Pedro Alves Thanks Pedro. Sorry to have caused a "clean up after Don" day. :-{ ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 3/4] Extended-remote exec test 2015-09-15 16:00 ` Breazeal, Don @ 2015-09-15 16:28 ` Pedro Alves 0 siblings, 0 replies; 55+ messages in thread From: Pedro Alves @ 2015-09-15 16:28 UTC (permalink / raw) To: Breazeal, Don, gdb-patches On 09/15/2015 05:00 PM, Breazeal, Don wrote: > Thanks Pedro. Sorry to have caused a "clean up after Don" day. :-{ No worries. :-) Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* [pushed][PATCH v3 2/4] Extended-remote exec catchpoints 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal 2015-09-11 18:38 ` [pushed][PATCH v3 3/4] Extended-remote exec test Don Breazeal @ 2015-09-11 18:38 ` Don Breazeal 2015-09-11 18:39 ` [pushed][PATCH v3 4/4] Extended-remote exec event docs Don Breazeal ` (3 subsequent siblings) 5 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-11 18:38 UTC (permalink / raw) To: gdb-patches Here is what I pushed. Thanks, --Don This patch implements exec catchpoints for extended-remote Linux targets. The implementation follows the same approach used for fork catchpoints, implementing extended-remote target routines for inserting and removing the catchpoints by just checking if exec events are supported. Existing host-side code and previous support for extended-remote exec events takes care of the rest. Tested on x86_64 GNU/Linux with native, native-gdbserver, and native-extended-gdbserver targets. gdb/ 2015-09-11 Don Breazeal <donb@codesourcery.com> * remote.c (remote_exec_event_p): New function. (remote_insert_exec_catchpoint): New function. (remote_remove_exec_catchpoint): New function. (init_extended_remote_ops): Initialize extended_remote_ops members to_insert_exec_catchpoint and to_remove_exec_catchpoint. --- gdb/remote.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/gdb/remote.c b/gdb/remote.c index 59004f9..db83e6b 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1596,6 +1596,14 @@ remote_vfork_event_p (struct remote_state *rs) return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE; } +/* Returns true if exec events are supported. */ + +static int +remote_exec_event_p (struct remote_state *rs) +{ + return packet_support (PACKET_exec_event_feature) == PACKET_ENABLE; +} + /* Insert fork catchpoint target routine. If fork events are enabled then return success, nothing more to do. */ @@ -1636,6 +1644,26 @@ remote_remove_vfork_catchpoint (struct target_ops *ops, int pid) return 0; } +/* Insert exec catchpoint target routine. If exec events are + enabled, just return success. */ + +static int +remote_insert_exec_catchpoint (struct target_ops *ops, int pid) +{ + struct remote_state *rs = get_remote_state (); + + return !remote_exec_event_p (rs); +} + +/* Remove exec catchpoint target routine. Nothing to do, just + return success. */ + +static int +remote_remove_exec_catchpoint (struct target_ops *ops, int pid) +{ + return 0; +} + /* Tokens for use by the asynchronous signal handlers for SIGINT. */ static struct async_signal_handler *async_sigint_remote_twice_token; static struct async_signal_handler *async_sigint_remote_token; @@ -12793,6 +12821,10 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; = remote_insert_vfork_catchpoint; extended_remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint; + extended_remote_ops.to_insert_exec_catchpoint + = remote_insert_exec_catchpoint; + extended_remote_ops.to_remove_exec_catchpoint + = remote_remove_exec_catchpoint; } static int -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [pushed][PATCH v3 4/4] Extended-remote exec event docs 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal 2015-09-11 18:38 ` [pushed][PATCH v3 3/4] Extended-remote exec test Don Breazeal 2015-09-11 18:38 ` [pushed][PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal @ 2015-09-11 18:39 ` Don Breazeal 2015-09-15 8:56 ` [pushed][PATCH v3 1/4] Extended-remote follow exec Yao Qi ` (2 subsequent siblings) 5 siblings, 0 replies; 55+ messages in thread From: Don Breazeal @ 2015-09-11 18:39 UTC (permalink / raw) To: gdb-patches Here is what I pushed. Thanks, --Don This patch adds documentation of support for exec events on extended-remote Linux targets. gdb/ 2015-09-11 Don Breazeal <donb@codesourcery.com> * NEWS: Announce new remote packets for the exec-events feature and the exec-events feature and associated commands. gdb/doc/ 2015-09-11 Don Breazeal <donb@codesourcery.com> * gdb.texinfo (Remote Configuration): Add exec event feature to table of packet settings. (Stop Reply Packets): Add exec events to the list of stop reasons. (General Query Packets): Add exec events to tables of 'gdbfeatures' and 'stub features' supported in the qSupported packet, as well as to the list containing stub feature details. --- gdb/NEWS | 21 +++++++++++++++++++++ gdb/doc/gdb.texinfo | 30 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index 0cf51e1..bb1c8d9 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -55,6 +55,27 @@ show remote multiprocess-extensions-packet * Support for reading/writing memory and extracting values on architectures whose memory is addressable in units of any integral multiple of 8 bits. +* New remote packets + +exec stop reason + Indicates that an exec system call was executed. + +exec-events feature in qSupported + The qSupported packet allows GDB to request support for exec + events using the new 'gdbfeature' exec-event, and the qSupported + response can contain the corresponding 'stubfeature'. Set and + show commands can be used to display whether these features are enabled. + +* Extended-remote exec events + + ** GDB now has support for exec events on extended-remote Linux targets. + For such targets with Linux kernels 2.5.46 and later, this enables + follow-exec-mode and exec catchpoints. + +set remote exec-event-feature-packet +show remote exec-event-feature-packet + Set/show the use of the remote exec event feature. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index cd0abad..395f0d4 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20225,6 +20225,10 @@ are: @tab @code{vfork stop reason} @tab @code{vfork} +@item @code{exec-event-feature} +@tab @code{exec stop reason} +@tab @code{exec} + @end multitable @node Remote Stub @@ -35506,6 +35510,18 @@ appropriate @samp{qSupported} feature (@pxref{qSupported}). The remote stub must also supply the appropriate @samp{qSupported} feature indicating support. +@cindex exec events, remote reply +@item exec +The packet indicates that @code{execve} was called, and @var{r} +is the absolute pathname of the file that was executed, in hex. +This packet is only applicable to targets that support exec events. + +This packet should not be sent by default; older @value{GDBN} versions +did not support it. @value{GDBN} requests it, by supplying an +appropriate @samp{qSupported} feature (@pxref{qSupported}). The +remote stub must also supply the appropriate @samp{qSupported} feature +indicating support. + @end table @item W @var{AA} @@ -36110,6 +36126,12 @@ This feature indicates whether @value{GDBN} supports vfork event extensions to the remote protocol. @value{GDBN} does not use such extensions unless the stub also reports that it supports them by including @samp{vfork-events+} in its @samp{qSupported} reply. + +@item exec-events +This feature indicates whether @value{GDBN} supports exec event +extensions to the remote protocol. @value{GDBN} does not use such +extensions unless the stub also reports that it supports them by +including @samp{exec-events+} in its @samp{qSupported} reply. @end table Stubs should ignore any unknown values for @@ -36373,6 +36395,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab No +@item @samp{exec-events} +@tab No +@tab @samp{-} +@tab No + @end multitable These are the currently defined stub features, in more detail: @@ -36578,6 +36605,9 @@ The remote stub reports the @samp{fork} stop reason for fork events. The remote stub reports the @samp{vfork} stop reason for vfork events and vforkdone events. +@item exec-events +The remote stub reports the @samp{exec} stop reason for exec events. + @end table @item qSymbol:: -- 1.8.1.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal ` (2 preceding siblings ...) 2015-09-11 18:39 ` [pushed][PATCH v3 4/4] Extended-remote exec event docs Don Breazeal @ 2015-09-15 8:56 ` Yao Qi 2015-09-15 16:12 ` Don Breazeal 2015-09-30 16:20 ` Pedro Alves 2016-12-08 11:54 ` Thomas Schwinge 5 siblings, 1 reply; 55+ messages in thread From: Yao Qi @ 2015-09-15 8:56 UTC (permalink / raw) To: Don Breazeal; +Cc: gdb-patches Don Breazeal <donb@codesourcery.com> writes: Hi Don, I happen to read the code you pushed in some days ago... > @@ -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) Shouldn't we use "else if"? > + { > + /* GDB supports and wants exec events if possible. */ > + if (target_supports_exec_events ()) > + report_exec_events = 1; > + } > else > target_process_qsupported (p); -- Yao (齐尧) From bb592f4d75544fda59a290cadf46bd33067220fc Mon Sep 17 00:00:00 2001 From: Yao Qi <yao.qi@linaro.org> Date: Tue, 15 Sep 2015 09:52:11 +0100 Subject: [PATCH] Fix typo gdb/gdbserver: 2015-09-15 Yao Qi <yao.qi@linaro.org> * server.c (handle_query): Check string comparison using "else if" instead of "if". diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 1481c47..c82c232 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -2112,7 +2112,7 @@ 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) + else if (strcmp (p, "exec-events+") == 0) { /* GDB supports and wants exec events if possible. */ if (target_supports_exec_events ()) ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-15 8:56 ` [pushed][PATCH v3 1/4] Extended-remote follow exec Yao Qi @ 2015-09-15 16:12 ` Don Breazeal 2015-09-15 16:31 ` Yao Qi 0 siblings, 1 reply; 55+ messages in thread From: Don Breazeal @ 2015-09-15 16:12 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches On 9/15/2015 1:56 AM, Yao Qi wrote: > Don Breazeal <donb@codesourcery.com> writes: > > Hi Don, > I happen to read the code you pushed in some days ago... > >> @@ -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) > > Shouldn't we use "else if"? Hi Yao, Yes, definitely "else if". Fortunately this didn't break anything. Do you want to go ahead and push the fix, or shall I do it? thanks --Don > >> + { >> + /* GDB supports and wants exec events if possible. */ >> + if (target_supports_exec_events ()) >> + report_exec_events = 1; >> + } >> else >> target_process_qsupported (p); > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-15 16:12 ` Don Breazeal @ 2015-09-15 16:31 ` Yao Qi 0 siblings, 0 replies; 55+ messages in thread From: Yao Qi @ 2015-09-15 16:31 UTC (permalink / raw) To: Don Breazeal; +Cc: Yao Qi, gdb-patches Don Breazeal <donb@codesourcery.com> writes: > Yes, definitely "else if". Fortunately this didn't break anything. Do > you want to go ahead and push the fix, or shall I do it? I've pushed it in. -- Yao (齐尧) ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal ` (3 preceding siblings ...) 2015-09-15 8:56 ` [pushed][PATCH v3 1/4] Extended-remote follow exec Yao Qi @ 2015-09-30 16:20 ` Pedro Alves 2015-09-30 16:22 ` Breazeal, Don 2016-12-08 11:54 ` Thomas Schwinge 5 siblings, 1 reply; 55+ messages in thread From: Pedro Alves @ 2015-09-30 16:20 UTC (permalink / raw) To: Don Breazeal, gdb-patches Hi Don, On 09/11/2015 07:38 PM, Don Breazeal wrote: > @@ -5977,6 +6065,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event) > struct remote_arch_state *rsa = get_remote_arch_state (); > ULONGEST addr; > char *p; > + int skipregs = 0; > > event->ptid = null_ptid; > event->rs = get_remote_state (); > @@ -6089,11 +6178,42 @@ Packet: '%s'\n"), > event->ws.kind = TARGET_WAITKIND_VFORK_DONE; > p = skip_to_semicolon (p1 + 1); > } > + else if (strncmp (p, "exec", p1 - p) == 0) > + { I happened to notice that this is still using strncmp while the rest of the magic registers are now using strprefix instead (26d56a939e). Looks like a mid-air collision happened. This one could be adjusted to use strprefix too, right? Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* RE: [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-30 16:20 ` Pedro Alves @ 2015-09-30 16:22 ` Breazeal, Don 0 siblings, 0 replies; 55+ messages in thread From: Breazeal, Don @ 2015-09-30 16:22 UTC (permalink / raw) To: Pedro Alves, gdb-patches > -----Original Message----- > From: Pedro Alves [mailto:palves@redhat.com] > Sent: Wednesday, September 30, 2015 9:20 AM > To: Breazeal, Don; gdb-patches@sourceware.org > Subject: Re: [pushed][PATCH v3 1/4] Extended-remote follow exec > > Hi Don, > > On 09/11/2015 07:38 PM, Don Breazeal wrote: > > @@ -5977,6 +6065,7 @@ remote_parse_stop_reply (char *buf, struct > stop_reply *event) > > struct remote_arch_state *rsa = get_remote_arch_state (); > > ULONGEST addr; > > char *p; > > + int skipregs = 0; > > > > event->ptid = null_ptid; > > event->rs = get_remote_state (); > > @@ -6089,11 +6178,42 @@ Packet: '%s'\n"), > > event->ws.kind = TARGET_WAITKIND_VFORK_DONE; > > p = skip_to_semicolon (p1 + 1); > > } > > + else if (strncmp (p, "exec", p1 - p) == 0) > > + { > > I happened to notice that this is still using strncmp while the rest > of the magic registers are now using strprefix instead (26d56a939e). > Looks like a mid-air collision happened. > This one could be adjusted to use strprefix too, right? Absolutely, thanks for pointing it out. I will take care of that today. --Don ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal ` (4 preceding siblings ...) 2015-09-30 16:20 ` Pedro Alves @ 2016-12-08 11:54 ` Thomas Schwinge 2017-02-17 16:45 ` Pedro Alves 5 siblings, 1 reply; 55+ messages in thread From: Thomas Schwinge @ 2016-12-08 11:54 UTC (permalink / raw) To: Don Breazeal, gdb-patches Cc: bug-hurd, 834575, 834575-forwarded, svante.signell Hi! On Fri, 11 Sep 2015 11:38:15 -0700, Don Breazeal <donb@codesourcery.com> wrote: > Here is what I pushed. > --- a/gdb/remote.c > +++ b/gdb/remote.c > @@ -6089,11 +6178,42 @@ Packet: '%s'\n"), > event->ws.kind = TARGET_WAITKIND_VFORK_DONE; > p = skip_to_semicolon (p1 + 1); > } > + else if (strncmp (p, "exec", p1 - p) == 0) > + { > + ULONGEST ignored; > + char pathname[PATH_MAX]; > + int pathlen; > + > + /* Determine the length of the execd pathname. */ > + p = unpack_varlen_hex (++p1, &ignored); > + pathlen = (p - p1) / 2; > + > + /* Save the pathname for event reporting and for > + the next run command. */ > + hex2bin (p1, (gdb_byte *) pathname, pathlen); > + pathname[pathlen] = '\0'; > + > + /* This is freed during event handling. */ > + event->ws.value.execd_pathname = xstrdup (pathname); > + event->ws.kind = TARGET_WAITKIND_EXECD; > + > + /* Skip the registers included in this packet, since > + they may be for an architecture different from the > + one used by the original program. */ > + skipregs = 1; > + } On GNU/Hurd, there is no "#define PATH_MAX", so this fails to build. (I'm aware that there is other PATH_MAX usage in GDB sources, which we ought to fix at some point, for example in gdbserver -- which is not yet enabled for GNU/Hurd.) OK to push the following? (Similar to Svante's patch in <https://bugs.debian.org/834575>.) --- gdb/remote.c +++ gdb/remote.c @@ -6927,7 +6927,6 @@ Packet: '%s'\n"), else if (strprefix (p, p1, "exec")) { ULONGEST ignored; - char pathname[PATH_MAX]; int pathlen; /* Determine the length of the execd pathname. */ @@ -6936,11 +6935,12 @@ Packet: '%s'\n"), /* Save the pathname for event reporting and for the next run command. */ + char *pathname = (char *) xmalloc (pathlen + 1); hex2bin (p1, (gdb_byte *) pathname, pathlen); pathname[pathlen] = '\0'; /* This is freed during event handling. */ - event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.value.execd_pathname = pathname; event->ws.kind = TARGET_WAITKIND_EXECD; /* Skip the registers included in this packet, since Grüße Thomas ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2016-12-08 11:54 ` Thomas Schwinge @ 2017-02-17 16:45 ` Pedro Alves 2019-02-14 16:42 ` Thomas Schwinge 0 siblings, 1 reply; 55+ messages in thread From: Pedro Alves @ 2017-02-17 16:45 UTC (permalink / raw) To: Thomas Schwinge, Don Breazeal, gdb-patches Cc: bug-hurd, 834575, 834575-forwarded, svante.signell Hi Thomas, Only noticed this patch now. > On GNU/Hurd, there is no "#define PATH_MAX", so this fails to build. > (I'm aware that there is other PATH_MAX usage in GDB sources, which we > ought to fix at some point, for example in gdbserver -- which is not yet > enabled for GNU/Hurd.) > > OK to push the following? (Similar to Svante's patch in > <https://bugs.debian.org/834575>.) > > --- gdb/remote.c > +++ gdb/remote.c > @@ -6927,7 +6927,6 @@ Packet: '%s'\n"), > else if (strprefix (p, p1, "exec")) > { > ULONGEST ignored; > - char pathname[PATH_MAX]; > int pathlen; > > /* Determine the length of the execd pathname. */ > @@ -6936,11 +6935,12 @@ Packet: '%s'\n"), > > /* Save the pathname for event reporting and for > the next run command. */ > + char *pathname = (char *) xmalloc (pathlen + 1); > hex2bin (p1, (gdb_byte *) pathname, pathlen); > pathname[pathlen] = '\0'; hex2bin can throw, so wrap with a cleanup: char *pathname = (char *) xmalloc (pathlen + 1); struct cleanup *old_chain = make_cleanup (xfree, pathname); hex2bin (p1, (gdb_byte *) pathname, pathlen); pathname[pathlen] = '\0'; discard_cleanups (old_chain); OK with that change. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2017-02-17 16:45 ` Pedro Alves @ 2019-02-14 16:42 ` Thomas Schwinge 2019-02-14 17:26 ` Tom Tromey 0 siblings, 1 reply; 55+ messages in thread From: Thomas Schwinge @ 2019-02-14 16:42 UTC (permalink / raw) To: Pedro Alves, gdb-patches Cc: 834575, 834575-forwarded, bug-hurd, svante.signell [-- Attachment #1: Type: text/plain, Size: 1727 bytes --] Hi! On Fri, 17 Feb 2017 16:45:01 +0000, Pedro Alves <palves@redhat.com> wrote: > Only noticed this patch now. Heh, and I've only now gotten back to completing this. ;-) > > On GNU/Hurd, there is no "#define PATH_MAX", so this fails to build. > > (I'm aware that there is other PATH_MAX usage in GDB sources, which we > > ought to fix at some point, for example in gdbserver -- which is not yet > > enabled for GNU/Hurd.) > > > > OK to push the following? (Similar to Svante's patch in > > <https://bugs.debian.org/834575>.) > > > > > > --- gdb/remote.c > > +++ gdb/remote.c > > @@ -6927,7 +6927,6 @@ Packet: '%s'\n"), > > else if (strprefix (p, p1, "exec")) > > { > > ULONGEST ignored; > > - char pathname[PATH_MAX]; > > int pathlen; > > > > /* Determine the length of the execd pathname. */ > > @@ -6936,11 +6935,12 @@ Packet: '%s'\n"), > > > > /* Save the pathname for event reporting and for > > the next run command. */ > > + char *pathname = (char *) xmalloc (pathlen + 1); > > hex2bin (p1, (gdb_byte *) pathname, pathlen); > > pathname[pathlen] = '\0'; > > > hex2bin can throw, so wrap with a cleanup: > > char *pathname = (char *) xmalloc (pathlen + 1); > struct cleanup *old_chain = make_cleanup (xfree, pathname); > hex2bin (p1, (gdb_byte *) pathname, pathlen); > pathname[pathlen] = '\0'; > discard_cleanups (old_chain); > > OK with that change. Thanks; pushed to master the attached commit b671c7fb21306ce125717a44c30a71686bd24db1 "[gdb, hurd] Avoid using 'PATH_MAX' in 'gdb/remote.c'". Grüße Thomas [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-gdb-hurd-Avoid-using-PATH_MAX-in-gdb-remote.c.patch --] [-- Type: text/x-diff, Size: 2311 bytes --] From b671c7fb21306ce125717a44c30a71686bd24db1 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge <thomas@codesourcery.com> Date: Fri, 17 Feb 2017 16:45:01 +0000 Subject: [PATCH] [gdb, hurd] Avoid using 'PATH_MAX' in 'gdb/remote.c' ..., which is not defined in GNU/Hurd systems, and so commit 94585166dfea8232c248044f9f4b1c217dc4ac2e "Extended-remote follow-exec" caused: [...]/gdb/remote.c: In member function 'void remote_target::remote_parse_stop_reply(const char*, stop_reply*)': [...]/gdb/remote.c:7343:22: error: 'PATH_MAX' was not declared in this scope char pathname[PATH_MAX]; ^~~~~~~~ gdb/ * remote.c (remote_target::remote_parse_stop_reply): Avoid using 'PATH_MAX'. --- gdb/ChangeLog | 6 ++++++ gdb/remote.c | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f2bbd77558..bb27f74de1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2019-02-14 Thomas Schwinge <thomas@codesourcery.com> + Pedro Alves <palves@redhat.com> + + * remote.c (remote_target::remote_parse_stop_reply): Avoid using + 'PATH_MAX'. + 2019-02-14 David Michael <fedora.dm0@gmail.com> Samuel Thibault <samuel.thibault@gnu.org> Thomas Schwinge <thomas@codesourcery.com> diff --git a/gdb/remote.c b/gdb/remote.c index 18e678d07a..85af01e4b7 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -7340,7 +7340,6 @@ Packet: '%s'\n"), else if (strprefix (p, p1, "exec")) { ULONGEST ignored; - char pathname[PATH_MAX]; int pathlen; /* Determine the length of the execd pathname. */ @@ -7349,11 +7348,14 @@ Packet: '%s'\n"), /* Save the pathname for event reporting and for the next run command. */ + char *pathname = (char *) xmalloc (pathlen + 1); + struct cleanup *old_chain = make_cleanup (xfree, pathname); hex2bin (p1, (gdb_byte *) pathname, pathlen); pathname[pathlen] = '\0'; + discard_cleanups (old_chain); /* This is freed during event handling. */ - event->ws.value.execd_pathname = xstrdup (pathname); + event->ws.value.execd_pathname = pathname; event->ws.kind = TARGET_WAITKIND_EXECD; /* Skip the registers included in this packet, since -- 2.19.2 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2019-02-14 16:42 ` Thomas Schwinge @ 2019-02-14 17:26 ` Tom Tromey 2019-02-14 23:11 ` Tom Tromey 0 siblings, 1 reply; 55+ messages in thread From: Tom Tromey @ 2019-02-14 17:26 UTC (permalink / raw) To: Thomas Schwinge Cc: Pedro Alves, gdb-patches, 834575, 834575-forwarded, bug-hurd, svante.signell >>>>> "Thomas" == Thomas Schwinge <thomas@codesourcery.com> writes: Thomas> + struct cleanup *old_chain = make_cleanup (xfree, pathname); Please don't add new cleanups to gdb. We're in the process of removing them all. Instead you can use gdb::unique_xmalloc_ptr<char>, or std::string, or a std::vector of some flavor. thanks, Tom ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [pushed][PATCH v3 1/4] Extended-remote follow exec 2019-02-14 17:26 ` Tom Tromey @ 2019-02-14 23:11 ` Tom Tromey 0 siblings, 0 replies; 55+ messages in thread From: Tom Tromey @ 2019-02-14 23:11 UTC (permalink / raw) To: Tom Tromey Cc: Thomas Schwinge, Pedro Alves, gdb-patches, 834575, 834575-forwarded, bug-hurd, svante.signell >>>>> "Tom" == Tom Tromey <tom@tromey.com> writes: >>>>> "Thomas" == Thomas Schwinge <thomas@codesourcery.com> writes: Thomas> + struct cleanup *old_chain = make_cleanup (xfree, pathname); Tom> Please don't add new cleanups to gdb. Tom> We're in the process of removing them all. Tom> Instead you can use gdb::unique_xmalloc_ptr<char>, or std::string, or a Tom> std::vector of some flavor. I went ahead and added a patch to fix this to my series to remove cleanups, so you don't need to do anything about this one. Tom ^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2019-02-14 23:11 UTC | newest] Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal 2015-07-15 21:50 ` [PATCH 2/5] Extended-remote exec catchpoints Don Breazeal 2015-08-13 15:00 ` Pedro Alves 2015-07-15 21:50 ` [PATCH 1/5] Extended-remote exec events Don Breazeal 2015-07-16 14:01 ` Yao Qi 2015-07-16 15:52 ` Don Breazeal 2015-07-16 16:35 ` Yao Qi 2015-07-16 17:06 ` Don Breazeal 2015-07-17 11:55 ` Yao Qi 2015-07-15 21:50 ` [PATCH 3/5] Extended-remote support for exec event tests Don Breazeal 2015-07-15 21:51 ` [PATCH 5/5] Extended-remote exec event docs Don Breazeal 2015-07-16 2:39 ` Eli Zaretskii 2015-07-15 21:51 ` [PATCH 4/5] Eliminate spurious warnings from remote exec Don Breazeal 2015-07-30 23:19 ` [PATCH v2 0/5] Extended-remote exec events Don Breazeal 2015-07-30 23:19 ` [PATCH v2 2/5] Extended-remote exec catchpoints Don Breazeal 2015-07-30 23:19 ` [PATCH v2 1/5] Extended-remote follow exec Don Breazeal 2015-08-13 14:50 ` Pedro Alves 2015-07-30 23:20 ` [PATCH v2 4/5] Eliminate spurious warnings from remote exec Don Breazeal 2015-08-13 15:38 ` Pedro Alves 2015-07-30 23:20 ` [PATCH v2 5/5] Extended-remote exec event docs Don Breazeal 2015-07-31 6:36 ` Eli Zaretskii 2015-07-31 17:06 ` Don Breazeal 2015-08-13 15:43 ` Pedro Alves 2015-07-30 23:20 ` [PATCH v2 3/5] Extended-remote support for exec event tests Don Breazeal 2015-08-13 15:22 ` Pedro Alves 2015-09-09 23:05 ` [PATCH v3 0/4] Extended-remote exec events Don Breazeal 2015-09-09 23:06 ` [PATCH v3 3/4] Extended-remote support for exec event tests Don Breazeal 2015-09-10 13:26 ` Pedro Alves 2015-09-09 23:06 ` [PATCH v3 4/4] Extended-remote exec event docs Don Breazeal 2015-09-10 15:23 ` Eli Zaretskii 2015-09-09 23:06 ` [PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal 2015-09-09 23:06 ` [PATCH v3 1/4] Extended-remote follow exec Don Breazeal 2015-09-10 12:43 ` Pedro Alves 2015-09-10 22:56 ` Don Breazeal 2015-09-10 23:00 ` Don Breazeal 2015-09-11 8:34 ` Pedro Alves 2015-09-11 18:38 ` [pushed][PATCH " Don Breazeal 2015-09-11 18:38 ` [pushed][PATCH v3 3/4] Extended-remote exec test Don Breazeal 2015-09-15 15:45 ` Pedro Alves 2015-09-15 15:53 ` Don Breazeal 2015-09-15 15:58 ` Pedro Alves 2015-09-15 16:00 ` Breazeal, Don 2015-09-15 16:28 ` Pedro Alves 2015-09-11 18:38 ` [pushed][PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal 2015-09-11 18:39 ` [pushed][PATCH v3 4/4] Extended-remote exec event docs Don Breazeal 2015-09-15 8:56 ` [pushed][PATCH v3 1/4] Extended-remote follow exec Yao Qi 2015-09-15 16:12 ` Don Breazeal 2015-09-15 16:31 ` Yao Qi 2015-09-30 16:20 ` Pedro Alves 2015-09-30 16:22 ` Breazeal, Don 2016-12-08 11:54 ` Thomas Schwinge 2017-02-17 16:45 ` Pedro Alves 2019-02-14 16:42 ` Thomas Schwinge 2019-02-14 17:26 ` Tom Tromey 2019-02-14 23:11 ` Tom Tromey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).