Blame SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-2of7.patch

7b26da
  NOTE: The testcase part of this patch has been removed.
7b26da
7b26da
commit 5ce0145de764dc9c6e92daf2f843fa6e496c49d0
7b26da
Author: Pedro Alves <palves@redhat.com>
7b26da
Date:   Tue Dec 17 20:47:36 2013 +0000
7b26da
7b26da
    "tfind" across unavailable-stack frames.
7b26da
    
7b26da
    Like when stepping, the current stack frame location is expected to be
7b26da
    printed as result of tfind command, if that results in moving to a
7b26da
    different function.  In tfind_1 we see:
7b26da
    
7b26da
      if (from_tty
7b26da
          && (has_stack_frames () || traceframe_number >= 0))
7b26da
        {
7b26da
          enum print_what print_what;
7b26da
    
7b26da
          /* NOTE: in imitation of the step command, try to determine
7b26da
             whether we have made a transition from one function to
7b26da
             another.  If so, we'll print the "stack frame" (ie. the new
7b26da
             function and it's arguments) -- otherwise we'll just show the
7b26da
             new source line.  */
7b26da
    
7b26da
          if (frame_id_eq (old_frame_id,
7b26da
                           get_frame_id (get_current_frame ())))
7b26da
            print_what = SRC_LINE;
7b26da
          else
7b26da
            print_what = SRC_AND_LOC;
7b26da
    
7b26da
          print_stack_frame (get_selected_frame (NULL), 1, print_what, 1);
7b26da
          do_displays ();
7b26da
        }
7b26da
    
7b26da
    However, when we haven't collected any registers in the tracepoint
7b26da
    (collect $regs), that doesn't actually work:
7b26da
    
7b26da
     (gdb) tstart
7b26da
     (gdb) info tracepoints
7b26da
     Num     Type           Disp Enb Address    What
7b26da
     1       tracepoint     keep y   0x080483b7 in func0
7b26da
                                                at ../.././../git/gdb/testsuite/gdb.trace/circ.c:28
7b26da
             collect testload
7b26da
         installed on target
7b26da
     2       tracepoint     keep y   0x080483bc in func1
7b26da
                                                at ../.././../git/gdb/testsuite/gdb.trace/circ.c:32
7b26da
             collect testload
7b26da
         installed on target
7b26da
     (gdb) c
7b26da
     Continuing.
7b26da
    
7b26da
     Breakpoint 3, end () at ../.././../git/gdb/testsuite/gdb.trace/circ.c:72
7b26da
     72    }
7b26da
     (gdb) tstop
7b26da
     (gdb) tfind start
7b26da
     Found trace frame 0, tracepoint 1
7b26da
     #0  func0 () at ../.././../git/gdb/testsuite/gdb.trace/circ.c:28
7b26da
     28    }
7b26da
     (gdb) tfind
7b26da
     Found trace frame 1, tracepoint 2
7b26da
     32    }
7b26da
     (gdb)
7b26da
    
7b26da
    When we don't have info about the stack available
7b26da
    (UNWIND_UNAVAILABLE), frames end up with outer_frame_id as frame ID.
7b26da
    And in the scenario above, the issue is that both frames before and
7b26da
    after the second tfind (the frames for func0 an func1) have the same
7b26da
    id (outer_frame_id), so the frame_id_eq check returns false, even
7b26da
    though the frames were of different functions.  GDB knows that,
7b26da
    because the PC is inferred from the tracepoint's address, even if no
7b26da
    registers were collected.
7b26da
    
7b26da
    To fix this, this patch adds support for frame ids with a valid code
7b26da
    address, but <unavailable> stack address, and then makes the unwinders
7b26da
    use that instead of the catch-all outer_frame_id for such frames.  The
7b26da
    frame_id_eq check in tfind_1 then automatically does the right thing
7b26da
    as expected.
7b26da
    
7b26da
    I tested with --directory=gdb.trace/ , before/after the patch, and
7b26da
    compared the resulting gdb.logs, then adjusted the tests to expect the
7b26da
    extra output that came out.  Turns out that was only circ.exp, the
7b26da
    original test that actually brought this issue to light.
7b26da
    
7b26da
    Tested on x86_64 Fedora 17, native and gdbserver.
7b26da
    
7b26da
    gdb/
7b26da
    2013-12-17  Pedro Alves  <palves@redhat.com>
7b26da
    
7b26da
    	* frame.h (enum frame_id_stack_status): New enum.
7b26da
    	(struct frame_id) <stack_addr>: Adjust comment.
