Blame SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-3of8.patch

2c2fa1
commit 194cca41192efa65f710967e3149bbc813c12b22
2c2fa1
Author: Pedro Alves <palves@redhat.com>
2c2fa1
Date:   Thu Nov 21 15:20:09 2013 +0000
2c2fa1
2c2fa1
    Make use of the frame stash to detect wider stack cycles.
2c2fa1
    
2c2fa1
    Given we already have the frame id stash, which holds the ids of all
2c2fa1
    frames in the chain, detecting corrupted stacks with wide stack cycles
2c2fa1
    with non-consecutive dup frame ids is just as cheap as just detecting
2c2fa1
    cycles in consecutive frames:
2c2fa1
    
2c2fa1
     #0 frame_id1
2c2fa1
     #1 frame_id2
2c2fa1
     #2 frame_id3
2c2fa1
     #3 frame_id1
2c2fa1
     #4 frame_id2
2c2fa1
     #5 frame_id3
2c2fa1
     #6 frame_id1
2c2fa1
     ... forever ...
2c2fa1
    
2c2fa1
    We just need to check whether the stash already knows about a given
2c2fa1
    frame id instead of comparing the ids of the previous/this frames.
2c2fa1
    
2c2fa1
    Tested on x86_64 Fedora 17.
2c2fa1
    
2c2fa1
    gdb/
2c2fa1
    2013-11-22  Pedro Alves  <palves@redhat.com>
2c2fa1
    	    Tom Tromey  <tromey@redhat.com>
2c2fa1
    
2c2fa1
    	* frame.c (frame_stash_add): Now returns whether a frame with the
2c2fa1
    	same ID was already known.
2c2fa1
    	(compute_frame_id): New function, factored out from get_frame_id.
2c2fa1
    	(get_frame_id): No longer lazilly compute the frame id here.
2c2fa1
    	(get_prev_frame_if_no_cycle): New function.  Detects wider stack
2c2fa1
    	cycles.
2c2fa1
    	(get_prev_frame_1): Use it instead of get_prev_frame_raw directly,
2c2fa1
    	and checking for stack cycles here.
2c2fa1
2c2fa1
Index: gdb-7.6.1/gdb/frame.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/frame.c
2c2fa1
+++ gdb-7.6.1/gdb/frame.c
2c2fa1
@@ -189,23 +189,31 @@ frame_stash_create (void)
2c2fa1
 			     NULL);
2c2fa1
 }
2c2fa1
 
2c2fa1
-/* Internal function to add a frame to the frame_stash hash table.  Do
2c2fa1
-   not store frames below 0 as they may not have any addresses to
2c2fa1
-   calculate a hash.  */
2c2fa1
+/* Internal function to add a frame to the frame_stash hash table.
2c2fa1
+   Returns false if a frame with the same ID was already stashed, true
2c2fa1
+   otherwise.  */
2c2fa1
 
2c2fa1
-static void
2c2fa1
+static int
2c2fa1
 frame_stash_add (struct frame_info *frame)
