From patchwork Tue Feb 2 18:05:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 10701 Received: (qmail 57314 invoked by alias); 2 Feb 2016 18:05:40 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 57298 invoked by uid 89); 2 Feb 2016 18:05:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.5 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=eli, H*MI:sk:047d7b2, H*M:sk:047d7b2 X-HELO: mail-pa0-f74.google.com Received: from mail-pa0-f74.google.com (HELO mail-pa0-f74.google.com) (209.85.220.74) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 02 Feb 2016 18:05:36 +0000 Received: by mail-pa0-f74.google.com with SMTP id uo6so11945655pac.0 for ; Tue, 02 Feb 2016 10:05:35 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:message-id:date:subject:from:to :content-type; bh=268VgBhwKCZEe4ApFqgFqN9vH3hY4XflkjjUmrV/CB8=; b=GIaDG+SV+50VK/u3t/Mf8DxbT+ClZsHzZjhJexHQ4G8mXNT1qRBLhMxPDvnqdHsSLU gEo5hkhDDyaAuzJqW4pD/m1v/KNjr/LMPonqCxuV/a6O7LnJdcdqiWP0dOgbcJJz3SvL ibXAe/NVnSk7KC46p23+utpH/n/fhSFBpkNBLRxpkVPEUoUHddL2c/BkO3+VE7RC1myQ 3ZRW1myvLffEkGFW9HEXirFhZ/rK0+rBEL49PrhqMuA9+wYEBgfOK8j3HrIxA0n0j40i WvGufVf1qsp5tCQ/9O1St9/rW1ehEtoFsQVJEraHYYJ6O7o/bfq0rEmpEYoYt0b8mX64 q3Dw== X-Gm-Message-State: AG10YOQMxA03dS0BK5Nf5PORggSBySatwhvl5oUFuS1nLFN5qVoiY8+KS8VhnIsEhoYO5clXvw== MIME-Version: 1.0 X-Received: by 10.66.121.132 with SMTP id lk4mr31396297pab.7.1454436334173; Tue, 02 Feb 2016 10:05:34 -0800 (PST) Message-ID: <047d7b2e15110c831f052acd5987@google.com> Date: Tue, 02 Feb 2016 18:05:34 +0000 Subject: Re: [PATCH, doc RFA] Add "skip regexp" From: Doug Evans To: Eli Zaretskii , gdb-patches@sourceware.org X-IsSubscribed: yes Eli Zaretskii writes: > > Date: Tue, 02 Feb 2016 01:03:19 +0000 > > From: Doug Evans > > > > With this patch one can specify the skip as: > > > > skip regexp ^std::(allocator|basic_string)<.*>::~?\1 *\( > > Thanks. > > > 2016-02-01 Doug Evans > > > > New command "skip regexp regular-expression". > > * NEWS: Document the new feature. > > * skip.c (skip_kind): New enum. > > (skiplist_entry) : Delete. > > : 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 New command "skip regexp regular-expression". * NEWS: Document the new feature. * skip.c (skip_kind): New enum. (skiplist_entry) : Delete. : 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 . */ + +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 . + +# 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 . + +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)