7b26da
    	<stack_addr_p>: Delete field, replaced with ...
7b26da
    	<stack_status>: ... this new field.
7b26da
    	(frame_id_build_unavailable_stack): Declare.
7b26da
    	* frame.c (frame_addr_hash, fprint_field, outer_frame_id)
7b26da
    	(frame_id_build_special): Adjust.
7b26da
    	(frame_id_build_unavailable_stack): New function.
7b26da
    	(frame_id_build, frame_id_build_wild): Adjust.
7b26da
    	(frame_id_p, frame_id_eq, frame_id_inner): Adjust to take into
7b26da
    	account frames with unavailable stack.
7b26da
    
7b26da
    	* amd64-tdep.c (amd64_frame_this_id)
7b26da
    	(amd64_sigtramp_frame_this_id, amd64_epilogue_frame_this_id): Use
7b26da
    	frame_id_build_unavailable_stack.
7b26da
    	* dwarf2-frame.c (dwarf2_frame_this_id): Likewise.
7b26da
    	* i386-tdep.c (i386_frame_this_id, i386_epilogue_frame_this_id)
7b26da
    	(i386_sigtramp_frame_this_id):  Likewise.
7b26da
    
7b26da
    gdb/testsuite/
7b26da
    2013-12-17  Pedro Alves  <palves@redhat.com>
7b26da
    
7b26da
    	* gdb.trace/circ.exp: Expect frame info to be printed when
7b26da
    	switching between frames with unavailable stack, but different
7b26da
    	functions.
7b26da
7b26da
Index: gdb-7.6.1/gdb/amd64-tdep.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/amd64-tdep.c
7b26da
+++ gdb-7.6.1/gdb/amd64-tdep.c
7b26da
@@ -2403,15 +2403,16 @@ amd64_frame_this_id (struct frame_info *
7b26da
   struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
7b26da
 
7b26da
   if (!cache->base_p)
7b26da
-    return;
7b26da
-
7b26da
-  /* This marks the outermost frame.  */
7b26da
-  if (cache->base == 0)
7b26da
-    return;
7b26da
-
7b26da
-  /* Detect OS dependent outermost frames; such as `clone'.  */
7b26da
-  if (tdep->outermost_frame_p && tdep->outermost_frame_p (this_frame))
7b26da
-    return;
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (cache->pc);
7b26da
+  else if (cache->base == 0)
7b26da
+    {
7b26da
+      /* This marks the outermost frame.  */
7b26da
+      return;
7b26da
+    }
7b26da
+  else
7b26da
+    /* Detect OS dependent outermost frames; such as `clone'.  */
7b26da
+    if (tdep->outermost_frame_p && tdep->outermost_frame_p (this_frame))
7b26da
+      return;
7b26da
 
7b26da
   (*this_id) = frame_id_build (cache->base + 16, cache->pc);
7b26da
 }
7b26da
@@ -2528,9 +2529,14 @@ amd64_sigtramp_frame_this_id (struct fra
7b26da
     amd64_sigtramp_frame_cache (this_frame, this_cache);
7b26da
 
7b26da
   if (!cache->base_p)
7b26da
-    return;
7b26da
-
7b26da
-  (*this_id) = frame_id_build (cache->base + 16, get_frame_pc (this_frame));
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (get_frame_pc (this_frame));
7b26da
+  else if (cache->base == 0)
7b26da
+    {
7b26da
+      /* This marks the outermost frame.  */
7b26da
+      return;
7b26da
+    }
7b26da
+  else
7b26da
+    (*this_id) = frame_id_build (cache->base + 16, get_frame_pc (this_frame));
7b26da
 }
7b26da
 
7b26da
 static struct value *
7b26da
@@ -2699,9 +2705,9 @@ amd64_epilogue_frame_this_id (struct fra
7b26da
 							       this_cache);
7b26da
 
7b26da
   if (!cache->base_p)
7b26da
-    return;
7b26da
-
7b26da
-  (*this_id) = frame_id_build (cache->base + 8, cache->pc);
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (cache->pc);
7b26da
+  else
7b26da
+    (*this_id) = frame_id_build (cache->base + 8, cache->pc);
7b26da
 }
7b26da
 
7b26da
 static const struct frame_unwind amd64_epilogue_frame_unwind =
