Extend "skip" command to support -file, -gfile, -function, -rfunction.

gdb/ChangeLog:

	Extend "skip" command to support -file, -gfile, -function, -rfunction.
	* NEWS: Document new features.
	* skip.c: #include "fnmatch.h", "gdb_regex.h".
	(skiplist_entry) <file>: Renamed from filename.
	<function>: Renamed from function_name.
	<file_is_glob, function_is_regexp>: New members.
	<compiled_function_regexp, compiled_function_regexp_is_valid>:
	New members.
	(make_skip_entry): New function.
	(free_skiplist_entry, free_skiplist_entry_cleanup): New functions.
	(make_free_skiplist_entry_cleanup): New function.
	(skip_file_command): Update.
	(skip_function, skip_function_command): Update.
	(compile_skip_regexp): New functions.
	(skip_command): Add support for new options.
	(skip_info): Update.
	(skip_file_p, skip_gfile_p): New functions.
	(skip_function_p, skip_rfunction_p): New functions.
	(function_name_is_marked_for_skip): Update and simplify.
	(_initialize_step_skip): Update.
	* symtab.c: #include "fnmatch.h".
	(compare_glob_filenames_for_search): New function.
	* symtab.h (compare_glob_filenames_for_search): Declare.
	* utils.c (count_path_elements): New function.
	(strip_leading_path_elements): New function.
	* utils.h (count_path_elements): Declare.
	(strip_leading_path_elements): Declare.

gdb/doc/ChangeLog:

	* gdb.texinfo (Skipping Over Functions and Files): Document new
	options to "skip" command.  Update docs of output of "info skip".

gdb/testsuite/ChangeLog:

	* gdb.base/skip.c (test_skip): New function.
	(end_test_skip_file_and_function): New function.
	(test_skip_file_and_function): New function.
	* gdb.base/skip1.c (test_skip): New function.
	(skip1_test_skip_file_and_function): New function.
	* gdb.base/skip.exp: Add tests for new skip options.
	* gdb.base/skip-solib.exp: Update expected output.
	* gdb.perf/skip-command.cc: New file.
	* gdb.perf/skip-command.exp: New file.
	* gdb.perf/skip-command.py: New file.
This commit is contained in:
Doug Evans 2016-02-23 13:25:18 -08:00
parent 742e5034ef
commit cce0e92333
17 changed files with 1089 additions and 187 deletions

View File

@ -1,3 +1,33 @@
2016-02-23 Doug Evans <dje@google.com>
Extend "skip" command to support -file, -gfile, -function, -rfunction.
* NEWS: Document new features.
* skip.c: #include "fnmatch.h", "gdb_regex.h".
(skiplist_entry) <file>: Renamed from filename.
<function>: Renamed from function_name.
<file_is_glob, function_is_regexp>: New members.
<compiled_function_regexp, compiled_function_regexp_is_valid>:
New members.
(make_skip_entry): New function.
(free_skiplist_entry, free_skiplist_entry_cleanup): New functions.
(make_free_skiplist_entry_cleanup): New function.
(skip_file_command): Update.
(skip_function, skip_function_command): Update.
(compile_skip_regexp): New functions.
(skip_command): Add support for new options.
(skip_info): Update.
(skip_file_p, skip_gfile_p): New functions.
(skip_function_p, skip_rfunction_p): New functions.
(function_name_is_marked_for_skip): Update and simplify.
(_initialize_step_skip): Update.
* symtab.c: #include "fnmatch.h".
(compare_glob_filenames_for_search): New function.
* symtab.h (compare_glob_filenames_for_search): Declare.
* utils.c (count_path_elements): New function.
(strip_leading_path_elements): New function.
* utils.h (count_path_elements): Declare.
(strip_leading_path_elements): Declare.
2016-02-23 Simon Marchi <simon.marchi@ericsson.com>
* arm-tdep.c (arm_decode_svc_copro): Remove "to" parameter.

View File

@ -141,6 +141,14 @@ show max-value-size
allocate for value contents. Prevents incorrect programs from
causing GDB to allocate overly large buffers. Default is 64k.
skip -file file
skip -gfile file-glob-pattern
skip -function function
skip -rfunction regular-expression
A generalized form of the skip command, with new support for
glob-style file names and regular expressions for function names.
Additionally, a file spec and a function spec may now be combined.
* The "disassemble" command accepts a new modifier: /s.
It prints mixed source+disassembly like /m with two differences:
- disassembled instructions are now printed in program order, and

View File

@ -1,3 +1,8 @@
2016-02-23 Doug Evans <dje@google.com>
* gdb.texinfo (Skipping Over Functions and Files): Document new
options to "skip" command. Update docs of output of "info skip".
2016-02-18 Walfred Tedeschi <walfred.tedeschi@intel.com>
* gdb.texinfo (Signals): Add bound violation display hints for

View File

