public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [Patch] Bug 8287: Skip uninteresting functions while debugging
@ 2010-06-18 18:56 Justin Lebar
  2010-06-18 19:37 ` Michael Snyder
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Justin Lebar @ 2010-06-18 18:56 UTC (permalink / raw)
  To: gdb-patches

This adds support for a "blacklist" which contains files and functions
which are skipped while single-stepping.  This patch also fixes bug
11614: decode_variable() in linespec.c does not obey its contract

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index fc148fe..5d2c23e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -653,6 +653,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c
ada-valprint.c ada-tasks.c \
 	auxv.c ax-general.c ax-gdb.c \
 	bcache.c \
 	bfd-target.c \
+	blacklist.c \
 	block.c blockframe.c breakpoint.c buildsym.c \
 	c-exp.y c-lang.c c-typeprint.c c-valprint.c \
 	charset.c cli-out.c coffread.c coff-pe-read.c \
@@ -772,7 +773,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h
frame-unwind.h	\
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
-psymtab.h psympriv.h
+psymtab.h psympriv.h blacklist.h

 # Header files that already have srcdir in them, or which are in objdir.

@@ -806,6 +807,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	addrmap.o \
 	auxv.o \
 	bfd-target.o \
+	blacklist.o \
 	blockframe.o breakpoint.o findvar.o regcache.o \
 	charset.o disasm.o dummy-frame.o dfp.o \
 	source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
diff --git a/gdb/blacklist.c b/gdb/blacklist.c
new file mode 100644
index 0000000..2bd65cc
--- /dev/null
+++ b/gdb/blacklist.c
@@ -0,0 +1,555 @@
+/* Header for GDB line completion.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "blacklist.h"
+#include "value.h"
+#include "valprint.h"
+#include "ui-out.h"
+#include "gdb_string.h"
+#include "symtab.h"
+#include "gdbcmd.h"
+#include "command.h"
+#include "completer.h"
+#include "stack.h"
+#include "arch-utils.h"
+#include "linespec.h"
+#include "objfiles.h"
+
+struct blacklist_entry
+{
+  int number;
+
+  /* null if this isn't a blacklist entry for an entire file.
+     The blacklist entry owns this pointer. */
+  char *filename;
+
+  /* The name of the blacklisted function, if this is a blacklist entry for a
+     function.  Note that this might be non-null even if the pc is 0 if the
+     entry is pending a shared library load.
+
+     The blacklist entry owns this pointer. */
+  char *function_name;
+
+  /* 0 if this is a blacklist entry for an entire file, or if this entry will
+     be on a function, pending a shared library load. */
+  CORE_ADDR pc;
+
+  /* Architecture we used to create the blacklist entry. May be null
+     if the entry is pending a shared library load. */
+  struct gdbarch *gdbarch;
+
+  int enabled;
+  int pending;
+
+  struct blacklist_entry *next;
+};
+
+static void blacklist_function_command (char *arg, int from_tty);
+static void blacklist_file_command (char *arg, int from_tty);
+static void blacklist_info (char *arg, int from_tty);
+
+static void add_blacklist_entry (struct blacklist_entry *b);
+static void blacklist_function_pc (CORE_ADDR pc, char *name,
+				   struct gdbarch *arch,
+				   int pending);
+static void try_resolve_pending_entry (struct blacklist_entry *b);
+static struct gdbarch *get_sal_arch (struct symtab_and_line *sal);
+
+static struct blacklist_entry *blacklist_entry_chain;
+static int blacklist_entry_count;
+
+#define ALL_BLACKLIST_ENTRIES(B) for (B = blacklist_entry_chain; B; B
= B->next)
+
+static void
+blacklist_file_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  struct symtab *symtab;
+  int pending = 0;
+  char *filename = 0;
+
+  /* If no argument was given, try to default to the last
+     displayed codepoint. */
+  if (arg == 0)
+    {
+      symtab = get_last_displayed_symtab ();
+      if (symtab == 0)
+	error (_("No default blacklist file now."));
+      else
+	filename = symtab->filename;
+    }
+  else
+    {
+      symtab = lookup_symtab (arg);
+      if (symtab == 0)
+	{
+	  fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg);
+	  if (!nquery (_("\
+Add file to blacklist pending future shared library load? ")))
+	    return;
+
+	  pending = 1;
+	  filename = arg;
+	}
+      else
+	filename = symtab->filename;
+    }
+
+  b = XZALLOC (struct blacklist_entry);
+  b->filename = strdup(filename);
+  b->enabled = 1;
+  b->pending = pending;
+  if (symtab != 0)
+    b->gdbarch = get_objfile_arch (symtab->objfile);
+
+  add_blacklist_entry (b);
+
+  printf_filtered ("Blacklisting file %s.\n", filename);
+}
+
+static void
+blacklist_function_command (char *arg, int from_tty)
+{
+  CORE_ADDR func_pc;
+  char *name = NULL;
+
+  /* Default to the current function if no argument is given. */
+  if (arg == 0)
+    {
+      CORE_ADDR pc;
+      if (!last_displayed_codepoint_is_valid ())
+	error (_("No default blacklist function now."));
+
+      pc = get_last_displayed_addr ();
+      if (!find_pc_partial_function (pc, &name, &func_pc, 0))
+	{
+	  error (_("No function found containing current program point %s."),
+		  paddress (get_current_arch (), pc));
+	}
+      blacklist_function_pc (func_pc, name, get_current_arch (), 0);
+    }
+  else
+    {
+      /* Decode arg.  We set funfirstline=1 so decode_line_1 will give us the
+	 first line of the function specified, if it can, and so that we'll
+	 reject variable names and the like. */
+
+      /* TODO maybe want something like parse_breakpoint_sals ()
+         in breakpoint.c. */
+      int i;
+      int not_found = 0;
+      int pending = 0;
+      char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */
+      struct symtabs_and_lines sals = decode_line_1 (&arg, 1, 0, 0, 0,
+						     &not_found);
+
+      if (not_found)
+	{
+	  fprintf_filtered (gdb_stderr,
+			    _("No function found named %s.\n"), orig_arg);
+
+	  if (nquery (_("\
+Add function to blacklist pending future shared library load? ")))
+	    {
+	      /* Add the pending blacklist entry. */
+	      blacklist_function_pc (0, orig_arg, 0, 1);
+	    }
+
+	  return;
+	}
+
+      if (sals.nelts == 0)
+	error (_("No function to blacklist.")); /* TODO can I trigger this? */
+      if (sals.nelts > 1)
+	error (_("Specify just one function at a time.")); /* TODO can I
trigger this? */
+      if (strlen (arg) != 0)
+	error (_("Junk at end of arguments."));
+
+      /* The pc decode_line_1 gives us is the first line of the function,
+	 but we actually want the line before that.  The call to
+	 find_pc_partial_function gets us the value we actually want. */
+      {
+	struct symtab_and_line *sal = &sals.sals[0];
+	CORE_ADDR pc = sal->pc;
+	CORE_ADDR func_start = 0;
+	struct gdbarch *arch = get_sal_arch (sal);
+
+	if (!find_pc_partial_function (pc, &name, &func_start, 0))
+	  {
+	    error (_("No function found containing program point %s."),
+		     paddress (arch, pc));
+	  }
+
+	blacklist_function_pc (func_start, name, arch, 0);
+      }
+    }
+}
+
+static void
+blacklist_info (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  int num_printable_entries = 0;
+  int entry_num = -1;
+  int address_width = 10;
+  struct value_print_options opts;
+  struct cleanup *tbl_chain;
+
+  get_user_print_options (&opts);
+
+  if (arg != 0)
+    {
+      entry_num = parse_and_eval_long (arg);
+    }
+
+  /* Count the number of rows in the table and see if we need space for a
+     64-bit address anywhere. */
+  ALL_BLACKLIST_ENTRIES (b)
+    if (entry_num == -1 || b->number == entry_num)
+      {
+	num_printable_entries++;
+	if (b->gdbarch && gdbarch_addr_bit (b->gdbarch) > 32)
+	  address_width = 18;
+      }
+
+  if (num_printable_entries == 0)
+    {
+      if (entry_num == -1)
+	ui_out_message (uiout, 0, "Blacklist is empty.\n");
+      else
+	ui_out_message (uiout, 0,
+			"No blacklist entry numbered %d.\n", entry_num);
+
+      return;
+    }
+
+  if (opts.addressprint)
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (uiout, 5, num_printable_entries,
+					      "BlacklistTable");
+  else
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (uiout, 4, num_printable_entries,
+					      "BlacklistTable");
+
+  ui_out_table_header (uiout, 7, ui_left, "number", "Num");
   /* 1 */
+  ui_out_table_header (uiout, 14, ui_left, "type", "Type");
   /* 2 */
+  ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");
   /* 3 */
+  if (opts.addressprint)
+    {
+      ui_out_table_header (uiout, address_width, ui_left,
+			   "addr", "Address");                           /* 4 */
+    }
+  ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
   /* 5 */
+  ui_out_table_body (uiout);
+
+  ALL_BLACKLIST_ENTRIES (b)
+    {
+      struct cleanup *entry_chain;
+
+      QUIT;
+      if (entry_num != -1 && entry_num != b->number)
+	continue;
+
+      entry_chain = make_cleanup_ui_out_tuple_begin_end (uiout,
"blklst-entry");
+      ui_out_field_int (uiout, "number", b->number);
   /* 1 */
+
+      if (b->function_name != 0)
+	ui_out_field_string (uiout, "type", "function");                 /* 2 */
+      else if (b->filename != 0)
+	ui_out_field_string (uiout, "type", "file");                     /* 2 */
+      else
+	internal_error (__FILE__, __LINE__, _("\
+Blacklist entry should have either a filename or a function name."));
+
+      if (b->enabled)
+	ui_out_field_string (uiout, "enabled", "y");                     /* 3 */
+      else
+	ui_out_field_string (uiout, "enabled", "n");                     /* 3 */
+
+      if (opts.addressprint)
+	{
+	  if (b->pc != 0)
+	    ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
+	  else
+	    ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
+	}
+
+      if (!b->pending && b->function_name != 0)
+	{
+	   struct symbol *sym;
+	   gdb_assert (b->pc != 0);
+	   sym = find_pc_function (b->pc);
+	   if (sym)
+	     ui_out_field_fmt (uiout, "what", "%s at %s:%d",
+			       sym->ginfo.name,
+			       sym->symtab->filename,
+			       sym->line);
+	   else
+	     ui_out_field_string (uiout, "what", "?");
+	}
+      else if (b->pending && b->function_name != 0)
+	{
+	  ui_out_field_fmt (uiout, "what", "%s (PENDING)",
+			    b->function_name);
+	}
+      else if (!b->pending && b->filename != 0)
+	ui_out_field_string (uiout, "what", b->filename);
+      else if (b->pending && b->filename != 0)
+	ui_out_field_fmt (uiout, "what", "%s (PENDING)",
+			  b->filename);
+
+      ui_out_text (uiout, "\n");
+      do_cleanups (entry_chain);
+    }
+
+  do_cleanups (tbl_chain);
+}
+
+static void
+blacklist_enable_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  int entry_num = parse_and_eval_long (arg);
+  ALL_BLACKLIST_ENTRIES (b)
+    if (b->number == entry_num)
+      {
+	b->enabled = 1;
+	return;
+      }
+
+  error (_("No blacklist entry numbered %d."), entry_num);
+}
+
+static void
+blacklist_disable_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  int entry_num = parse_and_eval_long (arg);
+  ALL_BLACKLIST_ENTRIES (b)
+    if (b->number == entry_num)
+      {
+	b->enabled = 0;
+	return;
+      }
+
+  error (_("No blacklist entry numbered %d."), entry_num);
+}
+
+static void
+blacklist_delete_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b, *b_prev;
+  int entry_num = parse_and_eval_long (arg);
+
+  /* We don't need to use a SAFE macro here since we return as soon as we
+     remove an element from the list. */
+  b_prev = 0;
+  ALL_BLACKLIST_ENTRIES (b)
+    if (b->number == entry_num)
+      {
+	if (b_prev != 0)
+	  b_prev->next = b->next;
+	else
+	  blacklist_entry_chain = b->next;
+
+	xfree (b->function_name);
+	xfree (b->filename);
+	xfree (b);
+	return;
+      }
+    else
+      {
+	b_prev = b;
+      }
+
+  error (_("No blacklist entry numbered %d."), entry_num);
+}
+
+static void
+blacklist_function_pc (CORE_ADDR pc, char *name, struct gdbarch *arch,
+		       int pending)
+{
+  struct blacklist_entry *b = XZALLOC (struct blacklist_entry);
+  b->pc = pc;
+  b->gdbarch = arch;
+  b->enabled = 1;
+  b->pending = pending;
+  b->function_name = strdup (name);
+
+  add_blacklist_entry (b);
+
+  if (!pending)
+    printf_filtered ("Blacklisting function %s at %s.\n",
+		     name, paddress (get_current_arch (), pc));
+  else
+    printf_filtered ("Blacklisting function %s pending shared library load.\n",
+		     name);
+}
+
+static void
+add_blacklist_entry (struct blacklist_entry *b)
+{
+  struct blacklist_entry *b1;
+
+  b->number = ++blacklist_entry_count;
+
+  /* Add to the end of the chain so that the list of
+     blacklist entries will be in numerical order. */
+
+  b1 = blacklist_entry_chain;
+  if (b1 == 0)
+    blacklist_entry_chain = b;
+  else
+    {
+      while (b1->next)
+	b1 = b1->next;
+      b1->next = b;
+    }
+}
+
+int
+function_pc_is_blacklisted (CORE_ADDR pc)
+{
+  struct symtab_and_line sal;
+  char *filename;
+  struct blacklist_entry *b;
+
+  sal = find_pc_line (pc, 0);
+  filename = sal.symtab->filename;
+
+  ALL_BLACKLIST_ENTRIES (b)
+    {
+      /* First, check whether the file or function this entry is pending on has
+	 been loaded.  It might be more sensible to do this on a solib load,
+	 but that doesn't seem to work for some reason. */
+      if (b->pending)
+	try_resolve_pending_entry (b);
+
+      if (b->enabled && !b->pending
+	  && ((b->pc != 0 && pc == b->pc)
+	      || (b->filename != 0 && filename != 0
+	          && strcmp (filename, b->filename) == 0)))
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Try to look up the file or function corresponding to the given blacklist
+   entry.  If the file or function now exists, update the entry and unmark it
+   as pending. */
+static void
+try_resolve_pending_entry (struct blacklist_entry *b)
+{
+  if (!b->pending)
+    return;
+
+  if (b->filename != 0)
+    {
+      struct symtab *symtab = lookup_symtab (b->filename);
+      if (symtab != 0)
+	{
+	  xfree (b->filename);
+	  b->filename = strdup (symtab->filename);
+	  b->gdbarch = get_objfile_arch (symtab->objfile);
+	  b->pending = 0;
+	}
+    }
+  else if (b->function_name != 0)
+    {
+      int not_found = 0;
+      char *func_name = b->function_name;
+      struct symtabs_and_lines sals = decode_line_1 (&func_name, 1, 0, 0, 0,
+						     &not_found);
+
+      if (!not_found && sals.nelts == 1 && strlen (func_name) == 0)
+	{
+	  struct symtab_and_line *sal = &sals.sals[0];
+	  CORE_ADDR pc = sal->pc;
+	  CORE_ADDR func_start = 0;
+	  struct gdbarch *arch = get_sal_arch (sal);
+
+	  if (find_pc_partial_function (pc, &b->function_name, &func_start, 0))
+	    {
+	      b->pending = 0;
+	      b->pc = func_start;
+	      b->gdbarch = arch;
+	    }
+	}
+    }
+}
+
+static struct gdbarch*
+get_sal_arch (struct symtab_and_line *sal)
+{
+  if (sal->section)
+    return get_objfile_arch (sal->section->objfile);
+  if (sal->symtab)
+    return get_objfile_arch (sal->symtab->objfile);
+  return get_current_arch ();
+}
+
+void
+_initialize_step_blacklist (void)
+{
+  struct cmd_list_element *c;
+
+  blacklist_entry_chain = 0;
+  blacklist_entry_count = 0;
+
+  add_prefix_cmd ("blacklist", class_blacklist,
blacklist_function_command, _("\
+Ignore a function while stepping.\n\
+blacklist [FUNCTION NAME]\n\
+If no function name is given, blacklist the current function."),
+                  &blacklistlist, "blacklist ", 1, &cmdlist);
+
+  c = add_cmd ("file", class_blacklist, blacklist_file_command, _("\
+Ignore a file while stepping.\n\
+blacklist file [FILENAME]\n\
+If no filename is given, blacklist the current file."),
+	       &blacklistlist);
+  set_cmd_completer (c, filename_completer);
+
+  c = add_cmd ("function", class_blacklist, blacklist_function_command, _("\
+Ignore a function while stepping.\n\
+blacklist function [FUNCTION NAME]\n\
+If no function name is given, blacklist the current function."),
+	       &blacklistlist);
+  set_cmd_completer (c, location_completer);
+
+  add_cmd ("enable", class_blacklist, blacklist_enable_command, _("\
+Enable a blacklist entry.\n\
+blacklist enable [NUMBER]"),
+	   &blacklistlist);
+
+  add_cmd ("disable", class_blacklist, blacklist_disable_command, _("\
+Disable a blacklist entry.\n\
+blacklist disable [NUMBER]"),
+	   &blacklistlist);
+
+  add_cmd ("delete", class_blacklist, blacklist_delete_command, _("\
+Delete a blacklist entry.\n\
+blacklist delete [NUMBER]"),
+           &blacklistlist);
+
+  add_info ("blacklist", blacklist_info, _("\
+Status of blacklist, or of blacklist entry NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tfile        - blacklisted file\n\
+\tfunction    - blacklisted function"));
+}
diff --git a/gdb/blacklist.h b/gdb/blacklist.h
new file mode 100644
index 0000000..94d1d93
--- /dev/null
+++ b/gdb/blacklist.h
@@ -0,0 +1,21 @@
+/* Header for GDB line completion.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Returns 1 if the given pc was blacklisted and shouldn't be stepped into.
+   Otherwise, returns 0. */
+
+int
+function_pc_is_blacklisted (CORE_ADDR pc);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3dca17e..8f60bd4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -61,6 +61,7 @@
 #include "valprint.h"
 #include "jit.h"
 #include "xml-syscall.h"
+#include "stack.h"

 /* readline include files */
 #include "readline/readline.h"
@@ -527,19 +528,6 @@ make_cleanup_decref_counted_command_line (struct
counted_command_line **cmdp)
   return make_cleanup (do_cleanup_counted_command_line, cmdp);
 }

-/* Default address, symtab and line to put a breakpoint at
-   for "break" command with no arg.
-   if default_breakpoint_valid is zero, the other three are
-   not valid, and "break" with no arg is an error.
-
-   This set by print_stack_frame, which calls set_default_breakpoint.  */
-
-int default_breakpoint_valid;
-CORE_ADDR default_breakpoint_address;
-struct symtab *default_breakpoint_symtab;
-int default_breakpoint_line;
-struct program_space *default_breakpoint_pspace;
-

 /* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
    Advance *PP after the string and any trailing whitespace.
@@ -5174,20 +5162,6 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
     }
 }

-/* Set the default place to put a breakpoint
-   for the `break' command with no arguments.  */
-
-void
-set_default_breakpoint (int valid, struct program_space *pspace,
-			CORE_ADDR addr, struct symtab *symtab,
-			int line)
-{
-  default_breakpoint_valid = valid;
-  default_breakpoint_pspace = pspace;
-  default_breakpoint_address = addr;
-  default_breakpoint_symtab = symtab;
-  default_breakpoint_line = line;
-}

 /* Return true iff it is meaningful to use the address member of
    BPT.  For some breakpoint types, the address member is irrelevant
@@ -7120,20 +7094,23 @@ parse_breakpoint_sals (char **address,
   if ((*address) == NULL
       || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
     {
-      if (default_breakpoint_valid)
+      /* The last displayed codepoint, if it's valid, is our default breakpoint
+         address. */
+      if (last_displayed_codepoint_is_valid ())
 	{
 	  struct symtab_and_line sal;
 	  init_sal (&sal);		/* initialize to zeroes */
 	  sals->sals = (struct symtab_and_line *)
 	    xmalloc (sizeof (struct symtab_and_line));
-	  sal.pc = default_breakpoint_address;
-	  sal.line = default_breakpoint_line;
-	  sal.symtab = default_breakpoint_symtab;
-	  sal.pspace = default_breakpoint_pspace;
+
+	  /* Set sal's pspace, pc, symtab, and line to the values corresponding
+	     to the last call to print_frame_info. */
+	  set_sal_to_last_displayed_codepoint (&sal);
+
 	  sal.section = find_pc_overlay (sal.pc);

 	  /* "break" without arguments is equivalent to "break *PC" where PC is
-	     the default_breakpoint_address.  So make sure to set
+	     the last displayed codepoint's address.  So make sure to set
 	     sal.explicit_pc to prevent GDB from trying to expand the list of
 	     sals to include all other instances with the same symtab and line.
 	   */
@@ -7150,19 +7127,22 @@ parse_breakpoint_sals (char **address,
       /* Force almost all breakpoints to be in terms of the
          current_source_symtab (which is decode_line_1's default).  This
          should produce the results we want almost all of the time while
-         leaving default_breakpoint_* alone.
+         leaving the last displayed codepoint pointers alone.
          ObjC: However, don't match an Objective-C method name which
          may have a '+' or '-' succeeded by a '[' */
 	
       struct symtab_and_line cursal = get_current_source_symtab_and_line ();
 			
-      if (default_breakpoint_valid
+      if (last_displayed_codepoint_is_valid ()
 	  && (!cursal.symtab
  	      || ((strchr ("+-", (*address)[0]) != NULL)
  		  && ((*address)[1] != '['))))
-	*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
-			       default_breakpoint_line, addr_string,
-			       not_found_ptr);
+	{
+	  *sals = decode_line_1 (address, 1,
+				 get_last_displayed_symtab (),
+				 get_last_displayed_line (),
+				 addr_string, not_found_ptr);
+	}
       else
 	*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
 		               addr_string, not_found_ptr);
@@ -7336,7 +7316,6 @@ create_breakpoint (struct gdbarch *gdbarch,
   struct captured_parse_breakpoint_args parse_args;
   int i;
   int pending = 0;
-  int not_found = 0;
   enum bptype type_wanted;
   int task = 0;
   int prev_bkpt_count = breakpoint_count;
@@ -7348,7 +7327,7 @@ create_breakpoint (struct gdbarch *gdbarch,
   parse_args.arg_p = &arg;
   parse_args.sals_p = &sals;
   parse_args.addr_string_p = &addr_string;
-  parse_args.not_found_ptr = &not_found;
+  parse_args.not_found_ptr = 0;

   e = catch_exception (uiout, do_captured_parse_breakpoint,
 		       &parse_args, RETURN_MASK_ALL);
@@ -8083,9 +8062,11 @@ until_break_command (char *arg, int from_tty,
int anywhere)
   /* Set a breakpoint where the user wants it and at return from
      this function */

-  if (default_breakpoint_valid)
-    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
-			  default_breakpoint_line, (char ***) NULL, NULL);
+  if (last_displayed_codepoint_is_valid ())
+    sals = decode_line_1 (&arg, 1,
+			  get_last_displayed_symtab (),
+			  get_last_displayed_line (),
+			  (char ***) NULL, NULL);
   else
     sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
 			  0, (char ***) NULL, NULL);
@@ -8673,10 +8654,11 @@ clear_command (char *arg, int from_tty)
 	xmalloc (sizeof (struct symtab_and_line));
       make_cleanup (xfree, sals.sals);
       init_sal (&sal);		/* initialize to zeroes */
-      sal.line = default_breakpoint_line;
-      sal.symtab = default_breakpoint_symtab;
-      sal.pc = default_breakpoint_address;
-      sal.pspace = default_breakpoint_pspace;
+
+      /* Set sal's line, symtab, pc, and pspace to the values corresponding to
+	 the last call to print_frame_info.  If the codepoint is not valid,
+	 this will set all the fields to 0. */
+      set_sal_to_last_displayed_codepoint (&sal);
       if (sal.symtab == 0)
 	error (_("No source file specified."));

@@ -10181,7 +10163,8 @@ invalidate_bp_value_on_memory_change
(CORE_ADDR addr, int len,
       }
 }

-/* Use default_breakpoint_'s, or nothing if they aren't valid.  */
+/* Use the last displayed codepoint's values, or nothing
+   if they aren't valid. */

 struct symtabs_and_lines
 decode_line_spec_1 (char *string, int funfirstline)
@@ -10189,11 +10172,13 @@ decode_line_spec_1 (char *string, int funfirstline)
   struct symtabs_and_lines sals;
   if (string == 0)
     error (_("Empty line specification."));
-  if (default_breakpoint_valid)
-    sals = decode_line_1 (&string, funfirstline,
-			  default_breakpoint_symtab,
-			  default_breakpoint_line,
-			  (char ***) NULL, NULL);
+  if (last_displayed_codepoint_is_valid ())
+    {
+      sals = decode_line_1 (&string, funfirstline,
+			    get_last_displayed_symtab (),
+			    get_last_displayed_line (),
+			    (char ***) NULL, NULL);
+    }
   else
     sals = decode_line_1 (&string, funfirstline,
 			  (struct symtab *) NULL, 0, (char ***) NULL, NULL);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 8b7a5c6..50602b2 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -789,9 +789,6 @@ extern struct breakpoint
*clone_momentary_breakpoint (struct breakpoint *bpkt);

 extern void set_ignore_count (int, int, int);

-extern void set_default_breakpoint (int, struct program_space *,
-				    CORE_ADDR, struct symtab *, int);
-
 extern void breakpoint_init_inferior (enum inf_context);

 extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index fdeb8db..c401eed 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -185,6 +185,8 @@ struct cmd_list_element *setchecklist;

 struct cmd_list_element *showchecklist;

+struct cmd_list_element *blacklistlist;
+
 /* Command tracing state.  */

 int source_verbose = 0;
@@ -1308,6 +1310,7 @@ init_cmd_lists (void)
   showprintlist = NULL;
   setchecklist = NULL;
   showchecklist = NULL;
+  blacklistlist = NULL;
 }

 static void
@@ -1372,7 +1375,7 @@ init_cli_cmds (void)
   char *source_help_text;

   /* Define the classes of commands.
-     They will appear in the help list in the reverse of this order.  */
+     They will appear in the help list in alphabetical order.  */

   add_cmd ("internals", class_maintenance, NULL, _("\
 Maintenance commands.\n\
diff --git a/gdb/command.h b/gdb/command.h
index a746c82..27cdc33 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -33,7 +33,7 @@ enum command_class
   no_class = -1, class_run = 0, class_vars, class_stack,
   class_files, class_support, class_info, class_breakpoint, class_trace,
   class_alias, class_bookmark, class_obscure, class_maintenance,
-  class_pseudo, class_tui, class_user, class_xdb
+  class_pseudo, class_tui, class_user, class_xdb, class_blacklist
 };

 /* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
index 6a230c0..d561e73 100644
--- a/gdb/gdbcmd.h
+++ b/gdb/gdbcmd.h
@@ -124,6 +124,8 @@ extern struct cmd_list_element *setchecklist;

 extern struct cmd_list_element *showchecklist;

+extern struct cmd_list_element *blacklistlist;
+
 extern void execute_command (char *, int);

 enum command_control_type execute_control_command (struct command_line *);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5f58759..7402fee 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -52,6 +52,7 @@
 #include "inline-frame.h"
 #include "jit.h"
 #include "tracepoint.h"
+#include "blacklist.h"

 /* Prototypes for local functions */

@@ -4490,7 +4491,8 @@ infrun: not switching back to stepped thread, it
has vanished\n");
 	}

       /* If we have line number information for the function we are
-         thinking of stepping into, step into it.
+         thinking of stepping into and the function isn't blacklisted,
+	 step into it.

          If there are several symtabs at that PC (e.g. with include
          files), just want to know whether *any* of them have line
@@ -4500,7 +4502,8 @@ infrun: not switching back to stepped thread, it
has vanished\n");

 	tmp_sal = find_pc_line (ecs->stop_func_start, 0);
 	tmp_sal.pspace = get_frame_program_space (frame);
-	if (tmp_sal.line != 0)
+	if (tmp_sal.line != 0 &&
+	    !function_pc_is_blacklisted (ecs->stop_func_start))
 	  {
 	    if (execution_direction == EXEC_REVERSE)
 	      handle_step_into_function_backward (gdbarch, ecs);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index c5ea28a..19727b5 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1857,7 +1857,13 @@ decode_variable (char *copy, int funfirstline,
char ***canonical,
     return minsym_found (funfirstline, msymbol);

   if (not_found_ptr)
-    *not_found_ptr = 1;
+    {
+      struct symtabs_and_lines sals;
+      *not_found_ptr = 1;
+      sals.sals = 0;
+      sals.nelts = 0;
+      return sals;
+    }

   if (!have_full_symbols ()
       && !have_partial_symbols ()
diff --git a/gdb/stack.c b/gdb/stack.c
index 53d4aeb..14febd9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -73,6 +73,12 @@ static void print_frame (struct frame_info *frame,
int print_level,
 			 enum print_what print_what,  int print_args,
 			 struct symtab_and_line sal);

+static void set_last_displayed_codepoint (int valid,
+					  struct program_space *pspace,
+			                  CORE_ADDR addr,
+					  struct symtab *symtab,
+			                  int line);
+
 /* Zero means do things normally; we are interacting directly with the
    user.  One means print the full filename and linenumber when a
    frame is printed, and do so in a format emacs18/emacs19.22 can
@@ -80,6 +86,14 @@ static void print_frame (struct frame_info *frame,
int print_level,
    cases and in a slightly different syntax.  */

 int annotation_level = 0;
+
+/* These variables hold the last codepoint we displayed to the user.  This is
+   where we insert a breakpoint or a blacklist entry by default. */
+static int last_codepoint_valid = 0;
+static struct program_space *last_codepoint_pspace = 0;
+static CORE_ADDR last_codepoint_addr = 0;
+static struct symtab *last_codepoint_symtab = 0;
+static int last_codepoint_line = 0;


 struct print_stack_frame_args
@@ -650,14 +664,96 @@ print_frame_info (struct frame_info *frame, int
print_level,
     }

   if (print_what != LOCATION)
-    set_default_breakpoint (1, sal.pspace,
-			    get_frame_pc (frame), sal.symtab, sal.line);
+    set_last_displayed_codepoint (1, sal.pspace,
+			          get_frame_pc (frame), sal.symtab,
+				  sal.line);

   annotate_frame_end ();

   gdb_flush (gdb_stdout);
 }

+/* Remember the last codepoint we displayed, which we use e.g. as the place to
+   put a breakpoint when the `break' command is invoked with no arguments. */
+static void
+set_last_displayed_codepoint (int valid, struct program_space *pspace,
+			      CORE_ADDR addr, struct symtab *symtab,
+			      int line)
+{
+  last_codepoint_valid = valid;
+  last_codepoint_pspace = pspace;
+  last_codepoint_addr = addr;
+  last_codepoint_symtab = symtab;
+  last_codepoint_line = line;
+}
+
+void
+clear_last_displayed_codepoint ()
+{
+  last_codepoint_valid = 0;
+  last_codepoint_pspace = 0;
+  last_codepoint_addr = 0;
+  last_codepoint_symtab = 0;
+  last_codepoint_line = 0;
+}
+
+int
+last_displayed_codepoint_is_valid ()
+{
+  return last_codepoint_valid;
+}
+
+struct program_space*
+get_last_displayed_pspace ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_pspace;
+  return 0;
+}
+
+CORE_ADDR
+get_last_displayed_addr ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_addr;
+  return 0;
+}
+
+struct symtab*
+get_last_displayed_symtab ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_symtab;
+  return 0;
+}
+
+int
+get_last_displayed_line ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_line;
+  return 0;
+}
+
+void
+set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal)
+{
+  if (last_codepoint_valid)
+    {
+      sal->pspace = last_codepoint_pspace;
+      sal->pc = last_codepoint_addr;
+      sal->symtab = last_codepoint_symtab;
+      sal->line = last_codepoint_line;
+    }
+  else
+    {
+      sal->pspace = 0;
+      sal->pc = 0;
+      sal->symtab = 0;
+      sal->line = 0;
+    }
+}
+
 /* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding
    to FRAME.  */
 void
