/* Python interface to finish breakpoints
- Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ Copyright (C) 2011-2016 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
-#include "exceptions.h"
#include "python-internal.h"
#include "breakpoint.h"
#include "frame.h"
#include "observer.h"
#include "inferior.h"
#include "block.h"
-
-static PyTypeObject finish_breakpoint_object_type;
+#include "location.h"
/* Function that is called when a Python finish bp is found out of scope. */
static char * const outofscope_func = "out_of_scope";
struct finish_breakpoint_object
{
/* gdb.Breakpoint base class. */
- breakpoint_object py_bp;
+ gdbpy_breakpoint_object py_bp;
/* gdb.Type object of the value return by the breakpointed function.
May be NULL if no debug information was available or return type
was VOID. */
PyObject *return_value;
};
+extern PyTypeObject finish_breakpoint_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("finish_breakpoint_object");
+
/* Python function to get the 'return_value' attribute of
FinishBreakpoint. */
`return_value', if possible. */
void
-bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj)
+bpfinishpy_pre_stop_hook (struct gdbpy_breakpoint_object *bp_obj)
{
struct finish_breakpoint_object *self_finishbp =
(struct finish_breakpoint_object *) bp_obj;
- volatile struct gdb_exception except;
/* Can compute return_value only once. */
gdb_assert (!self_finishbp->return_value);
if (!self_finishbp->return_type)
return;
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
struct value *function =
value_object_to_value (self_finishbp->function_value);
self_finishbp->return_value = Py_None;
}
}
- if (except.reason < 0)
+ CATCH (except, RETURN_MASK_ALL)
{
gdbpy_convert_exception (except);
gdbpy_print_stack ();
}
+ END_CATCH
}
/* Triggered when gdbpy_should_stop has triggered the `stop' callback
of the gdb.FinishBreakpoint object BP_OBJ. */
void
-bpfinishpy_post_stop_hook (struct breakpoint_object *bp_obj)
+bpfinishpy_post_stop_hook (struct gdbpy_breakpoint_object *bp_obj)
{
- volatile struct gdb_exception except;
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
/* Can't delete it here, but it will be removed at the next stop. */
disable_breakpoint (bp_obj->bp);
gdb_assert (bp_obj->bp->disposition == disp_del);
}
- if (except.reason < 0)
+ CATCH (except, RETURN_MASK_ALL)
{
gdbpy_convert_exception (except);
gdbpy_print_stack ();
}
+ END_CATCH
}
/* Python function to create a new breakpoint. */
int type = bp_breakpoint;
PyObject *frame_obj = NULL;
int thread;
- struct frame_info *frame, *prev_frame = NULL;
+ struct frame_info *frame = NULL; /* init for gcc -Wall */
+ struct frame_info *prev_frame = NULL;
struct frame_id frame_id;
PyObject *internal = NULL;
int internal_bp = 0;
- CORE_ADDR finish_pc, pc;
- volatile struct gdb_exception except;
- char *addr_str, small_buf[100];
+ CORE_ADDR pc;
struct symbol *function;
if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
&frame_obj, &internal))
return -1;
- /* Default frame to gdb.newest_frame if necessary. */
- if (!frame_obj)
- frame_obj = gdbpy_newest_frame (NULL, NULL);
- else
- Py_INCREF (frame_obj);
-
- frame = frame_object_to_frame_info (frame_obj);
- Py_DECREF (frame_obj);
-
- if (frame == NULL)
- goto invalid_frame;
-
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
- prev_frame = get_prev_frame (frame);
- if (prev_frame == 0)
- {
- PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" not " \
- "meaningful in the outermost "\
- "frame."));
- }
- else if (get_frame_type (prev_frame) == DUMMY_FRAME)
- {
- PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" cannot "\
- "be set on a dummy frame."));
- }
+ /* Default frame to newest frame if necessary. */
+ if (frame_obj == NULL)
+ frame = get_current_frame ();
else
- {
- frame_id = get_frame_id (prev_frame);
- if (frame_id_eq (frame_id, null_frame_id))
- PyErr_SetString (PyExc_ValueError,
- _("Invalid ID for the `frame' object."));
- }
+ frame = frame_object_to_frame_info (frame_obj);
+
+ if (frame == NULL)
+ {
+ PyErr_SetString (PyExc_ValueError,
+ _("Invalid ID for the `frame' object."));
+ }
+ else
+ {
+ prev_frame = get_prev_frame (frame);
+ if (prev_frame == 0)
+ {
+ PyErr_SetString (PyExc_ValueError,
+ _("\"FinishBreakpoint\" not "
+ "meaningful in the outermost "
+ "frame."));
+ }
+ else if (get_frame_type (prev_frame) == DUMMY_FRAME)
+ {
+ PyErr_SetString (PyExc_ValueError,
+ _("\"FinishBreakpoint\" cannot "
+ "be set on a dummy frame."));
+ }
+ else
+ {
+ frame_id = get_frame_id (prev_frame);
+ if (frame_id_eq (frame_id, null_frame_id))
+ PyErr_SetString (PyExc_ValueError,
+ _("Invalid ID for the `frame' object."));
+ }
+ }
}
- if (except.reason < 0)
+ CATCH (except, RETURN_MASK_ALL)
{
gdbpy_convert_exception (except);
return -1;
}
- else if (PyErr_Occurred ())
+ END_CATCH
+
+ if (PyErr_Occurred ())
return -1;
thread = pid_to_thread_id (inferior_ptid);
if (internal)
{
internal_bp = PyObject_IsTrue (internal);
- if (internal_bp == -1)
+ if (internal_bp == -1)
{
- PyErr_SetString (PyExc_ValueError,
+ PyErr_SetString (PyExc_ValueError,
_("The value of `internal' must be a boolean."));
return -1;
}
self_bpfinish->return_type = NULL;
self_bpfinish->function_value = NULL;
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
if (get_frame_pc_if_available (frame, &pc))
{
/* Ignore Python errors at this stage. */
self_bpfinish->return_type = type_to_type_object (ret_type);
PyErr_Clear ();
- func_value = read_var_value (function, frame);
+ func_value = read_var_value (function, NULL, frame);
self_bpfinish->function_value =
value_to_value_object (func_value);
PyErr_Clear ();
}
}
}
- if (except.reason < 0
- || !self_bpfinish->return_type || !self_bpfinish->function_value)
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ /* Just swallow. Either the return type or the function value
+ remain NULL. */
+ }
+ END_CATCH
+
+ if (self_bpfinish->return_type == NULL || self_bpfinish->function_value == NULL)
{
/* Won't be able to compute return value. */
Py_XDECREF (self_bpfinish->return_type);
bppy_pending_object->number = -1;
bppy_pending_object->bp = NULL;
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
- /* Set a breakpoint on the return address. */
- finish_pc = get_frame_pc (prev_frame);
- xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (finish_pc));
- addr_str = small_buf;
+ struct event_location *location;
+ struct cleanup *back_to;
+ /* Set a breakpoint on the return address. */
+ location = new_address_location (get_frame_pc (prev_frame));
+ back_to = make_cleanup_delete_event_location (location);
create_breakpoint (python_gdbarch,
- addr_str, NULL, thread, NULL,
+ location, NULL, thread, NULL,
0,
1 /*temp_flag*/,
bp_breakpoint,
AUTO_BOOLEAN_TRUE,
&bkpt_breakpoint_ops,
0, 1, internal_bp, 0);
+ do_cleanups (back_to);
+ }
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ GDB_PY_SET_HANDLE_EXCEPTION (except);
}
- GDB_PY_SET_HANDLE_EXCEPTION (except);
-
+ END_CATCH
+
self_bpfinish->py_bp.bp->frame_id = frame_id;
self_bpfinish->py_bp.is_finish_bp = 1;
-
+
/* Bind the breakpoint with the current program space. */
self_bpfinish->py_bp.bp->pspace = current_program_space;
return 0;
-
- invalid_frame:
- PyErr_SetString (PyExc_ValueError,
- _("Invalid ID for the `frame' object."));
- return -1;
}
/* Called when GDB notices that the finish breakpoint BP_OBJ is out of
static void
bpfinishpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj)
{
- breakpoint_object *bp_obj = (breakpoint_object *) bpfinish_obj;
+ gdbpy_breakpoint_object *bp_obj = (gdbpy_breakpoint_object *) bpfinish_obj;
PyObject *py_obj = (PyObject *) bp_obj;
if (bpfinish_obj->py_bp.bp->enable_state == bp_enabled
&& PyObject_HasAttrString (py_obj, outofscope_func))
{
- if (!PyObject_CallMethod (py_obj, outofscope_func, NULL))
- gdbpy_print_stack ();
+ PyObject *meth_result;
+
+ meth_result = PyObject_CallMethod (py_obj, outofscope_func, NULL);
+ if (meth_result == NULL)
+ gdbpy_print_stack ();
+ Py_XDECREF (meth_result);
}
delete_breakpoint (bpfinish_obj->py_bp.bp);
static int
bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args)
{
- volatile struct gdb_exception except;
struct breakpoint *bp_stopped = (struct breakpoint *) args;
PyObject *py_bp = (PyObject *) b->py_bp_object;
struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
-
+
/* Trigger out_of_scope if this is a FinishBreakpoint and its frame is
not anymore in the current callstack. */
if (py_bp != NULL && b->py_bp_object->is_finish_bp)
/* Check scope if not currently stopped at the FinishBreakpoint. */
if (b != bp_stopped)
{
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
if (b->pspace == current_inferior ()->pspace
&& (!target_has_registers
|| frame_find_by_id (b->frame_id) == NULL))
bpfinishpy_out_of_scope (finish_bp);
}
- if (except.reason < 0)
+ CATCH (except, RETURN_MASK_ALL)
{
gdbpy_convert_exception (except);
gdbpy_print_stack ();
}
+ END_CATCH
}
}
static void
bpfinishpy_handle_exit (struct inferior *inf)
{
- struct cleanup *cleanup = ensure_python_env (target_gdbarch,
+ struct cleanup *cleanup = ensure_python_env (target_gdbarch (),
current_language);
iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, NULL);
/* Initialize the Python finish breakpoint code. */
-void
+int
gdbpy_initialize_finishbreakpoints (void)
{
if (PyType_Ready (&finish_breakpoint_object_type) < 0)
- return;
-
- Py_INCREF (&finish_breakpoint_object_type);
- PyModule_AddObject (gdb_module, "FinishBreakpoint",
- (PyObject *) &finish_breakpoint_object_type);
-
+ return -1;
+
+ if (gdb_pymodule_addobject (gdb_module, "FinishBreakpoint",
+ (PyObject *) &finish_breakpoint_object_type) < 0)
+ return -1;
+
observer_attach_normal_stop (bpfinishpy_handle_stop);
observer_attach_inferior_exit (bpfinishpy_handle_exit);
+
+ return 0;
}
static PyGetSetDef finish_breakpoint_object_getset[] = {
{ NULL } /* Sentinel. */
};
-static PyTypeObject finish_breakpoint_object_type =
+PyTypeObject finish_breakpoint_object_type =
{
- PyObject_HEAD_INIT (NULL)
- 0, /*ob_size*/
+ PyVarObject_HEAD_INIT (NULL, 0)
"gdb.FinishBreakpoint", /*tp_name*/
sizeof (struct finish_breakpoint_object), /*tp_basicsize*/
0, /*tp_itemsize*/