From 2d7cc5c7973b6d1bdd9205288863bedadeaf8b41 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 7 Jun 2017 14:21:40 +0100 Subject: [PATCH] Introduce compiled_regex, eliminate make_regfree_cleanup This patch replaces compile_rx_or_error and make_regfree_cleanup with a class that wraps a regex_t. gdb/ChangeLog: 2017-06-07 Pedro Alves * Makefile.in (SFILES): Add gdb_regex.c. (COMMON_OBS): Add gdb_regex.o. * ada-lang.c (ada_add_standard_exceptions) (ada_add_exceptions_from_frame, name_matches_regex) (ada_add_global_exceptions, ada_exceptions_list_1): Change regex parameter type to compiled_regex. Adjust. (ada_exceptions_list): Use compiled_regex. * break-catch-throw.c (exception_catchpoint::pattern): Now a std::unique_ptr. (exception_catchpoint::~exception_catchpoint): Remove regfree call. (check_status_exception_catchpoint): Adjust to use compiled_regex. (handle_gnu_v3_exceptions): Adjust to use compiled_regex. * breakpoint.c (solib_catchpoint::compiled): Now a std::unique_ptr. (solib_catchpoint::~solib_catchpoint): Remove regfree call. (check_status_catch_solib): Adjust to use compiled_regex. (add_solib_catchpoint): Adjust to use compiled_regex. * cli/cli-cmds.c (apropos_command): Use compiled_regex. * cli/cli-decode.c (apropos_cmd): Change regex parameter to compiled_regex reference. Adjust to use it. * cli/cli-decode.h: Remove struct re_pattern_buffer forward declaration. Include "gdb_regex.h". (apropos_cmd): Change regex parameter to compiled_regex reference. * gdb_regex.c: New file. * gdb_regex.h (make_regfree_cleanup, get_regcomp_error): Delete declarations. (class compiled_regex): New. * linux-tdep.c: Include "common/gdb_optional.h". (struct mapping_regexes): New, factored out from mapping_is_anonymous_p, and adjusted to use compiled_regex. (mapping_is_anonymous_p): Use mapping_regexes wrapped in a gdb::optional and remove cleanups. Adjust to compiled_regex. * probe.c: Include "common/gdb_optional.h". (collect_probes): Use compiled_regex and gdb::optional and remove cleanups. * skip.c: Include "common/gdb_optional.h". (skiplist_entry::compiled_function_regexp): Now a gdb::optional. (skiplist_entry::compiled_function_regexp_is_valid): Delete field. (free_skiplist_entry): Remove regfree call. (compile_skip_regexp, skip_rfunction_p): Adjust to use compiled_regex and gdb::optional. * symtab.c: Include "common/gdb_optional.h". (search_symbols): Use compiled_regex and gdb::optional. * utils.c (do_regfree_cleanup, make_regfree_cleanup) (get_regcomp_error, compile_rx_or_error): Delete. Some bits moved to gdb_regex.c. --- gdb/ChangeLog | 51 +++++++++++++++++++++++++ gdb/Makefile.in | 2 + gdb/ada-lang.c | 33 +++++++--------- gdb/break-catch-throw.c | 21 ++++------ gdb/breakpoint.c | 20 +++------- gdb/cli/cli-cmds.c | 21 ++-------- gdb/cli/cli-decode.c | 11 ++++-- gdb/cli/cli-decode.h | 5 +-- gdb/gdb_regex.c | 56 +++++++++++++++++++++++++++ gdb/gdb_regex.h | 39 ++++++++++++++++--- gdb/linux-tdep.c | 85 +++++++++++++++++++++-------------------- gdb/probe.c | 19 +++++---- gdb/skip.c | 24 +++--------- gdb/symtab.c | 42 ++++++++------------ gdb/utils.c | 52 ------------------------- 15 files changed, 255 insertions(+), 226 deletions(-) create mode 100644 gdb/gdb_regex.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 31904109a7..6424388711 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,54 @@ +2017-06-07 Pedro Alves + + * Makefile.in (SFILES): Add gdb_regex.c. + (COMMON_OBS): Add gdb_regex.o. + * ada-lang.c (ada_add_standard_exceptions) + (ada_add_exceptions_from_frame, name_matches_regex) + (ada_add_global_exceptions, ada_exceptions_list_1): Change regex + parameter type to compiled_regex. Adjust. + (ada_exceptions_list): Use compiled_regex. + * break-catch-throw.c (exception_catchpoint::pattern): Now a + std::unique_ptr. + (exception_catchpoint::~exception_catchpoint): Remove regfree + call. + (check_status_exception_catchpoint): Adjust to use compiled_regex. + (handle_gnu_v3_exceptions): Adjust to use compiled_regex. + * breakpoint.c (solib_catchpoint::compiled): Now a + std::unique_ptr. + (solib_catchpoint::~solib_catchpoint): Remove regfree call. + (check_status_catch_solib): Adjust to use compiled_regex. + (add_solib_catchpoint): Adjust to use compiled_regex. + * cli/cli-cmds.c (apropos_command): Use compiled_regex. + * cli/cli-decode.c (apropos_cmd): Change regex parameter to + compiled_regex reference. Adjust to use it. + * cli/cli-decode.h: Remove struct re_pattern_buffer forward + declaration. Include "gdb_regex.h". + (apropos_cmd): Change regex parameter to compiled_regex reference. + * gdb_regex.c: New file. + * gdb_regex.h (make_regfree_cleanup, get_regcomp_error): Delete + declarations. + (class compiled_regex): New. + * linux-tdep.c: Include "common/gdb_optional.h". + (struct mapping_regexes): New, factored out from + mapping_is_anonymous_p, and adjusted to use compiled_regex. + (mapping_is_anonymous_p): Use mapping_regexes wrapped in a + gdb::optional and remove cleanups. Adjust to compiled_regex. + * probe.c: Include "common/gdb_optional.h". + (collect_probes): Use compiled_regex and gdb::optional and remove + cleanups. + * skip.c: Include "common/gdb_optional.h". + (skiplist_entry::compiled_function_regexp): Now a + gdb::optional. + (skiplist_entry::compiled_function_regexp_is_valid): Delete field. + (free_skiplist_entry): Remove regfree call. + (compile_skip_regexp, skip_rfunction_p): Adjust to use + compiled_regex and gdb::optional. + * symtab.c: Include "common/gdb_optional.h". + (search_symbols): Use compiled_regex and gdb::optional. + * utils.c (do_regfree_cleanup, make_regfree_cleanup) + (get_regcomp_error, compile_rx_or_error): Delete. Some bits moved + to gdb_regex.c. + 2017-06-07 Alan Hayward * regcache.c (regcache::save): Avoid buffer use. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8be73ba423..2156438c1b 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1104,6 +1104,7 @@ SFILES = \ gdb_bfd.c \ gdb-dlfcn.c \ gdb_obstack.c \ + gdb_regex.c \ gdb_usleep.c \ gdbarch.c \ gdbarch-selftests.c \ @@ -1717,6 +1718,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ gdb_bfd.o \ gdb-dlfcn.o \ gdb_obstack.o \ + gdb_regex.o \ gdb_usleep.o \ gdb_vecs.o \ gdbarch.o \ diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index f90907a928..57c670e8d6 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -13219,14 +13219,15 @@ sort_remove_dups_ada_exceptions_list (VEC(ada_exc_info) **exceptions, gets pushed. */ static void -ada_add_standard_exceptions (regex_t *preg, VEC(ada_exc_info) **exceptions) +ada_add_standard_exceptions (compiled_regex *preg, + VEC(ada_exc_info) **exceptions) { int i; for (i = 0; i < ARRAY_SIZE (standard_exc); i++) { if (preg == NULL - || regexec (preg, standard_exc[i], 0, NULL, 0) == 0) + || preg->exec (standard_exc[i], 0, NULL, 0) == 0) { struct bound_minimal_symbol msymbol = ada_lookup_simple_minsym (standard_exc[i]); @@ -13253,7 +13254,8 @@ ada_add_standard_exceptions (regex_t *preg, VEC(ada_exc_info) **exceptions) gets pushed. */ static void -ada_add_exceptions_from_frame (regex_t *preg, struct frame_info *frame, +ada_add_exceptions_from_frame (compiled_regex *preg, + struct frame_info *frame, VEC(ada_exc_info) **exceptions) { const struct block *block = get_frame_block (frame, 0); @@ -13290,10 +13292,10 @@ ada_add_exceptions_from_frame (regex_t *preg, struct frame_info *frame, /* Return true if NAME matches PREG or if PREG is NULL. */ static bool -name_matches_regex (const char *name, regex_t *preg) +name_matches_regex (const char *name, compiled_regex *preg) { return (preg == NULL - || regexec (preg, ada_decode (name), 0, NULL, 0) == 0); + || preg->exec (ada_decode (name), 0, NULL, 0) == 0); } /* Add all exceptions defined globally whose name name match @@ -13316,7 +13318,8 @@ name_matches_regex (const char *name, regex_t *preg) gets pushed. */ static void -ada_add_global_exceptions (regex_t *preg, VEC(ada_exc_info) **exceptions) +ada_add_global_exceptions (compiled_regex *preg, + VEC(ada_exc_info) **exceptions) { struct objfile *objfile; struct compunit_symtab *s; @@ -13364,7 +13367,7 @@ ada_add_global_exceptions (regex_t *preg, VEC(ada_exc_info) **exceptions) do not match. Otherwise, all exceptions are listed. */ static VEC(ada_exc_info) * -ada_exceptions_list_1 (regex_t *preg) +ada_exceptions_list_1 (compiled_regex *preg) { VEC(ada_exc_info) *result = NULL; struct cleanup *old_chain @@ -13417,19 +13420,11 @@ ada_exceptions_list_1 (regex_t *preg) VEC(ada_exc_info) * ada_exceptions_list (const char *regexp) { - VEC(ada_exc_info) *result = NULL; - struct cleanup *old_chain = NULL; - regex_t reg; - - if (regexp != NULL) - old_chain = compile_rx_or_error (®, regexp, - _("invalid regular expression")); + if (regexp == NULL) + return ada_exceptions_list_1 (NULL); - result = ada_exceptions_list_1 (regexp != NULL ? ® : NULL); - - if (old_chain != NULL) - do_cleanups (old_chain); - return result; + compiled_regex reg (regexp, REG_NOSUB, _("invalid regular expression")); + return ada_exceptions_list_1 (®); } /* Implement the "info exceptions" command. */ diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c index 7731c5e5b6..0074d061f2 100644 --- a/gdb/break-catch-throw.c +++ b/gdb/break-catch-throw.c @@ -87,10 +87,10 @@ struct exception_catchpoint : public breakpoint char *exception_rx; - /* If non-NULL, an xmalloc'd, compiled regular expression which is - used to determine which exceptions to stop on. */ + /* If non-NULL, a compiled regular expression which is used to + determine which exceptions to stop on. */ - regex_t *pattern; + std::unique_ptr pattern; }; @@ -145,8 +145,6 @@ classify_exception_breakpoint (struct breakpoint *b) exception_catchpoint::~exception_catchpoint () { xfree (this->exception_rx); - if (this->pattern != NULL) - regfree (this->pattern); } /* Implement the 'check_status' method. */ @@ -185,7 +183,7 @@ check_status_exception_catchpoint (struct bpstats *bs) if (!type_name.empty ()) { - if (regexec (self->pattern, type_name.c_str (), 0, NULL, 0) != 0) + if (self->pattern->exec (type_name.c_str (), 0, NULL, 0) != 0) bs->stop = 0; } } @@ -377,15 +375,12 @@ handle_gnu_v3_exceptions (int tempflag, char *except_rx, const char *cond_string, enum exception_event_kind ex_event, int from_tty) { - regex_t *pattern = NULL; + std::unique_ptr pattern; if (except_rx != NULL) { - pattern = XNEW (regex_t); - make_cleanup (xfree, pattern); - - compile_rx_or_error (pattern, except_rx, - _("invalid type-matching regexp")); + pattern.reset (new compiled_regex (except_rx, REG_NOSUB, + _("invalid type-matching regexp"))); } std::unique_ptr cp (new exception_catchpoint ()); @@ -397,7 +392,7 @@ handle_gnu_v3_exceptions (int tempflag, char *except_rx, cp->type = bp_breakpoint; cp->kind = ex_event; cp->exception_rx = except_rx; - cp->pattern = pattern; + cp->pattern = std::move (pattern); re_set_exception_catchpoint (cp.get ()); diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index e84d1642a4..053ccef0fa 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -8284,13 +8284,11 @@ struct solib_catchpoint : public breakpoint /* Regular expression to match, if any. COMPILED is only valid when REGEX is non-NULL. */ char *regex; - regex_t compiled; + std::unique_ptr compiled; }; solib_catchpoint::~solib_catchpoint () { - if (this->regex) - regfree (&this->compiled); xfree (this->regex); } @@ -8358,7 +8356,7 @@ check_status_catch_solib (struct bpstats *bs) ++ix) { if (!self->regex - || regexec (&self->compiled, iter->so_name, 0, NULL, 0) == 0) + || self->compiled->exec (iter->so_name, 0, NULL, 0) == 0) return; } } @@ -8372,7 +8370,7 @@ check_status_catch_solib (struct bpstats *bs) ++ix) { if (!self->regex - || regexec (&self->compiled, iter, 0, NULL, 0) == 0) + || self->compiled->exec (iter, 0, NULL, 0) == 0) return; } } @@ -8488,16 +8486,8 @@ add_solib_catchpoint (const char *arg, int is_load, int is_temp, int enabled) if (*arg != '\0') { - int errcode; - - errcode = regcomp (&c->compiled, arg, REG_NOSUB); - if (errcode != 0) - { - char *err = get_regcomp_error (errcode, &c->compiled); - - make_cleanup (xfree, err); - error (_("Invalid regexp (%s): %s"), err, arg); - } + c->compiled.reset (new compiled_regex (arg, REG_NOSUB, + _("Invalid regexp"))); c->regex = xstrdup (arg); } diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 2a5b128d56..09303423bf 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -1336,28 +1336,13 @@ show_user (char *args, int from_tty) static void apropos_command (char *searchstr, int from_tty) { - regex_t pattern; - int code; - if (searchstr == NULL) error (_("REGEXP string is empty")); - code = regcomp (&pattern, searchstr, REG_ICASE); - if (code == 0) - { - struct cleanup *cleanups; + compiled_regex pattern (searchstr, REG_ICASE, + _("Error in regular expression")); - cleanups = make_regfree_cleanup (&pattern); - apropos_cmd (gdb_stdout, cmdlist, &pattern, ""); - do_cleanups (cleanups); - } - else - { - char *err = get_regcomp_error (code, &pattern); - - make_cleanup (xfree, err); - error (_("Error in regular expression: %s"), err); - } + apropos_cmd (gdb_stdout, cmdlist, pattern, ""); } /* Subroutine of alias_command to simplify it. diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index d386d0296f..383adf8b1a 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -917,7 +917,7 @@ add_com_suppress_notification (const char *name, enum command_class theclass, void apropos_cmd (struct ui_file *stream, struct cmd_list_element *commandlist, - struct re_pattern_buffer *regex, const char *prefix) + compiled_regex ®ex, const char *prefix) { struct cmd_list_element *c; int returnvalue; @@ -928,9 +928,10 @@ apropos_cmd (struct ui_file *stream, returnvalue = -1; /* Needed to avoid double printing. */ if (c->name != NULL) { + size_t name_len = strlen (c->name); + /* Try to match against the name. */ - returnvalue = re_search (regex, c->name, strlen(c->name), - 0, strlen (c->name), NULL); + returnvalue = regex.search (c->name, name_len, 0, name_len, NULL); if (returnvalue >= 0) { print_help_for_command (c, prefix, @@ -939,8 +940,10 @@ apropos_cmd (struct ui_file *stream, } if (c->doc != NULL && returnvalue < 0) { + size_t doc_len = strlen (c->doc); + /* Try to match against documentation. */ - if (re_search(regex,c->doc,strlen(c->doc),0,strlen(c->doc),NULL) >=0) + if (regex.search (c->doc, doc_len, 0, doc_len, NULL) >= 0) { print_help_for_command (c, prefix, 0 /* don't recurse */, stream); diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index 66159fd4a4..11248baa96 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -23,8 +23,7 @@ /* Include the public interfaces. */ #include "command.h" - -struct re_pattern_buffer; +#include "gdb_regex.h" #if 0 /* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum @@ -234,7 +233,7 @@ extern void help_cmd_list (struct cmd_list_element *, enum command_class, extern void help_cmd (const char *, struct ui_file *); extern void apropos_cmd (struct ui_file *, struct cmd_list_element *, - struct re_pattern_buffer *, const char *); + compiled_regex &, const char *); /* Used to mark commands that don't do anything. If we just leave the function field NULL, the command is interpreted as a help topic, or diff --git a/gdb/gdb_regex.c b/gdb/gdb_regex.c new file mode 100644 index 0000000000..2e376e3869 --- /dev/null +++ b/gdb/gdb_regex.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2011-2017 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +#include "defs.h" +#include "gdb_regex.h" + +compiled_regex::compiled_regex (const char *regex, int cflags, + const char *message) +{ + gdb_assert (regex != NULL); + gdb_assert (message != NULL); + + int code = regcomp (&m_pattern, regex, cflags); + if (code != 0) + { + size_t length = regerror (code, &m_pattern, NULL, 0); + std::unique_ptr err (new char[length]); + + regerror (code, &m_pattern, err.get (), length); + error (("%s: %s"), message, err.get ()); + } +} + +compiled_regex::~compiled_regex () +{ + regfree (&m_pattern); +} + +int +compiled_regex::exec (const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags) const +{ + return regexec (&m_pattern, string, nmatch, pmatch, eflags); +} + +int +compiled_regex::search (const char *string, + int length, int start, int range, + struct re_registers *regs) +{ + return re_search (&m_pattern, string, length, start, range, regs); +} diff --git a/gdb/gdb_regex.h b/gdb/gdb_regex.h index 0be26efd90..f62f81d366 100644 --- a/gdb/gdb_regex.h +++ b/gdb/gdb_regex.h @@ -27,10 +27,39 @@ # include #endif -/* From utils.c. */ -struct cleanup *make_regfree_cleanup (regex_t *); -char *get_regcomp_error (int, regex_t *); -struct cleanup *compile_rx_or_error (regex_t *pattern, const char *rx, - const char *message); +/* A compiled regex. This is mainly a wrapper around regex_t. The + the constructor throws on regcomp error and the destructor is + responsible for calling regfree. The former means that it's not + possible to create an instance of compiled_regex that isn't + compiled, hence the name. */ +class compiled_regex +{ +public: + /* Compile a regexp and throw an exception on error, including + MESSAGE. REGEX and MESSAGE must not be NULL. */ + compiled_regex (const char *regex, int cflags, + const char *message) + ATTRIBUTE_NONNULL (2) ATTRIBUTE_NONNULL (4); + + ~compiled_regex (); + + /* Disable copy. */ + compiled_regex (const compiled_regex&) = delete; + void operator= (const compiled_regex&) = delete; + + /* Wrapper around ::regexec. */ + int exec (const char *string, + size_t nmatch, regmatch_t pmatch[], + int eflags) const; + + /* Wrapper around ::re_search. (Not const because re_search's + regex_t parameter isn't either.) */ + int search (const char *string, int size, int startpos, + int range, struct re_registers *regs); + +private: + /* The compiled pattern. */ + regex_t m_pattern; +}; #endif /* not GDB_REGEX_H */ diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 016aadff6b..1afa8d7b35 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -38,6 +38,7 @@ #include "gdbcmd.h" #include "gdb_regex.h" #include "common/enum-flags.h" +#include "common/gdb_optional.h" #include @@ -493,6 +494,44 @@ decode_vmflags (char *p, struct smaps_vmflags *v) } } +/* Regexes used by mapping_is_anonymous_p. Put in a structure because + they're initialized lazily. */ + +struct mapping_regexes +{ + /* Matches "/dev/zero" filenames (with or without the "(deleted)" + string in the end). We know for sure, based on the Linux kernel + code, that memory mappings whose associated filename is + "/dev/zero" are guaranteed to be MAP_ANONYMOUS. */ + compiled_regex dev_zero + {"^/dev/zero\\( (deleted)\\)\\?$", REG_NOSUB, + _("Could not compile regex to match /dev/zero filename")}; + + /* Matches "/SYSV%08x" filenames (with or without the "(deleted)" + string in the end). These filenames refer to shared memory + (shmem), and memory mappings associated with them are + MAP_ANONYMOUS as well. */ + compiled_regex shmem_file + {"^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$", REG_NOSUB, + _("Could not compile regex to match shmem filenames")}; + + /* A heuristic we use to try to mimic the Linux kernel's 'n_link == + 0' code, which is responsible to decide if it is dealing with a + 'MAP_SHARED | MAP_ANONYMOUS' mapping. In other words, if + FILE_DELETED matches, it does not necessarily mean that we are + dealing with an anonymous shared mapping. However, there is no + easy way to detect this currently, so this is the best + approximation we have. + + As a result, GDB will dump readonly pages of deleted executables + when using the default value of coredump_filter (0x33), while the + Linux kernel will not dump those pages. But we can live with + that. */ + compiled_regex file_deleted + {" (deleted)$", REG_NOSUB, + _("Could not compile regex to match ' (deleted)'")}; +}; + /* Return 1 if the memory mapping is anonymous, 0 otherwise. FILENAME is the name of the file present in the first line of the @@ -506,52 +545,16 @@ decode_vmflags (char *p, struct smaps_vmflags *v) static int mapping_is_anonymous_p (const char *filename) { - static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex; + static gdb::optional regexes; static int init_regex_p = 0; if (!init_regex_p) { - struct cleanup *c = make_cleanup (null_cleanup, NULL); - /* Let's be pessimistic and assume there will be an error while compiling the regex'es. */ init_regex_p = -1; - /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or - without the "(deleted)" string in the end). We know for - sure, based on the Linux kernel code, that memory mappings - whose associated filename is "/dev/zero" are guaranteed to be - MAP_ANONYMOUS. */ - compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$", - _("Could not compile regex to match /dev/zero " - "filename")); - /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or - without the "(deleted)" string in the end). These filenames - refer to shared memory (shmem), and memory mappings - associated with them are MAP_ANONYMOUS as well. */ - compile_rx_or_error (&shmem_file_regex, - "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$", - _("Could not compile regex to match shmem " - "filenames")); - /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the - Linux kernel's 'n_link == 0' code, which is responsible to - decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS' - mapping. In other words, if FILE_DELETED_REGEX matches, it - does not necessarily mean that we are dealing with an - anonymous shared mapping. However, there is no easy way to - detect this currently, so this is the best approximation we - have. - - As a result, GDB will dump readonly pages of deleted - executables when using the default value of coredump_filter - (0x33), while the Linux kernel will not dump those pages. - But we can live with that. */ - compile_rx_or_error (&file_deleted_regex, " (deleted)$", - _("Could not compile regex to match " - "' (deleted)'")); - /* We will never release these regexes, so just discard the - cleanups. */ - discard_cleanups (c); + regexes.emplace (); /* If we reached this point, then everything succeeded. */ init_regex_p = 1; @@ -573,9 +576,9 @@ mapping_is_anonymous_p (const char *filename) } if (*filename == '\0' - || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0 - || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0 - || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0) + || regexes->dev_zero.exec (filename, 0, NULL, 0) == 0 + || regexes->shmem_file.exec (filename, 0, NULL, 0) == 0 + || regexes->file_deleted.exec (filename, 0, NULL, 0) == 0) return 1; return 0; diff --git a/gdb/probe.c b/gdb/probe.c index e65e0313fe..cb2dcdb359 100644 --- a/gdb/probe.c +++ b/gdb/probe.c @@ -36,6 +36,7 @@ #include "location.h" #include #include +#include "common/gdb_optional.h" typedef struct bound_probe bound_probe_s; DEF_VEC_O (bound_probe_s); @@ -288,18 +289,17 @@ collect_probes (char *objname, char *provider, char *probe_name, { struct objfile *objfile; VEC (bound_probe_s) *result = NULL; - struct cleanup *cleanup, *cleanup_temps; - regex_t obj_pat, prov_pat, probe_pat; + struct cleanup *cleanup; + gdb::optional obj_pat, prov_pat, probe_pat; cleanup = make_cleanup (VEC_cleanup (bound_probe_s), &result); - cleanup_temps = make_cleanup (null_cleanup, NULL); if (provider != NULL) - compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp")); + prov_pat.emplace (provider, REG_NOSUB, _("Invalid provider regexp")); if (probe_name != NULL) - compile_rx_or_error (&probe_pat, probe_name, _("Invalid probe regexp")); + probe_pat.emplace (probe_name, REG_NOSUB, _("Invalid probe regexp")); if (objname != NULL) - compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp")); + obj_pat.emplace (objname, REG_NOSUB, _("Invalid object file regexp")); ALL_OBJFILES (objfile) { @@ -312,7 +312,7 @@ collect_probes (char *objname, char *provider, char *probe_name, if (objname) { - if (regexec (&obj_pat, objfile_name (objfile), 0, NULL, 0) != 0) + if (obj_pat->exec (objfile_name (objfile), 0, NULL, 0) != 0) continue; } @@ -326,11 +326,11 @@ collect_probes (char *objname, char *provider, char *probe_name, continue; if (provider - && regexec (&prov_pat, probe->provider, 0, NULL, 0) != 0) + && prov_pat->exec (probe->provider, 0, NULL, 0) != 0) continue; if (probe_name - && regexec (&probe_pat, probe->name, 0, NULL, 0) != 0) + && probe_pat->exec (probe->name, 0, NULL, 0) != 0) continue; bound.objfile = objfile; @@ -339,7 +339,6 @@ collect_probes (char *objname, char *provider, char *probe_name, } } - do_cleanups (cleanup_temps); discard_cleanups (cleanup); return result; } diff --git a/gdb/skip.c b/gdb/skip.c index 4bd8a9e1c2..e767f83ac1 100644 --- a/gdb/skip.c +++ b/gdb/skip.c @@ -34,6 +34,7 @@ #include "filenames.h" #include "fnmatch.h" #include "gdb_regex.h" +#include "common/gdb_optional.h" struct skiplist_entry { @@ -57,10 +58,7 @@ struct skiplist_entry char *function; /* If this is a function regexp, the compiled form. */ - regex_t compiled_function_regexp; - - /* Non-zero if the function regexp has been compiled. */ - int compiled_function_regexp_is_valid; + gdb::optional compiled_function_regexp; int enabled; @@ -112,8 +110,6 @@ 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); } @@ -202,7 +198,6 @@ skip_function_command (char *arg, int from_tty) static void compile_skip_regexp (struct skiplist_entry *e, const char *message) { - int code; int flags = REG_NOSUB; #ifdef REG_EXTENDED @@ -210,16 +205,7 @@ compile_skip_regexp (struct skiplist_entry *e, const char *message) #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; + e->compiled_function_regexp.emplace (e->function, flags, message); } /* Process "skip ..." that does not match "skip file" or "skip function". */ @@ -601,8 +587,8 @@ static int skip_rfunction_p (struct skiplist_entry *e, const char *function_name) { gdb_assert (e->function != NULL && e->function_is_regexp - && e->compiled_function_regexp_is_valid); - return (regexec (&e->compiled_function_regexp, function_name, 0, NULL, 0) + && e->compiled_function_regexp); + return (e->compiled_function_regexp->exec (function_name, 0, NULL, 0) == 0); } diff --git a/gdb/symtab.c b/gdb/symtab.c index 22d81fafb8..f1daf8cd6e 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -62,6 +62,7 @@ #include "parser-defs.h" #include "completer.h" #include "progspace-and-thread.h" +#include "common/gdb_optional.h" /* Forward declarations for local functions. */ @@ -4299,9 +4300,7 @@ search_symbols (const char *regexp, enum search_domain kind, struct symbol_search *found; struct symbol_search *tail; int nfound; - /* This is true if PREG contains valid data, false otherwise. */ - bool preg_p; - regex_t preg; + gdb::optional preg; /* OLD_CHAIN .. RETVAL_CHAIN is always freed, RETVAL_CHAIN .. current CLEANUP_CHAIN is freed only in the case of an error. */ @@ -4316,7 +4315,6 @@ search_symbols (const char *regexp, enum search_domain kind, ourtype4 = types4[kind]; *matches = NULL; - preg_p = false; if (regexp != NULL) { @@ -4355,18 +4353,9 @@ search_symbols (const char *regexp, enum search_domain kind, } } - errcode = regcomp (&preg, regexp, - REG_NOSUB | (case_sensitivity == case_sensitive_off - ? REG_ICASE : 0)); - if (errcode != 0) - { - char *err = get_regcomp_error (errcode, &preg); - - make_cleanup (xfree, err); - error (_("Invalid regexp (%s): %s"), err, regexp); - } - preg_p = true; - make_regfree_cleanup (&preg); + int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off + ? REG_ICASE : 0); + preg.emplace (regexp, cflags, _("Invalid regexp")); } /* Search through the partial symtabs *first* for all symbols @@ -4379,8 +4368,8 @@ search_symbols (const char *regexp, enum search_domain kind, }, [&] (const char *symname) { - return (!preg_p || regexec (&preg, symname, - 0, NULL, 0) == 0); + return (!preg || preg->exec (symname, + 0, NULL, 0) == 0); }, NULL, kind); @@ -4415,9 +4404,9 @@ search_symbols (const char *regexp, enum search_domain kind, || MSYMBOL_TYPE (msymbol) == ourtype3 || MSYMBOL_TYPE (msymbol) == ourtype4) { - if (!preg_p - || regexec (&preg, MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) + if (!preg + || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, + NULL, 0) == 0) { /* Note: An important side-effect of these lookup functions is to expand the symbol table if msymbol is found, for the @@ -4459,9 +4448,9 @@ search_symbols (const char *regexp, enum search_domain kind, files, nfiles, 1)) && file_matches (symtab_to_fullname (real_symtab), files, nfiles, 0))) - && ((!preg_p - || regexec (&preg, SYMBOL_NATURAL_NAME (sym), 0, - NULL, 0) == 0) + && ((!preg + || preg->exec (SYMBOL_NATURAL_NAME (sym), 0, + NULL, 0) == 0) && ((kind == VARIABLES_DOMAIN && SYMBOL_CLASS (sym) != LOC_TYPEDEF && SYMBOL_CLASS (sym) != LOC_UNRESOLVED @@ -4517,9 +4506,8 @@ search_symbols (const char *regexp, enum search_domain kind, || MSYMBOL_TYPE (msymbol) == ourtype3 || MSYMBOL_TYPE (msymbol) == ourtype4) { - if (!preg_p - || regexec (&preg, MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) + if (!preg || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, + NULL, 0) == 0) { /* For functions we can do a quick check of whether the symbol might be found via find_pc_symtab. */ diff --git a/gdb/utils.c b/gdb/utils.c index b4332f83b7..88a178930e 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1038,58 +1038,6 @@ make_hex_string (const gdb_byte *data, size_t length) -/* A cleanup function that calls regfree. */ - -static void -do_regfree_cleanup (void *r) -{ - regfree ((regex_t *) r); -} - -/* Create a new cleanup that frees the compiled regular expression R. */ - -struct cleanup * -make_regfree_cleanup (regex_t *r) -{ - return make_cleanup (do_regfree_cleanup, r); -} - -/* Return an xmalloc'd error message resulting from a regular - expression compilation failure. */ - -char * -get_regcomp_error (int code, regex_t *rx) -{ - size_t length = regerror (code, rx, NULL, 0); - char *result = (char *) xmalloc (length); - - regerror (code, rx, result, length); - return result; -} - -/* Compile a regexp and throw an exception on error. This returns a - cleanup to free the resulting pattern on success. RX must not be - NULL. */ - -struct cleanup * -compile_rx_or_error (regex_t *pattern, const char *rx, const char *message) -{ - int code; - - gdb_assert (rx != NULL); - - code = regcomp (pattern, rx, REG_NOSUB); - if (code != 0) - { - char *err = get_regcomp_error (code, pattern); - - make_cleanup (xfree, err); - error (("%s: %s"), message, err); - } - - return make_regfree_cleanup (pattern); -} - /* A cleanup that simply calls ui_unregister_input_event_handler. */ static void -- 2.34.1