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


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

Re: [PATCH, doc RFA] Add "skip regexp"


Eli Zaretskii writes:
 > > Date: Tue, 02 Feb 2016 01:03:19 +0000
 > > From: Doug Evans <dje@google.com>
 > >
 > > With this patch one can specify the skip as:
 > >
 > > skip regexp ^std::(allocator|basic_string)<.*>::~?\1 *\(
 >
 > Thanks.
 >
 > > 2016-02-01  Doug Evans  <dje@google.com>
 > >
 > > 	New command "skip regexp regular-expression".
 > > 	* NEWS: Document the new feature.
 > > 	* skip.c (skip_kind): New enum.
 > > 	(skiplist_entry) <filename,function_name>: Delete.
 > > 	<kind,text,regex,regex_valid>: New members.
 > > 	(skiplist_entry_kind_name): New function.
 > > 	(make_skip_file, make_skip_function, make_skip_regexp): New function.
 > > 	(free_skiplist_entry, free_skiplist_entry_cleanup): New functions.
 > > 	(make_free_skiplist_entry_cleanup): New function.
 > > 	(skip_file_command): Update.
 > > 	(skip_function): Update.
 > > 	(compile_skip_regexp, skip_regexp_command): New functions.
 > > 	(skip_info): Update.
 > > 	(sal_and_fullname): New struct.
 > > 	(skip_file_p, skip_function_p, skip_regexp_p): New functions.
 > > 	(function_name_is_marked_for_skip): Update and simplify.
 > > 	(_initialize_step_skip): Add "skip regexp" command.
 > >
 > > 	doc/
 > > 	* gdb.texinfo (Skipping Over Functions and Files): Document
 > > 	"skip regexp".
 >
 > The documentation parts are approved, with the following nit:
 >
 > > +Functions may be skipped by providing either a function name, linespec
 > > +(@pxref{Specify Location}), file name, or regular expression of the
 > > +function's name.                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 >    ^^^^^^^^^^^^^^^
 > "regular expression that matches the function's name" is more accurate
 > (and you also use it elsewhere in the patch).
 >
 > Otherwise, fine with me, thanks.

Thanks.

I included an older version of the perf testcase in my previous email.
This is an updated patch.

2016-02-02  Doug Evans  <dje@google.com>

	New command "skip regexp regular-expression".
	* NEWS: Document the new feature.
	* skip.c (skip_kind): New enum.
	(skiplist_entry) <filename,function_name>: Delete.
	<kind,text,regex,regex_valid>: New members.
	(skiplist_entry_kind_name): New function.
	(make_skip_file, make_skip_function, make_skip_regexp): New function.
	(free_skiplist_entry, free_skiplist_entry_cleanup): New functions.
	(make_free_skiplist_entry_cleanup): New function.
	(skip_file_command): Update.
	(skip_function): Update.
	(compile_skip_regexp, skip_regexp_command): New functions.
	(skip_info): Update.
	(sal_and_fullname): New struct.
	(skip_file_p, skip_function_p, skip_regexp_p): New functions.
	(function_name_is_marked_for_skip): Update and simplify.
	(_initialize_step_skip): Add "skip regexp" command.

	doc/
	* gdb.texinfo (Skipping Over Functions and Files): Document
	"skip regexp".

	testsuite/
	* gdb.base/skip.exp: Add tests for "skip regexp".
	* gdb.perf/skip-command.cc: New file.
	* gdb.perf/skip-command.exp: New file.
	* gdb.perf/skip-command.py: New file.

diff --git a/gdb/NEWS b/gdb/NEWS
index 962eae4..388daaa 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -125,6 +125,10 @@ show max-value-size
   allocate for value contents.  Prevents incorrect programs from
   causing GDB to allocate overly large buffers.  Default is 64k.

+skip regexp regular-expression
+  A variation of "skip function" where the function name is specified
+  as a regular expression.
+
 * 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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2d09d13..f249e3a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -5555,8 +5555,9 @@ 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}), file name, or regular expression that matches
