This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Status of 'blacklist' patch?


Rollup patch is attached, incorporating all feedback so far (I
think!).  As usual, you should be able to use interdiff to view the
changes.  Let me know if that doesn't work and I can make git spit it
out.

Unfortunately the tests are randomly failing on me.  I'm not sure
what's going on, but it looks like we're not always waiting long
enough after runto_main, somehow.

The relevant expect code (in gdb.base/skip.exp) is:

if ![runto_main] { fail "skip tests suppressed" }
send_gdb "step\n"
# XXX This gdb_test sometimes fails, due to an apparent race.
gdb_test "bt" "\\s*\\#0\\s+main.*" "step after all ignored"

Here's a diff of gdb.log in a successful run (-) and an unsuccessful run (+).

@@ -112,20 +112,20 @@
 Start it from the beginning? (y or n) y
 Starting program: /home/jlebar/code/gdb/debug/gdb/testsuite/gdb.base/skip

 Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.base/skip.c:7
 7	  return baz(foo(), bar());
 (gdb) step
 bt
 8	}
-(gdb) bt
+(gdb) FAIL: gdb.base/skip.exp: step after all ignored
+bt
 #0  main () at ../../../src/gdb/testsuite/gdb.base/skip.c:8
-(gdb) PASS: gdb.base/skip.exp: step after all ignored
-skip delete 1
+(gdb) skip delete 1
 (gdb) info skip
 Num     Type           Enb Address            What
 2       function       y   0x00000000004004e4 main at
../../../src/gdb/testsuite/gdb.base/skip.c:5
 3       file           y
../../../src/gdb/testsuite/gdb.base/skip1.c
 4       function       y   0x000000000040052b baz at
../../../src/gdb/testsuite/gdb.base/skip1.c:6
 (gdb) PASS: gdb.base/skip.exp: info skip
 delete breakpoints
 Delete all breakpoints? (y or n) y
@@ -226,17 +226,16 @@

Any ideas what's going on here?

-Justin

On Tue, Oct 25, 2011 at 8:26 PM, Stan Shebs <stan_shebs@mentor.com> wrote:
> On 10/25/2011 01:16 PM, Justin Lebar wrote:
>>
>> In the unlikely case that I actually opened the manual (not because
>> it's no good, but because most people I know who use GDB aren't aware
>> of the manual -- it's not well-linked on the web), I think the fact
>> that there are |skip file| and |skip function| commands would clear
>> things up pretty quickly.
>>
>> There's a cost to a comment like this; it's not useful to most
>> readers, but they have to parse it anyway. Â(What the heck does "skip
>> function file" mean?)
>
> Another purpose for having niggling details in the manual is that in the
> absence of a formal specification, the manual is our promise to users of
> what they should expect to work, and how it will work. ÂSo users find
> themselves referring to the manual when they try something that seems
> obvious, and are surprised that it doesn't work as expected.
>
>> But again, I don't really have a stake in this either way. ÂI just
>> want to get my patch in. Â:)
>
> I'd like to see a new rollup with all the feedback incorporated, I've lost
> track of the state... :-)
>
> Stan
>
>
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a166d14..0f10225 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,41 @@
+2011-10-06  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): Remove.
+	(get_sal_arch): Declare.
+	* breakpoint.c: Remove default_breakpoint_valid,
+	default_breakpoint_address, default_breakpoint_symtab,
+	default_breakpoint_line, default_breakpoint_pspace variables.
+	(get_sal_arch): Make public.
+	(set_default_breakpoint): Remove.
+	(parse_breakpoint_sals, create_breakpoint, clear_command,
+	decode_line_spec_1): Remove uses of default_breakpoint variables;
+	replaced with function calls into stack.c.
+	* cli/cli-cmds.h: Add cmd_list_element *skiplist.
+	* cli/cli-cmds.c: Add skiplist.
+	(init_cmd_lists): Initialize skiplist.
+	(init_cli_cmds): Fix comment (classes of commands appear in
+	alphabetical order).
+	* infrun.c (handle_inferior_event): Add check that we don't step into
+	a function whose pc is marked for skip.
+	* stack.c: Declare last_displayed_sal_valid, last_displayed_pspace,
+	last_displayed_addr, last_displayed_symtab, last_displayed_line
+	variables.
+	(set_last_displayed_sal): New static function.
+	(print_frame_info): Switch call to set_default_breakpoint to call to
+	set_last_displayed_sal.
+	(clear_last_displayed_sal, last_displayed_sal_is_valid,
+	get_last_displayed_pspace, get_last_displayed_addr,
+	get_last_displayed_symtab, get_last_displayed_line,
+	get_last_displayed_sal): New public functions.
+	* stack.h (clear_last_displayed_sal, last_displayed_sal_is_valid,
+	get_last_displayed_pspace, get_last_displayed_addr,
+	get_last_displayed_symtab, get_last_displayed_line,
+	get_last_displayed_sal): Declare.
+
 2011-10-05  Tristan Gingold  <gingold@adacore.com>
 
 	* ada-tasks.c (read_atcb): Make ravenscar_task_name static.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 826d339..d6b004b 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 \