diff --git a/gdb/stack.h b/gdb/stack.h
index 5e874b4..fa08035 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -39,4 +39,14 @@ void iterate_over_block_local_vars (struct block *block,
 				    iterate_over_block_arg_local_vars_cb cb,
 				    void *cb_data);

+/* Get or set the last displayed codepoint, which is, e.g. where we set a
+   breakpoint when `break' is supplied with no arguments. */
+void clear_last_displayed_codepoint ();
+int last_displayed_codepoint_is_valid ();
+struct program_space* get_last_displayed_pspace ();
+CORE_ADDR get_last_displayed_addr ();
+struct symtab* get_last_displayed_symtab ();
+int get_last_displayed_line ();
+void set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal);
+
 #endif /* #ifndef STACK_H */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index eda26cc..b56badf 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -56,6 +56,7 @@
 #include "elf-bfd.h"
 #include "solib.h"
 #include "remote.h"
+#include "stack.h"

 #include <sys/types.h>
 #include <fcntl.h>
@@ -2709,7 +2710,7 @@ clear_symtab_users (void)

   clear_displays ();
   breakpoint_re_set ();
-  set_default_breakpoint (0, NULL, 0, 0, 0);
+  clear_last_displayed_codepoint ();
   clear_pc_function_cache ();
   observer_notify_new_objfile (NULL);

diff --git a/gdb/testsuite/gdb.base/Makefile.in
b/gdb/testsuite/gdb.base/Makefile.in
index 5e8e385..bd54184 100644
--- a/gdb/testsuite/gdb.base/Makefile.in
+++ b/gdb/testsuite/gdb.base/Makefile.in
@@ -1,7 +1,7 @@
 VPATH = @srcdir@
 srcdir = @srcdir@

-EXECUTABLES = all-types annota1 bitfields break \
+EXECUTABLES = all-types annota1 bitfields blacklist blacklist-solib break \
 	call-ar-st call-rt-st call-strs callfuncs callfwmall \
 	chng-syms commands compiler condbreak constvars coremaker \
 	dbx-test display ending-run execd-prog exprs \