+the function's name.

 @table @code
 @kindex skip function
@@ -5577,8 +5578,42 @@ 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.
+
+@kindex skip regexp
+@item skip regexp @var{regular-expression}
+After running this command, any function whose name matches
+@var{regular-expression} 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++ std::string
+constructors or destructors.  Plus with C++ 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.
+
+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.
+
+@smallexample
+(gdb) skip regexp ^std::(allocator|basic_string)<.*>::~?\1 *\(
+@end smallexample
+
+If you wanted to skip every templated C++ constructor and destructor
+in the @code{std} namespace you could do:
+
+@smallexample
+(gdb) skip regexp ^std::([a-zA-z0-9_]+)<.*>::~?\1 *\(
+@end smallexample
 @end table

 Skips can be listed, deleted, disabled, and enabled, much like breakpoints.
@@ -5595,7 +5630,7 @@ print a table with details about all functions and files marked for skipping.
 @item Identifier
 A number identifying this skip.
 @item Type
-The type of this skip, either @samp{function} or @samp{file}.
+The type of this skip, either @samp{function}, @samp{file} or @samp{regexp}.
 @item Enabled or Disabled
Enabled skips are marked with @samp{y}. Disabled skips are marked with @samp{n}.
 @item Address
diff --git a/gdb/skip.c b/gdb/skip.c
index d90910d..31e240c 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -32,19 +32,31 @@
 #include "breakpoint.h" /* for get_sal_arch () */
 #include "source.h"
 #include "filenames.h"
+#include "gdb_regex.h"
+
+enum skip_kind
+{
+  SKIP_FILE,
+  SKIP_FUNCTION,
+  SKIP_REGEXP
+};

 struct skiplist_entry
 {
   int number;

-  /* NULL if this isn't a skiplist entry for an entire file.
+  enum skip_kind kind;
+
+  /* The text provided by the user.
      The skiplist entry owns this pointer.  */
-  char *filename;
+  char *text;

-  /* The name of the marked-for-skip function, if this is a skiplist
-     entry for a function.
+  /* If this is a regexp, the compiled form.
      The skiplist entry owns this pointer.  */
-  char *function_name;
+  regex_t regex;
+
+  /* Non-zero if regex has been compiled.  */
+  int regex_valid;

   int enabled;

@@ -65,10 +77,101 @@ static int skiplist_entry_count;
        E ? (TMP = E->next, 1) : 0;       \
        E = TMP)

+/* Return the name of the skiplist entry kind.  */
+
+static const char *
+skiplist_entry_kind_name (struct skiplist_entry *e)
+{
+  switch (e->kind)
+    {
+    case SKIP_FILE: return "file";
+    case SKIP_FUNCTION: return "function";
+    case SKIP_REGEXP: return "regexp";
+    default:
+      gdb_assert_not_reached ("bad skiplist_entry kind");
+    }
+}
+
+/* Create a SKIP_FILE object. */
+
+static struct skiplist_entry *
+make_skip_file (const char *name)
+{
+  struct skiplist_entry *e = XCNEW (struct skiplist_entry);
+
+  e->kind = SKIP_FILE;
+  e->text = xstrdup (name);
+  e->enabled = 1;
+
+  return e;
+}
+
+/* Create a SKIP_FUNCTION object. */
+
+static struct skiplist_entry *
+make_skip_function (const char *name)
+{
+  struct skiplist_entry *e = XCNEW (struct skiplist_entry);
+
+  e->kind = SKIP_FUNCTION;
+  e->enabled = 1;
+  e->text = xstrdup (name);
+
+  return e;
+}
+
+/* Create a SKIP_REGEXP object.
+   The regexp is not parsed, the caller must do that afterwards.  */
+
+static struct skiplist_entry *
+make_skip_regexp (const char *regexp)
+{
+  struct skiplist_entry *e = XCNEW (struct skiplist_entry);
+
+  e->kind = SKIP_REGEXP;
+  e->enabled = 1;
+  e->text = xstrdup (regexp);
+
+  return e;
+}
+
+/* Free a skiplist entry.  */
+
+static void
+free_skiplist_entry (struct skiplist_entry *e)
+{
+  xfree (e->text);
+  switch (e->kind)
+    {
+    case SKIP_REGEXP:
+      if (e->regex_valid)
+	regfree (&e->regex);
+      break;
+    default:
+      break;
+    }
+  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;

@@ -99,15 +202,22 @@ Ignore file pending future shared library load? ")))
       filename = arg;
     }

-  e = XCNEW (struct skiplist_entry);
-  e->filename = xstrdup (filename);
-  e->enabled = 1;
-
-  add_skiplist_entry (e);
+  add_skiplist_entry (make_skip_file (filename));

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_function (name));
+
+ printf_filtered (_("Function %s will be skipped when stepping.\n"), name);
+}
+
 static void
 skip_function_command (char *arg, int from_tty)
 {
@@ -149,6 +259,54 @@ Ignore function pending future shared library load? ")))
     }
 }

