Don't assume break/continue inside a TRY block works

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-29  Pedro Alves  <palves@redhat.com>

	* 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]
	<TRY/CATCH/END_CATCH>: Define as 1-1 wrappers around try/catch.
This commit is contained in:
Pedro Alves 2015-10-29 12:55:01 +00:00
parent f82aa1657b
commit 9c6595ab68
6 changed files with 269 additions and 202 deletions

View File

@ -1,3 +1,20 @@
2015-10-29 Pedro Alves <palves@redhat.com>
* 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]
<TRY/CATCH/END_CATCH>: Define as 1-1 wrappers around try/catch.
2015-10-28 Simon Dardis <Simon.Dardis@imgtec.com>
* mips-linux-tdep.c (mips_linux_in_dynsym_stub): Recognise 'or'

View File

@ -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

View File

@ -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)
{

View File

@ -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)
{
gdb_assert (fa != NULL && fa->error != NULL);
ui_out_field_fmt (out, "value",
_("<error reading variable: %s>"),
fa->error);
}
else if (py_print_value (out, val, opts, 0, args_type, language)
== EXT_LANG_BT_ERROR)
retval = EXT_LANG_BT_ERROR;
}
}
if (val != NULL)
annotate_arg_value (value_type (val));
do_cleanups (cleanups);
/* 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
{
/* 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)
{
gdb_assert (fa != NULL && fa->error != NULL);
ui_out_field_fmt (out, "value",
_("<error reading variable: %s>"),
fa->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);
}
}
CATCH (except, RETURN_MASK_ERROR)
{

View File

@ -1018,6 +1018,136 @@ enum valpy_opcode
#define STRIP_REFERENCE(TYPE) \
((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE))
/* 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_throw (enum valpy_opcode opcode, PyObject *self, PyObject *other)
{
PyObject *result = 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);
return NULL;
}
arg2 = convert_value_from_python (other);
if (arg2 == NULL)
{
do_cleanups (cleanup);
return NULL;
}
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
{
handled = 0;
op = BINOP_ADD;
}
}
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
{
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;
}
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);
do_cleanups (cleanup);
return result;
}
/* 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. */
@ -1028,123 +1158,7 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
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)
{
do_cleanups (cleanup);
break;
}
arg2 = convert_value_from_python (other);
if (arg2 == NULL)
{
do_cleanups (cleanup);
break;
}
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
{
handled = 0;
op = BINOP_ADD;
}
}
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
{
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;
}
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);
do_cleanups (cleanup);
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)
{

View File

@ -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;
}