| /* Exception Handling interface routines. |
| Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
| 2007, 2008, 2009 Free Software Foundation, Inc. |
| Contributed by Mike Stump <mrs@cygnus.com>. |
| |
| This file is part of GCC. |
| |
| GCC 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, or (at your option) any later |
| version. |
| |
| GCC 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 GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "sbitmap.h" |
| #include "vecprim.h" |
| |
| struct function; |
| struct eh_region_d; |
| struct pointer_map_t; |
| |
| /* The type of an exception region. */ |
| enum eh_region_type |
| { |
| /* CLEANUP regions implement e.g. destructors run when exiting a block. |
| They can be generated from both GIMPLE_TRY_FINALLY and GIMPLE_TRY_CATCH |
| nodes. It is expected by the runtime that cleanup regions will *not* |
| resume normal program flow, but will continue propagation of the |
| exception. */ |
| ERT_CLEANUP, |
| |
| /* TRY regions implement catching an exception. The list of types associated |
| with the attached catch handlers is examined in order by the runtime and |
| control is transfered to the appropriate handler. Note that a NULL type |
| list is a catch-all handler, and that it will catch *all* exceptions |
| including those originating from a different language. */ |
| ERT_TRY, |
| |
| /* ALLOWED_EXCEPTIONS regions implement exception filtering, e.g. the |
| throw(type-list) specification that can be added to C++ functions. |
| The runtime examines the thrown exception vs the type list, and if |
| the exception does not match, transfers control to the handler. The |
| normal handler for C++ calls __cxa_call_unexpected. */ |
| ERT_ALLOWED_EXCEPTIONS, |
| |
| /* MUST_NOT_THROW regions prevent all exceptions from propagating. This |
| region type is used in C++ to surround destructors being run inside a |
| CLEANUP region. This differs from an ALLOWED_EXCEPTIONS region with |
| an empty type list in that the runtime is prepared to terminate the |
| program directly. We only generate code for MUST_NOT_THROW regions |
| along control paths that are already handling an exception within the |
| current function. */ |
| ERT_MUST_NOT_THROW |
| }; |
| |
| |
| /* A landing pad for a given exception region. Any transfer of control |
| from the EH runtime to the function happens at a landing pad. */ |
| |
| struct GTY(()) eh_landing_pad_d |
| { |
| /* The linked list of all landing pads associated with the region. */ |
| struct eh_landing_pad_d *next_lp; |
| |
| /* The region with which this landing pad is associated. */ |
| struct eh_region_d *region; |
| |
| /* At the gimple level, the location to which control will be transfered |
| for this landing pad. There can be both EH and normal edges into the |
| block containing the post-landing-pad label. */ |
| tree post_landing_pad; |
| |
| /* At the rtl level, the location to which the runtime will transfer |
| control. This differs from the post-landing-pad in that the target's |
| EXCEPTION_RECEIVER pattern will be expanded here, as well as other |
| bookkeeping specific to exceptions. There must not be normal edges |
| into the block containing the landing-pad label. */ |
| rtx landing_pad; |
| |
| /* The index of this landing pad within fun->eh->lp_array. */ |
| int index; |
| }; |
| |
| /* A catch handler associated with an ERT_TRY region. */ |
| |
| struct GTY(()) eh_catch_d |
| { |
| /* The double-linked list of all catch handlers for the region. */ |
| struct eh_catch_d *next_catch; |
| struct eh_catch_d *prev_catch; |
| |
| /* A TREE_LIST of runtime type objects that this catch handler |
| will catch, or NULL if all exceptions are caught. */ |
| tree type_list; |
| |
| /* A TREE_LIST of INTEGER_CSTs that correspond to the type_list entries, |
| having been mapped by assign_filter_values. These integers are to be |
| compared against the __builtin_eh_filter value. */ |
| tree filter_list; |
| |
| /* The code that should be executed if this catch handler matches the |
| thrown exception. This label is only maintained until |
| pass_lower_eh_dispatch, at which point it is cleared. */ |
| tree label; |
| }; |
| |
| /* Describes one exception region. */ |
| |
| struct GTY(()) eh_region_d |
| { |
| /* The immediately surrounding region. */ |
| struct eh_region_d *outer; |
| |
| /* The list of immediately contained regions. */ |
| struct eh_region_d *inner; |
| struct eh_region_d *next_peer; |
| |
| /* The index of this region within fun->eh->region_array. */ |
| int index; |
| |
| /* Each region does exactly one thing. */ |
| enum eh_region_type type; |
| |
| /* Holds the action to perform based on the preceding type. */ |
| union eh_region_u { |
| struct eh_region_u_try { |
| /* The double-linked list of all catch handlers for this region. */ |
| struct eh_catch_d *first_catch; |
| struct eh_catch_d *last_catch; |
| } GTY ((tag ("ERT_TRY"))) eh_try; |
| |
| struct eh_region_u_allowed { |
| /* A TREE_LIST of runtime type objects allowed to pass. */ |
| tree type_list; |
| /* The code that should be executed if the thrown exception does |
| not match the type list. This label is only maintained until |
| pass_lower_eh_dispatch, at which point it is cleared. */ |
| tree label; |
| /* The integer that will be passed by the runtime to signal that |
| we should execute the code at LABEL. This integer is assigned |
| by assign_filter_values and is to be compared against the |
| __builtin_eh_filter value. */ |
| int filter; |
| } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed; |
| |
| struct eh_region_u_must_not_throw { |
| /* A function decl to be invoked if this region is actually reachable |
| from within the function, rather than implementable from the runtime. |
| The normal way for this to happen is for there to be a CLEANUP region |
| contained within this MUST_NOT_THROW region. Note that if the |
| runtime handles the MUST_NOT_THROW region, we have no control over |
| what termination function is called; it will be decided by the |
| personality function in effect for this CIE. */ |
| tree failure_decl; |
| /* The location assigned to the call of FAILURE_DECL, if expanded. */ |
| location_t failure_loc; |
| } GTY ((tag ("ERT_MUST_NOT_THROW"))) must_not_throw; |
| } GTY ((desc ("%0.type"))) u; |
| |
| /* The list of landing pads associated with this region. */ |
| struct eh_landing_pad_d *landing_pads; |
| |
| /* EXC_PTR and FILTER values copied from the runtime for this region. |
| Each region gets its own psuedos so that if there are nested exceptions |
| we do not overwrite the values of the first exception. */ |
| rtx exc_ptr_reg, filter_reg; |
| |
| /* True if this region should use __cxa_end_cleanup instead |
| of _Unwind_Resume. */ |
| bool use_cxa_end_cleanup; |
| }; |
| |
| typedef struct eh_landing_pad_d *eh_landing_pad; |
| typedef struct eh_catch_d *eh_catch; |
| typedef struct eh_region_d *eh_region; |
| |
| DEF_VEC_P(eh_region); |
| DEF_VEC_ALLOC_P(eh_region, gc); |
| DEF_VEC_ALLOC_P(eh_region, heap); |
| |
| DEF_VEC_P(eh_landing_pad); |
| DEF_VEC_ALLOC_P(eh_landing_pad, gc); |
| |
| |
| /* The exception status for each function. */ |
| |
| struct GTY(()) eh_status |
| { |
| /* The tree of all regions for this function. */ |
| eh_region region_tree; |
| |
| /* The same information as an indexable array. */ |
| VEC(eh_region,gc) *region_array; |
| |
| /* The landing pads as an indexable array. */ |
| VEC(eh_landing_pad,gc) *lp_array; |
| |
| /* At the gimple level, a mapping from gimple statement to landing pad |
| or must-not-throw region. See record_stmt_eh_region. */ |
| htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table; |
| |
| /* All of the runtime type data used by the function. These objects |
| are emitted to the lang-specific-data-area for the function. */ |
| VEC(tree,gc) *ttype_data; |
| |
| /* The table of all action chains. These encode the eh_region tree in |
| a compact form for use by the runtime, and is also emitted to the |
| lang-specific-data-area. Note that the ARM EABI uses a different |
| format for the encoding than all other ports. */ |
| union eh_status_u { |
| VEC(tree,gc) * GTY((tag ("1"))) arm_eabi; |
| VEC(uchar,gc) * GTY((tag ("0"))) other; |
| } GTY ((desc ("targetm.arm_eabi_unwinder"))) ehspec_data; |
| }; |
| |
| |
| /* Test: is exception handling turned on? */ |
| extern int doing_eh (int); |
| |
| /* Invokes CALLBACK for every exception handler label. Only used by old |
| loop hackery; should not be used by new code. */ |
| extern void for_each_eh_label (void (*) (rtx)); |
| |
| extern void init_eh (void); |
| extern void init_eh_for_function (void); |
| |
| extern void remove_eh_landing_pad (eh_landing_pad); |
| extern void remove_eh_handler (eh_region); |
| |
| extern bool current_function_has_exception_handlers (void); |
| extern void output_function_exception_table (const char *); |
| |
| extern rtx expand_builtin_eh_pointer (tree); |
| extern rtx expand_builtin_eh_filter (tree); |
| extern rtx expand_builtin_eh_copy_values (tree); |
| extern void expand_builtin_unwind_init (void); |
| extern rtx expand_builtin_eh_return_data_regno (tree); |
| extern rtx expand_builtin_extract_return_addr (tree); |
| extern void expand_builtin_init_dwarf_reg_sizes (tree); |
| extern rtx expand_builtin_frob_return_addr (tree); |
| extern rtx expand_builtin_dwarf_sp_column (void); |
| extern void expand_builtin_eh_return (tree, tree); |
| extern void expand_eh_return (void); |
| extern rtx expand_builtin_extend_pointer (tree); |
| |
| typedef tree (*duplicate_eh_regions_map) (tree, void *); |
| extern struct pointer_map_t *duplicate_eh_regions |
| (struct function *, eh_region, int, duplicate_eh_regions_map, void *); |
| |
| extern void sjlj_emit_function_exit_after (rtx); |
| |
| extern eh_region gen_eh_region_cleanup (eh_region); |
| extern eh_region gen_eh_region_try (eh_region); |
| extern eh_region gen_eh_region_allowed (eh_region, tree); |
| extern eh_region gen_eh_region_must_not_throw (eh_region); |
| |
| extern eh_catch gen_eh_region_catch (eh_region, tree); |
| extern eh_landing_pad gen_eh_landing_pad (eh_region); |
| |
| extern eh_region get_eh_region_from_number_fn (struct function *, int); |
| extern eh_region get_eh_region_from_number (int); |
| extern eh_landing_pad get_eh_landing_pad_from_number_fn (struct function*,int); |
| extern eh_landing_pad get_eh_landing_pad_from_number (int); |
| extern eh_region get_eh_region_from_lp_number_fn (struct function *, int); |
| extern eh_region get_eh_region_from_lp_number (int); |
| |
| extern eh_region eh_region_outermost (struct function *, eh_region, eh_region); |
| |
| extern void make_reg_eh_region_note (rtx insn, int ecf_flags, int lp_nr); |
| extern void make_reg_eh_region_note_nothrow_nononlocal (rtx); |
| |
| extern void verify_eh_tree (struct function *); |
| extern void dump_eh_tree (FILE *, struct function *); |
| void debug_eh_tree (struct function *); |
| extern void add_type_for_runtime (tree); |
| extern tree lookup_type_for_runtime (tree); |
| extern void assign_filter_values (void); |
| |
| extern eh_region get_eh_region_from_rtx (const_rtx); |
| extern eh_landing_pad get_eh_landing_pad_from_rtx (const_rtx); |
| |
| /* If non-NULL, this is a function that returns a function decl to be |
| executed if an unhandled exception is propagated out of a cleanup |
| region. For example, in C++, an exception thrown by a destructor |
| during stack unwinding is required to result in a call to |
| `std::terminate', so the C++ version of this function returns a |
| FUNCTION_DECL for `std::terminate'. */ |
| extern tree (*lang_protect_cleanup_actions) (void); |
| |
| /* Return true if type A catches type B. */ |
| extern int (*lang_eh_type_covers) (tree a, tree b); |
| |
| |
| /* Just because the user configured --with-sjlj-exceptions=no doesn't |
| mean that we can use call frame exceptions. Detect that the target |
| has appropriate support. */ |
| |
| #ifndef MUST_USE_SJLJ_EXCEPTIONS |
| # if defined (EH_RETURN_DATA_REGNO) \ |
| && (defined (TARGET_UNWIND_INFO) \ |
| || (DWARF2_UNWIND_INFO \ |
| && (defined (EH_RETURN_HANDLER_RTX) \ |
| || defined (HAVE_eh_return)))) |
| # define MUST_USE_SJLJ_EXCEPTIONS 0 |
| # else |
| # define MUST_USE_SJLJ_EXCEPTIONS 1 |
| # endif |
| #endif |
| |
| #ifdef CONFIG_SJLJ_EXCEPTIONS |
| # if CONFIG_SJLJ_EXCEPTIONS == 1 |
| # define USING_SJLJ_EXCEPTIONS 1 |
| # endif |
| # if CONFIG_SJLJ_EXCEPTIONS == 0 |
| # define USING_SJLJ_EXCEPTIONS 0 |
| # if !defined(EH_RETURN_DATA_REGNO) |
| #error "EH_RETURN_DATA_REGNO required" |
| # endif |
| # if ! (defined(TARGET_UNWIND_INFO) || DWARF2_UNWIND_INFO) |
| #error "{DWARF2,TARGET}_UNWIND_INFO required" |
| # endif |
| # if !defined(TARGET_UNWIND_INFO) \ |
| && !(defined(EH_RETURN_HANDLER_RTX) || defined(HAVE_eh_return)) |
| #error "EH_RETURN_HANDLER_RTX or eh_return required" |
| # endif |
| /* Usually the above error checks will have already triggered an |
| error, but backends may set MUST_USE_SJLJ_EXCEPTIONS for their own |
| reasons. */ |
| # if MUST_USE_SJLJ_EXCEPTIONS |
| #error "Must use SJLJ exceptions but configured not to" |
| # endif |
| # endif |
| #else |
| # define USING_SJLJ_EXCEPTIONS MUST_USE_SJLJ_EXCEPTIONS |
| #endif |
| |
| struct GTY(()) throw_stmt_node { |
| gimple stmt; |
| int lp_nr; |
| }; |
| |
| extern struct htab *get_eh_throw_stmt_table (struct function *); |
| extern void set_eh_throw_stmt_table (struct function *, struct htab *); |
| |
| enum eh_personality_kind { |
| eh_personality_none, |
| eh_personality_any, |
| eh_personality_lang |
| }; |
| |
| extern enum eh_personality_kind |
| function_needs_eh_personality (struct function *); |
| |
| /* Pre-order iteration within the eh_region tree. */ |
| |
| static inline eh_region |
| ehr_next (eh_region r, eh_region start) |
| { |
| if (r->inner) |
| r = r->inner; |
| else if (r->next_peer && r != start) |
| r = r->next_peer; |
| else |
| { |
| do |
| { |
| r = r->outer; |
| if (r == start) |
| return NULL; |
| } |
| while (r->next_peer == NULL); |
| r = r->next_peer; |
| } |
| return r; |
| } |
| |
| #define FOR_ALL_EH_REGION_AT(R, START) \ |
| for ((R) = (START); (R) != NULL; (R) = ehr_next (R, START)) |
| |
| #define FOR_ALL_EH_REGION_FN(R, FN) \ |
| for ((R) = (FN)->eh->region_tree; (R) != NULL; (R) = ehr_next (R, NULL)) |
| |
| #define FOR_ALL_EH_REGION(R) FOR_ALL_EH_REGION_FN (R, cfun) |