enum exception_event_kind
{
EX_EVENT_THROW,
+ EX_EVENT_RETHROW,
EX_EVENT_CATCH
};
static void stopat_command (char *arg, int from_tty);
-static char *ep_parse_optional_if_clause (char **arg);
-
-static void catch_exception_command_1 (enum exception_event_kind ex_event,
- char *arg, int tempflag, int from_tty);
-
static void tcatch_command (char *arg, int from_tty);
static void detach_single_step_breakpoints (void);
}
else
{
- char *arg = exp;
+ const char *arg = exp;
/* I don't know if it matters whether this is the string the user
typed in or the decompiled expression. */
/* Completion for the "condition" command. */
static VEC (char_ptr) *
-condition_completer (struct cmd_list_element *cmd, char *text, char *word)
+condition_completer (struct cmd_list_element *cmd,
+ const char *text, const char *word)
{
- char *space;
+ const char *space;
- text = skip_spaces (text);
- space = skip_to_space (text);
+ text = skip_spaces_const (text);
+ space = skip_to_space_const (text);
if (*space == '\0')
{
int len;
}
/* We're completing the expression part. */
- text = skip_spaces (space);
+ text = skip_spaces_const (space);
return expression_completer (cmd, text, word);
}
{
if (is_tracepoint (b))
{
- /* We need to verify that each top-level element of commands is
- valid for tracepoints, that there's at most one
- while-stepping element, and that while-stepping's body has
- valid tracing commands excluding nested while-stepping. */
+ struct tracepoint *t = (struct tracepoint *) b;
struct command_line *c;
struct command_line *while_stepping = 0;
+
+ /* Reset the while-stepping step count. The previous commands
+ might have included a while-stepping action, while the new
+ ones might not. */
+ t->step_count = 0;
+
+ /* We need to verify that each top-level element of commands is
+ valid for tracepoints, that there's at most one
+ while-stepping element, and that the while-stepping's body
+ has valid tracing commands excluding nested while-stepping.
+ We also need to validate the tracepoint action line in the
+ context of the tracepoint --- validate_actionline actually
+ has side effects, like setting the tracepoint's
+ while-stepping STEP_COUNT, in addition to checking if the
+ collect/teval actions parse and make sense in the
+ tracepoint's context. */
for (c = commands; c; c = c->next)
{
if (c->control_type == while_stepping_control)
else
while_stepping = c;
}
+
+ validate_actionline (c->line, b);
}
if (while_stepping)
{
{
struct breakpoint *b = closure;
- validate_actionline (&line, b);
+ validate_actionline (line, b);
}
/* A structure used to pass information through
if (within_current_scope && reparse)
{
- char *s;
+ const char *s;
if (b->exp)
{
parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond)
{
struct agent_expr *aexpr = NULL;
- struct cleanup *old_chain = NULL;
volatile struct gdb_exception ex;
if (!cond)
struct cleanup *old_cleanups = 0;
struct expression *expr, **argvec;
struct agent_expr *aexpr = NULL;
- struct cleanup *old_chain = NULL;
volatile struct gdb_exception ex;
- char *cmdrest;
- char *format_start, *format_end;
+ const char *cmdrest;
+ const char *format_start, *format_end;
struct format_piece *fpieces;
int nargs;
struct gdbarch *gdbarch = get_current_arch ();
if (*cmdrest == ',')
++cmdrest;
- cmdrest = skip_spaces (cmdrest);
+ cmdrest = skip_spaces_const (cmdrest);
if (*cmdrest++ != '"')
error (_("No format string following the location"));
if (*cmdrest++ != '"')
error (_("Bad format string, non-terminated '\"'."));
- cmdrest = skip_spaces (cmdrest);
+ cmdrest = skip_spaces_const (cmdrest);
if (!(*cmdrest == ',' || *cmdrest == '\0'))
error (_("Invalid argument syntax"));
if (*cmdrest == ',')
cmdrest++;
- cmdrest = skip_spaces (cmdrest);
+ cmdrest = skip_spaces_const (cmdrest);
/* For each argument, make an expression. */
nargs = 0;
while (*cmdrest != '\0')
{
- char *cmd1;
+ const char *cmd1;
cmd1 = cmdrest;
expr = parse_exp_1 (&cmd1, scope, block_for_pc (scope), 1);
{
/* Only go as far as the first NULL bytecode is
located. */
- if (!loc->cond_bytecode)
+ if (loc->cmd_bytecode == NULL)
return;
- free_agent_expr (loc->cond_bytecode);
- loc->cond_bytecode = NULL;
+ free_agent_expr (loc->cmd_bytecode);
+ loc->cmd_bytecode = NULL;
}
}
}
be adding them automatically. Switch terminal for any messages
produced by breakpoint_re_set. */
target_terminal_ours_for_output ();
-#ifdef SOLIB_ADD
- SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
-#else
solib_add (NULL, 0, ¤t_target, auto_solib_add);
-#endif
target_terminal_inferior ();
}
break;
case bp_dprintf:
- this_action = BPSTAT_WHAT_STOP_SILENT;
+ if (bs->stop)
+ this_action = BPSTAT_WHAT_STOP_SILENT;
+ else
+ this_action = BPSTAT_WHAT_SINGLE;
break;
default:
|| (is_tracepoint (b)))
&& loc->pspace == current_program_space
&& !loc->shlib_disabled
-#ifdef PC_SOLIB
- && PC_SOLIB (loc->address)
-#else
&& solib_name_from_address (loc->pspace, loc->address)
-#endif
)
{
loc->shlib_disabled = 1;
if (b->cond_string)
{
- char *arg = b->cond_string;
+ const char *arg = b->cond_string;
+
loc->cond = parse_exp_1 (&arg, loc->address,
block_for_pc (loc->address), 0);
if (*arg)
If no thread is found, *THREAD is set to -1. */
static void
-find_condition_and_thread (char *tok, CORE_ADDR pc,
+find_condition_and_thread (const char *tok, CORE_ADDR pc,
char **cond_string, int *thread, int *task,
char **rest)
{
while (tok && *tok)
{
- char *end_tok;
+ const char *end_tok;
int toklen;
- char *cond_start = NULL;
- char *cond_end = NULL;
+ const char *cond_start = NULL;
+ const char *cond_end = NULL;
- tok = skip_spaces (tok);
+ tok = skip_spaces_const (tok);
if ((*tok == '"' || *tok == ',') && rest)
{
return;
}
- end_tok = skip_to_space (tok);
+ end_tok = skip_to_space_const (tok);
toklen = end_tok - tok;
char *tmptok;
tok = end_tok + 1;
- tmptok = tok;
- *thread = strtol (tok, &tok, 0);
+ *thread = strtol (tok, &tmptok, 0);
if (tok == tmptok)
error (_("Junk after thread keyword."));
if (!valid_thread_id (*thread))
invalid_thread_id_error (*thread);
+ tok = tmptok;
}
else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
{
char *tmptok;
tok = end_tok + 1;
- tmptok = tok;
- *task = strtol (tok, &tok, 0);
+ *task = strtol (tok, &tmptok, 0);
if (tok == tmptok)
error (_("Junk after task keyword."));
if (!valid_task_id (*task))
error (_("Unknown task %d."), *task);
+ tok = tmptok;
}
else if (rest)
{
/* Set a breakpoint. This function is shared between CLI and MI
functions for setting a breakpoint. This function has two major
- modes of operations, selected by the PARSE_CONDITION_AND_THREAD
- parameter. If non-zero, the function will parse arg, extracting
- breakpoint location, address and thread. Otherwise, ARG is just
- the location of breakpoint, with condition and thread specified by
- the COND_STRING and THREAD parameters. If INTERNAL is non-zero,
- the breakpoint number will be allocated from the internal
- breakpoint count. Returns true if any breakpoint was created;
- false otherwise. */
+ modes of operations, selected by the PARSE_ARG parameter. If
+ non-zero, the function will parse ARG, extracting location,
+ condition, thread and extra string. Otherwise, ARG is just the
+ breakpoint's location, with condition, thread, and extra string
+ specified by the COND_STRING, THREAD and EXTRA_STRING parameters.
+ If INTERNAL is non-zero, the breakpoint number will be allocated
+ from the internal breakpoint count. Returns true if any breakpoint
+ was created; false otherwise. */
int
create_breakpoint (struct gdbarch *gdbarch,
char *arg, char *cond_string,
int thread, char *extra_string,
- int parse_condition_and_thread,
+ int parse_arg,
int tempflag, enum bptype type_wanted,
int ignore_count,
enum auto_boolean pending_break_support,
lsal = VEC_index (linespec_sals, canonical.sals, 0);
- if (parse_condition_and_thread)
+ if (parse_arg)
{
char *rest;
/* Here we only parse 'arg' to separate condition
}
else
{
+ if (*arg != '\0')
+ error (_("Garbage '%s' at end of location"), arg);
+
/* Create a private copy of condition string. */
if (cond_string)
{
init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
b->addr_string = copy_arg;
- if (parse_condition_and_thread)
+ if (parse_arg)
b->cond_string = NULL;
else
{
if (sym != NULL)
{
fixup_symbol_section (sym, sal->symtab->objfile);
- sal->section = SYMBOL_OBJ_SECTION (sym);
+ sal->section = SYMBOL_OBJ_SECTION (sal->symtab->objfile, sym);
}
else
{
if we have line numbers but no functions (as can
happen in assembly source). */
- struct minimal_symbol *msym;
+ struct bound_minimal_symbol msym;
struct cleanup *old_chain = save_current_space_and_thread ();
switch_to_program_space_and_thread (sal->pspace);
msym = lookup_minimal_symbol_by_pc (sal->pc);
- if (msym)
- sal->section = SYMBOL_OBJ_SECTION (msym);
+ if (msym.minsym)
+ sal->section = SYMBOL_OBJ_SECTION (msym.objfile, msym.minsym);
do_cleanups (old_chain);
}
case OP_TYPE:
case OP_TYPEOF:
case OP_DECLTYPE:
+ case OP_TYPEID:
case OP_NAME:
case OP_OBJC_NSSTRING:
{
struct cleanup *old_chain;
struct breakpoint *b;
- const struct bp_location *bl;
struct ui_file *stb;
enum print_stop_action result;
struct watchpoint *w;
gdb_assert (bs->bp_location_at != NULL);
- bl = bs->bp_location_at;
b = bs->breakpoint_at;
w = (struct watchpoint *) b;
hw_read: watch read,
hw_access: watch access (read or write) */
static void
-watch_command_1 (char *arg, int accessflag, int from_tty,
+watch_command_1 (const char *arg, int accessflag, int from_tty,
int just_location, int internal)
{
volatile struct gdb_exception e;
const struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
struct value *val, *mark, *result;
struct frame_info *frame;
- char *exp_start = NULL;
- char *exp_end = NULL;
- char *tok, *end_tok;
+ const char *exp_start = NULL;
+ const char *exp_end = NULL;
+ const char *tok, *end_tok;
int toklen = -1;
- char *cond_start = NULL;
- char *cond_end = NULL;
+ const char *cond_start = NULL;
+ const char *cond_end = NULL;
enum bptype bp_type;
int thread = -1;
int pc = 0;
int use_mask = 0;
CORE_ADDR mask = 0;
struct watchpoint *w;
+ char *expression;
+ struct cleanup *back_to;
/* Make sure that we actually have parameters to parse. */
if (arg != NULL && arg[0] != '\0')
{
- char *value_start;
+ const char *value_start;
+
+ exp_end = arg + strlen (arg);
/* Look for "parameter value" pairs at the end
of the arguments string. */
- for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+ for (tok = exp_end - 1; tok > arg; tok--)
{
/* Skip whitespace at the end of the argument list. */
while (tok > arg && (*tok == ' ' || *tok == '\t'))
/* Truncate the string and get rid of the "parameter value" pair before
the arguments string is parsed by the parse_exp_1 function. */
- *tok = '\0';
+ exp_end = tok;
}
}
+ else
+ exp_end = arg;
- /* Parse the rest of the arguments. */
+ /* Parse the rest of the arguments. From here on out, everything
+ is in terms of a newly allocated string instead of the original
+ ARG. */
innermost_block = NULL;
- exp_start = arg;
+ expression = savestring (arg, exp_end - arg);
+ back_to = make_cleanup (xfree, expression);
+ exp_start = arg = expression;
exp = parse_exp_1 (&arg, 0, 0, 0);
exp_end = arg;
/* Remove trailing whitespace from the expression before saving it.
else if (val != NULL)
release_value (val);
- tok = skip_spaces (arg);
- end_tok = skip_to_space (tok);
+ tok = skip_spaces_const (arg);
+ end_tok = skip_to_space_const (tok);
toklen = end_tok - tok;
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
}
install_breakpoint (internal, b, 1);
+ do_cleanups (back_to);
}
/* Return count of debug registers needed to watch the given expression.
it updates arg to point to the first character following the parsed
if clause in the arg string. */
-static char *
+char *
ep_parse_optional_if_clause (char **arg)
{
char *cond_string;
install_breakpoint (0, &c->base, 1);
}
-static enum print_stop_action
-print_it_exception_catchpoint (bpstat bs)
-{
- struct ui_out *uiout = current_uiout;
- struct breakpoint *b = bs->breakpoint_at;
- int bp_temp, bp_throw;
-
- annotate_catchpoint (b->number);
-
- bp_throw = strstr (b->addr_string, "throw") != NULL;
- if (b->loc->address != b->loc->requested_address)
- breakpoint_adjustment_warning (b->loc->requested_address,
- b->loc->address,
- b->number, 1);
- bp_temp = b->disposition == disp_del;
- ui_out_text (uiout,
- bp_temp ? "Temporary catchpoint "
- : "Catchpoint ");
- if (!ui_out_is_mi_like_p (uiout))
- ui_out_field_int (uiout, "bkptno", b->number);
- ui_out_text (uiout,
- bp_throw ? " (exception thrown), "
- : " (exception caught), ");
- if (ui_out_is_mi_like_p (uiout))
- {
- ui_out_field_string (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
- ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
- ui_out_field_int (uiout, "bkptno", b->number);
- }
- return PRINT_SRC_AND_LOC;
-}
-
-static void
-print_one_exception_catchpoint (struct breakpoint *b,
- struct bp_location **last_loc)
-{
- struct value_print_options opts;
- struct ui_out *uiout = current_uiout;
-
- get_user_print_options (&opts);
- if (opts.addressprint)
- {
- annotate_field (4);
- if (b->loc == NULL || b->loc->shlib_disabled)
- ui_out_field_string (uiout, "addr", "<PENDING>");
- else
- ui_out_field_core_addr (uiout, "addr",
- b->loc->gdbarch, b->loc->address);
- }
- annotate_field (5);
- if (b->loc)
- *last_loc = b->loc;
- if (strstr (b->addr_string, "throw") != NULL)
- {
- ui_out_field_string (uiout, "what", "exception throw");
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string (uiout, "catch-type", "throw");
- }
- else
- {
- ui_out_field_string (uiout, "what", "exception catch");
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string (uiout, "catch-type", "catch");
- }
-}
-
-static void
-print_mention_exception_catchpoint (struct breakpoint *b)
-{
- struct ui_out *uiout = current_uiout;
- int bp_temp;
- int bp_throw;
-
- bp_temp = b->disposition == disp_del;
- bp_throw = strstr (b->addr_string, "throw") != NULL;
- ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
- : _("Catchpoint "));
- ui_out_field_int (uiout, "bkptno", b->number);
- ui_out_text (uiout, bp_throw ? _(" (throw)")
- : _(" (catch)"));
-}
-
-/* Implement the "print_recreate" breakpoint_ops method for throw and
- catch catchpoints. */
-
-static void
-print_recreate_exception_catchpoint (struct breakpoint *b,
- struct ui_file *fp)
-{
- int bp_temp;
- int bp_throw;
-
- bp_temp = b->disposition == disp_del;
- bp_throw = strstr (b->addr_string, "throw") != NULL;
- fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
- fprintf_unfiltered (fp, bp_throw ? "throw" : "catch");
- print_recreate_thread (b, fp);
-}
-
-static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;
-
-static int
-handle_gnu_v3_exceptions (int tempflag, char *cond_string,
- enum exception_event_kind ex_event, int from_tty)
-{
- char *trigger_func_name;
-
- if (ex_event == EX_EVENT_CATCH)
- trigger_func_name = "__cxa_begin_catch";
- else
- trigger_func_name = "__cxa_throw";
-
- create_breakpoint (get_current_arch (),
- trigger_func_name, cond_string, -1, NULL,
- 0 /* condition and thread are valid. */,
- tempflag, bp_breakpoint,
- 0,
- AUTO_BOOLEAN_TRUE /* pending */,
- &gnu_v3_exception_catchpoint_ops, from_tty,
- 1 /* enabled */,
- 0 /* internal */,
- 0);
-
- return 1;
-}
-
-/* Deal with "catch catch" and "catch throw" commands. */
-
-static void
-catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
- int tempflag, int from_tty)
-{
- char *cond_string = NULL;
-
- if (!arg)
- arg = "";
- arg = skip_spaces (arg);
-
- cond_string = ep_parse_optional_if_clause (&arg);
-
- if ((*arg != '\0') && !isspace (*arg))
- error (_("Junk at end of arguments."));
-
- if (ex_event != EX_EVENT_THROW
- && ex_event != EX_EVENT_CATCH)
- error (_("Unsupported or unknown exception event; cannot catch it"));
-
- if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
- return;
-
- warning (_("Unsupported with this platform/compiler combination."));
-}
-
-/* Implementation of "catch catch" command. */
-
-static void
-catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
-{
- int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
- catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
-}
-
-/* Implementation of "catch throw" command. */
-
-static void
-catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
-{
- int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
- catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
-}
-
void
init_ada_exception_breakpoint (struct breakpoint *b,
struct gdbarch *gdbarch,
struct syscall s;
/* Skip whitespace. */
- while (isspace (*arg))
- arg++;
+ arg = skip_spaces (arg);
for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
cur_name[i] = arg[i];
static void
say_where (struct breakpoint *b)
{
- struct ui_out *uiout = current_uiout;
struct value_print_options opts;
get_user_print_options (&opts);
{
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
+ xfree (self->extra_string);
xfree (self->addr_string);
xfree (self->filter);
xfree (self->addr_string_range_end);
struct address_space *aspace, CORE_ADDR bp_addr,
const struct target_waitstatus *ws)
{
- struct breakpoint *b = bl->owner;
-
if (ws->kind != TARGET_WAITKIND_STOPPED
|| ws->value.sig != GDB_SIGNAL_TRAP)
return 0;
static enum print_stop_action
internal_bkpt_print_it (bpstat bs)
{
- struct ui_out *uiout = current_uiout;
struct breakpoint *b;
b = bs->breakpoint_at;
momentary_bkpt_re_set (struct breakpoint *b)
{
/* Keep temporary breakpoints, which can be encountered when we step
- over a dlopen call and SOLIB_ADD is resetting the breakpoints.
+ over a dlopen call and solib_add is resetting the breakpoints.
Otherwise these should have been blown away via the cleanup chain
or by breakpoint_init_inferior when we rerun the executable. */
}
static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
+/* Dprintf breakpoint_ops methods. */
+
+static void
+dprintf_re_set (struct breakpoint *b)
+{
+ breakpoint_re_set_default (b);
+
+ /* This breakpoint could have been pending, and be resolved now, and
+ if so, we should now have the extra string. If we don't, the
+ dprintf was malformed when created, but we couldn't tell because
+ we can't extract the extra string until the location is
+ resolved. */
+ if (b->loc != NULL && b->extra_string == NULL)
+ error (_("Format string required"));
+
+ /* 1 - connect to target 1, that can run breakpoint commands.
+ 2 - create a dprintf, which resolves fine.
+ 3 - disconnect from target 1
+ 4 - connect to target 2, that can NOT run breakpoint commands.
+
+ After steps #3/#4, you'll want the dprintf command list to
+ be updated, because target 1 and 2 may well return different
+ answers for target_can_run_breakpoint_commands().
+ Given absence of finer grained resetting, we get to do
+ it all the time. */
+ if (b->extra_string != NULL)
+ update_dprintf_command_list (b);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for dprintf. */
+
+static void
+dprintf_print_recreate (struct breakpoint *tp, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "dprintf %s%s", tp->addr_string,
+ tp->extra_string);
+ print_recreate_thread (tp, fp);
+}
+
/* The breakpoint_ops structure to be used on static tracepoints with
markers (`-m'). */
old symtab. */
if (b->cond_string != NULL)
{
- char *s;
+ const char *s;
volatile struct gdb_exception e;
s = b->cond_string;
/* Complete syscall names. Used by "catch syscall". */
static VEC (char_ptr) *
catch_syscall_completer (struct cmd_list_element *cmd,
- char *text, char *word)
+ const char *text, const char *word)
{
const char **list = get_syscall_names ();
VEC (char_ptr) *retlist
count = strtoul (args, &args, 10); /* Count comes first, then TP num. */
- while (*args && isspace ((int) *args))
- args++;
-
+ args = skip_spaces (args);
if (*args && strncasecmp (args, "all", 3) == 0)
{
struct breakpoint *b;
if (tp->ignore_count)
fprintf_unfiltered (fp, " ignore $bpnum %d\n", tp->ignore_count);
- if (tp->commands)
+ if (tp->type != bp_dprintf && tp->commands)
{
volatile struct gdb_exception ex;
ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
ops->decode_linespec = bkpt_probe_decode_linespec;
- /* GNU v3 exception catchpoints. */
- ops = &gnu_v3_exception_catchpoint_ops;
- *ops = bkpt_breakpoint_ops;
- ops->print_it = print_it_exception_catchpoint;
- ops->print_one = print_one_exception_catchpoint;
- ops->print_mention = print_mention_exception_catchpoint;
- ops->print_recreate = print_recreate_exception_catchpoint;
-
/* Watchpoints. */
ops = &watchpoint_breakpoint_ops;
*ops = base_breakpoint_ops;
ops = &dprintf_breakpoint_ops;
*ops = bkpt_base_breakpoint_ops;
- ops->re_set = bkpt_re_set;
+ ops->re_set = dprintf_re_set;
ops->resources_needed = bkpt_resources_needed;
ops->print_it = bkpt_print_it;
ops->print_mention = bkpt_print_mention;
- ops->print_recreate = bkpt_print_recreate;
+ ops->print_recreate = dprintf_print_recreate;
}
/* Chain containing all defined "enable breakpoint" subcommands. */
&tcatch_cmdlist, "tcatch ",
0/*allow-unknown*/, &cmdlist);
- /* Add catch and tcatch sub-commands. */
- add_catch_command ("catch", _("\
-Catch an exception, when caught."),
- catch_catch_command,
- NULL,
- CATCH_PERMANENT,
- CATCH_TEMPORARY);
- add_catch_command ("throw", _("\
-Catch an exception, when thrown."),
- catch_throw_command,
- NULL,
- CATCH_PERMANENT,
- CATCH_TEMPORARY);
add_catch_command ("fork", _("Catch calls to fork."),
catch_fork_command_1,
NULL,