This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: TUI + gdbserver broken?


Pedro Alves wrote:

OK, thanks. Sorry I can be of more help here. Debugging TUI on Cygwin really is a pain.


Gulp, I should stop replying like that first thing in the morning. What a lamer. :/

Humm, debugging a gdb from cvs just after that selected frame
patch that broke TUI, I got some things different from what I
see from current head.  When I first stepped in a native debug
session, I saw that deprecated_safe_get_selected_frame
returned NULL, because one of target_has_memory, target_has_stack
or target_has_registers was 0, but with current CVS they are
all still 1.  Maybe one of the follow up patches changed it,
I don't know.

I've just done a careful double debugging session, stepping
simultaneously in a native debugging session, and a remote
gdbserver debugging session, and surprisingly, I now see that
the native version also ends up calling target_fetch_registers -
that is, the trace I sent also happens on native cygwin, and
what I stated as "obviously wrong" might not be so wrong
after all.

So, in frame.c, we reinit the frame cache, which selects a
NULL frame, which calls the tui hook, that calls
deprecated_safe_get_selected_frame (with level -1), which since it
doesn't know that the target exited already, it calls
get_selected_frame, which ensures there is a frame, but by
doing it calls select_frame, that calls again the same tui hook
(now with level 0), which calls deprecated_safe_get_selected_frame,
returns a non null frame, and then goes into ... :

static void
tui_selected_frame_level_changed_hook (int level)
{
    struct frame_info *fi;

    fi = deprecated_safe_get_selected_frame ();
    /* Ensure that symbols for this frame are read in.  Also, determine the
       source language of this frame, and switch to it if desired.  */
    if (fi)
      {
        struct symtab *s;

        s = find_pc_symtab (get_frame_pc (fi));  <<<<< ... here.
(tui-hooks.c:240)

The backtrace is :

#0  tui_selected_frame_level_changed_hook (level=0) at
../../gdb-server_search/src/gdb/tui/tui-hooks.c:240
#1  0x0047c359 in select_frame (fi=0x1005b6f8) at
../../gdb-server_search/src/gdb/frame.c:995
#2  0x0047c2ab in get_selected_frame (message=0x0) at
../../gdb-server_search/src/gdb/frame.c:965
#3  0x0047c325 in deprecated_safe_get_selected_frame () at
../../gdb-server_search/src/gdb/frame.c:981
#4  0x004a3191 in tui_selected_frame_level_changed_hook (level=-1)
       at ../../gdb-server_search/src/gdb/tui/tui-hooks.c:233
#5  0x0047c359 in select_frame (fi=0x0) at
../../gdb-server_search/src/gdb/frame.c:995
#6  0x0047c572 in reinit_frame_cache () at
../../gdb-server_search/src/gdb/frame.c:1095
#7  0x004262f7 in handle_inferior_event (ecs=0x22c690) at
../../gdb-server_search/src/gdb/infrun.c:1302
(...)

And then, stepping a bit more, target_fetch_register will
eventually be called to fetch the pc.  Here is a trace
on native Cygwin.

#0  do_win32_fetch_inferior_registers (r=8) at
../../gdb-server_search/src/gdb/win32-nat.c:375
#1  0x004723c0 in win32_fetch_inferior_registers (r=8) at
../../gdb-server_search/src/gdb/win32-nat.c:413
#2  0x0047719e in regcache_raw_read (regcache=0x1008cf48, regnum=8,
buf=0x22c3b0 "Ø»\005\020ð")
    at ../../gdb-server_search/src/gdb/regcache.c:510
#3  0x00477769 in regcache_cooked_read (regcache=0x1008cf48, regnum=8,
buf=0x22c3b0 "Ø»\005\020ð")
    at ../../gdb-server_search/src/gdb/regcache.c:588
#4  0x00523565 in sentinel_frame_prev_register (next_frame=0x1005bb88,
this_prologue_cache=0x1005bb8c,
    regnum=8, optimized=0x22c394, lvalp=0x22c388, addrp=0x22c390,
realnum=0x22c38c,
    bufferp=0x22c3b0 "Ø»\005\020ð") at
../../gdb-server_search/src/gdb/sentinel-frame.c:69
#5  0x0047b794 in frame_register_unwind (frame=0x1005bb88, regnum=8,
optimizedp=0x22c394, lvalp=0x22c388,
    addrp=0x22c390, realnump=0x22c38c, bufferp=0x22c3b0 "Ø»\005\020ð")
    at ../../gdb-server_search/src/gdb/frame.c:589
#6  0x0047ba84 in frame_unwind_register (frame=0x1005bb88, regnum=8,
buf=0x22c3b0 "Ø»\005\020ð")
    at ../../gdb-server_search/src/gdb/frame.c:641
#7  0x0051db80 in i386_unwind_pc (gdbarch=0x1008a3d8, next_frame=0x1005bb88)
    at ../../gdb-server_search/src/gdb/i386-tdep.c:915
#8  0x0045bfa5 in gdbarch_unwind_pc (gdbarch=0x1008a3d8,
next_frame=0x1005bb88)
    at ../../gdb-server_search/src/gdb/gdbarch.c:3071
