Introduce compiled_regex, eliminate make_regfree_cleanup
authorPedro Alves <palves@redhat.com>
Wed, 7 Jun 2017 13:21:40 +0000 (14:21 +0100)
committerPedro Alves <palves@redhat.com>
Wed, 7 Jun 2017 13:21:40 +0000 (14:21 +0100)
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  <palves@redhat.com>

* 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<compiled_regex>.
(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<compiled_regex>.
(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<compiled_regex>.
(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.

15 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/ada-lang.c
gdb/break-catch-throw.c
gdb/breakpoint.c
gdb/cli/cli-cmds.c
gdb/cli/cli-decode.c
gdb/cli/cli-decode.h
gdb/gdb_regex.c [new file with mode: 0644]
gdb/gdb_regex.h
gdb/linux-tdep.c
gdb/probe.c
gdb/skip.c
gdb/symtab.c
gdb/utils.c

index 31904109a7ed0640bac5acf658f69cf597ec2f97..6424388711b240018f782ea6cbf7a2198c962fbe 100644 (file)
@@ -1,3 +1,54 @@
+2017-06-07  Pedro Alves  <palves@redhat.com>
+
+       * 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<compiled_regex>.
+       (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<compiled_regex>.
+       (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<compiled_regex>.
+       (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  <alan.hayward@arm.com>
 
        * regcache.c (regcache::save): Avoid buffer use.
index 8be73ba423d9f2e76e8cc32876c55ec62ea8d962..2156438c1b61642689bf8c33eedb3a0b460e0fdd 100644 (file)
@@ -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 \
index f90907a928ccdd351bada58ef5149a00f17a585d..57c670e8d6163bc98448640abdbba5ea4cf51a85 100644 (file)
@@ -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 (&reg, regexp,
-                                    _("invalid regular expression"));
+  if (regexp == NULL)
+    return ada_exceptions_list_1 (NULL);
 
-  result = ada_exceptions_list_1 (regexp != NULL ? &reg : 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 (&reg);
 }
 
 /* Implement the "info exceptions" command.  */
index 7731c5e5b6f6a11b647a820ad2c4069476eaf637..0074d061f24e396f0cb60b63aff9ab15efc4b0d2 100644 (file)
@@ -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<compiled_regex> pattern;
 };
 
 \f
@@ -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<compiled_regex> 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<exception_catchpoint> 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 ());
 
index e84d1642a4d73572e8bd0d5869c1fef98a9bbd6f..053ccef0fa2c081b46beb4fe8d9a5609135ee7eb 100644 (file)
@@ -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_regex> 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);
     }
 
index 2a5b128d5699014dbabbe439693dc7801e7165ce..09303423bf0391a36a1de8b8ae91d74497cddc58 100644 (file)
@@ -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.
index d386d0296f4f1897c6d4d0d09067a93b7cad6c80..383adf8b1ac496a4ddb248265d294b8099afcacc 100644 (file)
@@ -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 &regex, 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);
index 66159fd4a4112f782f3aa7e7410c33376a4358e4..11248baa96e344e491b4bfad526912da42b1c62a 100644 (file)
@@ -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 (file)
index 0000000..2e376e3
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.  */
+
+#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<char[]> 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);
+}
index 0be26efd905f47560eefe8a6c54640f5832f5061..f62f81d36644f03967f340a06c87ddfcbfe162f6 100644 (file)
 # include <regex.h>
 #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 */
index 016aadff6b475a69968213c56861706f5da0d91e..1afa8d7b3572899ca24978fc476075b09809e475 100644 (file)
@@ -38,6 +38,7 @@
 #include "gdbcmd.h"
 #include "gdb_regex.h"
 #include "common/enum-flags.h"
+#include "common/gdb_optional.h"
 
 #include <ctype.h>
 
@@ -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 '<file> (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<mapping_regexes> 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 "
-                            "'<file> (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;
index e65e0313fe64993cc3872f40c5888e8845ff8624..cb2dcdb35918364cdb010e0e9896dc0ed394cf55 100644 (file)
@@ -36,6 +36,7 @@
 #include "location.h"
 #include <ctype.h>
 #include <algorithm>
+#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<compiled_regex> 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;
 }
index 4bd8a9e1c280cef6c9476e6b6880692d7d9ad059..e767f83ac1cb594aec49f22dea793e36b1b974da 100644 (file)
@@ -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_regex> 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);
 }
 
index 22d81fafb83b24c9e2a43f5224013b8ccc5a3853..f1daf8cd6e9a8b8d565250970fbd66c09b89977c 100644 (file)
@@ -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<compiled_regex> 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.  */
index b4332f83b72758e906b5dee03b6ff76a727d6694..88a178930e11c84444521c5a5e96bb8c09eefa0f 100644 (file)
@@ -1038,58 +1038,6 @@ make_hex_string (const gdb_byte *data, size_t length)
 
 \f
 
-/* 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