diff --git a/gdb/testsuite/gdb.base/blacklist-solib-lib.c
b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
new file mode 100644
index 0000000..792cd01
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
@@ -0,0 +1,11 @@
+/* Simple shared library */
+
+int square(int num)
+{
+  return multiply(num, num);
+}
+
+int multiply(int a, int b)
+{
+  return a * b;
+}
diff --git a/gdb/testsuite/gdb.base/blacklist-solib-main.c
b/gdb/testsuite/gdb.base/blacklist-solib-main.c
new file mode 100644
index 0000000..746bb5f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist-solib-main.c
@@ -0,0 +1,6 @@
+int square(int num);
+
+int main()
+{
+  return square(0);
+}
diff --git a/gdb/testsuite/gdb.base/blacklist-solib.exp
b/gdb/testsuite/gdb.base/blacklist-solib.exp
new file mode 100644
index 0000000..b713394
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist-solib.exp
@@ -0,0 +1,129 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Justin Lebar. (justin.lebar@gmail.com)
+
+#
+# Tests blacklisting shared libraries.
+#
+
+# This only works on GNU/Linux.
+if { ![isnative] || [is_remote host] || ![istarget *-linux*] ||
[skip_shlib_tests]} {
+    continue
+}
+
+set test "blacklist-solib"
+set srcfile_main "${test}-main.c"
+set binfile_main "${objdir}/${subdir}/${test}-test"
+set srcfile_lib "${test}-lib.c"
+set libname "lib${test}"
+set binfile_lib ${objdir}/${subdir}/${libname}.so
+
+#
+# Compile our program under test.  The main program references a shared library
+# libblacklist-solib.so, which contains two functions, square(), which is
+# referenced by the main program, and multiply(), which is not referenced by
+# the main program.
+#
+
+if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib}
${binfile_lib} [list debug
additional_flags=-Wl,-soname,${libname}.so]] != ""} {
+    return -1
+}
+
+if {[gdb_compile "${srcdir}/${subdir}/${srcfile_main}"
"${binfile_main}.o" object debug] != ""} {
+    return -1
+}
+
+if {[gdb_compile "${binfile_main}.o" "${binfile_main}" executable \
+                 [list debug "additional_flags=-L${objdir}/${subdir}
-l${test} \
+
-Wl,-rpath=${objdir}/${subdir}"]] != ""} {
+    return -1
+}
+
+gdb_start
+gdb_load ${binfile_main}
+
+#
+# At this point, if we try to blacklist the file ${srcfile_lib} or the function
+# multiply(), we should get a prompt asking us if we want to enable the
+# blacklist entry pending a shared library load.
+#
+
+gdb_test "blacklist file ${srcfile_lib}" \
+"Blacklisting file ${srcfile_lib}." \
+"blacklisting file in solib" \
+"No source file named ${srcfile_lib}.*
+Add file to blacklist pending future shared library load.*"\
+"y"
+
+#
+# Does info blacklist list this entry as pending?
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+n/a\\s+${srcfile_lib} \\(PENDING\\)\\s*" \
+"info blacklist with pending file"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+
+#
+# We shouldn't step into square(), since we blacklisted blacklist-solib-lib.c.
+#
+gdb_test "step" ""
+gdb_test "bt" "#0\\s+main.*" "step after blacklisting solib file."
+
+#
+# Our entry should no longer be pending.  Note that we unfortunately need to do
+# at least one step before the entry will be unmarked as pending.
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+n/a\\s+.*${srcfile_lib}\\s*" \
+"info blacklist with pending file"
+
+#
+# Now restart gdb and testing blacklisting of a function inside a solib.
+#
+gdb_exit
+gdb_start
+gdb_load ${binfile_main}
+
+gdb_test "blacklist function multiply" \
+"Blacklisting function multiply pending shared library load." \
+"blacklisting function in solib" \
+"No function found named multiply..*
+Add function to blacklist pending future shared library load.*"\
+"y"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+
+#
+# Our first step should take us into square.
+#
+gdb_test "step" "square.*"
+
+#
+# Now our entry should no longer be pending.
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+function\\s+y\\s+0x\[0-9a-f\]+\\s+multiply at .*${srcfile_lib}:.*\\s*" \
+
+#
+# This step shouldn't go into multiply -- we should skip it and go on to the
+# last line of square.
+#
+gdb_test "step" ""
+gdb_test "bt" "#0\\s+square.*"
diff --git a/gdb/testsuite/gdb.base/blacklist.c
b/gdb/testsuite/gdb.base/blacklist.c
new file mode 100644
index 0000000..565ba93
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist.c
@@ -0,0 +1,13 @@
+int foo();
+int bar();
+int baz(int, int);
+
+int main()
+{
+  return baz(foo(), bar());
+}
+
+int foo()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/blacklist.exp
b/gdb/testsuite/gdb.base/blacklist.exp
new file mode 100644
index 0000000..ed1afb8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist.exp
@@ -0,0 +1,140 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Justin Lebar. (justin.lebar@gmail.com)
+
+if { [prepare_for_testing blacklist.exp "blacklist" \
+                          {blacklist.c blacklist1.c } \
+                          {debug nowarnings}] } {
+    return -1
+}
+
+set srcfile blacklist.c
+set srcfile1 blacklist1.c
+
+#
+# Right after we start gdb, there's no default file or function to blacklist.
+#
+gdb_test "blacklist file" "No default blacklist file now."
+gdb_test "blacklist function" "No default blacklist function now."
+gdb_test "blacklist" "No default blacklist function now."
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+
+#
+# Test |info blacklist| with an empty blacklist.
+#
+gdb_test "info blacklist" "Blacklist is empty." "info blacklist empty"
+
+#
+# Create a blacklist entry for the current file and function.
+#
+gdb_test "blacklist file" "Blacklisting file .*$srcfile."
+gdb_test "blacklist" "Blacklisting function main() at .*\."
+
+#
+# Create a blacklist entry for a specified file and function.
+#
+gdb_test "blacklist file blacklist1.c" "Blacklisting file .*$srcfile1."
+gdb_test "blacklist function baz" "Blacklisting function baz at .*"
+
+#
+# Test bad blacklist entry modification commands
+#
+gdb_test "blacklist enable 999" "No blacklist entry numbered 999."
+gdb_test "blacklist disable 999" "No blacklist entry numbered 999."
+gdb_test "blacklist delete 999" "No blacklist entry numbered 999."
+gdb_test "blacklist enable" "Argument required \\(expression to compute\\)."
+gdb_test "blacklist disable" "Argument required \\(expression to compute\\)."
+gdb_test "blacklist delete" "Argument required \\(expression to compute\\)."
+gdb_test "blacklist enable a" "No symbol \"a\" in current context."
+gdb_test "blacklist disable a" "No symbol \"a\" in current context."
+gdb_test "blacklist delete a" "No symbol \"a\" in current context."
+
+#
+# Test that blacklist function doesn't allow extra characters at the end of its
+# arguments list.
+#
+gdb_test "blacklist function foo bar" "Junk at end of arguments."
+
+#
+# Ask for info on a blacklist entry which doesn't exist.
+#
+gdb_test "info blacklist 999" "No blacklist entry numbered 999."
+
+#
+# Does |info blacklist| look right?
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+n/a.*$srcfile\\s*
+2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
+4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
+
+#
+# Right now, we have an outstanding blacklist on both source files, so when we
+# step into the first line in main(), we should step right over it and go to
+# the second line of main().
+#
+if ![runto_main] { fail "blacklist tests suppressed" }
+send_gdb "step\n"
+gdb_test "bt" "#0\\s+main.*" "step after all blacklisted"
+
+#
+# Now remove blacklist.c from the blacklist.  Our first step should take us
+# into foo(), and our second step should take us to the next line in main().
+#
+send_gdb "blacklist delete 1\n"
+# Check that entry 1 is missing from |info blacklist|
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
+4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
+
+#
+# Now disable our blacklisting of blacklist1.c.  We should now step into foo(),
+# then into bar(), but not into baz().
+#
+send_gdb "blacklist disable 3\n"
+# Is entry 3 disabled in |info blacklist|?
+gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+n.*" \
+         "info blacklist shows entry as disabled"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+gdb_test "step" "bar \\(\\) at.*" "step after disabling 3 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "foo \\(\\) at.*" "step after disabling 3 (2)"
+send_gdb "step\n"; # Return from bar()
+gdb_test "step" "main \\(\\) at.*" "step after disabling 3 (3)"
+
+#
+# Enable blacklist entry 3 and make sure we step over it like before.
+#
+send_gdb "blacklist enable 3\n"
+# Is entry 3 enabled in |info blacklist|?
+gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+y.*" \
+         "info blacklist shows entry as enabled"
+if ![runto_main] { fail "blacklist tests suppressed" }
+gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
+
diff --git a/gdb/testsuite/gdb.base/blacklist1.c
b/gdb/testsuite/gdb.base/blacklist1.c
new file mode 100644
index 0000000..2dab5c3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist1.c
@@ -0,0 +1,9 @@
+int bar()
+{
+  return 1;
+}
+
+int baz(int a, int b)
+{
+  return a + b;
+}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-06-18 18:56 [Patch] Bug 8287: Skip uninteresting functions while debugging Justin Lebar
@ 2010-06-18 19:37 ` Michael Snyder
  2010-06-18 20:58   ` Eli Zaretskii
  2010-06-20  7:03 ` Hui Zhu
  2010-06-25 21:57 ` Tom Tromey
  2 siblings, 1 reply; 10+ messages in thread
From: Michael Snyder @ 2010-06-18 19:37 UTC (permalink / raw)
  To: Justin Lebar; +Cc: gdb-patches

Justin Lebar wrote:
> This adds support for a "blacklist" which contains files and functions
> which are skipped while single-stepping.  This patch also fixes bug
> 11614: decode_variable() in linespec.c does not obey its contract

Greetings, welcome, and thanks for your submission.

There are a few problems, mostly things we usually encounter with new
contributors.

First, I can't apply your patch.  There are line wrappings, character
substitutions when I save the email, and so on.  Would you mind trying
to send the patch as a plain text attachment?

Second, we need a ChangeLog entry.  See gdb/ChangeLog for examples
of how those are composed and formatted.

Finally, have you got a copyright assignment filed?

Cheers,
Michael Snyder

> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index fc148fe..5d2c23e 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -653,6 +653,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c
> ada-valprint.c ada-tasks.c \
>         auxv.c ax-general.c ax-gdb.c \
>         bcache.c \
>         bfd-target.c \
> +       blacklist.c \
>         block.c blockframe.c breakpoint.c buildsym.c \
>         c-exp.y c-lang.c c-typeprint.c c-valprint.c \
>         charset.c cli-out.c coffread.c coff-pe-read.c \
> @@ -772,7 +773,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h
> frame-unwind.h  \
>  remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
>  sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
>  gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
> -psymtab.h psympriv.h
> +psymtab.h psympriv.h blacklist.h
> 
>  # Header files that already have srcdir in them, or which are in objdir.
> 
> @@ -806,6 +807,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>         addrmap.o \
>         auxv.o \
>         bfd-target.o \
> +       blacklist.o \
>         blockframe.o breakpoint.o findvar.o regcache.o \
>         charset.o disasm.o dummy-frame.o dfp.o \
>         source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
> diff --git a/gdb/blacklist.c b/gdb/blacklist.c
> new file mode 100644
> index 0000000..2bd65cc
> --- /dev/null
> +++ b/gdb/blacklist.c
> @@ -0,0 +1,555 @@
> +/* Header for GDB line completion.
> +   Copyright (C) 2010 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "blacklist.h"
> +#include "value.h"
> +#include "valprint.h"
> +#include "ui-out.h"
> +#include "gdb_string.h"
> +#include "symtab.h"
> +#include "gdbcmd.h"
> +#include "command.h"
> +#include "completer.h"
> +#include "stack.h"
> +#include "arch-utils.h"
> +#include "linespec.h"
> +#include "objfiles.h"
> +
> +struct blacklist_entry
> +{
> +  int number;
> +
> +  /* null if this isn't a blacklist entry for an entire file.
> +     The blacklist entry owns this pointer. */
> +  char *filename;
> +
> +  /* The name of the blacklisted function, if this is a blacklist entry for a
> +     function.  Note that this might be non-null even if the pc is 0 if the
> +     entry is pending a shared library load.
> +
> +     The blacklist entry owns this pointer. */
> +  char *function_name;
> +
> +  /* 0 if this is a blacklist entry for an entire file, or if this entry will
> +     be on a function, pending a shared library load. */
> +  CORE_ADDR pc;
> +
> +  /* Architecture we used to create the blacklist entry. May be null
> +     if the entry is pending a shared library load. */
> +  struct gdbarch *gdbarch;
> +
> +  int enabled;
> +  int pending;
> +
> +  struct blacklist_entry *next;
> +};
> +
> +static void blacklist_function_command (char *arg, int from_tty);
> +static void blacklist_file_command (char *arg, int from_tty);
> +static void blacklist_info (char *arg, int from_tty);
> +
> +static void add_blacklist_entry (struct blacklist_entry *b);
> +static void blacklist_function_pc (CORE_ADDR pc, char *name,
> +                                  struct gdbarch *arch,
> +                                  int pending);
> +static void try_resolve_pending_entry (struct blacklist_entry *b);
> +static struct gdbarch *get_sal_arch (struct symtab_and_line *sal);
> +
> +static struct blacklist_entry *blacklist_entry_chain;
> +static int blacklist_entry_count;
> +
> +#define ALL_BLACKLIST_ENTRIES(B) for (B = blacklist_entry_chain; B; B
> = B->next)
> +
> +static void
> +blacklist_file_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  struct symtab *symtab;
> +  int pending = 0;
> +  char *filename = 0;
> +
> +  /* If no argument was given, try to default to the last
> +     displayed codepoint. */
> +  if (arg == 0)
> +    {
> +      symtab = get_last_displayed_symtab ();
> +      if (symtab == 0)
> +       error (_("No default blacklist file now."));
> +      else
> +       filename = symtab->filename;
> +    }
> +  else
> +    {
> +      symtab = lookup_symtab (arg);
> +      if (symtab == 0)
> +       {
> +         fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg);
> +         if (!nquery (_("\
> +Add file to blacklist pending future shared library load? ")))
> +           return;
> +
> +         pending = 1;
> +         filename = arg;
> +       }
> +      else
> +       filename = symtab->filename;
> +    }
> +
> +  b = XZALLOC (struct blacklist_entry);
> +  b->filename = strdup(filename);
> +  b->enabled = 1;
> +  b->pending = pending;
> +  if (symtab != 0)
> +    b->gdbarch = get_objfile_arch (symtab->objfile);
> +
> +  add_blacklist_entry (b);
> +
> +  printf_filtered ("Blacklisting file %s.\n", filename);
> +}
> +
> +static void
> +blacklist_function_command (char *arg, int from_tty)
> +{
> +  CORE_ADDR func_pc;
> +  char *name = NULL;
> +
> +  /* Default to the current function if no argument is given. */
> +  if (arg == 0)
> +    {
> +      CORE_ADDR pc;
> +      if (!last_displayed_codepoint_is_valid ())
> +       error (_("No default blacklist function now."));
> +
> +      pc = get_last_displayed_addr ();
> +      if (!find_pc_partial_function (pc, &name, &func_pc, 0))
> +       {
> +         error (_("No function found containing current program point %s."),
> +                 paddress (get_current_arch (), pc));
> +       }
> +      blacklist_function_pc (func_pc, name, get_current_arch (), 0);
> +    }
> +  else
> +    {
> +      /* Decode arg.  We set funfirstline=1 so decode_line_1 will give us the
> +        first line of the function specified, if it can, and so that we'll
> +        reject variable names and the like. */
> +
> +      /* TODO maybe want something like parse_breakpoint_sals ()
> +         in breakpoint.c. */
> +      int i;
> +      int not_found = 0;
> +      int pending = 0;
> +      char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */
> +      struct symtabs_and_lines sals = decode_line_1 (&arg, 1, 0, 0, 0,
> +                                                    &not_found);
> +
> +      if (not_found)
> +       {
> +         fprintf_filtered (gdb_stderr,
> +                           _("No function found named %s.\n"), orig_arg);
> +
> +         if (nquery (_("\
> +Add function to blacklist pending future shared library load? ")))
> +           {
> +             /* Add the pending blacklist entry. */
> +             blacklist_function_pc (0, orig_arg, 0, 1);
> +           }
> +
> +         return;
> +       }
> +
> +      if (sals.nelts == 0)
> +       error (_("No function to blacklist.")); /* TODO can I trigger this? */
> +      if (sals.nelts > 1)
> +       error (_("Specify just one function at a time.")); /* TODO can I
> trigger this? */
> +      if (strlen (arg) != 0)
> +       error (_("Junk at end of arguments."));
> +
> +      /* The pc decode_line_1 gives us is the first line of the function,
> +        but we actually want the line before that.  The call to
> +        find_pc_partial_function gets us the value we actually want. */
> +      {
> +       struct symtab_and_line *sal = &sals.sals[0];
> +       CORE_ADDR pc = sal->pc;
> +       CORE_ADDR func_start = 0;
> +       struct gdbarch *arch = get_sal_arch (sal);
> +
> +       if (!find_pc_partial_function (pc, &name, &func_start, 0))
> +         {
> +           error (_("No function found containing program point %s."),
> +                    paddress (arch, pc));
> +         }
> +
> +       blacklist_function_pc (func_start, name, arch, 0);
> +      }
> +    }
> +}
> +
> +static void
> +blacklist_info (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  int num_printable_entries = 0;
> +  int entry_num = -1;
> +  int address_width = 10;
> +  struct value_print_options opts;
> +  struct cleanup *tbl_chain;
> +
> +  get_user_print_options (&opts);
> +
> +  if (arg != 0)
> +    {
> +      entry_num = parse_and_eval_long (arg);
> +    }
> +
> +  /* Count the number of rows in the table and see if we need space for a
> +     64-bit address anywhere. */
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (entry_num == -1 || b->number == entry_num)
> +      {
> +       num_printable_entries++;
> +       if (b->gdbarch && gdbarch_addr_bit (b->gdbarch) > 32)
> +         address_width = 18;
> +      }
> +
> +  if (num_printable_entries == 0)
> +    {
> +      if (entry_num == -1)
> +       ui_out_message (uiout, 0, "Blacklist is empty.\n");
> +      else
> +       ui_out_message (uiout, 0,
> +                       "No blacklist entry numbered %d.\n", entry_num);
> +
> +      return;
> +    }
> +
> +  if (opts.addressprint)
> +    tbl_chain
> +       = make_cleanup_ui_out_table_begin_end (uiout, 5, num_printable_entries,
> +                                             "BlacklistTable");
> +  else
> +    tbl_chain
> +       = make_cleanup_ui_out_table_begin_end (uiout, 4, num_printable_entries,
> +                                             "BlacklistTable");
> +
> +  ui_out_table_header (uiout, 7, ui_left, "number", "Num");
>    /* 1 */
> +  ui_out_table_header (uiout, 14, ui_left, "type", "Type");
>    /* 2 */
> +  ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");
>    /* 3 */
> +  if (opts.addressprint)
> +    {
> +      ui_out_table_header (uiout, address_width, ui_left,
> +                          "addr", "Address");                           /* 4 */
> +    }
> +  ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
>    /* 5 */
> +  ui_out_table_body (uiout);
> +
> +  ALL_BLACKLIST_ENTRIES (b)
> +    {
> +      struct cleanup *entry_chain;
> +
> +      QUIT;
> +      if (entry_num != -1 && entry_num != b->number)
> +       continue;
> +
> +      entry_chain = make_cleanup_ui_out_tuple_begin_end (uiout,
> "blklst-entry");
> +      ui_out_field_int (uiout, "number", b->number);
>    /* 1 */
> +
> +      if (b->function_name != 0)
> +       ui_out_field_string (uiout, "type", "function");                 /* 2 */
> +      else if (b->filename != 0)
> +       ui_out_field_string (uiout, "type", "file");                     /* 2 */
> +      else
> +       internal_error (__FILE__, __LINE__, _("\
> +Blacklist entry should have either a filename or a function name."));
> +
> +      if (b->enabled)
> +       ui_out_field_string (uiout, "enabled", "y");                     /* 3 */
> +      else
> +       ui_out_field_string (uiout, "enabled", "n");                     /* 3 */
> +
> +      if (opts.addressprint)
> +       {
> +         if (b->pc != 0)
> +           ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
> +         else
> +           ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
> +       }
> +
> +      if (!b->pending && b->function_name != 0)
> +       {
> +          struct symbol *sym;
> +          gdb_assert (b->pc != 0);
> +          sym = find_pc_function (b->pc);
> +          if (sym)
> +            ui_out_field_fmt (uiout, "what", "%s at %s:%d",
> +                              sym->ginfo.name,
> +                              sym->symtab->filename,
> +                              sym->line);
> +          else
> +            ui_out_field_string (uiout, "what", "?");
> +       }
> +      else if (b->pending && b->function_name != 0)
> +       {
> +         ui_out_field_fmt (uiout, "what", "%s (PENDING)",
> +                           b->function_name);
> +       }
> +      else if (!b->pending && b->filename != 0)
> +       ui_out_field_string (uiout, "what", b->filename);
> +      else if (b->pending && b->filename != 0)
> +       ui_out_field_fmt (uiout, "what", "%s (PENDING)",
> +                         b->filename);
> +
> +      ui_out_text (uiout, "\n");
> +      do_cleanups (entry_chain);
> +    }
> +
> +  do_cleanups (tbl_chain);
> +}
> +
> +static void
> +blacklist_enable_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  int entry_num = parse_and_eval_long (arg);
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (b->number == entry_num)
> +      {
> +       b->enabled = 1;
> +       return;
> +      }
> +
> +  error (_("No blacklist entry numbered %d."), entry_num);
> +}
> +
> +static void
> +blacklist_disable_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  int entry_num = parse_and_eval_long (arg);
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (b->number == entry_num)
> +      {
> +       b->enabled = 0;
> +       return;
> +      }
> +
> +  error (_("No blacklist entry numbered %d."), entry_num);
> +}
> +
> +static void
> +blacklist_delete_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b, *b_prev;
> +  int entry_num = parse_and_eval_long (arg);
> +
> +  /* We don't need to use a SAFE macro here since we return as soon as we
> +     remove an element from the list. */
> +  b_prev = 0;
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (b->number == entry_num)
> +      {
> +       if (b_prev != 0)
> +         b_prev->next = b->next;
> +       else
> +         blacklist_entry_chain = b->next;
> +
> +       xfree (b->function_name);
> +       xfree (b->filename);
> +       xfree (b);
> +       return;
> +      }
> +    else
> +      {
> +       b_prev = b;
> +      }
> +
> +  error (_("No blacklist entry numbered %d."), entry_num);
> +}
> +
> +static void
> +blacklist_function_pc (CORE_ADDR pc, char *name, struct gdbarch *arch,
> +                      int pending)
> +{
> +  struct blacklist_entry *b = XZALLOC (struct blacklist_entry);
> +  b->pc = pc;
> +  b->gdbarch = arch;
> +  b->enabled = 1;
> +  b->pending = pending;
> +  b->function_name = strdup (name);
> +
> +  add_blacklist_entry (b);
> +
> +  if (!pending)
> +    printf_filtered ("Blacklisting function %s at %s.\n",
> +                    name, paddress (get_current_arch (), pc));
> +  else
> +    printf_filtered ("Blacklisting function %s pending shared library load.\n",
> +                    name);
> +}
> +
> +static void
> +add_blacklist_entry (struct blacklist_entry *b)
> +{
> +  struct blacklist_entry *b1;
> +
> +  b->number = ++blacklist_entry_count;
> +
> +  /* Add to the end of the chain so that the list of
> +     blacklist entries will be in numerical order. */
> +
> +  b1 = blacklist_entry_chain;
> +  if (b1 == 0)
> +    blacklist_entry_chain = b;
> +  else
> +    {
> +      while (b1->next)
> +       b1 = b1->next;
> +      b1->next = b;
> +    }
> +}
> +
> +int
> +function_pc_is_blacklisted (CORE_ADDR pc)
> +{
> +  struct symtab_and_line sal;
> +  char *filename;
> +  struct blacklist_entry *b;
> +
> +  sal = find_pc_line (pc, 0);
> +  filename = sal.symtab->filename;
> +
> +  ALL_BLACKLIST_ENTRIES (b)
> +    {
> +      /* First, check whether the file or function this entry is pending on has
> +        been loaded.  It might be more sensible to do this on a solib load,
> +        but that doesn't seem to work for some reason. */
> +      if (b->pending)
> +       try_resolve_pending_entry (b);
> +
> +      if (b->enabled && !b->pending
> +         && ((b->pc != 0 && pc == b->pc)
> +             || (b->filename != 0 && filename != 0
> +                 && strcmp (filename, b->filename) == 0)))
> +       return 1;
> +    }
> +
> +  return 0;
> +}
> +
> +/* Try to look up the file or function corresponding to the given blacklist
> +   entry.  If the file or function now exists, update the entry and unmark it
> +   as pending. */
> +static void
> +try_resolve_pending_entry (struct blacklist_entry *b)
> +{
> +  if (!b->pending)
> +    return;
> +
> +  if (b->filename != 0)
> +    {
> +      struct symtab *symtab = lookup_symtab (b->filename);
> +      if (symtab != 0)
> +       {
> +         xfree (b->filename);
> +         b->filename = strdup (symtab->filename);
> +         b->gdbarch = get_objfile_arch (symtab->objfile);
> +         b->pending = 0;
> +       }
> +    }
> +  else if (b->function_name != 0)
> +    {
> +      int not_found = 0;
> +      char *func_name = b->function_name;
> +      struct symtabs_and_lines sals = decode_line_1 (&func_name, 1, 0, 0, 0,
> +                                                    &not_found);
> +
> +      if (!not_found && sals.nelts == 1 && strlen (func_name) == 0)
> +       {
> +         struct symtab_and_line *sal = &sals.sals[0];
> +         CORE_ADDR pc = sal->pc;
> +         CORE_ADDR func_start = 0;
> +         struct gdbarch *arch = get_sal_arch (sal);
> +
> +         if (find_pc_partial_function (pc, &b->function_name, &func_start, 0))
> +           {
> +             b->pending = 0;
> +             b->pc = func_start;
> +             b->gdbarch = arch;
> +           }
> +       }
> +    }
> +}
> +
> +static struct gdbarch*
> +get_sal_arch (struct symtab_and_line *sal)
> +{
> +  if (sal->section)
> +    return get_objfile_arch (sal->section->objfile);
> +  if (sal->symtab)
> +    return get_objfile_arch (sal->symtab->objfile);
> +  return get_current_arch ();
> +}
> +
> +void
> +_initialize_step_blacklist (void)
> +{
> +  struct cmd_list_element *c;
> +
> +  blacklist_entry_chain = 0;
> +  blacklist_entry_count = 0;
> +
> +  add_prefix_cmd ("blacklist", class_blacklist,
> blacklist_function_command, _("\
> +Ignore a function while stepping.\n\
> +blacklist [FUNCTION NAME]\n\
> +If no function name is given, blacklist the current function."),
> +                  &blacklistlist, "blacklist ", 1, &cmdlist);
> +
> +  c = add_cmd ("file", class_blacklist, blacklist_file_command, _("\
> +Ignore a file while stepping.\n\
> +blacklist file [FILENAME]\n\
> +If no filename is given, blacklist the current file."),
> +              &blacklistlist);
> +  set_cmd_completer (c, filename_completer);
> +
> +  c = add_cmd ("function", class_blacklist, blacklist_function_command, _("\
> +Ignore a function while stepping.\n\
> +blacklist function [FUNCTION NAME]\n\
> +If no function name is given, blacklist the current function."),
> +              &blacklistlist);
> +  set_cmd_completer (c, location_completer);
> +
> +  add_cmd ("enable", class_blacklist, blacklist_enable_command, _("\
> +Enable a blacklist entry.\n\
> +blacklist enable [NUMBER]"),
> +          &blacklistlist);
> +
> +  add_cmd ("disable", class_blacklist, blacklist_disable_command, _("\
> +Disable a blacklist entry.\n\
> +blacklist disable [NUMBER]"),
> +          &blacklistlist);
> +
> +  add_cmd ("delete", class_blacklist, blacklist_delete_command, _("\
> +Delete a blacklist entry.\n\
> +blacklist delete [NUMBER]"),
> +           &blacklistlist);
> +
> +  add_info ("blacklist", blacklist_info, _("\
> +Status of blacklist, or of blacklist entry NUMBER.\n\
> +The \"Type\" column indicates one of:\n\
> +\tfile        - blacklisted file\n\
> +\tfunction    - blacklisted function"));
> +}
> diff --git a/gdb/blacklist.h b/gdb/blacklist.h
> new file mode 100644
> index 0000000..94d1d93
> --- /dev/null
> +++ b/gdb/blacklist.h
> @@ -0,0 +1,21 @@
> +/* Header for GDB line completion.
> +   Copyright (C) 2010 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* Returns 1 if the given pc was blacklisted and shouldn't be stepped into.
> +   Otherwise, returns 0. */
> +
> +int
> +function_pc_is_blacklisted (CORE_ADDR pc);
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 3dca17e..8f60bd4 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -61,6 +61,7 @@
>  #include "valprint.h"
>  #include "jit.h"
>  #include "xml-syscall.h"
> +#include "stack.h"
> 
>  /* readline include files */
>  #include "readline/readline.h"
> @@ -527,19 +528,6 @@ make_cleanup_decref_counted_command_line (struct
> counted_command_line **cmdp)
>    return make_cleanup (do_cleanup_counted_command_line, cmdp);
>  }
> 
> -/* Default address, symtab and line to put a breakpoint at
> -   for "break" command with no arg.
> -   if default_breakpoint_valid is zero, the other three are
> -   not valid, and "break" with no arg is an error.
> -
> -   This set by print_stack_frame, which calls set_default_breakpoint.  */
> -
> -int default_breakpoint_valid;
> -CORE_ADDR default_breakpoint_address;
> -struct symtab *default_breakpoint_symtab;
> -int default_breakpoint_line;
> -struct program_space *default_breakpoint_pspace;
> -
> 
>  /* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
>     Advance *PP after the string and any trailing whitespace.
> @@ -5174,20 +5162,6 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
>      }
>  }
> 
> -/* Set the default place to put a breakpoint
> -   for the `break' command with no arguments.  */
> -
> -void
> -set_default_breakpoint (int valid, struct program_space *pspace,
> -                       CORE_ADDR addr, struct symtab *symtab,
> -                       int line)
> -{
> -  default_breakpoint_valid = valid;
> -  default_breakpoint_pspace = pspace;
> -  default_breakpoint_address = addr;
> -  default_breakpoint_symtab = symtab;
> -  default_breakpoint_line = line;
> -}
> 
>  /* Return true iff it is meaningful to use the address member of
>     BPT.  For some breakpoint types, the address member is irrelevant
> @@ -7120,20 +7094,23 @@ parse_breakpoint_sals (char **address,
>    if ((*address) == NULL
>        || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
>      {
> -      if (default_breakpoint_valid)
> +      /* The last displayed codepoint, if it's valid, is our default breakpoint
> +         address. */
> +      if (last_displayed_codepoint_is_valid ())
>         {
>           struct symtab_and_line sal;
>           init_sal (&sal);              /* initialize to zeroes */
>           sals->sals = (struct symtab_and_line *)
>             xmalloc (sizeof (struct symtab_and_line));
> -         sal.pc = default_breakpoint_address;
> -         sal.line = default_breakpoint_line;
> -         sal.symtab = default_breakpoint_symtab;
> -         sal.pspace = default_breakpoint_pspace;
> +
> +         /* Set sal's pspace, pc, symtab, and line to the values corresponding
> +            to the last call to print_frame_info. */
> +         set_sal_to_last_displayed_codepoint (&sal);
> +
>           sal.section = find_pc_overlay (sal.pc);
> 
>           /* "break" without arguments is equivalent to "break *PC" where PC is
> -            the default_breakpoint_address.  So make sure to set
> +            the last displayed codepoint's address.  So make sure to set
>              sal.explicit_pc to prevent GDB from trying to expand the list of
>              sals to include all other instances with the same symtab and line.
>            */
> @@ -7150,19 +7127,22 @@ parse_breakpoint_sals (char **address,
>        /* Force almost all breakpoints to be in terms of the
>           current_source_symtab (which is decode_line_1's default).  This
>           should produce the results we want almost all of the time while
> -         leaving default_breakpoint_* alone.
> +         leaving the last displayed codepoint pointers alone.
>           ObjC: However, don't match an Objective-C method name which
>           may have a '+' or '-' succeeded by a '[' */
> 
>        struct symtab_and_line cursal = get_current_source_symtab_and_line ();
> 
> -      if (default_breakpoint_valid
> +      if (last_displayed_codepoint_is_valid ()
>           && (!cursal.symtab
>               || ((strchr ("+-", (*address)[0]) != NULL)
>                   && ((*address)[1] != '['))))
> -       *sals = decode_line_1 (address, 1, default_breakpoint_symtab,
> -                              default_breakpoint_line, addr_string,
> -                              not_found_ptr);
> +       {
> +         *sals = decode_line_1 (address, 1,
> +                                get_last_displayed_symtab (),
> +                                get_last_displayed_line (),
> +                                addr_string, not_found_ptr);
> +       }
>        else
>         *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
>                                addr_string, not_found_ptr);
> @@ -7336,7 +7316,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>    struct captured_parse_breakpoint_args parse_args;
>    int i;
>    int pending = 0;
> -  int not_found = 0;
>    enum bptype type_wanted;
>    int task = 0;
>    int prev_bkpt_count = breakpoint_count;
> @@ -7348,7 +7327,7 @@ create_breakpoint (struct gdbarch *gdbarch,
>    parse_args.arg_p = &arg;
>    parse_args.sals_p = &sals;
>    parse_args.addr_string_p = &addr_string;
> -  parse_args.not_found_ptr = &not_found;
> +  parse_args.not_found_ptr = 0;
> 
>    e = catch_exception (uiout, do_captured_parse_breakpoint,
>                        &parse_args, RETURN_MASK_ALL);
> @@ -8083,9 +8062,11 @@ until_break_command (char *arg, int from_tty,
> int anywhere)
>    /* Set a breakpoint where the user wants it and at return from
>       this function */
> 
> -  if (default_breakpoint_valid)
> -    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
> -                         default_breakpoint_line, (char ***) NULL, NULL);
> +  if (last_displayed_codepoint_is_valid ())
> +    sals = decode_line_1 (&arg, 1,
> +                         get_last_displayed_symtab (),
> +                         get_last_displayed_line (),
> +                         (char ***) NULL, NULL);
>    else
>      sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
>                           0, (char ***) NULL, NULL);
> @@ -8673,10 +8654,11 @@ clear_command (char *arg, int from_tty)
>         xmalloc (sizeof (struct symtab_and_line));
>        make_cleanup (xfree, sals.sals);
>        init_sal (&sal);         /* initialize to zeroes */
> -      sal.line = default_breakpoint_line;
> -      sal.symtab = default_breakpoint_symtab;
> -      sal.pc = default_breakpoint_address;
> -      sal.pspace = default_breakpoint_pspace;
> +
> +      /* Set sal's line, symtab, pc, and pspace to the values corresponding to
> +        the last call to print_frame_info.  If the codepoint is not valid,
> +        this will set all the fields to 0. */
> +      set_sal_to_last_displayed_codepoint (&sal);
>        if (sal.symtab == 0)
>         error (_("No source file specified."));
> 
> @@ -10181,7 +10163,8 @@ invalidate_bp_value_on_memory_change
> (CORE_ADDR addr, int len,
>        }
>  }
> 
> -/* Use default_breakpoint_'s, or nothing if they aren't valid.  */
> +/* Use the last displayed codepoint's values, or nothing
> +   if they aren't valid. */
> 
>  struct symtabs_and_lines
>  decode_line_spec_1 (char *string, int funfirstline)
> @@ -10189,11 +10172,13 @@ decode_line_spec_1 (char *string, int funfirstline)
>    struct symtabs_and_lines sals;
>    if (string == 0)
>      error (_("Empty line specification."));
> -  if (default_breakpoint_valid)
> -    sals = decode_line_1 (&string, funfirstline,
> -                         default_breakpoint_symtab,
> -                         default_breakpoint_line,
> -                         (char ***) NULL, NULL);
> +  if (last_displayed_codepoint_is_valid ())
> +    {
> +      sals = decode_line_1 (&string, funfirstline,
> +                           get_last_displayed_symtab (),
> +                           get_last_displayed_line (),
> +                           (char ***) NULL, NULL);
> +    }
>    else
>      sals = decode_line_1 (&string, funfirstline,
>                           (struct symtab *) NULL, 0, (char ***) NULL, NULL);
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 8b7a5c6..50602b2 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -789,9 +789,6 @@ extern struct breakpoint
> *clone_momentary_breakpoint (struct breakpoint *bpkt);
> 
>  extern void set_ignore_count (int, int, int);
> 
> -extern void set_default_breakpoint (int, struct program_space *,
> -                                   CORE_ADDR, struct symtab *, int);
> -
>  extern void breakpoint_init_inferior (enum inf_context);
> 
>  extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index fdeb8db..c401eed 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -185,6 +185,8 @@ struct cmd_list_element *setchecklist;
> 
>  struct cmd_list_element *showchecklist;
> 
> +struct cmd_list_element *blacklistlist;
> +
>  /* Command tracing state.  */
> 
>  int source_verbose = 0;
> @@ -1308,6 +1310,7 @@ init_cmd_lists (void)
>    showprintlist = NULL;
>    setchecklist = NULL;
>    showchecklist = NULL;
> +  blacklistlist = NULL;
>  }
> 
>  static void
> @@ -1372,7 +1375,7 @@ init_cli_cmds (void)
>    char *source_help_text;
> 
>    /* Define the classes of commands.
> -     They will appear in the help list in the reverse of this order.  */
> +     They will appear in the help list in alphabetical order.  */
> 
>    add_cmd ("internals", class_maintenance, NULL, _("\
>  Maintenance commands.\n\
> diff --git a/gdb/command.h b/gdb/command.h
> index a746c82..27cdc33 100644
> --- a/gdb/command.h
> +++ b/gdb/command.h
> @@ -33,7 +33,7 @@ enum command_class
>    no_class = -1, class_run = 0, class_vars, class_stack,
>    class_files, class_support, class_info, class_breakpoint, class_trace,
>    class_alias, class_bookmark, class_obscure, class_maintenance,
> -  class_pseudo, class_tui, class_user, class_xdb
> +  class_pseudo, class_tui, class_user, class_xdb, class_blacklist
>  };
> 
>  /* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
> diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
> index 6a230c0..d561e73 100644
> --- a/gdb/gdbcmd.h
> +++ b/gdb/gdbcmd.h
> @@ -124,6 +124,8 @@ extern struct cmd_list_element *setchecklist;
> 
>  extern struct cmd_list_element *showchecklist;
> 
> +extern struct cmd_list_element *blacklistlist;
> +
>  extern void execute_command (char *, int);
> 
>  enum command_control_type execute_control_command (struct command_line *);
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 5f58759..7402fee 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -52,6 +52,7 @@
>  #include "inline-frame.h"
>  #include "jit.h"
>  #include "tracepoint.h"
> +#include "blacklist.h"
> 
>  /* Prototypes for local functions */
> 
> @@ -4490,7 +4491,8 @@ infrun: not switching back to stepped thread, it
> has vanished\n");
>         }
> 
>        /* If we have line number information for the function we are
> -         thinking of stepping into, step into it.
> +         thinking of stepping into and the function isn't blacklisted,
> +        step into it.
> 
>           If there are several symtabs at that PC (e.g. with include
>           files), just want to know whether *any* of them have line
> @@ -4500,7 +4502,8 @@ infrun: not switching back to stepped thread, it
> has vanished\n");
> 
>         tmp_sal = find_pc_line (ecs->stop_func_start, 0);
>         tmp_sal.pspace = get_frame_program_space (frame);
> -       if (tmp_sal.line != 0)
> +       if (tmp_sal.line != 0 &&
> +           !function_pc_is_blacklisted (ecs->stop_func_start))
>           {
>             if (execution_direction == EXEC_REVERSE)
>               handle_step_into_function_backward (gdbarch, ecs);
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index c5ea28a..19727b5 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -1857,7 +1857,13 @@ decode_variable (char *copy, int funfirstline,
> char ***canonical,
>      return minsym_found (funfirstline, msymbol);
> 
>    if (not_found_ptr)
> -    *not_found_ptr = 1;
> +    {
> +      struct symtabs_and_lines sals;
> +      *not_found_ptr = 1;
> +      sals.sals = 0;
> +      sals.nelts = 0;
> +      return sals;
> +    }
> 
>    if (!have_full_symbols ()
>        && !have_partial_symbols ()
> diff --git a/gdb/stack.c b/gdb/stack.c
> index 53d4aeb..14febd9 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -73,6 +73,12 @@ static void print_frame (struct frame_info *frame,
> int print_level,
>                          enum print_what print_what,  int print_args,
>                          struct symtab_and_line sal);
> 
> +static void set_last_displayed_codepoint (int valid,
> +                                         struct program_space *pspace,
> +                                         CORE_ADDR addr,
> +                                         struct symtab *symtab,
> +                                         int line);
> +
>  /* Zero means do things normally; we are interacting directly with the
>     user.  One means print the full filename and linenumber when a
>     frame is printed, and do so in a format emacs18/emacs19.22 can
> @@ -80,6 +86,14 @@ static void print_frame (struct frame_info *frame,
> int print_level,
>     cases and in a slightly different syntax.  */
> 
>  int annotation_level = 0;
> +
> +/* These variables hold the last codepoint we displayed to the user.  This is
> +   where we insert a breakpoint or a blacklist entry by default. */
> +static int last_codepoint_valid = 0;
> +static struct program_space *last_codepoint_pspace = 0;
> +static CORE_ADDR last_codepoint_addr = 0;
> +static struct symtab *last_codepoint_symtab = 0;
> +static int last_codepoint_line = 0;
> 
> 
>  struct print_stack_frame_args
> @@ -650,14 +664,96 @@ print_frame_info (struct frame_info *frame, int
> print_level,
>      }
> 
>    if (print_what != LOCATION)
> -    set_default_breakpoint (1, sal.pspace,
> -                           get_frame_pc (frame), sal.symtab, sal.line);
> +    set_last_displayed_codepoint (1, sal.pspace,
> +                                 get_frame_pc (frame), sal.symtab,
> +                                 sal.line);
> 
>    annotate_frame_end ();
> 
>    gdb_flush (gdb_stdout);
>  }
> 
> +/* Remember the last codepoint we displayed, which we use e.g. as the place to
> +   put a breakpoint when the `break' command is invoked with no arguments. */
> +static void
> +set_last_displayed_codepoint (int valid, struct program_space *pspace,
> +                             CORE_ADDR addr, struct symtab *symtab,
> +                             int line)
> +{
> +  last_codepoint_valid = valid;
> +  last_codepoint_pspace = pspace;
> +  last_codepoint_addr = addr;
> +  last_codepoint_symtab = symtab;
> +  last_codepoint_line = line;
> +}
> +
> +void
> +clear_last_displayed_codepoint ()
> +{
> +  last_codepoint_valid = 0;
> +  last_codepoint_pspace = 0;
> +  last_codepoint_addr = 0;
> +  last_codepoint_symtab = 0;
> +  last_codepoint_line = 0;
> +}
> +
> +int
> +last_displayed_codepoint_is_valid ()
> +{
> +  return last_codepoint_valid;
> +}
> +
> +struct program_space*
> +get_last_displayed_pspace ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_pspace;
> +  return 0;
> +}
> +
> +CORE_ADDR
> +get_last_displayed_addr ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_addr;
> +  return 0;
> +}
> +
> +struct symtab*
> +get_last_displayed_symtab ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_symtab;
> +  return 0;
> +}
> +
> +int
> +get_last_displayed_line ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_line;
> +  return 0;
> +}
> +
> +void
> +set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal)
> +{
> +  if (last_codepoint_valid)
> +    {
> +      sal->pspace = last_codepoint_pspace;
> +      sal->pc = last_codepoint_addr;
> +      sal->symtab = last_codepoint_symtab;
> +      sal->line = last_codepoint_line;
> +    }
> +  else
> +    {
> +      sal->pspace = 0;
> +      sal->pc = 0;
> +      sal->symtab = 0;
> +      sal->line = 0;
> +    }
> +}
> +
>  /* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding
>     to FRAME.  */
>  void
> diff --git a/gdb/stack.h b/gdb/stack.h
> index 5e874b4..fa08035 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -39,4 +39,14 @@ void iterate_over_block_local_vars (struct block *block,
>                                     iterate_over_block_arg_local_vars_cb cb,
>                                     void *cb_data);
> 
> +/* Get or set the last displayed codepoint, which is, e.g. where we set a
> +   breakpoint when `break' is supplied with no arguments. */
> +void clear_last_displayed_codepoint ();
> +int last_displayed_codepoint_is_valid ();
> +struct program_space* get_last_displayed_pspace ();
> +CORE_ADDR get_last_displayed_addr ();
> +struct symtab* get_last_displayed_symtab ();
> +int get_last_displayed_line ();
> +void set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal);
> +
>  #endif /* #ifndef STACK_H */
> diff --git a/gdb/symfile.c b/gdb/symfile.c
> index eda26cc..b56badf 100644
> --- a/gdb/symfile.c
> +++ b/gdb/symfile.c
> @@ -56,6 +56,7 @@
>  #include "elf-bfd.h"
>  #include "solib.h"
>  #include "remote.h"
> +#include "stack.h"
> 
>  #include <sys/types.h>
>  #include <fcntl.h>
> @@ -2709,7 +2710,7 @@ clear_symtab_users (void)
> 
>    clear_displays ();
>    breakpoint_re_set ();
> -  set_default_breakpoint (0, NULL, 0, 0, 0);
> +  clear_last_displayed_codepoint ();
>    clear_pc_function_cache ();
>    observer_notify_new_objfile (NULL);
> 
> diff --git a/gdb/testsuite/gdb.base/Makefile.in
> b/gdb/testsuite/gdb.base/Makefile.in
> index 5e8e385..bd54184 100644
> --- a/gdb/testsuite/gdb.base/Makefile.in
> +++ b/gdb/testsuite/gdb.base/Makefile.in
> @@ -1,7 +1,7 @@
>  VPATH = @srcdir@
>  srcdir = @srcdir@
> 
> -EXECUTABLES = all-types annota1 bitfields break \
> +EXECUTABLES = all-types annota1 bitfields blacklist blacklist-solib break \
>         call-ar-st call-rt-st call-strs callfuncs callfwmall \
>         chng-syms commands compiler condbreak constvars coremaker \
>         dbx-test display ending-run execd-prog exprs \
> diff --git a/gdb/testsuite/gdb.base/blacklist-solib-lib.c
> b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
> new file mode 100644
> index 0000000..792cd01
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
> @@ -0,0 +1,11 @@
> +/* Simple shared library */
> +
> +int square(int num)
> +{
> +  return multiply(num, num);
> +}
> +
> +int multiply(int a, int b)
> +{
> +  return a * b;
> +}
> diff --git a/gdb/testsuite/gdb.base/blacklist-solib-main.c
> b/gdb/testsuite/gdb.base/blacklist-solib-main.c
> new file mode 100644
> index 0000000..746bb5f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist-solib-main.c
> @@ -0,0 +1,6 @@
> +int square(int num);
> +
> +int main()
> +{
> +  return square(0);
> +}
> diff --git a/gdb/testsuite/gdb.base/blacklist-solib.exp
> b/gdb/testsuite/gdb.base/blacklist-solib.exp
> new file mode 100644
> index 0000000..b713394
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist-solib.exp
> @@ -0,0 +1,129 @@
> +#   Copyright 2010 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# This file was written by Justin Lebar. (justin.lebar@gmail.com)
> +
> +#
> +# Tests blacklisting shared libraries.
> +#
> +
> +# This only works on GNU/Linux.
> +if { ![isnative] || [is_remote host] || ![istarget *-linux*] ||
> [skip_shlib_tests]} {
> +    continue
> +}
> +
> +set test "blacklist-solib"
> +set srcfile_main "${test}-main.c"
> +set binfile_main "${objdir}/${subdir}/${test}-test"
> +set srcfile_lib "${test}-lib.c"
> +set libname "lib${test}"
> +set binfile_lib ${objdir}/${subdir}/${libname}.so
> +
> +#
> +# Compile our program under test.  The main program references a shared library
> +# libblacklist-solib.so, which contains two functions, square(), which is
> +# referenced by the main program, and multiply(), which is not referenced by
> +# the main program.
> +#
> +
> +if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib}
> ${binfile_lib} [list debug
> additional_flags=-Wl,-soname,${libname}.so]] != ""} {
> +    return -1
> +}
> +
> +if {[gdb_compile "${srcdir}/${subdir}/${srcfile_main}"
> "${binfile_main}.o" object debug] != ""} {
> +    return -1
> +}
> +
> +if {[gdb_compile "${binfile_main}.o" "${binfile_main}" executable \
> +                 [list debug "additional_flags=-L${objdir}/${subdir}
> -l${test} \
> +
> -Wl,-rpath=${objdir}/${subdir}"]] != ""} {
> +    return -1
> +}
> +
> +gdb_start
> +gdb_load ${binfile_main}
> +
> +#
> +# At this point, if we try to blacklist the file ${srcfile_lib} or the function
> +# multiply(), we should get a prompt asking us if we want to enable the
> +# blacklist entry pending a shared library load.
> +#
> +
> +gdb_test "blacklist file ${srcfile_lib}" \
> +"Blacklisting file ${srcfile_lib}." \
> +"blacklisting file in solib" \
> +"No source file named ${srcfile_lib}.*
> +Add file to blacklist pending future shared library load.*"\
> +"y"
> +
> +#
> +# Does info blacklist list this entry as pending?
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+file\\s+y\\s+n/a\\s+${srcfile_lib} \\(PENDING\\)\\s*" \
> +"info blacklist with pending file"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +
> +#
> +# We shouldn't step into square(), since we blacklisted blacklist-solib-lib.c.
> +#
> +gdb_test "step" ""
> +gdb_test "bt" "#0\\s+main.*" "step after blacklisting solib file."
> +
> +#
> +# Our entry should no longer be pending.  Note that we unfortunately need to do
> +# at least one step before the entry will be unmarked as pending.
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+file\\s+y\\s+n/a\\s+.*${srcfile_lib}\\s*" \
> +"info blacklist with pending file"
> +
> +#
> +# Now restart gdb and testing blacklisting of a function inside a solib.
> +#
> +gdb_exit
> +gdb_start
> +gdb_load ${binfile_main}
> +
> +gdb_test "blacklist function multiply" \
> +"Blacklisting function multiply pending shared library load." \
> +"blacklisting function in solib" \
> +"No function found named multiply..*
> +Add function to blacklist pending future shared library load.*"\
> +"y"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +
> +#
> +# Our first step should take us into square.
> +#
> +gdb_test "step" "square.*"
> +
> +#
> +# Now our entry should no longer be pending.
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+function\\s+y\\s+0x\[0-9a-f\]+\\s+multiply at .*${srcfile_lib}:.*\\s*" \
> +
> +#
> +# This step shouldn't go into multiply -- we should skip it and go on to the
> +# last line of square.
> +#
> +gdb_test "step" ""
> +gdb_test "bt" "#0\\s+square.*"
> diff --git a/gdb/testsuite/gdb.base/blacklist.c
> b/gdb/testsuite/gdb.base/blacklist.c
> new file mode 100644
> index 0000000..565ba93
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist.c
> @@ -0,0 +1,13 @@
> +int foo();
> +int bar();
> +int baz(int, int);
> +
> +int main()
> +{
> +  return baz(foo(), bar());
> +}
> +
> +int foo()
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/blacklist.exp
> b/gdb/testsuite/gdb.base/blacklist.exp
> new file mode 100644
> index 0000000..ed1afb8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist.exp
> @@ -0,0 +1,140 @@
> +#   Copyright 2010 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# This file was written by Justin Lebar. (justin.lebar@gmail.com)
> +
> +if { [prepare_for_testing blacklist.exp "blacklist" \
> +                          {blacklist.c blacklist1.c } \
> +                          {debug nowarnings}] } {
> +    return -1
> +}
> +
> +set srcfile blacklist.c
> +set srcfile1 blacklist1.c
> +
> +#
> +# Right after we start gdb, there's no default file or function to blacklist.
> +#
> +gdb_test "blacklist file" "No default blacklist file now."
> +gdb_test "blacklist function" "No default blacklist function now."
> +gdb_test "blacklist" "No default blacklist function now."
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +
> +#
> +# Test |info blacklist| with an empty blacklist.
> +#
> +gdb_test "info blacklist" "Blacklist is empty." "info blacklist empty"
> +
> +#
> +# Create a blacklist entry for the current file and function.
> +#
> +gdb_test "blacklist file" "Blacklisting file .*$srcfile."
> +gdb_test "blacklist" "Blacklisting function main() at .*\."
> +
> +#
> +# Create a blacklist entry for a specified file and function.
> +#
> +gdb_test "blacklist file blacklist1.c" "Blacklisting file .*$srcfile1."
> +gdb_test "blacklist function baz" "Blacklisting function baz at .*"
> +
> +#
> +# Test bad blacklist entry modification commands
> +#
> +gdb_test "blacklist enable 999" "No blacklist entry numbered 999."
> +gdb_test "blacklist disable 999" "No blacklist entry numbered 999."
> +gdb_test "blacklist delete 999" "No blacklist entry numbered 999."
> +gdb_test "blacklist enable" "Argument required \\(expression to compute\\)."
> +gdb_test "blacklist disable" "Argument required \\(expression to compute\\)."
> +gdb_test "blacklist delete" "Argument required \\(expression to compute\\)."
> +gdb_test "blacklist enable a" "No symbol \"a\" in current context."
> +gdb_test "blacklist disable a" "No symbol \"a\" in current context."
> +gdb_test "blacklist delete a" "No symbol \"a\" in current context."
> +
> +#
> +# Test that blacklist function doesn't allow extra characters at the end of its
> +# arguments list.
> +#
> +gdb_test "blacklist function foo bar" "Junk at end of arguments."
> +
> +#
> +# Ask for info on a blacklist entry which doesn't exist.
> +#
> +gdb_test "info blacklist 999" "No blacklist entry numbered 999."
> +
> +#
> +# Does |info blacklist| look right?
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+file\\s+y\\s+n/a.*$srcfile\\s*
> +2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
> +3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
> +4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
> +
> +#
> +# Right now, we have an outstanding blacklist on both source files, so when we
> +# step into the first line in main(), we should step right over it and go to
> +# the second line of main().
> +#
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +send_gdb "step\n"
> +gdb_test "bt" "#0\\s+main.*" "step after all blacklisted"
> +
> +#
> +# Now remove blacklist.c from the blacklist.  Our first step should take us
> +# into foo(), and our second step should take us to the next line in main().
> +#
> +send_gdb "blacklist delete 1\n"
> +# Check that entry 1 is missing from |info blacklist|
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
> +3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
> +4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
> +send_gdb "step\n"; # Return from foo()
> +gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
> +
> +#
> +# Now disable our blacklisting of blacklist1.c.  We should now step into foo(),
> +# then into bar(), but not into baz().
> +#
> +send_gdb "blacklist disable 3\n"
> +# Is entry 3 disabled in |info blacklist|?
> +gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+n.*" \
> +         "info blacklist shows entry as disabled"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +gdb_test "step" "bar \\(\\) at.*" "step after disabling 3 (1)"
> +send_gdb "step\n"; # Return from foo()
> +gdb_test "step" "foo \\(\\) at.*" "step after disabling 3 (2)"
> +send_gdb "step\n"; # Return from bar()
> +gdb_test "step" "main \\(\\) at.*" "step after disabling 3 (3)"
> +
> +#
> +# Enable blacklist entry 3 and make sure we step over it like before.
> +#
> +send_gdb "blacklist enable 3\n"
> +# Is entry 3 enabled in |info blacklist|?
> +gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+y.*" \
> +         "info blacklist shows entry as enabled"
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
> +send_gdb "step\n"; # Return from foo()
> +gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
> +
> diff --git a/gdb/testsuite/gdb.base/blacklist1.c
> b/gdb/testsuite/gdb.base/blacklist1.c
> new file mode 100644
> index 0000000..2dab5c3
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist1.c
> @@ -0,0 +1,9 @@
> +int bar()
> +{
> +  return 1;
> +}
> +
> +int baz(int a, int b)
> +{
> +  return a + b;
> +}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-06-18 19:37 ` Michael Snyder
@ 2010-06-18 20:58   ` Eli Zaretskii
  0 siblings, 0 replies; 10+ messages in thread
From: Eli Zaretskii @ 2010-06-18 20:58 UTC (permalink / raw)
  To: Michael Snyder; +Cc: justin.lebar, gdb-patches

> Date: Fri, 18 Jun 2010 12:37:25 -0700
> From: Michael Snyder <msnyder@vmware.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
> 
> Justin Lebar wrote:
> > This adds support for a "blacklist" which contains files and functions
> > which are skipped while single-stepping.  This patch also fixes bug
> > 11614: decode_variable() in linespec.c does not obey its contract
> 
> Greetings, welcome, and thanks for your submission.
> 
> There are a few problems, mostly things we usually encounter with new
> contributors.
> 
> First, I can't apply your patch.  There are line wrappings, character
> substitutions when I save the email, and so on.  Would you mind trying
> to send the patch as a plain text attachment?
> 
> Second, we need a ChangeLog entry.  See gdb/ChangeLog for examples
> of how those are composed and formatted.
> 
> Finally, have you got a copyright assignment filed?

If this contribution is accepted, we will also need a suitable patch
for the manual, to describe the new feature and commands, and a NEWS
entry.

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-06-18 18:56 [Patch] Bug 8287: Skip uninteresting functions while debugging Justin Lebar
  2010-06-18 19:37 ` Michael Snyder
@ 2010-06-20  7:03 ` Hui Zhu
  2010-06-25 21:57 ` Tom Tromey
  2 siblings, 0 replies; 10+ messages in thread
From: Hui Zhu @ 2010-06-20  7:03 UTC (permalink / raw)
  To: Justin Lebar; +Cc: gdb-patches

patch -p1 < /tmp/prefix.txt
patching file gdb/Makefile.in
Hunk #1 succeeded at 657 (offset 4 lines).
patch: **** malformed patch at line 14: frame-unwind.h	\

Could you try other mail client or post your patch as attachment?

I think your patch that your post was added a lot of enter like following line:

@@ -653,6 +653,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c
ada-valprint.c ada-tasks.c \

Thanks,
Hui

On Sat, Jun 19, 2010 at 02:55, Justin Lebar <justin.lebar@gmail.com> wrote:
> This adds support for a "blacklist" which contains files and functions
> which are skipped while single-stepping.  This patch also fixes bug
> 11614: decode_variable() in linespec.c does not obey its contract
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index fc148fe..5d2c23e 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -653,6 +653,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c
> ada-valprint.c ada-tasks.c \
>        auxv.c ax-general.c ax-gdb.c \
>        bcache.c \
>        bfd-target.c \
> +       blacklist.c \
>        block.c blockframe.c breakpoint.c buildsym.c \
>        c-exp.y c-lang.c c-typeprint.c c-valprint.c \
>        charset.c cli-out.c coffread.c coff-pe-read.c \
> @@ -772,7 +773,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h
> frame-unwind.h  \
>  remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
>  sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
>  gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
> -psymtab.h psympriv.h
> +psymtab.h psympriv.h blacklist.h
>
>  # Header files that already have srcdir in them, or which are in objdir.
>
> @@ -806,6 +807,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>        addrmap.o \
>        auxv.o \
>        bfd-target.o \
> +       blacklist.o \
>        blockframe.o breakpoint.o findvar.o regcache.o \
>        charset.o disasm.o dummy-frame.o dfp.o \
>        source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
> diff --git a/gdb/blacklist.c b/gdb/blacklist.c
> new file mode 100644
> index 0000000..2bd65cc
> --- /dev/null
> +++ b/gdb/blacklist.c
> @@ -0,0 +1,555 @@
> +/* Header for GDB line completion.
> +   Copyright (C) 2010 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "blacklist.h"
> +#include "value.h"
> +#include "valprint.h"
> +#include "ui-out.h"
> +#include "gdb_string.h"
> +#include "symtab.h"
> +#include "gdbcmd.h"
> +#include "command.h"
> +#include "completer.h"
> +#include "stack.h"
> +#include "arch-utils.h"
> +#include "linespec.h"
> +#include "objfiles.h"
> +
> +struct blacklist_entry
> +{
> +  int number;
> +
> +  /* null if this isn't a blacklist entry for an entire file.
> +     The blacklist entry owns this pointer. */
> +  char *filename;
> +
> +  /* The name of the blacklisted function, if this is a blacklist entry for a
> +     function.  Note that this might be non-null even if the pc is 0 if the
> +     entry is pending a shared library load.
> +
> +     The blacklist entry owns this pointer. */
> +  char *function_name;
> +
> +  /* 0 if this is a blacklist entry for an entire file, or if this entry will
> +     be on a function, pending a shared library load. */
> +  CORE_ADDR pc;
> +
> +  /* Architecture we used to create the blacklist entry. May be null
> +     if the entry is pending a shared library load. */
> +  struct gdbarch *gdbarch;
> +
> +  int enabled;
> +  int pending;
> +
> +  struct blacklist_entry *next;
> +};
> +
> +static void blacklist_function_command (char *arg, int from_tty);
> +static void blacklist_file_command (char *arg, int from_tty);
> +static void blacklist_info (char *arg, int from_tty);
> +
> +static void add_blacklist_entry (struct blacklist_entry *b);
> +static void blacklist_function_pc (CORE_ADDR pc, char *name,
> +                                  struct gdbarch *arch,
> +                                  int pending);
> +static void try_resolve_pending_entry (struct blacklist_entry *b);
> +static struct gdbarch *get_sal_arch (struct symtab_and_line *sal);
> +
> +static struct blacklist_entry *blacklist_entry_chain;
> +static int blacklist_entry_count;
> +
> +#define ALL_BLACKLIST_ENTRIES(B) for (B = blacklist_entry_chain; B; B
> = B->next)
> +
> +static void
> +blacklist_file_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  struct symtab *symtab;
> +  int pending = 0;
> +  char *filename = 0;
> +
> +  /* If no argument was given, try to default to the last
> +     displayed codepoint. */
> +  if (arg == 0)
> +    {
> +      symtab = get_last_displayed_symtab ();
> +      if (symtab == 0)
> +       error (_("No default blacklist file now."));
> +      else
> +       filename = symtab->filename;
> +    }
> +  else
> +    {
> +      symtab = lookup_symtab (arg);
> +      if (symtab == 0)
> +       {
> +         fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg);
> +         if (!nquery (_("\
> +Add file to blacklist pending future shared library load? ")))
> +           return;
> +
> +         pending = 1;
> +         filename = arg;
> +       }
> +      else
> +       filename = symtab->filename;
> +    }
> +
> +  b = XZALLOC (struct blacklist_entry);
> +  b->filename = strdup(filename);
> +  b->enabled = 1;
> +  b->pending = pending;
> +  if (symtab != 0)
> +    b->gdbarch = get_objfile_arch (symtab->objfile);
> +
> +  add_blacklist_entry (b);
> +
> +  printf_filtered ("Blacklisting file %s.\n", filename);
> +}
> +
> +static void
> +blacklist_function_command (char *arg, int from_tty)
> +{
> +  CORE_ADDR func_pc;
> +  char *name = NULL;
> +
> +  /* Default to the current function if no argument is given. */
> +  if (arg == 0)
> +    {
> +      CORE_ADDR pc;
> +      if (!last_displayed_codepoint_is_valid ())
> +       error (_("No default blacklist function now."));
> +
> +      pc = get_last_displayed_addr ();
> +      if (!find_pc_partial_function (pc, &name, &func_pc, 0))
> +       {
> +         error (_("No function found containing current program point %s."),
> +                 paddress (get_current_arch (), pc));
> +       }
> +      blacklist_function_pc (func_pc, name, get_current_arch (), 0);
> +    }
> +  else
> +    {
> +      /* Decode arg.  We set funfirstline=1 so decode_line_1 will give us the
> +        first line of the function specified, if it can, and so that we'll
> +        reject variable names and the like. */
> +
> +      /* TODO maybe want something like parse_breakpoint_sals ()
> +         in breakpoint.c. */
> +      int i;
> +      int not_found = 0;
> +      int pending = 0;
> +      char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */
> +      struct symtabs_and_lines sals = decode_line_1 (&arg, 1, 0, 0, 0,
> +                                                    &not_found);
> +
> +      if (not_found)
> +       {
> +         fprintf_filtered (gdb_stderr,
> +                           _("No function found named %s.\n"), orig_arg);
> +
> +         if (nquery (_("\
> +Add function to blacklist pending future shared library load? ")))
> +           {
> +             /* Add the pending blacklist entry. */
> +             blacklist_function_pc (0, orig_arg, 0, 1);
> +           }
> +
> +         return;
> +       }
> +
> +      if (sals.nelts == 0)
> +       error (_("No function to blacklist.")); /* TODO can I trigger this? */
> +      if (sals.nelts > 1)
> +       error (_("Specify just one function at a time.")); /* TODO can I
> trigger this? */
> +      if (strlen (arg) != 0)
> +       error (_("Junk at end of arguments."));
> +
> +      /* The pc decode_line_1 gives us is the first line of the function,
> +        but we actually want the line before that.  The call to
> +        find_pc_partial_function gets us the value we actually want. */
> +      {
> +       struct symtab_and_line *sal = &sals.sals[0];
> +       CORE_ADDR pc = sal->pc;
> +       CORE_ADDR func_start = 0;
> +       struct gdbarch *arch = get_sal_arch (sal);
> +
> +       if (!find_pc_partial_function (pc, &name, &func_start, 0))
> +         {
> +           error (_("No function found containing program point %s."),
> +                    paddress (arch, pc));
> +         }
> +
> +       blacklist_function_pc (func_start, name, arch, 0);
> +      }
> +    }
> +}
> +
> +static void
> +blacklist_info (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  int num_printable_entries = 0;
> +  int entry_num = -1;
> +  int address_width = 10;
> +  struct value_print_options opts;
> +  struct cleanup *tbl_chain;
> +
> +  get_user_print_options (&opts);
> +
> +  if (arg != 0)
> +    {
> +      entry_num = parse_and_eval_long (arg);
> +    }
> +
> +  /* Count the number of rows in the table and see if we need space for a
> +     64-bit address anywhere. */
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (entry_num == -1 || b->number == entry_num)
> +      {
> +       num_printable_entries++;
> +       if (b->gdbarch && gdbarch_addr_bit (b->gdbarch) > 32)
> +         address_width = 18;
> +      }
> +
> +  if (num_printable_entries == 0)
> +    {
> +      if (entry_num == -1)
> +       ui_out_message (uiout, 0, "Blacklist is empty.\n");
> +      else
> +       ui_out_message (uiout, 0,
> +                       "No blacklist entry numbered %d.\n", entry_num);
> +
> +      return;
> +    }
> +
> +  if (opts.addressprint)
> +    tbl_chain
> +       = make_cleanup_ui_out_table_begin_end (uiout, 5, num_printable_entries,
> +                                             "BlacklistTable");
> +  else
> +    tbl_chain
> +       = make_cleanup_ui_out_table_begin_end (uiout, 4, num_printable_entries,
> +                                             "BlacklistTable");
> +
> +  ui_out_table_header (uiout, 7, ui_left, "number", "Num");
>   /* 1 */
> +  ui_out_table_header (uiout, 14, ui_left, "type", "Type");
>   /* 2 */
> +  ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");
>   /* 3 */
> +  if (opts.addressprint)
> +    {
> +      ui_out_table_header (uiout, address_width, ui_left,
> +                          "addr", "Address");                           /* 4 */
> +    }
> +  ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
>   /* 5 */
> +  ui_out_table_body (uiout);
> +
> +  ALL_BLACKLIST_ENTRIES (b)
> +    {
> +      struct cleanup *entry_chain;
> +
> +      QUIT;
> +      if (entry_num != -1 && entry_num != b->number)
> +       continue;
> +
> +      entry_chain = make_cleanup_ui_out_tuple_begin_end (uiout,
> "blklst-entry");
> +      ui_out_field_int (uiout, "number", b->number);
>   /* 1 */
> +
> +      if (b->function_name != 0)
> +       ui_out_field_string (uiout, "type", "function");                 /* 2 */
> +      else if (b->filename != 0)
> +       ui_out_field_string (uiout, "type", "file");                     /* 2 */
> +      else
> +       internal_error (__FILE__, __LINE__, _("\
> +Blacklist entry should have either a filename or a function name."));
> +
> +      if (b->enabled)
> +       ui_out_field_string (uiout, "enabled", "y");                     /* 3 */
> +      else
> +       ui_out_field_string (uiout, "enabled", "n");                     /* 3 */
> +
> +      if (opts.addressprint)
> +       {
> +         if (b->pc != 0)
> +           ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
> +         else
> +           ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
> +       }
> +
> +      if (!b->pending && b->function_name != 0)
> +       {
> +          struct symbol *sym;
> +          gdb_assert (b->pc != 0);
> +          sym = find_pc_function (b->pc);
> +          if (sym)
> +            ui_out_field_fmt (uiout, "what", "%s at %s:%d",
> +                              sym->ginfo.name,
> +                              sym->symtab->filename,
> +                              sym->line);
> +          else
> +            ui_out_field_string (uiout, "what", "?");
> +       }
> +      else if (b->pending && b->function_name != 0)
> +       {
> +         ui_out_field_fmt (uiout, "what", "%s (PENDING)",
> +                           b->function_name);
> +       }
> +      else if (!b->pending && b->filename != 0)
> +       ui_out_field_string (uiout, "what", b->filename);
> +      else if (b->pending && b->filename != 0)
> +       ui_out_field_fmt (uiout, "what", "%s (PENDING)",
> +                         b->filename);
> +
> +      ui_out_text (uiout, "\n");
> +      do_cleanups (entry_chain);
> +    }
> +
> +  do_cleanups (tbl_chain);
> +}
> +
> +static void
> +blacklist_enable_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  int entry_num = parse_and_eval_long (arg);
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (b->number == entry_num)
> +      {
> +       b->enabled = 1;
> +       return;
> +      }
> +
> +  error (_("No blacklist entry numbered %d."), entry_num);
> +}
> +
> +static void
> +blacklist_disable_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b;
> +  int entry_num = parse_and_eval_long (arg);
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (b->number == entry_num)
> +      {
> +       b->enabled = 0;
> +       return;
> +      }
> +
> +  error (_("No blacklist entry numbered %d."), entry_num);
> +}
> +
> +static void
> +blacklist_delete_command (char *arg, int from_tty)
> +{
> +  struct blacklist_entry *b, *b_prev;
> +  int entry_num = parse_and_eval_long (arg);
> +
> +  /* We don't need to use a SAFE macro here since we return as soon as we
> +     remove an element from the list. */
> +  b_prev = 0;
> +  ALL_BLACKLIST_ENTRIES (b)
> +    if (b->number == entry_num)
> +      {
> +       if (b_prev != 0)
> +         b_prev->next = b->next;
> +       else
> +         blacklist_entry_chain = b->next;
> +
> +       xfree (b->function_name);
> +       xfree (b->filename);
> +       xfree (b);
> +       return;
> +      }
> +    else
> +      {
> +       b_prev = b;
> +      }
> +
> +  error (_("No blacklist entry numbered %d."), entry_num);
> +}
> +
> +static void
> +blacklist_function_pc (CORE_ADDR pc, char *name, struct gdbarch *arch,
> +                      int pending)
> +{
> +  struct blacklist_entry *b = XZALLOC (struct blacklist_entry);
> +  b->pc = pc;
> +  b->gdbarch = arch;
> +  b->enabled = 1;
> +  b->pending = pending;
> +  b->function_name = strdup (name);
> +
> +  add_blacklist_entry (b);
> +
> +  if (!pending)
> +    printf_filtered ("Blacklisting function %s at %s.\n",
> +                    name, paddress (get_current_arch (), pc));
> +  else
> +    printf_filtered ("Blacklisting function %s pending shared library load.\n",
> +                    name);
> +}
> +
> +static void
> +add_blacklist_entry (struct blacklist_entry *b)
> +{
> +  struct blacklist_entry *b1;
> +
> +  b->number = ++blacklist_entry_count;
> +
> +  /* Add to the end of the chain so that the list of
> +     blacklist entries will be in numerical order. */
> +
> +  b1 = blacklist_entry_chain;
> +  if (b1 == 0)
> +    blacklist_entry_chain = b;
> +  else
> +    {
> +      while (b1->next)
> +       b1 = b1->next;
> +      b1->next = b;
> +    }
> +}
> +
> +int
> +function_pc_is_blacklisted (CORE_ADDR pc)
> +{
> +  struct symtab_and_line sal;
> +  char *filename;
> +  struct blacklist_entry *b;
> +
> +  sal = find_pc_line (pc, 0);
> +  filename = sal.symtab->filename;
> +
> +  ALL_BLACKLIST_ENTRIES (b)
> +    {
> +      /* First, check whether the file or function this entry is pending on has
> +        been loaded.  It might be more sensible to do this on a solib load,
> +        but that doesn't seem to work for some reason. */
> +      if (b->pending)
> +       try_resolve_pending_entry (b);
> +
> +      if (b->enabled && !b->pending
> +         && ((b->pc != 0 && pc == b->pc)
> +             || (b->filename != 0 && filename != 0
> +                 && strcmp (filename, b->filename) == 0)))
> +       return 1;
> +    }
> +
> +  return 0;
> +}
> +
> +/* Try to look up the file or function corresponding to the given blacklist
> +   entry.  If the file or function now exists, update the entry and unmark it
> +   as pending. */
> +static void
> +try_resolve_pending_entry (struct blacklist_entry *b)
> +{
> +  if (!b->pending)
> +    return;
> +
> +  if (b->filename != 0)
> +    {
> +      struct symtab *symtab = lookup_symtab (b->filename);
> +      if (symtab != 0)
> +       {
> +         xfree (b->filename);
> +         b->filename = strdup (symtab->filename);
> +         b->gdbarch = get_objfile_arch (symtab->objfile);
> +         b->pending = 0;
> +       }
> +    }
> +  else if (b->function_name != 0)
> +    {
> +      int not_found = 0;
> +      char *func_name = b->function_name;
> +      struct symtabs_and_lines sals = decode_line_1 (&func_name, 1, 0, 0, 0,
> +                                                    &not_found);
> +
> +      if (!not_found && sals.nelts == 1 && strlen (func_name) == 0)
> +       {
> +         struct symtab_and_line *sal = &sals.sals[0];
> +         CORE_ADDR pc = sal->pc;
> +         CORE_ADDR func_start = 0;
> +         struct gdbarch *arch = get_sal_arch (sal);
> +
> +         if (find_pc_partial_function (pc, &b->function_name, &func_start, 0))
> +           {
> +             b->pending = 0;
> +             b->pc = func_start;
> +             b->gdbarch = arch;
> +           }
> +       }
> +    }
> +}
> +
> +static struct gdbarch*
> +get_sal_arch (struct symtab_and_line *sal)
> +{
> +  if (sal->section)
> +    return get_objfile_arch (sal->section->objfile);
> +  if (sal->symtab)
> +    return get_objfile_arch (sal->symtab->objfile);
> +  return get_current_arch ();
> +}
> +
> +void
> +_initialize_step_blacklist (void)
> +{
> +  struct cmd_list_element *c;
> +
> +  blacklist_entry_chain = 0;
> +  blacklist_entry_count = 0;
> +
> +  add_prefix_cmd ("blacklist", class_blacklist,
> blacklist_function_command, _("\
> +Ignore a function while stepping.\n\
> +blacklist [FUNCTION NAME]\n\
> +If no function name is given, blacklist the current function."),
> +                  &blacklistlist, "blacklist ", 1, &cmdlist);
> +
> +  c = add_cmd ("file", class_blacklist, blacklist_file_command, _("\
> +Ignore a file while stepping.\n\
> +blacklist file [FILENAME]\n\
> +If no filename is given, blacklist the current file."),
> +              &blacklistlist);
> +  set_cmd_completer (c, filename_completer);
> +
> +  c = add_cmd ("function", class_blacklist, blacklist_function_command, _("\
> +Ignore a function while stepping.\n\
> +blacklist function [FUNCTION NAME]\n\
> +If no function name is given, blacklist the current function."),
> +              &blacklistlist);
> +  set_cmd_completer (c, location_completer);
> +
> +  add_cmd ("enable", class_blacklist, blacklist_enable_command, _("\
> +Enable a blacklist entry.\n\
> +blacklist enable [NUMBER]"),
> +          &blacklistlist);
> +
> +  add_cmd ("disable", class_blacklist, blacklist_disable_command, _("\
> +Disable a blacklist entry.\n\
> +blacklist disable [NUMBER]"),
> +          &blacklistlist);
> +
> +  add_cmd ("delete", class_blacklist, blacklist_delete_command, _("\
> +Delete a blacklist entry.\n\
> +blacklist delete [NUMBER]"),
> +           &blacklistlist);
> +
> +  add_info ("blacklist", blacklist_info, _("\
> +Status of blacklist, or of blacklist entry NUMBER.\n\
> +The \"Type\" column indicates one of:\n\
> +\tfile        - blacklisted file\n\
> +\tfunction    - blacklisted function"));
> +}
> diff --git a/gdb/blacklist.h b/gdb/blacklist.h
> new file mode 100644
> index 0000000..94d1d93
> --- /dev/null
> +++ b/gdb/blacklist.h
> @@ -0,0 +1,21 @@
> +/* Header for GDB line completion.
> +   Copyright (C) 2010 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* Returns 1 if the given pc was blacklisted and shouldn't be stepped into.
> +   Otherwise, returns 0. */
> +
> +int
> +function_pc_is_blacklisted (CORE_ADDR pc);
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 3dca17e..8f60bd4 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -61,6 +61,7 @@
>  #include "valprint.h"
>  #include "jit.h"
>  #include "xml-syscall.h"
> +#include "stack.h"
>
>  /* readline include files */
>  #include "readline/readline.h"
> @@ -527,19 +528,6 @@ make_cleanup_decref_counted_command_line (struct
> counted_command_line **cmdp)
>   return make_cleanup (do_cleanup_counted_command_line, cmdp);
>  }
>
> -/* Default address, symtab and line to put a breakpoint at
> -   for "break" command with no arg.
> -   if default_breakpoint_valid is zero, the other three are
> -   not valid, and "break" with no arg is an error.
> -
> -   This set by print_stack_frame, which calls set_default_breakpoint.  */
> -
> -int default_breakpoint_valid;
> -CORE_ADDR default_breakpoint_address;
> -struct symtab *default_breakpoint_symtab;
> -int default_breakpoint_line;
> -struct program_space *default_breakpoint_pspace;
> -
>
>  /* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
>    Advance *PP after the string and any trailing whitespace.
> @@ -5174,20 +5162,6 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
>     }
>  }
>
> -/* Set the default place to put a breakpoint
> -   for the `break' command with no arguments.  */
> -
> -void
> -set_default_breakpoint (int valid, struct program_space *pspace,
> -                       CORE_ADDR addr, struct symtab *symtab,
> -                       int line)
> -{
> -  default_breakpoint_valid = valid;
> -  default_breakpoint_pspace = pspace;
> -  default_breakpoint_address = addr;
> -  default_breakpoint_symtab = symtab;
> -  default_breakpoint_line = line;
> -}
>
>  /* Return true iff it is meaningful to use the address member of
>    BPT.  For some breakpoint types, the address member is irrelevant
> @@ -7120,20 +7094,23 @@ parse_breakpoint_sals (char **address,
>   if ((*address) == NULL
>       || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
>     {
> -      if (default_breakpoint_valid)
> +      /* The last displayed codepoint, if it's valid, is our default breakpoint
> +         address. */
> +      if (last_displayed_codepoint_is_valid ())
>        {
>          struct symtab_and_line sal;
>          init_sal (&sal);              /* initialize to zeroes */
>          sals->sals = (struct symtab_and_line *)
>            xmalloc (sizeof (struct symtab_and_line));
> -         sal.pc = default_breakpoint_address;
> -         sal.line = default_breakpoint_line;
> -         sal.symtab = default_breakpoint_symtab;
> -         sal.pspace = default_breakpoint_pspace;
> +
> +         /* Set sal's pspace, pc, symtab, and line to the values corresponding
> +            to the last call to print_frame_info. */
> +         set_sal_to_last_displayed_codepoint (&sal);
> +
>          sal.section = find_pc_overlay (sal.pc);
>
>          /* "break" without arguments is equivalent to "break *PC" where PC is
> -            the default_breakpoint_address.  So make sure to set
> +            the last displayed codepoint's address.  So make sure to set
>             sal.explicit_pc to prevent GDB from trying to expand the list of
>             sals to include all other instances with the same symtab and line.
>           */
> @@ -7150,19 +7127,22 @@ parse_breakpoint_sals (char **address,
>       /* Force almost all breakpoints to be in terms of the
>          current_source_symtab (which is decode_line_1's default).  This
>          should produce the results we want almost all of the time while
> -         leaving default_breakpoint_* alone.
> +         leaving the last displayed codepoint pointers alone.
>          ObjC: However, don't match an Objective-C method name which
>          may have a '+' or '-' succeeded by a '[' */
>
>       struct symtab_and_line cursal = get_current_source_symtab_and_line ();
>
> -      if (default_breakpoint_valid
> +      if (last_displayed_codepoint_is_valid ()
>          && (!cursal.symtab
>              || ((strchr ("+-", (*address)[0]) != NULL)
>                  && ((*address)[1] != '['))))
> -       *sals = decode_line_1 (address, 1, default_breakpoint_symtab,
> -                              default_breakpoint_line, addr_string,
> -                              not_found_ptr);
> +       {
> +         *sals = decode_line_1 (address, 1,
> +                                get_last_displayed_symtab (),
> +                                get_last_displayed_line (),
> +                                addr_string, not_found_ptr);
> +       }
>       else
>        *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
>                               addr_string, not_found_ptr);
> @@ -7336,7 +7316,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>   struct captured_parse_breakpoint_args parse_args;
>   int i;
>   int pending = 0;
> -  int not_found = 0;
>   enum bptype type_wanted;
>   int task = 0;
>   int prev_bkpt_count = breakpoint_count;
> @@ -7348,7 +7327,7 @@ create_breakpoint (struct gdbarch *gdbarch,
>   parse_args.arg_p = &arg;
>   parse_args.sals_p = &sals;
>   parse_args.addr_string_p = &addr_string;
> -  parse_args.not_found_ptr = &not_found;
> +  parse_args.not_found_ptr = 0;
>
>   e = catch_exception (uiout, do_captured_parse_breakpoint,
>                       &parse_args, RETURN_MASK_ALL);
> @@ -8083,9 +8062,11 @@ until_break_command (char *arg, int from_tty,
> int anywhere)
>   /* Set a breakpoint where the user wants it and at return from
>      this function */
>
> -  if (default_breakpoint_valid)
> -    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
> -                         default_breakpoint_line, (char ***) NULL, NULL);
> +  if (last_displayed_codepoint_is_valid ())
> +    sals = decode_line_1 (&arg, 1,
> +                         get_last_displayed_symtab (),
> +                         get_last_displayed_line (),
> +                         (char ***) NULL, NULL);
>   else
>     sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
>                          0, (char ***) NULL, NULL);
> @@ -8673,10 +8654,11 @@ clear_command (char *arg, int from_tty)
>        xmalloc (sizeof (struct symtab_and_line));
>       make_cleanup (xfree, sals.sals);
>       init_sal (&sal);         /* initialize to zeroes */
> -      sal.line = default_breakpoint_line;
> -      sal.symtab = default_breakpoint_symtab;
> -      sal.pc = default_breakpoint_address;
> -      sal.pspace = default_breakpoint_pspace;
> +
> +      /* Set sal's line, symtab, pc, and pspace to the values corresponding to
> +        the last call to print_frame_info.  If the codepoint is not valid,
> +        this will set all the fields to 0. */
> +      set_sal_to_last_displayed_codepoint (&sal);
>       if (sal.symtab == 0)
>        error (_("No source file specified."));
>
> @@ -10181,7 +10163,8 @@ invalidate_bp_value_on_memory_change
> (CORE_ADDR addr, int len,
>       }
>  }
>
> -/* Use default_breakpoint_'s, or nothing if they aren't valid.  */
> +/* Use the last displayed codepoint's values, or nothing
> +   if they aren't valid. */
>
>  struct symtabs_and_lines
>  decode_line_spec_1 (char *string, int funfirstline)
> @@ -10189,11 +10172,13 @@ decode_line_spec_1 (char *string, int funfirstline)
>   struct symtabs_and_lines sals;
>   if (string == 0)
>     error (_("Empty line specification."));
> -  if (default_breakpoint_valid)
> -    sals = decode_line_1 (&string, funfirstline,
> -                         default_breakpoint_symtab,
> -                         default_breakpoint_line,
> -                         (char ***) NULL, NULL);
> +  if (last_displayed_codepoint_is_valid ())
> +    {
> +      sals = decode_line_1 (&string, funfirstline,
> +                           get_last_displayed_symtab (),
> +                           get_last_displayed_line (),
> +                           (char ***) NULL, NULL);
> +    }
>   else
>     sals = decode_line_1 (&string, funfirstline,
>                          (struct symtab *) NULL, 0, (char ***) NULL, NULL);
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 8b7a5c6..50602b2 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -789,9 +789,6 @@ extern struct breakpoint
> *clone_momentary_breakpoint (struct breakpoint *bpkt);
>
>  extern void set_ignore_count (int, int, int);
>
> -extern void set_default_breakpoint (int, struct program_space *,
> -                                   CORE_ADDR, struct symtab *, int);
> -
>  extern void breakpoint_init_inferior (enum inf_context);
>
>  extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index fdeb8db..c401eed 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -185,6 +185,8 @@ struct cmd_list_element *setchecklist;
>
>  struct cmd_list_element *showchecklist;
>
> +struct cmd_list_element *blacklistlist;
> +
>  /* Command tracing state.  */
>
>  int source_verbose = 0;
> @@ -1308,6 +1310,7 @@ init_cmd_lists (void)
>   showprintlist = NULL;
>   setchecklist = NULL;
>   showchecklist = NULL;
> +  blacklistlist = NULL;
>  }
>
>  static void
> @@ -1372,7 +1375,7 @@ init_cli_cmds (void)
>   char *source_help_text;
>
>   /* Define the classes of commands.
> -     They will appear in the help list in the reverse of this order.  */
> +     They will appear in the help list in alphabetical order.  */
>
>   add_cmd ("internals", class_maintenance, NULL, _("\
>  Maintenance commands.\n\
> diff --git a/gdb/command.h b/gdb/command.h
> index a746c82..27cdc33 100644
> --- a/gdb/command.h
> +++ b/gdb/command.h
> @@ -33,7 +33,7 @@ enum command_class
>   no_class = -1, class_run = 0, class_vars, class_stack,
>   class_files, class_support, class_info, class_breakpoint, class_trace,
>   class_alias, class_bookmark, class_obscure, class_maintenance,
> -  class_pseudo, class_tui, class_user, class_xdb
> +  class_pseudo, class_tui, class_user, class_xdb, class_blacklist
>  };
>
>  /* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
> diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
> index 6a230c0..d561e73 100644
> --- a/gdb/gdbcmd.h
> +++ b/gdb/gdbcmd.h
> @@ -124,6 +124,8 @@ extern struct cmd_list_element *setchecklist;
>
>  extern struct cmd_list_element *showchecklist;
>
> +extern struct cmd_list_element *blacklistlist;
> +
>  extern void execute_command (char *, int);
>
>  enum command_control_type execute_control_command (struct command_line *);
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 5f58759..7402fee 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -52,6 +52,7 @@
>  #include "inline-frame.h"
>  #include "jit.h"
>  #include "tracepoint.h"
> +#include "blacklist.h"
>
>  /* Prototypes for local functions */
>
> @@ -4490,7 +4491,8 @@ infrun: not switching back to stepped thread, it
> has vanished\n");
>        }
>
>       /* If we have line number information for the function we are
> -         thinking of stepping into, step into it.
> +         thinking of stepping into and the function isn't blacklisted,
> +        step into it.
>
>          If there are several symtabs at that PC (e.g. with include
>          files), just want to know whether *any* of them have line
> @@ -4500,7 +4502,8 @@ infrun: not switching back to stepped thread, it
> has vanished\n");
>
>        tmp_sal = find_pc_line (ecs->stop_func_start, 0);
>        tmp_sal.pspace = get_frame_program_space (frame);
> -       if (tmp_sal.line != 0)
> +       if (tmp_sal.line != 0 &&
> +           !function_pc_is_blacklisted (ecs->stop_func_start))
>          {
>            if (execution_direction == EXEC_REVERSE)
>              handle_step_into_function_backward (gdbarch, ecs);
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index c5ea28a..19727b5 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -1857,7 +1857,13 @@ decode_variable (char *copy, int funfirstline,
> char ***canonical,
>     return minsym_found (funfirstline, msymbol);
>
>   if (not_found_ptr)
> -    *not_found_ptr = 1;
> +    {
> +      struct symtabs_and_lines sals;
> +      *not_found_ptr = 1;
> +      sals.sals = 0;
> +      sals.nelts = 0;
> +      return sals;
> +    }
>
>   if (!have_full_symbols ()
>       && !have_partial_symbols ()
> diff --git a/gdb/stack.c b/gdb/stack.c
> index 53d4aeb..14febd9 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -73,6 +73,12 @@ static void print_frame (struct frame_info *frame,
> int print_level,
>                         enum print_what print_what,  int print_args,
>                         struct symtab_and_line sal);
>
> +static void set_last_displayed_codepoint (int valid,
> +                                         struct program_space *pspace,
> +                                         CORE_ADDR addr,
> +                                         struct symtab *symtab,
> +                                         int line);
> +
>  /* Zero means do things normally; we are interacting directly with the
>    user.  One means print the full filename and linenumber when a
>    frame is printed, and do so in a format emacs18/emacs19.22 can
> @@ -80,6 +86,14 @@ static void print_frame (struct frame_info *frame,
> int print_level,
>    cases and in a slightly different syntax.  */
>
>  int annotation_level = 0;
> +
> +/* These variables hold the last codepoint we displayed to the user.  This is
> +   where we insert a breakpoint or a blacklist entry by default. */
> +static int last_codepoint_valid = 0;
> +static struct program_space *last_codepoint_pspace = 0;
> +static CORE_ADDR last_codepoint_addr = 0;
> +static struct symtab *last_codepoint_symtab = 0;
> +static int last_codepoint_line = 0;
>
>
>  struct print_stack_frame_args
> @@ -650,14 +664,96 @@ print_frame_info (struct frame_info *frame, int
> print_level,
>     }
>
>   if (print_what != LOCATION)
> -    set_default_breakpoint (1, sal.pspace,
> -                           get_frame_pc (frame), sal.symtab, sal.line);
> +    set_last_displayed_codepoint (1, sal.pspace,
> +                                 get_frame_pc (frame), sal.symtab,
> +                                 sal.line);
>
>   annotate_frame_end ();
>
>   gdb_flush (gdb_stdout);
>  }
>
> +/* Remember the last codepoint we displayed, which we use e.g. as the place to
> +   put a breakpoint when the `break' command is invoked with no arguments. */
> +static void
> +set_last_displayed_codepoint (int valid, struct program_space *pspace,
> +                             CORE_ADDR addr, struct symtab *symtab,
> +                             int line)
> +{
> +  last_codepoint_valid = valid;
> +  last_codepoint_pspace = pspace;
> +  last_codepoint_addr = addr;
> +  last_codepoint_symtab = symtab;
> +  last_codepoint_line = line;
> +}
> +
> +void
> +clear_last_displayed_codepoint ()
> +{
> +  last_codepoint_valid = 0;
> +  last_codepoint_pspace = 0;
> +  last_codepoint_addr = 0;
> +  last_codepoint_symtab = 0;
> +  last_codepoint_line = 0;
> +}
> +
> +int
> +last_displayed_codepoint_is_valid ()
> +{
> +  return last_codepoint_valid;
> +}
> +
> +struct program_space*
> +get_last_displayed_pspace ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_pspace;
> +  return 0;
> +}
> +
> +CORE_ADDR
> +get_last_displayed_addr ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_addr;
> +  return 0;
> +}
> +
> +struct symtab*
> +get_last_displayed_symtab ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_symtab;
> +  return 0;
> +}
> +
> +int
> +get_last_displayed_line ()
> +{
> +  if (last_codepoint_valid)
> +    return last_codepoint_line;
> +  return 0;
> +}
> +
> +void
> +set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal)
> +{
> +  if (last_codepoint_valid)
> +    {
> +      sal->pspace = last_codepoint_pspace;
> +      sal->pc = last_codepoint_addr;
> +      sal->symtab = last_codepoint_symtab;
> +      sal->line = last_codepoint_line;
> +    }
> +  else
> +    {
> +      sal->pspace = 0;
> +      sal->pc = 0;
> +      sal->symtab = 0;
> +      sal->line = 0;
> +    }
> +}
> +
>  /* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding
>    to FRAME.  */
>  void
> diff --git a/gdb/stack.h b/gdb/stack.h
> index 5e874b4..fa08035 100644
> --- a/gdb/stack.h
> +++ b/gdb/stack.h
> @@ -39,4 +39,14 @@ void iterate_over_block_local_vars (struct block *block,
>                                    iterate_over_block_arg_local_vars_cb cb,
>                                    void *cb_data);
>
> +/* Get or set the last displayed codepoint, which is, e.g. where we set a
> +   breakpoint when `break' is supplied with no arguments. */
> +void clear_last_displayed_codepoint ();
> +int last_displayed_codepoint_is_valid ();
> +struct program_space* get_last_displayed_pspace ();
> +CORE_ADDR get_last_displayed_addr ();
> +struct symtab* get_last_displayed_symtab ();
> +int get_last_displayed_line ();
> +void set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal);
> +
>  #endif /* #ifndef STACK_H */
> diff --git a/gdb/symfile.c b/gdb/symfile.c
> index eda26cc..b56badf 100644
> --- a/gdb/symfile.c
> +++ b/gdb/symfile.c
> @@ -56,6 +56,7 @@
>  #include "elf-bfd.h"
>  #include "solib.h"
>  #include "remote.h"
> +#include "stack.h"
>
>  #include <sys/types.h>
>  #include <fcntl.h>
> @@ -2709,7 +2710,7 @@ clear_symtab_users (void)
>
>   clear_displays ();
>   breakpoint_re_set ();
> -  set_default_breakpoint (0, NULL, 0, 0, 0);
> +  clear_last_displayed_codepoint ();
>   clear_pc_function_cache ();
>   observer_notify_new_objfile (NULL);
>
> diff --git a/gdb/testsuite/gdb.base/Makefile.in
> b/gdb/testsuite/gdb.base/Makefile.in
> index 5e8e385..bd54184 100644
> --- a/gdb/testsuite/gdb.base/Makefile.in
> +++ b/gdb/testsuite/gdb.base/Makefile.in
> @@ -1,7 +1,7 @@
>  VPATH = @srcdir@
>  srcdir = @srcdir@
>
> -EXECUTABLES = all-types annota1 bitfields break \
> +EXECUTABLES = all-types annota1 bitfields blacklist blacklist-solib break \
>        call-ar-st call-rt-st call-strs callfuncs callfwmall \
>        chng-syms commands compiler condbreak constvars coremaker \
>        dbx-test display ending-run execd-prog exprs \
> diff --git a/gdb/testsuite/gdb.base/blacklist-solib-lib.c
> b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
> new file mode 100644
> index 0000000..792cd01
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
> @@ -0,0 +1,11 @@
> +/* Simple shared library */
> +
> +int square(int num)
> +{
> +  return multiply(num, num);
> +}
> +
> +int multiply(int a, int b)
> +{
> +  return a * b;
> +}
> diff --git a/gdb/testsuite/gdb.base/blacklist-solib-main.c
> b/gdb/testsuite/gdb.base/blacklist-solib-main.c
> new file mode 100644
> index 0000000..746bb5f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist-solib-main.c
> @@ -0,0 +1,6 @@
> +int square(int num);
> +
> +int main()
> +{
> +  return square(0);
> +}
> diff --git a/gdb/testsuite/gdb.base/blacklist-solib.exp
> b/gdb/testsuite/gdb.base/blacklist-solib.exp
> new file mode 100644
> index 0000000..b713394
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist-solib.exp
> @@ -0,0 +1,129 @@
> +#   Copyright 2010 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# This file was written by Justin Lebar. (justin.lebar@gmail.com)
> +
> +#
> +# Tests blacklisting shared libraries.
> +#
> +
> +# This only works on GNU/Linux.
> +if { ![isnative] || [is_remote host] || ![istarget *-linux*] ||
> [skip_shlib_tests]} {
> +    continue
> +}
> +
> +set test "blacklist-solib"
> +set srcfile_main "${test}-main.c"
> +set binfile_main "${objdir}/${subdir}/${test}-test"
> +set srcfile_lib "${test}-lib.c"
> +set libname "lib${test}"
> +set binfile_lib ${objdir}/${subdir}/${libname}.so
> +
> +#
> +# Compile our program under test.  The main program references a shared library
> +# libblacklist-solib.so, which contains two functions, square(), which is
> +# referenced by the main program, and multiply(), which is not referenced by
> +# the main program.
> +#
> +
> +if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib}
> ${binfile_lib} [list debug
> additional_flags=-Wl,-soname,${libname}.so]] != ""} {
> +    return -1
> +}
> +
> +if {[gdb_compile "${srcdir}/${subdir}/${srcfile_main}"
> "${binfile_main}.o" object debug] != ""} {
> +    return -1
> +}
> +
> +if {[gdb_compile "${binfile_main}.o" "${binfile_main}" executable \
> +                 [list debug "additional_flags=-L${objdir}/${subdir}
> -l${test} \
> +
> -Wl,-rpath=${objdir}/${subdir}"]] != ""} {
> +    return -1
> +}
> +
> +gdb_start
> +gdb_load ${binfile_main}
> +
> +#
> +# At this point, if we try to blacklist the file ${srcfile_lib} or the function
> +# multiply(), we should get a prompt asking us if we want to enable the
> +# blacklist entry pending a shared library load.
> +#
> +
> +gdb_test "blacklist file ${srcfile_lib}" \
> +"Blacklisting file ${srcfile_lib}." \
> +"blacklisting file in solib" \
> +"No source file named ${srcfile_lib}.*
> +Add file to blacklist pending future shared library load.*"\
> +"y"
> +
> +#
> +# Does info blacklist list this entry as pending?
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+file\\s+y\\s+n/a\\s+${srcfile_lib} \\(PENDING\\)\\s*" \
> +"info blacklist with pending file"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +
> +#
> +# We shouldn't step into square(), since we blacklisted blacklist-solib-lib.c.
> +#
> +gdb_test "step" ""
> +gdb_test "bt" "#0\\s+main.*" "step after blacklisting solib file."
> +
> +#
> +# Our entry should no longer be pending.  Note that we unfortunately need to do
> +# at least one step before the entry will be unmarked as pending.
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+file\\s+y\\s+n/a\\s+.*${srcfile_lib}\\s*" \
> +"info blacklist with pending file"
> +
> +#
> +# Now restart gdb and testing blacklisting of a function inside a solib.
> +#
> +gdb_exit
> +gdb_start
> +gdb_load ${binfile_main}
> +
> +gdb_test "blacklist function multiply" \
> +"Blacklisting function multiply pending shared library load." \
> +"blacklisting function in solib" \
> +"No function found named multiply..*
> +Add function to blacklist pending future shared library load.*"\
> +"y"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +
> +#
> +# Our first step should take us into square.
> +#
> +gdb_test "step" "square.*"
> +
> +#
> +# Now our entry should no longer be pending.
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+function\\s+y\\s+0x\[0-9a-f\]+\\s+multiply at .*${srcfile_lib}:.*\\s*" \
> +
> +#
> +# This step shouldn't go into multiply -- we should skip it and go on to the
> +# last line of square.
> +#
> +gdb_test "step" ""
> +gdb_test "bt" "#0\\s+square.*"
> diff --git a/gdb/testsuite/gdb.base/blacklist.c
> b/gdb/testsuite/gdb.base/blacklist.c
> new file mode 100644
> index 0000000..565ba93
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist.c
> @@ -0,0 +1,13 @@
> +int foo();
> +int bar();
> +int baz(int, int);
> +
> +int main()
> +{
> +  return baz(foo(), bar());
> +}
> +
> +int foo()
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/blacklist.exp
> b/gdb/testsuite/gdb.base/blacklist.exp
> new file mode 100644
> index 0000000..ed1afb8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist.exp
> @@ -0,0 +1,140 @@
> +#   Copyright 2010 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# This file was written by Justin Lebar. (justin.lebar@gmail.com)
> +
> +if { [prepare_for_testing blacklist.exp "blacklist" \
> +                          {blacklist.c blacklist1.c } \
> +                          {debug nowarnings}] } {
> +    return -1
> +}
> +
> +set srcfile blacklist.c
> +set srcfile1 blacklist1.c
> +
> +#
> +# Right after we start gdb, there's no default file or function to blacklist.
> +#
> +gdb_test "blacklist file" "No default blacklist file now."
> +gdb_test "blacklist function" "No default blacklist function now."
> +gdb_test "blacklist" "No default blacklist function now."
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +
> +#
> +# Test |info blacklist| with an empty blacklist.
> +#
> +gdb_test "info blacklist" "Blacklist is empty." "info blacklist empty"
> +
> +#
> +# Create a blacklist entry for the current file and function.
> +#
> +gdb_test "blacklist file" "Blacklisting file .*$srcfile."
> +gdb_test "blacklist" "Blacklisting function main() at .*\."
> +
> +#
> +# Create a blacklist entry for a specified file and function.
> +#
> +gdb_test "blacklist file blacklist1.c" "Blacklisting file .*$srcfile1."
> +gdb_test "blacklist function baz" "Blacklisting function baz at .*"
> +
> +#
> +# Test bad blacklist entry modification commands
> +#
> +gdb_test "blacklist enable 999" "No blacklist entry numbered 999."
> +gdb_test "blacklist disable 999" "No blacklist entry numbered 999."
> +gdb_test "blacklist delete 999" "No blacklist entry numbered 999."
> +gdb_test "blacklist enable" "Argument required \\(expression to compute\\)."
> +gdb_test "blacklist disable" "Argument required \\(expression to compute\\)."
> +gdb_test "blacklist delete" "Argument required \\(expression to compute\\)."
> +gdb_test "blacklist enable a" "No symbol \"a\" in current context."
> +gdb_test "blacklist disable a" "No symbol \"a\" in current context."
> +gdb_test "blacklist delete a" "No symbol \"a\" in current context."
> +
> +#
> +# Test that blacklist function doesn't allow extra characters at the end of its
> +# arguments list.
> +#
> +gdb_test "blacklist function foo bar" "Junk at end of arguments."
> +
> +#
> +# Ask for info on a blacklist entry which doesn't exist.
> +#
> +gdb_test "info blacklist 999" "No blacklist entry numbered 999."
> +
> +#
> +# Does |info blacklist| look right?
> +#
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +1\\s+file\\s+y\\s+n/a.*$srcfile\\s*
> +2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
> +3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
> +4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
> +
> +#
> +# Right now, we have an outstanding blacklist on both source files, so when we
> +# step into the first line in main(), we should step right over it and go to
> +# the second line of main().
> +#
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +send_gdb "step\n"
> +gdb_test "bt" "#0\\s+main.*" "step after all blacklisted"
> +
> +#
> +# Now remove blacklist.c from the blacklist.  Our first step should take us
> +# into foo(), and our second step should take us to the next line in main().
> +#
> +send_gdb "blacklist delete 1\n"
> +# Check that entry 1 is missing from |info blacklist|
> +gdb_test "info blacklist" \
> +"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
> +2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
> +3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
> +4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
> +send_gdb "step\n"; # Return from foo()
> +gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
> +
> +#
> +# Now disable our blacklisting of blacklist1.c.  We should now step into foo(),
> +# then into bar(), but not into baz().
> +#
> +send_gdb "blacklist disable 3\n"
> +# Is entry 3 disabled in |info blacklist|?
> +gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+n.*" \
> +         "info blacklist shows entry as disabled"
> +
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +gdb_test "step" "bar \\(\\) at.*" "step after disabling 3 (1)"
> +send_gdb "step\n"; # Return from foo()
> +gdb_test "step" "foo \\(\\) at.*" "step after disabling 3 (2)"
> +send_gdb "step\n"; # Return from bar()
> +gdb_test "step" "main \\(\\) at.*" "step after disabling 3 (3)"
> +
> +#
> +# Enable blacklist entry 3 and make sure we step over it like before.
> +#
> +send_gdb "blacklist enable 3\n"
> +# Is entry 3 enabled in |info blacklist|?
> +gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+y.*" \
> +         "info blacklist shows entry as enabled"
> +if ![runto_main] { fail "blacklist tests suppressed" }
> +gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
> +send_gdb "step\n"; # Return from foo()
> +gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
> +
> diff --git a/gdb/testsuite/gdb.base/blacklist1.c
> b/gdb/testsuite/gdb.base/blacklist1.c
> new file mode 100644
> index 0000000..2dab5c3
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/blacklist1.c
> @@ -0,0 +1,9 @@
> +int bar()
> +{
> +  return 1;
> +}
> +
> +int baz(int a, int b)
> +{
> +  return a + b;
> +}
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-06-18 18:56 [Patch] Bug 8287: Skip uninteresting functions while debugging Justin Lebar
  2010-06-18 19:37 ` Michael Snyder
  2010-06-20  7:03 ` Hui Zhu
@ 2010-06-25 21:57 ` Tom Tromey
  2010-06-28 17:44   ` Justin Lebar
  2 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2010-06-25 21:57 UTC (permalink / raw)
  To: Justin Lebar; +Cc: gdb-patches

>>>>> "Justin" == Justin Lebar <justin.lebar@gmail.com> writes:

Justin> This adds support for a "blacklist" which contains files and
Justin> functions which are skipped while single-stepping.

Thanks for doing this.

FWIW I think this is a very good first patch to gdb.


One concern of mine is that this code will not perform well with many
blacklists in place.  It may make sense to keep a hash table indexed by
name (function or file), to make lookups faster.  What do you think?

Another random thought is whether we want to be able to blacklist based
on objfile name.

Justin> This patch also fixes bug 11614: decode_variable() in linespec.c
Justin> does not obey its contract

It is somewhat preferred in gdb to submit things like this as separate
patches.

Now for the nits ...

Justin> +#define ALL_BLACKLIST_ENTRIES(B) for (B = blacklist_entry_chain; B; B = B->next)

I think this should be wrapped before the 'for'.

Justin> +  b->filename = strdup(filename);

Space before open paren.  Also, you must use xstrdup, not strdup.  This
occurs more than once.

Justin> +      if (sals.nelts == 0)
Justin> +	error (_("No function to blacklist.")); /* TODO can I trigger this? */
Justin> +      if (sals.nelts > 1)
Justin> +	error (_("Specify just one function at a time.")); /* TODO can I
Justin> trigger this? */

Good questions :-)

It is great to be defensive here, but the comments should go before
checkin.

Maybe you can get nelts>1 with a C++ destructor?  I'm not sure.

Justin> +      if (opts.addressprint)
Justin> +	{
Justin> +	  if (b->pc != 0)
Justin> +	    ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
Justin> +	  else
Justin> +	    ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
Justin> +	}

A small nit, but I'm not sure about the exact string "n/a" here.
If there is an analogous situation elsewhere it would be good to just do
whatever is done there.

Justin> +int
Justin> +function_pc_is_blacklisted (CORE_ADDR pc)

All functions should have an introductory comment explaining its
contract -- purpose and meaning of arguments and result.  For functions
implementing commands or other helpers, this can be pretty short.

Justin> +      /* First, check whether the file or function this entry is pending on has
Justin> +	 been loaded.  It might be more sensible to do this on a solib load,
Justin> +	 but that doesn't seem to work for some reason. */

Let's figure this out.

Also, since the blacklist includes a PC value, I think you have to reset
it when re-running the inferior, and on some other state changes as well.

Justin> +  add_cmd ("enable", class_blacklist, blacklist_enable_command, _("\
Justin> +Enable a blacklist entry.\n\
Justin> +blacklist enable [NUMBER]"),
Justin> +	   &blacklistlist);

I think it would be more usual to make the commands "enable blacklist ..."
instead of "blacklist enable ...".  Likewise for disable and delete.

Justin> --- /dev/null
Justin> +++ b/gdb/blacklist.h
[...]
Justin> +int
Justin> +function_pc_is_blacklisted (CORE_ADDR pc);

No newline after "int" in a declaration.

A header file should have a #if guard.

Justin> -int default_breakpoint_valid;
Justin> -CORE_ADDR default_breakpoint_address;
Justin> -struct symtab *default_breakpoint_symtab;
Justin> -int default_breakpoint_line;
Justin> -struct program_space *default_breakpoint_pspace;

I'm not sure I understand the rationale for this set of changes.
Is it just to make the naming more clear?

I do like the new, more opaque, approach.

Justin> -  class_pseudo, class_tui, class_user, class_xdb
Justin> +  class_pseudo, class_tui, class_user, class_xdb, class_blacklist

I don't think you need a new command class for this.
I think class_breakpoint might be fine.

Tom

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-06-25 21:57 ` Tom Tromey
@ 2010-06-28 17:44   ` Justin Lebar
  2010-07-20 21:03     ` Tom Tromey
  0 siblings, 1 reply; 10+ messages in thread
From: Justin Lebar @ 2010-06-28 17:44 UTC (permalink / raw)
  To: tromey, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 5219 bytes --]

On Fri, Jun 25, 2010 at 2:56 PM, Tom Tromey <tromey@redhat.com> wrote:
> FWIW I think this is a very good first patch to gdb.

Thanks!

> One concern of mine is that this code will not perform well with many
> blacklists in place.  It may make sense to keep a hash table indexed by
> name (function or file), to make lookups faster.  What do you think?

I imagine you'd have to have a pretty large blacklist to notice a delay when
using gdb interactively, even on modest hardware.  I don't know much about gdb
scripting -- this might matter more in that case.  But would one single-step in
a script?

FWIW, enabling/disabling/deleting breakpoints takes time linear to the number
of breakpoints.

I'm happy to switch to a hashtable here if that's what we want.

> Another random thought is whether we want to be able to blacklist based
> on objfile name.

That seems like it might be nice.  Regular expression matching on file and
function names has also been suggested.

While I'm thinking about it, one problem I've run into while using this patch
while debugging Firefox is that we somehow load multiple copies of our smart
pointer header, so I have to blacklist both ../../nsCOMPtr.h and
../../../nsCOMPtr.h.  I need to investigate further exactly what about our
build system is causing this to see if it's something which should be fixed in
gdb or Mozilla's build, but my guess is that we may want to support this in gdb
somehow.

> Justin> This patch also fixes bug 11614: decode_variable() in linespec.c
> Justin> does not obey its contract
>
> It is somewhat preferred in gdb to submit things like this as separate
> patches.

I've split them out in this new set.  Because you need the bug11614 patch in
order for the blacklist patch to work (and since bug11614 is a trivial fix),
I've included both attachments in this one e-mail.

> Justin> +      if (sals.nelts == 0)
> Justin> +       error (_("No function to blacklist.")); /* TODO can I trigger this? */
> Justin> +      if (sals.nelts > 1)
> Justin> +       error (_("Specify just one function at a time.")); /* TODO can I
> Justin> trigger this? */
>
> Good questions :-)
>
> It is great to be defensive here, but the comments should go before
> checkin.
>
> Maybe you can get nelts>1 with a C++ destructor?  I'm not sure.

I didn't hit that error with a simple C++ destructor.  Maybe some kind of
pathological destructor could hit it.

I'm mostly concerned that the error messages are meaningful if we do hit them.
I'm only guessing at what nelts == 0 and nelts > 1 mean.

> Justin> +      if (opts.addressprint)
> Justin> +       {
> Justin> +         if (b->pc != 0)
> Justin> +           ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
> Justin> +         else
> Justin> +           ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
> Justin> +       }
>
> A small nit, but I'm not sure about the exact string "n/a" here.
> If there is an analogous situation elsewhere it would be good to just do
> whatever is done there.

We could just use the empty string if that would be clearer.

> Justin> +      /* First, check whether the file or function this entry is pending on has
> Justin> +        been loaded.  It might be more sensible to do this on a solib load,
> Justin> +        but that doesn't seem to work for some reason. */
>
> Let's figure this out.

I spent a while in #gdb with a few people (I don't recall who) and we couldn't
figure this out.  I added a solib load observer, but from within it,
find_pc_partial_function always failed.

I'm not sure where to look to figure out what's going on.

> Also, since the blacklist includes a PC value, I think you have to reset
> it when re-running the inferior, and on some other state changes as well.

Hm.  How do we handle this with breakpoints?

> Justin> +  add_cmd ("enable", class_blacklist, blacklist_enable_command, _("\
> Justin> +Enable a blacklist entry.\n\
> Justin> +blacklist enable [NUMBER]"),
> Justin> +          &blacklistlist);
>
> I think it would be more usual to make the commands "enable blacklist ..."
> instead of "blacklist enable ...".  Likewise for disable and delete.

I'm not sure I like "enable blacklist".  The problem is that "blacklist" is a
noun referring to the list of all functions we skip and also a verb meaning
"add an entry to the blacklist".  "Enable blacklist" sounds to me like we're
enabling an entire list of blacklist entries.

Maybe we can name the thing which indicates that we shouldn't step into a
function something less confusing than a "blacklist entry"?

> Justin> -int default_breakpoint_valid;
> Justin> -CORE_ADDR default_breakpoint_address;
> Justin> -struct symtab *default_breakpoint_symtab;
> Justin> -int default_breakpoint_line;
> Justin> -struct program_space *default_breakpoint_pspace;
>
> I'm not sure I understand the rationale for this set of changes.
> Is it just to make the naming more clear?

Right: They're no longer the default breakpoint values since they're now also
the default blacklist values too.  I moved them into stack.c so that
set_last_displayed_codepoint (which replaces set_default_breakpoint) could be a
static function -- it's only called in stack.c.

-Justin

[-- Attachment #2: bug8287 --]
[-- Type: application/octet-stream, Size: 47308 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 969f31d..3285f70 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,40 @@
+2010-06-18  Justin Lebar <justin.lebar@gmail.com>
+
+	* Makefile.in: (SFILES): Add blacklist.c.
+	(HFILES_NO_SRCDIR): Add blacklist.h.
+	(COMMON_OBS): Add blacklist.o.
+	* blacklist.h, blacklist.c: New
+	* breakpoint.h (set_default_breakpoint): removed
+	* breakpoint.c: Removed default_breakpoint_valid,
+	default_breakpoint_address, default_breakpoint_symtab,
+	default_breakpoint_line, default_breakpoint_pspace variables.
+	(set_default_breakpoint): Removed
+	(parse_breakpoint_sals, create_breakpoint, clear_command,
+	decode_line_spec_1): Removed uses of default_breakpoint variables;
+	replaced with function calls into stack.c.
+	* cli-cmds.h: Added cmd_list_element *blacklistlist.
+	* cli-cmds.c: Added blacklistlist.
+	(init_cmd_lists): Initialize blacklistlist.
+	(init_cli_cmds): Fixed comment (classes of commands appear in
+	alphabetical order).
+	* infrun.c (handle_inferior_event): Added check that we don't step
+	into a function whose pc is blacklisted.
+	* stack.c: Added last_codepoint_valid, last_codepoint_pspace,
+	last_codepoint_addr, last_codepoint_symtab, last_codepoint_line
+	variables.
+	(set_last_displayed_codepoint): New static function.
+	(print_frame_info): Switched call to set_default_breakpoint to call to
+	set_last_displayed_codepoint.
+	(clear_last_displayed_codepoint,
+	last_displayed_codepoint_is_valid, get_last_displayed_pspace,
+	get_last_displayed_addr, get_last_displayed_symtab,
+	get_last_displayed_line, set_sal_to_last_displayed_codepoint): New
+	public functions.
+	* stack.h (clear_last_displayed_codepoint,
+	last_displayed_codepoint_is_valid, get_last_displayed_pspace,
+	get_last_displayed_addr, get_last_displayed_symtab,
+	get_last_displayed_line, set_sal_to_last_displayed_codepoint): Added
+
 2010-06-25  Justin Lebar <justin.lebar@gmail.com>
 
 	* linespec.c (decode_variable): Passing a non-null not_found_ptr
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index fc148fe..5d2c23e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -653,6 +653,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	auxv.c ax-general.c ax-gdb.c \
 	bcache.c \
 	bfd-target.c \
+	blacklist.c \
 	block.c blockframe.c breakpoint.c buildsym.c \
 	c-exp.y c-lang.c c-typeprint.c c-valprint.c \
 	charset.c cli-out.c coffread.c coff-pe-read.c \
@@ -772,7 +773,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h	\
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
-psymtab.h psympriv.h
+psymtab.h psympriv.h blacklist.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -806,6 +807,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	addrmap.o \
 	auxv.o \
 	bfd-target.o \
+	blacklist.o \
 	blockframe.o breakpoint.o findvar.o regcache.o \
 	charset.o disasm.o dummy-frame.o dfp.o \
 	source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
diff --git a/gdb/blacklist.c b/gdb/blacklist.c
new file mode 100644
index 0000000..6594a28
--- /dev/null
+++ b/gdb/blacklist.c
@@ -0,0 +1,562 @@
+/* Header for GDB line completion.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "blacklist.h"
+#include "value.h"
+#include "valprint.h"
+#include "ui-out.h"
+#include "gdb_string.h"
+#include "symtab.h"
+#include "gdbcmd.h"
+#include "command.h"
+#include "completer.h"
+#include "stack.h"
+#include "arch-utils.h"
+#include "linespec.h"
+#include "objfiles.h"
+
+struct blacklist_entry
+{
+  int number;
+
+  /* null if this isn't a blacklist entry for an entire file. 
+     The blacklist entry owns this pointer. */
+  char *filename;
+
+  /* The name of the blacklisted function, if this is a blacklist entry for a
+     function.  Note that this might be non-null even if the pc is 0 if the
+     entry is pending a shared library load.
+
+     The blacklist entry owns this pointer. */
+  char *function_name;
+
+  /* 0 if this is a blacklist entry for an entire file, or if this entry will
+     be on a function, pending a shared library load. */
+  CORE_ADDR pc;
+
+  /* Architecture we used to create the blacklist entry. May be null 
+     if the entry is pending a shared library load. */
+  struct gdbarch *gdbarch;
+
+  int enabled;
+  int pending;
+
+  struct blacklist_entry *next;
+};
+
+static void blacklist_function_command (char *arg, int from_tty);
+static void blacklist_file_command (char *arg, int from_tty);
+static void blacklist_info (char *arg, int from_tty);
+
+static void add_blacklist_entry (struct blacklist_entry *b);
+static void blacklist_function_pc (CORE_ADDR pc, char *name,
+				   struct gdbarch *arch,
+				   int pending);
+static void try_resolve_pending_entry (struct blacklist_entry *b);
+static struct gdbarch *get_sal_arch (struct symtab_and_line *sal);
+
+static struct blacklist_entry *blacklist_entry_chain;
+static int blacklist_entry_count;
+
+#define ALL_BLACKLIST_ENTRIES(B) \
+  for (B = blacklist_entry_chain; B; B = B->next)
+
+static void
+blacklist_file_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  struct symtab *symtab;
+  int pending = 0;
+  char *filename = 0;
+
+  /* If no argument was given, try to default to the last
+     displayed codepoint. */
+  if (arg == 0)
+    {
+      symtab = get_last_displayed_symtab ();
+      if (symtab == 0)
+	error (_("No default blacklist file now."));
+      else
+	filename = symtab->filename;
+    }
+  else
+    {
+      symtab = lookup_symtab (arg);
+      if (symtab == 0)
+	{
+	  fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg);
+	  if (!nquery (_("\
+Add file to blacklist pending future shared library load? ")))
+	    return;
+
+	  pending = 1;
+	  filename = arg;
+	}
+      else
+	filename = symtab->filename;
+    }
+
+  b = XZALLOC (struct blacklist_entry);
+  b->filename = xstrdup (filename);
+  b->enabled = 1;
+  b->pending = pending;
+  if (symtab != 0)
+    b->gdbarch = get_objfile_arch (symtab->objfile);
+
+  add_blacklist_entry (b);
+
+  printf_filtered ("Blacklisting file %s.\n", filename);
+}
+
+static void
+blacklist_function_command (char *arg, int from_tty)
+{
+  CORE_ADDR func_pc;
+  char *name = NULL;
+
+  /* Default to the current function if no argument is given. */
+  if (arg == 0)
+    {
+      CORE_ADDR pc;
+      if (!last_displayed_codepoint_is_valid ())
+	error (_("No default blacklist function now."));
+
+      pc = get_last_displayed_addr ();
+      if (!find_pc_partial_function (pc, &name, &func_pc, 0))
+	{
+	  error (_("No function found containing current program point %s."),
+		  paddress (get_current_arch (), pc));
+	}
+      blacklist_function_pc (func_pc, name, get_current_arch (), 0);
+    }
+  else
+    {
+      /* Decode arg.  We set funfirstline=1 so decode_line_1 will give us the
+	 first line of the function specified, if it can, and so that we'll
+	 reject variable names and the like. */
+
+      /* TODO maybe want something like parse_breakpoint_sals ()
+         in breakpoint.c. */
+      int i;
+      int not_found = 0;
+      int pending = 0;
+      char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */
+      struct symtabs_and_lines sals = decode_line_1 (&arg, 1, 0, 0, 0,
+						     &not_found);
+
+      if (not_found)
+	{
+	  fprintf_filtered (gdb_stderr,
+			    _("No function found named %s.\n"), orig_arg);
+
+	  if (nquery (_("\
+Add function to blacklist pending future shared library load? ")))
+	    {
+	      /* Add the pending blacklist entry. */
+	      blacklist_function_pc (0, orig_arg, 0, 1);
+	    }
+
+	  return;
+	}
+
+      if (sals.nelts == 0)
+	error (_("No function to blacklist.")); /* TODO can I trigger this? */
+      if (sals.nelts > 1)
+	error (_("Specify just one function at a time.")); /* TODO can I trigger this? */
+      if (strlen (arg) != 0)
+	error (_("Junk at end of arguments."));
+
+      /* The pc decode_line_1 gives us is the first line of the function,
+	 but we actually want the line before that.  The call to
+	 find_pc_partial_function gets us the value we actually want. */
+      {
+	struct symtab_and_line *sal = &sals.sals[0];
+	CORE_ADDR pc = sal->pc;
+	CORE_ADDR func_start = 0;
+	struct gdbarch *arch = get_sal_arch (sal);
+
+	if (!find_pc_partial_function (pc, &name, &func_start, 0))
+	  {
+	    error (_("No function found containing program point %s."),
+		     paddress (arch, pc));
+	  }
+
+	blacklist_function_pc (func_start, name, arch, 0);
+      }
+    }
+}
+
+static void
+blacklist_info (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  int num_printable_entries = 0;
+  int entry_num = -1;
+  int address_width = 10;
+  struct value_print_options opts;
+  struct cleanup *tbl_chain;
+
+  get_user_print_options (&opts);
+
+  if (arg != 0)
+    {
+      entry_num = parse_and_eval_long (arg);
+    }
+
+  /* Count the number of rows in the table and see if we need space for a
+     64-bit address anywhere. */
+  ALL_BLACKLIST_ENTRIES (b)
+    if (entry_num == -1 || b->number == entry_num)
+      {
+	num_printable_entries++;
+	if (b->gdbarch && gdbarch_addr_bit (b->gdbarch) > 32)
+	  address_width = 18;
+      }
+
+  if (num_printable_entries == 0)
+    {
+      if (entry_num == -1)
+	ui_out_message (uiout, 0, "Blacklist is empty.\n");
+      else
+	ui_out_message (uiout, 0,
+			"No blacklist entry numbered %d.\n", entry_num);
+
+      return;
+    }
+
+  if (opts.addressprint)
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (uiout, 5, num_printable_entries,
+					      "BlacklistTable");
+  else
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (uiout, 4, num_printable_entries,
+					      "BlacklistTable");
+
+  ui_out_table_header (uiout, 7, ui_left, "number", "Num");              /* 1 */
+  ui_out_table_header (uiout, 14, ui_left, "type", "Type");              /* 2 */
+  ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");             /* 3 */
+  if (opts.addressprint)
+    {
+      ui_out_table_header (uiout, address_width, ui_left,
+			   "addr", "Address");                           /* 4 */
+    }
+  ui_out_table_header (uiout, 40, ui_noalign, "what", "What");           /* 5 */
+  ui_out_table_body (uiout);
+
+  ALL_BLACKLIST_ENTRIES (b)
+    {
+      struct cleanup *entry_chain;
+
+      QUIT;
+      if (entry_num != -1 && entry_num != b->number)
+	continue;
+
+      entry_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "blklst-entry");
+      ui_out_field_int (uiout, "number", b->number);                     /* 1 */
+
+      if (b->function_name != 0)
+	ui_out_field_string (uiout, "type", "function");                 /* 2 */
+      else if (b->filename != 0)
+	ui_out_field_string (uiout, "type", "file");                     /* 2 */
+      else
+	internal_error (__FILE__, __LINE__, _("\
+Blacklist entry should have either a filename or a function name."));
+
+      if (b->enabled)
+	ui_out_field_string (uiout, "enabled", "y");                     /* 3 */
+      else
+	ui_out_field_string (uiout, "enabled", "n");                     /* 3 */
+
+      if (opts.addressprint)
+	{
+	  if (b->pc != 0)
+	    ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
+	  else
+	    ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
+	}
+
+      if (!b->pending && b->function_name != 0)
+	{
+	   struct symbol *sym;
+	   gdb_assert (b->pc != 0);
+	   sym = find_pc_function (b->pc);
+	   if (sym)
+	     ui_out_field_fmt (uiout, "what", "%s at %s:%d",
+			       sym->ginfo.name,
+			       sym->symtab->filename,
+			       sym->line);
+	   else
+	     ui_out_field_string (uiout, "what", "?");
+	}
+      else if (b->pending && b->function_name != 0)
+	{
+	  ui_out_field_fmt (uiout, "what", "%s (PENDING)",
+			    b->function_name);
+	}
+      else if (!b->pending && b->filename != 0)
+	ui_out_field_string (uiout, "what", b->filename);
+      else if (b->pending && b->filename != 0)
+	ui_out_field_fmt (uiout, "what", "%s (PENDING)",
+			  b->filename);
+
+      ui_out_text (uiout, "\n");
+      do_cleanups (entry_chain);
+    }
+
+  do_cleanups (tbl_chain);
+}
+
+static void
+blacklist_enable_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  int entry_num = parse_and_eval_long (arg);
+  ALL_BLACKLIST_ENTRIES (b)
+    if (b->number == entry_num)
+      {
+	b->enabled = 1;
+	return;
+      }
+
+  error (_("No blacklist entry numbered %d."), entry_num);
+}
+
+static void
+blacklist_disable_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b;
+  int entry_num = parse_and_eval_long (arg);
+  ALL_BLACKLIST_ENTRIES (b)
+    if (b->number == entry_num)
+      {
+	b->enabled = 0;
+	return;
+      }
+
+  error (_("No blacklist entry numbered %d."), entry_num);
+}
+
+/* Command do delete a blacklist entry. */
+static void
+blacklist_delete_command (char *arg, int from_tty)
+{
+  struct blacklist_entry *b, *b_prev;
+  int entry_num = parse_and_eval_long (arg);
+
+  /* We don't need to use a SAFE macro here since we return as soon as we
+     remove an element from the list. */
+  b_prev = 0;
+  ALL_BLACKLIST_ENTRIES (b)
+    if (b->number == entry_num)
+      {
+	if (b_prev != 0)
+	  b_prev->next = b->next;
+	else
+	  blacklist_entry_chain = b->next;
+
+	xfree (b->function_name);
+	xfree (b->filename);
+	xfree (b);
+	return;
+      }
+    else
+      {
+	b_prev = b;
+      }
+
+  error (_("No blacklist entry numbered %d."), entry_num);
+}
+
+/* Create a blacklist entry for the given pc corresponding to the given
+   function name and add it to the list. */
+static void
+blacklist_function_pc (CORE_ADDR pc, char *name, struct gdbarch *arch,
+		       int pending)
+{
+  struct blacklist_entry *b = XZALLOC (struct blacklist_entry);
+  b->pc = pc;
+  b->gdbarch = arch;
+  b->enabled = 1;
+  b->pending = pending;
+  b->function_name = xstrdup (name);
+
+  add_blacklist_entry (b);
+
+  if (!pending)
+    printf_filtered ("Blacklisting function %s at %s.\n",
+		     name, paddress (get_current_arch (), pc));
+  else
+    printf_filtered ("Blacklisting function %s pending shared library load.\n",
+		     name);
+}
+
+/* Add the given blacklist entry to our list, and set the entry's number. */
+static void
+add_blacklist_entry (struct blacklist_entry *b)
+{
+  struct blacklist_entry *b1;
+
+  b->number = ++blacklist_entry_count;
+
+  /* Add to the end of the chain so that the list of
+     blacklist entries will be in numerical order. */
+
+  b1 = blacklist_entry_chain;
+  if (b1 == 0)
+    blacklist_entry_chain = b;
+  else
+    {
+      while (b1->next)
+	b1 = b1->next;
+      b1->next = b;
+    }
+}
+
+/* Does the given pc correspond to the beginning of a blacklisted function? */
+int
+function_pc_is_blacklisted (CORE_ADDR pc)
+{
+  struct symtab_and_line sal;
+  char *filename;
+  struct blacklist_entry *b;
+
+  sal = find_pc_line (pc, 0);
+  filename = sal.symtab->filename;
+
+  ALL_BLACKLIST_ENTRIES (b)
+    {
+      /* First, check whether the file or function this entry is pending on has
+	 been loaded.  It might be more sensible to do this on a solib load,
+	 but that doesn't seem to work for some reason. */
+      if (b->pending)
+	try_resolve_pending_entry (b);
+
+      if (b->enabled && !b->pending
+	  && ((b->pc != 0 && pc == b->pc)
+	      || (b->filename != 0 && filename != 0
+	          && strcmp (filename, b->filename) == 0)))
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Try to look up the file or function corresponding to the given blacklist
+   entry.  If the file or function now exists, update the entry and unmark it
+   as pending. */
+static void
+try_resolve_pending_entry (struct blacklist_entry *b)
+{
+  if (!b->pending)
+    return;
+
+  if (b->filename != 0)
+    {
+      struct symtab *symtab = lookup_symtab (b->filename);
+      if (symtab != 0)
+	{
+	  xfree (b->filename);
+	  b->filename = xstrdup (symtab->filename);
+	  b->gdbarch = get_objfile_arch (symtab->objfile);
+	  b->pending = 0;
+	}
+    }
+  else if (b->function_name != 0)
+    {
+      int not_found = 0;
+      char *func_name = b->function_name;
+      struct symtabs_and_lines sals = decode_line_1 (&func_name, 1, 0, 0, 0,
+						     &not_found);
+
+      if (!not_found && sals.nelts == 1 && strlen (func_name) == 0)
+	{
+	  struct symtab_and_line *sal = &sals.sals[0];
+	  CORE_ADDR pc = sal->pc;
+	  CORE_ADDR func_start = 0;
+	  struct gdbarch *arch = get_sal_arch (sal);
+
+	  if (find_pc_partial_function (pc, &b->function_name, &func_start, 0))
+	    {
+	      b->pending = 0;
+	      b->pc = func_start;
+	      b->gdbarch = arch;
+	    }
+	}
+    }
+}
+
+/* Helper function to get a gdbarch from a symtab_and_line. */
+static struct gdbarch*
+get_sal_arch (struct symtab_and_line *sal)
+{
+  if (sal->section)
+    return get_objfile_arch (sal->section->objfile);
+  if (sal->symtab)
+    return get_objfile_arch (sal->symtab->objfile);
+  return get_current_arch ();
+}
+
+void
+_initialize_step_blacklist (void)
+{
+  struct cmd_list_element *c;
+
+  blacklist_entry_chain = 0;
+  blacklist_entry_count = 0;
+
+  add_prefix_cmd ("blacklist", class_breakpoint, blacklist_function_command, _("\
+Ignore a function while stepping.\n\
+blacklist [FUNCTION NAME]\n\
+If no function name is given, blacklist the current function."),
+                  &blacklistlist, "blacklist ", 1, &cmdlist);
+
+  c = add_cmd ("file", class_breakpoint, blacklist_file_command, _("\
+Ignore a file while stepping.\n\
+blacklist file [FILENAME]\n\
+If no filename is given, blacklist the current file."),
+	       &blacklistlist);
+  set_cmd_completer (c, filename_completer);
+
+  c = add_cmd ("function", class_breakpoint, blacklist_function_command, _("\
+Ignore a function while stepping.\n\
+blacklist function [FUNCTION NAME]\n\
+If no function name is given, blacklist the current function."),
+	       &blacklistlist);
+  set_cmd_completer (c, location_completer);
+
+  add_cmd ("enable", class_breakpoint, blacklist_enable_command, _("\
+Enable a blacklist entry.\n\
+blacklist enable [NUMBER]"),
+	   &blacklistlist);
+
+  add_cmd ("disable", class_breakpoint, blacklist_disable_command, _("\
+Disable a blacklist entry.\n\
+blacklist disable [NUMBER]"),
+	   &blacklistlist);
+
+  add_cmd ("delete", class_breakpoint, blacklist_delete_command, _("\
+Delete a blacklist entry.\n\
+blacklist delete [NUMBER]"),
+           &blacklistlist);
+
+  add_info ("blacklist", blacklist_info, _("\
+Status of blacklist, or of blacklist entry NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tfile        - blacklisted file\n\
+\tfunction    - blacklisted function"));
+}
diff --git a/gdb/blacklist.h b/gdb/blacklist.h
new file mode 100644
index 0000000..b5b5c20
--- /dev/null
+++ b/gdb/blacklist.h
@@ -0,0 +1,27 @@
+/* Header for GDB line completion.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Returns 1 if the given pc was blacklisted and shouldn't be stepped into.
+   Otherwise, returns 0. */
+
+#if !defined (BlACKLIST_H)
+#define BLACKLIST_H
+
+/* Indicates whether the given pc is blacklisted and shouldn't be stepped
+   into. */
+int function_pc_is_blacklisted (CORE_ADDR pc);
+
+#endif /* !defined (BLACKLIST_H) */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 74838e8..8f60bd4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -61,6 +61,7 @@
 #include "valprint.h"
 #include "jit.h"
 #include "xml-syscall.h"
+#include "stack.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -527,19 +528,6 @@ make_cleanup_decref_counted_command_line (struct counted_command_line **cmdp)
   return make_cleanup (do_cleanup_counted_command_line, cmdp);
 }
 
-/* Default address, symtab and line to put a breakpoint at
-   for "break" command with no arg.
-   if default_breakpoint_valid is zero, the other three are
-   not valid, and "break" with no arg is an error.
-
-   This set by print_stack_frame, which calls set_default_breakpoint.  */
-
-int default_breakpoint_valid;
-CORE_ADDR default_breakpoint_address;
-struct symtab *default_breakpoint_symtab;
-int default_breakpoint_line;
-struct program_space *default_breakpoint_pspace;
-
 \f
 /* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
    Advance *PP after the string and any trailing whitespace.
@@ -5174,20 +5162,6 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
     }
 }
 \f
-/* Set the default place to put a breakpoint
-   for the `break' command with no arguments.  */
-
-void
-set_default_breakpoint (int valid, struct program_space *pspace,
-			CORE_ADDR addr, struct symtab *symtab,
-			int line)
-{
-  default_breakpoint_valid = valid;
-  default_breakpoint_pspace = pspace;
-  default_breakpoint_address = addr;
-  default_breakpoint_symtab = symtab;
-  default_breakpoint_line = line;
-}
 
 /* Return true iff it is meaningful to use the address member of
    BPT.  For some breakpoint types, the address member is irrelevant
@@ -7120,20 +7094,23 @@ parse_breakpoint_sals (char **address,
   if ((*address) == NULL
       || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
     {
-      if (default_breakpoint_valid)
+      /* The last displayed codepoint, if it's valid, is our default breakpoint
+         address. */
+      if (last_displayed_codepoint_is_valid ())
 	{
 	  struct symtab_and_line sal;
 	  init_sal (&sal);		/* initialize to zeroes */
 	  sals->sals = (struct symtab_and_line *)
 	    xmalloc (sizeof (struct symtab_and_line));
-	  sal.pc = default_breakpoint_address;
-	  sal.line = default_breakpoint_line;
-	  sal.symtab = default_breakpoint_symtab;
-	  sal.pspace = default_breakpoint_pspace;
+
+	  /* Set sal's pspace, pc, symtab, and line to the values corresponding
+	     to the last call to print_frame_info. */
+	  set_sal_to_last_displayed_codepoint (&sal);
+
 	  sal.section = find_pc_overlay (sal.pc);
 
 	  /* "break" without arguments is equivalent to "break *PC" where PC is
-	     the default_breakpoint_address.  So make sure to set
+	     the last displayed codepoint's address.  So make sure to set
 	     sal.explicit_pc to prevent GDB from trying to expand the list of
 	     sals to include all other instances with the same symtab and line.
 	   */
@@ -7150,19 +7127,22 @@ parse_breakpoint_sals (char **address,
       /* Force almost all breakpoints to be in terms of the
          current_source_symtab (which is decode_line_1's default).  This
          should produce the results we want almost all of the time while
-         leaving default_breakpoint_* alone.  
+         leaving the last displayed codepoint pointers alone.  
          ObjC: However, don't match an Objective-C method name which
          may have a '+' or '-' succeeded by a '[' */
 	 
       struct symtab_and_line cursal = get_current_source_symtab_and_line ();
 			
-      if (default_breakpoint_valid
+      if (last_displayed_codepoint_is_valid ()
 	  && (!cursal.symtab
  	      || ((strchr ("+-", (*address)[0]) != NULL)
  		  && ((*address)[1] != '['))))
-	*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
-			       default_breakpoint_line, addr_string, 
-			       not_found_ptr);
+	{
+	  *sals = decode_line_1 (address, 1,
+				 get_last_displayed_symtab (),
+				 get_last_displayed_line (),
+				 addr_string, not_found_ptr);
+	}
       else
 	*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
 		               addr_string, not_found_ptr);
@@ -8082,9 +8062,11 @@ until_break_command (char *arg, int from_tty, int anywhere)
   /* Set a breakpoint where the user wants it and at return from
      this function */
 
-  if (default_breakpoint_valid)
-    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
-			  default_breakpoint_line, (char ***) NULL, NULL);
+  if (last_displayed_codepoint_is_valid ())
+    sals = decode_line_1 (&arg, 1,
+			  get_last_displayed_symtab (),
+			  get_last_displayed_line (),
+			  (char ***) NULL, NULL);
   else
     sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 
 			  0, (char ***) NULL, NULL);
