Subject: gdb-thread-skip-frame.patch
From: Jim Houston <[email-masked]>
To: Andrew Morton <[email-masked]>
Date: Thu, 8 Jan 2004 21:09:20 -0500 (EST)

Hi Andrew,

In the i386 kgdb_stub, George Anzinger has code to find the first
stack frame which is not in the scheduler.  He returns the register
information for this frame so the "info thread" command will
display an interesting frame.

Doing this on the x86_64 was not as easy because frame pointers
are not used consistently.  The attached patch adds an option to 
gdb to skip over frames which are executing function listed in the
option.

Use:
	set skip-frame thread_return,schedule_timeout

Jim Houston - Concurrent Computer Corp.

--

--- old/gdb-6.0/gdb/thread.c	2004-01-06 12:34:14.786496352 -0500
+++ new/gdb-6.0/gdb/thread.c	2004-01-06 12:34:28.804365312 -0500
@@ -404,6 +404,43 @@
     }
 }
 
+/*
+ * When using gdb as a kernel debugger, its really boring to
+ * see every thread is blocked in schedule.  By setting a
+ * list of functions with "set skip-frame schedule,thread_return" 
+ * we can display the frame that called into the scheduler.
+ */
+static char *skip_frame_string;
+
+int
+skip_frame(struct frame_info *fi)
+{
+  struct minimal_symbol *msym;
+  CORE_ADDR pc;
+  char *name;
+  char *s, *r;
+  int n;
+
+  pc = get_frame_pc (fi);
+  msym = lookup_minimal_symbol_by_pc_section(pc, NULL);
+  if (!msym)
+    return 0;
+  name = SYMBOL_LINKAGE_NAME(msym);
+
+  for (s = skip_frame_string; s && *s ; ) {
+    if ((r = strchr(s, ',')))
+      n = r - s - 1;
+    else
+      n = strlen(s);
+    if (n && strncmp(s, name, n) == 0)
+      return 1;
+    if (!r)
+      break;
+    s = r + 1;
+  }
+  return 0;
+}
+
 /* Print information about currently known threads 
 
  * Note: this has the drawback that it _really_ switches
@@ -416,7 +453,7 @@
 {
   struct thread_info *tp;
   ptid_t current_ptid;
-  struct frame_info *cur_frame;
+  struct frame_info *cur_frame, *fi;
   int saved_frame_level = frame_relative_level (get_selected_frame ());
   int counter;
   char *extra_info;
@@ -448,6 +485,18 @@
       puts_filtered ("  ");
 
       switch_to_thread (tp->ptid);
+
+      if (skip_frame_string) {
+	/* skip up the stack to an interesting frame. */
+        fi = get_selected_frame ();
+        while (fi) {
+          if (!skip_frame(fi))
+            break;
+          fi = get_prev_frame(fi);
+  	  if (fi)
+            select_frame(fi);
+        }
+      }
       print_stack_frame (get_selected_frame (), -1, 0);
     }
 
@@ -740,4 +789,12 @@
 
   if (!xdb_commands)
     add_com_alias ("t", "thread", class_run, 1);
+
+  add_show_from_set (add_set_cmd ("skip-frame", class_obscure,
+    var_string_noescape, (char *)&skip_frame_string, "\
+Set list of functions to skip when choosing the frame to display\n\
+for a info-thread command.  When gdb is used for kernel debug this option\n\
+allows the frame which calls the scheduler to be displayed rather than\n\
+having all blocked threads showing the same function in the scheduler.",
+    &setlist), &showlist);
 }