public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Extended-remote follow exec
@ 2015-07-15 21:49 Don Breazeal
  2015-07-15 21:50 ` [PATCH 1/5] Extended-remote exec events 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 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 1/5] Extended-remote exec events 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-15 21:51 ` [PATCH 4/5] Eliminate spurious warnings from remote exec 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 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 ` Don Breazeal
  2015-07-16 14:01   ` Yao Qi
  2015-07-15 21:50 ` [PATCH 2/5] Extended-remote exec catchpoints 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 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

* [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 ` [PATCH 1/5] Extended-remote exec events Don Breazeal
@ 2015-07-15 21:50 ` Don Breazeal
  2015-08-13 15:00   ` Pedro Alves
  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 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

* [PATCH 4/5] Eliminate spurious warnings from remote exec
  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-15 21:51 ` [PATCH 5/5] Extended-remote exec event docs 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 5/5] Extended-remote exec event docs
  2015-07-15 21:49 [PATCH 0/5] Extended-remote follow exec Don Breazeal
                   ` (3 preceding siblings ...)
  2015-07-15 21:51 ` [PATCH 4/5] Eliminate spurious warnings from remote exec Don Breazeal
@ 2015-07-15 21:51 ` Don Breazeal
  2015-07-16  2:39   ` Eli Zaretskii
  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

* 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 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 5/5] Extended-remote exec event docs 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

* [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 5/5] Extended-remote exec event docs 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 5/5] Extended-remote exec event docs
  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-07-31  6:36     ` Eli Zaretskii
  2015-08-13 15:43     ` Pedro Alves
  2015-07-30 23:20   ` [PATCH v2 4/5] Eliminate spurious warnings from remote exec Don Breazeal
                     ` (2 subsequent siblings)
  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

* [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 4/5] Eliminate spurious warnings from remote exec 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

* [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
                     ` (2 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:38     ` 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, 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 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 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

* 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

* 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

* 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

* 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 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 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

* [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

* [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 (&current_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

* [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

* 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 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

* 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

* 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 (&current_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 3/4] Extended-remote exec test
  2015-09-11 18:38             ` [pushed][PATCH " Don Breazeal
  2015-09-11 18:38               ` [pushed][PATCH v3 2/4] Extended-remote exec catchpoints Don Breazeal
@ 2015-09-11 18:38               ` Don Breazeal
  2015-09-15 15:45                 ` Pedro Alves
  2015-09-11 18:39               ` [pushed][PATCH v3 4/4] Extended-remote exec event docs Don Breazeal
                                 ` (3 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

* [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 2/4] Extended-remote exec catchpoints 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 (&current_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 2/4] Extended-remote exec catchpoints
  2015-09-11 18:38             ` [pushed][PATCH " Don Breazeal
@ 2015-09-11 18:38               ` Don Breazeal
  2015-09-11 18:38               ` [pushed][PATCH v3 3/4] Extended-remote exec test Don Breazeal
                                 ` (4 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 2/4] Extended-remote exec catchpoints Don Breazeal
  2015-09-11 18:38               ` [pushed][PATCH v3 3/4] Extended-remote exec test 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 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 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 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

* 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 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 2/5] Extended-remote exec catchpoints Don Breazeal
2015-08-13 15:00   ` Pedro Alves
2015-07-15 21:50 ` [PATCH 3/5] Extended-remote support for exec event tests Don Breazeal
2015-07-15 21:51 ` [PATCH 4/5] Eliminate spurious warnings from remote exec 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-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 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 4/5] Eliminate spurious warnings from remote exec Don Breazeal
2015-08-13 15:38     ` 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 2/4] Extended-remote exec catchpoints 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: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).