| /* Exception Handling interface routines. |
| Copyright (C) 1996-2022 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/>. */ |
| |
| /* No include guards here, but define an include file marker anyway, so |
| that the compiler can keep track of where this file is included. This |
| is e.g. used to avoid including this file in front-end specific files. */ |
| #ifndef GCC_EXCEPT_H |
| #define GCC_EXCEPT_H |
| |
| |
| struct function; |
| struct eh_region_d; |
| |
| /* 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 transferred 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 transferred |
| 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_code_label *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; |
| |
| |
| |
| |
| /* 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, va_gc> *region_array; |
| |
| /* The landing pads as an indexable array. */ |
| vec<eh_landing_pad, va_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. */ |
| hash_map<gimple *, int> *GTY(()) 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, va_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, va_gc> *GTY((tag ("1"))) arm_eabi; |
| vec<uchar, va_gc> *GTY((tag ("0"))) other; |
| } GTY ((desc ("targetm.arm_eabi_unwinder"))) ehspec_data; |
| }; |
| |
| |
| /* 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_for_function (void); |
| |
| extern void remove_eh_landing_pad (eh_landing_pad); |
| extern void remove_eh_handler (eh_region); |
| extern void remove_unreachable_eh_regions (sbitmap); |
| |
| extern bool current_function_has_exception_handlers (void); |
| extern void output_function_exception_table (int); |
| |
| 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 hash_map<void *, void *> *duplicate_eh_regions |
| (struct function *, eh_region, int, duplicate_eh_regions_map, void *); |
| |
| extern void sjlj_emit_function_exit_after (rtx_insn *); |
| extern void update_sjlj_context (void); |
| |
| 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 *insn, int ecf_flags, int lp_nr); |
| extern void make_reg_eh_region_note_nothrow_nononlocal (rtx_insn *); |
| |
| 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); |
| |
| extern void finish_eh_generation (void); |
| |
| struct GTY(()) throw_stmt_node { |
| gimple *stmt; |
| int lp_nr; |
| }; |
| |
| extern hash_map<gimple *, int> *get_eh_throw_stmt_table (struct function *); |
| extern void set_eh_throw_stmt_table (function *, hash_map<gimple *, int> *); |
| |
| 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) |
| |
| #endif |