@ -5528,7 +5528,8 @@ default is @code{on}.
The program you are debugging may contain some functions which are
uninteresting to debug. The @code{skip} command lets you tell @value{GDBN} to
skip a function or all functions in a file when stepping.
skip a function, all functions in a file or a particular function in
a particular file when stepping.
For example, consider the following C function:
@ -5555,13 +5556,75 @@ A more flexible solution is to execute @kbd{skip boring}. This instructs
@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}.
Functions may be skipped by providing either a function name, linespec
(@pxref{Specify Location}), regular expression that matches the function's
name, file name or a @code{glob}-style pattern that matches the file name.
On Posix systems the form of the regular expression is
``Extended Regular Expressions''. See for example @samp{man 7 regex}
on @sc{gnu}/Linux systems. On non-Posix systems the form of the regular
expression is whatever is provided by the @code{regcomp} function of
the underlying system.
See for example @samp{man 7 glob} on @sc{gnu}/Linux systems for a
description of @code{glob}-style patterns.
@table @code
@kindex skip
@item skip @r{[}@var{options}@r{]}
The basic form of the @code{skip} command takes zero or more options
that specify what to skip.
The @var{options} argument is any useful combination of the following:
@table @code
@item -file @var{file}
@itemx -fi @var{file}
Functions in @var{file} will be skipped over when stepping.
@item -gfile @var{file-glob-pattern}
@itemx -gfi @var{file-glob-pattern}
@cindex skipping over files via glob-style patterns
Functions in files matching @var{file-glob-pattern} will be skipped
over when stepping.
@smallexample
(gdb) skip -gfi utils/*.c
@end smallexample
@item -function @var{linespec}
@itemx -fu @var{linespec}
Functions named by @var{linespec} or the function containing the line
named by @var{linespec} will be skipped over when stepping.
@xref{Specify Location}.
@item -rfunction @var{regexp}
@itemx -rfu @var{regexp}
@cindex skipping over functions via regular expressions
Functions whose name matches @var{regexp} will be skipped over when stepping.
This form is useful for complex function names.
For example, there is generally no need to step into C@t{++} @code{std::string}
constructors or destructors. Plus with C@t{++} templates it can be hard to
write out the full name of the function, and often it doesn't matter what
the template arguments are. Specifying the function to be skipped as a
regular expression makes this easier.
@smallexample
(gdb) skip -rfu ^std::(allocator|basic_string)<.*>::~?\1 *\(
@end smallexample
If you want to skip every templated C@t{++} constructor and destructor
in the @code{std} namespace you can do:
@smallexample
(gdb) skip -rfu ^std::([a-zA-z0-9_]+)<.*>::~?\1 *\(
@end smallexample
@end table
If no options are specified, the function you're currently debugging
will be skipped.
@kindex skip function
@item skip @r{[}@var{linespec}@r{]}
@itemx skip function @r{[}@var{linespec}@r{]}
@item 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}.
@ -5577,6 +5640,11 @@ will be skipped.
After running this command, any function whose source lives in @var{filename}
will be skipped over when stepping.
@smallexample
(gdb) skip file boring.c
File boring.c will be skipped when stepping.
@end smallexample
If you do not specify @var{filename}, functions whose source lives in the file
you're currently debugging will be skipped.
@end table
@ -5594,20 +5662,21 @@ print a table with details about all functions and files marked for skipping.
@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.
Enabled skips are marked with @samp{y}.
Disabled skips are marked with @samp{n}.
@item Glob
If the file name is a @samp{glob} pattern this is @samp{y}.
Otherwise it is @samp{n}.
@item File
The name or @samp{glob} pattern of the file to be skipped.
If no file is specified this is @samp{<none>}.
@item RE
If the function name is a @samp{regular expression} this is @samp{y}.
Otherwise it is @samp{n}.
@item Function
The name or regular expression of the function to skip.
If no function is specified this is @samp{<none>}.
@end table
@kindex skip delete

View File

@ -32,19 +32,35 @@
#include "breakpoint.h" /* for get_sal_arch () */
#include "source.h"
#include "filenames.h"
#include "fnmatch.h"
#include "gdb_regex.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;
/* Non-zero if FILE is a glob-style pattern.
Otherewise it is the plain file name (possibly with directories). */
int file_is_glob;
/* The name of the marked-for-skip function, if this is a skiplist
entry for a function.
/* The name of the file or NULL.
The skiplist entry owns this pointer. */
char *function_name;
char *file;
/* Non-zero if FUNCTION is a regexp.
Otherwise it is a plain function name (possibly with arguments,
for C++). */
int function_is_regexp;
/* The name of the function or NULL.
The skiplist entry owns this pointer. */
char *function;
/* If this is a function regexp, the compiled form. */
regex_t compiled_function_regexp;
/* Non-zero if the function regexp has been compiled. */
int compiled_function_regexp_is_valid;
int enabled;
@ -52,7 +68,6 @@ struct skiplist_entry
};
static void add_skiplist_entry (struct skiplist_entry *e);
static void skip_function (const char *name);
static struct skiplist_entry *skiplist_entry_chain;
static int skiplist_entry_count;
@ -65,10 +80,62 @@ static int skiplist_entry_count;
E ? (TMP = E->next, 1) : 0; \
E = TMP)
/* Create a skip object. */
static struct skiplist_entry *
make_skip_entry (int file_is_glob, const char *file,
int function_is_regexp, const char *function)
{
struct skiplist_entry *e = XCNEW (struct skiplist_entry);
gdb_assert (file != NULL || function != NULL);
if (file_is_glob)
gdb_assert (file != NULL);
if (function_is_regexp)
gdb_assert (function != NULL);
if (file != NULL)
e->file = xstrdup (file);
if (function != NULL)
e->function = xstrdup (function);
e->file_is_glob = file_is_glob;
e->function_is_regexp = function_is_regexp;
e->enabled = 1;
return e;
}
/* Free a skiplist entry. */
static void
free_skiplist_entry (struct skiplist_entry *e)
{
xfree (e->file);
xfree (e->function);
if (e->function_is_regexp && e->compiled_function_regexp_is_valid)
regfree (&e->compiled_function_regexp);
xfree (e);
}
/* Wrapper to free_skiplist_entry for use as a cleanup. */
static void
free_skiplist_entry_cleanup (void *e)
{
free_skiplist_entry ((struct skiplist_entry *) e);
}
/* Create a cleanup to free skiplist entry E. */
static struct cleanup *
make_free_skiplist_entry_cleanup (struct skiplist_entry *e)
{
return make_cleanup (free_skiplist_entry_cleanup, e);
}
static void
skip_file_command (char *arg, int from_tty)
{
struct skiplist_entry *e;
struct symtab *symtab;
const char *filename = NULL;
@ -85,37 +152,31 @@ skip_file_command (char *arg, int from_tty)
filename = symtab_to_fullname (symtab);
}
else
{
symtab = lookup_symtab (arg);
if (symtab == NULL)
{
fprintf_filtered (gdb_stderr, _("No source file named %s.\n"), arg);
if (!nquery (_("\
Ignore file pending future shared library load? ")))
return;
}
/* Do not use SYMTAB's filename, later loaded shared libraries may match
given ARG but not SYMTAB's filename. */
filename = arg;
}
filename = arg;
e = XCNEW (struct skiplist_entry);
e->filename = xstrdup (filename);
e->enabled = 1;
add_skiplist_entry (e);
add_skiplist_entry (make_skip_entry (0, filename, 0, NULL));
printf_filtered (_("File %s will be skipped when stepping.\n"), filename);
}
/* Create a skiplist entry for the given function NAME and add it to the
list. */
static void
skip_function (const char *name)
{
add_skiplist_entry (make_skip_entry (0, NULL, 0, name));
printf_filtered (_("Function %s will be skipped when stepping.\n"), name);
}
static void
skip_function_command (char *arg, int from_tty)
{
const char *name = NULL;
/* Default to the current function if no argument is given. */
if (arg == NULL)
{
const char *name = NULL;
CORE_ADDR pc;
if (!last_displayed_sal_is_valid ())
@ -128,25 +189,169 @@ skip_function_command (char *arg, int from_tty)
paddress (get_current_arch (), pc));
}
skip_function (name);
return;
}
else
{
if (lookup_symbol (arg, NULL, VAR_DOMAIN, NULL).symbol == NULL)
{
fprintf_filtered (gdb_stderr,
_("No function found named %s.\n"), arg);
if (nquery (_("\
Ignore function pending future shared library load? ")))
{
/* Add the unverified skiplist entry. */
skip_function (arg);
}
skip_function (arg);
}
/* Compile the regexp in E.
An error is thrown if there's an error.
MESSAGE is used as a prefix of the error message. */
static void
compile_skip_regexp (struct skiplist_entry *e, const char *message)
{
int code;
int flags = REG_NOSUB;
#ifdef REG_EXTENDED
flags |= REG_EXTENDED;
#endif
gdb_assert (e->function_is_regexp && e->function != NULL);
code = regcomp (&e->compiled_function_regexp, e->function, flags);
if (code != 0)
{
char *err = get_regcomp_error (code, &e->compiled_function_regexp);
make_cleanup (xfree, err);
error (_("%s: %s"), message, err);
}
e->compiled_function_regexp_is_valid = 1;
}
/* Process "skip ..." that does not match "skip file" or "skip function". */
static void
skip_command (char *arg, int from_tty)
{
const char *file = NULL;
const char *gfile = NULL;
const char *function = NULL;
const char *rfunction = NULL;
char **argv;
struct cleanup *cleanups;
struct skiplist_entry *e;
int i;
if (arg == NULL)
{
skip_function_command (arg, from_tty);
return;
}
argv = buildargv (arg);
cleanups = make_cleanup_freeargv (argv);
for (i = 0; argv[i] != NULL; ++i)
{
const char *p = argv[i];
const char *value = argv[i + 1];
if (strcmp (p, "-fi") == 0
|| strcmp (p, "-file") == 0)
{
if (value == NULL)
error (_("Missing value for %s option."), p);
file = value;
++i;
}
else if (strcmp (p, "-gfi") == 0
|| strcmp (p, "-gfile") == 0)
{
if (value == NULL)
error (_("Missing value for %s option."), p);
gfile = value;
++i;
}
else if (strcmp (p, "-fu") == 0
|| strcmp (p, "-function") == 0)
{
if (value == NULL)
error (_("Missing value for %s option."), p);
function = value;
++i;
}
else if (strcmp (p, "-rfu") == 0
|| strcmp (p, "-rfunction") == 0)
{
if (value == NULL)
error (_("Missing value for %s option."), p);
rfunction = value;
++i;
}
else if (*p == '-')
error (_("Invalid skip option: %s"), p);
else if (i == 0)
{
/* Assume the user entered "skip FUNCTION-NAME".
FUNCTION-NAME may be `foo (int)', and therefore we pass the
complete original arg to skip_function command as if the user
typed "skip function arg". */
do_cleanups (cleanups);
skip_function_command (arg, from_tty);
return;
}
skip_function (arg);
else
error (_("Invalid argument: %s"), p);
}
if (file != NULL && gfile != NULL)
error (_("Cannot specify both -file and -gfile."));
if (function != NULL && rfunction != NULL)
error (_("Cannot specify both -function and -rfunction."));
/* This shouldn't happen as "skip" by itself gets punted to
skip_function_command. */
gdb_assert (file != NULL || gfile != NULL
|| function != NULL || rfunction != NULL);
e = make_skip_entry (gfile != NULL, file ? file : gfile,
rfunction != NULL, function ? function : rfunction);
if (rfunction != NULL)
{
struct cleanup *rf_cleanups = make_free_skiplist_entry_cleanup (e);
compile_skip_regexp (e, _("regexp"));
discard_cleanups (rf_cleanups);
}
add_skiplist_entry (e);
/* I18N concerns drive some of the choices here (we can't piece together
the output too much). OTOH we want to keep this simple. Therefore the
only polish we add to the output is to append "(s)" to "File" or
"Function" if they're a glob/regexp. */
{
const char *file_to_print = file != NULL ? file : gfile;
const char *function_to_print = function != NULL ? function : rfunction;
const char *file_text = gfile != NULL ? _("File(s)") : _("File");
const char *lower_file_text = gfile != NULL ? _("file(s)") : _("file");
const char *function_text
= rfunction != NULL ? _("Function(s)") : _("Function");
if (function_to_print == NULL)
{
printf_filtered (_("%s %s will be skipped when stepping.\n"),
file_text, file_to_print);
}
else if (file_to_print == NULL)
{
printf_filtered (_("%s %s will be skipped when stepping.\n"),
function_text, function_to_print);
}
else
{
printf_filtered (_("%s %s in %s %s will be skipped"
" when stepping.\n"),
function_text, function_to_print,
lower_file_text, file_to_print);
}
}
do_cleanups (cleanups);
}
static void
@ -177,14 +382,17 @@ Not skipping any files or functions.\n"));
return;
}
tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 4,
tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 6,
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 */
ui_out_table_header (current_uiout, 40, ui_noalign, "what", "What"); /* 4 */
ui_out_table_header (current_uiout, 5, ui_left, "number", "Num"); /* 1 */
ui_out_table_header (current_uiout, 3, ui_left, "enabled", "Enb"); /* 2 */
ui_out_table_header (current_uiout, 4, ui_right, "regexp", "Glob"); /* 3 */
ui_out_table_header (current_uiout, 20, ui_left, "file", "File"); /* 4 */
ui_out_table_header (current_uiout, 2, ui_right, "regexp", "RE"); /* 5 */
ui_out_table_header (current_uiout, 40, ui_noalign,
"function", "Function"); /* 6 */
ui_out_table_body (current_uiout);
ALL_SKIPLIST_ENTRIES (e)
@ -197,25 +405,27 @@ Not skipping any files or functions.\n"));
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 != NULL)
ui_out_field_string (current_uiout, "type", "function"); /* 2 */
else if (e->filename != NULL)
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."));
ui_out_field_int (current_uiout, "number", e->number); /* 1 */
if (e->enabled)
ui_out_field_string (current_uiout, "enabled", "y"); /* 3 */
ui_out_field_string (current_uiout, "enabled", "y"); /* 2 */
else
ui_out_field_string (current_uiout, "enabled", "n"); /* 3 */
ui_out_field_string (current_uiout, "enabled", "n"); /* 2 */
if (e->function_name != NULL)
ui_out_field_string (current_uiout, "what", e->function_name); /* 4 */
else if (e->filename != NULL)
ui_out_field_string (current_uiout, "what", e->filename); /* 4 */
if (e->file_is_glob)
ui_out_field_string (current_uiout, "regexp", "y"); /* 3 */
else
ui_out_field_string (current_uiout, "regexp", "n"); /* 3 */
ui_out_field_string (current_uiout, "file",
e->file ? e->file : "<none>"); /* 4 */
if (e->function_is_regexp)
ui_out_field_string (current_uiout, "regexp", "y"); /* 5 */
else
ui_out_field_string (current_uiout, "regexp", "n"); /* 5 */
ui_out_field_string (current_uiout, "function",
e->function ? e->function : "<none>"); /* 6 */
ui_out_text (current_uiout, "\n");
do_cleanups (entry_chain);
@ -273,9 +483,7 @@ skip_delete_command (char *arg, int from_tty)
else
skiplist_entry_chain = e->next;
xfree (e->function_name);
xfree (e->filename);
xfree (e);
free_skiplist_entry (e);
found = 1;
}
else
@ -287,22 +495,6 @@ skip_delete_command (char *arg, int from_tty)
error (_("No skiplist entries found with number %s."), arg);
}
/* Create a skiplist entry for the given function NAME and add it to the
list. */
static void
skip_function (const char *name)
{
struct skiplist_entry *e = XCNEW (struct skiplist_entry);
e->enabled = 1;
e->function_name = xstrdup (name);
add_skiplist_entry (e);
printf_filtered (_("Function %s will be skipped when stepping.\n"), name);
}
/* Add the given skiplist entry to our list, and set the entry's number. */
static void
@ -326,6 +518,98 @@ add_skiplist_entry (struct skiplist_entry *e)
}
}
/* Return non-zero if we're stopped at a file to be skipped. */
static int
skip_file_p (struct skiplist_entry *e,
const struct symtab_and_line *function_sal)
{
gdb_assert (e->file != NULL && !e->file_is_glob);
if (function_sal->symtab == NULL)
return 0;
/* Check first sole SYMTAB->FILENAME. It may not be a substring of
symtab_to_fullname as it may contain "./" etc. */
if (compare_filenames_for_search (function_sal->symtab->filename, e->file))
return 1;
/* Before we invoke realpath, which can get expensive when many
files are involved, do a quick comparison of the basenames. */
if (!basenames_may_differ
&& filename_cmp (lbasename (function_sal->symtab->filename),
lbasename (e->file)) != 0)
return 0;
/* Note: symtab_to_fullname caches its result, thus we don't have to. */
{
const char *fullname = symtab_to_fullname (function_sal->symtab);
if (compare_filenames_for_search (fullname, e->file))
return 1;
}
return 0;
}
/* Return non-zero if we're stopped at a globbed file to be skipped. */
static int
skip_gfile_p (struct skiplist_entry *e,
const struct symtab_and_line *function_sal)
{
gdb_assert (e->file != NULL && e->file_is_glob);
if (function_sal->symtab == NULL)
return 0;
/* Check first sole SYMTAB->FILENAME. It may not be a substring of
symtab_to_fullname as it may contain "./" etc. */
if (gdb_filename_fnmatch (e->file, function_sal->symtab->filename,
FNM_FILE_NAME | FNM_NOESCAPE) == 0)
return 1;
/* Before we invoke symtab_to_fullname, which is expensive, do a quick
comparison of the basenames.
Note that we assume that lbasename works with glob-style patterns.
If the basename of the glob pattern is something like "*.c" then this
isn't much of a win. Oh well. */
if (!basenames_may_differ
&& gdb_filename_fnmatch (lbasename (e->file),
lbasename (function_sal->symtab->filename),
FNM_FILE_NAME | FNM_NOESCAPE) != 0)
return 0;
/* Note: symtab_to_fullname caches its result, thus we don't have to. */
{
const char *fullname = symtab_to_fullname (function_sal->symtab);
if (compare_glob_filenames_for_search (fullname, e->file))
return 1;
}
return 0;
}
/* Return non-zero if we're stopped at a function to be skipped. */
static int
skip_function_p (struct skiplist_entry *e, const char *function_name)
{
gdb_assert (e->function != NULL && !e->function_is_regexp);
return strcmp_iw (function_name, e->function) == 0;
}
/* Return non-zero if we're stopped at a function regexp to be skipped. */
static int
skip_rfunction_p (struct skiplist_entry *e, const char *function_name)
{
gdb_assert (e->function != NULL && e->function_is_regexp
&& e->compiled_function_regexp_is_valid);
return (regexec (&e->compiled_function_regexp, function_name, 0, NULL, 0)
== 0);
}
/* See skip.h. */
@ -333,8 +617,6 @@ int
function_name_is_marked_for_skip (const char *function_name,
const struct symtab_and_line *function_sal)
{
int searched_for_fullname = 0;
const char *fullname = NULL;
struct skiplist_entry *e;
if (function_name == NULL)
@ -342,43 +624,49 @@ function_name_is_marked_for_skip (const char *function_name,
ALL_SKIPLIST_ENTRIES (e)
{
int skip_by_file = 0;
int skip_by_function = 0;
if (!e->enabled)
continue;
/* Does the pc we're stepping into match e's stored pc? */
if (e->function_name != NULL
&& strcmp_iw (function_name, e->function_name) == 0)
return 1;
if (e->filename != NULL)
if (e->file != NULL)
{
/* Check first sole SYMTAB->FILENAME. It does not need to be
a substring of symtab_to_fullname as it may contain "./" etc. */
if (function_sal->symtab != NULL
&& compare_filenames_for_search (function_sal->symtab->filename,
e->filename))
return 1;
/* Before we invoke realpath, which can get expensive when many
files are involved, do a quick comparison of the basenames. */
if (!basenames_may_differ
&& (function_sal->symtab == NULL
|| filename_cmp (lbasename (function_sal->symtab->filename),
lbasename (e->filename)) != 0))
continue;
/* Get the filename corresponding to this FUNCTION_SAL, if we haven't
yet. */
if (!searched_for_fullname)
if (e->file_is_glob)
{
if (function_sal->symtab != NULL)
fullname = symtab_to_fullname (function_sal->symtab);
searched_for_fullname = 1;
if (skip_gfile_p (e, function_sal))
skip_by_file = 1;
}
if (fullname != NULL
&& compare_filenames_for_search (fullname, e->filename))
else
{
if (skip_file_p (e, function_sal))
skip_by_file = 1;
}
}
if (e->function != NULL)
{
if (e->function_is_regexp)
{
if (skip_rfunction_p (e, function_name))
skip_by_function = 1;
}
else
{
if (skip_function_p (e, function_name))
skip_by_function = 1;
}
}
/* If both file and function must match, make sure we don't errantly
exit if only one of them match. */
if (e->file != NULL && e->function != NULL)
{
if (skip_by_file && skip_by_function)
return 1;
}
/* Only one of file/function is specified. */
else if (skip_by_file || skip_by_function)
return 1;
}
return 0;
@ -396,22 +684,31 @@ _initialize_step_skip (void)
skiplist_entry_chain = 0;
skiplist_entry_count = 0;
add_prefix_cmd ("skip", class_breakpoint, skip_function_command, _("\
add_prefix_cmd ("skip", class_breakpoint, skip_command, _("\
Ignore a function while stepping.\n\
Usage: skip [FUNCTION NAME]\n\
If no function name is given, ignore the current function."),
\n\
Usage: skip [FUNCTION-NAME]\n\
skip [<file-spec>] [<function-spec>]\n\
If no arguments are given, ignore the current function.\n\
\n\
<file-spec> is one of:\n\
-fi|-file FILE-NAME\n\
-gfi|-gfile GLOB-FILE-PATTERN\n\
<function-spec> is one of:\n\
-fu|-function FUNCTION-NAME\n\
-rfu|-rfunction FUNCTION-NAME-REGULAR-EXPRESSION"),
&skiplist, "skip ", 1, &cmdlist);
c = add_cmd ("file", class_breakpoint, skip_file_command, _("\
Ignore a file while stepping.\n\
Usage: skip file [FILENAME]\n\
Usage: skip file [FILE-NAME]\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\
Usage: skip function [FUNCTION-NAME]\n\
If no function name is given, skip the current function."),
&skiplist);
set_cmd_completer (c, location_completer);

View File

@ -41,7 +41,7 @@
#include "p-lang.h"
#include "addrmap.h"
#include "cli/cli-utils.h"
#include "fnmatch.h"
#include "hashtab.h"
#include "gdb_obstack.h"
@ -342,6 +342,40 @@ compare_filenames_for_search (const char *filename, const char *search_name)
&& STRIP_DRIVE_SPEC (filename) == &filename[len - search_len]));
}
/* Same as compare_filenames_for_search, but for glob-style patterns.
Heads up on the order of the arguments. They match the order of
compare_filenames_for_search, but it's the opposite of the order of
arguments to gdb_filename_fnmatch. */
int
compare_glob_filenames_for_search (const char *filename,
const char *search_name)
{
/* We rely on the property of glob-style patterns with FNM_FILE_NAME that
all /s have to be explicitly specified. */
int file_path_elements = count_path_elements (filename);
int search_path_elements = count_path_elements (search_name);
if (search_path_elements > file_path_elements)
return 0;
if (IS_ABSOLUTE_PATH (search_name))
{
return (search_path_elements == file_path_elements
&& gdb_filename_fnmatch (search_name, filename,
FNM_FILE_NAME | FNM_NOESCAPE) == 0);
}
{
const char *file_to_compare
= strip_leading_path_elements (filename,
file_path_elements - search_path_elements);
return gdb_filename_fnmatch (search_name, file_to_compare,
FNM_FILE_NAME | FNM_NOESCAPE) == 0;
}
}
/* Check for a symtab of a specific name by searching some symtabs.
This is a helper function for callbacks of iterate_over_symtabs.

View File

@ -1600,6 +1600,9 @@ extern int basenames_may_differ;
int compare_filenames_for_search (const char *filename,
const char *search_name);
int compare_glob_filenames_for_search (const char *filename,
const char *search_name);
int iterate_over_some_symtabs (const char *name,
const char *real_path,
int (*callback) (struct symtab *symtab,

View File

@ -1,3 +1,16 @@
2016-02-23 Doug Evans <dje@google.com>
* gdb.base/skip.c (test_skip): New function.
(end_test_skip_file_and_function): New function.
(test_skip_file_and_function): New function.
* gdb.base/skip1.c (test_skip): New function.
(skip1_test_skip_file_and_function): New function.
* gdb.base/skip.exp: Add tests for new skip options.
* gdb.base/skip-solib.exp: Update expected output.
* gdb.perf/skip-command.cc: New file.
* gdb.perf/skip-command.exp: New file.
* gdb.perf/skip-command.py: New file.
2016-02-22 Marcin Kościelnicki <koriakin@0x04.net>
* gdb.trace/unavailable.exp (gdb_unavailable_registers_test_1): Fix

View File

@ -73,8 +73,8 @@ Ignore file pending future shared library load.*" \
# Checkinfo skip list.
#
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
1\\s+file\\s+y\\s+${srcfile_lib}\\s*" \
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
1\\s+y\\s+n\\s+${srcfile_lib}\\s+n\\s+<none>\\s*" \
"info skip with pending file"
if ![runto_main] { fail "skip tests suppressed" }
@ -108,8 +108,8 @@ gdb_test "step" "square.*"
# Now our entry should no longer be pending.
#
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
1\\s+function\\s+y\\s+multiply\\s*" \
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
1\\s+y\\s+n\\s+<none>\\s+n\\s+multiply\\s*" \
"info skip for function multiply"
#

View File

@ -20,6 +20,7 @@
int foo (void);
int bar (void);
int baz (int);
void skip1_test_skip_file_and_function (void);
int
main ()
@ -33,3 +34,22 @@ foo ()
{
return 0;
}
static void
test_skip (void)
{
}
static void
end_test_skip_file_and_function (void)
{
abort ();
}
void
test_skip_file_and_function (void)
{
test_skip ();
skip1_test_skip_file_and_function ();
end_test_skip_file_and_function ();
}

View File

@ -14,6 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This file was written by Justin Lebar. (justin.lebar@gmail.com)
# And further hacked on by Doug Evans. (dje@google.com)
if { [prepare_for_testing skip.exp "skip" \
{skip.c skip1.c } \
@ -30,7 +31,24 @@ gdb_test "skip file" "No default file now." "skip file (no default file)"
gdb_test "skip function" "No default function now."
gdb_test "skip" "No default function now." "skip (no default function)"
if ![runto_main] { fail "skip tests suppressed" }
# Test elided args.
gdb_test "skip -fi" "Missing value for -fi option."
gdb_test "skip -file" "Missing value for -file option."
gdb_test "skip -fu" "Missing value for -fu option."
gdb_test "skip -function" "Missing value for -function option."
gdb_test "skip -rfu" "Missing value for -rfu option."
gdb_test "skip -rfunction" "Missing value for -rfunction option."
# Test other invalid option combinations.
gdb_test "skip -x" "Invalid skip option: -x"
gdb_test "skip -rfu foo.* xyzzy" "Invalid argument: xyzzy"
if ![runto_main] {
fail "Can't run to main"
return
}
# Test |info skip| with an empty skiplist.
@ -62,34 +80,39 @@ 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+What\\s*
1\\s+file\\s+y\\s+.*$srcfile\\s*
2\\s+function\\s+y\\s+main\\s*
3\\s+file\\s+y\\s+$srcfile1\\s*
4\\s+function\\s+y\\s+baz\\s*"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
1\\s+y\\s+n\\s+.*$srcfile\\s+n\\s+<none>\\s*
2\\s+y\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*
4\\s+y\\s+n\\s+<none>\\s+n\\s+baz\\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" }
if ![runto_main] {
fail "Can't run to main"
return
}
gdb_test "step" ".*" "step in the main"
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().
# into foo(), and our second step should take us to the next line in main().
gdb_test "skip delete 1"
# Check that entry 1 is missing from |info skip|
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
2\\s+function\\s+y\\s+main\\s*
3\\s+file\\s+y\\s+$srcfile1\\s*
4\\s+function\\s+y\\s+baz\\s*" \
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
2\\s+y\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*
4\\s+y\\s+n\\s+<none>\\s+n\\s+baz\\s*" \
"info skip (delete 1)"
if ![runto_main] { fail "skip tests suppressed" }
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step after deleting 1"
gdb_test "step" "foo \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)" ; # Return from foo()
@ -100,10 +123,14 @@ gdb_test "step" "main \\(\\) at.*" "$test (3)"
gdb_test "skip disable 3"
# Is entry 3 disabled in |info skip|?
gdb_test "info skip 3" ".*\\n3\\s+file\\s+n.*" \
"info skip shows entry as disabled"
gdb_test "info skip 3" \
"3\\s+n\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*" \
"info skip shows entry as disabled"
if ![runto_main] { fail "skip tests suppressed" }
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step after disabling 3"
gdb_test "step" "bar \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)"; # Return from foo()
@ -115,9 +142,13 @@ gdb_test "step" "main \\(\\) at.*" "$test (5)"
gdb_test "skip enable 3"
# 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 "info skip 3" \
"3\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*" \
"info skip shows entry as enabled"
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step after enable 3"
gdb_test "step" "foo \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)"; # Return from foo()
@ -125,47 +156,129 @@ gdb_test "step" "main \\(\\) at.*" "$test (3)"
gdb_test "skip disable"
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
2\\s+function\\s+n\\s+main\\s*
3\\s+file\\s+n\\s+$srcfile1\\s*
4\\s+function\\s+n\\s+baz\\s*" \
"info skip after disabling all"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
2\\s+n\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+n\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*
4\\s+n\\s+n\\s+<none>\\s+n\\s+baz\\s*" \
"info skip after disabling all"
gdb_test "skip enable"
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
2\\s+function\\s+y\\s+main\\s*
3\\s+file\\s+y\\s+$srcfile1\\s*
4\\s+function\\s+y\\s+baz\\s*" \
"info skip after enabling all"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
2\\s+y\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*
4\\s+y\\s+n\\s+<none>\\s+n\\s+baz\\s*" \
"info skip after enabling all"
gdb_test "skip disable 4 2-3"
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
2\\s+function\\s+n\\s+main\\s*
3\\s+file\\s+n\\s+$srcfile1\\s*
4\\s+function\\s+n\\s+baz\\s*" \
"info skip after disabling 4 2-3"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
2\\s+n\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+n\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*
4\\s+n\\s+n\\s+<none>\\s+n\\s+baz\\s*" \
"info skip after disabling 4 2-3"
gdb_test "skip enable 2-3"
gdb_test "info skip" \
"Num\\s+Type\\s+Enb\\s+What\\s*
2\\s+function\\s+y\\s+main\\s*
3\\s+file\\s+y\\s+$srcfile1\\s*
4\\s+function\\s+n\\s+baz\\s*" \
"info skip after enabling 2-3"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
2\\s+y\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*
4\\s+n\\s+n\\s+<none>\\s+n\\s+baz\\s*" \
"info skip after enabling 2-3"
gdb_test "info skip 2-3" \
"Num\\s+Type\\s+Enb\\s+What\\s*
2\\s+function\\s+y\\s+main\\s*
3\\s+file\\s+y\\s+$srcfile1\\s*" \
"info skip 2-3"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
2\\s+y\\s+n\\s+<none>\\s+n\\s+main\\s*
3\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>\\s*" \
"info skip 2-3"
gdb_test "skip delete 2 3"
gdb_test "info skip" \
"4\\s+function\\s+n\\s+baz\\s*" \
"info skip after deleting 2 3"
"Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function\\s*
4\\s+n\\s+n\\s+<none>\\s+n\\s+baz\\s*" \
"info skip after deleting 2 3"
gdb_test "skip delete"
gdb_test "info skip" "Not skipping any files or functions\." \
"info skip after deleting all"
"info skip after deleting all"
# Now test skip -fi, etc.
# Create a skiplist entry for a specified file and function.
gdb_test "skip -fi skip1.c" "File .*$srcfile1 will be skipped when stepping\."
gdb_test "skip -gfi sk*1.c" "File\\(s\\) sk\\*1.c will be skipped when stepping\."
gdb_test "skip -fu baz" "Function baz will be skipped when stepping\."
gdb_test "skip -rfu ^b.z$" "Function\\(s\\) \\^b\\.z\\$ will be skipped when stepping."
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step using -fi"
gdb_test_no_output "skip disable"
gdb_test_no_output "skip enable 5"
gdb_test "step" "foo \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)"; # Return from foo()
gdb_test "step" "main \\(\\) at.*" "$test (3)"
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step using -gfi"
gdb_test_no_output "skip disable"
gdb_test_no_output "skip enable 6"
gdb_test "step" "foo \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)"; # Return from foo()
gdb_test "step" "main \\(\\) at.*" "$test (3)"
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step using -fu for baz"
gdb_test_no_output "skip disable"
gdb_test_no_output "skip enable 7"
gdb_test "step" "bar \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)"; # Return from bar()
gdb_test "step" "foo \\(\\) at.*" "$test (3)"
gdb_test "step" ".*" "$test (4)"; # Return from foo()
gdb_test "step" "main \\(\\) at.*" "$test (5)"
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step using -rfu for baz"
gdb_test_no_output "skip disable"
gdb_test_no_output "skip enable 8"
gdb_test "step" "bar \\(\\) at.*" "$test (1)"
gdb_test "step" ".*" "$test (2)"; # Return from bar()
gdb_test "step" "foo \\(\\) at.*" "$test (3)"
gdb_test "step" ".*" "$test (4)"; # Return from foo()
gdb_test "step" "main \\(\\) at.*" "$test (5)"
# Test -fi + -fu.
if ![runto_main] {
fail "Can't run to main"
return
}
set test "step using -fi + -fu"
gdb_test_no_output "skip delete"
gdb_test "skip -fi skip1.c -fu test_skip" \
"Function test_skip in file skip1.c will be skipped when stepping\."
gdb_breakpoint "test_skip_file_and_function"
gdb_breakpoint "end_test_skip_file_and_function"
gdb_test "call test_skip_file_and_function ()" "silently stop."
# Verify we can step into skip.c:test_skip but not skip1.c:test_skip.
gdb_test "step" "test_skip \\(\\) at.*" "$test (1)"
gdb_test "step" "test_skip_file_and_function \\(\\) at.*" "$test (2)"; # Return from test_skip()
gdb_test "step" "skip1_test_skip_file_and_function \\(\\) at.*" "$test (4)"
gdb_test "step" ".*" "$test (5)"; # Skip over test_skip()
gdb_test "step" "test_skip_file_and_function \\(\\) at.*" "$test (6)"; # Return from skip1_test_skip_file_and_function()

View File

@ -26,3 +26,14 @@ baz (int a)
{
return a + 1;
}
static void
test_skip (void)
{
}
void
skip1_test_skip_file_and_function (void)
{
test_skip ();
}

View File

@ -0,0 +1,46 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright (C) 2016 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/>. */
volatile int flag;
int
func ()
{
return 42;
}
class c
{
public:
int _x;
c () : _x (42) {}
};
void
call_me (int x, c y)
{
}
int
main ()
{
while (flag)
{
call_me (func (), c ());
}
return 0;
}