2c2fa1
 {
2c2fa1
-  /* Do not stash frames below level 0.  */
2c2fa1
-  if (frame->level >= 0)
2c2fa1
-    {
2c2fa1
-      struct frame_info **slot;
2c2fa1
+  struct frame_info **slot;
2c2fa1
 
2c2fa1
-      slot = (struct frame_info **) htab_find_slot (frame_stash,
2c2fa1
-						    frame,
2c2fa1
-						    INSERT);
2c2fa1
-      *slot = frame;
2c2fa1
-    }
2c2fa1
+  /* Do not try to stash the sentinel frame.  */
2c2fa1
+  gdb_assert (frame->level >= 0);
2c2fa1
+
2c2fa1
+  slot = (struct frame_info **) htab_find_slot (frame_stash,
2c2fa1
+						frame,
2c2fa1
+						INSERT);
2c2fa1
+
2c2fa1
+  /* If we already have a frame in the stack with the same id, we
2c2fa1
+     either have a stack cycle (corrupted stack?), or some bug
2c2fa1
+     elsewhere in GDB.  In any case, ignore the duplicate and return
2c2fa1
+     an indication to the caller.  */
2c2fa1
+  if (*slot != NULL)
2c2fa1
+    return 0;
2c2fa1
+
2c2fa1
+  *slot = frame;
2c2fa1
+  return 1;
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Internal function to search the frame stash for an entry with the
2c2fa1
@@ -397,6 +405,34 @@ skip_artificial_frames (struct frame_inf
2c2fa1
   return frame;
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* Compute the frame's uniq ID that can be used to, later, re-find the
2c2fa1
+   frame.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+compute_frame_id (struct frame_info *fi)
2c2fa1
+{
2c2fa1
+  gdb_assert (!fi->this_id.p);
2c2fa1
+
2c2fa1
+  if (frame_debug)
2c2fa1
+    fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ",
2c2fa1
+			fi->level);
2c2fa1
+  /* Find the unwinder.  */
2c2fa1
+  if (fi->unwind == NULL)
2c2fa1
+    frame_unwind_find_by_frame (fi, &fi->prologue_cache);
2c2fa1
+  /* Find THIS frame's ID.  */
2c2fa1
+  /* Default to outermost if no ID is found.  */
2c2fa1
+  fi->this_id.value = outer_frame_id;
2c2fa1
+  fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
2c2fa1
+  gdb_assert (frame_id_p (fi->this_id.value));
2c2fa1
+  fi->this_id.p = 1;
2c2fa1
+  if (frame_debug)
2c2fa1
+    {
2c2fa1
+      fprintf_unfiltered (gdb_stdlog, "-> ");
2c2fa1
+      fprint_frame_id (gdb_stdlog, fi->this_id.value);
2c2fa1
+      fprintf_unfiltered (gdb_stdlog, " }\n");
2c2fa1
+    }
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* Return a frame uniq ID that can be used to, later, re-find the
2c2fa1
    frame.  */
2c2fa1
 
2c2fa1
@@ -406,29 +442,7 @@ get_frame_id (struct frame_info *fi)
2c2fa1
   if (fi == NULL)
2c2fa1
     return null_frame_id;
2c2fa1
 
2c2fa1
-  if (!fi->this_id.p)
2c2fa1
-    {
2c2fa1
-      if (frame_debug)
2c2fa1
-	fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
2c2fa1
-			    fi->level);
2c2fa1
-      /* Find the unwinder.  */
2c2fa1
-      if (fi->unwind == NULL)
2c2fa1
-	frame_unwind_find_by_frame (fi, &fi->prologue_cache);
2c2fa1
-      /* Find THIS frame's ID.  */
2c2fa1
-      /* Default to outermost if no ID is found.  */
2c2fa1
-      fi->this_id.value = outer_frame_id;
2c2fa1
-      fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
2c2fa1
-      gdb_assert (frame_id_p (fi->this_id.value));
2c2fa1
-      fi->this_id.p = 1;
2c2fa1
-      if (frame_debug)
2c2fa1
-	{
2c2fa1
-	  fprintf_unfiltered (gdb_stdlog, "-> ");
2c2fa1
-	  fprint_frame_id (gdb_stdlog, fi->this_id.value);
2c2fa1
-	  fprintf_unfiltered (gdb_stdlog, " }\n");
2c2fa1
-	}
2c2fa1
-      frame_stash_add (fi);
2c2fa1
-    }
2c2fa1
-
2c2fa1
+  gdb_assert (fi->this_id.p);
2c2fa1
   return fi->this_id.value;
2c2fa1
 }
2c2fa1
 
