From patchwork Tue Oct 27 17:11:46 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 9404 Received: (qmail 73383 invoked by alias); 27 Oct 2015 17:11:57 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 73373 invoked by uid 89); 27 Oct 2015 17:11:56 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 27 Oct 2015 17:11:49 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id B752DC0A1467; Tue, 27 Oct 2015 17:11:48 +0000 (UTC) Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t9RHBlst025772; Tue, 27 Oct 2015 13:11:47 -0400 From: Pedro Alves To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH] Don't assume break/continue inside a TRY block works Date: Tue, 27 Oct 2015 17:11:46 +0000 Message-Id: <1445965906-2479-1-git-send-email-palves@redhat.com> In C++, this: try { break; } catch () {} is invalid. However, because our TRY/CATCH macros support it in C, the C++ version of those macros support it too. To catch such assumptions, this adds a (disabled) hack that maps TRY/CATCH to raw C++ try/catch. Then it goes through all instances that building on x86_64 GNU/Linux trips on, fixing them. This isn't strictly necessary yet, but I think it's nicer to try to keep the tree in a state where it's easier to eliminate the TRY/CATCH macros. gdb/ChangeLog: 2015-10-27 Pedro Alves * dwarf2-frame-tailcall.c (dwarf2_tailcall_sniffer_first): Don't assume that "break" breaks out of a TRY/CATCH. * python/py-framefilter.c (py_print_single_arg): Don't assume "continue" breaks out of a TRY/CATCH. * python/py-value.c (valpy_binop_throw): New function, factored out from ... (valpy_binop): ... this. (valpy_richcompare_throw): New function, factored out from ... (valpy_richcompare): ... this. * solib.c (solib_read_symbols): Don't assume "break" breaks out of a TRY/CATCH. * common/common-exceptions.h [USE_RAW_CXX_TRY] : Define as 1-1 wrappers around try/catch. --- gdb/common/common-exceptions.h | 16 ++ gdb/dwarf2-frame-tailcall.c | 16 +- gdb/python/py-framefilter.c | 46 +++--- gdb/python/py-value.c | 340 ++++++++++++++++++++++------------------- gdb/solib.c | 20 +-- 5 files changed, 244 insertions(+), 194 deletions(-) diff --git a/gdb/common/common-exceptions.h b/gdb/common/common-exceptions.h index 2e6a6d9..51795b1 100644 --- a/gdb/common/common-exceptions.h +++ b/gdb/common/common-exceptions.h @@ -195,6 +195,14 @@ struct exception_try_scope void *saved_state; }; +/* Define this to build with TRY/CATCH mapped directly to raw + try/catch. GDB won't work correctly, but building that way catches + code tryin to break/continue out of the try block, along with + spurious code between the TRY and the CATCH block. */ +//#define USE_RAW_CXX_TRY + +#ifndef USE_RAW_CXX_TRY + /* We still need to wrap TRY/CATCH in C++ so that cleanups and C++ exceptions can coexist. The TRY blocked is wrapped in a do/while(0) so that break/continue within the block works the same @@ -216,6 +224,14 @@ struct exception_try_scope { \ exception_rethrow (); \ } +#else + +#define TRY try +#define CATCH(EXCEPTION, MASK) \ + catch (struct gdb_exception ## _ ## MASK &EXCEPTION) +#define END_CATCH + +#endif /* The exception types client code may catch. They're just shims around gdb_exception that add nothing but type info. Which is used diff --git a/gdb/dwarf2-frame-tailcall.c b/gdb/dwarf2-frame-tailcall.c index 952bc14..613cc34 100644 --- a/gdb/dwarf2-frame-tailcall.c +++ b/gdb/dwarf2-frame-tailcall.c @@ -386,13 +386,15 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame, /* call_site_find_chain can throw an exception. */ chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc); - if (entry_cfa_sp_offsetp == NULL) - break; - sp_regnum = gdbarch_sp_regnum (prev_gdbarch); - if (sp_regnum == -1) - break; - prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum); - prev_sp_p = 1; + if (entry_cfa_sp_offsetp != NULL) + { + sp_regnum = gdbarch_sp_regnum (prev_gdbarch); + if (sp_regnum != -1) + { + prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum); + prev_sp_p = 1; + } + } } CATCH (except, RETURN_MASK_ERROR) { diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c index ac97723..0f8dc62 100644 --- a/gdb/python/py-framefilter.c +++ b/gdb/python/py-framefilter.c @@ -448,37 +448,39 @@ py_print_single_arg (struct ui_out *out, { retval = EXT_LANG_BT_ERROR; do_cleanups (cleanups); - continue; } } - if (val != NULL) - annotate_arg_value (value_type (val)); - - /* If the output is to the CLI, and the user option "set print - frame-arguments" is set to none, just output "...". */ - if (! ui_out_is_mi_like_p (out) && args_type == NO_VALUES) - ui_out_field_string (out, "value", "..."); - else + if (retval != EXT_LANG_BT_ERROR) { - /* Otherwise, print the value for both MI and the CLI, except - for the case of MI_PRINT_NO_VALUES. */ - if (args_type != NO_VALUES) + if (val != NULL) + annotate_arg_value (value_type (val)); + + /* If the output is to the CLI, and the user option "set print + frame-arguments" is set to none, just output "...". */ + if (! ui_out_is_mi_like_p (out) && args_type == NO_VALUES) + ui_out_field_string (out, "value", "..."); + else { - if (val == NULL) + /* Otherwise, print the value for both MI and the CLI, except + for the case of MI_PRINT_NO_VALUES. */ + if (args_type != NO_VALUES) { - gdb_assert (fa != NULL && fa->error != NULL); - ui_out_field_fmt (out, "value", - _(""), - fa->error); + if (val == NULL) + { + gdb_assert (fa != NULL && fa->error != NULL); + ui_out_field_fmt (out, "value", + _(""), + fa->error); + } + else if (py_print_value (out, val, opts, 0, args_type, language) + == EXT_LANG_BT_ERROR) + retval = EXT_LANG_BT_ERROR; } - else if (py_print_value (out, val, opts, 0, args_type, language) - == EXT_LANG_BT_ERROR) - retval = EXT_LANG_BT_ERROR; } - } - do_cleanups (cleanups); + do_cleanups (cleanups); + } } CATCH (except, RETURN_MASK_ERROR) { diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index ac6b224..140aaf5 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -1018,133 +1018,147 @@ enum valpy_opcode #define STRIP_REFERENCE(TYPE) \ ((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE)) -/* Returns a value object which is the result of applying the operation - specified by OPCODE to the given arguments. Returns NULL on error, with - a python exception set. */ +/* Helper for valpy_binop. Returns a value object which is the result + of applying the operation specified by OPCODE to the given + arguments. Throws a GDB exception on error. */ + static PyObject * -valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) +valpy_binop_throw (enum valpy_opcode opcode, PyObject *self, PyObject *other) { PyObject *result = NULL; - TRY + struct value *arg1, *arg2; + struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); + struct value *res_val = NULL; + enum exp_opcode op = OP_NULL; + int handled = 0; + + /* If the gdb.Value object is the second operand, then it will be + passed to us as the OTHER argument, and SELF will be an entirely + different kind of object, altogether. Because of this, we can't + assume self is a gdb.Value object and need to convert it from + python as well. */ + arg1 = convert_value_from_python (self); + if (arg1 == NULL) { - struct value *arg1, *arg2; - struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ()); - struct value *res_val = NULL; - enum exp_opcode op = OP_NULL; - int handled = 0; - - /* If the gdb.Value object is the second operand, then it will be passed - to us as the OTHER argument, and SELF will be an entirely different - kind of object, altogether. Because of this, we can't assume self is - a gdb.Value object and need to convert it from python as well. */ - arg1 = convert_value_from_python (self); - if (arg1 == NULL) - { - do_cleanups (cleanup); - break; - } + do_cleanups (cleanup); + return NULL; + } - arg2 = convert_value_from_python (other); - if (arg2 == NULL) - { - do_cleanups (cleanup); - break; - } + arg2 = convert_value_from_python (other); + if (arg2 == NULL) + { + do_cleanups (cleanup); + return NULL; + } - switch (opcode) - { - case VALPY_ADD: + switch (opcode) + { + case VALPY_ADD: + { + struct type *ltype = value_type (arg1); + struct type *rtype = value_type (arg2); + + ltype = check_typedef (ltype); + ltype = STRIP_REFERENCE (ltype); + rtype = check_typedef (rtype); + rtype = STRIP_REFERENCE (rtype); + + handled = 1; + if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && is_integral_type (rtype)) + res_val = value_ptradd (arg1, value_as_long (arg2)); + else if (TYPE_CODE (rtype) == TYPE_CODE_PTR + && is_integral_type (ltype)) + res_val = value_ptradd (arg2, value_as_long (arg1)); + else { - struct type *ltype = value_type (arg1); - struct type *rtype = value_type (arg2); - - ltype = check_typedef (ltype); - ltype = STRIP_REFERENCE (ltype); - rtype = check_typedef (rtype); - rtype = STRIP_REFERENCE (rtype); - - handled = 1; - if (TYPE_CODE (ltype) == TYPE_CODE_PTR - && is_integral_type (rtype)) - res_val = value_ptradd (arg1, value_as_long (arg2)); - else if (TYPE_CODE (rtype) == TYPE_CODE_PTR - && is_integral_type (ltype)) - res_val = value_ptradd (arg2, value_as_long (arg1)); - else - { - handled = 0; - op = BINOP_ADD; - } + handled = 0; + op = BINOP_ADD; } - break; - case VALPY_SUB: + } + break; + case VALPY_SUB: + { + struct type *ltype = value_type (arg1); + struct type *rtype = value_type (arg2); + + ltype = check_typedef (ltype); + ltype = STRIP_REFERENCE (ltype); + rtype = check_typedef (rtype); + rtype = STRIP_REFERENCE (rtype); + + handled = 1; + if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && TYPE_CODE (rtype) == TYPE_CODE_PTR) + /* A ptrdiff_t for the target would be preferable here. */ + res_val = value_from_longest (builtin_type_pyint, + value_ptrdiff (arg1, arg2)); + else if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && is_integral_type (rtype)) + res_val = value_ptradd (arg1, - value_as_long (arg2)); + else { - struct type *ltype = value_type (arg1); - struct type *rtype = value_type (arg2); - - ltype = check_typedef (ltype); - ltype = STRIP_REFERENCE (ltype); - rtype = check_typedef (rtype); - rtype = STRIP_REFERENCE (rtype); - - handled = 1; - if (TYPE_CODE (ltype) == TYPE_CODE_PTR - && TYPE_CODE (rtype) == TYPE_CODE_PTR) - /* A ptrdiff_t for the target would be preferable here. */ - res_val = value_from_longest (builtin_type_pyint, - value_ptrdiff (arg1, arg2)); - else if (TYPE_CODE (ltype) == TYPE_CODE_PTR - && is_integral_type (rtype)) - res_val = value_ptradd (arg1, - value_as_long (arg2)); - else - { - handled = 0; - op = BINOP_SUB; - } + handled = 0; + op = BINOP_SUB; } - break; - case VALPY_MUL: - op = BINOP_MUL; - break; - case VALPY_DIV: - op = BINOP_DIV; - break; - case VALPY_REM: - op = BINOP_REM; - break; - case VALPY_POW: - op = BINOP_EXP; - break; - case VALPY_LSH: - op = BINOP_LSH; - break; - case VALPY_RSH: - op = BINOP_RSH; - break; - case VALPY_BITAND: - op = BINOP_BITWISE_AND; - break; - case VALPY_BITOR: - op = BINOP_BITWISE_IOR; - break; - case VALPY_BITXOR: - op = BINOP_BITWISE_XOR; - break; - } + } + break; + case VALPY_MUL: + op = BINOP_MUL; + break; + case VALPY_DIV: + op = BINOP_DIV; + break; + case VALPY_REM: + op = BINOP_REM; + break; + case VALPY_POW: + op = BINOP_EXP; + break; + case VALPY_LSH: + op = BINOP_LSH; + break; + case VALPY_RSH: + op = BINOP_RSH; + break; + case VALPY_BITAND: + op = BINOP_BITWISE_AND; + break; + case VALPY_BITOR: + op = BINOP_BITWISE_IOR; + break; + case VALPY_BITXOR: + op = BINOP_BITWISE_XOR; + break; + } + + if (!handled) + { + if (binop_user_defined_p (op, arg1, arg2)) + res_val = value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); + else + res_val = value_binop (arg1, arg2, op); + } - if (!handled) - { - if (binop_user_defined_p (op, arg1, arg2)) - res_val = value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); - else - res_val = value_binop (arg1, arg2, op); - } + if (res_val) + result = value_to_value_object (res_val); - if (res_val) - result = value_to_value_object (res_val); + do_cleanups (cleanup); + return result; +} - do_cleanups (cleanup); +/* Returns a value object which is the result of applying the operation + specified by OPCODE to the given arguments. Returns NULL on error, with + a python exception set. */ +static PyObject * +valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) +{ + PyObject *result = NULL; + + TRY + { + result = valpy_binop_throw (opcode, self, other); } CATCH (except, RETURN_MASK_ALL) { @@ -1351,6 +1365,63 @@ valpy_xor (PyObject *self, PyObject *other) return valpy_binop (VALPY_BITXOR, self, other); } +/* Helper for valpy_richcompare. Implements comparison operations for + value objects. Returns true/false on success. Returns -1 with a + Python exception set if a Python error is detected. Throws a GDB + exception on other errors (memory error, etc.). */ + +static int +valpy_richcompare_throw (PyObject *self, PyObject *other, int op) +{ + int result; + struct value *value_other; + struct value *value_self; + struct value *mark = value_mark (); + struct cleanup *cleanup; + + value_other = convert_value_from_python (other); + if (value_other == NULL) + return -1; + + cleanup = make_cleanup_value_free_to_mark (mark); + + value_self = ((value_object *) self)->value; + + switch (op) + { + case Py_LT: + result = value_less (value_self, value_other); + break; + case Py_LE: + result = value_less (value_self, value_other) + || value_equal (value_self, value_other); + break; + case Py_EQ: + result = value_equal (value_self, value_other); + break; + case Py_NE: + result = !value_equal (value_self, value_other); + break; + case Py_GT: + result = value_less (value_other, value_self); + break; + case Py_GE: + result = (value_less (value_other, value_self) + || value_equal (value_self, value_other)); + break; + default: + /* Can't happen. */ + PyErr_SetString (PyExc_NotImplementedError, + _("Invalid operation on gdb.Value.")); + result = -1; + break; + } + + do_cleanups (cleanup); + return result; +} + + /* Implements comparison operations for value objects. Returns NULL on error, with a python exception set. */ static PyObject * @@ -1379,48 +1450,7 @@ valpy_richcompare (PyObject *self, PyObject *other, int op) TRY { - struct value *value_other, *mark = value_mark (); - struct cleanup *cleanup; - - value_other = convert_value_from_python (other); - if (value_other == NULL) - { - result = -1; - break; - } - - cleanup = make_cleanup_value_free_to_mark (mark); - - switch (op) { - case Py_LT: - result = value_less (((value_object *) self)->value, value_other); - break; - case Py_LE: - result = value_less (((value_object *) self)->value, value_other) - || value_equal (((value_object *) self)->value, value_other); - break; - case Py_EQ: - result = value_equal (((value_object *) self)->value, value_other); - break; - case Py_NE: - result = !value_equal (((value_object *) self)->value, value_other); - break; - case Py_GT: - result = value_less (value_other, ((value_object *) self)->value); - break; - case Py_GE: - result = value_less (value_other, ((value_object *) self)->value) - || value_equal (((value_object *) self)->value, value_other); - break; - default: - /* Can't happen. */ - PyErr_SetString (PyExc_NotImplementedError, - _("Invalid operation on gdb.Value.")); - result = -1; - break; - } - - do_cleanups (cleanup); + result = valpy_richcompare_throw (self, other, op); } CATCH (except, RETURN_MASK_ALL) { diff --git a/gdb/solib.c b/gdb/solib.c index ca2c9ab..d715897 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -696,16 +696,16 @@ solib_read_symbols (struct so_list *so, int flags) && so->objfile->addr_low == so->addr_low) break; } - if (so->objfile != NULL) - break; - - sap = build_section_addr_info_from_section_table (so->sections, - so->sections_end); - so->objfile = symbol_file_add_from_bfd (so->abfd, so->so_name, - flags, sap, OBJF_SHARED, - NULL); - so->objfile->addr_low = so->addr_low; - free_section_addr_info (sap); + if (so->objfile == NULL) + { + sap = build_section_addr_info_from_section_table (so->sections, + so->sections_end); + so->objfile = symbol_file_add_from_bfd (so->abfd, so->so_name, + flags, sap, OBJF_SHARED, + NULL); + so->objfile->addr_low = so->addr_low; + free_section_addr_info (sap); + } so->symbols_loaded = 1; }