@@ -8672,10 +8654,11 @@ clear_command (char *arg, int from_tty)
 	xmalloc (sizeof (struct symtab_and_line));
       make_cleanup (xfree, sals.sals);
       init_sal (&sal);		/* initialize to zeroes */
-      sal.line = default_breakpoint_line;
-      sal.symtab = default_breakpoint_symtab;
-      sal.pc = default_breakpoint_address;
-      sal.pspace = default_breakpoint_pspace;
+
+      /* Set sal's line, symtab, pc, and pspace to the values corresponding to
+	 the last call to print_frame_info.  If the codepoint is not valid,
+	 this will set all the fields to 0. */
+      set_sal_to_last_displayed_codepoint (&sal);
       if (sal.symtab == 0)
 	error (_("No source file specified."));
 
@@ -10180,7 +10163,8 @@ invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
       }
 }
 
-/* Use default_breakpoint_'s, or nothing if they aren't valid.  */
+/* Use the last displayed codepoint's values, or nothing 
+   if they aren't valid. */
 
 struct symtabs_and_lines
 decode_line_spec_1 (char *string, int funfirstline)
@@ -10188,11 +10172,13 @@ decode_line_spec_1 (char *string, int funfirstline)
   struct symtabs_and_lines sals;
   if (string == 0)
     error (_("Empty line specification."));