#9  0x005235bb in sentinel_frame_prev_pc (next_frame=0x1005bb88,
this_prologue_cache=0x1005bb8c)
    at ../../gdb-server_search/src/gdb/sentinel-frame.c:89
#10 0x0047b37f in frame_pc_unwind (this_frame=0x1005bb88) at
../../gdb-server_search/src/gdb/frame.c:438
#11 0x0047cec4 in get_frame_pc (frame=0x1005bbd8) at
../../gdb-server_search/src/gdb/frame.c:1491
#12 0x004a31a5 in tui_selected_frame_level_changed_hook (level=0)
    at ../../gdb-server_search/src/gdb/tui/tui-hooks.c:240
#13 0x0047c359 in select_frame (fi=0x1005bbd8) at
../../gdb-server_search/src/gdb/frame.c:995
#14 0x0047c2ab in get_selected_frame (message=0x0) at
../../gdb-server_search/src/gdb/frame.c:965
#15 0x0047c325 in deprecated_safe_get_selected_frame () at
../../gdb-server_search/src/gdb/frame.c:981
#16 0x004a3191 in tui_selected_frame_level_changed_hook (level=-1)
    at ../../gdb-server_search/src/gdb/tui/tui-hooks.c:233
#17 0x0047c359 in select_frame (fi=0x0) at
../../gdb-server_search/src/gdb/frame.c:995
#18 0x0047c572 in reinit_frame_cache () at
../../gdb-server_search/src/gdb/frame.c:1095
#19 0x004262f7 in handle_inferior_event (ecs=0x22c660) at
../../gdb-server_search/src/gdb/infrun.c:1302
#20 0x00425b87 in wait_for_inferior () at
../../gdb-server_search/src/gdb/infrun.c:1003
(...)

Since when native debugging there is no problem
(at least on Windows) to read the registers from an already
exited process, TUI doesn't brake.  But when remote debugging,
if the target stub has exited, we can't of course read
registers (or whatever) from it.

The attached patch implements a possible fix.  We can have
the target support (in this case remote.c) take care of
knowing when it is possible to attend a request from upper
layers.  That is, ... :

(...)
Packet vCont (verbose-resume) is supported
Sending packet: $vCont;c#a8...Ack
Packet received: W00
Sending packet: $g#67...Remote communication error: Software caused
connection
abort.

 - ... stop it from trying to to fetch registers when
the target already exited (got a 'W' packed).

(let me know if I reached the wrong patches patience level. :( )

Cheers,
Pedro Alves

gdb/ChangeLog

	* remote.c (remote_fetch_registers): Don't try to fetch
	registers from an already exited inferior.

---
 gdb/remote.c |   42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c	2007-03-19 19:52:28.000000000 +0000
+++ src/gdb/remote.c	2007-03-20 22:19:58.000000000 +0000
@@ -3684,28 +3684,34 @@ remote_fetch_registers (int regnum)
   struct remote_state *rs = get_remote_state ();
   struct remote_arch_state *rsa = get_remote_arch_state ();
   int i;
+  int exited;
 
   set_thread (PIDGET (inferior_ptid), 1);
 
+  exited = (rs->buf[0] == 'W');
+
   if (regnum >= 0)
     {
       struct packet_reg *reg = packet_reg_from_regnum (rsa, regnum);
       gdb_assert (reg != NULL);
 
-      /* If this register might be in the 'g' packet, try that first -
-	 we are likely to read more than one register.  If this is the
-	 first 'g' packet, we might be overly optimistic about its
-	 contents, so fall back to 'p'.  */
-      if (reg->in_g_packet)
+      if (!exited)
 	{
-	  fetch_registers_using_g ();
+	  /* If this register might be in the 'g' packet, try that first -
+	     we are likely to read more than one register.  If this is the
+	     first 'g' packet, we might be overly optimistic about its
+	     contents, so fall back to 'p'.  */
 	  if (reg->in_g_packet)
+	    {
+	      fetch_registers_using_g ();
+	      if (reg->in_g_packet)
+		return;
+	    }
+
+	  if (fetch_register_using_p (reg))
 	    return;
 	}
 
-      if (fetch_register_using_p (reg))
-	return;
-
       /* This register is not available.  */
       regcache_raw_supply (current_regcache, reg->regnum, NULL);
       set_register_cached (reg->regnum, -1);
@@ -3713,16 +3719,18 @@ remote_fetch_registers (int regnum)
       return;
     }
 
-  fetch_registers_using_g ();
+  if (!exited)
+    fetch_registers_using_g ();
 
   for (i = 0; i < NUM_REGS; i++)
-    if (!rsa->regs[i].in_g_packet)
-      if (!fetch_register_using_p (&rsa->regs[i]))
-	{
-	  /* This register is not available.  */
-	  regcache_raw_supply (current_regcache, i, NULL);
-	  set_register_cached (i, -1);
-	}
+    if (exited
+	|| (!rsa->regs[i].in_g_packet
+	    && !fetch_register_using_p (&rsa->regs[i])))
+      {
+	/* This register is not available.  */
+	regcache_raw_supply (current_regcache, i, NULL);
+	set_register_cached (i, -1);
+      }
 }
 
 /* Prepare to store registers.  Since we may send them all (using a


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]