2013-04-16 02:04:53 +08:00
|
|
|
|
/* Everything about catch/throw catchpoints, for GDB.
|
|
|
|
|
|
2015-01-01 17:32:14 +08:00
|
|
|
|
Copyright (C) 1986-2015 Free Software Foundation, Inc.
|
2013-04-16 02:04:53 +08:00
|
|
|
|
|
|
|
|
|
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 "arch-utils.h"
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include "breakpoint.h"
|
|
|
|
|
#include "gdbcmd.h"
|
|
|
|
|
#include "inferior.h"
|
|
|
|
|
#include "annotate.h"
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
#include "cli/cli-utils.h"
|
|
|
|
|
#include "completer.h"
|
|
|
|
|
#include "gdb_obstack.h"
|
|
|
|
|
#include "mi/mi-common.h"
|
2013-04-16 02:05:48 +08:00
|
|
|
|
#include "linespec.h"
|
2013-04-16 02:06:42 +08:00
|
|
|
|
#include "probe.h"
|
2013-04-16 02:09:02 +08:00
|
|
|
|
#include "objfiles.h"
|
|
|
|
|
#include "cp-abi.h"
|
2013-04-16 02:13:01 +08:00
|
|
|
|
#include "gdb_regex.h"
|
|
|
|
|
#include "cp-support.h"
|
2013-04-16 02:04:53 +08:00
|
|
|
|
|
|
|
|
|
/* Enums for exception-handling support. */
|
|
|
|
|
enum exception_event_kind
|
|
|
|
|
{
|
|
|
|
|
EX_EVENT_THROW,
|
|
|
|
|
EX_EVENT_RETHROW,
|
|
|
|
|
EX_EVENT_CATCH
|
|
|
|
|
};
|
|
|
|
|
|
2013-04-16 02:06:42 +08:00
|
|
|
|
/* Each spot where we may place an exception-related catchpoint has
|
|
|
|
|
two names: the SDT probe point and the function name. This
|
|
|
|
|
structure holds both. */
|
|
|
|
|
|
|
|
|
|
struct exception_names
|
|
|
|
|
{
|
|
|
|
|
/* The name of the probe point to try, in the form accepted by
|
|
|
|
|
'parse_probes'. */
|
|
|
|
|
|
|
|
|
|
const char *probe;
|
|
|
|
|
|
|
|
|
|
/* The name of the corresponding function. */
|
|
|
|
|
|
|
|
|
|
const char *function;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Names of the probe points and functions on which to break. This is
|
|
|
|
|
indexed by exception_event_kind. */
|
|
|
|
|
static const struct exception_names exception_functions[] =
|
2013-04-16 02:05:48 +08:00
|
|
|
|
{
|
2013-04-16 02:06:42 +08:00
|
|
|
|
{ "-probe-stap libstdcxx:throw", "__cxa_throw" },
|
|
|
|
|
{ "-probe-stap libstdcxx:rethrow", "__cxa_rethrow" },
|
|
|
|
|
{ "-probe-stap libstdcxx:catch", "__cxa_begin_catch" }
|
2013-04-16 02:05:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;
|
|
|
|
|
|
|
|
|
|
/* The type of an exception catchpoint. */
|
|
|
|
|
|
|
|
|
|
struct exception_catchpoint
|
|
|
|
|
{
|
|
|
|
|
/* The base class. */
|
|
|
|
|
|
|
|
|
|
struct breakpoint base;
|
|
|
|
|
|
|
|
|
|
/* The kind of exception catchpoint. */
|
|
|
|
|
|
|
|
|
|
enum exception_event_kind kind;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
|
|
|
|
|
/* If non-NULL, an xmalloc'd string holding the source form of the
|
|
|
|
|
regular expression to match against. */
|
|
|
|
|
|
|
|
|
|
char *exception_rx;
|
|
|
|
|
|
|
|
|
|
/* If non-NULL, an xmalloc'd, compiled regular expression which is
|
|
|
|
|
used to determine which exceptions to stop on. */
|
|
|
|
|
|
|
|
|
|
regex_t *pattern;
|
2013-04-16 02:05:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
2013-04-16 02:13:01 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* A helper function that fetches exception probe arguments. This
|
|
|
|
|
fills in *ARG0 (if non-NULL) and *ARG1 (which must be non-NULL).
|
|
|
|
|
It will throw an exception on any kind of failure. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fetch_probe_arguments (struct value **arg0, struct value **arg1)
|
|
|
|
|
{
|
|
|
|
|
struct frame_info *frame = get_selected_frame (_("No frame selected"));
|
|
|
|
|
CORE_ADDR pc = get_frame_pc (frame);
|
change probes to be program-space-independent
This changes the probes to be independent of the program space.
After this, when a probe's address is needed, it is determined by
applying offsets at the point of use.
This introduces a bound_probe object, similar to bound minimal
symbols. Objects of this type are used when it's necessary to pass a
probe and its corresponding objfile.
This removes the backlink from probe to objfile, which was primarily
used to fetch the architecture to use.
This adds a get_probe_address function which calls a probe method to
compute the probe's relocated address. Similarly, it adds an objfile
parameter to the semaphore methods so they can do the relocation
properly as well.
2014-03-03 Tom Tromey <tromey@redhat.com>
* break-catch-throw.c (fetch_probe_arguments): Use bound probes.
* breakpoint.c (create_longjmp_master_breakpoint): Use
get_probe_address.
(add_location_to_breakpoint, bkpt_probe_insert_location)
(bkpt_probe_remove_location): Update.
* breakpoint.h (struct bp_location) <probe>: Now a bound_probe.
* elfread.c (elf_symfile_relocate_probe): Remove.
(elf_probe_fns): Update.
(insert_exception_resume_breakpoint): Change type of "probe"
parameter to bound_probe.
(check_exception_resume): Update.
* objfiles.c (objfile_relocate1): Don't relocate probes.
* probe.c (bound_probe_s): New typedef.
(parse_probes): Use get_probe_address. Set sal's objfile.
(find_probe_by_pc): Return a bound_probe.
(collect_probes): Return a VEC(bound_probe_s).
(compare_probes): Update.
(gen_ui_out_table_header_info): Change type of "probes"
parameter. Update.
(info_probes_for_ops): Update.
(get_probe_address): New function.
(probe_safe_evaluate_at_pc): Update.
* probe.h (struct probe_ops) <get_probe_address>: New field.
<set_semaphore, clear_semaphore>: Add objfile parameter.
(struct probe) <objfile>: Remove field.
<arch>: New field.
<address>: Update comment.
(struct bound_probe): New.
(find_probe_by_pc): Return a bound_probe.
(get_probe_address): Declare.
* solib-svr4.c (struct probe_and_action) <address>: New field.
(hash_probe_and_action, equal_probe_and_action): Update.
(register_solib_event_probe): Add address parameter.
(solib_event_probe_at): Update.
(svr4_create_probe_breakpoints): Add objfile parameter. Use
get_probe_address.
* stap-probe.c (struct stap_probe) <sem_addr>: Update comment.
(stap_get_probe_address): New function.
(stap_can_evaluate_probe_arguments, compute_probe_arg)
(compile_probe_arg): Update.
(stap_set_semaphore, stap_clear_semaphore): Compute semaphore's
address.
(handle_stap_probe): Don't relocate the probe.
(stap_relocate): Remove.
(stap_gen_info_probes_table_values): Update.
(stap_probe_ops): Remove stap_relocate.
* symfile-debug.c (debug_sym_relocate_probe): Remove.
(debug_sym_probe_fns): Update.
* symfile.h (struct sym_probe_fns) <sym_relocate_probe>: Remove.
* symtab.c (init_sal): Use memset.
* symtab.h (struct symtab_and_line) <objfile>: New field.
* tracepoint.c (start_tracing, stop_tracing): Update.
2013-12-03 04:58:59 +08:00
|
|
|
|
struct bound_probe pc_probe;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
const struct sym_probe_fns *pc_probe_fns;
|
|
|
|
|
unsigned n_args;
|
|
|
|
|
|
|
|
|
|
pc_probe = find_probe_by_pc (pc);
|
change probes to be program-space-independent
This changes the probes to be independent of the program space.
After this, when a probe's address is needed, it is determined by
applying offsets at the point of use.
This introduces a bound_probe object, similar to bound minimal
symbols. Objects of this type are used when it's necessary to pass a
probe and its corresponding objfile.
This removes the backlink from probe to objfile, which was primarily
used to fetch the architecture to use.
This adds a get_probe_address function which calls a probe method to
compute the probe's relocated address. Similarly, it adds an objfile
parameter to the semaphore methods so they can do the relocation
properly as well.
2014-03-03 Tom Tromey <tromey@redhat.com>
* break-catch-throw.c (fetch_probe_arguments): Use bound probes.
* breakpoint.c (create_longjmp_master_breakpoint): Use
get_probe_address.
(add_location_to_breakpoint, bkpt_probe_insert_location)
(bkpt_probe_remove_location): Update.
* breakpoint.h (struct bp_location) <probe>: Now a bound_probe.
* elfread.c (elf_symfile_relocate_probe): Remove.
(elf_probe_fns): Update.
(insert_exception_resume_breakpoint): Change type of "probe"
parameter to bound_probe.
(check_exception_resume): Update.
* objfiles.c (objfile_relocate1): Don't relocate probes.
* probe.c (bound_probe_s): New typedef.
(parse_probes): Use get_probe_address. Set sal's objfile.
(find_probe_by_pc): Return a bound_probe.
(collect_probes): Return a VEC(bound_probe_s).
(compare_probes): Update.
(gen_ui_out_table_header_info): Change type of "probes"
parameter. Update.
(info_probes_for_ops): Update.
(get_probe_address): New function.
(probe_safe_evaluate_at_pc): Update.
* probe.h (struct probe_ops) <get_probe_address>: New field.
<set_semaphore, clear_semaphore>: Add objfile parameter.
(struct probe) <objfile>: Remove field.
<arch>: New field.
<address>: Update comment.
(struct bound_probe): New.
(find_probe_by_pc): Return a bound_probe.
(get_probe_address): Declare.
* solib-svr4.c (struct probe_and_action) <address>: New field.
(hash_probe_and_action, equal_probe_and_action): Update.
(register_solib_event_probe): Add address parameter.
(solib_event_probe_at): Update.
(svr4_create_probe_breakpoints): Add objfile parameter. Use
get_probe_address.
* stap-probe.c (struct stap_probe) <sem_addr>: Update comment.
(stap_get_probe_address): New function.
(stap_can_evaluate_probe_arguments, compute_probe_arg)
(compile_probe_arg): Update.
(stap_set_semaphore, stap_clear_semaphore): Compute semaphore's
address.
(handle_stap_probe): Don't relocate the probe.
(stap_relocate): Remove.
(stap_gen_info_probes_table_values): Update.
(stap_probe_ops): Remove stap_relocate.
* symfile-debug.c (debug_sym_relocate_probe): Remove.
(debug_sym_probe_fns): Update.
* symfile.h (struct sym_probe_fns) <sym_relocate_probe>: Remove.
* symtab.c (init_sal): Use memset.
* symtab.h (struct symtab_and_line) <objfile>: New field.
* tracepoint.c (start_tracing, stop_tracing): Update.
2013-12-03 04:58:59 +08:00
|
|
|
|
if (pc_probe.probe == NULL
|
|
|
|
|
|| strcmp (pc_probe.probe->provider, "libstdcxx") != 0
|
|
|
|
|
|| (strcmp (pc_probe.probe->name, "catch") != 0
|
|
|
|
|
&& strcmp (pc_probe.probe->name, "throw") != 0
|
|
|
|
|
&& strcmp (pc_probe.probe->name, "rethrow") != 0))
|
2013-04-16 02:13:01 +08:00
|
|
|
|
error (_("not stopped at a C++ exception catchpoint"));
|
|
|
|
|
|
change probes to be program-space-independent
This changes the probes to be independent of the program space.
After this, when a probe's address is needed, it is determined by
applying offsets at the point of use.
This introduces a bound_probe object, similar to bound minimal
symbols. Objects of this type are used when it's necessary to pass a
probe and its corresponding objfile.
This removes the backlink from probe to objfile, which was primarily
used to fetch the architecture to use.
This adds a get_probe_address function which calls a probe method to
compute the probe's relocated address. Similarly, it adds an objfile
parameter to the semaphore methods so they can do the relocation
properly as well.
2014-03-03 Tom Tromey <tromey@redhat.com>
* break-catch-throw.c (fetch_probe_arguments): Use bound probes.
* breakpoint.c (create_longjmp_master_breakpoint): Use
get_probe_address.
(add_location_to_breakpoint, bkpt_probe_insert_location)
(bkpt_probe_remove_location): Update.
* breakpoint.h (struct bp_location) <probe>: Now a bound_probe.
* elfread.c (elf_symfile_relocate_probe): Remove.
(elf_probe_fns): Update.
(insert_exception_resume_breakpoint): Change type of "probe"
parameter to bound_probe.
(check_exception_resume): Update.
* objfiles.c (objfile_relocate1): Don't relocate probes.
* probe.c (bound_probe_s): New typedef.
(parse_probes): Use get_probe_address. Set sal's objfile.
(find_probe_by_pc): Return a bound_probe.
(collect_probes): Return a VEC(bound_probe_s).
(compare_probes): Update.
(gen_ui_out_table_header_info): Change type of "probes"
parameter. Update.
(info_probes_for_ops): Update.
(get_probe_address): New function.
(probe_safe_evaluate_at_pc): Update.
* probe.h (struct probe_ops) <get_probe_address>: New field.
<set_semaphore, clear_semaphore>: Add objfile parameter.
(struct probe) <objfile>: Remove field.
<arch>: New field.
<address>: Update comment.
(struct bound_probe): New.
(find_probe_by_pc): Return a bound_probe.
(get_probe_address): Declare.
* solib-svr4.c (struct probe_and_action) <address>: New field.
(hash_probe_and_action, equal_probe_and_action): Update.
(register_solib_event_probe): Add address parameter.
(solib_event_probe_at): Update.
(svr4_create_probe_breakpoints): Add objfile parameter. Use
get_probe_address.
* stap-probe.c (struct stap_probe) <sem_addr>: Update comment.
(stap_get_probe_address): New function.
(stap_can_evaluate_probe_arguments, compute_probe_arg)
(compile_probe_arg): Update.
(stap_set_semaphore, stap_clear_semaphore): Compute semaphore's
address.
(handle_stap_probe): Don't relocate the probe.
(stap_relocate): Remove.
(stap_gen_info_probes_table_values): Update.
(stap_probe_ops): Remove stap_relocate.
* symfile-debug.c (debug_sym_relocate_probe): Remove.
(debug_sym_probe_fns): Update.
* symfile.h (struct sym_probe_fns) <sym_relocate_probe>: Remove.
* symtab.c (init_sal): Use memset.
* symtab.h (struct symtab_and_line) <objfile>: New field.
* tracepoint.c (start_tracing, stop_tracing): Update.
2013-12-03 04:58:59 +08:00
|
|
|
|
n_args = get_probe_argument_count (pc_probe.probe, frame);
|
2013-04-16 02:13:01 +08:00
|
|
|
|
if (n_args < 2)
|
|
|
|
|
error (_("C++ exception catchpoint has too few arguments"));
|
|
|
|
|
|
|
|
|
|
if (arg0 != NULL)
|
change probes to be program-space-independent
This changes the probes to be independent of the program space.
After this, when a probe's address is needed, it is determined by
applying offsets at the point of use.
This introduces a bound_probe object, similar to bound minimal
symbols. Objects of this type are used when it's necessary to pass a
probe and its corresponding objfile.
This removes the backlink from probe to objfile, which was primarily
used to fetch the architecture to use.
This adds a get_probe_address function which calls a probe method to
compute the probe's relocated address. Similarly, it adds an objfile
parameter to the semaphore methods so they can do the relocation
properly as well.
2014-03-03 Tom Tromey <tromey@redhat.com>
* break-catch-throw.c (fetch_probe_arguments): Use bound probes.
* breakpoint.c (create_longjmp_master_breakpoint): Use
get_probe_address.
(add_location_to_breakpoint, bkpt_probe_insert_location)
(bkpt_probe_remove_location): Update.
* breakpoint.h (struct bp_location) <probe>: Now a bound_probe.
* elfread.c (elf_symfile_relocate_probe): Remove.
(elf_probe_fns): Update.
(insert_exception_resume_breakpoint): Change type of "probe"
parameter to bound_probe.
(check_exception_resume): Update.
* objfiles.c (objfile_relocate1): Don't relocate probes.
* probe.c (bound_probe_s): New typedef.
(parse_probes): Use get_probe_address. Set sal's objfile.
(find_probe_by_pc): Return a bound_probe.
(collect_probes): Return a VEC(bound_probe_s).
(compare_probes): Update.
(gen_ui_out_table_header_info): Change type of "probes"
parameter. Update.
(info_probes_for_ops): Update.
(get_probe_address): New function.
(probe_safe_evaluate_at_pc): Update.
* probe.h (struct probe_ops) <get_probe_address>: New field.
<set_semaphore, clear_semaphore>: Add objfile parameter.
(struct probe) <objfile>: Remove field.
<arch>: New field.
<address>: Update comment.
(struct bound_probe): New.
(find_probe_by_pc): Return a bound_probe.
(get_probe_address): Declare.
* solib-svr4.c (struct probe_and_action) <address>: New field.
(hash_probe_and_action, equal_probe_and_action): Update.
(register_solib_event_probe): Add address parameter.
(solib_event_probe_at): Update.
(svr4_create_probe_breakpoints): Add objfile parameter. Use
get_probe_address.
* stap-probe.c (struct stap_probe) <sem_addr>: Update comment.
(stap_get_probe_address): New function.
(stap_can_evaluate_probe_arguments, compute_probe_arg)
(compile_probe_arg): Update.
(stap_set_semaphore, stap_clear_semaphore): Compute semaphore's
address.
(handle_stap_probe): Don't relocate the probe.
(stap_relocate): Remove.
(stap_gen_info_probes_table_values): Update.
(stap_probe_ops): Remove stap_relocate.
* symfile-debug.c (debug_sym_relocate_probe): Remove.
(debug_sym_probe_fns): Update.
* symfile.h (struct sym_probe_fns) <sym_relocate_probe>: Remove.
* symtab.c (init_sal): Use memset.
* symtab.h (struct symtab_and_line) <objfile>: New field.
* tracepoint.c (start_tracing, stop_tracing): Update.
2013-12-03 04:58:59 +08:00
|
|
|
|
*arg0 = evaluate_probe_argument (pc_probe.probe, 0, frame);
|
|
|
|
|
*arg1 = evaluate_probe_argument (pc_probe.probe, 1, frame);
|
2013-04-16 02:13:01 +08:00
|
|
|
|
|
|
|
|
|
if ((arg0 != NULL && *arg0 == NULL) || *arg1 == NULL)
|
|
|
|
|
error (_("error computing probe argument at c++ exception catchpoint"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-16 02:04:53 +08:00
|
|
|
|
/* A helper function that returns a value indicating the kind of the
|
|
|
|
|
exception catchpoint B. */
|
|
|
|
|
|
|
|
|
|
static enum exception_event_kind
|
|
|
|
|
classify_exception_breakpoint (struct breakpoint *b)
|
|
|
|
|
{
|
2013-04-16 02:05:48 +08:00
|
|
|
|
struct exception_catchpoint *cp = (struct exception_catchpoint *) b;
|
|
|
|
|
|
|
|
|
|
return cp->kind;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 02:13:01 +08:00
|
|
|
|
/* Implement the 'dtor' method. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dtor_exception_catchpoint (struct breakpoint *self)
|
|
|
|
|
{
|
|
|
|
|
struct exception_catchpoint *cp = (struct exception_catchpoint *) self;
|
|
|
|
|
|
|
|
|
|
xfree (cp->exception_rx);
|
|
|
|
|
if (cp->pattern != NULL)
|
|
|
|
|
regfree (cp->pattern);
|
|
|
|
|
bkpt_breakpoint_ops.dtor (self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Implement the 'check_status' method. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_status_exception_catchpoint (struct bpstats *bs)
|
|
|
|
|
{
|
|
|
|
|
struct exception_catchpoint *self
|
|
|
|
|
= (struct exception_catchpoint *) bs->breakpoint_at;
|
2015-02-28 00:33:07 +08:00
|
|
|
|
char *type_name = NULL;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
|
|
|
|
|
bkpt_breakpoint_ops.check_status (bs);
|
|
|
|
|
if (bs->stop == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (self->pattern == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
TRY
|
2013-04-16 02:13:01 +08:00
|
|
|
|
{
|
|
|
|
|
struct value *typeinfo_arg;
|
|
|
|
|
char *canon;
|
|
|
|
|
|
|
|
|
|
fetch_probe_arguments (NULL, &typeinfo_arg);
|
2015-02-28 00:33:07 +08:00
|
|
|
|
type_name = cplus_typename_from_type_info (typeinfo_arg);
|
2013-04-16 02:13:01 +08:00
|
|
|
|
|
2015-02-28 00:33:07 +08:00
|
|
|
|
canon = cp_canonicalize_string (type_name);
|
2013-04-16 02:13:01 +08:00
|
|
|
|
if (canon != NULL)
|
|
|
|
|
{
|
2015-02-28 00:33:07 +08:00
|
|
|
|
xfree (type_name);
|
|
|
|
|
type_name = canon;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
CATCH (e, RETURN_MASK_ERROR)
|
|
|
|
|
{
|
|
|
|
|
exception_print (gdb_stderr, e);
|
|
|
|
|
}
|
|
|
|
|
END_CATCH
|
2013-04-16 02:13:01 +08:00
|
|
|
|
|
2015-03-07 22:50:04 +08:00
|
|
|
|
if (type_name != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (regexec (self->pattern, type_name, 0, NULL, 0) != 0)
|
|
|
|
|
bs->stop = 0;
|
|
|
|
|
|
|
|
|
|
xfree (type_name);
|
|
|
|
|
}
|
2013-04-16 02:13:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 02:05:48 +08:00
|
|
|
|
/* Implement the 're_set' method. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
re_set_exception_catchpoint (struct breakpoint *self)
|
|
|
|
|
{
|
|
|
|
|
struct symtabs_and_lines sals = {0};
|
|
|
|
|
struct symtabs_and_lines sals_end = {0};
|
|
|
|
|
struct cleanup *cleanup;
|
|
|
|
|
enum exception_event_kind kind = classify_exception_breakpoint (self);
|
|
|
|
|
|
2014-03-21 05:08:31 +08:00
|
|
|
|
/* We first try to use the probe interface. */
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
TRY
|
2013-04-16 02:05:48 +08:00
|
|
|
|
{
|
2014-03-21 05:08:31 +08:00
|
|
|
|
char *spec = ASTRDUP (exception_functions[kind].probe);
|
|
|
|
|
|
|
|
|
|
sals = parse_probes (&spec, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
CATCH (e, RETURN_MASK_ERROR)
|
2014-03-21 05:08:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Using the probe interface failed. Let's fallback to the normal
|
|
|
|
|
catchpoint mode. */
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
TRY
|
2013-04-16 02:06:42 +08:00
|
|
|
|
{
|
2014-03-21 05:08:31 +08:00
|
|
|
|
char *spec = ASTRDUP (exception_functions[kind].function);
|
|
|
|
|
|
|
|
|
|
self->ops->decode_linespec (self, &spec, &sals);
|
2013-04-16 02:06:42 +08:00
|
|
|
|
}
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
CATCH (ex, RETURN_MASK_ERROR)
|
2015-03-07 22:50:04 +08:00
|
|
|
|
{
|
|
|
|
|
/* NOT_FOUND_ERROR just means the breakpoint will be
|
|
|
|
|
pending, so let it through. */
|
|
|
|
|
if (ex.error != NOT_FOUND_ERROR)
|
|
|
|
|
throw_exception (ex);
|
|
|
|
|
}
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
END_CATCH
|
2013-04-16 02:05:48 +08:00
|
|
|
|
}
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
END_CATCH
|
2013-04-16 02:05:48 +08:00
|
|
|
|
|
|
|
|
|
cleanup = make_cleanup (xfree, sals.sals);
|
|
|
|
|
update_breakpoint_locations (self, sals, sals_end);
|
|
|
|
|
do_cleanups (cleanup);
|
2013-04-16 02:04:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
enum exception_event_kind kind = classify_exception_breakpoint (b);
|
|
|
|
|
|
|
|
|
|
annotate_catchpoint (b->number);
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
(kind == EX_EVENT_THROW ? " (exception thrown), "
|
|
|
|
|
: (kind == EX_EVENT_CATCH ? " (exception caught), "
|
|
|
|
|
: " (exception rethrown), ")));
|
|
|
|
|
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;
|
|
|
|
|
enum exception_event_kind kind = classify_exception_breakpoint (b);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
switch (kind)
|
|
|
|
|
{
|
|
|
|
|
case EX_EVENT_THROW:
|
|
|
|
|
ui_out_field_string (uiout, "what", "exception throw");
|
|
|
|
|
if (ui_out_is_mi_like_p (uiout))
|
|
|
|
|
ui_out_field_string (uiout, "catch-type", "throw");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EX_EVENT_RETHROW:
|
|
|
|
|
ui_out_field_string (uiout, "what", "exception rethrow");
|
|
|
|
|
if (ui_out_is_mi_like_p (uiout))
|
|
|
|
|
ui_out_field_string (uiout, "catch-type", "rethrow");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EX_EVENT_CATCH:
|
|
|
|
|
ui_out_field_string (uiout, "what", "exception catch");
|
|
|
|
|
if (ui_out_is_mi_like_p (uiout))
|
|
|
|
|
ui_out_field_string (uiout, "catch-type", "catch");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 02:13:01 +08:00
|
|
|
|
/* Implement the 'print_one_detail' method. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_one_detail_exception_catchpoint (const struct breakpoint *b,
|
|
|
|
|
struct ui_out *uiout)
|
|
|
|
|
{
|
|
|
|
|
const struct exception_catchpoint *cp
|
|
|
|
|
= (const struct exception_catchpoint *) b;
|
|
|
|
|
|
|
|
|
|
if (cp->exception_rx != NULL)
|
|
|
|
|
{
|
|
|
|
|
ui_out_text (uiout, _("\tmatching: "));
|
|
|
|
|
ui_out_field_string (uiout, "regexp", cp->exception_rx);
|
|
|
|
|
ui_out_text (uiout, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 02:04:53 +08:00
|
|
|
|
static void
|
|
|
|
|
print_mention_exception_catchpoint (struct breakpoint *b)
|
|
|
|
|
{
|
|
|
|
|
struct ui_out *uiout = current_uiout;
|
|
|
|
|
int bp_temp;
|
|
|
|
|
enum exception_event_kind kind = classify_exception_breakpoint (b);
|
|
|
|
|
|
|
|
|
|
bp_temp = b->disposition == disp_del;
|
|
|
|
|
ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
|
|
|
|
|
: _("Catchpoint "));
|
|
|
|
|
ui_out_field_int (uiout, "bkptno", b->number);
|
|
|
|
|
ui_out_text (uiout, (kind == EX_EVENT_THROW ? _(" (throw)")
|
|
|
|
|
: (kind == EX_EVENT_CATCH ? _(" (catch)")
|
|
|
|
|
: _(" (rethrow)"))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
enum exception_event_kind kind = classify_exception_breakpoint (b);
|
|
|
|
|
|
|
|
|
|
bp_temp = b->disposition == disp_del;
|
|
|
|
|
fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
|
|
|
|
|
switch (kind)
|
|
|
|
|
{
|
|
|
|
|
case EX_EVENT_THROW:
|
|
|
|
|
fprintf_unfiltered (fp, "throw");
|
|
|
|
|
break;
|
|
|
|
|
case EX_EVENT_CATCH:
|
|
|
|
|
fprintf_unfiltered (fp, "catch");
|
|
|
|
|
break;
|
|
|
|
|
case EX_EVENT_RETHROW:
|
|
|
|
|
fprintf_unfiltered (fp, "rethrow");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
print_recreate_thread (b, fp);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 02:05:48 +08:00
|
|
|
|
static void
|
2013-04-16 02:13:01 +08:00
|
|
|
|
handle_gnu_v3_exceptions (int tempflag, char *except_rx, char *cond_string,
|
2013-04-16 02:04:53 +08:00
|
|
|
|
enum exception_event_kind ex_event, int from_tty)
|
|
|
|
|
{
|
2013-04-16 02:05:48 +08:00
|
|
|
|
struct exception_catchpoint *cp;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
|
|
|
|
|
regex_t *pattern = NULL;
|
|
|
|
|
|
|
|
|
|
if (except_rx != NULL)
|
|
|
|
|
{
|
|
|
|
|
pattern = XNEW (regex_t);
|
|
|
|
|
make_cleanup (xfree, pattern);
|
|
|
|
|
|
|
|
|
|
compile_rx_or_error (pattern, except_rx,
|
|
|
|
|
_("invalid type-matching regexp"));
|
|
|
|
|
}
|
2013-04-16 02:04:53 +08:00
|
|
|
|
|
2013-04-16 02:05:48 +08:00
|
|
|
|
cp = XCNEW (struct exception_catchpoint);
|
2013-04-16 02:13:01 +08:00
|
|
|
|
make_cleanup (xfree, cp);
|
|
|
|
|
|
2013-04-16 02:05:48 +08:00
|
|
|
|
init_catchpoint (&cp->base, get_current_arch (), tempflag, cond_string,
|
|
|
|
|
&gnu_v3_exception_catchpoint_ops);
|
|
|
|
|
/* We need to reset 'type' in order for code in breakpoint.c to do
|
|
|
|
|
the right thing. */
|
|
|
|
|
cp->base.type = bp_breakpoint;
|
|
|
|
|
cp->kind = ex_event;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
cp->exception_rx = except_rx;
|
|
|
|
|
cp->pattern = pattern;
|
2013-04-16 02:05:48 +08:00
|
|
|
|
|
|
|
|
|
re_set_exception_catchpoint (&cp->base);
|
|
|
|
|
|
|
|
|
|
install_breakpoint (0, &cp->base, 1);
|
2013-04-16 02:13:01 +08:00
|
|
|
|
discard_cleanups (cleanup);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look for an "if" token in *STRING. The "if" token must be preceded
|
|
|
|
|
by whitespace.
|
|
|
|
|
|
|
|
|
|
If there is any non-whitespace text between *STRING and the "if"
|
|
|
|
|
token, then it is returned in a newly-xmalloc'd string. Otherwise,
|
|
|
|
|
this returns NULL.
|
|
|
|
|
|
|
|
|
|
STRING is updated to point to the "if" token, if it exists, or to
|
|
|
|
|
the end of the string. */
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
extract_exception_regexp (char **string)
|
|
|
|
|
{
|
|
|
|
|
char *start;
|
|
|
|
|
char *last, *last_space;
|
|
|
|
|
|
|
|
|
|
start = skip_spaces (*string);
|
|
|
|
|
|
|
|
|
|
last = start;
|
|
|
|
|
last_space = start;
|
|
|
|
|
while (*last != '\0')
|
|
|
|
|
{
|
|
|
|
|
char *if_token = last;
|
|
|
|
|
|
|
|
|
|
/* Check for the "if". */
|
|
|
|
|
if (check_for_argument (&if_token, "if", 2))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* No "if" token here. Skip to the next word start. */
|
|
|
|
|
last_space = skip_to_space (last);
|
|
|
|
|
last = skip_spaces (last_space);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*string = last;
|
|
|
|
|
if (last_space > start)
|
|
|
|
|
return savestring (start, last_space - start);
|
|
|
|
|
return NULL;
|
2013-04-16 02:04:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Deal with "catch catch", "catch throw", and "catch rethrow"
|
|
|
|
|
commands. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
|
|
|
|
|
int tempflag, int from_tty)
|
|
|
|
|
{
|
2013-04-16 02:13:01 +08:00
|
|
|
|
char *except_rx;
|
2013-04-16 02:04:53 +08:00
|
|
|
|
char *cond_string = NULL;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
struct cleanup *cleanup;
|
2013-04-16 02:04:53 +08:00
|
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
|
arg = "";
|
|
|
|
|
arg = skip_spaces (arg);
|
|
|
|
|
|
2013-04-16 02:13:01 +08:00
|
|
|
|
except_rx = extract_exception_regexp (&arg);
|
|
|
|
|
cleanup = make_cleanup (xfree, except_rx);
|
|
|
|
|
|
2013-04-16 02:04:53 +08:00
|
|
|
|
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
|
|
|
|
|
&& ex_event != EX_EVENT_RETHROW)
|
|
|
|
|
error (_("Unsupported or unknown exception event; cannot catch it"));
|
|
|
|
|
|
2013-04-16 02:13:01 +08:00
|
|
|
|
handle_gnu_v3_exceptions (tempflag, except_rx, cond_string,
|
|
|
|
|
ex_event, from_tty);
|
|
|
|
|
|
|
|
|
|
discard_cleanups (cleanup);
|
2013-04-16 02:04:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Implementation of "catch rethrow" command. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
catch_rethrow_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_RETHROW, arg, tempflag, from_tty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-16 02:09:02 +08:00
|
|
|
|
/* Implement the 'make_value' method for the $_exception
|
|
|
|
|
internalvar. */
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
compute_exception (struct gdbarch *argc, struct internalvar *var, void *ignore)
|
|
|
|
|
{
|
|
|
|
|
struct value *arg0, *arg1;
|
|
|
|
|
struct type *obj_type;
|
|
|
|
|
|
2013-04-16 02:13:01 +08:00
|
|
|
|
fetch_probe_arguments (&arg0, &arg1);
|
2013-04-16 02:09:02 +08:00
|
|
|
|
|
|
|
|
|
/* ARG0 is a pointer to the exception object. ARG1 is a pointer to
|
|
|
|
|
the std::type_info for the exception. Now we find the type from
|
|
|
|
|
the type_info and cast the result. */
|
|
|
|
|
obj_type = cplus_type_from_type_info (arg1);
|
|
|
|
|
return value_ind (value_cast (make_pointer_type (obj_type, NULL), arg0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Implementation of the '$_exception' variable. */
|
|
|
|
|
|
|
|
|
|
static const struct internalvar_funcs exception_funcs =
|
|
|
|
|
{
|
|
|
|
|
compute_exception,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-16 02:04:53 +08:00
|
|
|
|
static void
|
|
|
|
|
initialize_throw_catchpoint_ops (void)
|
|
|
|
|
{
|
|
|
|
|
struct breakpoint_ops *ops;
|
|
|
|
|
|
|
|
|
|
initialize_breakpoint_ops ();
|
|
|
|
|
|
|
|
|
|
/* GNU v3 exception catchpoints. */
|
|
|
|
|
ops = &gnu_v3_exception_catchpoint_ops;
|
|
|
|
|
*ops = bkpt_breakpoint_ops;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
ops->dtor = dtor_exception_catchpoint;
|
2013-04-16 02:05:48 +08:00
|
|
|
|
ops->re_set = re_set_exception_catchpoint;
|
2013-04-16 02:04:53 +08:00
|
|
|
|
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;
|
2013-04-16 02:13:01 +08:00
|
|
|
|
ops->print_one_detail = print_one_detail_exception_catchpoint;
|
|
|
|
|
ops->check_status = check_status_exception_catchpoint;
|
2013-04-16 02:04:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initialize_file_ftype _initialize_break_catch_throw;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_initialize_break_catch_throw (void)
|
|
|
|
|
{
|
|
|
|
|
initialize_throw_catchpoint_ops ();
|
|
|
|
|
|
|
|
|
|
/* 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 ("rethrow", _("\
|
|
|
|
|
Catch an exception, when rethrown."),
|
|
|
|
|
catch_rethrow_command,
|
|
|
|
|
NULL,
|
|
|
|
|
CATCH_PERMANENT,
|
|
|
|
|
CATCH_TEMPORARY);
|
2013-04-16 02:09:02 +08:00
|
|
|
|
|
|
|
|
|
create_internalvar_type_lazy ("_exception", &exception_funcs, NULL);
|
2013-04-16 02:04:53 +08:00
|
|
|
|
}
|