7b26da
Index: gdb-7.6.1/gdb/dwarf2-frame.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/dwarf2-frame.c
7b26da
+++ gdb-7.6.1/gdb/dwarf2-frame.c
7b26da
@@ -1265,12 +1265,11 @@ dwarf2_frame_this_id (struct frame_info
7b26da
     dwarf2_frame_cache (this_frame, this_cache);
7b26da
 
7b26da
   if (cache->unavailable_retaddr)
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (get_frame_func (this_frame));
7b26da
+  else if (cache->undefined_retaddr)
7b26da
     return;
7b26da
-
7b26da
-  if (cache->undefined_retaddr)
7b26da
-    return;
7b26da
-
7b26da
-  (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame));
7b26da
+  else
7b26da
+    (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame));
7b26da
 }
7b26da
 
7b26da
 static struct value *
7b26da
Index: gdb-7.6.1/gdb/frame.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/frame.c
7b26da
+++ gdb-7.6.1/gdb/frame.c
7b26da
@@ -147,10 +147,11 @@ frame_addr_hash (const void *ap)
7b26da
   const struct frame_id f_id = frame->this_id.value;
7b26da
   hashval_t hash = 0;
7b26da
 
7b26da
-  gdb_assert (f_id.stack_addr_p || f_id.code_addr_p
7b26da
+  gdb_assert (f_id.stack_status != FID_STACK_INVALID
7b26da
+	      || f_id.code_addr_p
7b26da
 	      || f_id.special_addr_p);
7b26da
 
7b26da
-  if (f_id.stack_addr_p)
7b26da
+  if (f_id.stack_status == FID_STACK_VALID)
7b26da
     hash = iterative_hash (&f_id.stack_addr,
7b26da
 			   sizeof (f_id.stack_addr), hash);
7b26da
   if (f_id.code_addr_p)
7b26da
@@ -290,13 +291,23 @@ void
7b26da
 fprint_frame_id (struct ui_file *file, struct frame_id id)
7b26da
 {
7b26da
   fprintf_unfiltered (file, "{");
7b26da
-  fprint_field (file, "stack", id.stack_addr_p, id.stack_addr);
7b26da
+
7b26da
+  if (id.stack_status == FID_STACK_INVALID)
7b26da
+    fprintf_unfiltered (file, "!stack");
7b26da
+  else if (id.stack_status == FID_STACK_UNAVAILABLE)
7b26da
+    fprintf_unfiltered (file, "stack=<unavailable>");
7b26da
+  else
7b26da
+    fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr));
7b26da
   fprintf_unfiltered (file, ",");
7b26da
+
7b26da
   fprint_field (file, "code", id.code_addr_p, id.code_addr);
7b26da
   fprintf_unfiltered (file, ",");
7b26da
+
7b26da
   fprint_field (file, "special", id.special_addr_p, id.special_addr);
7b26da
+
7b26da
   if (id.artificial_depth)
7b26da
     fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth);
7b26da
+
7b26da
   fprintf_unfiltered (file, "}");
7b26da
 }
7b26da
 
7b26da
@@ -446,7 +457,7 @@ frame_unwind_caller_id (struct frame_inf
7b26da
 }
7b26da
 
7b26da
 const struct frame_id null_frame_id; /* All zeros.  */
7b26da
-const struct frame_id outer_frame_id = { 0, 0, 0, 0, 0, 1, 0 };
7b26da
+const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 };
7b26da
 
7b26da
 struct frame_id
7b26da
 frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
