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

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