[bug?] [patch] target remote and multiprocess+

Matthias Pfaller leo@marco.de
Mon Nov 28 09:24:00 GMT 2016


On 11/23/2016 04:45 PM, Luis Machado wrote:
> Hi,
> 
> On 11/23/2016 02:55 AM, Matthias Pfaller wrote:
>> To make sure I'm not totally wrong I did run an (unpatched) gdbserver
>> (7.11.1) -multi on my host machine. Then I connected with
>> extended-remote and created two inferiors. After a disconnect and a
>> reconnect gdbserver responds with the following inferior/thread list:
>>
>> l<threads>\n<thread id="p29ae.29ae" core="3" name="xterm"/>\n<thread
>> id="p3dcf.3dcf" core="1" name="xterm"/>\n</threads>\n
>>
>> But doing a "info inferiors" will show:
>> (gdb) info inferiors
>>   Num  Description       Executable
>> * 1    process 15823     /usr/uti/xterm
>>
>> and info threads:
>> (gdb) info threads
>> Sending packet: $qXfer:threads:read::0,fff#03...Packet received:
>> l<threads>\n<thread id="p29ae.29ae" core="3" name="xterm"/>\n<thread
>> id="p3dcf.3dcf" core="1" name="xterm"/>\n</threads>\n
>>   Id   Target Id         Frame
>>   1    Thread 10670.10670 "xterm"
>> ../../gdb/thread.c:1447: internal-error: switch_to_thread: Assertion
>> `inf != NULL' failed.
>> A problem internal to GDB has been detected,
>> further debugging may prove unreliable.
>> Quit this debugging session? (y or n)
>>
>> (note that this is the host system's gdb 7.11.1)
>> So attaching to a target with multiple running inferiors just doesn't
>> work at the moment.
>>
>> Now I tried with gdb-7.12 and my patches applied:
>>
>> (gdb) set non-stop on
>> (gdb) target remote localhost:29979
>> Remote debugging using localhost:29979
>> Reading /usr/uti/xterm from remote target...
>> warning: File transfers from remote targets can be slow. Use "set
>> sysroot" to access files locally instead.
>> Reading /usr/uti/xterm from remote target...
>> Reading symbols from target:/usr/uti/xterm...(no debugging symbols
>> found)...done.
>> Python Exception <type 'exceptions.NameError'> Installation error:
>> gdb.execute_unwinders function is missing:
>>
>> Thread 1.1 "xterm" stopped.
>> 0x00007ffff7ddac80 in ?? ()
>> Python Exception <type 'exceptions.NameError'> Installation error:
>> gdb.execute_unwinders function is missing:
>>
>> Thread 2.1 "xterm" stopped.
>> 0x00007ffff7ddac80 in ?? ()
>> (gdb) info threads
>>   Id   Target Id         Frame
>>   1.1  Thread 10670.10670 "xterm" Python Exception <type
>> 'exceptions.NameError'> Installation error: gdb.execute_unwinders
>> function is missing:
>> 0x00007ffff7ddac80 in ?? ()
>> * 2.1  Thread 15823.15823 "xterm" Python Exception <type
>> 'exceptions.NameError'> Installation error: gdb.execute_unwinders
>> function is missing:
>> 0x00007ffff7ddac80 in ?? ()
>> (gdb) info inferiors
>>   Num  Description       Executable
>>   1    process 10670     target:/usr/uti/xterm
>> * 2    process 15823     target:/usr/uti/xterm
>>
>> So I think this is at least not worse than what gdb was doing before...
>> Is there a chance to get this patch into gdb?
>>
>> Matthias
>>
> 
> I think i misunderstood your initial explanation. So the patch in
> questions attempts to fix the internal error plus the fact that GDB
> doesn't show more than one inferior when connecting to a gdbserver that
> is controlling multiple inferiors?
> 
> If so, indeed it is a bug and i still see it on master GDB. I'd send the
> patch to gdb-patches so we can properly review it.
> 
> Also, did you run the gdb testsuite to make sure your patch did not
> introduce regressions comparing against the unpatch gdb testsuite run?
> 
> You can run the testsuite like this:
> 
> make check-gdb (top-level) or make-gdb
> 
> You should also run the testsuite against gdbserver like this:
> 
> make check-gdb RUNTESTFLAGS="--target_board native-gdbserver"

A gdb-7.12 built with the attached patch gives the same FAIL lines for
  make check
and
  make check-gdb RUNTESTFLAGS="--target_board native-gdbserver"
as a gdb-7.12 built without my patch.

The patch does:
* make "multiprocess+;" work with "target remote"
* stop inferiors only for the event thread when a break or watch point
is hit
* stop new inferiors only when global break or watch points are in place

This makes it possible to debug an embedded target where gdbserver is
running as native thread on the target. The target has to report the
threadlist as an inferiorlist with one thread per inferior. That way one
can context switch break and watch points and halt only the thread to be
debugged.

regards, Matthias
-- 
Matthias Pfaller                          Software Entwicklung
marco Systemanalyse und Entwicklung GmbH  Tel   +49 8131 5161 41
Hans-Böckler-Str. 2, D 85221 Dachau       Fax   +49 8131 5161 66
http://www.marco.de/                      Email leo@marco.de
Geschäftsführer Martin Reuter             HRB 171775 Amtsgericht München
-------------- next part --------------
--- ../orig/gdb/breakpoint.c
+++ ./gdb/breakpoint.c
--- ../orig/gdb/infcmd.c
+++ ./gdb/infcmd.c
@@ -2741,7 +2741,7 @@
 	  struct thread_info *lowest = inferior_thread ();
 	  int pid = current_inferior ()->pid;
 
-	  stop_all_threads ();
+	  stop_all_threads (inferior);
 
 	  /* It's not defined which thread will report the attach
 	     stop.  For consistency, always select the thread with
@@ -2920,6 +2920,28 @@
   attach_post_wait (args, from_tty, mode);
 }
 
+/* Helper function for any_global_breakpoint.  If B is a global
+   break or catch point, return 1 (which will make
+   'breakpoint_find_if' return).  Otherwise, return 0.  */
+
+static int
+any_global_breakpoint_1 (struct breakpoint *b,
+			   void *data)
+{
+  if (b->enable_state == bp_enabled && b->thread == -1)
+    return 1;
+  else
+    return 0;
+}
+
+static int
+any_global_breakpoint (void)
+{
+  struct breakpoint *b = breakpoint_find_if (any_global_breakpoint_1, NULL);
+
+  return b != NULL;
+}
+
 /* We had just found out that the target was already attached to an
    inferior.  PTID points at a thread of this new inferior, that is
    the most likely to be stopped right now, but not necessarily so.
@@ -2948,7 +2970,9 @@
   /* When we "notice" a new inferior we need to do all the things we
      would normally do if we had just attached to it.  */
 
-  if (is_executing (inferior_ptid))
+  if (!leave_running &&
+      any_global_breakpoint () &&
+      is_executing (inferior_ptid))
     {
       struct attach_command_continuation_args *a;
       struct inferior *inferior = current_inferior ();
--- ../orig/gdb/inferior.c
+++ ./gdb/inferior.c
@@ -320,13 +320,27 @@
 void
 discard_all_inferiors (void)
 {
-  struct inferior *inf;
+  struct inferior *inf, *infnext;
 
-  for (inf = inferior_list; inf; inf = inf->next)
+  for (inf = inferior_list; inf; inf = infnext)
     {
-      if (inf->pid != 0)
-	exit_inferior_silent (inf->pid);
+      infnext = inf->next;
+      
+      if (inf->num == 1)
+        {
+	  if (inf->pid != 0)
+	    exit_inferior_1 (inf, 1);
+	}
+      else
+	delete_inferior (inf);
     }
+
+  inferior_ptid = null_ptid;
+  inferior_list->pid = 0;
+  set_current_inferior (inferior_list);
+  switch_to_thread (null_ptid);
+
+  highest_inferior_num = inferior_list->num;
 }
 
 struct inferior *
--- ../orig/gdb/infrun.c
+++ ./gdb/infrun.c
@@ -2584,7 +2584,7 @@
 	  /* Fallback to stepping over the breakpoint in-line.  */
 
 	  if (target_is_non_stop_p ())
-	    stop_all_threads ();
+	    stop_all_threads (tp->inf);
 
 	  set_step_over_info (get_regcache_aspace (regcache),
 			      regcache_read_pc (regcache), 0, tp->global_num);
@@ -4496,7 +4496,7 @@
 /* See infrun.h.  */
 
 void
-stop_all_threads (void)
+stop_all_threads (struct inferior *inferior)
 {
   /* We may need multiple passes to discover all threads.  */
   int pass;
@@ -4509,6 +4509,11 @@
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n");
 
+  /* With global break points we have always to
+     stop all threads of all inferiors.  */
+  if (gdbarch_has_global_breakpoints (target_gdbarch ()))
+    inferior = NULL;
+
   entry_ptid = inferior_ptid;
   old_chain = make_cleanup (switch_to_thread_cleanup, &entry_ptid);
 
@@ -4539,6 +4544,8 @@
 	     to tell the target to stop.  */
 	  ALL_NON_EXITED_THREADS (t)
 	    {
+	      if (inferior != NULL && inferior != t->inf)
+	      	continue;
 	      if (t->executing)
 		{
 		  /* If already stopping, don't request a stop again.
@@ -5442,7 +5449,7 @@
 
   ALL_NON_EXITED_THREADS (tp)
     {
-      if (tp == event_thread)
+      if (tp == event_thread || tp->inf != event_thread->inf)
 	{
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog,
@@ -7705,7 +7712,7 @@
   /* If all-stop, but the target is always in non-stop mode, stop all
      threads now that we're presenting the stop to the user.  */
   if (!non_stop && target_is_non_stop_p ())
-    stop_all_threads ();
+    stop_all_threads (NULL);
 }
 
 /* Like keep_going, but passes the signal to the inferior, even if the
@@ -7821,7 +7828,7 @@
 	 we're about to step over, otherwise other threads could miss
 	 it.  */
       if (step_over_info_valid_p () && target_is_non_stop_p ())
-	stop_all_threads ();
+	stop_all_threads (ecs->event_thread->inf);
 
       /* Stop stepping if inserting breakpoints fails.  */
       TRY
--- ../orig/gdb/infrun.h
+++ ./gdb/infrun.h
@@ -110,8 +110,12 @@
 extern void set_last_target_status (ptid_t ptid,
 				    struct target_waitstatus status);
 
-/* Stop all threads.  Only returns after everything is halted.  */
-extern void stop_all_threads (void);
+/* Stop all threads belonging to inf.
+   When called with inf == NULL, stop all threads of all inferiors.
+   With gdbarch_has_global_breakpoints () is true, always stop all
+   threads of all inferiors.
+   Only returns after everything is halted.  */
+extern void stop_all_threads (struct inferior *inf);
 
 extern void prepare_for_detach (void);
 
--- ../orig/gdb/remote.c
+++ ./gdb/remote.c
@@ -1789,8 +1789,24 @@
       /* In the traditional debugging scenario, there's a 1-1 match
 	 between program/address spaces.  We simply bind the inferior
 	 to the program space's address space.  */
-      inf = current_inferior ();
-      inferior_appeared (inf, pid);
+
+      inf = find_inferior_id (pid);
+      if (inf == NULL)
+        {
+	  if (current_inferior () ->pid == 0)
+	    {
+	      inf = current_inferior ();
+	      inferior_appeared (inf, pid);
+	    }
+	  else
+	    {
+	      inf = add_inferior (pid);
+	      inf->aspace = current_inferior () ->aspace;
+	      inf->pspace = current_program_space;
+	      inf->gdbarch = current_inferior () ->gdbarch;
+	      copy_inferior_target_desc_info(inf, current_inferior ());
+	    }
+        }
     }
 
   inf->attach_flag = attached;
@@ -1801,6 +1817,10 @@
   if (try_open_exec && get_exec_file (0) == NULL)
     exec_file_locate_attach (pid, 0, 1);
 
+  set_current_inferior (inf);
+
+  inferior_ptid = pid_to_ptid (pid);
+
   return inf;
 }
 
@@ -1902,6 +1922,9 @@
 
       /* This is really a new thread.  Add it.  */
       remote_add_thread (currthread, running, executing);
+      if (ptid_is_pid (inferior_ptid)
+	  && pid == ptid_get_pid (inferior_ptid))
+        inferior_ptid = currthread;
 
       /* If we found a new inferior, let the common code do whatever
 	 it needs to with it (e.g., read shared libraries, insert
@@ -3937,7 +3960,7 @@
      the inferiors.  */
   if (!non_stop)
     {
-      stop_all_threads ();
+      stop_all_threads (NULL);
 
       /* If all threads of an inferior were already stopped, we
 	 haven't setup the inferior yet.  */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4349 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://sourceware.org/pipermail/gdb/attachments/20161128/3ac7637b/attachment.p7s>


More information about the Gdb mailing list