@@ -819,7 +819,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 \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
 common/linux-osdata.h
 
@@ -907,7 +907,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	xml-support.o xml-syscall.o xml-utils.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 \
 	common-utils.o buffer.o ptid.o
 
 TSOBS = inflow.o
diff --git a/gdb/NEWS b/gdb/NEWS
index 4d434c5..8225cf8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.3.1
 
+* GDB now allows you to skip uninteresting functions and files when
+  stepping with the "skip function" and "skip file" commands.
+
 * GDB has two new commands: "set remote hardware-watchpoint-length-limit"
   and "show remote hardware-watchpoint-length-limit".  These allows to
   set or show the maximum length limit (in bytes) of a remote
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 08ff69b..b41fb79 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -65,6 +65,8 @@
 #include "parser-defs.h"
 #include "cli/cli-utils.h"
 #include "continuations.h"
+#include "stack.h"
+#include "skip.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -572,19 +574,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;
-
 
 /* Return the breakpoint with the specified number, or NULL
    if the number does not refer to an existing breakpoint.  */
@@ -5339,20 +5328,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
@@ -5764,7 +5739,7 @@ set_breakpoint_location_function (struct bp_location *loc, int explicit_loc)
 }
 
 /* Attempt to determine architecture of location identified by SAL.  */
-static struct gdbarch *
+struct gdbarch *
 get_sal_arch (struct symtab_and_line sal)
 {
   if (sal.section)
@@ -7543,24 +7518,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_sal_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. */
+	  get_last_displayed_sal (&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;
@@ -7574,19 +7551,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_sal_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);
@@ -9611,9 +9591,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_sal_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);
 
@@ -10135,10 +10117,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. */
+      get_last_displayed_sal (&sal);
       if (sal.symtab == 0)
 	error (_("No source file specified."));
 
@@ -11986,6 +11969,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 ();
 }
 
 /* Reset the thread number of this breakpoint:
@@ -12435,7 +12421,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)
@@ -12444,10 +12431,10 @@ decode_line_spec_1 (char *string, int funfirstline)
 
   if (string == 0)
     error (_("Empty line specification."));
-  if (default_breakpoint_valid)
+  if (last_displayed_sal_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 5e5d1b9..f171035 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1033,9 +1033,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 *);
@@ -1359,4 +1356,8 @@ extern struct breakpoint *iterate_over_breakpoints (int (*) (struct breakpoint *
 
 extern int user_breakpoint_p (struct breakpoint *);
 
+/* Attempt to determine architecture of location identified by SAL.  */
+extern struct gdbarch *
+get_sal_arch (struct symtab_and_line sal);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index ccf6ea6..dab3a12 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;
@@ -1329,6 +1331,7 @@ init_cmd_lists (void)
   showprintlist = NULL;
   setchecklist = NULL;
   showchecklist = NULL;
+  skiplist = NULL;
 }
 
 static void
