Re: Status of 'blacklist' patch?

Justin Lebar
2011-10-06T20:16:13Z

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

> If you update the patch and resubmit, I promise I'll give it a prompt
> review.

Deal. I've attached an updated patch, and it looks like gmail got the
mime type right this time. :)

> There's a lot of change of terminology from "default breakpoint" to
> "displayed codepoint". I know we've debated better substitutes for
> "breakpoint", but this patch is maybe not the best place to introduce one.

How about "last displayed symtab and line"? That seems to be
something which is meaningful.

On Thu, Oct 6, 2011 at 1:33 PM, Tom Tromey <tromey@redhat.com> wrote:
> Just for future reference, I encourage everybody to ping a lot -- send a
> ping once a week. In my experience, it feels like I'm being obnoxious
> when I write the note, but it is a good way to get attention, and I
> promise you nobody will be offended by it.

Thanks; that's good to know. Different communities handle this sort
of thing differently.

Regards,
-Justin

On Thu, Oct 6, 2011 at 11:51 AM, Stan Shebs <stanshebs@earthlink.net> wrote:
> On 10/6/11 7:07 AM, Justin Lebar wrote:
>>
>> I last pinged gdb-patches about the patch on May 16 and got no response.
>>
>> I imagine the patch has bitrotted by now.  I'd be happy to bring it up
>> to date if there were a reasonable chance it would get reviewed this
>> time.
>>
>
> (It took a bit of digging to find the last version of the patch - I probably
> missed it because the patch was attached as a binary, including the
> changelog entry.)
>
> Anyway, I really like the concept, and "skip" seems like a good general term
> for the functionality.
>
> I skimmed the April version, and noticed a few things to fix up.
>
> The file headers say things like "Header for GDB line completion.", which
> I'm guessing is cut-n-paste from another file. :-)  Also it's now 2011, not
> 2010.
>
> There's a lot of change of terminology from "default breakpoint" to
> "displayed codepoint".  I know we've debated better substitutes for
> "breakpoint", but this patch is maybe not the best place to introduce one.
>  (Or I'm confused about what "codepoint" means, I didn't see a definition.)
>
> I didn't see a patch for the GDB manual, so I'm not sure of the intended
> functionality details.
>
> If you update the patch and resubmit, I promise I'll give it a prompt
> review.
>
> Stan
> stan@codesourcery.com
>
>
>

[-- Attachment #2: skip.diff --]
[-- Type: text/x-patch, Size: 52231 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a166d14..22130b9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,40 @@
+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): 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_symtab_and_line,
+ last_displayed_symtab_and_line_is_valid, get_last_displayed_pspace,
+ get_last_displayed_addr, get_last_displayed_symtab,
+ get_last_displayed_line, get_last_displayed_symtab_and_line): New
+ public functions.
+ * stack.h (clear_last_displayed_symtab_and_line,
+ last_displayed_symtab_and_line_is_valid, get_last_displayed_pspace,
+ get_last_displayed_addr, get_last_displayed_symtab,
+ get_last_displayed_line, get_last_displayed_symtab_and_line): Added
+
2011-10-05 Tristan Gingold <gingold@adacore.com>

* ada-tasks.c (read_atcb): Make ravenscar_task_name static.
@@ -4733,6 +4770,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 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/breakpoint.c b/gdb/breakpoint.c
index 08ff69b..3d3e12b 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;
-
\f
/* 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,
}
}
\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
@@ -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_symtab_and_line_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_symtab_and_line (&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_symtab_and_line_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_symtab_and_line_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_symtab_and_line (&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 ();
}
\f
/* 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_symtab_and_line_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..d7e3799 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 *);
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..bd854ca 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4854,6 +4854,104 @@ 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 skip
+
+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 over a file or function when stepping.
+
+For example, suppose you are stepping through 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}! What can you do?
+
+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.
+
+Another solution is to execute @code{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
+@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. (@pxref{Specify Location})
+
+If you do not specify @var{linespec}, the function you're currently debugging
+will be skipped.
+
+@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
+Print a table of all functions and files marked for skipping. This table
+contains the following information for each function or file:
+
+@table @emph
+@item Identifier
+A number identifying this skip.
+@item Type
+@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 break} 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 @var{n}
+Delete the skip with identifier @var{n}.
+
+@kindex skip enable
+@item skip enable @var{n}
+Enable the skip with identifier @var{n}.
+
+@kindex skip disable
+@item skip disable @var{n}
+Disable the skip with identifier @var{n}.
+
+@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..edb51ff
--- /dev/null
+++ b/gdb/skip.c
@@ -0,0 +1,574 @@
+/* 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/>. */
+
+#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_symtab_and_line_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 (current_uiout, 0, _("Not ignoring any files or functions.\n"));
+ else
+ ui_out_message (current_uiout, 0,
+ _("No skiplist entry numbered %d.\n"), entry_num);
+
+ 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 (entry_num != -1 && entry_num != 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 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..c611555
--- /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 ();
+
+#endif /* !defined (SKIP_H) */
diff --git a/gdb/stack.c b/gdb/stack.c
index 15666ee..6f3693a 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

/* 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_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 ();
@@ -609,6 +623,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_symtab_and_line ()
+{
+ last_codepoint_valid = 0;
+ last_codepoint_pspace = 0;
+ last_codepoint_addr = 0;
+ last_codepoint_symtab = 0;
+ last_codepoint_line = 0;
+}
+
+int
+last_displayed_symtab_and_line_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
+get_last_displayed_symtab_and_line (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..320332b 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_symtab_and_line ();
+int last_displayed_symtab_and_line_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 get_last_displayed_symtab_and_line (struct symtab_and_line *sal);
+
#endif /* #ifndef STACK_H */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 1540cb7..6967805 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_symtab_and_line ();
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..ba1e87b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/skip.exp
@@ -0,0 +1,135 @@
+# 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 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."
+
+#
+# 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;
+}