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

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