@@ -1394,7 +1397,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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dd0f7f6..382dfd4 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4854,6 +4854,111 @@ proceed until the function returns.
 An argument is a repeat count, as in @code{next}.
 @end table
 
+@node Skipping Over Functions and Files
+@subsection Skipping Over Functions and Files
+@cindex skipping over functions and files
+
+The program you are debugging may contain some functions which are
+uninteresting to debug.  The @code{skip} comand lets you tell @value{GDBN} to
+skip a function or all functions in a file when stepping.
+
+For example, consider the following C function:
+
+@smallexample
+101     int func()
+102     @{
+103         foo(boring());
+104         bar(boring());
+105     @}
+@end smallexample
+
+@noindent
+Suppose you wish to step into the functions @code{foo} and @code{bar}, but you
+are not interested in stepping through @code{boring}.  If you run @code{step}
+at line 103, you'll enter @code{boring()}, but if you run @code{next}, you'll
+step over both @code{foo} and @code{boring}!
+
+One solution is to @code{step} into @code{boring} and use the @code{finish}
+command to immediately exit it.  But this can become tedious if @code{boring}
+is called from many places.
+
+A more flexible solution is to execute @kbd{skip boring}.  This instructs
+@value{GDBN} never to step into @code{boring}.  Now when you execute
+@code{step} at line 103, you'll step over @code{boring} and directly into
+@code{foo}.
+
+You can also instruct @value{GDBN} to skip all functions in a file, with, for
+example, @code{skip file boring.c}.
+
+@table @code
+@kindex skip function
+@item skip @r{[}@var{linespec}@r{]}
+@itemx skip function @r{[}@var{linespec}@r{]}
+After running this command, the function named by @var{linespec} or the
+function containing the line named by @var{linespec} will be skipped over when
+stepping.  @xref{Specify Location}
+
+If you do not specify @var{linespec}, the function you're currently debugging
+will be skipped.
+
+(If you have a function called @code{file} that you want to skip, use
+@kbd{skip function file}.)
+
+@kindex skip file
+@item skip file @r{[}@var{filename}@r{]}
+After running this command, any function whose source lives in @var{filename}
+will be skipped over when stepping.
+
+If you do not specify @var{filename}, functions whose source lives in the file
+you're currently debugging will be skipped.
+@end table
+
+Skips can be listed, deleted, disabled, and enabled, much like breakpoints.
+These are the commands for managing your list of skips:
+
+@table @code
+@kindex info skip
+@item info skip @r{[}@var{range}@r{]}
+Print details about the specified skip(s).  If @var{range} is not specified,
+print a table with details about all functions and files marked for skipping.
+@code{info skip} prints the following information about each skip:
+
+@table @emph
+@item Identifier
+A number identifying this skip.
+@item Type
+The type of this skip, either @samp{function} or @samp{file}.
+@item Enabled or Disabled
+Enabled skips are marked with @samp{y}.  Disabled skips are marked with @samp{n}.
+@item Address
+For function skips, this column indicates the address in memory of the function
+being skipped.  If you've set a function skip on a function which has not yet
+been loaded, this field will contain @samp{<PENDING>}.  Once a shared library
+which has the function is loaded, @code{info skip} will show the function's
+address here.
+@item What
+For file skips, this field contains the filename being skipped.  For functions
+skips, this field contains the function name and its line number in the file
+where it is defined.
+@end table
+
+@kindex skip delete
+@item skip delete @r{[}@var{range}@r{]}
+Delete the specified skip(s).  If @var{range} is not specified, delete all
+skips.
+
+@kindex skip enable
+@item skip enable @r{[}@var{range}@r{]}
+Enable the specified skip(s).  If @var{range} is not specified, enable all
+skips.
+
+@kindex skip disable
+@item skip disable @r{[}@var{range}@r{]}
+Disable the specified skip(s).  If @var{range} is not specified, disable all
+skips.
+
+@end table
+
 @node Signals
 @section Signals
 @cindex signals
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 225034c..e8be121 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -56,6 +56,7 @@
 #include "tracepoint.h"
 #include "continuations.h"
 #include "interps.h"
