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:
parent
f82aa1657b
commit
9c6595ab68
6 changed files with 269 additions and 202 deletions
|
@ -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>
|
2015-10-28 Simon Dardis <Simon.Dardis@imgtec.com>
|
||||||
|
|
||||||
* mips-linux-tdep.c (mips_linux_in_dynsym_stub): Recognise 'or'
|
* mips-linux-tdep.c (mips_linux_in_dynsym_stub): Recognise 'or'
|
||||||
|
|
|
@ -195,6 +195,14 @@ struct exception_try_scope
|
||||||
void *saved_state;
|
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++
|
/* We still need to wrap TRY/CATCH in C++ so that cleanups and C++
|
||||||
exceptions can coexist. The TRY blocked is wrapped in a
|
exceptions can coexist. The TRY blocked is wrapped in a
|
||||||
do/while(0) so that break/continue within the block works the same
|
do/while(0) so that break/continue within the block works the same
|
||||||
|
@ -216,6 +224,14 @@ struct exception_try_scope
|
||||||
{ \
|
{ \
|
||||||
exception_rethrow (); \
|
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
|
/* The exception types client code may catch. They're just shims
|
||||||
around gdb_exception that add nothing but type info. Which is used
|
around gdb_exception that add nothing but type info. Which is used
|
||||||
|
|
|
@ -386,13 +386,15 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
|
||||||
/* call_site_find_chain can throw an exception. */
|
/* call_site_find_chain can throw an exception. */
|
||||||
chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc);
|
chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc);
|
||||||
|
|
||||||
if (entry_cfa_sp_offsetp == NULL)
|
if (entry_cfa_sp_offsetp != NULL)
|
||||||
break;
|
{
|
||||||
sp_regnum = gdbarch_sp_regnum (prev_gdbarch);
|
sp_regnum = gdbarch_sp_regnum (prev_gdbarch);
|
||||||
if (sp_regnum == -1)
|
if (sp_regnum != -1)
|
||||||
break;
|
{
|
||||||
prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum);
|
prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum);
|
||||||
prev_sp_p = 1;
|
prev_sp_p = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CATCH (except, RETURN_MASK_ERROR)
|
CATCH (except, RETURN_MASK_ERROR)
|
||||||
{
|
{
|
||||||
|
|
|
@ -448,37 +448,39 @@ py_print_single_arg (struct ui_out *out,
|
||||||
{
|
{
|
||||||
retval = EXT_LANG_BT_ERROR;
|
retval = EXT_LANG_BT_ERROR;
|
||||||
do_cleanups (cleanups);
|
do_cleanups (cleanups);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val != NULL)
|
if (retval != EXT_LANG_BT_ERROR)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
/* Otherwise, print the value for both MI and the CLI, except
|
if (val != NULL)
|
||||||
for the case of MI_PRINT_NO_VALUES. */
|
annotate_arg_value (value_type (val));
|
||||||
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);
|
/* 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)
|
CATCH (except, RETURN_MASK_ERROR)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1018,6 +1018,136 @@ enum valpy_opcode
|
||||||
#define STRIP_REFERENCE(TYPE) \
|
#define STRIP_REFERENCE(TYPE) \
|
||||||
((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (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
|
/* Returns a value object which is the result of applying the operation
|
||||||
specified by OPCODE to the given arguments. Returns NULL on error, with
|
specified by OPCODE to the given arguments. Returns NULL on error, with
|
||||||
a python exception set. */
|
a python exception set. */
|
||||||
|
@ -1028,123 +1158,7 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
|
||||||
|
|
||||||
TRY
|
TRY
|
||||||
{
|
{
|
||||||
struct value *arg1, *arg2;
|
result = valpy_binop_throw (opcode, self, other);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
CATCH (except, RETURN_MASK_ALL)
|
CATCH (except, RETURN_MASK_ALL)
|
||||||
{
|
{
|
||||||
|
@ -1351,6 +1365,63 @@ valpy_xor (PyObject *self, PyObject *other)
|
||||||
return valpy_binop (VALPY_BITXOR, self, 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,
|
/* Implements comparison operations for value objects. Returns NULL on error,
|
||||||
with a python exception set. */
|
with a python exception set. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1379,48 +1450,7 @@ valpy_richcompare (PyObject *self, PyObject *other, int op)
|
||||||
|
|
||||||
TRY
|
TRY
|
||||||
{
|
{
|
||||||
struct value *value_other, *mark = value_mark ();
|
result = valpy_richcompare_throw (self, other, op);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
CATCH (except, RETURN_MASK_ALL)
|
CATCH (except, RETURN_MASK_ALL)
|
||||||
{
|
{
|
||||||
|
|
20
gdb/solib.c
20
gdb/solib.c
|
@ -696,16 +696,16 @@ solib_read_symbols (struct so_list *so, int flags)
|
||||||
&& so->objfile->addr_low == so->addr_low)
|
&& so->objfile->addr_low == so->addr_low)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (so->objfile != NULL)
|
if (so->objfile == NULL)
|
||||||
break;
|
{
|
||||||
|
sap = build_section_addr_info_from_section_table (so->sections,
|
||||||
sap = build_section_addr_info_from_section_table (so->sections,
|
so->sections_end);
|
||||||
so->sections_end);
|
so->objfile = symbol_file_add_from_bfd (so->abfd, so->so_name,
|
||||||
so->objfile = symbol_file_add_from_bfd (so->abfd, so->so_name,
|
flags, sap, OBJF_SHARED,
|
||||||
flags, sap, OBJF_SHARED,
|
NULL);
|
||||||
NULL);
|
so->objfile->addr_low = so->addr_low;
|
||||||
so->objfile->addr_low = so->addr_low;
|
free_section_addr_info (sap);
|
||||||
free_section_addr_info (sap);
|
}
|
||||||
|
|
||||||
so->symbols_loaded = 1;
|
so->symbols_loaded = 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue