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]

[unavailable regs/locals, 03/11] glue unavailable regcache registers / lval_register values / frame registers


This patch glues the regcache registers unavailableness
with frame unwinding, and lval_register values.

 * sentinel-frame.c can now make use of the changes done in
   the previous patch to mark register values as unvailable:

  -  regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value));
  +  if (regcache_cooked_read (cache->regcache,
  +			    regnum,
  +			    value_contents_raw (value)) == REG_UNAVAILABLE)
  +    mark_value_bytes_unavailable (value, 0, register_size (gdbarch, regnum));

 * frame_register_unwind and frame_register gain a new `unavailablep' output
   boolean parameter, that is set to true if the register read or unwound is
   unavailable.  This is obviously modeled on the `optimizedp' output
   parameter.  Then all callers are updated.

 * Adds a few basic tests around "info registers", and "print $regfoo".

"info frame" behaves better after this patch (no longer throws a "value
not available" error), but I'm saving adding a test for that for later.

As for the mandatory screenshots, here's Before Patch:

This is inspecting the traceframe of a tracepoint that
collected nothing.

  (gdb) info registers
  rax            0x0      0
  rbx            0x0      0
  rcx            0x0      0
  rdx            0x0      0
  rsi            0x0      0
  rdi            0x0      0
  rbp            0x0      0x0
  rsp            0x0      0x0
  r8             0x0      0
  r9             0x0      0
  r10            0x0      0
  r11            0x0      0
  r12            0x0      0
  r13            0x0      0
  r14            0x0      0
  r15            0x0      0
  rip            0x4007e4 0x4007e4 <globals_test_func()+4>
  eflags         0x0      [ ]
  cs             0x0      0
  ss             0x0      0
  ds             0x0      0
  es             0x0      0
  fs             0x0      0
  gs             0x0      0

  (gdb) info registers $rsp
  rsp            0x0      0x0

  (gdb) print /x $rbp
  $1 = 0x0

  (gdb) print /x $rsp
  $2 = 0x0

And After Patch:

  (gdb) info registers 
  rax            *value not available*
  rbx            *value not available*
  rcx            *value not available*
  rdx            *value not available*
  rsi            *value not available*
  rdi            *value not available*
  rbp            *value not available*
  rsp            *value not available*
  r8             *value not available*
  r9             *value not available*
  r10            *value not available*
  r11            *value not available*
  r12            *value not available*
  r13            *value not available*
  r14            *value not available*
  r15            *value not available*
  rip            0x4007d8 0x4007d8 <begin()+4>
  eflags         *value not available*
  cs             *value not available*
  ss             *value not available*
  ds             *value not available*
  es             *value not available*
  fs             *value not available*
  gs             *value not available*

  (gdb) p $rax
  $1 = <unavailable>

  (gdb) p *$rax
  value is not available


The "*value not available*" output of "info registers"
is not new (and it wasn't me who added it).  Only the glue
was missing.

-- 
Pedro Alves

2011-02-22  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* findvar.c (value_of_register): Mark the value as unavailable, if
	the register is unavailable.
	* frame.h (frame_register_unwind): New `unavailablep' parameter.
	(frame_register): New `unavailablep' parameter.
	(frame_register_read): Update comment.
	* frame.c (frame_register_unwind): New `unavailablep' parameter.
	Set it if the register is unavailable.  If the register is
	unavailable, clear the output buffer.
	(frame_register): New `unavailablep' parameter.  Pass it down.
	(frame_unwind_register): Adjust.
	(put_frame_register): Adjust.
	(frame_register_read): Adjust.  Also return false if the register
	is not available.
	(frame_register_unwind_location): Adjust.
	* sentinel-frame.c (sentinel_frame_prev_register): If the register
	is unavailable, mark the value accordingly.
	* stack.c (frame_info): Handle unavailable registers.

	gdb/testsuite/
	* gdb.trace/unavailable.exp (fpreg, spreg, pcreg): Define.
	(test_register, test_register_unavailable): New procedures.
	(gdb_unavailable_registers_test): New procedure.
	(gdb_trace_collection_test): Call it.

---
 gdb/findvar.c                           |   15 ++++-
 gdb/frame.c                             |   44 +++++++++-----
 gdb/frame.h                             |   20 ++++--
 gdb/sentinel-frame.c                    |    5 +
 gdb/stack.c                             |   17 +++--
 gdb/testsuite/gdb.trace/unavailable.exp |   96 ++++++++++++++++++++++++++++++++
 6 files changed, 162 insertions(+), 35 deletions(-)

Index: src/gdb/findvar.c
===================================================================
--- src.orig/gdb/findvar.c	2011-02-21 20:30:31.979344010 +0000
+++ src/gdb/findvar.c	2011-02-22 11:39:35.994707993 +0000
@@ -265,6 +265,7 @@ value_of_register (int regnum, struct fr
   struct gdbarch *gdbarch = get_frame_arch (frame);
   CORE_ADDR addr;
   int optim;
+  int unavail;
   struct value *reg_val;
   int realnum;
   gdb_byte raw_buffer[MAX_REGISTER_SIZE];
@@ -276,16 +277,24 @@ value_of_register (int regnum, struct fr
 		+ gdbarch_num_pseudo_regs (gdbarch))
     return value_of_user_reg (regnum, frame);
 
-  frame_register (frame, regnum, &optim, &lval, &addr, &realnum, raw_buffer);
+  frame_register (frame, regnum, &optim, &unavail,
+		  &lval, &addr, &realnum, raw_buffer);
 
   reg_val = allocate_value (register_type (gdbarch, regnum));
 
-  memcpy (value_contents_raw (reg_val), raw_buffer,
-	  register_size (gdbarch, regnum));
+  if (!optim && !unavail)
+    memcpy (value_contents_raw (reg_val), raw_buffer,
+	    register_size (gdbarch, regnum));
+  else
+    memset (value_contents_raw (reg_val), 0,
+	    register_size (gdbarch, regnum));
+
   VALUE_LVAL (reg_val) = lval;
   set_value_address (reg_val, addr);
   VALUE_REGNUM (reg_val) = regnum;
   set_value_optimized_out (reg_val, optim);
+  if (unavail)
+    mark_value_bytes_unavailable (reg_val, 0, register_size (gdbarch, regnum));
   VALUE_FRAME_ID (reg_val) = get_frame_id (frame);
   return reg_val;
 }
Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c	2011-02-21 21:09:45.449344005 +0000
+++ src/gdb/frame.c	2011-02-22 11:39:36.004707990 +0000
@@ -757,8 +757,9 @@ frame_pop (struct frame_info *this_frame
 
 void
 frame_register_unwind (struct frame_info *frame, int regnum,
-		       int *optimizedp, enum lval_type *lvalp,
-		       CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
+		       int *optimizedp, int *unavailablep,
+		       enum lval_type *lvalp, CORE_ADDR *addrp,
+		       int *realnump, gdb_byte *bufferp)
 {
   struct value *value;
 
@@ -775,13 +776,19 @@ frame_register_unwind (struct frame_info
   gdb_assert (value != NULL);
 
   *optimizedp = value_optimized_out (value);
+  *unavailablep = !value_entirely_available (value);
   *lvalp = VALUE_LVAL (value);
   *addrp = value_address (value);
   *realnump = VALUE_REGNUM (value);
 
-  if (bufferp && !*optimizedp)
-    memcpy (bufferp, value_contents_all (value),
-	    TYPE_LENGTH (value_type (value)));
+  if (bufferp)
+    {
+      if (!*optimizedp && !*unavailablep)
+	memcpy (bufferp, value_contents_all (value),
+		TYPE_LENGTH (value_type (value)));
+      else
+	memset (bufferp, 0, TYPE_LENGTH (value_type (value)));
+    }
 
   /* Dispose of the new value.  This prevents watchpoints from
      trying to watch the saved frame pointer.  */
@@ -791,7 +798,7 @@ frame_register_unwind (struct frame_info
 
 void
 frame_register (struct frame_info *frame, int regnum,
-		int *optimizedp, enum lval_type *lvalp,
+		int *optimizedp, int *unavailablep, enum lval_type *lvalp,
 		CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
 {
   /* Require all but BUFFERP to be valid.  A NULL BUFFERP indicates
@@ -805,20 +812,21 @@ frame_register (struct frame_info *frame
   /* Obtain the register value by unwinding the register from the next
      (more inner frame).  */
   gdb_assert (frame != NULL && frame->next != NULL);
-  frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
-			 realnump, bufferp);
+  frame_register_unwind (frame->next, regnum, optimizedp, unavailablep,
+			 lvalp, addrp, realnump, bufferp);
 }
 
 void
 frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
 {
   int optimized;
+  int unavailable;
   CORE_ADDR addr;
   int realnum;
   enum lval_type lval;
 
-  frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
-			 &realnum, buf);
+  frame_register_unwind (frame, regnum, &optimized, &unavailable,
+			 &lval, &addr, &realnum, buf);
 }
 
 void
@@ -940,10 +948,12 @@ put_frame_register (struct frame_info *f
   struct gdbarch *gdbarch = get_frame_arch (frame);
   int realnum;
   int optim;
+  int unavail;
   enum lval_type lval;
   CORE_ADDR addr;
 
-  frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
+  frame_register (frame, regnum, &optim, &unavail,
+		  &lval, &addr, &realnum, NULL);
   if (optim)
     error (_("Attempt to assign to a value that was optimized out."));
   switch (lval)
@@ -978,13 +988,15 @@ frame_register_read (struct frame_info *
 		     gdb_byte *myaddr)
 {
   int optimized;
+  int unavailable;
   enum lval_type lval;
   CORE_ADDR addr;
   int realnum;
 
-  frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
+  frame_register (frame, regnum, &optimized, &unavailable,
+		  &lval, &addr, &realnum, myaddr);
 
-  return !optimized;
+  return !optimized && !unavailable;
 }
 
 int
@@ -1417,8 +1429,10 @@ frame_register_unwind_location (struct f
 
   while (this_frame != NULL)
     {
-      frame_register_unwind (this_frame, regnum, optimizedp, lvalp,
-			     addrp, realnump, NULL);
+      int unavailable;
+
+      frame_register_unwind (this_frame, regnum, optimizedp, &unavailable,
+			     lvalp, addrp, realnump, NULL);
 
       if (*optimizedp)
 	break;
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h	2011-02-21 20:30:31.979344010 +0000
+++ src/gdb/frame.h	2011-02-22 11:43:39.464708012 +0000
@@ -468,7 +468,8 @@ const char *frame_stop_reason_string (en
    fetch/compute the value.  Instead just return the location of the
    value.  */
 extern void frame_register_unwind (struct frame_info *frame, int regnum,
-				   int *optimizedp, enum lval_type *lvalp,
+				   int *optimizedp, int *unavailablep,
+				   enum lval_type *lvalp,
 				   CORE_ADDR *addrp, int *realnump,
 				   gdb_byte *valuep);
 
@@ -504,7 +505,8 @@ extern ULONGEST get_frame_register_unsig
    VALUEP is NULL, the registers value is not fetched/computed.  */
 
 extern void frame_register (struct frame_info *frame, int regnum,
-			    int *optimizedp, enum lval_type *lvalp,
+			    int *optimizedp, int *unavailablep,
+			    enum lval_type *lvalp,
 			    CORE_ADDR *addrp, int *realnump,
 			    gdb_byte *valuep);
 
@@ -651,12 +653,14 @@ extern int deprecated_pc_in_call_dummy (
 /* FIXME: cagney/2003-02-02: Should be deprecated or replaced with a
    function called get_frame_register_p().  This slightly weird (and
    older) variant of get_frame_register() returns zero (indicating the
-   register is unavailable) if either: the register isn't cached; or
-   the register has been optimized out.  Problem is, neither check is
-   exactly correct.  A register can't be optimized out (it may not
-   have been saved as part of a function call); The fact that a
-   register isn't in the register cache doesn't mean that the register
-   isn't available (it could have been fetched from memory).  */
+   register value is unavailable/invalid) if either: the register
+   isn't cached; or the register has been optimized out; or the
+   register contents are unavailable (because they haven't been
+   collected in a traceframe).  Problem is, neither check is exactly
+   correct.  A register can't be optimized out (it may not have been
+   saved as part of a function call); The fact that a register isn't
+   in the register cache doesn't mean that the register isn't
+   available (it could have been fetched from memory).  */
 
 extern int frame_register_read (struct frame_info *frame, int regnum,
 				gdb_byte *buf);
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c	2011-02-21 20:30:31.979344010 +0000
+++ src/gdb/sentinel-frame.c	2011-02-22 11:39:36.064707994 +0000
@@ -61,7 +61,10 @@ sentinel_frame_prev_register (struct fra
   /* Use the regcache_cooked_read() method so that it, on the fly,
      constructs either a raw or pseudo register from the raw
      register cache.  */
-  regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value));
+  if (regcache_cooked_read (cache->regcache,
+			    regnum,
+			    value_contents_raw (value)) == REG_UNAVAILABLE)
+    mark_value_bytes_unavailable (value, 0, register_size (gdbarch, regnum));
 
   return value;
 }
Index: src/gdb/stack.c
===================================================================
--- src.orig/gdb/stack.c	2011-02-21 20:30:31.979344010 +0000
+++ src/gdb/stack.c	2011-02-22 11:39:36.064707994 +0000
@@ -1186,6 +1186,7 @@ frame_info (char *addr_exp, int from_tty
   {
     enum lval_type lval;
     int optimized;
+    int unavailable;
     CORE_ADDR addr;
     int realnum;
     int count;
@@ -1202,9 +1203,9 @@ frame_info (char *addr_exp, int from_tty
 	/* Find out the location of the saved stack pointer with out
            actually evaluating it.  */
 	frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch),
-			       &optimized, &lval, &addr,
+			       &optimized, &unavailable, &lval, &addr,
 			       &realnum, NULL);
-	if (!optimized && lval == not_lval)
+	if (!optimized && !unavailable && lval == not_lval)
 	  {
 	    enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 	    int sp_size = register_size (gdbarch, gdbarch_sp_regnum (gdbarch));
@@ -1212,7 +1213,7 @@ frame_info (char *addr_exp, int from_tty
 	    CORE_ADDR sp;
 
 	    frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch),
-				   &optimized, &lval, &addr,
+				   &optimized, &unavailable, &lval, &addr,
 				   &realnum, value);
 	    /* NOTE: cagney/2003-05-22: This is assuming that the
                stack pointer was packed as an unsigned integer.  That
@@ -1223,14 +1224,14 @@ frame_info (char *addr_exp, int from_tty
 	    printf_filtered ("\n");
 	    need_nl = 0;
 	  }
-	else if (!optimized && lval == lval_memory)
+	else if (!optimized && !unavailable && lval == lval_memory)
 	  {
 	    printf_filtered (" Previous frame's sp at ");
 	    fputs_filtered (paddress (gdbarch, addr), gdb_stdout);
 	    printf_filtered ("\n");
 	    need_nl = 0;
 	  }
-	else if (!optimized && lval == lval_register)
+	else if (!optimized && !unavailable && lval == lval_register)
 	  {
 	    printf_filtered (" Previous frame's sp in %s\n",
 			     gdbarch_register_name (gdbarch, realnum));
@@ -1248,11 +1249,11 @@ frame_info (char *addr_exp, int from_tty
 	{
 	  /* Find out the location of the saved register without
              fetching the corresponding value.  */
-	  frame_register_unwind (fi, i, &optimized, &lval, &addr, &realnum,
-				 NULL);
+	  frame_register_unwind (fi, i, &optimized, &unavailable,
+				 &lval, &addr, &realnum, NULL);
 	  /* For moment, only display registers that were saved on the
 	     stack.  */
-	  if (!optimized && lval == lval_memory)
+	  if (!optimized && !unavailable && lval == lval_memory)
 	    {
 	      if (count == 0)
 		puts_filtered (" Saved registers:\n ");
Index: src/gdb/testsuite/gdb.trace/unavailable.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.trace/unavailable.exp	2011-02-21 20:30:31.979344010 +0000
+++ src/gdb/testsuite/gdb.trace/unavailable.exp	2011-02-22 11:39:36.064707994 +0000
@@ -30,10 +30,48 @@ if { [gdb_compile "$srcdir/$subdir/$srcf
 set ws "\[\r\n\t \]+"
 set cr "\[\r\n\]+"
 
+if [istarget "x86_64-*"] then {
+    set fpreg "rbp"
+    set spreg "rsp"
+    set pcreg "rip"
+} elseif [istarget "i?86-*"] then {
+    set fpreg "ebp"
+    set spreg "esp"
+    set pcreg "eip"
+} else {
+    set fpreg "fp"
+    set spreg "sp"
+    set pcreg "pc"
+}
+
 #
 # Utility procs
 #
 
+proc test_register { reg } {
+    global gdb_prompt
+    global hex
+    global cr
+
+    gdb_test_multiple "print /x $reg" "collected $reg" {
+	-re "\\$\[0-9\]+ = \[x0\]+$cr$gdb_prompt $" {
+	    fail "collected $reg (zero)"
+	}
+	-re "\\$\[0-9\]+ = $hex$cr$gdb_prompt $" {
+	    pass "collected $reg"
+	}
+	-re "\[Ee\]rror.*$gdb_prompt $" {
+	    fail "collected $reg (error)"
+	}
+    }
+}
+
+proc test_register_unavailable { reg } {
+    gdb_test "print /x $reg" \
+	"<unavailable>" \
+	"correctly report $reg as unavailable"
+}
+
 proc prepare_for_trace_test {} {
     global executable
 
@@ -69,6 +107,63 @@ proc run_trace_experiment { test_func }
 # Test procs
 #
 
+proc gdb_unavailable_registers_test { } {
+    global gdb_prompt
+    global spreg
+    global pcreg
+    global pf_prefix
+
+    set old_pf_prefix $pf_prefix
+    set pf_prefix "$pf_prefix unavailable registers:"
+
+    prepare_for_trace_test
+
+    # We'll simply re-use the globals_test_function for this test
+    gdb_test "trace globals_test_func" \
+	    "Tracepoint \[0-9\]+ at .*" \
+	    "set tracepoint"
+
+    # Collect nothing.
+
+    # Begin the test.
+    run_trace_experiment globals_test_func
+
+    # On some archs, the $sp/$pc are a real raw registers.  On others,
+    # like x86, they're user registers.  Test both variants.
+    test_register_unavailable "\$$spreg"
+    test_register_unavailable "\$sp"
+
+    # Test reading uncollected pseudo-registers.  The set of which
+    # depends on target.
+    if [istarget "x86_64-*"] then {
+	# Check the raw register first.
+	test_register_unavailable "\$rax"
+	test_register_unavailable "\$eax"
+	test_register_unavailable "\$ax"
+    } elseif [istarget "i?86-*"] then {
+	# Check the raw register first.
+	test_register_unavailable "\$eax"
+	test_register_unavailable "\$ax"
+    }
+
+    # GDBserver always provides the PC value of regular tracepoint
+    # hits, since it's the same as the tracepoint's address.
+    test_register "\$$pcreg"
+    test_register "\$pc"
+
+    gdb_test "info registers" \
+	"\\*value not available\\*.*\\*value not available\\*" \
+	"info registers, multiple registers not available"
+
+    gdb_test "info registers \$$spreg" \
+	"\\*value not available\\*" \
+	"info registers \$$spreg reports not available"
+
+    gdb_test "tfind none" "#0  end .*" "cease trace debugging"
+
+    set pf_prefix $old_pf_prefix
+}
+
 proc gdb_collect_globals_test { } {
     global ws
     global cr
@@ -321,6 +416,7 @@ proc gdb_collect_globals_test { } {
 
 proc gdb_trace_collection_test {} {
     gdb_collect_globals_test
+    gdb_unavailable_registers_test
 }
 
 clean_restart $executable


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