+#include "skip.h"
 
 /* Prototypes for local functions */
 
@@ -4829,7 +4830,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
@@ -4838,7 +4840,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..d2f064f
--- /dev/null
+++ b/gdb/skip.c
@@ -0,0 +1,598 @@
+/* Skipping uninteresting files and functions while stepping.
+
+   Copyright (C) 2011 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 "cli/cli-utils.h"
+#include "arch-utils.h"
+#include "linespec.h"
+#include "objfiles.h"
+#include "exceptions.h"
+#include "breakpoint.h" /* for get_sal_arch() */
+
+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 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)
+
+#define ALL_SKIPLIST_ENTRIES_SAFE(E,TMP) \
+  for (E = skiplist_entry_chain;         \
+       E ? (TMP = E->next, 1) : 0;       \
+       E = TMP)
+
+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_sal_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 address_width = 10;
+  struct value_print_options opts;
+  struct cleanup *tbl_chain;
+
+  get_user_print_options (&opts);
+
+  /* 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 (arg == 0 || number_is_in_list(arg, e->number))
+      {
+	num_printable_entries++;
+	if (e->gdbarch && gdbarch_addr_bit (e->gdbarch) > 32)
+	  address_width = 18;
+      }
+
+  if (num_printable_entries == 0)
+    {
+      if (arg == 0)
+	ui_out_message (current_uiout, 0, _("\
+Not skipping any files or functions.\n"));
+      else
+	ui_out_message (current_uiout, 0,
+			_("No skiplist entries found with number %s.\n"), arg);
+
+      return;
+    }
+
+  if (opts.addressprint)
+    tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 5,
+						     num_printable_entries,
+						     "SkiplistTable");
+  else
+    tbl_chain
+       = make_cleanup_ui_out_table_begin_end (current_uiout, 4,
+					      num_printable_entries,
+					      "SkiplistTable");
+
+  ui_out_table_header (current_uiout, 7, ui_left, "number", "Num");      /* 1 */
+  ui_out_table_header (current_uiout, 14, ui_left, "type", "Type");      /* 2 */
+  ui_out_table_header (current_uiout, 3, ui_left, "enabled", "Enb");     /* 3 */
+  if (opts.addressprint)
+    {
+      ui_out_table_header (current_uiout, address_width, ui_left,
+			   "addr", "Address");                           /* 4 */
+    }
+  ui_out_table_header (current_uiout, 40, ui_noalign, "what", "What");   /* 5 */
+  ui_out_table_body (current_uiout);
+
+  ALL_SKIPLIST_ENTRIES (e)
+    {
+      struct cleanup *entry_chain;
+
+      QUIT;
+      if (arg != 0 && !number_is_in_list(arg, e->number))
+	continue;
+
+      entry_chain = make_cleanup_ui_out_tuple_begin_end (current_uiout,
+							 "blklst-entry");
+      ui_out_field_int (current_uiout, "number", e->number);             /* 1 */
+
+      if (e->function_name != 0)
+	ui_out_field_string (current_uiout, "type", "function");         /* 2 */
+      else if (e->filename != 0)
+	ui_out_field_string (current_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 (current_uiout, "enabled", "y");             /* 3 */
+      else
+	ui_out_field_string (current_uiout, "enabled", "n");             /* 3 */
+
+      if (opts.addressprint)
+	{
+	  if (e->pc != 0)
+	    ui_out_field_core_addr (current_uiout, "addr",
+				    e->gdbarch, e->pc);                  /* 4 */
+	  else
+	    ui_out_field_string (current_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 (current_uiout, "what", "%s at %s:%d",
+			       sym->ginfo.name,
+			       sym->symtab->filename,
+			       sym->line);
+	   else
+	     ui_out_field_string (current_uiout, "what", "?");
+	}
+      else if (e->pending && e->function_name != 0)
+	{
+	  ui_out_field_fmt (current_uiout, "what", "%s (PENDING)",
+			    e->function_name);
+	}
+      else if (!e->pending && e->filename != 0)
+	ui_out_field_string (current_uiout, "what", e->filename);
+      else if (e->pending && e->filename != 0)
+	ui_out_field_fmt (current_uiout, "what", "%s (PENDING)",
+			  e->filename);
+
+      ui_out_text (current_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 found = 0;
+
+  ALL_SKIPLIST_ENTRIES (e)
+    if (arg == 0 || number_is_in_list(arg, e->number))
+      {
+        e->enabled = 1;
+        found = 1;
+      }
+
+  if (!found)
+    error (_("No skiplist entries found with number %s."), arg);
+}
+
+static void
+skip_disable_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e;
+  int found = 0;
+
+  ALL_SKIPLIST_ENTRIES (e)
+    if (arg == 0 || number_is_in_list(arg, e->number))
+      {
+	e->enabled = 0;
+        found = 1;
+      }
+
+  if (!found)
+    error (_("No skiplist entries found with number %s."), arg);
+}
+
+static void
+skip_delete_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e, *temp, *b_prev;
+  int found = 0;
+
+  b_prev = 0;
+  ALL_SKIPLIST_ENTRIES_SAFE (e, temp)
+    if (arg == 0 || number_is_in_list(arg, e->number))
+      {
+	if (b_prev != 0)
+	  b_prev->next = e->next;
+	else
+	  skiplist_entry_chain = e->next;
+
+	xfree (e->function_name);
+	xfree (e->filename);
+	xfree (e);
+        found = 1;
+      }
+    else
+      {
+	b_prev = e;
+      }
+
+  if (!found)
+    error (_("No skiplist entries found with number %s."), arg);
+}
+
+/* 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)
+{
+  int searched_for_sal = 0;
+  struct symtab_and_line sal;
+  char *filename = NULL;
+  struct skiplist_entry *e;
+
+  sal = find_pc_line (pc, 0);
+  filename = sal.symtab->filename;
+
+  ALL_SKIPLIST_ENTRIES (e)
+    {
+      if (!e->enabled || e->pending)
+	continue;
+
+      /* Does the pc we're stepping into match e's stored pc? */
+      if (e->pc != 0 && pc == e->pc)
+	return 1;
+
+      if (e->filename != 0)
+	{
+	  /* Get the filename corresponding to this pc, if we haven't
+	   * yet. */
+	  if (!searched_for_sal)
+	    {
+	      sal = find_pc_line (pc, 0);
+	      filename = sal.symtab->filename;
+	      searched_for_sal = 1;
+	    }
+	  if (filename != 0 && strcmp (filename, e->filename) == 0)
+	    return 1;
+	}
+    }
+
+  return 0;
+}
+
+/* Re-set the skip list after symbols have been re-loaded. */
+void
+skip_re_set (void)
+{
+  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);
+              char *func_name;
+
+	      if (find_pc_partial_function (pc, &func_name, &func_start, 0))
+		{
+		  e->pending = 0;
+                  e->function_name = xstrdup (func_name);
+		  e->pc = func_start;
+		  e->gdbarch = arch;
+		}
+	    }
+	  else
+	    {
+	      e->pending = 1;
+	    }
+        }
+    }
+}
+
+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\
+Usage: 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\
+Usage: 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\
+Usage: 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 skip entries.  You can specify numbers (e.g. \"skip enable 1 3\"), \
+ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\
+If you don't specify any numbers or ranges, we'll enable all skip entries.\n\n\
+Usage: skip enable [NUMBERS AND/OR RANGES]"),
+	   &skiplist);
+
+  add_cmd ("disable", class_breakpoint, skip_disable_command, _("\
+Disable skip entries.  You can specify numbers (e.g. \"skip disable 1 3\"), \
+ranges (e.g. \"skip disable 4-8\"), or both (e.g. \"skip disable 1 3 4-8\").\n\n\
+If you don't specify any numbers or ranges, we'll disable all skip entries.\n\n\
+Usage: skip disable [NUMBERS AND/OR RANGES]"),
+	   &skiplist);
+
+  add_cmd ("delete", class_breakpoint, skip_delete_command, _("\
+Delete skip entries.  You can specify numbers (e.g. \"skip delete 1 3\"), \
+ranges (e.g. \"skip delete 4-8\"), or both (e.g. \"skip delete 1 3 4-8\").\n\n\
+If you don't specify any numbers or ranges, we'll delete all skip entries.\n\n\
+Usage: skip delete [NUMBERS AND/OR RANGES]"),
+           &skiplist);
+
+  add_info ("skip", skip_info, _("\
+Display the status of skips.  You can specify numbers (e.g. \"skip info 1 3\"), \
+ranges (e.g. \"skip info 4-8\"), or both (e.g. \"skip info 1 3 4-8\").\n\n\
+If you don't specify any numbers or ranges, we'll show all skips.\n\n\
+Usage: skip info [NUMBERS AND/OR RANGES]\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..143f7ed
--- /dev/null
+++ b/gdb/skip.h
@@ -0,0 +1,28 @@
+/* Header for skipping over uninteresting files and functions when debugging.
+
+   Copyright (C) 2011 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 (void);
+
+#endif /* !defined (SKIP_H) */
diff --git a/gdb/stack.c b/gdb/stack.c
index 15666ee..cf25eb7 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_sal (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 symtab and line we displayed to the user.
+ * This is where we insert a breakpoint or a skiplist entry by default. */
+static int last_displayed_sal_valid = 0;
+static struct program_space *last_displayed_pspace = 0;
+static CORE_ADDR last_displayed_addr = 0;
+static struct symtab *last_displayed_symtab = 0;
+static int last_displayed_line = 0;
 
 
 /* Return 1 if we should display the address in addition to the location,
@@ -599,9 +613,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_sal (1, sal.pspace, pc, sal.symtab, sal.line);
       else
-	set_default_breakpoint (0, 0, 0, 0, 0);
+	set_last_displayed_sal (0, 0, 0, 0, 0);
     }
 
   annotate_frame_end ();
@@ -609,6 +623,98 @@ print_frame_info (struct frame_info *frame, int print_level,
   gdb_flush (gdb_stdout);
 }
 
+/* Remember the last symtab and line 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_sal (int valid, struct program_space *pspace,
+			CORE_ADDR addr, struct symtab *symtab,
+			int line)
+{
+  last_displayed_sal_valid = valid;
+  last_displayed_pspace = pspace;
+  last_displayed_addr = addr;
+  last_displayed_symtab = symtab;
+  last_displayed_line = line;
+}
+
+/* Forget the last sal we displayed.  */
+void
+clear_last_displayed_sal (void)
+{
+  last_displayed_sal_valid = 0;
+  last_displayed_pspace = 0;
+  last_displayed_addr = 0;
+  last_displayed_symtab = 0;
+  last_displayed_line = 0;
+}
+
+/* Is our record of the last sal we displayed valid?  If not,
+ * the get_last_displayed_* functions will return NULL or 0, as
+ * appropriate.  */
+int
+last_displayed_sal_is_valid (void)
+{
+  return last_displayed_sal_valid;
+}
+
+/* Get the pspace of the last sal we displayed, if it's valid.  */
+struct program_space *
+get_last_displayed_pspace (void)
+{
+  if (last_displayed_sal_valid)
+    return last_displayed_pspace;
+  return 0;
+}
+
+/* Get the address of the last sal we displayed, if it's valid.  */
+CORE_ADDR
+get_last_displayed_addr (void)
+{
+  if (last_displayed_sal_valid)
+    return last_displayed_addr;
+  return 0;
+}
+
+/* Get the symtab of the last sal we displayed, if it's valid.  */
+struct symtab*
+get_last_displayed_symtab (void)
+{
+  if (last_displayed_sal_valid)
+    return last_displayed_symtab;
+  return 0;
+}
+
+/* Get the line of the last sal we displayed, if it's valid.  */
+int
+get_last_displayed_line (void)
+{
+  if (last_displayed_sal_valid)
+    return last_displayed_line;
+  return 0;
+}
+
+/* Get the last sal we displayed, if it's valid.  */
+void
+get_last_displayed_sal (struct symtab_and_line *sal)
+{
+  if (last_displayed_sal_valid)
+    {
+      sal->pspace = last_displayed_pspace;
+      sal->pc = last_displayed_addr;
+      sal->symtab = last_displayed_symtab;
+      sal->line = last_displayed_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..312e8ff 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 symtab and line, which is, e.g. where we set a
+ * breakpoint when `break' is supplied with no arguments.  */
+void clear_last_displayed_sal (void);
+int last_displayed_sal_is_valid (void);
+struct program_space* get_last_displayed_pspace (void);
+CORE_ADDR get_last_displayed_addr (void);
+struct symtab* get_last_displayed_symtab (void);
+int get_last_displayed_line (void);
+void get_last_displayed_sal (struct symtab_and_line *sal);
+
 #endif /* #ifndef STACK_H */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 1540cb7..1c4d0c9 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>
@@ -2780,7 +2781,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_sal ();
   clear_pc_function_cache ();
   observer_notify_new_objfile (NULL);
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 8f9efd1..7deea3e 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2011-10-06  Justin Lebar <justin.lebar@gmail.com>
+
+	Add tests for skip command.
+	* 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-10-05  Pierre Muller  <muller@ics.u-strasbg.fr>
 
 	Add tests for passing of environment variables to inferior.
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..4f8838d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip-solib.exp
@@ -0,0 +1,129 @@
+#   Copyright 2011 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..d26a3c3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip.exp
@@ -0,0 +1,180 @@
+#   Copyright 2011 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 skipping 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 entries found with number 999."
+gdb_test "skip disable 999" "No skiplist entries found with number 999."
+gdb_test "skip delete 999" "No skiplist entries found with number 999."
+gdb_test "skip enable a" "Args must be numbers or '\\$' variables."
+gdb_test "skip disable a" "Args must be numbers or '\\$' variables."
+gdb_test "skip delete a" "Args must be numbers or '\\$' variables."
+
+#
+# Ask for info on a skiplist entry which doesn't exist.
+#
+gdb_test "info skip 999" "No skiplist entries found with number 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().
+#
+
+# XXX This gdb_test sometimes fails, due to an apparent race.
+if ![runto_main] { fail "skip tests suppressed" }
+send_gdb "step\n"
+gdb_test "bt" "\\s*\\#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)"
+
+send_gdb "skip disable\n"
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+2\\s+function\\s+n\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+n\\s+.*$srcfile1\\s*
+4\\s+function\\s+n\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*" \
+"info skip after disabling all"
+
+send_gdb "skip enable\n"
+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*" \
+"info skip after enabling all"
+
+send_gdb "skip disable 4 2-3\n"
+gdb_test "info skip" \
+"Num\\s+Type\\s+Enb\\s+Address\\s+What\\s*
+2\\s+function\\s+n\\s+0x\[0-9a-f\]+ main at .*$srcfile:\[0-9\]+\\s*
+3\\s+file\\s+n\\s+.*$srcfile1\\s*
+4\\s+function\\s+n\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*" \
+"info skip after disabling 4 2-3"
+
+send_gdb "skip enable 2-3\n"
+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+n\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*" \
+"info skip after enabling 2-3"
+
+gdb_test "info skip 2-3" \
+"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*" \
+"info skip 2-3"
+
+send_gdb "skip delete 2 3\n"
+gdb_test "info skip" \
+"4\\s+function\\s+n\\s+0x\[0-9a-f\]+ baz at .*$srcfile1:\[0-9\]+\\s*" \
+"info skip after deleting 2 3"
+
+send_gdb "skip delete\n"
+gdb_test "info skip" "Not skipping any files or functions\." \
+"info skip after deleting all"
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;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]