From: Tim Wiederhake Date: Mon, 21 Nov 2016 15:39:57 +0000 (+0100) Subject: python: Create Python bindings for record history. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4726b2d82c89fe6f8e769d1ae9f9e5e528f91156;p=binutils-gdb.git python: Create Python bindings for record history. This patch adds three new functions to the gdb module in Python: - start_recording - stop_recording - current_recording start_recording and current_recording return an object of the new type gdb.Record, which can be used to access the recorded data. Signed-off-by: Tim Wiederhake gdb/ChangeLog * Makefile.in (SUBDIR_PYTHON_OBS): Add python/py-record.o. (SUBDIR_PYTHON_SRCS): Add python/py-record.c. * python/py-record.c: New file. * python/python-internal.h (gdbpy_start_recording, gdbpy_current_recording, gdpy_stop_recording, gdbpy_initialize_record): New export. * python/python.c (_initialize_python): Add gdbpy_initialize_record. (python_GdbMethods): Add gdbpy_start_recording, gdbpy_current_recording and gdbpy_stop_recording. Change-Id: I772aa9aa068621443f10a330b11dc7dc9a63face --- diff --git a/gdb/Makefile.in b/gdb/Makefile.in index e0fe4429381..b4419f02638 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -460,6 +460,7 @@ SUBDIR_PYTHON_OBS = \ py-param.o \ py-prettyprint.o \ py-progspace.o \ + py-record.o \ py-signalevent.o \ py-stopevent.o \ py-symbol.o \ @@ -500,6 +501,7 @@ SUBDIR_PYTHON_SRCS = \ python/py-param.c \ python/py-prettyprint.c \ python/py-progspace.c \ + python/py-record.c \ python/py-signalevent.c \ python/py-stopevent.c \ python/py-symbol.c \ diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c new file mode 100644 index 00000000000..27ecbb68fcf --- /dev/null +++ b/gdb/python/py-record.c @@ -0,0 +1,227 @@ +/* Python interface to record targets. + + Copyright 2016-2017 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 . */ + +#include "defs.h" +#include "inferior.h" +#include "record.h" +#include "python-internal.h" +#include "target.h" + +/* Python Record object. */ + +typedef struct +{ + PyObject_HEAD + + /* The ptid this object refers to. */ + ptid_t ptid; + + /* The current recording method. */ + enum record_method method; +} recpy_record_object; + +/* Python Record type. */ + +static PyTypeObject recpy_record_type = { + PyVarObject_HEAD_INIT (NULL, 0) +}; + +/* Implementation of record.ptid. */ + +static PyObject * +recpy_ptid (PyObject *self, void* closure) +{ + const recpy_record_object * const obj = (recpy_record_object *) self; + + return gdbpy_create_ptid_object (obj->ptid); +} + +/* Implementation of record.method. */ + +static PyObject * +recpy_method (PyObject *self, void* closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.format. */ + +static PyObject * +recpy_format (PyObject *self, void* closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.goto (instruction) -> None. */ + +static PyObject * +recpy_goto (PyObject *self, PyObject *value) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.replay_position [instruction] */ + +static PyObject * +recpy_replay_position (PyObject *self, void *closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.instruction_history [list]. */ + +static PyObject * +recpy_instruction_history (PyObject *self, void* closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.function_call_history [list]. */ + +static PyObject * +recpy_function_call_history (PyObject *self, void* closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.begin [instruction]. */ + +static PyObject * +recpy_begin (PyObject *self, void* closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of record.end [instruction]. */ + +static PyObject * +recpy_end (PyObject *self, void* closure) +{ + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Record method list. */ + +static PyMethodDef recpy_record_methods[] = { + { "goto", recpy_goto, METH_VARARGS, + "goto (instruction|function_call) -> None.\n\ +Rewind to given location."}, + { NULL } +}; + +/* Record member list. */ + +static PyGetSetDef recpy_record_getset[] = { + { "ptid", recpy_ptid, NULL, "Current thread.", NULL }, + { "method", recpy_method, NULL, "Current recording method.", NULL }, + { "format", recpy_format, NULL, "Current recording format.", NULL }, + { "replay_position", recpy_replay_position, NULL, "Current replay position.", + NULL }, + { "instruction_history", recpy_instruction_history, NULL, + "List of instructions in current recording.", NULL }, + { "function_call_history", recpy_function_call_history, NULL, + "List of function calls in current recording.", NULL }, + { "begin", recpy_begin, NULL, + "First instruction in current recording.", NULL }, + { "end", recpy_end, NULL, + "One past the last instruction in current recording. This is typically \ +the current instruction and is used for e.g. record.goto (record.end).", NULL }, + { NULL } +}; + +/* Sets up the record API in the gdb module. */ + +int +gdbpy_initialize_record (void) +{ + recpy_record_type.tp_new = PyType_GenericNew; + recpy_record_type.tp_flags = Py_TPFLAGS_DEFAULT; + recpy_record_type.tp_basicsize = sizeof (recpy_record_object); + recpy_record_type.tp_name = "gdb.Record"; + recpy_record_type.tp_doc = "GDB record object"; + recpy_record_type.tp_methods = recpy_record_methods; + recpy_record_type.tp_getset = recpy_record_getset; + + return PyType_Ready (&recpy_record_type); +} + +/* Implementation of gdb.start_recording (method) -> gdb.Record. */ + +PyObject * +gdbpy_start_recording (PyObject *self, PyObject *args) +{ + const char *method = NULL; + const char *format = NULL; + PyObject *ret = NULL; + + if (!PyArg_ParseTuple (args, "|ss", &method, &format)) + return NULL; + + TRY + { + record_start (method, format, 0); + ret = gdbpy_current_recording (self, args); + } + CATCH (except, RETURN_MASK_ALL) + { + gdbpy_convert_exception (except); + } + END_CATCH + + return ret; +} + +/* Implementation of gdb.current_recording (self) -> gdb.Record. */ + +PyObject * +gdbpy_current_recording (PyObject *self, PyObject *args) +{ + recpy_record_object *ret = NULL; + + if (find_record_target () == NULL) + Py_RETURN_NONE; + + ret = PyObject_New (recpy_record_object, &recpy_record_type); + ret->ptid = inferior_ptid; + ret->method = target_record_method (inferior_ptid); + + return (PyObject *) ret; +} + +/* Implementation of gdb.stop_recording (self) -> None. */ + +PyObject * +gdbpy_stop_recording (PyObject *self, PyObject *args) +{ + PyObject *ret = NULL; + + TRY + { + record_stop (0); + ret = Py_None; + Py_INCREF (Py_None); + } + CATCH (except, RETURN_MASK_ALL) + { + gdbpy_convert_exception (except); + } + END_CATCH + + return ret; +} diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index e2ebc1b8a2a..c6af9f7679d 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -369,6 +369,9 @@ PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *); PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw); PyObject *gdbpy_lookup_global_symbol (PyObject *self, PyObject *args, PyObject *kw); +PyObject *gdbpy_start_recording (PyObject *self, PyObject *args); +PyObject *gdbpy_current_recording (PyObject *self, PyObject *args); +PyObject *gdbpy_stop_recording (PyObject *self, PyObject *args); PyObject *gdbpy_newest_frame (PyObject *self, PyObject *args); PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args); PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args); @@ -436,6 +439,8 @@ int gdbpy_initialize_values (void) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; int gdbpy_initialize_frames (void) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; +int gdbpy_initialize_record (void) + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; int gdbpy_initialize_symtabs (void) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; int gdbpy_initialize_commands (void) diff --git a/gdb/python/python.c b/gdb/python/python.c index 1f5ab4230ef..f8b9f7ea58b 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1628,6 +1628,7 @@ do_start_initialization () || gdbpy_initialize_values () < 0 || gdbpy_initialize_frames () < 0 || gdbpy_initialize_commands () < 0 + || gdbpy_initialize_record () < 0 || gdbpy_initialize_symbols () < 0 || gdbpy_initialize_symtabs () < 0 || gdbpy_initialize_blocks () < 0 @@ -1910,6 +1911,18 @@ Return the selected frame object." }, "stop_reason_string (Integer) -> String.\n\ Return a string explaining unwind stop reason." }, + { "start_recording", gdbpy_start_recording, METH_VARARGS, + "start_recording ([method] [, format]) -> gdb.Record.\n\ +Start recording with the given method. If no method is given, will fall back\n\ +to the system default method. If no format is given, will fall back to the\n\ +default format for the given method."}, + { "current_recording", gdbpy_current_recording, METH_NOARGS, + "current_recording () -> gdb.Record.\n\ +Return current recording object." }, + { "stop_recording", gdbpy_stop_recording, METH_NOARGS, + "stop_recording () -> None.\n\ +Stop current recording." }, + { "lookup_type", (PyCFunction) gdbpy_lookup_type, METH_VARARGS | METH_KEYWORDS, "lookup_type (name [, block]) -> type\n\