-  if (default_breakpoint_valid)
-    sals = decode_line_1 (&string, funfirstline,
-			  default_breakpoint_symtab,
-			  default_breakpoint_line,
-			  (char ***) NULL, NULL);
+  if (last_displayed_codepoint_is_valid ())
+    {
+      sals = decode_line_1 (&string, funfirstline,
+			    get_last_displayed_symtab (),
+			    get_last_displayed_line (),
+			    (char ***) NULL, NULL);
+    }
   else
     sals = decode_line_1 (&string, funfirstline,
 			  (struct symtab *) NULL, 0, (char ***) NULL, NULL);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 8b7a5c6..50602b2 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -789,9 +789,6 @@ extern struct breakpoint *clone_momentary_breakpoint (struct breakpoint *bpkt);
 
 extern void set_ignore_count (int, int, int);
 
-extern void set_default_breakpoint (int, struct program_space *,
-				    CORE_ADDR, struct symtab *, int);
-
 extern void breakpoint_init_inferior (enum inf_context);
 
 extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index fdeb8db..c401eed 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -185,6 +185,8 @@ struct cmd_list_element *setchecklist;
 
 struct cmd_list_element *showchecklist;
 
+struct cmd_list_element *blacklistlist;
+
 /* Command tracing state.  */
 
 int source_verbose = 0;