2c2fa1
@@ -1678,6 +1692,42 @@ frame_register_unwind_location (struct f
2c2fa1
     }
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* Get the previous raw frame, and check that it is not identical to
2c2fa1
+   same other frame frame already in the chain.  If it is, there is
2c2fa1
+   most likely a stack cycle, so we discard it, and mark THIS_FRAME as
2c2fa1
+   outermost, with UNWIND_SAME_ID stop reason.  Unlike the other
2c2fa1
+   validity tests, that compare THIS_FRAME and the next frame, we do
2c2fa1
+   this right after creating the previous frame, to avoid ever ending
2c2fa1
+   up with two frames with the same id in the frame chain.  */
2c2fa1
+
2c2fa1
+static struct frame_info *
2c2fa1
+get_prev_frame_if_no_cycle (struct frame_info *this_frame)
2c2fa1
+{
2c2fa1
+  struct frame_info *prev_frame;
2c2fa1
+
2c2fa1
+  prev_frame = get_prev_frame_raw (this_frame);
2c2fa1
+  if (prev_frame == NULL)
2c2fa1
+    return NULL;
2c2fa1
+
2c2fa1
+  compute_frame_id (prev_frame);
2c2fa1
+  if (frame_stash_add (prev_frame))
2c2fa1
+    return prev_frame;
2c2fa1
+
2c2fa1
+  /* Another frame with the same id was already in the stash.  We just
2c2fa1
+     detected a cycle.  */
2c2fa1
+  if (frame_debug)
2c2fa1
+    {
2c2fa1
+      fprintf_unfiltered (gdb_stdlog, "-> ");
2c2fa1
+      fprint_frame (gdb_stdlog, NULL);
2c2fa1
+      fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
2c2fa1
+    }
2c2fa1
+  this_frame->stop_reason = UNWIND_SAME_ID;
2c2fa1
+  /* Unlink.  */
2c2fa1
+  prev_frame->next = NULL;
2c2fa1
+  this_frame->prev = NULL;
2c2fa1
+  return NULL;
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* Return a "struct frame_info" corresponding to the frame that called
2c2fa1
    THIS_FRAME.  Returns NULL if there is no such frame.
2c2fa1
 
2c2fa1
@@ -1689,7 +1739,6 @@ get_prev_frame_1 (struct frame_info *thi
2c2fa1
 {
2c2fa1
   struct frame_id this_id;
2c2fa1
   struct gdbarch *gdbarch;
2c2fa1
-  struct frame_info *prev_frame;
2c2fa1
 
2c2fa1
   gdb_assert (this_frame != NULL);
2c2fa1
   gdbarch = get_frame_arch (this_frame);
2c2fa1
@@ -1732,7 +1781,7 @@ get_prev_frame_1 (struct frame_info *thi
2c2fa1
      until we have unwound all the way down to the previous non-inline
2c2fa1
      frame.  */
2c2fa1
   if (get_frame_type (this_frame) == INLINE_FRAME)
2c2fa1
-    return get_prev_frame_raw (this_frame);
2c2fa1
+    return get_prev_frame_if_no_cycle (this_frame);
2c2fa1
 
2c2fa1
   /* Check that this frame is unwindable.  If it isn't, don't try to
2c2fa1
      unwind to the prev frame.  */
2c2fa1
@@ -1838,31 +1887,7 @@ get_prev_frame_1 (struct frame_info *thi
2c2fa1
 	}
2c2fa1
     }
2c2fa1
 
2c2fa1
-  prev_frame = get_prev_frame_raw (this_frame);
2c2fa1
-
2c2fa1
-  /* Check that this and the prev frame are not identical.  If they
2c2fa1
-     are, there is most likely a stack cycle.  Unlike the tests above,
2c2fa1
-     we do this right after creating the prev frame, to avoid ever
2c2fa1
-     ending up with two frames with the same id in the frame
2c2fa1
-     chain.  */
2c2fa1
-  if (prev_frame != NULL
2c2fa1
-      && frame_id_eq (get_frame_id (prev_frame),
2c2fa1
-		      get_frame_id (this_frame)))
2c2fa1
-    {
2c2fa1
-      if (frame_debug)
2c2fa1
-	{
2c2fa1
-	  fprintf_unfiltered (gdb_stdlog, "-> ");
2c2fa1
-	  fprint_frame (gdb_stdlog, NULL);
2c2fa1
-	  fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
2c2fa1
-	}
2c2fa1
-      this_frame->stop_reason = UNWIND_SAME_ID;
2c2fa1
-      /* Unlink.  */
2c2fa1
-      prev_frame->next = NULL;
2c2fa1
-      this_frame->prev = NULL;
2c2fa1
-      return NULL;
2c2fa1
-    }
2c2fa1
-
2c2fa1
-  return prev_frame;
2c2fa1
+  return get_prev_frame_if_no_cycle (this_frame);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Construct a new "struct frame_info" and link it previous to