This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: fix PR 1535


>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> This patch fixes PR 1535.
Tom> The bug here is that CLI tab completion does not work for "catch"
Tom> commands.

After sending this I noticed a gettext snafu in the
DEFINE_UNIMPLEMENTED macro -- stringization can't reasonably work
here.

The fix is to change the error call to use %s instead.

I ran 'make gdb.pot' and looked at the result to verify that this
change worked.

Tom

2008-08-12  Tom Tromey  <tromey@redhat.com>

	PR gdb/1535:
	* breakpoint.c (ep_find_event_name_end): Remove.
	(catch_fork_command_1): Handle NULL 'arg'.
	(catch_exec_command): Rename from catch_exec_command_1.  Handle
	NULL 'arg'.
	(catch_load_command): Rename from catch_load_command_1.  Handle
	NULL 'arg'.
	(catch_unload_command): Rename from catch_unload_command_1.
	Handle NULL 'arg'.
	(catch_exception_command_1): Handle NULL 'arg'.
	(catch_exception_command): Rename from
	catch_ada_exception_command.  Handle NULL 'arg'.
	(catch_assert_command): Handle NULL 'arg'.
	(catch_catch_command): New function.
	(catch_throw_command): Likewise.
	(catch_fork_command): Likewise.
	(catch_vfork_command): Likewise.
	(TABLE): New macro.
	(UNIMPLEMENTED_NAME): Likewise.
	(DEFINE_UNIMPLEMENTED): Likewise.
	(DEFINE_ONE_CATCH_FUNCTION): Likewise.
	(DEFINE_NORMAL): Likewise.
	(ENTRY): Likewise.
	(struct catch_handler_entry): New type.
	(NORMAL_NAME): New define.
	(permanent_catch_entries): New global.
	(temporary_catch_entries): Likewise.
	(catch_command_1): Remove.
	(catch_command): Just call error.
	(tcatch_command): Likewise.
	(catch_cmdlist): New global.
	(tcatch_cmdlist): Likewise.
	(add_catch_commands): New function.
	(_initialize_breakpoint): Use add_catch_commands.  Create "catch"
	and "tcatch" as prefix commands.

2008-08-12  Tom Tromey  <tromey@redhat.com>

	* gdb.base/help.exp (help catch): Rewrite.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 2a10d61..e49530d 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -61,8 +61,6 @@
 
 /* Prototypes for local functions. */
 
-static void catch_command_1 (char *, int, int);
-
 static void enable_delete_command (char *, int);
 
 static void enable_delete_breakpoint (struct breakpoint *);
@@ -167,8 +165,6 @@ static void stopin_command (char *arg, int from_tty);
 
 static void stopat_command (char *arg, int from_tty);
 
-static char *ep_find_event_name_end (char *arg);
-
 static char *ep_parse_optional_if_clause (char **arg);
 
 static char *ep_parse_optional_filename (char **arg);
@@ -6251,36 +6247,6 @@ ep_skip_leading_whitespace (char **s)
     *s += 1;
 }
 