View File

@ -0,0 +1,138 @@
# Copyright (C) 2016 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 test case is to test the speed of GDB when it is single-stepping
# with skip directives active. There's no need to test skip directives that
# match functions we're stepping through. That's not the interesting case.
# The interesting case is where there are 100s or more classes or libraries,
# each providing their own set of skip directives.
#
# Parameters:
# SKIP_STEP_COUNT: the number of single steps GDB performs
# SKIP_DIRECTIVE_COUNT: the number of skip directives to create
load_lib perftest.exp
if [skip_perf_tests] {
return 0
}
standard_testfile .cc skip-funcs.cc
set executable $testfile
set skip_func_file [standard_output_file $srcfile2]
set expfile $testfile.exp
# make check-perf RUNTESTFLAGS='skip-command.exp SKIP_STEP_COUNT=1000 ...'
if ![info exists SKIP_STEP_COUNT] {
set SKIP_STEP_COUNT 1000
}
if ![info exists SKIP_DIRECTIVE_COUNT] {
set SKIP_DIRECTIVE_COUNT 1000
}
proc delete_all_skips { } {
# FIXME: skip currently doesn't ask for confirmation
# FIXME: "skip delete" with no skips ->
# "No skiplist entries found with number (null)."
gdb_test_no_output "set confirm off"
gdb_test "skip delete" ""
gdb_test_no_output "set confirm on"
}
proc install_skips { kind text nr_skips } {
global gdb_prompt
set test "install_skips"
delete_all_skips
switch $kind {
"function" { set skip_arg "-function" }
"regexp" { set skip_arg "-rfunction" }
default {
perror "bad skip kind: $kind"
return
}
}
for { set i 0 } { $i < $nr_skips } { incr i } {
gdb_test "skip $skip_arg [format $text $i]" ""
}
# There could be 1000's of these, which can overflow the buffer.
# However, it's good to have this in the log, so we go to the effort
# to read it all in.
gdb_test_multiple "info skip" $test {
-re "\[^\r\n\]*\r\n" { exp_continue }
-re "\[\r\n\]*$gdb_prompt $" {
pass $test
}
timeout {
fail "$test (timeout)"
}
}
}
proc write_skip_func_source { file_name func_name_prefix nr_funcs } {
set f [open $file_name "w"]
puts $f "// DO NOT EDIT, machine generated file. See skip-command.exp."
for { set i 0 } { $i < $nr_funcs } { incr i } {
set func_name [format "${func_name_prefix}_%02d" $i]
puts $f "int $func_name () { return 0; }"
}
close $f
}
proc run_skip_bench { kind text } {
global SKIP_STEP_COUNT SKIP_DIRECTIVE_COUNT
if ![runto_main] {
fail "Can't run to main"
return -1
}
gdb_test_no_output "set variable flag = 1"
for { set i 0 } { $i < 5 } { incr i } {
set nr_skips [expr $i * $SKIP_DIRECTIVE_COUNT]
install_skips $kind $text $nr_skips
gdb_test_no_output "python SkipCommand\(\"skip-$kind-$nr_skips\", ${SKIP_STEP_COUNT}\).run()"
}
gdb_test "set variable flag = 0"
}
PerfTest::assemble {
global srcdir subdir srcfile binfile skip_func_file
global SKIP_DIRECTIVE_COUNT
write_skip_func_source $skip_func_file "skip_func" [expr 4 * $SKIP_DIRECTIVE_COUNT]
if { [gdb_compile [list "$srcdir/$subdir/$srcfile" $skip_func_file] ${binfile} executable {c++ debug}] != "" } {
return -1
}
return 0
} {
global binfile
clean_restart $binfile
return 0
} {
global SKIP_STEP_COUNT SKIP_DIRECTIVE_COUNT
with_test_prefix "time_skip_func" {
# N.B. The function name must match the ones in skip-command.cc.
run_skip_bench "function" "skip_func_%02d"
}
with_test_prefix "time_skip_constructor" {
run_skip_bench "regexp" "^(skip_class_%02d)::\\1 *\\("
}
return 0
}