@@ -1308,6 +1310,7 @@ init_cmd_lists (void)
   showprintlist = NULL;
   setchecklist = NULL;
   showchecklist = NULL;
+  blacklistlist = NULL;
 }
 
 static void
@@ -1372,7 +1375,7 @@ init_cli_cmds (void)
   char *source_help_text;
 
   /* Define the classes of commands.
-     They will appear in the help list in the reverse of this order.  */
+     They will appear in the help list in alphabetical order.  */
 
   add_cmd ("internals", class_maintenance, NULL, _("\
 Maintenance commands.\n\
diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
index 6a230c0..d561e73 100644
--- a/gdb/gdbcmd.h
+++ b/gdb/gdbcmd.h
@@ -124,6 +124,8 @@ extern struct cmd_list_element *setchecklist;
 
 extern struct cmd_list_element *showchecklist;
 
+extern struct cmd_list_element *blacklistlist;
+
 extern void execute_command (char *, int);
 
 enum command_control_type execute_control_command (struct command_line *);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5f58759..7402fee 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -52,6 +52,7 @@
 #include "inline-frame.h"
 #include "jit.h"
 #include "tracepoint.h"
+#include "blacklist.h"
 
 /* Prototypes for local functions */
 
@@ -4490,7 +4491,8 @@ infrun: not switching back to stepped thread, it has vanished\n");
 	}
 
       /* If we have line number information for the function we are
-         thinking of stepping into, step into it.
+         thinking of stepping into and the function isn't blacklisted,
+	 step into it.
 
          If there are several symtabs at that PC (e.g. with include
          files), just want to know whether *any* of them have line
@@ -4500,7 +4502,8 @@ infrun: not switching back to stepped thread, it has vanished\n");
 
 	tmp_sal = find_pc_line (ecs->stop_func_start, 0);
 	tmp_sal.pspace = get_frame_program_space (frame);
-	if (tmp_sal.line != 0)
+	if (tmp_sal.line != 0 &&
+	    !function_pc_is_blacklisted (ecs->stop_func_start))
 	  {
 	    if (execution_direction == EXEC_REVERSE)
 	      handle_step_into_function_backward (gdbarch, ecs);
diff --git a/gdb/stack.c b/gdb/stack.c
index 53d4aeb..14febd9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -73,6 +73,12 @@ static void print_frame (struct frame_info *frame, int print_level,
 			 enum print_what print_what,  int print_args,
 			 struct symtab_and_line sal);
 
+static void set_last_displayed_codepoint (int valid,
+					  struct program_space *pspace,
+			                  CORE_ADDR addr,
+					  struct symtab *symtab,
+			                  int line);
+
 /* Zero means do things normally; we are interacting directly with the
    user.  One means print the full filename and linenumber when a
    frame is printed, and do so in a format emacs18/emacs19.22 can
@@ -80,6 +86,14 @@ static void print_frame (struct frame_info *frame, int print_level,
    cases and in a slightly different syntax.  */
 
 int annotation_level = 0;
+
+/* These variables hold the last codepoint we displayed to the user.  This is
+   where we insert a breakpoint or a blacklist entry by default. */
+static int last_codepoint_valid = 0;
+static struct program_space *last_codepoint_pspace = 0;
+static CORE_ADDR last_codepoint_addr = 0;
+static struct symtab *last_codepoint_symtab = 0;
+static int last_codepoint_line = 0;
 \f
 
 struct print_stack_frame_args
@@ -650,14 +664,96 @@ print_frame_info (struct frame_info *frame, int print_level,
     }
 
   if (print_what != LOCATION)
-    set_default_breakpoint (1, sal.pspace,
-			    get_frame_pc (frame), sal.symtab, sal.line);
+    set_last_displayed_codepoint (1, sal.pspace,
+			          get_frame_pc (frame), sal.symtab,
+				  sal.line);
 
   annotate_frame_end ();
 
   gdb_flush (gdb_stdout);
 }
 
+/* Remember the last codepoint we displayed, which we use e.g. as the place to
+   put a breakpoint when the `break' command is invoked with no arguments. */
+static void
+set_last_displayed_codepoint (int valid, struct program_space *pspace,
+			      CORE_ADDR addr, struct symtab *symtab,
+			      int line)
+{
+  last_codepoint_valid = valid;
+  last_codepoint_pspace = pspace;
+  last_codepoint_addr = addr;
+  last_codepoint_symtab = symtab;
+  last_codepoint_line = line;
+}
+
+void
+clear_last_displayed_codepoint ()
+{
+  last_codepoint_valid = 0;
+  last_codepoint_pspace = 0;
+  last_codepoint_addr = 0;
+  last_codepoint_symtab = 0;
+  last_codepoint_line = 0;
+}
+
+int
+last_displayed_codepoint_is_valid ()
+{
+  return last_codepoint_valid;
+}
+
+struct program_space*
+get_last_displayed_pspace ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_pspace;
+  return 0;
+}
+
+CORE_ADDR
+get_last_displayed_addr ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_addr;
+  return 0;
+}
+
+struct symtab*
+get_last_displayed_symtab ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_symtab;
+  return 0;
+}
+
+int
+get_last_displayed_line ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_line;
+  return 0;
+}
+
+void
+set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal)
+{
+  if (last_codepoint_valid)
+    {
+      sal->pspace = last_codepoint_pspace;
+      sal->pc = last_codepoint_addr;
+      sal->symtab = last_codepoint_symtab;
+      sal->line = last_codepoint_line;
+    }
+  else
+    {
+      sal->pspace = 0;
+      sal->pc = 0;
+      sal->symtab = 0;
+      sal->line = 0;
+    }
+}
+
 /* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding
    to FRAME.  */
 void
diff --git a/gdb/stack.h b/gdb/stack.h
index 5e874b4..fa08035 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -39,4 +39,14 @@ void iterate_over_block_local_vars (struct block *block,
 				    iterate_over_block_arg_local_vars_cb cb,
 				    void *cb_data);
 
+/* Get or set the last displayed codepoint, which is, e.g. where we set a
+   breakpoint when `break' is supplied with no arguments. */
+void clear_last_displayed_codepoint ();
+int last_displayed_codepoint_is_valid ();
+struct program_space* get_last_displayed_pspace ();
+CORE_ADDR get_last_displayed_addr ();
+struct symtab* get_last_displayed_symtab ();
+int get_last_displayed_line ();
+void set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal);
+
 #endif /* #ifndef STACK_H */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index eda26cc..b56badf 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -56,6 +56,7 @@
 #include "elf-bfd.h"
 #include "solib.h"
 #include "remote.h"
+#include "stack.h"
 
 #include <sys/types.h>
 #include <fcntl.h>
@@ -2709,7 +2710,7 @@ clear_symtab_users (void)
 
   clear_displays ();
   breakpoint_re_set ();
-  set_default_breakpoint (0, NULL, 0, 0, 0);
+  clear_last_displayed_codepoint ();
   clear_pc_function_cache ();
   observer_notify_new_objfile (NULL);
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 024054d..d62ff07 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2010-06-18  Justin Lebar <justin.lebar@gmail.com>
+
+	testsuite/gdb.base/blacklist-solib-lib.c: New
+	testsuite/gdb.base/blacklist-solib-main.c: New
+	testsuite/gdb.base/blacklist-solib.exp: New
+	testsuite/gdb.base/blacklist.c: New
+	testsuite/gdb.base/blacklist.exp: New
+	testsuite/gdb.base/blacklist1.c: New
+	testsuite/gdb.base/Makefile.in: Adding new files.
+
 2010-04-23  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	Fix deadlock on looped list of loaded shared objects.
diff --git a/gdb/testsuite/gdb.base/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in
index 5e8e385..bd54184 100644
--- a/gdb/testsuite/gdb.base/Makefile.in
+++ b/gdb/testsuite/gdb.base/Makefile.in
@@ -1,7 +1,7 @@
 VPATH = @srcdir@
 srcdir = @srcdir@
 
-EXECUTABLES = all-types annota1 bitfields break \
+EXECUTABLES = all-types annota1 bitfields blacklist blacklist-solib break \
 	call-ar-st call-rt-st call-strs callfuncs callfwmall \
 	chng-syms commands compiler condbreak constvars coremaker \
 	dbx-test display ending-run execd-prog exprs \