-/* This function examines a string, and attempts to find a token
-   that might be an event name in the leading characters.  If a
-   possible match is found, a pointer to the last character of
-   the token is returned.  Else, NULL is returned. */
-
-static char *
-ep_find_event_name_end (char *arg)
-{
-  char *s = arg;
-  char *event_name_end = NULL;
-
-  /* If we could depend upon the presense of strrpbrk, we'd use that... */
-  if (arg == NULL)
-    return NULL;
-
-  /* We break out of the loop when we find a token delimiter.
-     Basically, we're looking for alphanumerics and underscores;
-     anything else delimites the token. */
-  while (*s != '\0')
-    {
-      if (!isalnum (*s) && (*s != '_'))
-	break;
-      event_name_end = s;
-      s++;
-    }
-
-  return event_name_end;
-}
-
-
 /* This function attempts to parse an optional "if <cond>" clause
    from the arg string.  If one is not found, it returns NULL.
 
@@ -6362,6 +6328,8 @@ catch_fork_command_1 (catch_fork_kind fork_kind, char *arg, int tempflag,
 {
   char *cond_string = NULL;
 
+  if (!arg)
+    arg = "";
   ep_skip_leading_whitespace (&arg);
 
   /* The allowed syntax is:
@@ -6391,10 +6359,12 @@ catch_fork_command_1 (catch_fork_kind fork_kind, char *arg, int tempflag,
 }
 
 static void
-catch_exec_command_1 (char *arg, int tempflag, int from_tty)
+catch_exec_command (char *arg, int tempflag, int from_tty)
 {
   char *cond_string = NULL;
 
+  if (!arg)
+    arg = "";
   ep_skip_leading_whitespace (&arg);
 
   /* The allowed syntax is:
@@ -6413,11 +6383,13 @@ catch_exec_command_1 (char *arg, int tempflag, int from_tty)
 }
 
 static void
-catch_load_command_1 (char *arg, int tempflag, int from_tty)
+catch_load_command (char *arg, int tempflag, int from_tty)
 {
   char *dll_pathname = NULL;
   char *cond_string = NULL;
 
+  if (!arg)
+    arg = "";
   ep_skip_leading_whitespace (&arg);
 
   /* The allowed syntax is:
@@ -6455,11 +6427,13 @@ catch_load_command_1 (char *arg, int tempflag, int from_tty)
 }
 
 static void
-catch_unload_command_1 (char *arg, int tempflag, int from_tty)
+catch_unload_command (char *arg, int tempflag, int from_tty)
 {
   char *dll_pathname = NULL;
   char *cond_string = NULL;
 
+  if (!arg)
+    arg = "";
   ep_skip_leading_whitespace (&arg);
 
   /* The allowed syntax is:
@@ -6598,6 +6572,8 @@ catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
   char *cond_string = NULL;
   struct symtab_and_line *sal = NULL;
 
+  if (!arg)
+    arg = "";
   ep_skip_leading_whitespace (&arg);
 
   cond_string = ep_parse_optional_if_clause (&arg);
@@ -6664,7 +6640,7 @@ create_ada_exception_breakpoint (struct symtab_and_line sal,
 /* Implement the "catch exception" command.  */
 
 static void