+/* 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->kind == SKIP_REGEXP);
+
+  code = regcomp (&e->regex, e->text, flags);
+  if (code != 0)
+    {
+      char *err = get_regcomp_error (code, &e->regex);
+
+      make_cleanup (xfree, err);
+      error (("%s: %s"), message, err);
+    }
+  e->regex_valid = 1;
+}
+
+static void
+skip_regexp_command (char *arg, int from_tty)
+{
+  struct skiplist_entry *e;
+  struct cleanup *cleanups;
+
+  /* If no argument was given, try to default to the last
+     displayed codepoint.  */
+  if (arg == NULL)
+    error (_("Missing regexp."));
+
+  e = make_skip_regexp (arg);
+  cleanups = make_free_skiplist_entry_cleanup (e);
+  compile_skip_regexp (e, _("regexp"));
+  discard_cleanups (cleanups);
+  add_skiplist_entry (e);
+
+  printf_filtered (_("Functions matching regexp %s will be skipped"
+		     " when stepping.\n"), arg);
+}
+
 static void
 skip_info (char *arg, int from_tty)
 {
@@ -199,23 +357,15 @@ Not skipping any files or functions.\n"));
 							 "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_string (current_uiout, "type",
+			   skiplist_entry_kind_name (e));                /* 2 */

       if (e->enabled)
 	ui_out_field_string (current_uiout, "enabled", "y");             /* 3 */
       else
 	ui_out_field_string (current_uiout, "enabled", "n");             /* 3 */

-      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 */
+ ui_out_field_string (current_uiout, "what", e->text); /* 4 */

       ui_out_text (current_uiout, "\n");
       do_cleanups (entry_chain);
@@ -273,9 +423,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 +435,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 +458,73 @@ add_skiplist_entry (struct skiplist_entry *e)
     }
 }

+/* The file-based location where we're stopped.
+   This simplifies calling skip_file_p because we only want to call
+   symtab_to_fullname once.  */
+
+struct sal_and_fullname
+{
+  const struct symtab_and_line *function_sal;
+  int searched_for_fullname;
+  const char *fullname;
+};
+
+/* Return non-zero if we're stopped at a file to be skipped.  */
+
+static int
+skip_file_p (struct skiplist_entry *e, struct sal_and_fullname *file_location)
+{
+  const struct symtab_and_line *function_sal = file_location->function_sal;
+
+  gdb_assert (e->kind == SKIP_FILE);
+
+  /* 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->text))
+    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->text)) != 0))
+    return 0;
+
+  /* Get the filename corresponding to this FUNCTION_SAL, if we haven't
+     yet.  */
+  if (!file_location->searched_for_fullname)
+    {
+      if (function_sal->symtab != NULL)
+	file_location->fullname = symtab_to_fullname (function_sal->symtab);
+      file_location->searched_for_fullname = 1;
+    }
+  if (file_location->fullname != NULL
+      && compare_filenames_for_search (file_location->fullname, e->text))
+    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->kind == SKIP_FUNCTION);
+  return strcmp_iw (function_name, e->text) == 0;
+}
+
+/* Return non-zero if we're stopped at a function regexp to be skipped.  */
+
+static int
+skip_regexp_p (struct skiplist_entry *e, const char *function_name)
+{
+  gdb_assert (e->kind == SKIP_REGEXP);
+  return regexec (&e->regex, function_name, 0, NULL, 0) == 0;
+}

 /* See skip.h.  */