diff --git a/gdb/testsuite/gdb.base/blacklist-solib-lib.c b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
new file mode 100644
index 0000000..792cd01
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist-solib-lib.c
@@ -0,0 +1,11 @@
+/* Simple shared library */
+
+int square(int num)
+{
+  return multiply(num, num);
+}
+
+int multiply(int a, int b)
+{
+  return a * b;
+}
diff --git a/gdb/testsuite/gdb.base/blacklist-solib-main.c b/gdb/testsuite/gdb.base/blacklist-solib-main.c
new file mode 100644
index 0000000..746bb5f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist-solib-main.c
@@ -0,0 +1,6 @@
+int square(int num);
+
+int main()
+{
+  return square(0);
+}
diff --git a/gdb/testsuite/gdb.base/blacklist-solib.exp b/gdb/testsuite/gdb.base/blacklist-solib.exp
new file mode 100644
index 0000000..d6b8bb5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist-solib.exp
@@ -0,0 +1,129 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Justin Lebar. (justin.lebar@gmail.com)
+
+#
+# Tests blacklisting shared libraries.
+#
+
+# This only works on GNU/Linux.
+if { ![isnative] || [is_remote host] || ![istarget *-linux*] || [skip_shlib_tests]} {
+    continue
+}
+
+set test "blacklist-solib"
+set srcfile_main "${test}-main.c"
+set binfile_main "${objdir}/${subdir}/${test}-test"
+set srcfile_lib "${test}-lib.c"
+set libname "lib${test}"
+set binfile_lib ${objdir}/${subdir}/${libname}.so
+
+#
+# Compile our program under test.  The main program references a shared library
+# libblacklist-solib.so, which contains two functions, square(), which is
+# referenced by the main program, and multiply(), which is not referenced by
+# the main program.
+#
+
+if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} [list debug additional_flags=-fPIC -Wl,-soname,${libname}.so]] != ""} {
+    return -1
+}
+
+if {[gdb_compile "${srcdir}/${subdir}/${srcfile_main}" "${binfile_main}.o" object debug] != ""} {
+    return -1
+}
+
+if {[gdb_compile "${binfile_main}.o" "${binfile_main}" executable \
+                 [list debug "additional_flags=-L${objdir}/${subdir} -l${test} \
+                                               -Wl,-rpath=${objdir}/${subdir}"]] != ""} {
+    return -1
+}
+
+gdb_start
+gdb_load ${binfile_main}
+
+#
+# At this point, if we try to blacklist the file ${srcfile_lib} or the function
+# multiply(), we should get a prompt asking us if we want to enable the
+# blacklist entry pending a shared library load.
+#
+
+gdb_test "blacklist file ${srcfile_lib}" \
+"Blacklisting file ${srcfile_lib}." \
+"blacklisting file in solib" \
+"No source file named ${srcfile_lib}.*
+Add file to blacklist pending future shared library load.*"\
+"y"
+
+#
+# Does info blacklist list this entry as pending?
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+n/a\\s+${srcfile_lib} \\(PENDING\\)\\s*" \
+"info blacklist with pending file"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+
+#
+# We shouldn't step into square(), since we blacklisted blacklist-solib-lib.c.
+#
+gdb_test "step" ""
+gdb_test "bt" "#0\\s+main.*" "step after blacklisting solib file."
+
+#
+# Our entry should no longer be pending.  Note that we unfortunately need to do
+# at least one step before the entry will be unmarked as pending.
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+n/a\\s+.*${srcfile_lib}\\s*" \
+"info blacklist with pending file"
+
+#
+# Now restart gdb and testing blacklisting of a function inside a solib.
+#
+gdb_exit
+gdb_start
+gdb_load ${binfile_main}
+
+gdb_test "blacklist function multiply" \
+"Blacklisting function multiply pending shared library load." \
+"blacklisting function in solib" \
+"No function found named multiply..*
+Add function to blacklist pending future shared library load.*"\
+"y"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+
+#
+# Our first step should take us into square.
+#
+gdb_test "step" "square.*"
+
+#
+# Now our entry should no longer be pending.
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+function\\s+y\\s+0x\[0-9a-f\]+\\s+multiply at .*${srcfile_lib}:.*\\s*" \
+
+#
+# This step shouldn't go into multiply -- we should skip it and go on to the
+# last line of square.
+#
+gdb_test "step" ""
+gdb_test "bt" "#0\\s+square.*"
diff --git a/gdb/testsuite/gdb.base/blacklist.c b/gdb/testsuite/gdb.base/blacklist.c
new file mode 100644
index 0000000..565ba93
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist.c
@@ -0,0 +1,13 @@
+int foo();
+int bar();
+int baz(int, int);
+
+int main()
+{
+  return baz(foo(), bar());
+}
+
+int foo()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/blacklist.exp b/gdb/testsuite/gdb.base/blacklist.exp
new file mode 100644
index 0000000..ed1afb8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist.exp
@@ -0,0 +1,140 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Justin Lebar. (justin.lebar@gmail.com)
+
+if { [prepare_for_testing blacklist.exp "blacklist" \
+                          {blacklist.c blacklist1.c } \
+                          {debug nowarnings}] } {
+    return -1
+}
+
+set srcfile blacklist.c
+set srcfile1 blacklist1.c
+
+#
+# Right after we start gdb, there's no default file or function to blacklist.
+#
+gdb_test "blacklist file" "No default blacklist file now."
+gdb_test "blacklist function" "No default blacklist function now."
+gdb_test "blacklist" "No default blacklist function now."
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+
+#
+# Test |info blacklist| with an empty blacklist.
+#
+gdb_test "info blacklist" "Blacklist is empty." "info blacklist empty"
+
+#
+# Create a blacklist entry for the current file and function.
+#
+gdb_test "blacklist file" "Blacklisting file .*$srcfile."
+gdb_test "blacklist" "Blacklisting function main() at .*\."
+
+#
+# Create a blacklist entry for a specified file and function.
+#
+gdb_test "blacklist file blacklist1.c" "Blacklisting file .*$srcfile1."
+gdb_test "blacklist function baz" "Blacklisting function baz at .*"
+
+#
+# Test bad blacklist entry modification commands
+#
+gdb_test "blacklist enable 999" "No blacklist entry numbered 999."
+gdb_test "blacklist disable 999" "No blacklist entry numbered 999."
+gdb_test "blacklist delete 999" "No blacklist entry numbered 999."
+gdb_test "blacklist enable" "Argument required \\(expression to compute\\)."
+gdb_test "blacklist disable" "Argument required \\(expression to compute\\)."
+gdb_test "blacklist delete" "Argument required \\(expression to compute\\)."
+gdb_test "blacklist enable a" "No symbol \"a\" in current context."
+gdb_test "blacklist disable a" "No symbol \"a\" in current context."
+gdb_test "blacklist delete a" "No symbol \"a\" in current context."
+
+#
+# Test that blacklist function doesn't allow extra characters at the end of its
+# arguments list.
+#
+gdb_test "blacklist function foo bar" "Junk at end of arguments."
+
+#
+# Ask for info on a blacklist entry which doesn't exist.
+#
+gdb_test "info blacklist 999" "No blacklist entry numbered 999."
+
+#
+# Does |info blacklist| look right?
+#
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+n/a.*$srcfile\\s*
+2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
+4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
+
+#
+# Right now, we have an outstanding blacklist on both source files, so when we
+# step into the first line in main(), we should step right over it and go to
+# the second line of main().
+#
+if ![runto_main] { fail "blacklist tests suppressed" }
+send_gdb "step\n"
+gdb_test "bt" "#0\\s+main.*" "step after all blacklisted"
+
+#
+# Now remove blacklist.c from the blacklist.  Our first step should take us
+# into foo(), and our second step should take us to the next line in main().
+#
+send_gdb "blacklist delete 1\n"
+# Check that entry 1 is missing from |info blacklist|
+gdb_test "info blacklist" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+y\\s+n/a.*$srcfile1\\s*
+4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
+
+#
+# Now disable our blacklisting of blacklist1.c.  We should now step into foo(),
+# then into bar(), but not into baz().
+#
+send_gdb "blacklist disable 3\n"
+# Is entry 3 disabled in |info blacklist|?
+gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+n.*" \
+         "info blacklist shows entry as disabled"
+
+if ![runto_main] { fail "blacklist tests suppressed" }
+gdb_test "step" "bar \\(\\) at.*" "step after disabling 3 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "foo \\(\\) at.*" "step after disabling 3 (2)"
+send_gdb "step\n"; # Return from bar()
+gdb_test "step" "main \\(\\) at.*" "step after disabling 3 (3)"
+
+#
+# Enable blacklist entry 3 and make sure we step over it like before.
+#
+send_gdb "blacklist enable 3\n"
+# Is entry 3 enabled in |info blacklist|?
+gdb_test "info blacklist 3" ".*\\n3\\s+file\\s+y.*" \
+         "info blacklist shows entry as enabled"
+if ![runto_main] { fail "blacklist tests suppressed" }
+gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
+
diff --git a/gdb/testsuite/gdb.base/blacklist1.c b/gdb/testsuite/gdb.base/blacklist1.c
new file mode 100644
index 0000000..2dab5c3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/blacklist1.c
@@ -0,0 +1,9 @@
+int bar()
+{
+  return 1;
+}
+
+int baz(int a, int b)
+{
+  return a + b;
+}

[-- Attachment #3: bug11614 --]
[-- Type: application/octet-stream, Size: 1806 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 148219e..969f31d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2010-06-25  Justin Lebar <justin.lebar@gmail.com>
+
+	* linespec.c (decode_variable): Passing a non-null not_found_ptr
+	prevents an error from being thrown if the function cannot be found.
+	* breakpoint.c (create_breakpoint): Pass a null not_found_ptr to
+	decode_variable so we get an exception when a function cannot be
+	found, as desired.
+
 2010-04-24  Pedro Alves  <pedro@codesourcery.com>
 
 	* defs.h: Adjust comment.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3dca17e..74838e8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7336,7 +7336,6 @@ create_breakpoint (struct gdbarch *gdbarch,
   struct captured_parse_breakpoint_args parse_args;
   int i;
   int pending = 0;
-  int not_found = 0;
   enum bptype type_wanted;
   int task = 0;
   int prev_bkpt_count = breakpoint_count;
@@ -7348,7 +7347,7 @@ create_breakpoint (struct gdbarch *gdbarch,
   parse_args.arg_p = &arg;
   parse_args.sals_p = &sals;
   parse_args.addr_string_p = &addr_string;
-  parse_args.not_found_ptr = &not_found;
+  parse_args.not_found_ptr = 0;
 
   e = catch_exception (uiout, do_captured_parse_breakpoint, 
 		       &parse_args, RETURN_MASK_ALL);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index c5ea28a..19727b5 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1857,7 +1857,13 @@ decode_variable (char *copy, int funfirstline, char ***canonical,
     return minsym_found (funfirstline, msymbol);
 
   if (not_found_ptr)
-    *not_found_ptr = 1;
+    {
+      struct symtabs_and_lines sals;
+      *not_found_ptr = 1;
+      sals.sals = 0;
+      sals.nelts = 0;
+      return sals;
+    }
 
   if (!have_full_symbols ()
       && !have_partial_symbols ()

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-06-28 17:44   ` Justin Lebar
@ 2010-07-20 21:03     ` Tom Tromey
  2010-07-23 19:50       ` Justin Lebar
  0 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2010-07-20 21:03 UTC (permalink / raw)
  To: Justin Lebar; +Cc: gdb-patches

>>>>> "Justin" == Justin Lebar <justin.lebar@gmail.com> writes:

Tom> One concern of mine is that this code will not perform well with many
Tom> blacklists in place.  It may make sense to keep a hash table indexed by
Tom> name (function or file), to make lookups faster.  What do you think?

Justin> I imagine you'd have to have a pretty large blacklist to notice
Justin> a delay when using gdb interactively, even on modest hardware.
Justin> I don't know much about gdb scripting -- this might matter more
Justin> in that case.  But would one single-step in a script?

Justin> FWIW, enabling/disabling/deleting breakpoints takes time linear
Justin> to the number of breakpoints.

Yeah, good points, let's just leave it as is.

Tom> Another random thought is whether we want to be able to blacklist based
Tom> on objfile name.

Justin> That seems like it might be nice.  Regular expression matching
Justin> on file and function names has also been suggested.

All good ideas; it is fine to defer these if you'd rather.

Justin> While I'm thinking about it, one problem I've run into while
Justin> using this patch while debugging Firefox is that we somehow load
Justin> multiple copies of our smart pointer header, so I have to
Justin> blacklist both ../../nsCOMPtr.h and ../../../nsCOMPtr.h.  I need
Justin> to investigate further exactly what about our build system is
Justin> causing this to see if it's something which should be fixed in
Justin> gdb or Mozilla's build, but my guess is that we may want to
Justin> support this in gdb somehow.

Allowing regular expressions is a solid gdb tradition.

Justin> This patch also fixes bug 11614: decode_variable() in linespec.c
Justin> does not obey its contract

Tom> It is somewhat preferred in gdb to submit things like this as separate
Tom> patches.

Justin> I've split them out in this new set.  Because you need the
Justin> bug11614 patch in order for the blacklist patch to work (and
Justin> since bug11614 is a trivial fix), I've included both attachments
Justin> in this one e-mail.

This patch is ok.  Please check it in.

Mention the PR in the ChangeLog entry, like:

2010-06-25  Justin Lebar <justin.lebar@gmail.com>

	PR gdb/11614:
	* linespec.c (decode_variable): Passing a non-null not_found_ptr
[...]

If you do this, and then use the ChangeLog entry as the commit message,
the commit will show up in bugzilla.

Justin> +         if (b->pc != 0)
Justin> +           ui_out_field_core_addr (uiout, "addr", b->gdbarch, b->pc);   /* 4 */
Justin> +         else
Justin> +           ui_out_field_string (uiout, "addr", "n/a");                  /* 4 */
Justin> +       }

Tom> A small nit, but I'm not sure about the exact string "n/a" here.
Tom> If there is an analogous situation elsewhere it would be good to just do
Tom> whatever is done there.

Justin> We could just use the empty string if that would be clearer.

Yeah, I think so.

Justin> +      /* First, check whether the file or function this entry is pending on has
Justin> +        been loaded.  It might be more sensible to do this on a solib load,
Justin> +        but that doesn't seem to work for some reason. */

Tom> Let's figure this out.

Justin> I spent a while in #gdb with a few people (I don't recall who)
Justin> and we couldn't figure this out.  I added a solib load observer,
Justin> but from within it, find_pc_partial_function always failed.

Justin> I'm not sure where to look to figure out what's going on.

Offhand I'm not sure either, I think all you can do is debug the
particular call.

Tom> Also, since the blacklist includes a PC value, I think you have to reset
Tom> it when re-running the inferior, and on some other state changes as well.

Justin> Hm.  How do we handle this with breakpoints?

See breakpoint_re_set.

Tom> I think it would be more usual to make the commands "enable blacklist ..."
Tom> instead of "blacklist enable ...".  Likewise for disable and delete.

Justin> I'm not sure I like "enable blacklist".  The problem is that
Justin> "blacklist" is a noun referring to the list of all functions we
Justin> skip and also a verb meaning "add an entry to the blacklist".
Justin> "Enable blacklist" sounds to me like we're enabling an entire
Justin> list of blacklist entries.

Yeah, that makes sense.

Justin> Maybe we can name the thing which indicates that we shouldn't
Justin> step into a function something less confusing than a "blacklist
Justin> entry"?

Yes, that would be good.  Any ideas for names?

Tom

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-07-20 21:03     ` Tom Tromey
@ 2010-07-23 19:50       ` Justin Lebar
  2011-04-25 19:35         ` Justin Lebar
  0 siblings, 1 reply; 10+ messages in thread
From: Justin Lebar @ 2010-07-23 19:50 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Justin> I'm not sure I like "enable blacklist".  The problem is that
Justin> "blacklist" is a noun referring to the list of all functions we
Justin> skip and also a verb meaning "add an entry to the blacklist".
Justin> "Enable blacklist" sounds to me like we're enabling an entire
Justin> list of blacklist entries.

Tom> Yeah, that makes sense.
Tom> Yes, that would be good.  Any ideas for names?

Maybe we could use "skip":

skip function foo
skip file bar
info skip
delete skip 1
disable skip 42

"Ignore" might also work, but I don't like "delete ignore 1", or
"enable ignore 2".

-Justin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2010-07-23 19:50       ` Justin Lebar
@ 2011-04-25 19:35         ` Justin Lebar
  2011-05-16 21:04           ` Justin Lebar
  0 siblings, 1 reply; 10+ messages in thread
From: Justin Lebar @ 2011-04-25 19:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1360 bytes --]

After many months of inactivity, I finally have time to work on this
again.  I'm really sorry for the delay.

I've attached a patch for tip of trunk.  I renamed the command from
"blacklist" to "skip".

The one major issue outstanding on the previous patch was that every
time you stepped, I tried to resolve all skips pending a shared
library load.  I did this because registering a solib load listener
didn't work -- somehow even after I was notified of the load, the
solib's symbols weren't available.

I hacked around this problem by putting a call to skip_re_set at the
end of breakpoint_re_set.

-Justin

On Fri, Jul 23, 2010 at 3:50 PM, Justin Lebar <justin.lebar@gmail.com> wrote:
> Justin> I'm not sure I like "enable blacklist".  The problem is that
> Justin> "blacklist" is a noun referring to the list of all functions we
> Justin> skip and also a verb meaning "add an entry to the blacklist".
> Justin> "Enable blacklist" sounds to me like we're enabling an entire
> Justin> list of blacklist entries.
>
> Tom> Yeah, that makes sense.
> Tom> Yes, that would be good.  Any ideas for names?
>
> Maybe we could use "skip":
>
> skip function foo
> skip file bar
> info skip
> delete skip 1
> disable skip 42
>
> "Ignore" might also work, but I don't like "delete ignore 1", or
> "enable ignore 2".
>
> -Justin
>

[-- Attachment #2: skips --]
[-- Type: application/octet-stream, Size: 48074 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 326e5a9..d8de28e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,40 @@
+2011-04-23  Justin Lebar  <justin.lebar@gmail.com>
+
+	* Makefile.in: (SFILES): Add skip.c.
+	(HFILES_NO_SRCDIR): Add skip.h.
+	(COMMON_OBS): Add skip.o.
+	* skip.h, skip.c: New
+	* breakpoint.h (set_default_breakpoint): removed
+	* breakpoint.c: Removed default_breakpoint_valid,
+	default_breakpoint_address, default_breakpoint_symtab,
+	default_breakpoint_line, default_breakpoint_pspace variables.
+	(set_default_breakpoint): Removed
+	(parse_breakpoint_sals, create_breakpoint, clear_command,
+	decode_line_spec_1): Removed uses of default_breakpoint variables;
+	replaced with function calls into stack.c.
+	* cli/cli-cmds.h: Added cmd_list_element *skiplist.
+	* cli/cli-cmds.c: Added skiplist.
+	(init_cmd_lists): Initialize skiplist.
+	(init_cli_cmds): Fixed comment (classes of commands appear in
+	alphabetical order).
+	* infrun.c (handle_inferior_event): Added check that we don't step
+	into a function whose pc is marked for skip.
+	* stack.c: Added last_codepoint_valid, last_codepoint_pspace,
+	last_codepoint_addr, last_codepoint_symtab, last_codepoint_line
+	variables.
+	(set_last_displayed_codepoint): New static function.
+	(print_frame_info): Switched call to set_default_breakpoint to call to
+	set_last_displayed_codepoint.
+	(clear_last_displayed_codepoint,
+	last_displayed_codepoint_is_valid, get_last_displayed_pspace,
+	get_last_displayed_addr, get_last_displayed_symtab,
+	get_last_displayed_line, set_sal_to_last_displayed_codepoint): New
+	public functions.
+	* stack.h (clear_last_displayed_codepoint,
+	last_displayed_codepoint_is_valid, get_last_displayed_pspace,
+	get_last_displayed_addr, get_last_displayed_symtab,
+	get_last_displayed_line, set_sal_to_last_displayed_codepoint): Added
+
 2011-04-21  Jie Zhang  <jzhang918@gmail.com>
 
 	* MAINTAINERS: Update my email address.
@@ -210,6 +247,7 @@
 	(symbol_file_add): Pass NULL to the new parameter parent.
 	* symfile.h (symbol_file_add_from_bfd): New parameter parent.
 
+<<<<<<< HEAD
 2011-04-17  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	* elfread.c (elf_symtab_read): Do not ignore .L symbols if they are
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5bab360..ae2a299 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -719,7 +719,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	prologue-value.c psymtab.c \
 	regcache.c reggroups.c remote.c remote-fileio.c reverse.c \
 	sentinel-frame.c \
-	serial.c ser-base.c ser-unix.c \
+	serial.c ser-base.c ser-unix.c skip.c \
 	solib.c solib-target.c source.c \
 	stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
 	symtab.c \
@@ -814,7 +814,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
-gnulib/stddef.in.h inline-frame.h
+gnulib/stddef.in.h inline-frame.h skip.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -899,7 +899,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	prologue-value.o memory-map.o memrange.o xml-support.o xml-syscall.o \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
 	inferior.o osdata.o gdb_usleep.o record.o gcore.o \
-	jit.o progspace.o
+	jit.o progspace.o skip.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3dbee85..bb97558 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -64,6 +64,8 @@
 #include "xml-syscall.h"
 #include "parser-defs.h"
 #include "cli/cli-utils.h"
+#include "stack.h"
+#include "skip.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -543,19 +545,6 @@ make_cleanup_decref_counted_command_line (struct counted_command_line **cmdp)
   return make_cleanup (do_cleanup_counted_command_line, cmdp);
 }
 
-/* Default address, symtab and line to put a breakpoint at
-   for "break" command with no arg.
-   If default_breakpoint_valid is zero, the other three are
-   not valid, and "break" with no arg is an error.
-
-   This set by print_stack_frame, which calls set_default_breakpoint.  */
-
-int default_breakpoint_valid;
-CORE_ADDR default_breakpoint_address;
-struct symtab *default_breakpoint_symtab;
-int default_breakpoint_line;
-struct program_space *default_breakpoint_pspace;
-
 \f
 /* Return the breakpoint with the specified number, or NULL
    if the number does not refer to an existing breakpoint.  */
@@ -5443,20 +5432,6 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
     }
 }
 \f
-/* Set the default place to put a breakpoint
-   for the `break' command with no arguments.  */
-
-void
-set_default_breakpoint (int valid, struct program_space *pspace,
-			CORE_ADDR addr, struct symtab *symtab,
-			int line)
-{
-  default_breakpoint_valid = valid;
-  default_breakpoint_pspace = pspace;
-  default_breakpoint_address = addr;
-  default_breakpoint_symtab = symtab;
-  default_breakpoint_line = line;
-}
 
 /* Return true iff it is meaningful to use the address member of
    BPT.  For some breakpoint types, the address member is irrelevant
@@ -7654,24 +7629,26 @@ parse_breakpoint_sals (char **address,
   if ((*address) == NULL
       || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
     {
-      if (default_breakpoint_valid)
+      /* The last displayed codepoint, if it's valid, is our default breakpoint
+         address. */
+      if (last_displayed_codepoint_is_valid ())
 	{
 	  struct symtab_and_line sal;
 
 	  init_sal (&sal);		/* Initialize to zeroes.  */
 	  sals->sals = (struct symtab_and_line *)
 	    xmalloc (sizeof (struct symtab_and_line));
-	  sal.pc = default_breakpoint_address;
-	  sal.line = default_breakpoint_line;
-	  sal.symtab = default_breakpoint_symtab;
-	  sal.pspace = default_breakpoint_pspace;
-	  sal.section = find_pc_overlay (sal.pc);
+
+	  /* Set sal's pspace, pc, symtab, and line to the values
+	     corresponding to the last call to print_frame_info. */
+	  set_sal_to_last_displayed_codepoint (&sal);
+          sal.section = find_pc_overlay (sal.pc);
 
 	  /* "break" without arguments is equivalent to "break *PC"
-	     where PC is the default_breakpoint_address.  So make sure
-	     to set sal.explicit_pc to prevent GDB from trying to
-	     expand the list of sals to include all other instances
-	     with the same symtab and line.  */
+	     where PC is the last displayed codepoint's address.  So
+	     make sure to set sal.explicit_pc to prevent GDB from
+	     trying to expand the list of sals to include all other
+	     instances with the same symtab and line.  */
 	  sal.explicit_pc = 1;
 
 	  sals->sals[0] = sal;
@@ -7685,19 +7662,22 @@ parse_breakpoint_sals (char **address,
       /* Force almost all breakpoints to be in terms of the
          current_source_symtab (which is decode_line_1's default).
          This should produce the results we want almost all of the
-         time while leaving default_breakpoint_* alone.
+	 time while leaving the last displayed codepoint pointers
+	 alone.
 
          ObjC: However, don't match an Objective-C method name which
          may have a '+' or '-' succeeded by a '[' */
 	 
       struct symtab_and_line cursal = get_current_source_symtab_and_line ();
 			
-      if (default_breakpoint_valid
+      if (last_displayed_codepoint_is_valid ()
 	  && (!cursal.symtab
  	      || ((strchr ("+-", (*address)[0]) != NULL)
  		  && ((*address)[1] != '['))))
-	*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
-			       default_breakpoint_line, canonical);
+	*sals = decode_line_1 (address, 1,
+			       get_last_displayed_symtab (),
+			       get_last_displayed_line (),
+			       canonical);
       else
 	*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
 		               canonical);
@@ -9277,9 +9257,11 @@ until_break_command (char *arg, int from_tty, int anywhere)
   /* Set a breakpoint where the user wants it and at return from
      this function.  */
 
-  if (default_breakpoint_valid)
-    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
-			  default_breakpoint_line, NULL);
+  if (last_displayed_codepoint_is_valid ())
+    sals = decode_line_1 (&arg, 1,
+			  get_last_displayed_symtab (),
+			  get_last_displayed_line (),
+			  NULL);
   else
     sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
 
@@ -9875,10 +9857,11 @@ clear_command (char *arg, int from_tty)
 	xmalloc (sizeof (struct symtab_and_line));
       make_cleanup (xfree, sals.sals);
       init_sal (&sal);		/* Initialize to zeroes.  */
-      sal.line = default_breakpoint_line;
-      sal.symtab = default_breakpoint_symtab;
-      sal.pc = default_breakpoint_address;
-      sal.pspace = default_breakpoint_pspace;
+
+      /* Set sal's line, symtab, pc, and pspace to the values
+	 corresponding to the last call to print_frame_info.  If the
+	 codepoint is not valid, this will set all the fields to 0. */
+      set_sal_to_last_displayed_codepoint (&sal);
       if (sal.symtab == 0)
 	error (_("No source file specified."));
 
@@ -11203,6 +11186,9 @@ breakpoint_re_set (void)
   create_longjmp_master_breakpoint ();
   create_std_terminate_master_breakpoint ();
   create_exception_master_breakpoint ();
+
+  /* While we're at it, reset the skip list too. */
+  skip_re_set ();
 }
 \f
 /* Reset the thread number of this breakpoint:
@@ -11635,7 +11621,8 @@ invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
       }
 }
 
-/* Use default_breakpoint_'s, or nothing if they aren't valid.  */
+/* Use the last displayed codepoint's values, or nothing 
+   if they aren't valid. */
 
 struct symtabs_and_lines
 decode_line_spec_1 (char *string, int funfirstline)
@@ -11644,10 +11631,10 @@ decode_line_spec_1 (char *string, int funfirstline)
 
   if (string == 0)
     error (_("Empty line specification."));
-  if (default_breakpoint_valid)
+  if (last_displayed_codepoint_is_valid ())
     sals = decode_line_1 (&string, funfirstline,
-			  default_breakpoint_symtab,
-			  default_breakpoint_line,
+			  get_last_displayed_symtab (),
+			  get_last_displayed_line (),
 			  NULL);
   else
     sals = decode_line_1 (&string, funfirstline,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..9df1ae1 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -946,9 +946,6 @@ extern struct breakpoint *clone_momentary_breakpoint (struct breakpoint *bpkt);
 
 extern void set_ignore_count (int, int, int);
 
-extern void set_default_breakpoint (int, struct program_space *,
-				    CORE_ADDR, struct symtab *, int);
-
 extern void breakpoint_init_inferior (enum inf_context);
 
 extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 7fd2f50..38580e9 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -185,6 +185,8 @@ struct cmd_list_element *setchecklist;
 
 struct cmd_list_element *showchecklist;
 
+struct cmd_list_element *skiplist;
+
 /* Command tracing state.  */
 
 int source_verbose = 0;
@@ -1330,6 +1332,7 @@ init_cmd_lists (void)
   showprintlist = NULL;
   setchecklist = NULL;
   showchecklist = NULL;
+  skiplist = NULL;
 }
 
 static void
@@ -1395,7 +1398,7 @@ init_cli_cmds (void)
   char *source_help_text;
 
   /* Define the classes of commands.
-     They will appear in the help list in the reverse of this order.  */
+     They will appear in the help list in alphabetical order.  */
 
   add_cmd ("internals", class_maintenance, NULL, _("\
 Maintenance commands.\n\
diff --git a/gdb/cli/cli-cmds.h b/gdb/cli/cli-cmds.h
index e79dcf0..73ccdd2 100644
--- a/gdb/cli/cli-cmds.h
+++ b/gdb/cli/cli-cmds.h
@@ -106,6 +106,8 @@ extern struct cmd_list_element *setchecklist;
 
 extern struct cmd_list_element *showchecklist;
 
+extern struct cmd_list_element *skiplist;
+
 /* Exported to gdb/top.c */
 
 void init_cmd_lists (void);
diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
index c02ce69..606b812 100644
--- a/gdb/gdbcmd.h
+++ b/gdb/gdbcmd.h
@@ -124,6 +124,8 @@ extern struct cmd_list_element *setchecklist;
 
 extern struct cmd_list_element *showchecklist;
 
+extern struct cmd_list_element *skiplist;
+
 /* Chain containing all defined "save" subcommands.  */
 
 extern struct cmd_list_element *save_cmdlist;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 8eccb60..6ea633e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -54,6 +54,7 @@
 #include "inline-frame.h"
 #include "jit.h"
 #include "tracepoint.h"
+#include "skip.h"
 
 /* Prototypes for local functions */
 
@@ -4671,7 +4672,8 @@ process_event_stop_test:
 	}
 
       /* If we have line number information for the function we are
-         thinking of stepping into, step into it.
+	 thinking of stepping into and the function isn't on the skip
+	 list, step into it.
 
          If there are several symtabs at that PC (e.g. with include
          files), just want to know whether *any* of them have line
@@ -4680,7 +4682,8 @@ process_event_stop_test:
 	struct symtab_and_line tmp_sal;
 
 	tmp_sal = find_pc_line (ecs->stop_func_start, 0);
-	if (tmp_sal.line != 0)
+	if (tmp_sal.line != 0 &&
+	    !function_pc_is_marked_for_skip (ecs->stop_func_start))
 	  {
 	    if (execution_direction == EXEC_REVERSE)
 	      handle_step_into_function_backward (gdbarch, ecs);
diff --git a/gdb/skip.c b/gdb/skip.c
new file mode 100644
index 0000000..e080241
--- /dev/null
+++ b/gdb/skip.c
@@ -0,0 +1,573 @@
+/* Header for GDB line completion.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "skip.h"
+#include "value.h"
+#include "valprint.h"
+#include "ui-out.h"
+#include "gdb_string.h"
+#include "symtab.h"
+#include "gdbcmd.h"
+#include "command.h"
+#include "completer.h"
+#include "stack.h"
+#include "arch-utils.h"
+#include "linespec.h"
+#include "objfiles.h"
+#include "exceptions.h"
+
+struct skiplist_entry
+{
+  int number;
+
+  /* null if this isn't a skiplist entry for an entire file.
+     The skiplist entry owns this pointer. */
+  char *filename;
+
+  /* The name of the marked-for-skip function, if this is a skiplist
+     entry for a function.  Note that this might be non-null even if
+     the pc is 0 if the entry is pending a shared library load.
+
+     The skiplist entry owns this pointer. */
+  char *function_name;
+
+  /* 0 if this is a skiplist entry for an entire file, or if this
+     entry will be on a function, pending a shared library load. */
+  CORE_ADDR pc;
+
+  /* Architecture we used to create the skiplist entry. May be null 
+     if the entry is pending a shared library load. */
+  struct gdbarch *gdbarch;
+
+  int enabled;
+  int pending;
+
+  struct skiplist_entry *next;
+};
+
+static void skip_function_command (char *arg, int from_tty);
+static void skip_file_command (char *arg, int from_tty);
+static void skip_info (char *arg, int from_tty);
+
+static void add_skiplist_entry (struct skiplist_entry *e);
+static void skip_function_pc (CORE_ADDR pc, char *name,
+			      struct gdbarch *arch,
+			      int pending);
+//static void try_resolve_pending_entry (struct skiplist_entry *e);
+static struct gdbarch *get_sal_arch (struct symtab_and_line *sal);
+
+static struct skiplist_entry *skiplist_entry_chain;
+static int skiplist_entry_count;
+
+#define ALL_SKIPLIST_ENTRIES(E) \
+  for (E = skiplist_entry_chain; E; E = E->next)
+
+static void
+skip_file_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e;
+  struct symtab *symtab;
+  int pending = 0;
+  char *filename = 0;
+
+  /* If no argument was given, try to default to the last
+     displayed codepoint. */
+  if (arg == 0)
+    {
+      symtab = get_last_displayed_symtab ();
+      if (symtab == 0)
+	error (_("No default file now."));
+      else
+	filename = symtab->filename;
+    }
+  else
+    {
+      symtab = lookup_symtab (arg);
+      if (symtab == 0)
+	{
+	  fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg);
+	  if (!nquery (_("\
+Ignore file pending future shared library load? ")))
+	    return;
+
+	  pending = 1;
+	  filename = arg;
+	}
+      else
+	filename = symtab->filename;
+    }
+
+  e = XZALLOC (struct skiplist_entry);
+  e->filename = xstrdup (filename);
+  e->enabled = 1;
+  e->pending = pending;
+  if (symtab != 0)
+    e->gdbarch = get_objfile_arch (symtab->objfile);
+
+  add_skiplist_entry (e);
+
+  printf_filtered (_("File %s will be skipped when stepping.\n"), filename);
+}
+
+static void
+skip_function_command (char *arg, int from_tty)
+{
+  CORE_ADDR func_pc;
+  char *name = NULL;
+
+  /* Default to the current function if no argument is given. */
+  if (arg == 0)
+    {
+      CORE_ADDR pc;
+      if (!last_displayed_codepoint_is_valid ())
+	error (_("No default function now."));
+
+      pc = get_last_displayed_addr ();
+      if (!find_pc_partial_function (pc, &name, &func_pc, 0))
+	{
+	  error (_("No function found containing current program point %s."),
+		  paddress (get_current_arch (), pc));
+	}
+      skip_function_pc (func_pc, name, get_current_arch (), 0);
+    }
+  else
+    {
+      /* Decode arg.  We set funfirstline=1 so decode_line_1 will give us the
+	 first line of the function specified, if it can, and so that we'll
+	 reject variable names and the like. */
+
+      int i;
+      int pending = 0;
+      char *orig_arg = arg; /* decode_line_1 modifies the arg pointer. */
+      volatile struct gdb_exception decode_exception;
+      struct symtabs_and_lines sals;
+
+      TRY_CATCH(decode_exception, NOT_FOUND_ERROR)
+	{
+	  sals = decode_line_1 (&arg, 1, 0, 0, 0);
+	}
+
+      if (decode_exception.reason < 0)
+        {
+	  fprintf_filtered (gdb_stderr,
+			    _("No function found named %s.\n"), orig_arg);
+
+	  if (nquery (_("\
+Ignore function pending future shared library load? ")))
+	    {
+	      /* Add the pending skiplist entry. */
+	      skip_function_pc (0, orig_arg, 0, 1);
+	    }
+
+	  return;
+	}
+
+      if (sals.nelts > 1)
+	error (_("Specify just one function at a time."));
+      if (strlen (arg) != 0)
+	error (_("Junk at end of arguments."));
+
+      /* The pc decode_line_1 gives us is the first line of the function,
+	 but we actually want the line before that.  The call to
+	 find_pc_partial_function gets us the value we actually want. */
+      {
+	struct symtab_and_line *sal = &sals.sals[0];
+	CORE_ADDR pc = sal->pc;
+	CORE_ADDR func_start = 0;
+	struct gdbarch *arch = get_sal_arch (sal);
+
+	if (!find_pc_partial_function (pc, &name, &func_start, 0))
+	  {
+	    error (_("No function found containing program point %s."),
+		     paddress (arch, pc));
+	  }
+
+	skip_function_pc (func_start, name, arch, 0);
+      }
+    }
+}
+
+static void
+skip_info (char *arg, int from_tty)
+{
+  struct skiplist_entry *e;
+  int num_printable_entries = 0;
+  int entry_num = -1;
+  int address_width = 10;
+  struct value_print_options opts;
+  struct cleanup *tbl_chain;
+
+  get_user_print_options (&opts);
+
+  if (arg != 0)
+    {
+      entry_num = parse_and_eval_long (arg);
+    }
+
+  /* Count the number of rows in the table and see if we need space for a
+     64-bit address anywhere. */
+  ALL_SKIPLIST_ENTRIES (e)
+    if (entry_num == -1 || e->number == entry_num)
+      {
+	num_printable_entries++;
+	if (e->gdbarch && gdbarch_addr_bit (e->gdbarch) > 32)
+	  address_width = 18;
+      }
+
+  if (num_printable_entries == 0)
+    {
+      if (entry_num == -1)
+	ui_out_message (uiout, 0, _("Not ignoring any files or functions.\n"));
+      else
+	ui_out_message (uiout, 0,
+			_("No skiplist entry numbered %d.\n"), entry_num);
+
+      return;
+    }
+
+  if (opts.addressprint)
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (uiout, 5, num_printable_entries,
+					      "SkiplistTable");
+  else
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (uiout, 4, num_printable_entries,
+					      "SkiplistTable");
+
+  ui_out_table_header (uiout, 7, ui_left, "number", "Num");              /* 1 */
+  ui_out_table_header (uiout, 14, ui_left, "type", "Type");              /* 2 */
+  ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");             /* 3 */
+  if (opts.addressprint)
+    {
+      ui_out_table_header (uiout, address_width, ui_left,
+			   "addr", "Address");                           /* 4 */
+    }
+  ui_out_table_header (uiout, 40, ui_noalign, "what", "What");           /* 5 */
+  ui_out_table_body (uiout);
+
+  ALL_SKIPLIST_ENTRIES (e)
+    {
+      struct cleanup *entry_chain;
+
+      QUIT;
+      if (entry_num != -1 && entry_num != e->number)
+	continue;
+
+      entry_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "blklst-entry");
+      ui_out_field_int (uiout, "number", e->number);                     /* 1 */
+
+      if (e->function_name != 0)
+	ui_out_field_string (uiout, "type", "function");                 /* 2 */
+      else if (e->filename != 0)
+	ui_out_field_string (uiout, "type", "file");                     /* 2 */
+      else
+	internal_error (__FILE__, __LINE__, _("\
+Skiplist entry should have either a filename or a function name."));
+
+      if (e->enabled)
+	ui_out_field_string (uiout, "enabled", "y");                     /* 3 */
+      else
+	ui_out_field_string (uiout, "enabled", "n");                     /* 3 */
+
+      if (opts.addressprint)
+	{
+	  if (e->pc != 0)
+	    ui_out_field_core_addr (uiout, "addr", e->gdbarch, e->pc);   /* 4 */
+	  else
+	    ui_out_field_string (uiout, "addr", "");                     /* 4 */
+	}
+
+      if (!e->pending && e->function_name != 0)
+	{
+	   struct symbol *sym;
+	   gdb_assert (e->pc != 0);
+	   sym = find_pc_function (e->pc);
+	   if (sym)
+	     ui_out_field_fmt (uiout, "what", "%s at %s:%d",
+			       sym->ginfo.name,
+			       sym->symtab->filename,
+			       sym->line);
+	   else
+	     ui_out_field_string (uiout, "what", "?");
+	}
+      else if (e->pending && e->function_name != 0)
+	{
+	  ui_out_field_fmt (uiout, "what", "%s (PENDING)",
+			    e->function_name);
+	}
+      else if (!e->pending && e->filename != 0)
+	ui_out_field_string (uiout, "what", e->filename);
+      else if (e->pending && e->filename != 0)
+	ui_out_field_fmt (uiout, "what", "%s (PENDING)",
+			  e->filename);
+
+      ui_out_text (uiout, "\n");
+      do_cleanups (entry_chain);
+    }
+
+  do_cleanups (tbl_chain);
+}
+
+static void
+skip_enable_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e;
+  int entry_num = parse_and_eval_long (arg);
+  ALL_SKIPLIST_ENTRIES (e)
+    if (e->number == entry_num)
+      {
+	e->enabled = 1;
+	return;
+      }
+
+  error (_("No skiplist entry numbered %d."), entry_num);
+}
+
+static void
+skip_disable_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e;
+  int entry_num = parse_and_eval_long (arg);
+  ALL_SKIPLIST_ENTRIES (e)
+    if (e->number == entry_num)
+      {
+	e->enabled = 0;
+	return;
+      }
+
+  error (_("No skiplist entry numbered %d."), entry_num);
+}
+
+static void
+skip_delete_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e, *b_prev;
+  int entry_num = parse_and_eval_long (arg);
+
+  /* We don't need to use a SAFE macro here since we return as soon as we
+     remove an element from the list. */
+  b_prev = 0;
+  ALL_SKIPLIST_ENTRIES (e)
+    if (e->number == entry_num)
+      {
+	if (b_prev != 0)
+	  b_prev->next = e->next;
+	else
+	  skiplist_entry_chain = e->next;
+
+	xfree (e->function_name);
+	xfree (e->filename);
+	xfree (e);
+	return;
+      }
+    else
+      {
+	b_prev = e;
+      }
+
+  error (_("No skiplist entry numbered %d."), entry_num);
+}
+
+/* Create a skiplist entry for the given pc corresponding to the given
+   function name and add it to the list. */
+static void
+skip_function_pc (CORE_ADDR pc, char *name, struct gdbarch *arch,
+		  int pending)
+{
+  struct skiplist_entry *e = XZALLOC (struct skiplist_entry);
+  e->pc = pc;
+  e->gdbarch = arch;
+  e->enabled = 1;
+  e->pending = pending;
+  e->function_name = xstrdup (name);
+
+  add_skiplist_entry (e);
+
+  if (!pending)
+    printf_filtered (_("Function %s at %s will be skipped when stepping.\n"),
+		     name, paddress (get_current_arch (), pc));
+  else
+    printf_filtered (_("Function %s will be skipped when stepping, "
+		       "pending shared library load.\n"),
+		     name);
+}
+
+/* Add the given skiplist entry to our list, and set the entry's number. */
+static void
+add_skiplist_entry (struct skiplist_entry *e)
+{
+  struct skiplist_entry *e1;
+
+  e->number = ++skiplist_entry_count;
+
+  /* Add to the end of the chain so that the list of
+     skiplist entries will be in numerical order. */
+
+  e1 = skiplist_entry_chain;
+  if (e1 == 0)
+    skiplist_entry_chain = e;
+  else
+    {
+      while (e1->next)
+	e1 = e1->next;
+      e1->next = e;
+    }
+}
+
+/* Does the given pc correspond to the beginning of a skipped function? */
+int
+function_pc_is_marked_for_skip (CORE_ADDR pc)
+{
+  struct symtab_and_line sal;
+  char *filename;
+  struct skiplist_entry *e;
+
+  sal = find_pc_line (pc, 0);
+  filename = sal.symtab->filename;
+
+  ALL_SKIPLIST_ENTRIES (e)
+    {
+      int pc_match = e->pc != 0 && pc == e->pc;
+      int filename_match = e->filename != 0 && filename != 0 &&
+			   strcmp (filename, e->filename) == 0;
+      if (e->enabled && !e->pending && (pc_match || filename_match))
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Re-set the skip list after symbols have been re-loaded. */
+void
+skip_re_set ()
+{
+  struct skiplist_entry *e;
+  ALL_SKIPLIST_ENTRIES (e)
+    {
+      if (e->filename != 0)
+	{
+	  /* If it's an entry telling us to skip a file, but the entry is
+	     currently pending a solib load, let's see if we now know
+	     about the file. */
+	  struct symtab *symtab = lookup_symtab (e->filename);
+	  if (symtab != 0)
+	    {
+	      xfree (e->filename);
+	      e->filename = xstrdup (symtab->filename);
+	      e->gdbarch = get_objfile_arch (symtab->objfile);
+	      e->pending = 0;
+	    }
+	  else
+	    {
+	      e->pending = 1;
+	    }
+	}
+      else if (e->function_name != 0)
+        {
+	  char *func_name = e->function_name;
+	  struct symtabs_and_lines sals;
+	  volatile struct gdb_exception decode_exception;
+
+	  TRY_CATCH(decode_exception, NOT_FOUND_ERROR)
+	    {
+	      sals = decode_line_1 (&func_name, 1, 0, 0, 0);
+	    }
+
+	  if (decode_exception.reason >= 0 && 
+	      sals.nelts == 1 && strlen (func_name) == 0)
+	    {
+	      struct symtab_and_line *sal = &sals.sals[0];
+	      CORE_ADDR pc = sal->pc;
+	      CORE_ADDR func_start = 0;
+	      struct gdbarch *arch = get_sal_arch (sal);
+
+	      if (find_pc_partial_function (pc, &e->function_name,
+		                            &func_start, 0))
+		{
+		  e->pending = 0;
+		  e->pc = func_start;
+		  e->gdbarch = arch;
+		}
+	    }
+	  else
+	    {
+	      e->pending = 1;
+	    }
+        }
+    }
+}
+
+/* Helper function to get a gdbarch from a symtab_and_line. */
+static struct gdbarch*
+get_sal_arch (struct symtab_and_line *sal)
+{
+  if (sal->section)
+    return get_objfile_arch (sal->section->objfile);
+  if (sal->symtab)
+    return get_objfile_arch (sal->symtab->objfile);
+  return get_current_arch ();
+}
+
+void
+_initialize_step_skip (void)
+{
+  struct cmd_list_element *c;
+
+  skiplist_entry_chain = 0;
+  skiplist_entry_count = 0;
+
+  add_prefix_cmd ("skip", class_breakpoint, skip_function_command, _("\
+Ignore a function while stepping.\n\
+skip [FUNCTION NAME]\n\
+If no function name is given, ignore the current function."),
+                  &skiplist, "skip ", 1, &cmdlist);
+
+  c = add_cmd ("file", class_breakpoint, skip_file_command, _("\
+Ignore a file while stepping.\n\
+skip file [FILENAME]\n\
+If no filename is given, ignore the current file."),
+	       &skiplist);
+  set_cmd_completer (c, filename_completer);
+
+  c = add_cmd ("function", class_breakpoint, skip_function_command, _("\
+Ignore a function while stepping.\n\
+skip function [FUNCTION NAME]\n\
+If no function name is given, skip the current function."),
+	       &skiplist);
+  set_cmd_completer (c, location_completer);
+
+  add_cmd ("enable", class_breakpoint, skip_enable_command, _("\
+Enable a skip entry.\n\
+skip enable [NUMBER]"),
+	   &skiplist);
+
+  add_cmd ("disable", class_breakpoint, skip_disable_command, _("\
+Disable a skip entry.\n\
+skip disable [NUMBER]"),
+	   &skiplist);
+
+  add_cmd ("delete", class_breakpoint, skip_delete_command, _("\
+Delete a skip entry.\n\
+skip delete [NUMBER]"),
+           &skiplist);
+
+  add_info ("skip", skip_info, _("\
+Status of all skips, or of skip NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tfile        - ignored file\n\
+\tfunction    - ignored function"));
+}
diff --git a/gdb/skip.h b/gdb/skip.h
new file mode 100644
index 0000000..63d4cae
--- /dev/null
+++ b/gdb/skip.h
@@ -0,0 +1,27 @@
+/* Header for GDB line completion.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#if !defined (SKIP_H)
+#define SKIP_H
+
+/* Returns 1 if the given pc is marked for skip and shouldn't be
+   stepped into.  Otherwise, returns 0. */
+int function_pc_is_marked_for_skip (CORE_ADDR pc);
+
+/* Re-set the skip list after symbols have been reloaded. */
+void skip_re_set ();
+
+#endif /* !defined (SKIP_H) */
diff --git a/gdb/stack.c b/gdb/stack.c
index 0888b69..270f0fb 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -73,6 +73,12 @@ static void print_frame (struct frame_info *frame, int print_level,
 			 enum print_what print_what,  int print_args,
 			 struct symtab_and_line sal);
 
+static void set_last_displayed_codepoint (int valid,
+					  struct program_space *pspace,
+					  CORE_ADDR addr,
+					  struct symtab *symtab,
+					  int line);
+
 /* Zero means do things normally; we are interacting directly with the
    user.  One means print the full filename and linenumber when a
    frame is printed, and do so in a format emacs18/emacs19.22 can
@@ -80,6 +86,14 @@ static void print_frame (struct frame_info *frame, int print_level,
    cases and in a slightly different syntax.  */
 
 int annotation_level = 0;
+
+/* These variables hold the last codepoint we displayed to the user.  This is
+   where we insert a breakpoint or a skiplist entry by default. */
+static int last_codepoint_valid = 0;
+static struct program_space *last_codepoint_pspace = 0;
+static CORE_ADDR last_codepoint_addr = 0;
+static struct symtab *last_codepoint_symtab = 0;
+static int last_codepoint_line = 0;
 \f
 
 struct print_stack_frame_args
@@ -658,9 +672,9 @@ print_frame_info (struct frame_info *frame, int print_level,
       CORE_ADDR pc;
 
       if (get_frame_pc_if_available (frame, &pc))
-	set_default_breakpoint (1, sal.pspace, pc, sal.symtab, sal.line);
+	set_last_displayed_codepoint (1, sal.pspace, pc, sal.symtab, sal.line);
       else
-	set_default_breakpoint (0, 0, 0, 0, 0);
+	set_last_displayed_codepoint (0, 0, 0, 0, 0);
     }
 
   annotate_frame_end ();
@@ -668,6 +682,88 @@ print_frame_info (struct frame_info *frame, int print_level,
   gdb_flush (gdb_stdout);
 }
 
+/* Remember the last codepoint we displayed, which we use e.g. as the place to
+   put a breakpoint when the `break' command is invoked with no arguments. */
+static void
+set_last_displayed_codepoint (int valid, struct program_space *pspace,
+			      CORE_ADDR addr, struct symtab *symtab,
+			      int line)
+{
+  last_codepoint_valid = valid;
+  last_codepoint_pspace = pspace;
+  last_codepoint_addr = addr;
+  last_codepoint_symtab = symtab;
+  last_codepoint_line = line;
+}
+
+void
+clear_last_displayed_codepoint ()
+{
+  last_codepoint_valid = 0;
+  last_codepoint_pspace = 0;
+  last_codepoint_addr = 0;
+  last_codepoint_symtab = 0;
+  last_codepoint_line = 0;
+}
+
+int
+last_displayed_codepoint_is_valid ()
+{
+  return last_codepoint_valid;
+}
+
+struct program_space*
+get_last_displayed_pspace ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_pspace;
+  return 0;
+}
+
+CORE_ADDR
+get_last_displayed_addr ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_addr;
+  return 0;
+}
+
+struct symtab*
+get_last_displayed_symtab ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_symtab;
+  return 0;
+}
+
+int
+get_last_displayed_line ()
+{
+  if (last_codepoint_valid)
+    return last_codepoint_line;
+  return 0;
+}
+
+void
+set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal)
+{
+  if (last_codepoint_valid)
+    {
+      sal->pspace = last_codepoint_pspace;
+      sal->pc = last_codepoint_addr;
+      sal->symtab = last_codepoint_symtab;
+      sal->line = last_codepoint_line;
+    }
+  else
+    {
+      sal->pspace = 0;
+      sal->pc = 0;
+      sal->symtab = 0;
+      sal->line = 0;
+    }
+}
+
+
 /* Attempt to obtain the FUNNAME, FUNLANG and optionally FUNCP of the function
    corresponding to FRAME.  */
 