-catch_ada_exception_command (char *arg, int tempflag, int from_tty)
+catch_exception_command (char *arg, int tempflag, int from_tty)
 {
   struct symtab_and_line sal;
   enum bptype type;
@@ -6674,6 +6650,8 @@ catch_ada_exception_command (char *arg, int tempflag, int from_tty)
   struct expression *cond = NULL;
   struct breakpoint_ops *ops = NULL;
 
+  if (!arg)
+    arg = "";
   sal = ada_decode_exception_location (arg, &addr_string, &exp_string,
                                        &cond_string, &cond, &ops);
   create_ada_exception_breakpoint (sal, addr_string, exp_string,
@@ -6690,132 +6668,161 @@ catch_assert_command (char *arg, int tempflag, int from_tty)
   char *addr_string = NULL;
   struct breakpoint_ops *ops = NULL;
 
+  if (!arg)
+    arg = "";
   sal = ada_decode_assert_location (arg, &addr_string, &ops);
   create_ada_exception_breakpoint (sal, addr_string, NULL, NULL, NULL, ops,
                                    tempflag, from_tty);
 }
 
+/* Implement the "catch catch" command.  */
+
 static void
-catch_command_1 (char *arg, int tempflag, int from_tty)
+catch_catch_command (char *arg, int tempflag, int from_tty)
 {
+  catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
+}
 
-  /* The first argument may be an event name, such as "start" or "load".
-     If so, then handle it as such.  If it doesn't match an event name,
-     then attempt to interpret it as an exception name.  (This latter is
-     the v4.16-and-earlier GDB meaning of the "catch" command.)
+/* Implement the "catch throw" command.  */
 
-     First, try to find the bounds of what might be an event name. */
-  char *arg1_start = arg;
-  char *arg1_end;
-  int arg1_length;
+static void
+catch_throw_command (char *arg, int tempflag, int from_tty)
+{
+  catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
+}
 
-  if (arg1_start == NULL)
-    {
-      /* Old behaviour was to use pre-v-4.16 syntax */
-      /* catch_throw_command_1 (arg1_start, tempflag, from_tty); */
-      /* return; */
-      /* Now, this is not allowed */
-      error (_("Catch requires an event name."));
+/* Implement the "catch fork" command.  */
 
-    }
-  arg1_end = ep_find_event_name_end (arg1_start);
-  if (arg1_end == NULL)
-    error (_("catch requires an event"));
-  arg1_length = arg1_end + 1 - arg1_start;
+static void
+catch_fork_command (char *arg, int tempflag, int from_tty)
+{
+  catch_fork_command_1 (catch_fork, arg, tempflag, from_tty);
+}
 
-  /* Try to match what we found against known event names. */
-  if (strncmp (arg1_start, "signal", arg1_length) == 0)
-    {
-      error (_("Catch of signal not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "catch", arg1_length) == 0)
-    {
-      catch_exception_command_1 (EX_EVENT_CATCH, arg1_end + 1, 
-				 tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "throw", arg1_length) == 0)
-    {
-      catch_exception_command_1 (EX_EVENT_THROW, arg1_end + 1, 
-				 tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "thread_start", arg1_length) == 0)
-    {
-      error (_("Catch of thread_start not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "thread_exit", arg1_length) == 0)
-    {
-      error (_("Catch of thread_exit not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "thread_join", arg1_length) == 0)
-    {
-      error (_("Catch of thread_join not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "start", arg1_length) == 0)
-    {
-      error (_("Catch of start not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "exit", arg1_length) == 0)
-    {
-      error (_("Catch of exit not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "fork", arg1_length) == 0)
-    {
-      catch_fork_command_1 (catch_fork, arg1_end + 1, tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "vfork", arg1_length) == 0)
-    {
-      catch_fork_command_1 (catch_vfork, arg1_end + 1, tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "exec", arg1_length) == 0)
-    {
-      catch_exec_command_1 (arg1_end + 1, tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "load", arg1_length) == 0)
-    {
-      catch_load_command_1 (arg1_end + 1, tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "unload", arg1_length) == 0)
-    {
-      catch_unload_command_1 (arg1_end + 1, tempflag, from_tty);
-    }
-  else if (strncmp (arg1_start, "stop", arg1_length) == 0)
-    {
-      error (_("Catch of stop not yet implemented"));
-    }
-  else if (strncmp (arg1_start, "exception", arg1_length) == 0)
-    {
-      catch_ada_exception_command (arg1_end + 1, tempflag, from_tty);
-    }
+/* Implement the "catch vfork" command.  */
 
-  else if (strncmp (arg1_start, "assert", arg1_length) == 0)
-    {
-      catch_assert_command (arg1_end + 1, tempflag, from_tty);
-    }
+static void
+catch_vfork_command (char *arg, int tempflag, int from_tty)
+{
+  catch_fork_command_1 (catch_vfork, arg, tempflag, from_tty);
+}
+
+/* A table holding information about all "catch" events.  Each entry
+   holds the name of the event, whether the event is implemented or
+   not, and documentation for the event.  */
+#define TABLE								\
+  ENTRY (signal, UNIMPLEMENTED, N_("Catch signals."))			\
+  ENTRY (thread_start, UNIMPLEMENTED, N_("Catch thread start."))	\
+  ENTRY (thread_exit, UNIMPLEMENTED, N_("Catch thread exit."))		\
+  ENTRY (thread_join, UNIMPLEMENTED, N_("Catch thread after a join."))	\
+  ENTRY (start, UNIMPLEMENTED, N_("Catch process at creation."))	\
+  ENTRY (stop, UNIMPLEMENTED, N_("Catch program stopping."))		\
+  ENTRY (catch, NORMAL, N_("Catch an exception, when caught.\n\
+With an argument, catch only exceptions with the given name."))		\
+  ENTRY (throw, NORMAL, N_("Catch an exception, when thrown.\n\
+With an exception, catch only exceptions with the given name."))	\
+  ENTRY (fork, NORMAL, N_("Catch calls to fork."))			\
+  ENTRY (vfork, NORMAL, N_("Catch calls to vfork."))			\
+  ENTRY (exec, NORMAL, N_("Catch calls to exec."))			\
+  ENTRY (load, NORMAL, N_("Catch library loads.\n\
+With an argument, catch only loads of that library."))			\
+  ENTRY (unload, NORMAL, N_("Catch library unloads.\n\
+With an argument, catch only unloads of that library."))		\
+  ENTRY (exception, NORMAL, N_("Catch Ada exceptions, when raised.\n\
+With an argument, catch only exceptions with the given name."))		\
+  ENTRY (assert, NORMAL, N_("Catch failed Ada assertions, when raised.\n\
+With an argument, catch only exceptions with the given name."))
+
+/* This macro computes the name of a function which is used for an
+   unimplemented catch command.  */
+#define UNIMPLEMENTED_NAME(NAME) unimplemented_catch_ ## NAME
+
+/* Define a new function for an unimplemented catch event.  */
+#define DEFINE_UNIMPLEMENTED(NAME)					\
+    static void UNIMPLEMENTED_NAME (NAME) (char *arg, int from_tty)	\
+    {									\
+      error (_("Catch of %s not yet implemented"), #NAME);		\
+    }
+
+/* Define a new function that calls a catch handler function with an
+   extra argument.  */
+#define DEFINE_ONE_CATCH_FUNCTION(NAME, TEMP)				\
+    static void do_catch_ ## NAME ## TEMP (char *arg, int from_tty)	\
+    {									\
+      catch_ ## NAME ## _command (arg, TEMP, from_tty);			\
+    }
+
+/* Define a pair of catch functions, one temporary, one not.  */
+#define DEFINE_NORMAL(NAME) \
+  DEFINE_ONE_CATCH_FUNCTION (NAME, 0) \
+  DEFINE_ONE_CATCH_FUNCTION (NAME, 1)
+
+/* This is used to expand all the "catch" commands into a series of
+   function definitions.  */
+#define ENTRY(NAME, TYPE, DOC)  DEFINE_ ## TYPE (NAME)
+
+/* Emit all function definitions.  */
+TABLE
+
+/* This is the type of a single entry in a table of "catch" event
+   commands.  */
+struct catch_handler_entry
+{
+  /* Name of the command.  */
+  char *name;
+  /* Documentation for the command.  */
+  char *doc;
+  /* Function which implements the command.  */
+  void (*handler) (char *arg, int from_tty);
+};
 
-  /* This doesn't appear to be an event name */
+/* How to compute the name of the function which implements an
+   ordinary, permanent catch event.  */
+#define NORMAL_NAME(NAME) do_catch_ ## NAME ## 0
 
-  else
-    {
-      /* Pre-v.4.16 behaviour was to treat the argument
-         as the name of an exception */
-      /* catch_throw_command_1 (arg1_start, tempflag, from_tty); */
-      /* Now this is not allowed */
-      error (_("Unknown event kind specified for catch"));
+/* Redefine ENTRY so that it expands to a struct catch_handler_entry.  */
+#undef ENTRY
+#define ENTRY(NAME, TYPE, DOC)					\
+  { #NAME, DOC, TYPE ## _NAME (NAME) },
 
-    }
-}
+/* All the "catch" commands.  */
+static struct catch_handler_entry permanent_catch_entries[] =
+{
+  TABLE
+  { NULL, NULL, NULL }
+};  
+
+/* How to compute the name of the function which implements an
+   ordinary, temporary catch event.  */
+#undef NORMAL_NAME
+#define NORMAL_NAME(NAME) do_catch_ ## NAME ## 1
+
+/* All the "tcatch" commands.  */
+static struct catch_handler_entry temporary_catch_entries[] =
+{
+  TABLE
+  { NULL, NULL, NULL }
+};  
+
+#undef ENTRY
+#undef NORMAL_NAME
+#undef DEFINE_NORMAL
+#undef DEFINE_ONE_CATCH_FUNCTION
+#undef DEFINE_UNIMPLEMENTED
+#undef UNIMPLEMENTED_NAME
+#undef TABLE
 
 static void
 catch_command (char *arg, int from_tty)
 {
-  catch_command_1 (arg, 0, from_tty);
+  error (_("Catch requires an event name."));
 }
 
 
 static void
 tcatch_command (char *arg, int from_tty)
 {
-  catch_command_1 (arg, 1, from_tty);
+  error (_("Catch requires an event name."));
 }
 
 /* Delete breakpoints by address or line.  */
@@ -8222,6 +8229,24 @@ Multiple breakpoints at one place are permitted, and useful if conditional.\n\
 \n\
 Do \"help breakpoints\" for info on other commands dealing with breakpoints."
 
+/* List of subcommands for "catch".  */
+static struct cmd_list_element *catch_cmdlist;
+
+/* List of subcommands for "tcatch".  */
+static struct cmd_list_element *tcatch_cmdlist;
+
+/* Add all the catch commands from TABLE to CMDLIST.  */
+static void
+add_catch_commands (struct cmd_list_element **cmdlist,
+		    struct catch_handler_entry *table)
+{
+  int i;
+
+  for (i = 0; table[i].name; ++i)
+    add_cmd (table[i].name, class_breakpoint, table[i].handler,
+	     _(table[i].doc), cmdlist);
+}
+
 void
 _initialize_breakpoint (void)
 {
@@ -8479,52 +8504,17 @@ Convenience variable \"$bpnum\" contains the number of the last\n\
 breakpoint set."),
 	   &maintenanceinfolist);
 
-  add_com ("catch", class_breakpoint, catch_command, _("\
-Set catchpoints to catch events.\n\
-Raised signals may be caught:\n\
-\tcatch signal              - all signals\n\
-\tcatch signal <signame>    - a particular signal\n\
-Raised exceptions may be caught:\n\
-\tcatch throw               - all exceptions, when thrown\n\
-\tcatch throw <exceptname>  - a particular exception, when thrown\n\
-\tcatch catch               - all exceptions, when caught\n\
-\tcatch catch <exceptname>  - a particular exception, when caught\n\
-Thread or process events may be caught:\n\
-\tcatch thread_start        - any threads, just after creation\n\
-\tcatch thread_exit         - any threads, just before expiration\n\
-\tcatch thread_join         - any threads, just after joins\n\
-Process events may be caught:\n\
-\tcatch start               - any processes, just after creation\n\
-\tcatch exit                - any processes, just before expiration\n\
-\tcatch fork                - calls to fork()\n\
-\tcatch vfork               - calls to vfork()\n\
-\tcatch exec                - calls to exec()\n\
-Dynamically-linked library events may be caught:\n\
-\tcatch load                - loads of any library\n\
-\tcatch load <libname>      - loads of a particular library\n\
-\tcatch unload              - unloads of any library\n\
-\tcatch unload <libname>    - unloads of a particular library\n\
-The act of your program's execution stopping may also be caught:\n\
-\tcatch stop\n\n\
-C++ exceptions may be caught:\n\
-\tcatch throw               - all exceptions, when thrown\n\
-\tcatch catch               - all exceptions, when caught\n\
-Ada exceptions may be caught:\n\
-\tcatch exception           - all exceptions, when raised\n\
-\tcatch exception <name>    - a particular exception, when raised\n\
-\tcatch exception unhandled - all unhandled exceptions, when raised\n\
-\tcatch assert              - all failed assertions, when raised\n\
-\n\
-Do \"help set follow-fork-mode\" for info on debugging your program\n\
-after a fork or vfork is caught.\n\n\
-Do \"help breakpoints\" for info on other commands dealing with breakpoints."));
-
-  add_com ("tcatch", class_breakpoint, tcatch_command, _("\
-Set temporary catchpoints to catch events.\n\
-Args like \"catch\" command.\n\
-Like \"catch\" except the catchpoint is only temporary,\n\
-so it will be deleted when hit.  Equivalent to \"catch\" followed\n\
-by using \"enable delete\" on the catchpoint number."));
+  add_prefix_cmd ("catch", class_breakpoint, catch_command, _("\
+Set catchpoints to catch events."),
+		  &catch_cmdlist, "catch ",
+		  0/*allow-unknown*/, &cmdlist);
+  add_catch_commands (&catch_cmdlist, permanent_catch_entries);
+
+  add_prefix_cmd ("tcatch", class_breakpoint, tcatch_command, _("\
+Set temporary catchpoints to catch events."),
+		  &tcatch_cmdlist, "tcatch ",
+		  0/*allow-unknown*/, &cmdlist);
+  add_catch_commands (&tcatch_cmdlist, temporary_catch_entries);
 
   c = add_com ("watch", class_breakpoint, watch_command, _("\
 Set a watchpoint for an expression.\n\
diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp
index c427b31..ef07667 100644
--- a/gdb/testsuite/gdb.base/help.exp
+++ b/gdb/testsuite/gdb.base/help.exp
@@ -68,7 +68,7 @@ gdb_test "help continue" "Continue program being debugged.*" "help continue"
 # test help call
 gdb_test "help call" "Call a function.*" "help call"
 # test help catch
-gdb_test "help catch" "Set catchpoints to catch events.*Raised signals may be caught:.*catch signal.*all signals.*catch signal.*signame.*a particular signal.*Raised exceptions may be caught:.*catch throw.*all exceptions, when thrown.*catch throw.*exceptname.*a particular exception, when thrown.*catch catch.*all exceptions, when caught.*catch catch.*exceptname.*a particular exception, when caught.*Thread or process events may be caught:.*catch thread_start.*any threads, just after creation.*catch thread_exit.*any threads, just before expiration.*catch thread_join.*any threads, just after joins.*catch start.*any processes, just after creation.*catch exit.*any processes, just before expiration.*catch fork.*calls to fork.*catch vfork.*calls to vfork.*catch exec.*calls to exec.*Dynamically.linked library events may be caught:.*catch load.*loads of any library.*catch load.*libname.*loads of a particular library.*catch unload.*unloads of any library.*catch unload.*libname.*unloads of a particular library.*The act of your program's execution stopping may also be caught:.*catch stop.*Do.*help set follow-fork-mode.*for info on debugging your program.*after a fork or vfork is caught.*Do.*help breakpoints.*for info on other commands dealing with breakpoints." "help catch"
+gdb_test "help catch" "Set catchpoints to catch events.*List of catch subcommands:.*catch assert -- Catch failed Ada assertions.*catch catch -- Catch an exception.*catch exception -- Catch Ada exceptions.*catch exec -- Catch calls to exec.*catch fork -- Catch calls to fork.*catch load -- Catch library loads.*catch signal -- Catch signals.*catch start -- Catch process at creation.*catch stop -- Catch program stopping.*catch thread_exit -- Catch thread exit.*catch thread_join -- Catch thread after a join.*catch thread_start -- Catch thread start.*catch throw -- Catch an exception.*catch unload -- Catch library unloads.*catch vfork -- Catch calls to vfork.*Type .help catch. followed by catch subcommand name for full documentation.*Type .apropos word. to search for commands related to .word..*Command name abbreviations are allowed if unambiguous.*" "help catch"
 # test help cd
 gdb_test "help cd" "Set working directory to DIR for debugger and program being debugged\.\[\r\n\]+The change does not take effect for the program being debugged\[\r\n\]+until the next time it is started\." "help cd"
 # test help clear


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]