@@ -333,8 +532,7 @@ 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 sal_and_fullname file_location = { function_sal, 0, NULL };
   struct skiplist_entry *e;

   if (function_name == NULL)
@@ -345,39 +543,22 @@ function_name_is_marked_for_skip (const char *function_name,
       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)
+      switch (e->kind)
 	{
-	  /* 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))
+	case SKIP_FILE:
+	  if (skip_file_p (e, &file_location))
 	    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 (function_sal->symtab != NULL)
-		fullname = symtab_to_fullname (function_sal->symtab);
-	      searched_for_fullname = 1;
-	    }
-	  if (fullname != NULL
-	      && compare_filenames_for_search (fullname, e->filename))
+	  break;
+	case SKIP_FUNCTION:
+	  if (skip_function_p (e, function_name))
 	    return 1;
+	  break;
+	case SKIP_REGEXP:
+	  if (skip_regexp_p (e, function_name))
+	    return 1;
+	  break;
+	default:
+	  gdb_assert_not_reached ("bad skiplist_entry kind");
 	}
     }

@@ -416,6 +597,12 @@ If no function name is given, skip the current function."),
 	       &skiplist);
   set_cmd_completer (c, location_completer);

+  c = add_cmd ("regexp", class_breakpoint,
+	       skip_regexp_command, _("\
+Ignore a function while stepping.\n\
+Usage: skip regexp [FUNCTION-NAME-REGEXP]."),
+	       &skiplist);
+
   add_cmd ("enable", class_breakpoint, skip_enable_command, _("\
 Enable skip entries.  You can specify numbers (e.g. \"skip enable 1 3\"), \
ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\ diff --git a/gdb/testsuite/gdb.base/skip.exp b/gdb/testsuite/gdb.base/skip.exp
index 9fa4acf..cb88829 100644
--- a/gdb/testsuite/gdb.base/skip.exp
+++ b/gdb/testsuite/gdb.base/skip.exp
@@ -31,6 +31,11 @@ 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)"

+#
+# Regexps don't have a default, but we can still test an elided arg.
+#
+gdb_test "skip regexp" "Missing regexp."
+
 if ![runto_main] { fail "skip tests suppressed" }

 #
@@ -51,6 +56,12 @@ gdb_test "skip file skip1.c" "File .*$srcfile1 will be skipped when stepping\."
 gdb_test "skip function baz" "Function baz will be skipped when stepping\."

 #
+# Create a regexp of skipping baz, disabled until we need it so as to not
+# interfere with "skip function baz"
+gdb_test "skip regexp ^b.z$" "Functions matching regexp \\^b\\.z\\$ will be skipped when stepping."
+gdb_test "skip disable 5"
+
+#
 # Test bad skiplist entry modification commands
 #
 gdb_test "skip enable 999" "No skiplist entries found with number 999."
@@ -73,7 +84,8 @@ gdb_test "info skip" \
 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*"
+4\\s+function\\s+y\\s+baz\\s*
+5\\s+regexp\\s+n\\s+\\^b\\.z\\$\\s*"

 #
 # Right now, we have an outstanding skiplist entry on both source
@@ -96,7 +108,8 @@ 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*" \
+4\\s+function\\s+y\\s+baz\\s*
+5\\s+regexp\\s+n\\s+\\^b\\.z\\$\\s*" \
     "info skip (delete 1)"

 if ![runto_main] { fail "skip tests suppressed" }
@@ -123,6 +136,22 @@ gdb_test "step" ".*" "$test (4)"; # Return from bar()
 gdb_test "step" "main \\(\\) at.*" "$test (5)"

 #
+# Repeat, but replace "skip function baz" (#4) with its regexp (#5).
+#
+gdb_test "skip disable 4"
+gdb_test "skip enable 5"
+if ![runto_main] { fail "skip tests suppressed" }
+set test "step using regexp for baz"
+gdb_test "step" "bar \\(\\) at.*" "$test (1)"
+gdb_test "step" ".*" "$test (2)"; # Return from foo()
+gdb_test "step" "foo \\(\\) at.*" "$test (3)"
+gdb_test "step" ".*" "$test (4)"; # Return from bar()
+gdb_test "step" "main \\(\\) at.*" "$test (5)"
+# Restore.
+gdb_test "skip enable 4"
+gdb_test "skip disable 5"
+
+#
 # Enable skiplist entry 3 and make sure we step over it like before.
 #
 gdb_test "skip enable 3"
@@ -140,7 +169,8 @@ 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*" \
+4\\s+function\\s+n\\s+baz\\s*
+5\\s+regexp\\s+n\\s+\\^b\\.z\\$\\s*" \
   "info skip after disabling all"

 gdb_test "skip enable"
@@ -148,7 +178,8 @@ 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*" \
+4\\s+function\\s+y\\s+baz\\s*
+5\\s+regexp\\s+y\\s+\\^b\\.z\\$\\s*" \
   "info skip after enabling all"

 gdb_test "skip disable 4 2-3"
@@ -156,7 +187,8 @@ 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*" \
+4\\s+function\\s+n\\s+baz\\s*
+5\\s+regexp\\s+y\\s+\\^b\\.z\\$\\s*" \
   "info skip after disabling 4 2-3"

 gdb_test "skip enable 2-3"
@@ -164,7 +196,8 @@ 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*" \
+4\\s+function\\s+n\\s+baz\\s*
+5\\s+regexp\\s+y\\s+\\^b\\.z\\$\\s*" \
   "info skip after enabling 2-3"

 gdb_test "info skip 2-3" \
@@ -173,7 +206,7 @@ gdb_test "info skip 2-3" \
 3\\s+file\\s+y\\s+$srcfile1\\s*" \
   "info skip 2-3"

-gdb_test "skip delete 2 3"
+gdb_test "skip delete 2 3 5"
 gdb_test "info skip" \
   "4\\s+function\\s+n\\s+baz\\s*" \
   "info skip after deleting 2 3"
diff --git a/gdb/testsuite/gdb.perf/skip-command.cc b/gdb/testsuite/gdb.perf/skip-command.cc
new file mode 100644
index 0000000..5820ef7
--- /dev/null
+++ b/gdb/testsuite/gdb.perf/skip-command.cc
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.perf/skip-command.exp b/gdb/testsuite/gdb.perf/skip-command.exp
new file mode 100644
index 0000000..2a6fc81
--- /dev/null
+++ b/gdb/testsuite/gdb.perf/skip-command.exp
@@ -0,0 +1,130 @@
+# 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
+     for { set i 0 } { $i < $nr_skips } { incr i } {
+	gdb_test "skip $kind [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
+}
diff --git a/gdb/testsuite/gdb.perf/skip-command.py b/gdb/testsuite/gdb.perf/skip-command.py
new file mode 100644
index 0000000..12c28f2
--- /dev/null
+++ b/gdb/testsuite/gdb.perf/skip-command.py
@@ -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)


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