diff --git a/gdb/stack.h b/gdb/stack.h
index 3cce623..d6783b6 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -38,4 +38,14 @@ void iterate_over_block_local_vars (struct block *block,
 				    iterate_over_block_arg_local_vars_cb cb,
 				    void *cb_data);
 
+/* Get or set the last displayed codepoint, which is, e.g. where we set a
+   breakpoint when `break' is supplied with no arguments. */
+void clear_last_displayed_codepoint ();
+int last_displayed_codepoint_is_valid ();
+struct program_space* get_last_displayed_pspace ();
+CORE_ADDR get_last_displayed_addr ();
+struct symtab* get_last_displayed_symtab ();
+int get_last_displayed_line ();
+void set_sal_to_last_displayed_codepoint (struct symtab_and_line *sal);
+
 #endif /* #ifndef STACK_H */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index cec6870..65b0723 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -56,6 +56,7 @@
 #include "elf-bfd.h"
 #include "solib.h"
 #include "remote.h"
+#include "stack.h"
 
 #include <sys/types.h>
 #include <fcntl.h>
@@ -2785,7 +2786,7 @@ clear_symtab_users (int add_flags)
   clear_displays ();
   if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0)
     breakpoint_re_set ();
-  set_default_breakpoint (0, NULL, 0, 0, 0);
+  clear_last_displayed_codepoint ();
   clear_pc_function_cache ();
   observer_notify_new_objfile (NULL);
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c964f5c..a11d978 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2011-04-23  Justin Lebar <justin.lebar@gmail.com>
+
+	testsuite/gdb.base/skip-solib-lib.c: New
+	testsuite/gdb.base/skip-solib-main.c: New
+	testsuite/gdb.base/skip-solib.exp: New
+	testsuite/gdb.base/skip.c: New
+	testsuite/gdb.base/skip.exp: New
+	testsuite/gdb.base/skip1.c: New
+	testsuite/gdb.base/Makefile.in: Adding new files.
+
 2011-04-20  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	* gdb.cp/cpcompletion.exp (complete class methods)
diff --git a/gdb/testsuite/gdb.base/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in
index 72f1ba4..7ceb121 100644
--- a/gdb/testsuite/gdb.base/Makefile.in
+++ b/gdb/testsuite/gdb.base/Makefile.in
@@ -30,8 +30,8 @@ EXECUTABLES = a2-run advance all-types annota1 annota1-watch_thread_num \
 	sepsymtab.debug sepsymtab.stripped setshow setvar shmain shreloc \
 	sigall sigaltstack sigbpt sigchld siginfo siginfo-addr \
 	siginfo-infcall siginfo-obj signals signull sigrepeat sigstep \
-	sizeof solib solib-corrupted solib-display-main solib-nodir \
-	solib-overlap-main-0x40000000 solib-symbol-main solib-weak \
+	sizeof skip skip-solib solib solib-corrupted solib-display-main
+	solib-nodir solib-overlap-main-0x40000000 solib-symbol-main solib-weak \
 	solib-weak-lib2 solib_sl so-impl-ld so-indr-cl \
 	stack-checking start step-break step-bt step-line step-resume-infcall \
 	step-test store structs-t* structs2 structs3 \
diff --git a/gdb/testsuite/gdb.base/skip-solib-lib.c b/gdb/testsuite/gdb.base/skip-solib-lib.c
new file mode 100644
index 0000000..792cd01
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip-solib-lib.c
@@ -0,0 +1,11 @@
+/* Simple shared library */
+
+int square(int num)
+{
+  return multiply(num, num);
+}
+
+int multiply(int a, int b)
+{
+  return a * b;
+}
diff --git a/gdb/testsuite/gdb.base/skip-solib-main.c b/gdb/testsuite/gdb.base/skip-solib-main.c
new file mode 100644
index 0000000..746bb5f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip-solib-main.c
@@ -0,0 +1,6 @@
+int square(int num);
+
+int main()
+{
+  return square(0);
+}
diff --git a/gdb/testsuite/gdb.base/skip-solib.exp b/gdb/testsuite/gdb.base/skip-solib.exp
new file mode 100644
index 0000000..9530aa0
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip-solib.exp
@@ -0,0 +1,129 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Justin Lebar. (justin.lebar@gmail.com)
+
+#
+# Tests skipping shared libraries.
+#
+
+# This only works on GNU/Linux.
+if { ![isnative] || [is_remote host] || ![istarget *-linux*] || [skip_shlib_tests]} {
+    continue
+}
+
+set test "skip-solib"
+set srcfile_main "${test}-main.c"
+set binfile_main "${objdir}/${subdir}/${test}-test"
+set srcfile_lib "${test}-lib.c"
+set libname "lib${test}"
+set binfile_lib ${objdir}/${subdir}/${libname}.so
+
+#
+# Compile our program under test.  The main program references a shared library
+# libskip-solib.so, which contains two functions, square(), which is
+# referenced by the main program, and multiply(), which is not referenced by
+# the main program.
+#
+
+if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} [list debug additional_flags=-fPIC -Wl,-soname,${libname}.so]] != ""} {
+    return -1
+}
+
+if {[gdb_compile "${srcdir}/${subdir}/${srcfile_main}" "${binfile_main}.o" object debug] != ""} {
+    return -1
+}
+
+if {[gdb_compile "${binfile_main}.o" "${binfile_main}" executable \
+                 [list debug "additional_flags=-L${objdir}/${subdir} -l${test} \
+                                               -Wl,-rpath=${objdir}/${subdir}"]] != ""} {
+    return -1
+}
+
+gdb_start
+gdb_load ${binfile_main}
+
+#
+# At this point, if we try to skip the file ${srcfile_lib} or the function
+# multiply(), we should get a prompt asking us if we want to enable the
+# skip entry pending a shared library load.
+#
+
+gdb_test "skip file ${srcfile_lib}" \
+"File ${srcfile_lib} will be skipped when stepping." \
+"ignoring file in solib" \
+"No source file named ${srcfile_lib}.*
+Ignore file pending future shared library load.*"\
+"y"
+
+#
+# Does info skip list this entry as pending?
+#
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+\\s+${srcfile_lib} \\(PENDING\\)\\s*" \
+"info skip with pending file"
+
+if ![runto_main] { fail "skip tests suppressed" }
+
+#
+# We shouldn't step into square(), since we skipped skip-solib-lib.c.
+#
+gdb_test "step" ""
+gdb_test "bt" "#0\\s+main.*" "step after ignoring solib file."
+
+#
+# Our entry should no longer be pending.  Note that we unfortunately need to do
+# at least one step before the entry will be unmarked as pending.
+#
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+\\s+.*${srcfile_lib}\\s*" \
+"info skip with pending file"
+
+#
+# Now restart gdb and testing ignoring of a function inside a solib.
+#
+gdb_exit
+gdb_start
+gdb_load ${binfile_main}
+
+gdb_test "skip function multiply" \
+"Function multiply will be skipped when stepping, pending shared library load." \
+"ignoring function in solib" \
+"No function found named multiply..*
+Ignore function pending future shared library load.*"\
+"y"
+
+if ![runto_main] { fail "skip tests suppressed" }
+
+#
+# Our first step should take us into square.
+#
+gdb_test "step" "square.*"
+
+#
+# Now our entry should no longer be pending.
+#
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+function\\s+y\\s+0x\[0-9a-f\]+\\s+multiply at .*${srcfile_lib}:.*\\s*" \
+
+#
+# This step shouldn't go into multiply -- we should skip it and go on to the
+# last line of square.
+#
+gdb_test "step" ""
+gdb_test "bt" "#0\\s+square.*"
diff --git a/gdb/testsuite/gdb.base/skip.c b/gdb/testsuite/gdb.base/skip.c
new file mode 100644
index 0000000..565ba93
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip.c
@@ -0,0 +1,13 @@
+int foo();
+int bar();
+int baz(int, int);
+
+int main()
+{
+  return baz(foo(), bar());
+}
+
+int foo()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/skip.exp b/gdb/testsuite/gdb.base/skip.exp
new file mode 100644
index 0000000..f52a0e2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip.exp
@@ -0,0 +1,141 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Justin Lebar. (justin.lebar@gmail.com)
+
+if { [prepare_for_testing skip.exp "skip" \
+                          {skip.c skip1.c } \
+                          {debug nowarnings}] } {
+    return -1
+}
+
+set srcfile skip.c
+set srcfile1 skip1.c
+
+#
+# Right after we start gdb, there's no default file or function to skip.
+#
+gdb_test "skip file" "No default file now."
+gdb_test "skip function" "No default function now."
+gdb_test "skip" "No default function now."
+
+if ![runto_main] { fail "skip tests suppressed" }
+
+#
+# Test |info skip| with an empty skiplist.
+#
+gdb_test "info skip" "Not ignoring any files or functions\." "info skip empty"
+
+#
+# Create a skiplist entry for the current file and function.
+#
+gdb_test "skip file" "File .*$srcfile will be skipped when stepping\."
+gdb_test "skip" "Function main at .* will be skipped when stepping\."
+
+#
+# Create a skiplist entry for a specified file and function.
+#
+gdb_test "skip file skip1.c" "File .*$srcfile1 will be skipped when stepping\."
+gdb_test "skip function baz" "Function baz at .* will be skipped when stepping\."
+
+#
+# Test bad skiplist entry modification commands
+#
+gdb_test "skip enable 999" "No skiplist entry numbered 999."
+gdb_test "skip disable 999" "No skiplist entry numbered 999."
+gdb_test "skip delete 999" "No skiplist entry numbered 999."
+gdb_test "skip enable" "Argument required \\(expression to compute\\)."
+gdb_test "skip disable" "Argument required \\(expression to compute\\)."
+gdb_test "skip delete" "Argument required \\(expression to compute\\)."
+gdb_test "skip enable a" "No symbol \"a\" in current context."
+gdb_test "skip disable a" "No symbol \"a\" in current context."
+gdb_test "skip delete a" "No symbol \"a\" in current context."
+
+#
+# Test that skip function doesn't allow extra characters at the end of
+# its arguments list.
+#
+gdb_test "skip function foo bar" "Junk at end of arguments."
+
+#
+# Ask for info on a skiplist entry which doesn't exist.
+#
+gdb_test "info skip 999" "No skiplist entry numbered 999."
+
+#
+# Does |info skip| look right?
+#
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+1\\s+file\\s+y\\s+.*$srcfile\\s*
+2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+y\\s+.*$srcfile1\\s*
+4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
+
+#
+# Right now, we have an outstanding skiplist entry on both source
+# files, so when we step into the first line in main(), we should step
+# right over it and go to the second line of main().
+#
+if ![runto_main] { fail "skip tests suppressed" }
+send_gdb "step\n"
+gdb_test "bt" "#0\\s+main.*" "step after all ignored"
+
+#
+# Now remove skip.c from the skiplist.  Our first step should take us
+# into foo(), and our second step should take us to the next line in
+# main().
+#
+send_gdb "skip delete 1\n"
+# Check that entry 1 is missing from |info skip|
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+2\\s+function\\s+y\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+y\\s+.*$srcfile1\\s*
+4\\s+function\\s+y\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*"
+
+if ![runto_main] { fail "skip tests suppressed" }
+gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
+
+#
+# Now disable the skiplist entry for  skip1.c.  We should now
+# step into foo(), then into bar(), but not into baz().
+#
+send_gdb "skip disable 3\n"
+# Is entry 3 disabled in |info skip|?
+gdb_test "info skip 3" ".*\\n3\\s+file\\s+n.*" \
+         "info skip shows entry as disabled"
+
+if ![runto_main] { fail "skip tests suppressed" }
+gdb_test "step" "bar \\(\\) at.*" "step after disabling 3 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "foo \\(\\) at.*" "step after disabling 3 (2)"
+send_gdb "step\n"; # Return from bar()
+gdb_test "step" "main \\(\\) at.*" "step after disabling 3 (3)"
+
+#
+# Enable skiplist entry 3 and make sure we step over it like before.
+#
+send_gdb "skip enable 3\n"
+# Is entry 3 enabled in |info skip|?
+gdb_test "info skip 3" ".*\\n3\\s+file\\s+y.*" \
+         "info skip shows entry as enabled"
+if ![runto_main] { fail "skip tests suppressed" }
+gdb_test "step" "foo \\(\\) at.*" "step after deleting 1 (1)"
+send_gdb "step\n"; # Return from foo()
+gdb_test "step" "main \\(\\) at.*" "step after deleting 1 (2)"
+
diff --git a/gdb/testsuite/gdb.base/skip1.c b/gdb/testsuite/gdb.base/skip1.c
new file mode 100644
index 0000000..2dab5c3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip1.c
@@ -0,0 +1,9 @@
+int bar()
+{
+  return 1;
+}
+
+int baz(int a, int b)
+{
+  return a + b;
+}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch] Bug 8287: Skip uninteresting functions while debugging
  2011-04-25 19:35         ` Justin Lebar
@ 2011-05-16 21:04           ` Justin Lebar
  0 siblings, 0 replies; 10+ messages in thread
From: Justin Lebar @ 2011-05-16 21:04 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Anything I can do to push this forward?  I'd be a bit sad if the patch
sat and rotted again...

-Justin

On Mon, Apr 25, 2011 at 3:34 PM, Justin Lebar <justin.lebar@gmail.com> wrote:
> After many months of inactivity, I finally have time to work on this
> again.  I'm really sorry for the delay.
>
> I've attached a patch for tip of trunk.  I renamed the command from
> "blacklist" to "skip".
>
> The one major issue outstanding on the previous patch was that every
> time you stepped, I tried to resolve all skips pending a shared
> library load.  I did this because registering a solib load listener
> didn't work -- somehow even after I was notified of the load, the
> solib's symbols weren't available.
>
> I hacked around this problem by putting a call to skip_re_set at the
> end of breakpoint_re_set.
>
> -Justin
>
> On Fri, Jul 23, 2010 at 3:50 PM, Justin Lebar <justin.lebar@gmail.com> wrote:
>> Justin> I'm not sure I like "enable blacklist".  The problem is that
>> Justin> "blacklist" is a noun referring to the list of all functions we
>> Justin> skip and also a verb meaning "add an entry to the blacklist".
>> Justin> "Enable blacklist" sounds to me like we're enabling an entire
>> Justin> list of blacklist entries.
>>
>> Tom> Yeah, that makes sense.
>> Tom> Yes, that would be good.  Any ideas for names?
>>
>> Maybe we could use "skip":
>>
>> skip function foo
>> skip file bar
>> info skip
>> delete skip 1
>> disable skip 42
>>
>> "Ignore" might also work, but I don't like "delete ignore 1", or
>> "enable ignore 2".
>>
>> -Justin
>>
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-05-16 21:04 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-18 18:56 [Patch] Bug 8287: Skip uninteresting functions while debugging Justin Lebar
2010-06-18 19:37 ` Michael Snyder
2010-06-18 20:58   ` Eli Zaretskii
2010-06-20  7:03 ` Hui Zhu
2010-06-25 21:57 ` Tom Tromey
2010-06-28 17:44   ` Justin Lebar
2010-07-20 21:03     ` Tom Tromey
2010-07-23 19:50       ` Justin Lebar
2011-04-25 19:35         ` Justin Lebar
2011-05-16 21:04           ` Justin Lebar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).