18dffb485Schristos /* Exception (throw catch) mechanism, for GDB, the GNU debugger. 28dffb485Schristos 3*5ba1f45fSchristos Copyright (C) 1986-2024 Free Software Foundation, Inc. 48dffb485Schristos 58dffb485Schristos This file is part of GDB. 68dffb485Schristos 78dffb485Schristos This program is free software; you can redistribute it and/or modify 88dffb485Schristos it under the terms of the GNU General Public License as published by 98dffb485Schristos the Free Software Foundation; either version 3 of the License, or 108dffb485Schristos (at your option) any later version. 118dffb485Schristos 128dffb485Schristos This program is distributed in the hope that it will be useful, 138dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 148dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 158dffb485Schristos GNU General Public License for more details. 168dffb485Schristos 178dffb485Schristos You should have received a copy of the GNU General Public License 188dffb485Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 198dffb485Schristos 208dffb485Schristos #ifndef COMMON_COMMON_EXCEPTIONS_H 218dffb485Schristos #define COMMON_COMMON_EXCEPTIONS_H 228dffb485Schristos 238dffb485Schristos #include <setjmp.h> 248dffb485Schristos #include <new> 258dffb485Schristos #include <memory> 268dffb485Schristos #include <string> 274b169a6bSchristos #include <functional> 288dffb485Schristos 29*5ba1f45fSchristos #include "gdbsupport/underlying.h" 30*5ba1f45fSchristos 318dffb485Schristos /* Reasons for calling throw_exceptions(). NOTE: all reason values 328dffb485Schristos must be different from zero. enum value 0 is reserved for internal 338dffb485Schristos use as the return value from an initial setjmp(). */ 348dffb485Schristos 358dffb485Schristos enum return_reason 368dffb485Schristos { 37*5ba1f45fSchristos /* SIGTERM sent to GDB. */ 38*5ba1f45fSchristos RETURN_FORCED_QUIT = -3, 398dffb485Schristos /* User interrupt. */ 408dffb485Schristos RETURN_QUIT = -2, 418dffb485Schristos /* Any other error. */ 428dffb485Schristos RETURN_ERROR 438dffb485Schristos }; 448dffb485Schristos 458dffb485Schristos #define RETURN_MASK(reason) (1 << (int)(-reason)) 468dffb485Schristos 478dffb485Schristos typedef enum 488dffb485Schristos { 49*5ba1f45fSchristos RETURN_MASK_FORCED_QUIT = RETURN_MASK (RETURN_FORCED_QUIT), 508dffb485Schristos RETURN_MASK_QUIT = RETURN_MASK (RETURN_QUIT), 518dffb485Schristos RETURN_MASK_ERROR = RETURN_MASK (RETURN_ERROR), 52*5ba1f45fSchristos RETURN_MASK_ALL = (RETURN_MASK_FORCED_QUIT | RETURN_MASK_QUIT | RETURN_MASK_ERROR) 538dffb485Schristos } return_mask; 548dffb485Schristos 558dffb485Schristos /* Describe all exceptions. */ 568dffb485Schristos 578dffb485Schristos enum errors { 588dffb485Schristos GDB_NO_ERROR, 598dffb485Schristos 608dffb485Schristos /* Any generic error, the corresponding text is in 618dffb485Schristos exception.message. */ 628dffb485Schristos GENERIC_ERROR, 638dffb485Schristos 648dffb485Schristos /* Something requested was not found. */ 658dffb485Schristos NOT_FOUND_ERROR, 668dffb485Schristos 678dffb485Schristos /* Thread library lacks support necessary for finding thread local 688dffb485Schristos storage. */ 698dffb485Schristos TLS_NO_LIBRARY_SUPPORT_ERROR, 708dffb485Schristos 718dffb485Schristos /* Load module not found while attempting to find thread local storage. */ 728dffb485Schristos TLS_LOAD_MODULE_NOT_FOUND_ERROR, 738dffb485Schristos 748dffb485Schristos /* Thread local storage has not been allocated yet. */ 758dffb485Schristos TLS_NOT_ALLOCATED_YET_ERROR, 768dffb485Schristos 778dffb485Schristos /* Something else went wrong while attempting to find thread local 788dffb485Schristos storage. The ``struct gdb_exception'' message field provides 798dffb485Schristos more detail. */ 808dffb485Schristos TLS_GENERIC_ERROR, 818dffb485Schristos 828dffb485Schristos /* Problem parsing an XML document. */ 838dffb485Schristos XML_PARSE_ERROR, 848dffb485Schristos 858dffb485Schristos /* Error accessing memory. */ 868dffb485Schristos MEMORY_ERROR, 878dffb485Schristos 888dffb485Schristos /* Value not available. E.g., a register was not collected in a 898dffb485Schristos traceframe. */ 908dffb485Schristos NOT_AVAILABLE_ERROR, 918dffb485Schristos 928dffb485Schristos /* Value was optimized out. Note: if the value was a register, this 938dffb485Schristos means the register was not saved in the frame. */ 948dffb485Schristos OPTIMIZED_OUT_ERROR, 958dffb485Schristos 968dffb485Schristos /* DW_OP_entry_value resolving failed. */ 978dffb485Schristos NO_ENTRY_VALUE_ERROR, 988dffb485Schristos 998dffb485Schristos /* Target throwing an error has been closed. Current command should be 1008dffb485Schristos aborted as the inferior state is no longer valid. */ 1018dffb485Schristos TARGET_CLOSE_ERROR, 1028dffb485Schristos 1038dffb485Schristos /* An undefined command was executed. */ 1048dffb485Schristos UNDEFINED_COMMAND_ERROR, 1058dffb485Schristos 1068dffb485Schristos /* Requested feature, method, mechanism, etc. is not supported. */ 1078dffb485Schristos NOT_SUPPORTED_ERROR, 1088dffb485Schristos 1098dffb485Schristos /* The number of candidates generated during line completion has 1108dffb485Schristos reached the user's specified limit. This isn't an error, this exception 1118dffb485Schristos is used to halt searching for more completions, but for consistency 1128dffb485Schristos "_ERROR" is appended to the name. */ 1138dffb485Schristos MAX_COMPLETIONS_REACHED_ERROR, 1148dffb485Schristos 1158dffb485Schristos /* Add more errors here. */ 1168dffb485Schristos NR_ERRORS 1178dffb485Schristos }; 1188dffb485Schristos 1198dffb485Schristos struct gdb_exception 1208dffb485Schristos { 1218dffb485Schristos gdb_exception () 1228dffb485Schristos : reason ((enum return_reason) 0), 1238dffb485Schristos error (GDB_NO_ERROR) 1248dffb485Schristos { 1258dffb485Schristos } 1268dffb485Schristos 1278dffb485Schristos gdb_exception (enum return_reason r, enum errors e) 1288dffb485Schristos : reason (r), 1298dffb485Schristos error (e) 1308dffb485Schristos { 1318dffb485Schristos } 1328dffb485Schristos 1338dffb485Schristos gdb_exception (enum return_reason r, enum errors e, 1348dffb485Schristos const char *fmt, va_list ap) 1358dffb485Schristos ATTRIBUTE_PRINTF (4, 0) 1368dffb485Schristos : reason (r), 1378dffb485Schristos error (e), 1388dffb485Schristos message (std::make_shared<std::string> (string_vprintf (fmt, ap))) 1398dffb485Schristos { 1408dffb485Schristos } 1418dffb485Schristos 1428dffb485Schristos /* The move constructor exists so that we can mark it "noexcept", 1438dffb485Schristos which is a good practice for any sort of exception object. */ 1448dffb485Schristos explicit gdb_exception (gdb_exception &&other) noexcept = default; 1458dffb485Schristos 1468dffb485Schristos /* The copy constructor exists so that we can mark it "noexcept", 1478dffb485Schristos which is a good practice for any sort of exception object. */ 1488dffb485Schristos gdb_exception (const gdb_exception &other) noexcept 1498dffb485Schristos : reason (other.reason), 1508dffb485Schristos error (other.error), 1518dffb485Schristos message (other.message) 1528dffb485Schristos { 1538dffb485Schristos } 1548dffb485Schristos 1558dffb485Schristos /* The assignment operator exists so that we can mark it "noexcept", 1568dffb485Schristos which is a good practice for any sort of exception object. */ 1578dffb485Schristos gdb_exception &operator= (const gdb_exception &other) noexcept 1588dffb485Schristos { 1598dffb485Schristos reason = other.reason; 1608dffb485Schristos error = other.error; 1618dffb485Schristos message = other.message; 1628dffb485Schristos return *this; 1638dffb485Schristos } 1648dffb485Schristos 1658dffb485Schristos gdb_exception &operator= (gdb_exception &&other) noexcept = default; 1668dffb485Schristos 1678dffb485Schristos /* Return the contents of the exception message, as a C string. The 1688dffb485Schristos string remains owned by the exception object. */ 1698dffb485Schristos const char *what () const noexcept 1708dffb485Schristos { 1718dffb485Schristos return message->c_str (); 1728dffb485Schristos } 1738dffb485Schristos 1744b169a6bSchristos /* Compare two exceptions. */ 1754b169a6bSchristos bool operator== (const gdb_exception &other) const 1764b169a6bSchristos { 1774b169a6bSchristos const char *msg1 = message == nullptr ? "" : what (); 1784b169a6bSchristos const char *msg2 = other.message == nullptr ? "" : other.what (); 1794b169a6bSchristos 1804b169a6bSchristos return (reason == other.reason 1814b169a6bSchristos && error == other.error 1824b169a6bSchristos && strcmp (msg1, msg2) == 0); 1834b169a6bSchristos } 1844b169a6bSchristos 1854b169a6bSchristos /* Compare two exceptions. */ 1864b169a6bSchristos bool operator!= (const gdb_exception &other) const 1874b169a6bSchristos { 1884b169a6bSchristos return !(*this == other); 1894b169a6bSchristos } 1904b169a6bSchristos 1918dffb485Schristos enum return_reason reason; 1928dffb485Schristos enum errors error; 1938dffb485Schristos std::shared_ptr<std::string> message; 1948dffb485Schristos }; 1958dffb485Schristos 1964b169a6bSchristos namespace std 1974b169a6bSchristos { 1984b169a6bSchristos 1994b169a6bSchristos /* Specialization of std::hash for gdb_exception. */ 2004b169a6bSchristos template<> 2014b169a6bSchristos struct hash<gdb_exception> 2024b169a6bSchristos { 2034b169a6bSchristos size_t operator() (const gdb_exception &exc) const 2044b169a6bSchristos { 205*5ba1f45fSchristos size_t result = to_underlying (exc.reason) + to_underlying (exc.error); 2064b169a6bSchristos if (exc.message != nullptr) 2074b169a6bSchristos result += std::hash<std::string> {} (*exc.message); 2084b169a6bSchristos return result; 2094b169a6bSchristos } 2104b169a6bSchristos }; 2114b169a6bSchristos 2124b169a6bSchristos } 2134b169a6bSchristos 2148dffb485Schristos /* Functions to drive the sjlj-based exceptions state machine. Though 2158dffb485Schristos declared here by necessity, these functions should be considered 2168dffb485Schristos internal to the exceptions subsystem and not used other than via 2178dffb485Schristos the TRY/CATCH (or TRY_SJLJ/CATCH_SJLJ) macros defined below. */ 2188dffb485Schristos 2198dffb485Schristos extern jmp_buf *exceptions_state_mc_init (void); 2208dffb485Schristos extern int exceptions_state_mc_action_iter (void); 2218dffb485Schristos extern int exceptions_state_mc_action_iter_1 (void); 2228dffb485Schristos extern int exceptions_state_mc_catch (struct gdb_exception *, int); 2238dffb485Schristos 2248dffb485Schristos /* Macro to wrap up standard try/catch behavior. 2258dffb485Schristos 2268dffb485Schristos The double loop lets us correctly handle code "break"ing out of the 2278dffb485Schristos try catch block. (It works as the "break" only exits the inner 2288dffb485Schristos "while" loop, the outer for loop detects this handling it 2298dffb485Schristos correctly.) Of course "return" and "goto" are not so lucky. 2308dffb485Schristos 2318dffb485Schristos For instance: 2328dffb485Schristos 2338dffb485Schristos *INDENT-OFF* 2348dffb485Schristos 2358dffb485Schristos TRY_SJLJ 2368dffb485Schristos { 2378dffb485Schristos } 2388dffb485Schristos CATCH_SJLJ (e, RETURN_MASK_ERROR) 2398dffb485Schristos { 2408dffb485Schristos switch (e.reason) 2418dffb485Schristos { 2428dffb485Schristos case RETURN_ERROR: ... 2438dffb485Schristos } 2448dffb485Schristos } 2458dffb485Schristos END_CATCH_SJLJ 2468dffb485Schristos 2478dffb485Schristos The SJLJ variants are needed in some cases where gdb exceptions 2488dffb485Schristos need to cross third-party library code compiled without exceptions 2498dffb485Schristos support (e.g., readline). */ 2508dffb485Schristos 2518dffb485Schristos #define TRY_SJLJ \ 2528dffb485Schristos { \ 2538dffb485Schristos jmp_buf *buf = \ 2548dffb485Schristos exceptions_state_mc_init (); \ 2558dffb485Schristos setjmp (*buf); \ 2568dffb485Schristos } \ 2578dffb485Schristos while (exceptions_state_mc_action_iter ()) \ 2588dffb485Schristos while (exceptions_state_mc_action_iter_1 ()) 2598dffb485Schristos 2608dffb485Schristos #define CATCH_SJLJ(EXCEPTION, MASK) \ 2618dffb485Schristos { \ 2628dffb485Schristos struct gdb_exception EXCEPTION; \ 2638dffb485Schristos if (exceptions_state_mc_catch (&(EXCEPTION), MASK)) 2648dffb485Schristos 2658dffb485Schristos #define END_CATCH_SJLJ \ 2668dffb485Schristos } 2678dffb485Schristos 2688dffb485Schristos /* The exception types client code may catch. They're just shims 2698dffb485Schristos around gdb_exception that add nothing but type info. Which is used 2708dffb485Schristos is selected depending on the MASK argument passed to CATCH. */ 2718dffb485Schristos 2728dffb485Schristos struct gdb_exception_error : public gdb_exception 2738dffb485Schristos { 2748dffb485Schristos gdb_exception_error (enum errors e, const char *fmt, va_list ap) 2758dffb485Schristos ATTRIBUTE_PRINTF (3, 0) 2768dffb485Schristos : gdb_exception (RETURN_ERROR, e, fmt, ap) 2778dffb485Schristos { 2788dffb485Schristos } 2798dffb485Schristos 2808dffb485Schristos explicit gdb_exception_error (gdb_exception &&ex) noexcept 2818dffb485Schristos : gdb_exception (std::move (ex)) 2828dffb485Schristos { 2838dffb485Schristos gdb_assert (ex.reason == RETURN_ERROR); 2848dffb485Schristos } 2858dffb485Schristos }; 2868dffb485Schristos 2878dffb485Schristos struct gdb_exception_quit : public gdb_exception 2888dffb485Schristos { 2898dffb485Schristos gdb_exception_quit (const char *fmt, va_list ap) 2908dffb485Schristos ATTRIBUTE_PRINTF (2, 0) 2918dffb485Schristos : gdb_exception (RETURN_QUIT, GDB_NO_ERROR, fmt, ap) 2928dffb485Schristos { 2938dffb485Schristos } 2948dffb485Schristos 2958dffb485Schristos explicit gdb_exception_quit (gdb_exception &&ex) noexcept 2968dffb485Schristos : gdb_exception (std::move (ex)) 2978dffb485Schristos { 2988dffb485Schristos gdb_assert (ex.reason == RETURN_QUIT); 2998dffb485Schristos } 3008dffb485Schristos }; 3018dffb485Schristos 302*5ba1f45fSchristos struct gdb_exception_forced_quit : public gdb_exception 303*5ba1f45fSchristos { 304*5ba1f45fSchristos gdb_exception_forced_quit (const char *fmt, va_list ap) 305*5ba1f45fSchristos ATTRIBUTE_PRINTF (2, 0) 306*5ba1f45fSchristos : gdb_exception (RETURN_FORCED_QUIT, GDB_NO_ERROR, fmt, ap) 307*5ba1f45fSchristos { 308*5ba1f45fSchristos } 309*5ba1f45fSchristos 310*5ba1f45fSchristos explicit gdb_exception_forced_quit (gdb_exception &&ex) noexcept 311*5ba1f45fSchristos : gdb_exception (std::move (ex)) 312*5ba1f45fSchristos { 313*5ba1f45fSchristos gdb_assert (ex.reason == RETURN_FORCED_QUIT); 314*5ba1f45fSchristos } 315*5ba1f45fSchristos }; 316*5ba1f45fSchristos 3178dffb485Schristos /* An exception type that inherits from both std::bad_alloc and a gdb 3188dffb485Schristos exception. This is necessary because operator new can only throw 3198dffb485Schristos std::bad_alloc, and OTOH, we want exceptions thrown due to memory 3208dffb485Schristos allocation error to be caught by all the CATCH/RETURN_MASK_ALL 3218dffb485Schristos spread around the codebase. */ 3228dffb485Schristos 3238dffb485Schristos struct gdb_quit_bad_alloc 3248dffb485Schristos : public gdb_exception_quit, 3258dffb485Schristos public std::bad_alloc 3268dffb485Schristos { 3278dffb485Schristos explicit gdb_quit_bad_alloc (gdb_exception &&ex) noexcept 3288dffb485Schristos : gdb_exception_quit (std::move (ex)), 3298dffb485Schristos std::bad_alloc () 3308dffb485Schristos { 3318dffb485Schristos } 3328dffb485Schristos }; 3338dffb485Schristos 3348dffb485Schristos /* *INDENT-ON* */ 3358dffb485Schristos 3368dffb485Schristos /* Throw an exception (as described by "struct gdb_exception"), 3378dffb485Schristos landing in the inner most containing exception handler established 3388dffb485Schristos using TRY/CATCH. */ 3398dffb485Schristos extern void throw_exception (gdb_exception &&exception) 3408dffb485Schristos ATTRIBUTE_NORETURN; 3418dffb485Schristos 3428dffb485Schristos /* Throw an exception by executing a LONG JUMP to the inner most 3438dffb485Schristos containing exception handler established using TRY_SJLJ. Necessary 3448dffb485Schristos in some cases where we need to throw GDB exceptions across 3458dffb485Schristos third-party library code (e.g., readline). */ 3468dffb485Schristos extern void throw_exception_sjlj (const struct gdb_exception &exception) 3478dffb485Schristos ATTRIBUTE_NORETURN; 3488dffb485Schristos 3498dffb485Schristos /* Convenience wrappers around throw_exception that throw GDB 3508dffb485Schristos errors. */ 3518dffb485Schristos extern void throw_verror (enum errors, const char *fmt, va_list ap) 3528dffb485Schristos ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0); 3538dffb485Schristos extern void throw_vquit (const char *fmt, va_list ap) 3548dffb485Schristos ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0); 3558dffb485Schristos extern void throw_error (enum errors error, const char *fmt, ...) 3568dffb485Schristos ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3); 3578dffb485Schristos extern void throw_quit (const char *fmt, ...) 3588dffb485Schristos ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2); 359*5ba1f45fSchristos extern void throw_forced_quit (const char *fmt, ...) 360*5ba1f45fSchristos ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2); 3618dffb485Schristos 3628dffb485Schristos #endif /* COMMON_COMMON_EXCEPTIONS_H */ 363