X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fskip.c;h=419dd7a46821f4f7f34087956ed432e82322159a;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=fa0f0c9075289956516f51d4af02cfe4458f9b39;hpb=7fb048a2ee38bbc85ba0e96e2932cb0cb1f7381e;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/skip.c b/gdb/skip.c index fa0f0c9075..419dd7a468 100644 --- a/gdb/skip.c +++ b/gdb/skip.c @@ -1,6 +1,6 @@ /* Skipping uninteresting files and functions while stepping. - Copyright (C) 2011-2016 Free Software Foundation, Inc. + Copyright (C) 2011-2020 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 @@ -34,107 +34,139 @@ #include "filenames.h" #include "fnmatch.h" #include "gdb_regex.h" +#include "gdbsupport/gdb_optional.h" +#include +#include "cli/cli-style.h" -struct skiplist_entry -{ - int number; - - /* Non-zero if FILE is a glob-style pattern. - Otherewise it is the plain file name (possibly with directories). */ - int file_is_glob; +/* True if we want to print debug printouts related to file/function + skipping. */ +static bool debug_skip = false; - /* The name of the file or NULL. - The skiplist entry owns this pointer. */ - char *file; - - /* Non-zero if FUNCTION is a regexp. +class skiplist_entry +{ +public: + /* Create a skiplist_entry object and add it to the chain. */ + static void add_entry (bool file_is_glob, + std::string &&file, + bool function_is_regexp, + std::string &&function); + + /* Return true if the skip entry has a file or glob-style file + pattern that matches FUNCTION_SAL. */ + bool skip_file_p (const symtab_and_line &function_sal) const; + + /* Return true if the skip entry has a function or function regexp + that matches FUNCTION_NAME. */ + bool skip_function_p (const char *function_name) const; + + /* Getters. */ + int number () const { return m_number; }; + bool enabled () const { return m_enabled; }; + bool file_is_glob () const { return m_file_is_glob; } + const std::string &file () const { return m_file; } + const std::string &function () const { return m_function; } + bool function_is_regexp () const { return m_function_is_regexp; } + + /* Setters. */ + void enable () { m_enabled = true; }; + void disable () { m_enabled = false; }; + + /* Disable copy. */ + skiplist_entry (const skiplist_entry &) = delete; + void operator= (const skiplist_entry &) = delete; + +private: + /* Key that grants access to the constructor. */ + struct private_key {}; +public: + /* Public so we can construct with container::emplace_back. Since + it requires a private class key, it can't be called from outside. + Use the add_entry static factory method to construct instead. */ + skiplist_entry (bool file_is_glob, std::string &&file, + bool function_is_regexp, std::string &&function, + private_key); + +private: + /* Return true if we're stopped at a file to be skipped. */ + bool do_skip_file_p (const symtab_and_line &function_sal) const; + + /* Return true if we're stopped at a globbed file to be skipped. */ + bool do_skip_gfile_p (const symtab_and_line &function_sal) const; + +private: /* data */ + int m_number = -1; + + /* True if FILE is a glob-style pattern. + Otherwise it is the plain file name (possibly with directories). */ + bool m_file_is_glob; + + /* The name of the file or empty if no name. */ + std::string m_file; + + /* True if FUNCTION is a regexp. Otherwise it is a plain function name (possibly with arguments, for C++). */ - int function_is_regexp; + bool m_function_is_regexp; - /* The name of the function or NULL. - The skiplist entry owns this pointer. */ - char *function; + /* The name of the function or empty if no name. */ + std::string m_function; /* If this is a function regexp, the compiled form. */ - regex_t compiled_function_regexp; + gdb::optional m_compiled_function_regexp; - /* Non-zero if the function regexp has been compiled. */ - int compiled_function_regexp_is_valid; - - int enabled; - - struct skiplist_entry *next; + /* Enabled/disabled state. */ + bool m_enabled = true; }; -static void add_skiplist_entry (struct skiplist_entry *e); - -static struct skiplist_entry *skiplist_entry_chain; -static int skiplist_entry_count; - -#define ALL_SKIPLIST_ENTRIES(E) \ - for (E = skiplist_entry_chain; E; E = E->next) - -#define ALL_SKIPLIST_ENTRIES_SAFE(E,TMP) \ - for (E = skiplist_entry_chain; \ - E ? (TMP = E->next, 1) : 0; \ - E = TMP) - -/* 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) +static std::list skiplist_entries; +static int highest_skiplist_entry_num = 0; + +skiplist_entry::skiplist_entry (bool file_is_glob, + std::string &&file, + bool function_is_regexp, + std::string &&function, + private_key) + : m_file_is_glob (file_is_glob), + m_file (std::move (file)), + m_function_is_regexp (function_is_regexp), + m_function (std::move (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; + gdb_assert (!m_file.empty () || !m_function.empty ()); - return e; -} - -/* Free a skiplist entry. */ + if (m_file_is_glob) + gdb_assert (!m_file.empty ()); -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); -} + if (m_function_is_regexp) + { + gdb_assert (!m_function.empty ()); -/* Wrapper to free_skiplist_entry for use as a cleanup. */ + int flags = REG_NOSUB; +#ifdef REG_EXTENDED + flags |= REG_EXTENDED; +#endif -static void -free_skiplist_entry_cleanup (void *e) -{ - free_skiplist_entry ((struct skiplist_entry *) e); + gdb_assert (!m_function.empty ()); + m_compiled_function_regexp.emplace (m_function.c_str (), flags, + _("regexp")); + } } -/* Create a cleanup to free skiplist entry E. */ - -static struct cleanup * -make_free_skiplist_entry_cleanup (struct skiplist_entry *e) +void +skiplist_entry::add_entry (bool file_is_glob, std::string &&file, + bool function_is_regexp, std::string &&function) { - return make_cleanup (free_skiplist_entry_cleanup, e); + skiplist_entries.emplace_back (file_is_glob, + std::move (file), + function_is_regexp, + std::move (function), + private_key {}); + + /* Incremented after push_back, in case push_back throws. */ + skiplist_entries.back ().m_number = ++highest_skiplist_entry_num; } static void -skip_file_command (char *arg, int from_tty) +skip_file_command (const char *arg, int from_tty) { struct symtab *symtab; const char *filename = NULL; @@ -147,14 +179,15 @@ skip_file_command (char *arg, int from_tty) if (symtab == NULL) error (_("No default file now.")); - /* It is not a typo, symtab_to_filename_for_display woule be needlessly + /* It is not a typo, symtab_to_filename_for_display would be needlessly ambiguous. */ filename = symtab_to_fullname (symtab); } else filename = arg; - add_skiplist_entry (make_skip_entry (0, filename, 0, NULL)); + skiplist_entry::add_entry (false, std::string (filename), + false, std::string ()); printf_filtered (_("File %s will be skipped when stepping.\n"), filename); } @@ -165,29 +198,26 @@ skip_file_command (char *arg, int from_tty) static void skip_function (const char *name) { - add_skiplist_entry (make_skip_entry (0, NULL, 0, name)); + skiplist_entry::add_entry (false, std::string (), false, std::string (name)); printf_filtered (_("Function %s will be skipped when stepping.\n"), name); } static void -skip_function_command (char *arg, int from_tty) +skip_function_command (const char *arg, int from_tty) { /* Default to the current function if no argument is given. */ if (arg == NULL) { + frame_info *fi = get_selected_frame (_("No default function now.")); + struct symbol *sym = get_frame_function (fi); const char *name = NULL; - CORE_ADDR pc; - - if (!last_displayed_sal_is_valid ()) - error (_("No default function now.")); - pc = get_last_displayed_addr (); - if (!find_pc_partial_function (pc, &name, NULL, NULL)) - { - error (_("No function found containing current program point %s."), - paddress (get_current_arch (), pc)); - } + if (sym != NULL) + name = sym->print_name (); + else + error (_("No function found containing current program point %s."), + paddress (get_current_arch (), get_frame_pc (fi))); skip_function (name); return; } @@ -195,45 +225,15 @@ skip_function_command (char *arg, int from_tty) 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) +skip_command (const 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) @@ -242,8 +242,7 @@ skip_command (char *arg, int from_tty) return; } - argv = buildargv (arg); - cleanups = make_cleanup_freeargv (argv); + gdb_argv argv (arg); for (i = 0; argv[i] != NULL; ++i) { @@ -290,7 +289,6 @@ skip_command (char *arg, int from_tty) 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; } @@ -309,16 +307,20 @@ skip_command (char *arg, int from_tty) 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); + std::string entry_file; + if (file != NULL) + entry_file = file; + else if (gfile != NULL) + entry_file = gfile; - compile_skip_regexp (e, _("regexp")); - discard_cleanups (rf_cleanups); - } - add_skiplist_entry (e); + std::string entry_function; + if (function != NULL) + entry_function = function; + else if (rfunction != NULL) + entry_function = rfunction; + + skiplist_entry::add_entry (gfile != NULL, std::move (entry_file), + rfunction != NULL, std::move (entry_function)); /* 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 @@ -350,101 +352,95 @@ skip_command (char *arg, int from_tty) lower_file_text, file_to_print); } } - - do_cleanups (cleanups); } static void -skip_info (char *arg, int from_tty) +info_skip_command (const char *arg, int from_tty) { - struct skiplist_entry *e; int num_printable_entries = 0; struct value_print_options opts; - struct cleanup *tbl_chain; get_user_print_options (&opts); /* Count the number of rows in the table and see if we need space for a 64-bit address anywhere. */ - ALL_SKIPLIST_ENTRIES (e) - if (arg == NULL || number_is_in_list (arg, e->number)) + for (const skiplist_entry &e : skiplist_entries) + if (arg == NULL || number_is_in_list (arg, e.number ())) num_printable_entries++; if (num_printable_entries == 0) { if (arg == NULL) - ui_out_message (current_uiout, _("\ -Not skipping any files or functions.\n")); + current_uiout->message (_("Not skipping any files or functions.\n")); else - ui_out_message (current_uiout, - _("No skiplist entries found with number %s.\n"), arg); + current_uiout->message ( + _("No skiplist entries found with number %s.\n"), arg); return; } - tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 6, - num_printable_entries, - "SkiplistTable"); + ui_out_emit_table table_emitter (current_uiout, 6, num_printable_entries, + "SkiplistTable"); - 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); + current_uiout->table_header (5, ui_left, "number", "Num"); /* 1 */ + current_uiout->table_header (3, ui_left, "enabled", "Enb"); /* 2 */ + current_uiout->table_header (4, ui_right, "regexp", "Glob"); /* 3 */ + current_uiout->table_header (20, ui_left, "file", "File"); /* 4 */ + current_uiout->table_header (2, ui_right, "regexp", "RE"); /* 5 */ + current_uiout->table_header (40, ui_noalign, "function", "Function"); /* 6 */ + current_uiout->table_body (); - ALL_SKIPLIST_ENTRIES (e) + for (const skiplist_entry &e : skiplist_entries) { - struct cleanup *entry_chain; - QUIT; - if (arg != NULL && !number_is_in_list (arg, e->number)) + if (arg != NULL && !number_is_in_list (arg, e.number ())) continue; - entry_chain = make_cleanup_ui_out_tuple_begin_end (current_uiout, - "blklst-entry"); - ui_out_field_int (current_uiout, "number", e->number); /* 1 */ + ui_out_emit_tuple tuple_emitter (current_uiout, "blklst-entry"); + current_uiout->field_signed ("number", e.number ()); /* 1 */ - if (e->enabled) - ui_out_field_string (current_uiout, "enabled", "y"); /* 2 */ + if (e.enabled ()) + current_uiout->field_string ("enabled", "y"); /* 2 */ else - ui_out_field_string (current_uiout, "enabled", "n"); /* 2 */ + current_uiout->field_string ("enabled", "n"); /* 2 */ - if (e->file_is_glob) - ui_out_field_string (current_uiout, "regexp", "y"); /* 3 */ + if (e.file_is_glob ()) + current_uiout->field_string ("regexp", "y"); /* 3 */ else - ui_out_field_string (current_uiout, "regexp", "n"); /* 3 */ - - ui_out_field_string (current_uiout, "file", - e->file ? e->file : ""); /* 4 */ - if (e->function_is_regexp) - ui_out_field_string (current_uiout, "regexp", "y"); /* 5 */ + current_uiout->field_string ("regexp", "n"); /* 3 */ + + current_uiout->field_string ("file", + e.file ().empty () ? "" + : e.file ().c_str (), + e.file ().empty () + ? metadata_style.style () + : file_name_style.style ()); /* 4 */ + if (e.function_is_regexp ()) + current_uiout->field_string ("regexp", "y"); /* 5 */ else - ui_out_field_string (current_uiout, "regexp", "n"); /* 5 */ + current_uiout->field_string ("regexp", "n"); /* 5 */ - ui_out_field_string (current_uiout, "function", - e->function ? e->function : ""); /* 6 */ + current_uiout->field_string ("function", + e.function ().empty () ? "" + : e.function ().c_str (), + e.function ().empty () + ? metadata_style.style () + : function_name_style.style ()); /* 6 */ - ui_out_text (current_uiout, "\n"); - do_cleanups (entry_chain); + current_uiout->text ("\n"); } - - do_cleanups (tbl_chain); } static void -skip_enable_command (char *arg, int from_tty) +skip_enable_command (const char *arg, int from_tty) { - struct skiplist_entry *e; - int found = 0; + bool found = false; - ALL_SKIPLIST_ENTRIES (e) - if (arg == NULL || number_is_in_list (arg, e->number)) + for (skiplist_entry &e : skiplist_entries) + if (arg == NULL || number_is_in_list (arg, e.number ())) { - e->enabled = 1; - found = 1; + e.enable (); + found = true; } if (!found) @@ -452,16 +448,15 @@ skip_enable_command (char *arg, int from_tty) } static void -skip_disable_command (char *arg, int from_tty) +skip_disable_command (const char *arg, int from_tty) { - struct skiplist_entry *e; - int found = 0; + bool found = false; - ALL_SKIPLIST_ENTRIES (e) - if (arg == NULL || number_is_in_list (arg, e->number)) + for (skiplist_entry &e : skiplist_entries) + if (arg == NULL || number_is_in_list (arg, e.number ())) { - e->enabled = 0; - found = 1; + e.disable (); + found = true; } if (!found) @@ -469,232 +464,222 @@ skip_disable_command (char *arg, int from_tty) } static void -skip_delete_command (char *arg, int from_tty) +skip_delete_command (const char *arg, int from_tty) { - struct skiplist_entry *e, *temp, *b_prev; - int found = 0; + bool found = false; - b_prev = 0; - ALL_SKIPLIST_ENTRIES_SAFE (e, temp) - if (arg == NULL || number_is_in_list (arg, e->number)) - { - if (b_prev != NULL) - b_prev->next = e->next; - else - skiplist_entry_chain = e->next; + for (auto it = skiplist_entries.begin (), + end = skiplist_entries.end (); + it != end;) + { + const skiplist_entry &e = *it; - free_skiplist_entry (e); - found = 1; - } - else - { - b_prev = e; - } + if (arg == NULL || number_is_in_list (arg, e.number ())) + { + it = skiplist_entries.erase (it); + found = true; + } + else + ++it; + } if (!found) error (_("No skiplist entries found with number %s."), arg); } -/* Add the given skiplist entry to our list, and set the entry's number. */ - -static void -add_skiplist_entry (struct skiplist_entry *e) -{ - struct skiplist_entry *e1; - - e->number = ++skiplist_entry_count; - - /* Add to the end of the chain so that the list of - skiplist entries will be in numerical order. */ - - e1 = skiplist_entry_chain; - if (e1 == NULL) - skiplist_entry_chain = e; - else - { - while (e1->next) - e1 = e1->next; - e1->next = 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) +bool +skiplist_entry::do_skip_file_p (const symtab_and_line &function_sal) const { - gdb_assert (e->file != NULL && !e->file_is_glob); + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, + "skip: checking if file %s matches non-glob %s...", + function_sal.symtab->filename, m_file.c_str ()); - if (function_sal->symtab == NULL) - return 0; + bool result; /* 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; + if (compare_filenames_for_search (function_sal.symtab->filename, + m_file.c_str ())) + result = true; /* 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; + else if (!basenames_may_differ + && filename_cmp (lbasename (function_sal.symtab->filename), + lbasename (m_file.c_str ())) != 0) + result = false; + else + { + /* Note: symtab_to_fullname caches its result, thus we don't have to. */ + const char *fullname = symtab_to_fullname (function_sal.symtab); - /* Note: symtab_to_fullname caches its result, thus we don't have to. */ - { - const char *fullname = symtab_to_fullname (function_sal->symtab); + result = compare_filenames_for_search (fullname, m_file.c_str ()); + } - if (compare_filenames_for_search (fullname, e->file)) - return 1; - } + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, result ? "yes.\n" : "no.\n"); - return 0; + return result; } -/* 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) +bool +skiplist_entry::do_skip_gfile_p (const symtab_and_line &function_sal) const { - gdb_assert (e->file != NULL && e->file_is_glob); + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, + "skip: checking if file %s matches glob %s...", + function_sal.symtab->filename, m_file.c_str ()); - if (function_sal->symtab == NULL) - return 0; + bool result; /* 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, + if (gdb_filename_fnmatch (m_file.c_str (), function_sal.symtab->filename, FNM_FILE_NAME | FNM_NOESCAPE) == 0) - return 1; + result = true; /* 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), + else if (!basenames_may_differ + && gdb_filename_fnmatch (lbasename (m_file.c_str ()), + lbasename (function_sal.symtab->filename), FNM_FILE_NAME | FNM_NOESCAPE) != 0) - return 0; + result = false; + else + { + /* Note: symtab_to_fullname caches its result, thus we don't have to. */ + const char *fullname = symtab_to_fullname (function_sal.symtab); - /* Note: symtab_to_fullname caches its result, thus we don't have to. */ - { - const char *fullname = symtab_to_fullname (function_sal->symtab); + result = compare_glob_filenames_for_search (fullname, m_file.c_str ()); + } - if (compare_glob_filenames_for_search (fullname, e->file)) - return 1; - } + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, result ? "yes.\n" : "no.\n"); - return 0; + return result; } -/* 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) +bool +skiplist_entry::skip_file_p (const symtab_and_line &function_sal) const { - gdb_assert (e->function != NULL && !e->function_is_regexp); - return strcmp_iw (function_name, e->function) == 0; -} + if (m_file.empty ()) + return false; -/* Return non-zero if we're stopped at a function regexp to be skipped. */ + if (function_sal.symtab == NULL) + return false; -static int -skip_rfunction_p (struct skiplist_entry *e, const char *function_name) + if (m_file_is_glob) + return do_skip_gfile_p (function_sal); + else + return do_skip_file_p (function_sal); +} + +bool +skiplist_entry::skip_function_p (const char *function_name) const { - 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); + if (m_function.empty ()) + return false; + + bool result; + + if (m_function_is_regexp) + { + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, + "skip: checking if function %s matches regex %s...", + function_name, m_function.c_str ()); + + gdb_assert (m_compiled_function_regexp); + result + = (m_compiled_function_regexp->exec (function_name, 0, NULL, 0) == 0); + } + else + { + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, + ("skip: checking if function %s matches non-regex " + "%s..."), + function_name, m_function.c_str ()); + result = (strcmp_iw (function_name, m_function.c_str ()) == 0); + } + + if (debug_skip) + fprintf_unfiltered (gdb_stdlog, result ? "yes.\n" : "no.\n"); + + return result; } /* See skip.h. */ -int +bool function_name_is_marked_for_skip (const char *function_name, - const struct symtab_and_line *function_sal) + const symtab_and_line &function_sal) { - struct skiplist_entry *e; - if (function_name == NULL) - return 0; + return false; - ALL_SKIPLIST_ENTRIES (e) + for (const skiplist_entry &e : skiplist_entries) { - int skip_by_file = 0; - int skip_by_function = 0; - - if (!e->enabled) + if (!e.enabled ()) continue; - if (e->file != NULL) - { - if (e->file_is_glob) - { - if (skip_gfile_p (e, function_sal)) - skip_by_file = 1; - } - 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; - } - } + bool skip_by_file = e.skip_file_p (function_sal); + bool skip_by_function = e.skip_function_p (function_name); /* 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 (!e.file ().empty () && !e.function ().empty ()) { if (skip_by_file && skip_by_function) - return 1; + return true; } /* Only one of file/function is specified. */ else if (skip_by_file || skip_by_function) - return 1; + return true; } - return 0; + return false; } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_step_skip; +/* Completer for skip numbers. */ + +static void +complete_skip_number (cmd_list_element *cmd, + completion_tracker &completer, + const char *text, const char *word) +{ + size_t word_len = strlen (word); + + for (const skiplist_entry &entry : skiplist_entries) + { + gdb::unique_xmalloc_ptr name (xstrprintf ("%d", entry.number ())); + if (strncmp (word, name.get (), word_len) == 0) + completer.add_completion (std::move (name)); + } +} +void _initialize_step_skip (); void -_initialize_step_skip (void) +_initialize_step_skip () { static struct cmd_list_element *skiplist = NULL; struct cmd_list_element *c; - skiplist_entry_chain = 0; - skiplist_entry_count = 0; - add_prefix_cmd ("skip", class_breakpoint, skip_command, _("\ Ignore a function while stepping.\n\ \n\ Usage: skip [FUNCTION-NAME]\n\ - skip [] []\n\ + skip [FILE-SPEC] [FUNCTION-SPEC]\n\ If no arguments are given, ignore the current function.\n\ \n\ - is one of:\n\ +FILE-SPEC is one of:\n\ -fi|-file FILE-NAME\n\ -gfi|-gfile GLOB-FILE-PATTERN\n\ - is one of:\n\ +FUNCTION-SPEC is one of:\n\ -fu|-function FUNCTION-NAME\n\ -rfu|-rfunction FUNCTION-NAME-REGULAR-EXPRESSION"), &skiplist, "skip ", 1, &cmdlist); @@ -713,33 +698,48 @@ If no function name is given, skip the current function."), &skiplist); set_cmd_completer (c, location_completer); - add_cmd ("enable", class_breakpoint, skip_enable_command, _("\ -Enable skip entries. You can specify numbers (e.g. \"skip enable 1 3\"), \ + c = add_cmd ("enable", class_breakpoint, skip_enable_command, _("\ +Enable skip entries.\n\ +Usage: skip enable [NUMBER | RANGE]...\n\ +You can specify numbers (e.g. \"skip enable 1 3\"),\n\ ranges (e.g. \"skip enable 4-8\"), or both (e.g. \"skip enable 1 3 4-8\").\n\n\ -If you don't specify any numbers or ranges, we'll enable all skip entries.\n\n\ -Usage: skip enable [NUMBERS AND/OR RANGES]"), - &skiplist); +If you don't specify any numbers or ranges, we'll enable all skip entries."), + &skiplist); + set_cmd_completer (c, complete_skip_number); - add_cmd ("disable", class_breakpoint, skip_disable_command, _("\ -Disable skip entries. You can specify numbers (e.g. \"skip disable 1 3\"), \ + c = add_cmd ("disable", class_breakpoint, skip_disable_command, _("\ +Disable skip entries.\n\ +Usage: skip disable [NUMBER | RANGE]...\n\ +You can specify numbers (e.g. \"skip disable 1 3\"),\n\ ranges (e.g. \"skip disable 4-8\"), or both (e.g. \"skip disable 1 3 4-8\").\n\n\ -If you don't specify any numbers or ranges, we'll disable all skip entries.\n\n\ -Usage: skip disable [NUMBERS AND/OR RANGES]"), - &skiplist); +If you don't specify any numbers or ranges, we'll disable all skip entries."), + &skiplist); + set_cmd_completer (c, complete_skip_number); - add_cmd ("delete", class_breakpoint, skip_delete_command, _("\ -Delete skip entries. You can specify numbers (e.g. \"skip delete 1 3\"), \ + c = add_cmd ("delete", class_breakpoint, skip_delete_command, _("\ +Delete skip entries.\n\ +Usage: skip delete [NUMBER | RANGES]...\n\ +You can specify numbers (e.g. \"skip delete 1 3\"),\n\ ranges (e.g. \"skip delete 4-8\"), or both (e.g. \"skip delete 1 3 4-8\").\n\n\ -If you don't specify any numbers or ranges, we'll delete all skip entries.\n\n\ -Usage: skip delete [NUMBERS AND/OR RANGES]"), - &skiplist); - - add_info ("skip", skip_info, _("\ -Display the status of skips. You can specify numbers (e.g. \"skip info 1 3\"), \ -ranges (e.g. \"skip info 4-8\"), or both (e.g. \"skip info 1 3 4-8\").\n\n\ -If you don't specify any numbers or ranges, we'll show all skips.\n\n\ -Usage: skip info [NUMBERS AND/OR RANGES]\n\ -The \"Type\" column indicates one of:\n\ -\tfile - ignored file\n\ -\tfunction - ignored function")); +If you don't specify any numbers or ranges, we'll delete all skip entries."), + &skiplist); + set_cmd_completer (c, complete_skip_number); + + add_info ("skip", info_skip_command, _("\ +Display the status of skips.\n\ +Usage: info skip [NUMBER | RANGES]...\n\ +You can specify numbers (e.g. \"info skip 1 3\"), \n\ +ranges (e.g. \"info skip 4-8\"), or both (e.g. \"info skip 1 3 4-8\").\n\n\ +If you don't specify any numbers or ranges, we'll show all skips.")); + set_cmd_completer (c, complete_skip_number); + + add_setshow_boolean_cmd ("skip", class_maintenance, + &debug_skip, _("\ +Set whether to print the debug output about skipping files and functions."), + _("\ +Show whether the debug output about skipping files and functions is printed."), + _("\ +When non-zero, debug output about skipping files and functions is displayed."), + NULL, NULL, + &setdebuglist, &showdebuglist); }