7b26da
@@ -455,7 +466,7 @@ frame_id_build_special (CORE_ADDR stack_
7b26da
   struct frame_id id = null_frame_id;
7b26da
 
7b26da
   id.stack_addr = stack_addr;
7b26da
-  id.stack_addr_p = 1;
7b26da
+  id.stack_status = FID_STACK_VALID;
7b26da
   id.code_addr = code_addr;
7b26da
   id.code_addr_p = 1;
7b26da
   id.special_addr = special_addr;
7b26da
@@ -463,13 +474,26 @@ frame_id_build_special (CORE_ADDR stack_
7b26da
   return id;
7b26da
 }
7b26da
 
7b26da
+/* See frame.h.  */
7b26da
+
7b26da
+struct frame_id
7b26da
+frame_id_build_unavailable_stack (CORE_ADDR code_addr)
7b26da
+{
7b26da
+  struct frame_id id = null_frame_id;
7b26da
+
7b26da
+  id.stack_status = FID_STACK_UNAVAILABLE;
7b26da
+  id.code_addr = code_addr;
7b26da
+  id.code_addr_p = 1;
7b26da
+  return id;
7b26da
+}
7b26da
+
7b26da
 struct frame_id
7b26da
 frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
7b26da
 {
7b26da
   struct frame_id id = null_frame_id;
7b26da
 
7b26da
   id.stack_addr = stack_addr;
7b26da
-  id.stack_addr_p = 1;
7b26da
+  id.stack_status = FID_STACK_VALID;
7b26da
   id.code_addr = code_addr;
7b26da
   id.code_addr_p = 1;
7b26da
   return id;
7b26da
@@ -481,7 +505,7 @@ frame_id_build_wild (CORE_ADDR stack_add
7b26da
   struct frame_id id = null_frame_id;
7b26da
 
7b26da
   id.stack_addr = stack_addr;
7b26da
-  id.stack_addr_p = 1;
7b26da
+  id.stack_status = FID_STACK_VALID;
7b26da
   return id;
7b26da
 }
7b26da
 
7b26da
@@ -491,7 +515,7 @@ frame_id_p (struct frame_id l)
7b26da
   int p;
7b26da
 
7b26da
   /* The frame is valid iff it has a valid stack address.  */
7b26da
-  p = l.stack_addr_p;
7b26da
+  p = l.stack_status != FID_STACK_INVALID;
7b26da
   /* outer_frame_id is also valid.  */
7b26da
   if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0)
7b26da
     p = 1;
7b26da
@@ -518,19 +542,20 @@ frame_id_eq (struct frame_id l, struct f
7b26da
 {
7b26da
   int eq;
7b26da
 
7b26da
-  if (!l.stack_addr_p && l.special_addr_p
7b26da
-      && !r.stack_addr_p && r.special_addr_p)
7b26da
+  if (l.stack_status == FID_STACK_INVALID && l.special_addr_p
7b26da
+      && r.stack_status == FID_STACK_INVALID && r.special_addr_p)
7b26da
     /* The outermost frame marker is equal to itself.  This is the
7b26da
        dodgy thing about outer_frame_id, since between execution steps
7b26da
        we might step into another function - from which we can't
7b26da
        unwind either.  More thought required to get rid of
7b26da
        outer_frame_id.  */
7b26da
     eq = 1;
7b26da
-  else if (!l.stack_addr_p || !r.stack_addr_p)
7b26da
+  else if (l.stack_status == FID_STACK_INVALID
7b26da
+	   || r.stack_status == FID_STACK_INVALID)
7b26da
     /* Like a NaN, if either ID is invalid, the result is false.
7b26da
        Note that a frame ID is invalid iff it is the null frame ID.  */
7b26da
     eq = 0;
7b26da
-  else if (l.stack_addr != r.stack_addr)
7b26da
+  else if (l.stack_status != r.stack_status || l.stack_addr != r.stack_addr)
7b26da
     /* If .stack addresses are different, the frames are different.  */
7b26da
     eq = 0;
7b26da
   else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr)
7b26da
@@ -597,8 +622,9 @@ frame_id_inner (struct gdbarch *gdbarch,
7b26da
 {
7b26da
   int inner;
7b26da
 
7b26da
-  if (!l.stack_addr_p || !r.stack_addr_p)
7b26da
-    /* Like NaN, any operation involving an invalid ID always fails.  */
7b26da
+  if (l.stack_status != FID_STACK_VALID || r.stack_status != FID_STACK_VALID)
7b26da
+    /* Like NaN, any operation involving an invalid ID always fails.
7b26da
+       Likewise if either ID has an unavailable stack address.  */
7b26da
     inner = 0;
7b26da
   else if (l.artificial_depth > r.artificial_depth
7b26da
 	   && l.stack_addr == r.stack_addr
7b26da
Index: gdb-7.6.1/gdb/frame.h
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/frame.h
7b26da
+++ gdb-7.6.1/gdb/frame.h
7b26da
@@ -76,6 +76,23 @@ struct block;
7b26da
 struct gdbarch;
7b26da
 struct ui_file;
7b26da
 
7b26da
+/* Status of a given frame's stack.  */
7b26da
+
7b26da
+enum frame_id_stack_status
7b26da
+{
7b26da
+  /* Stack address is invalid.  E.g., this frame is the outermost
7b26da
+     (i.e., _start), and the stack hasn't been setup yet.  */
7b26da
+  FID_STACK_INVALID = 0,
7b26da
+
7b26da
+  /* Stack address is valid, and is found in the stack_addr field.  */
7b26da
+  FID_STACK_VALID = 1,
7b26da
+
7b26da
+  /* Stack address is unavailable.  I.e., there's a valid stack, but
7b26da
+     we don't know where it is (because memory or registers we'd
7b26da
+     compute it from were not collected).  */
7b26da
+  FID_STACK_UNAVAILABLE = -1
7b26da
+};
7b26da
+
7b26da
 /* The frame object.  */
7b26da
 
7b26da
 struct frame_info;
7b26da
@@ -97,8 +114,9 @@ struct frame_id
7b26da
      function pointer register or stack pointer register.  They are
7b26da
      wrong.
7b26da
 
7b26da
-     This field is valid only if stack_addr_p is true.  Otherwise, this
7b26da
-     frame represents the null frame.  */
7b26da
+     This field is valid only if frame_id.stack_status is
7b26da
+     FID_STACK_VALID.  It will be 0 for other
7b26da
+     FID_STACK_... statuses.  */
7b26da
   CORE_ADDR stack_addr;
7b26da
 
7b26da
   /* The frame's code address.  This shall be constant through out the
7b26da
@@ -129,7 +147,7 @@ struct frame_id
7b26da
   CORE_ADDR special_addr;
7b26da
 
7b26da
   /* Flags to indicate the above fields have valid contents.  */
7b26da
-  unsigned int stack_addr_p : 1;
7b26da
+  ENUM_BITFIELD(frame_id_stack_status) stack_status : 2;
7b26da
   unsigned int code_addr_p : 1;
7b26da
   unsigned int special_addr_p : 1;
7b26da
 
7b26da
@@ -169,6 +187,12 @@ extern struct frame_id frame_id_build_sp
7b26da
 					       CORE_ADDR code_addr,
7b26da
 					       CORE_ADDR special_addr);
7b26da
 
7b26da
+/* Construct a frame ID representing a frame where the stack address
7b26da
+   exists, but is unavailable.  CODE_ADDR is the frame's constant code
7b26da
+   address (typically the entry point).  The special identifier
7b26da
+   address is set to indicate a wild card.  */
7b26da
+extern struct frame_id frame_id_build_unavailable_stack (CORE_ADDR code_addr);
7b26da
+
7b26da
 /* Construct a wild card frame ID.  The parameter is the frame's constant
7b26da
    stack address (typically the outer-bound).  The code address as well
7b26da
    as the special identifier address are set to indicate wild cards.  */
7b26da
Index: gdb-7.6.1/gdb/i386-tdep.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/i386-tdep.c
7b26da
+++ gdb-7.6.1/gdb/i386-tdep.c
7b26da
@@ -1846,12 +1846,17 @@ i386_frame_this_id (struct frame_info *t
7b26da
 {
7b26da
   struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);
7b26da
 
7b26da
-  /* This marks the outermost frame.  */
7b26da
-  if (cache->base == 0)
7b26da
-    return;
7b26da
-
7b26da
-  /* See the end of i386_push_dummy_call.  */
7b26da
-  (*this_id) = frame_id_build (cache->base + 8, cache->pc);
7b26da
+  if (!cache->base_p)
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (cache->pc);
7b26da
+  else if (cache->base == 0)
7b26da
+    {
7b26da
+      /* This marks the outermost frame.  */
7b26da
+    }
7b26da
+  else
7b26da
+    {
7b26da
+      /* See the end of i386_push_dummy_call.  */
7b26da
+      (*this_id) = frame_id_build (cache->base + 8, cache->pc);
7b26da
+    }
7b26da
 }
7b26da
 
7b26da
 static enum unwind_stop_reason
7b26da
@@ -2032,9 +2037,9 @@ i386_epilogue_frame_this_id (struct fram
7b26da
     i386_epilogue_frame_cache (this_frame, this_cache);
7b26da
 
7b26da
   if (!cache->base_p)
7b26da
-    return;
7b26da
-
7b26da
-  (*this_id) = frame_id_build (cache->base + 8, cache->pc);
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (cache->pc);
7b26da
+  else
7b26da
+    (*this_id) = frame_id_build (cache->base + 8, cache->pc);
7b26da
 }
7b26da
 
7b26da
 static struct value *
7b26da
@@ -2226,10 +2231,12 @@ i386_sigtramp_frame_this_id (struct fram
7b26da
     i386_sigtramp_frame_cache (this_frame, this_cache);
7b26da
 
7b26da
   if (!cache->base_p)
7b26da
-    return;
7b26da
-
7b26da
-  /* See the end of i386_push_dummy_call.  */
7b26da
-  (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
7b26da
+    (*this_id) = frame_id_build_unavailable_stack (get_frame_pc (this_frame));
7b26da
+  else
7b26da
+    {
7b26da
+      /* See the end of i386_push_dummy_call.  */
7b26da
+      (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
7b26da
+    }
7b26da
 }
7b26da
 
7b26da
 static struct value *