123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332 |
- /* Python interface to breakpoints
- Copyright (C) 2008-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "value.h"
- #include "python-internal.h"
- #include "python.h"
- #include "charset.h"
- #include "breakpoint.h"
- #include "gdbcmd.h"
- #include "gdbthread.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"
- /* Debugging of Python breakpoints. */
- static bool pybp_debug;
- /* Implementation of "show debug py-breakpoint". */
- static void
- show_pybp_debug (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Python breakpoint debugging is %s.\n"), value);
- }
- /* Print a "py-breakpoint" debug statement. */
- #define pybp_debug_printf(fmt, ...) \
- debug_prefixed_printf_cond (pybp_debug, "py-breakpoint", fmt, ##__VA_ARGS__)
- /* Print a "py-breakpoint" enter/exit debug statements. */
- #define PYBP_SCOPED_DEBUG_ENTER_EXIT \
- scoped_debug_enter_exit (pybp_debug, "py-breakpoint")
- /* Number of live breakpoints. */
- static int bppy_live;
- /* Variables used to pass information between the Breakpoint
- constructor and the breakpoint-created hook function. */
- gdbpy_breakpoint_object *bppy_pending_object;
- /* Function that is called when a Python condition is evaluated. */
- static const char stop_func[] = "stop";
- /* This is used to initialize various gdb.bp_* constants. */
- struct pybp_code
- {
- /* The name. */
- const char *name;
- /* The code. */
- int code;
- };
- /* Entries related to the type of user set breakpoints. */
- static struct pybp_code pybp_codes[] =
- {
- { "BP_NONE", bp_none},
- { "BP_BREAKPOINT", bp_breakpoint},
- { "BP_HARDWARE_BREAKPOINT", bp_hardware_breakpoint},
- { "BP_WATCHPOINT", bp_watchpoint},
- { "BP_HARDWARE_WATCHPOINT", bp_hardware_watchpoint},
- { "BP_READ_WATCHPOINT", bp_read_watchpoint},
- { "BP_ACCESS_WATCHPOINT", bp_access_watchpoint},
- { "BP_CATCHPOINT", bp_catchpoint},
- {NULL} /* Sentinel. */
- };
- /* Entries related to the type of watchpoint. */
- static struct pybp_code pybp_watch_types[] =
- {
- { "WP_READ", hw_read},
- { "WP_WRITE", hw_write},
- { "WP_ACCESS", hw_access},
- {NULL} /* Sentinel. */
- };
- /* Python function which checks the validity of a breakpoint object. */
- static PyObject *
- bppy_is_valid (PyObject *self, PyObject *args)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- if (self_bp->bp)
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Python function to test whether or not the breakpoint is enabled. */
- static PyObject *
- bppy_get_enabled (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (! self_bp->bp)
- Py_RETURN_FALSE;
- if (self_bp->bp->enable_state == bp_enabled)
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Python function to test whether or not the breakpoint is silent. */
- static PyObject *
- bppy_get_silent (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (self_bp->bp->silent)
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Python function to set the enabled state of a breakpoint. */
- static int
- bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- int cmp;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `enabled' attribute."));
- return -1;
- }
- else if (! PyBool_Check (newvalue))
- {
- PyErr_SetString (PyExc_TypeError,
- _("The value of `enabled' must be a boolean."));
- return -1;
- }
- cmp = PyObject_IsTrue (newvalue);
- if (cmp < 0)
- return -1;
- try
- {
- if (cmp == 1)
- enable_breakpoint (self_bp->bp);
- else
- disable_breakpoint (self_bp->bp);
- }
- catch (const gdb_exception &except)
- {
- GDB_PY_SET_HANDLE_EXCEPTION (except);
- }
- return 0;
- }
- /* Python function to set the 'silent' state of a breakpoint. */
- static int
- bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- int cmp;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `silent' attribute."));
- return -1;
- }
- else if (! PyBool_Check (newvalue))
- {
- PyErr_SetString (PyExc_TypeError,
- _("The value of `silent' must be a boolean."));
- return -1;
- }
- cmp = PyObject_IsTrue (newvalue);
- if (cmp < 0)
- return -1;
- else
- breakpoint_set_silent (self_bp->bp, cmp);
- return 0;
- }
- /* Python function to set the thread of a breakpoint. */
- static int
- bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- long id;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `thread' attribute."));
- return -1;
- }
- else if (PyLong_Check (newvalue))
- {
- if (! gdb_py_int_as_long (newvalue, &id))
- return -1;
- if (!valid_global_thread_id (id))
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("Invalid thread ID."));
- return -1;
- }
- }
- else if (newvalue == Py_None)
- id = -1;
- else
- {
- PyErr_SetString (PyExc_TypeError,
- _("The value of `thread' must be an integer or None."));
- return -1;
- }
- breakpoint_set_thread (self_bp->bp, id);
- return 0;
- }
- /* Python function to set the (Ada) task of a breakpoint. */
- static int
- bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- long id;
- int valid_id = 0;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `task' attribute."));
- return -1;
- }
- else if (PyLong_Check (newvalue))
- {
- if (! gdb_py_int_as_long (newvalue, &id))
- return -1;
- try
- {
- valid_id = valid_task_id (id);
- }
- catch (const gdb_exception &except)
- {
- GDB_PY_SET_HANDLE_EXCEPTION (except);
- }
- if (! valid_id)
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("Invalid task ID."));
- return -1;
- }
- }
- else if (newvalue == Py_None)
- id = 0;
- else
- {
- PyErr_SetString (PyExc_TypeError,
- _("The value of `task' must be an integer or None."));
- return -1;
- }
- breakpoint_set_task (self_bp->bp, id);
- return 0;
- }
- /* Python function which deletes the underlying GDB breakpoint. This
- triggers the breakpoint_deleted observer which will call
- gdbpy_breakpoint_deleted; that function cleans up the Python
- sections. */
- static PyObject *
- bppy_delete_breakpoint (PyObject *self, PyObject *args)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- try
- {
- delete_breakpoint (self_bp->bp);
- }
- catch (const gdb_exception &except)
- {
- GDB_PY_HANDLE_EXCEPTION (except);
- }
- Py_RETURN_NONE;
- }
- /* Python function to set the ignore count of a breakpoint. */
- static int
- bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- long value;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `ignore_count' attribute."));
- return -1;
- }
- else if (!PyLong_Check (newvalue))
- {
- PyErr_SetString (PyExc_TypeError,
- _("The value of `ignore_count' must be an integer."));
- return -1;
- }
- if (! gdb_py_int_as_long (newvalue, &value))
- return -1;
- if (value < 0)
- value = 0;
- try
- {
- set_ignore_count (self_bp->number, (int) value, 0);
- }
- catch (const gdb_exception &except)
- {
- GDB_PY_SET_HANDLE_EXCEPTION (except);
- }
- return 0;
- }
- /* Python function to set the hit count of a breakpoint. */
- static int
- bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `hit_count' attribute."));
- return -1;
- }
- else
- {
- long value;
- if (! gdb_py_int_as_long (newvalue, &value))
- return -1;
- if (value != 0)
- {
- PyErr_SetString (PyExc_AttributeError,
- _("The value of `hit_count' must be zero."));
- return -1;
- }
- }
- self_bp->bp->hit_count = 0;
- return 0;
- }
- /* Python function to get the location of a breakpoint. */
- static PyObject *
- bppy_get_location (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (obj);
- if (obj->bp->type != bp_breakpoint
- && obj->bp->type != bp_hardware_breakpoint)
- Py_RETURN_NONE;
- const char *str = event_location_to_string (obj->bp->location.get ());
- if (! str)
- str = "";
- return host_string_to_python_string (str).release ();
- }
- /* Python function to get the breakpoint expression. */
- static PyObject *
- bppy_get_expression (PyObject *self, void *closure)
- {
- const char *str;
- gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
- struct watchpoint *wp;
- BPPY_REQUIRE_VALID (obj);
- if (!is_watchpoint (obj->bp))
- Py_RETURN_NONE;
- wp = (struct watchpoint *) obj->bp;
- str = wp->exp_string.get ();
- if (! str)
- str = "";
- return host_string_to_python_string (str).release ();
- }
- /* Python function to get the condition expression of a breakpoint. */
- static PyObject *
- bppy_get_condition (PyObject *self, void *closure)
- {
- char *str;
- gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (obj);
- str = obj->bp->cond_string.get ();
- if (! str)
- Py_RETURN_NONE;
- return host_string_to_python_string (str).release ();
- }
- /* Returns 0 on success. Returns -1 on error, with a python exception set.
- */
- static int
- bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
- {
- gdb::unique_xmalloc_ptr<char> exp_holder;
- const char *exp = NULL;
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- struct gdb_exception except;
- BPPY_SET_REQUIRE_VALID (self_bp);
- if (newvalue == NULL)
- {
- PyErr_SetString (PyExc_TypeError,
- _("Cannot delete `condition' attribute."));
- return -1;
- }
- else if (newvalue == Py_None)
- exp = "";
- else
- {
- exp_holder = python_string_to_host_string (newvalue);
- if (exp_holder == NULL)
- return -1;
- exp = exp_holder.get ();
- }
- try
- {
- set_breakpoint_condition (self_bp->bp, exp, 0, false);
- }
- catch (gdb_exception &ex)
- {
- except = std::move (ex);
- }
- GDB_PY_SET_HANDLE_EXCEPTION (except);
- return 0;
- }
- /* Python function to get the commands attached to a breakpoint. */
- static PyObject *
- bppy_get_commands (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- struct breakpoint *bp = self_bp->bp;
- BPPY_REQUIRE_VALID (self_bp);
- if (! self_bp->bp->commands)
- Py_RETURN_NONE;
- string_file stb;
- current_uiout->redirect (&stb);
- try
- {
- print_command_lines (current_uiout, breakpoint_commands (bp), 0);
- }
- catch (const gdb_exception &except)
- {
- current_uiout->redirect (NULL);
- gdbpy_convert_exception (except);
- return NULL;
- }
- current_uiout->redirect (NULL);
- 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. */
- static PyObject *
- bppy_get_type (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- return gdb_py_object_from_longest (self_bp->bp->type).release ();
- }
- /* Python function to get the visibility of the breakpoint. */
- static PyObject *
- bppy_get_visibility (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (user_breakpoint_p (self_bp->bp))
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Python function to determine if the breakpoint is a temporary
- breakpoint. */
- static PyObject *
- bppy_get_temporary (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (self_bp->bp->disposition == disp_del
- || self_bp->bp->disposition == disp_del_at_next_stop)
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Python function to determine if the breakpoint is a pending
- breakpoint. */
- static PyObject *
- bppy_get_pending (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (is_watchpoint (self_bp->bp))
- Py_RETURN_FALSE;
- if (pending_breakpoint_p (self_bp->bp))
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- /* Python function to get the breakpoint's number. */
- static PyObject *
- bppy_get_number (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- return gdb_py_object_from_longest (self_bp->number).release ();
- }
- /* Python function to get the breakpoint's thread ID. */
- static PyObject *
- bppy_get_thread (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (self_bp->bp->thread == -1)
- Py_RETURN_NONE;
- return gdb_py_object_from_longest (self_bp->bp->thread).release ();
- }
- /* Python function to get the breakpoint's task ID (in Ada). */
- static PyObject *
- bppy_get_task (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- if (self_bp->bp->task == 0)
- Py_RETURN_NONE;
- return gdb_py_object_from_longest (self_bp->bp->task).release ();
- }
- /* Python function to get the breakpoint's hit count. */
- static PyObject *
- bppy_get_hit_count (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- return gdb_py_object_from_longest (self_bp->bp->hit_count).release ();
- }
- /* Python function to get the breakpoint's ignore count. */
- static PyObject *
- bppy_get_ignore_count (PyObject *self, void *closure)
- {
- gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
- BPPY_REQUIRE_VALID (self_bp);
- return gdb_py_object_from_longest (self_bp->bp->ignore_count).release ();
- }
- /* 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","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, "|siiOOsssOO", keywords,
- &spec, &type, &access_type,
- &internal,
- &temporary, &source,
- &function, &label, &lineobj,
- &qualified))
- return -1;
- if (lineobj != NULL)
- {
- if (PyLong_Check (lineobj))
- line = xstrprintf ("%ld", PyLong_AsLong (lineobj));
- else if (PyUnicode_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);
- if (internal_bp == -1)
- return -1;
- }
- if (temporary != NULL)
- {
- temporary_bp = PyObject_IsTrue (temporary);
- if (temporary_bp == -1)
- 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
- {
- switch (type)
- {
- case bp_breakpoint:
- case bp_hardware_breakpoint:
- {
- 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 (gdbpy_enter::get_gdbarch (),
- location.get (), NULL, -1, NULL, false,
- 0,
- temporary_bp, type,
- 0,
- AUTO_BOOLEAN_TRUE,
- ops,
- 0, 1, internal_bp, 0);
- break;
- }
- 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)
- awatch_command_wrapper (copy, 0, internal_bp);
- else if (access_type == hw_read)
- rwatch_command_wrapper (copy, 0, internal_bp);
- else
- error(_("Cannot understand watchpoint access type."));
- break;
- }
- case bp_catchpoint:
- error (_("BP_CATCHPOINT not supported"));
- default:
- error(_("Do not understand breakpoint type to set."));
- }
- }
- catch (const gdb_exception &except)
- {
- bppy_pending_object = NULL;
- gdbpy_convert_exception (except);
- return -1;
- }
- BPPY_SET_REQUIRE_VALID ((gdbpy_breakpoint_object *) self);
- return 0;
- }
- /* Append to LIST the breakpoint Python object associated to B.
- Return true on success. Return false on failure, with the Python error
- indicator set. */
- static bool
- build_bp_list (struct breakpoint *b, PyObject *list)
- {
- PyObject *bp = (PyObject *) b->py_bp_object;
- /* Not all breakpoints will have a companion Python object.
- Only breakpoints that were created via bppy_new, or
- breakpoints that were created externally and are tracked by
- the Python Scripting API. */
- if (bp == nullptr)
- return true;
- return PyList_Append (list, bp) == 0;
- }
- /* Static function to return a tuple holding all breakpoints. */
- PyObject *
- gdbpy_breakpoints (PyObject *self, PyObject *args)
- {
- if (bppy_live == 0)
- return PyTuple_New (0);
- gdbpy_ref<> list (PyList_New (0));
- if (list == NULL)
- return NULL;
- /* If build_bp_list returns false, it signals an error condition. In that
- case abandon building the list and return nullptr. */
- for (breakpoint *bp : all_breakpoints ())
- if (!build_bp_list (bp, list.get ()))
- return nullptr;
- return PyList_AsTuple (list.get ());
- }
- /* Call the "stop" method (if implemented) in the breakpoint
- class. If the method returns True, the inferior will be
- stopped at the breakpoint. Otherwise the inferior will be
- allowed to continue. */
- enum ext_lang_bp_stop
- gdbpy_breakpoint_cond_says_stop (const struct extension_language_defn *extlang,
- struct breakpoint *b)
- {
- int stop;
- struct gdbpy_breakpoint_object *bp_obj = b->py_bp_object;
- PyObject *py_bp = (PyObject *) bp_obj;
- if (bp_obj == NULL)
- return EXT_LANG_BP_STOP_UNSET;
- stop = -1;
- gdbpy_enter enter_py (b->gdbarch);
- if (bp_obj->is_finish_bp)
- bpfinishpy_pre_stop_hook (bp_obj);
- if (PyObject_HasAttrString (py_bp, stop_func))
- {
- gdbpy_ref<> result (PyObject_CallMethod (py_bp, stop_func, NULL));
- stop = 1;
- if (result != NULL)
- {
- int evaluate = PyObject_IsTrue (result.get ());
- if (evaluate == -1)
- gdbpy_print_stack ();
- /* If the "stop" function returns False that means
- the Python breakpoint wants GDB to continue. */
- if (! evaluate)
- stop = 0;
- }
- else
- gdbpy_print_stack ();
- }
- if (bp_obj->is_finish_bp)
- bpfinishpy_post_stop_hook (bp_obj);
- if (stop < 0)
- return EXT_LANG_BP_STOP_UNSET;
- return stop ? EXT_LANG_BP_STOP_YES : EXT_LANG_BP_STOP_NO;
- }
- /* Checks if the "stop" method exists in this breakpoint.
- Used by condition_command to ensure mutual exclusion of breakpoint
- conditions. */
- int
- gdbpy_breakpoint_has_cond (const struct extension_language_defn *extlang,
- struct breakpoint *b)
- {
- PyObject *py_bp;
- if (b->py_bp_object == NULL)
- return 0;
- py_bp = (PyObject *) b->py_bp_object;
- gdbpy_enter enter_py (b->gdbarch);
- return PyObject_HasAttrString (py_bp, stop_func);
- }
- /* Event callback functions. */
- /* Callback that is used when a breakpoint is created. This function
- will create a new Python breakpoint object. */
- static void
- gdbpy_breakpoint_created (struct breakpoint *bp)
- {
- PYBP_SCOPED_DEBUG_ENTER_EXIT;
- gdbpy_breakpoint_object *newbp;
- if (!user_breakpoint_p (bp) && bppy_pending_object == NULL)
- {
- pybp_debug_printf ("not attaching python object to this breakpoint");
- return;
- }
- if (bp->type != bp_breakpoint
- && bp->type != bp_hardware_breakpoint
- && bp->type != bp_watchpoint
- && bp->type != bp_hardware_watchpoint
- && bp->type != bp_read_watchpoint
- && bp->type != bp_access_watchpoint
- && bp->type != bp_catchpoint)
- {
- pybp_debug_printf ("is not a breakpoint or watchpoint");
- return;
- }
- gdbpy_enter enter_py (bp->gdbarch);
- if (bppy_pending_object)
- {
- newbp = bppy_pending_object;
- Py_INCREF (newbp);
- bppy_pending_object = NULL;
- pybp_debug_printf ("attaching existing breakpoint object");
- }
- else
- {
- newbp = PyObject_New (gdbpy_breakpoint_object, &breakpoint_object_type);
- pybp_debug_printf ("attaching new breakpoint object");
- }
- if (newbp)
- {
- newbp->number = bp->number;
- newbp->bp = bp;
- newbp->bp->py_bp_object = newbp;
- newbp->is_finish_bp = 0;
- ++bppy_live;
- }
- else
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("Error while creating breakpoint from GDB."));
- gdbpy_print_stack ();
- }
- if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_created))
- {
- if (evpy_emit_event ((PyObject *) newbp,
- gdb_py_events.breakpoint_created) < 0)
- gdbpy_print_stack ();
- }
- }
- /* Callback that is used when a breakpoint is deleted. This will
- invalidate the corresponding Python object. */
- static void
- gdbpy_breakpoint_deleted (struct breakpoint *b)
- {
- PYBP_SCOPED_DEBUG_ENTER_EXIT;
- int num = b->number;
- struct breakpoint *bp = NULL;
- bp = get_breakpoint (num);
- if (bp)
- {
- gdbpy_enter enter_py (b->gdbarch);
- gdbpy_ref<gdbpy_breakpoint_object> bp_obj (bp->py_bp_object);
- if (bp_obj != NULL)
- {
- if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_deleted))
- {
- if (evpy_emit_event ((PyObject *) bp_obj.get (),
- gdb_py_events.breakpoint_deleted) < 0)
- gdbpy_print_stack ();
- }
- bp_obj->bp = NULL;
- --bppy_live;
- }
- }
- }
- /* Callback that is used when a breakpoint is modified. */
- static void
- gdbpy_breakpoint_modified (struct breakpoint *b)
- {
- PYBP_SCOPED_DEBUG_ENTER_EXIT;
- int num = b->number;
- struct breakpoint *bp = NULL;
- bp = get_breakpoint (num);
- if (bp)
- {
- gdbpy_enter enter_py (b->gdbarch);
- PyObject *bp_obj = (PyObject *) bp->py_bp_object;
- if (bp_obj)
- {
- if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_modified))
- {
- if (evpy_emit_event (bp_obj,
- gdb_py_events.breakpoint_modified) < 0)
- gdbpy_print_stack ();
- }
- }
- }
- }
- /* Initialize the Python breakpoint code. */
- int
- gdbpy_initialize_breakpoints (void)
- {
- int i;
- breakpoint_object_type.tp_new = PyType_GenericNew;
- if (PyType_Ready (&breakpoint_object_type) < 0)
- return -1;
- if (gdb_pymodule_addobject (gdb_module, "Breakpoint",
- (PyObject *) &breakpoint_object_type) < 0)
- return -1;
- gdb::observers::breakpoint_created.attach (gdbpy_breakpoint_created,
- "py-breakpoint");
- gdb::observers::breakpoint_deleted.attach (gdbpy_breakpoint_deleted,
- "py-breakpoint");
- gdb::observers::breakpoint_modified.attach (gdbpy_breakpoint_modified,
- "py-breakpoint");
- /* Add breakpoint types constants. */
- for (i = 0; pybp_codes[i].name; ++i)
- {
- 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, pybp_watch_types[i].name,
- pybp_watch_types[i].code) < 0)
- return -1;
- }
- return 0;
- }
- /* Helper function that overrides this Python object's
- PyObject_GenericSetAttr to allow extra validation of the attribute
- being set. */
- static int
- local_setattro (PyObject *self, PyObject *name, PyObject *v)
- {
- gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
- gdb::unique_xmalloc_ptr<char> attr (python_string_to_host_string (name));
- if (attr == NULL)
- return -1;
- /* If the attribute trying to be set is the "stop" method,
- but we already have a condition set in the CLI or other extension
- language, disallow this operation. */
- if (strcmp (attr.get (), stop_func) == 0)
- {
- const struct extension_language_defn *extlang = NULL;
- if (obj->bp->cond_string != NULL)
- extlang = get_ext_lang_defn (EXT_LANG_GDB);
- if (extlang == NULL)
- extlang = get_breakpoint_cond_ext_lang (obj->bp, EXT_LANG_PYTHON);
- if (extlang != NULL)
- {
- 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 (self, name, v);
- }
- static gdb_PyGetSetDef breakpoint_object_getset[] = {
- { "enabled", bppy_get_enabled, bppy_set_enabled,
- "Boolean telling whether the breakpoint is enabled.", NULL },
- { "silent", bppy_get_silent, bppy_set_silent,
- "Boolean telling whether the breakpoint is silent.", NULL },
- { "thread", bppy_get_thread, bppy_set_thread,
- "Thread ID for the breakpoint.\n\
- If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\
- If the value is None, then this breakpoint is not thread-specific.\n\
- No other type of value can be used.", NULL },
- { "task", bppy_get_task, bppy_set_task,
- "Thread ID for the breakpoint.\n\
- If the value is a task ID (integer), then this is an Ada task-specific breakpoint.\n\
- If the value is None, then this breakpoint is not task-specific.\n\
- No other type of value can be used.", NULL },
- { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count,
- "Number of times this breakpoint should be automatically continued.",
- NULL },
- { "number", bppy_get_number, NULL,
- "Breakpoint's number assigned by GDB.", NULL },
- { "hit_count", bppy_get_hit_count, bppy_set_hit_count,
- "Number of times the breakpoint has been hit.\n\
- Can be set to zero to clear the count. No other value is valid\n\
- when setting this property.", NULL },
- { "location", bppy_get_location, NULL,
- "Location of the breakpoint, as specified by the user.", NULL},
- { "expression", bppy_get_expression, NULL,
- "Expression of the breakpoint, as specified by the user.", NULL},
- { "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, bppy_set_commands,
- "Commands of the breakpoint, as specified by the user."},
- { "type", bppy_get_type, NULL,
- "Type of breakpoint."},
- { "visible", bppy_get_visibility, NULL,
- "Whether the breakpoint is visible to the user."},
- { "temporary", bppy_get_temporary, NULL,
- "Whether this breakpoint is a temporary breakpoint."},
- { "pending", bppy_get_pending, NULL,
- "Whether this breakpoint is a pending breakpoint."},
- { NULL } /* Sentinel. */
- };
- static PyMethodDef breakpoint_object_methods[] =
- {
- { "is_valid", bppy_is_valid, METH_NOARGS,
- "Return true if this breakpoint is valid, false if not." },
- { "delete", bppy_delete_breakpoint, METH_NOARGS,
- "Delete the underlying GDB breakpoint." },
- { NULL } /* Sentinel. */
- };
- PyTypeObject breakpoint_object_type =
- {
- PyVarObject_HEAD_INIT (NULL, 0)
- "gdb.Breakpoint", /*tp_name*/
- sizeof (gdbpy_breakpoint_object), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- (setattrofunc)local_setattro, /*tp_setattro */
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- "GDB breakpoint object", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- breakpoint_object_methods, /* tp_methods */
- 0, /* tp_members */
- breakpoint_object_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- bppy_init, /* tp_init */
- 0, /* tp_alloc */
- };
- void _initialize_py_breakpoint ();
- void
- _initialize_py_breakpoint ()
- {
- add_setshow_boolean_cmd
- ("py-breakpoint", class_maintenance, &pybp_debug,
- _("Set Python breakpoint debugging."),
- _("Show Python breakpoint debugging."),
- _("When on, Python breakpoint debugging is enabled."),
- NULL,
- show_pybp_debug,
- &setdebuglist, &showdebuglist);
- }
|