* frame.c (frame_register_unwind_location): New function.
authorDaniel Jacobowitz <drow@false.org>
Fri, 10 Nov 2006 20:11:35 +0000 (20:11 +0000)
committerDaniel Jacobowitz <drow@false.org>
Fri, 10 Nov 2006 20:11:35 +0000 (20:11 +0000)
(get_prev_frame_1): Check for UNWIND_NO_SAVED_PC.
(frame_stop_reason_string): Handle UNWIND_NO_SAVED_PC.
* frame.h (enum unwind_stop_reason): Add UNWIND_NO_SAVED_PC.

gdb/ChangeLog
gdb/frame.c
gdb/frame.h

index 2a98c717d41269324a0e1ccf8641f6525e6feac5..e6a4cc482cbb048623c632dd26a6e63f1801af03 100644 (file)
@@ -1,3 +1,10 @@
+2006-11-10  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * frame.c (frame_register_unwind_location): New function.
+       (get_prev_frame_1): Check for UNWIND_NO_SAVED_PC.
+       (frame_stop_reason_string): Handle UNWIND_NO_SAVED_PC.
+       * frame.h (enum unwind_stop_reason): Add UNWIND_NO_SAVED_PC.
+
 2006-11-10  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * arch-utils.c (target_byte_order_user): Renamed from
index 917ec45db47d5ca1e96592d00a7b2e4fbf205ffe..f1b28f7a6f744fa68061fbe549411e0bb4b854d4 100644 (file)
@@ -1023,6 +1023,36 @@ reinit_frame_cache (void)
     }
 }
 
+/* Find where a register is saved (in memory or another register).
+   The result of frame_register_unwind is just where it is saved
+   relative to this particular frame.
+
+   FIXME: alpha, m32c, and h8300 actually do the transitive operation
+   themselves.  */
+
+static void
+frame_register_unwind_location (struct frame_info *this_frame, int regnum,
+                               int *optimizedp, enum lval_type *lvalp,
+                               CORE_ADDR *addrp, int *realnump)
+{
+  gdb_assert (this_frame == NULL || this_frame->level >= 0);
+
+  while (this_frame != NULL)
+    {
+      frame_register_unwind (this_frame, regnum, optimizedp, lvalp,
+                            addrp, realnump, NULL);
+
+      if (*optimizedp)
+       break;
+
+      if (*lvalp != lval_register)
+       break;
+
+      regnum = *realnump;
+      this_frame = get_next_frame (this_frame);
+    }
+}
+
 /* Return a "struct frame_info" corresponding to the frame that called
    THIS_FRAME.  Returns NULL if there is no such frame.
 
@@ -1111,6 +1141,42 @@ get_prev_frame_1 (struct frame_info *this_frame)
       return NULL;
     }
 
+  /* Check that this and the next frame do not unwind the PC register
+     to the same memory location.  If they do, then even though they
+     have different frame IDs, the new frame will be bogus; two
+     functions can't share a register save slot for the PC.  This can
+     happen when the prologue analyzer finds a stack adjustment, but
+     no PC save.  This check does assume that the "PC register" is
+     roughly a traditional PC, even if the gdbarch_unwind_pc method
+     frobs it.  */
+  if (this_frame->level > 0
+      && get_frame_type (this_frame) == NORMAL_FRAME
+      && get_frame_type (this_frame->next) == NORMAL_FRAME)
+    {
+      int optimized, realnum;
+      enum lval_type lval, nlval;
+      CORE_ADDR addr, naddr;
+
+      frame_register_unwind_location (this_frame, PC_REGNUM, &optimized,
+                                     &lval, &addr, &realnum);
+      frame_register_unwind_location (get_next_frame (this_frame), PC_REGNUM,
+                                     &optimized, &nlval, &naddr, &realnum);
+
+      if (lval == lval_memory && lval == nlval && addr == naddr)
+       {
+         if (frame_debug)
+           {
+             fprintf_unfiltered (gdb_stdlog, "-> ");
+             fprint_frame (gdb_stdlog, NULL);
+             fprintf_unfiltered (gdb_stdlog, " // no saved PC }\n");
+           }
+
+         this_frame->stop_reason = UNWIND_NO_SAVED_PC;
+         this_frame->prev = NULL;
+         return NULL;
+       }
+    }
+
   /* Allocate the new frame but do not wire it in to the frame chain.
      Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
      frame->next to pull some fancy tricks (of course such code is, by
@@ -1611,6 +1677,9 @@ frame_stop_reason_string (enum unwind_stop_reason reason)
     case UNWIND_SAME_ID:
       return _("previous frame identical to this frame (corrupt stack?)");
 
+    case UNWIND_NO_SAVED_PC:
+      return _("frame did not save the PC");
+
     case UNWIND_NO_REASON:
     case UNWIND_FIRST_ERROR:
     default:
index 1d6ae9d753d5b675338ed78d31c13faa525e26c7..5843a25c790cd94198ad20a58a617915b9b95eab 100644 (file)
@@ -428,6 +428,10 @@ enum unwind_stop_reason
        this is a sign of unwinder failure.  It could also indicate
        stack corruption.  */
     UNWIND_SAME_ID,
+
+    /* The frame unwinder didn't find any saved PC, but we needed
+       one to unwind further.  */
+    UNWIND_NO_SAVED_PC,
   };
 
 /* Return the reason why we can't unwind past this frame.  */
This page took 0.047868 seconds and 4 git commands to generate.