/* Python interface to breakpoints
- Copyright (C) 2008-2017 Free Software Foundation, Inc.
+ Copyright (C) 2008-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "breakpoint.h"
#include "gdbcmd.h"
#include "gdbthread.h"
-#include "observer.h"
+#include "observable.h"
#include "cli/cli-script.h"
#include "ada-lang.h"
#include "arch-utils.h"
#include "language.h"
#include "location.h"
#include "py-event.h"
+#include "linespec.h"
/* Number of live breakpoints. */
static int bppy_live;
if (cmp < 0)
return -1;
- TRY
+ try
{
if (cmp == 1)
enable_breakpoint (self_bp->bp);
else
disable_breakpoint (self_bp->bp);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_SET_HANDLE_EXCEPTION (except);
}
- END_CATCH
return 0;
}
if (! gdb_py_int_as_long (newvalue, &id))
return -1;
- TRY
+ try
{
valid_id = valid_task_id (id);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_SET_HANDLE_EXCEPTION (except);
}
- END_CATCH
if (! valid_id)
{
BPPY_REQUIRE_VALID (self_bp);
- TRY
+ try
{
delete_breakpoint (self_bp->bp);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
Py_RETURN_NONE;
}
if (value < 0)
value = 0;
- TRY
+ try
{
set_ignore_count (self_bp->number, (int) value, 0);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_SET_HANDLE_EXCEPTION (except);
}
- END_CATCH
return 0;
}
static PyObject *
bppy_get_location (PyObject *self, void *closure)
{
- const char *str;
gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
BPPY_REQUIRE_VALID (obj);
if (obj->bp->type != bp_breakpoint)
Py_RETURN_NONE;
- str = event_location_to_string (obj->bp->location);
+ const char *str = event_location_to_string (obj->bp->location.get ());
if (! str)
str = "";
- return host_string_to_python_string (str);
+ return host_string_to_python_string (str).release ();
}
/* Python function to get the breakpoint expression. */
if (! str)
str = "";
- return host_string_to_python_string (str);
+ return host_string_to_python_string (str).release ();
}
/* Python function to get the condition expression of a breakpoint. */
if (! str)
Py_RETURN_NONE;
- return host_string_to_python_string (str);
+ return host_string_to_python_string (str).release ();
}
/* Returns 0 on success. Returns -1 on error, with a python exception set.
gdb::unique_xmalloc_ptr<char> exp_holder;
const char *exp = NULL;
gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- struct gdb_exception except = exception_none;
+ struct gdb_exception except;
BPPY_SET_REQUIRE_VALID (self_bp);
exp = exp_holder.get ();
}
- TRY
+ try
{
set_breakpoint_condition (self_bp->bp, exp, 0);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (gdb_exception &ex)
{
- except = ex;
+ except = std::move (ex);
}
- END_CATCH
GDB_PY_SET_HANDLE_EXCEPTION (except);
{
gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
struct breakpoint *bp = self_bp->bp;
- long length;
- PyObject *result;
BPPY_REQUIRE_VALID (self_bp);
string_file stb;
current_uiout->redirect (&stb);
- TRY
+ try
{
print_command_lines (current_uiout, breakpoint_commands (bp), 0);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
current_uiout->redirect (NULL);
gdbpy_convert_exception (except);
return NULL;
}
- END_CATCH
current_uiout->redirect (NULL);
- return host_string_to_python_string (stb.c_str ());
+ return host_string_to_python_string (stb.c_str ()).release ();
+}
+
+/* Set the commands attached to a breakpoint. Returns 0 on success.
+ Returns -1 on error, with a python exception set. */
+static int
+bppy_set_commands (PyObject *self, PyObject *newvalue, void *closure)
+{
+ gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
+ struct gdb_exception except;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ gdb::unique_xmalloc_ptr<char> commands
+ (python_string_to_host_string (newvalue));
+ if (commands == nullptr)
+ return -1;
+
+ try
+ {
+ bool first = true;
+ char *save_ptr = nullptr;
+ auto reader
+ = [&] ()
+ {
+ const char *result = strtok_r (first ? commands.get () : nullptr,
+ "\n", &save_ptr);
+ first = false;
+ return result;
+ };
+
+ counted_command_line lines = read_command_lines_1 (reader, 1, nullptr);
+ breakpoint_set_commands (self_bp->bp, std::move (lines));
+ }
+ catch (gdb_exception &ex)
+ {
+ except = std::move (ex);
+ }
+
+ GDB_PY_SET_HANDLE_EXCEPTION (except);
+
+ return 0;
}
/* Python function to get the breakpoint type. */
return PyInt_FromLong (self_bp->bp->ignore_count);
}
+/* Internal function to validate the Python parameters/keywords
+ provided to bppy_init. */
+
+static int
+bppy_init_validate_args (const char *spec, char *source,
+ char *function, char *label,
+ char *line, enum bptype type)
+{
+ /* If spec is defined, ensure that none of the explicit location
+ keywords are also defined. */
+ if (spec != NULL)
+ {
+ if (source != NULL || function != NULL || label != NULL || line != NULL)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Breakpoints specified with spec cannot "
+ "have source, function, label or line defined."));
+ return -1;
+ }
+ }
+ else
+ {
+ /* If spec isn't defined, ensure that the user is not trying to
+ define a watchpoint with an explicit location. */
+ if (type == bp_watchpoint)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Watchpoints cannot be set by explicit "
+ "location parameters."));
+ return -1;
+ }
+ else
+ {
+ /* Otherwise, ensure some explicit locations are defined. */
+ if (source == NULL && function == NULL && label == NULL
+ && line == NULL)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Neither spec nor explicit location set."));
+ return -1;
+ }
+ /* Finally, if source is specified, ensure that line, label
+ or function are specified too. */
+ if (source != NULL && function == NULL && label == NULL
+ && line == NULL)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Specifying a source must also include a "
+ "line, label or function."));
+ return -1;
+ }
+ }
+ }
+ return 1;
+}
+
/* Python function to create a new breakpoint. */
static int
bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
{
static const char *keywords[] = { "spec", "type", "wp_class", "internal",
- "temporary", NULL };
- const char *spec;
- int type = bp_breakpoint;
+ "temporary","source", "function",
+ "label", "line", "qualified", NULL };
+ const char *spec = NULL;
+ enum bptype type = bp_breakpoint;
int access_type = hw_write;
PyObject *internal = NULL;
PyObject *temporary = NULL;
+ PyObject *lineobj = NULL;;
int internal_bp = 0;
int temporary_bp = 0;
+ gdb::unique_xmalloc_ptr<char> line;
+ char *label = NULL;
+ char *source = NULL;
+ char *function = NULL;
+ PyObject * qualified = NULL;
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiOO", keywords,
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|siiOOsssOO", keywords,
&spec, &type, &access_type,
- &internal, &temporary))
+ &internal,
+ &temporary, &source,
+ &function, &label, &lineobj,
+ &qualified))
return -1;
+
+ if (lineobj != NULL)
+ {
+ if (PyInt_Check (lineobj))
+ line.reset (xstrprintf ("%ld", PyInt_AsLong (lineobj)));
+ else if (PyString_Check (lineobj))
+ line = python_string_to_host_string (lineobj);
+ else
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Line keyword should be an integer or a string. "));
+ return -1;
+ }
+ }
+
if (internal)
{
internal_bp = PyObject_IsTrue (internal);
return -1;
}
+ if (bppy_init_validate_args (spec, source, function, label, line.get (),
+ type) == -1)
+ return -1;
+
bppy_pending_object = (gdbpy_breakpoint_object *) self;
bppy_pending_object->number = -1;
bppy_pending_object->bp = NULL;
- TRY
+ try
{
- gdb::unique_xmalloc_ptr<char>
- copy_holder (xstrdup (skip_spaces_const (spec)));
- char *copy = copy_holder.get ();
-
switch (type)
{
case bp_breakpoint:
{
- event_location_up location
- = string_to_event_location_basic (©, current_language);
+ event_location_up location;
+ symbol_name_match_type func_name_match_type
+ = (qualified != NULL && PyObject_IsTrue (qualified)
+ ? symbol_name_match_type::FULL
+ : symbol_name_match_type::WILD);
+
+ if (spec != NULL)
+ {
+ gdb::unique_xmalloc_ptr<char>
+ copy_holder (xstrdup (skip_spaces (spec)));
+ const char *copy = copy_holder.get ();
+
+ location = string_to_event_location (©,
+ current_language,
+ func_name_match_type);
+ }
+ else
+ {
+ struct explicit_location explicit_loc;
+
+ initialize_explicit_location (&explicit_loc);
+ explicit_loc.source_filename = source;
+ explicit_loc.function_name = function;
+ explicit_loc.label_name = label;
+
+ if (line != NULL)
+ explicit_loc.line_offset =
+ linespec_parse_line_offset (line.get ());
+
+ explicit_loc.func_name_match_type = func_name_match_type;
+
+ location = new_explicit_location (&explicit_loc);
+ }
+
+ const struct breakpoint_ops *ops =
+ breakpoint_ops_for_event_location (location.get (), false);
+
create_breakpoint (python_gdbarch,
location.get (), NULL, -1, NULL,
0,
temporary_bp, bp_breakpoint,
0,
AUTO_BOOLEAN_TRUE,
- &bkpt_breakpoint_ops,
+ ops,
0, 1, internal_bp, 0);
break;
}
- case bp_watchpoint:
+ case bp_watchpoint:
{
+ gdb::unique_xmalloc_ptr<char>
+ copy_holder (xstrdup (skip_spaces (spec)));
+ char *copy = copy_holder.get ();
+
if (access_type == hw_write)
watch_command_wrapper (copy, 0, internal_bp);
else if (access_type == hw_access)
error(_("Do not understand breakpoint type to set."));
}
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
bppy_pending_object = NULL;
- PyErr_Format (except.reason == RETURN_QUIT
- ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
- "%s", except.message);
+ gdbpy_convert_exception (except);
return -1;
}
- END_CATCH
BPPY_SET_REQUIRE_VALID ((gdbpy_breakpoint_object *) self);
return 0;
\f
-static int
-build_bp_list (struct breakpoint *b, void *arg)
+static bool
+build_bp_list (struct breakpoint *b, PyObject *list)
{
- PyObject *list = (PyObject *) arg;
PyObject *bp = (PyObject *) b->py_bp_object;
int iserr = 0;
iserr = PyList_Append (list, bp);
if (iserr == -1)
- return 1;
+ return true;
- return 0;
+ return false;
}
/* Static function to return a tuple holding all breakpoints. */
/* If iterate_over_breakpoints returns non NULL it signals an error
condition. In that case abandon building the list and return
NULL. */
- if (iterate_over_breakpoints (build_bp_list, list.get ()) != NULL)
+ auto callback = [&] (breakpoint *bp)
+ {
+ return build_bp_list(bp, list.get ());
+ };
+ if (iterate_over_breakpoints (callback) != NULL)
return NULL;
return PyList_AsTuple (list.get ());
gdbpy_breakpoint_created (struct breakpoint *bp)
{
gdbpy_breakpoint_object *newbp;
- PyGILState_STATE state;
if (!user_breakpoint_p (bp) && bppy_pending_object == NULL)
return;
&& bp->type != bp_access_watchpoint)
return;
- state = PyGILState_Ensure ();
+ struct gdbarch *garch = bp->gdbarch ? bp->gdbarch : get_current_arch ();
+ gdbpy_enter enter_py (garch, current_language);
if (bppy_pending_object)
{
newbp = bppy_pending_object;
+ Py_INCREF (newbp);
bppy_pending_object = NULL;
}
else
newbp->bp = bp;
newbp->bp->py_bp_object = newbp;
newbp->is_finish_bp = 0;
- Py_INCREF (newbp);
++bppy_live;
}
else
gdb_py_events.breakpoint_created) < 0)
gdbpy_print_stack ();
}
-
- PyGILState_Release (state);
}
/* Callback that is used when a breakpoint is deleted. This will
gdbpy_breakpoint_deleted (struct breakpoint *b)
{
int num = b->number;
- PyGILState_STATE state;
struct breakpoint *bp = NULL;
- state = PyGILState_Ensure ();
bp = get_breakpoint (num);
if (bp)
{
+ struct gdbarch *garch = bp->gdbarch ? bp->gdbarch : get_current_arch ();
+ gdbpy_enter enter_py (garch, current_language);
+
gdbpy_ref<gdbpy_breakpoint_object> bp_obj (bp->py_bp_object);
if (bp_obj != NULL)
{
--bppy_live;
}
}
- PyGILState_Release (state);
}
/* Callback that is used when a breakpoint is modified. */
gdbpy_breakpoint_modified (struct breakpoint *b)
{
int num = b->number;
- PyGILState_STATE state;
struct breakpoint *bp = NULL;
- gdbpy_breakpoint_object *bp_obj;
- state = PyGILState_Ensure ();
bp = get_breakpoint (num);
if (bp)
{
+ struct gdbarch *garch = bp->gdbarch ? bp->gdbarch : get_current_arch ();
+ gdbpy_enter enter_py (garch, current_language);
+
PyObject *bp_obj = (PyObject *) bp->py_bp_object;
if (bp_obj)
{
}
}
}
- PyGILState_Release (state);
}
\f
(PyObject *) &breakpoint_object_type) < 0)
return -1;
- observer_attach_breakpoint_created (gdbpy_breakpoint_created);
- observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
- observer_attach_breakpoint_modified (gdbpy_breakpoint_modified);
+ gdb::observers::breakpoint_created.attach (gdbpy_breakpoint_created);
+ gdb::observers::breakpoint_deleted.attach (gdbpy_breakpoint_deleted);
+ gdb::observers::breakpoint_modified.attach (gdbpy_breakpoint_modified);
/* Add breakpoint types constants. */
for (i = 0; pybp_codes[i].name; ++i)
{
- if (PyModule_AddIntConstant (gdb_module,
- /* Cast needed for Python 2.4. */
- (char *) pybp_codes[i].name,
+ if (PyModule_AddIntConstant (gdb_module, pybp_codes[i].name,
pybp_codes[i].code) < 0)
return -1;
}
/* Add watchpoint types constants. */
for (i = 0; pybp_watch_types[i].name; ++i)
{
- if (PyModule_AddIntConstant (gdb_module,
- /* Cast needed for Python 2.4. */
- (char *) pybp_watch_types[i].name,
+ if (PyModule_AddIntConstant (gdb_module, pybp_watch_types[i].name,
pybp_watch_types[i].code) < 0)
return -1;
}
extlang = get_breakpoint_cond_ext_lang (obj->bp, EXT_LANG_PYTHON);
if (extlang != NULL)
{
- char *error_text;
-
- error_text
- = xstrprintf (_("Only one stop condition allowed. There is"
- " currently a %s stop condition defined for"
- " this breakpoint."),
- ext_lang_capitalized_name (extlang));
- PyErr_SetString (PyExc_RuntimeError, error_text);
- xfree (error_text);
+ std::string error_text
+ = string_printf (_("Only one stop condition allowed. There is"
+ " currently a %s stop condition defined for"
+ " this breakpoint."),
+ ext_lang_capitalized_name (extlang));
+ PyErr_SetString (PyExc_RuntimeError, error_text.c_str ());
return -1;
}
}
- return PyObject_GenericSetAttr ((PyObject *)self, name, v);
+ return PyObject_GenericSetAttr (self, name, v);
}
static gdb_PyGetSetDef breakpoint_object_getset[] = {
{ "condition", bppy_get_condition, bppy_set_condition,
"Condition of the breakpoint, as specified by the user,\
or None if no condition set."},
- { "commands", bppy_get_commands, NULL,
+ { "commands", bppy_get_commands, bppy_set_commands,
"Commands of the breakpoint, as specified by the user."},
{ "type", bppy_get_type, NULL,
"Type of breakpoint."},