diff options
Diffstat (limited to 'gdb/skip.c')
-rw-r--r-- | gdb/skip.c | 503 |
1 files changed, 222 insertions, 281 deletions
@@ -35,98 +35,129 @@ #include "fnmatch.h" #include "gdb_regex.h" #include "common/gdb_optional.h" +#include <list> -struct skiplist_entry +class 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; - - /* The name of the file or NULL. - The skiplist entry owns this pointer. */ - char *file; - - /* Non-zero if FUNCTION is a regexp. +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. */ - gdb::optional<compiled_regex> compiled_function_regexp; + gdb::optional<compiled_regex> m_compiled_function_regexp; - 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_entry> 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; - - return e; -} + gdb_assert (!m_file.empty () || !m_function.empty ()); -/* 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); - 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 @@ -150,7 +181,8 @@ skip_file_command (char *arg, int from_tty) 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); } @@ -161,7 +193,7 @@ 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); } @@ -191,23 +223,6 @@ 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 flags = REG_NOSUB; - -#ifdef REG_EXTENDED - flags |= REG_EXTENDED; -#endif - - gdb_assert (e->function_is_regexp && e->function != NULL); - e->compiled_function_regexp.emplace (e->function, flags, message); -} - /* Process "skip ..." that does not match "skip file" or "skip function". */ static void @@ -217,9 +232,6 @@ skip_command (char *arg, int from_tty) 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) @@ -228,8 +240,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) { @@ -276,7 +287,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; } @@ -295,16 +305,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 @@ -336,24 +350,20 @@ 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 (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) @@ -367,9 +377,8 @@ skip_info (char *arg, int from_tty) 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"); current_uiout->table_header (5, ui_left, "number", "Num"); /* 1 */ current_uiout->table_header (3, ui_left, "enabled", "Enb"); /* 2 */ @@ -379,53 +388,51 @@ skip_info (char *arg, int from_tty) 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) { - QUIT; - if (arg != NULL && !number_is_in_list (arg, e->number)) + if (arg != NULL && !number_is_in_list (arg, e.number ())) continue; ui_out_emit_tuple tuple_emitter (current_uiout, "blklst-entry"); - current_uiout->field_int ("number", e->number); /* 1 */ + current_uiout->field_int ("number", e.number ()); /* 1 */ - if (e->enabled) + if (e.enabled ()) current_uiout->field_string ("enabled", "y"); /* 2 */ else current_uiout->field_string ("enabled", "n"); /* 2 */ - if (e->file_is_glob) + if (e.file_is_glob ()) current_uiout->field_string ("regexp", "y"); /* 3 */ else current_uiout->field_string ("regexp", "n"); /* 3 */ current_uiout->field_string ("file", - e->file ? e->file : "<none>"); /* 4 */ - if (e->function_is_regexp) + e.file ().empty () ? "<none>" + : e.file ().c_str ()); /* 4 */ + if (e.function_is_regexp ()) current_uiout->field_string ("regexp", "y"); /* 5 */ else current_uiout->field_string ("regexp", "n"); /* 5 */ - current_uiout->field_string ( - "function", e->function ? e->function : "<none>"); /* 6 */ + current_uiout->field_string ("function", + e.function ().empty () ? "<none>" + : e.function ().c_str ()); /* 6 */ current_uiout->text ("\n"); } - - do_cleanups (tbl_chain); } static void skip_enable_command (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) @@ -435,14 +442,13 @@ skip_enable_command (char *arg, int from_tty) static void skip_disable_command (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) @@ -452,103 +458,62 @@ skip_disable_command (char *arg, int from_tty) static void skip_delete_command (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 (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; + if (compare_filenames_for_search (function_sal.symtab->filename, + m_file.c_str ())) + return 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; + && filename_cmp (lbasename (function_sal.symtab->filename), + lbasename (m_file.c_str ())) != 0) + return false; /* Note: symtab_to_fullname caches its result, thus we don't have to. */ { - const char *fullname = symtab_to_fullname (function_sal->symtab); + const char *fullname = symtab_to_fullname (function_sal.symtab); - if (compare_filenames_for_search (fullname, e->file)) - return 1; + if (compare_filenames_for_search (fullname, m_file.c_str ())) + return true; } - return 0; + return false; } -/* 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 (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, + if (gdb_filename_fnmatch (m_file.c_str (), function_sal.symtab->filename, FNM_FILE_NAME | FNM_NOESCAPE) == 0) - return 1; + return true; /* Before we invoke symtab_to_fullname, which is expensive, do a quick comparison of the basenames. @@ -556,115 +521,91 @@ skip_gfile_p (struct skiplist_entry *e, 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), + && gdb_filename_fnmatch (lbasename (m_file.c_str ()), + lbasename (function_sal.symtab->filename), FNM_FILE_NAME | FNM_NOESCAPE) != 0) - return 0; + return false; /* Note: symtab_to_fullname caches its result, thus we don't have to. */ { - const char *fullname = symtab_to_fullname (function_sal->symtab); + const char *fullname = symtab_to_fullname (function_sal.symtab); - if (compare_glob_filenames_for_search (fullname, e->file)) - return 1; + if (compare_glob_filenames_for_search (fullname, m_file.c_str ())) + return true; } - return 0; + return false; } -/* 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); - return (e->compiled_function_regexp->exec (function_name, 0, NULL, 0) - == 0); + if (m_function.empty ()) + return false; + + if (m_function_is_regexp) + { + gdb_assert (m_compiled_function_regexp); + return (m_compiled_function_regexp->exec (function_name, 0, NULL, 0) + == 0); + } + else + return strcmp_iw (function_name, m_function.c_str ()) == 0; } /* 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; - void _initialize_step_skip (void) { 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\ @@ -715,7 +656,7 @@ 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, _("\ + add_info ("skip", info_skip_command, _("\ 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\ |