View File

@ -0,0 +1,34 @@
# Copyright (C) 2016 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/>.
from perftest import perftest
class SkipCommand (perftest.TestCaseWithBasicMeasurements):
def __init__(self, name, step):
super (SkipCommand, self).__init__ (name)
self.step = step
def warm_up(self):
for _ in range(0, 10):
gdb.execute("step", False, True)
def _run(self, r):
for _ in range(0, r):
gdb.execute("step", False, True)
def execute_test(self):
for i in range(1, 5):
func = lambda: self._run(i * self.step)
self.measure.measure(func, i * self.step)

View File

@ -3380,6 +3380,83 @@ gdb_filename_fnmatch (const char *pattern, const char *string, int flags)
return fnmatch (pattern, string, flags);
}
/* Return the number of path elements in PATH.
/ = 1
/foo = 2
/foo/ = 2
foo/bar = 2
foo/ = 1 */
int
count_path_elements (const char *path)
{
int count = 0;
const char *p = path;
if (HAS_DRIVE_SPEC (p))
{
p = STRIP_DRIVE_SPEC (p);
++count;
}
while (*p != '\0')
{
if (IS_DIR_SEPARATOR (*p))
++count;
++p;
}
/* Backup one if last character is /, unless it's the only one. */
if (p > path + 1 && IS_DIR_SEPARATOR (p[-1]))
--count;
/* Add one for the file name, if present. */
if (p > path && !IS_DIR_SEPARATOR (p[-1]))
++count;
return count;
}
/* Remove N leading path elements from PATH.
N must be non-negative.
If PATH has more than N path elements then return NULL.
If PATH has exactly N path elements then return "".
See count_path_elements for a description of how we do the counting. */
const char *
strip_leading_path_elements (const char *path, int n)
{
int i = 0;
const char *p = path;
gdb_assert (n >= 0);
if (n == 0)
return p;
if (HAS_DRIVE_SPEC (p))
{
p = STRIP_DRIVE_SPEC (p);
++i;
}
while (i < n)
{
while (*p != '\0' && !IS_DIR_SEPARATOR (*p))
++p;
if (*p == '\0')
{
if (i + 1 == n)
return "";
return NULL;
}
++p;
++i;
}
return p;
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_utils;

View File

@ -135,6 +135,10 @@ extern void substitute_path_component (char **stringp, const char *from,
const char *to);
char *ldirname (const char *filename);
extern int count_path_elements (const char *path);
extern const char *strip_leading_path_elements (const char *path, int n);
/* GDB output, ui_file utilities. */