Commit | Line | Data |
---|---|---|
4726b2d8 TW |
1 | /* Python interface to record targets. |
2 | ||
3 | Copyright 2016-2017 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "inferior.h" | |
22 | #include "record.h" | |
23 | #include "python-internal.h" | |
75c0bdf4 TW |
24 | #include "py-record-btrace.h" |
25 | #include "py-record-full.h" | |
4726b2d8 TW |
26 | #include "target.h" |
27 | ||
28 | /* Python Record object. */ | |
29 | ||
30 | typedef struct | |
31 | { | |
32 | PyObject_HEAD | |
33 | ||
34 | /* The ptid this object refers to. */ | |
35 | ptid_t ptid; | |
36 | ||
37 | /* The current recording method. */ | |
38 | enum record_method method; | |
39 | } recpy_record_object; | |
40 | ||
41 | /* Python Record type. */ | |
42 | ||
43 | static PyTypeObject recpy_record_type = { | |
44 | PyVarObject_HEAD_INIT (NULL, 0) | |
45 | }; | |
46 | ||
47 | /* Implementation of record.ptid. */ | |
48 | ||
49 | static PyObject * | |
50 | recpy_ptid (PyObject *self, void* closure) | |
51 | { | |
52 | const recpy_record_object * const obj = (recpy_record_object *) self; | |
53 | ||
54 | return gdbpy_create_ptid_object (obj->ptid); | |
55 | } | |
56 | ||
57 | /* Implementation of record.method. */ | |
58 | ||
59 | static PyObject * | |
60 | recpy_method (PyObject *self, void* closure) | |
61 | { | |
75c0bdf4 TW |
62 | const recpy_record_object * const obj = (recpy_record_object *) self; |
63 | ||
64 | if (obj->method == RECORD_METHOD_FULL) | |
65 | return recpy_full_method (self, closure); | |
66 | ||
67 | if (obj->method == RECORD_METHOD_BTRACE) | |
68 | return recpy_bt_method (self, closure); | |
69 | ||
4726b2d8 TW |
70 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
71 | } | |
72 | ||
73 | /* Implementation of record.format. */ | |
74 | ||
75 | static PyObject * | |
76 | recpy_format (PyObject *self, void* closure) | |
77 | { | |
75c0bdf4 TW |
78 | const recpy_record_object * const obj = (recpy_record_object *) self; |
79 | ||
80 | if (obj->method == RECORD_METHOD_FULL) | |
81 | return recpy_full_format (self, closure); | |
82 | ||
83 | if (obj->method == RECORD_METHOD_BTRACE) | |
84 | return recpy_bt_format (self, closure); | |
85 | ||
4726b2d8 TW |
86 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
87 | } | |
88 | ||
89 | /* Implementation of record.goto (instruction) -> None. */ | |
90 | ||
91 | static PyObject * | |
92 | recpy_goto (PyObject *self, PyObject *value) | |
93 | { | |
75c0bdf4 TW |
94 | const recpy_record_object * const obj = (recpy_record_object *) self; |
95 | ||
96 | if (obj->method == RECORD_METHOD_BTRACE) | |
97 | return recpy_bt_goto (self, value); | |
98 | ||
4726b2d8 TW |
99 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
100 | } | |
101 | ||
102 | /* Implementation of record.replay_position [instruction] */ | |
103 | ||
104 | static PyObject * | |
105 | recpy_replay_position (PyObject *self, void *closure) | |
106 | { | |
75c0bdf4 TW |
107 | const recpy_record_object * const obj = (recpy_record_object *) self; |
108 | ||
109 | if (obj->method == RECORD_METHOD_BTRACE) | |
110 | return recpy_bt_replay_position (self, closure); | |
111 | ||
4726b2d8 TW |
112 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
113 | } | |
114 | ||
115 | /* Implementation of record.instruction_history [list]. */ | |
116 | ||
117 | static PyObject * | |
118 | recpy_instruction_history (PyObject *self, void* closure) | |
119 | { | |
75c0bdf4 TW |
120 | const recpy_record_object * const obj = (recpy_record_object *) self; |
121 | ||
122 | if (obj->method == RECORD_METHOD_BTRACE) | |
123 | return recpy_bt_instruction_history (self, closure); | |
124 | ||
4726b2d8 TW |
125 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
126 | } | |
127 | ||
128 | /* Implementation of record.function_call_history [list]. */ | |
129 | ||
130 | static PyObject * | |
131 | recpy_function_call_history (PyObject *self, void* closure) | |
132 | { | |
75c0bdf4 TW |
133 | const recpy_record_object * const obj = (recpy_record_object *) self; |
134 | ||
135 | if (obj->method == RECORD_METHOD_BTRACE) | |
136 | return recpy_bt_function_call_history (self, closure); | |
137 | ||
4726b2d8 TW |
138 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
139 | } | |
140 | ||
141 | /* Implementation of record.begin [instruction]. */ | |
142 | ||
143 | static PyObject * | |
144 | recpy_begin (PyObject *self, void* closure) | |
145 | { | |
75c0bdf4 TW |
146 | const recpy_record_object * const obj = (recpy_record_object *) self; |
147 | ||
148 | if (obj->method == RECORD_METHOD_BTRACE) | |
149 | return recpy_bt_begin (self, closure); | |
150 | ||
4726b2d8 TW |
151 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
152 | } | |
153 | ||
154 | /* Implementation of record.end [instruction]. */ | |
155 | ||
156 | static PyObject * | |
157 | recpy_end (PyObject *self, void* closure) | |
158 | { | |
75c0bdf4 TW |
159 | const recpy_record_object * const obj = (recpy_record_object *) self; |
160 | ||
161 | if (obj->method == RECORD_METHOD_BTRACE) | |
162 | return recpy_bt_end (self, closure); | |
163 | ||
4726b2d8 TW |
164 | return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); |
165 | } | |
166 | ||
167 | /* Record method list. */ | |
168 | ||
169 | static PyMethodDef recpy_record_methods[] = { | |
170 | { "goto", recpy_goto, METH_VARARGS, | |
171 | "goto (instruction|function_call) -> None.\n\ | |
172 | Rewind to given location."}, | |
173 | { NULL } | |
174 | }; | |
175 | ||
176 | /* Record member list. */ | |
177 | ||
178 | static PyGetSetDef recpy_record_getset[] = { | |
179 | { "ptid", recpy_ptid, NULL, "Current thread.", NULL }, | |
180 | { "method", recpy_method, NULL, "Current recording method.", NULL }, | |
181 | { "format", recpy_format, NULL, "Current recording format.", NULL }, | |
182 | { "replay_position", recpy_replay_position, NULL, "Current replay position.", | |
183 | NULL }, | |
184 | { "instruction_history", recpy_instruction_history, NULL, | |
185 | "List of instructions in current recording.", NULL }, | |
186 | { "function_call_history", recpy_function_call_history, NULL, | |
187 | "List of function calls in current recording.", NULL }, | |
188 | { "begin", recpy_begin, NULL, | |
189 | "First instruction in current recording.", NULL }, | |
190 | { "end", recpy_end, NULL, | |
191 | "One past the last instruction in current recording. This is typically \ | |
192 | the current instruction and is used for e.g. record.goto (record.end).", NULL }, | |
193 | { NULL } | |
194 | }; | |
195 | ||
196 | /* Sets up the record API in the gdb module. */ | |
197 | ||
198 | int | |
199 | gdbpy_initialize_record (void) | |
200 | { | |
201 | recpy_record_type.tp_new = PyType_GenericNew; | |
202 | recpy_record_type.tp_flags = Py_TPFLAGS_DEFAULT; | |
203 | recpy_record_type.tp_basicsize = sizeof (recpy_record_object); | |
204 | recpy_record_type.tp_name = "gdb.Record"; | |
205 | recpy_record_type.tp_doc = "GDB record object"; | |
206 | recpy_record_type.tp_methods = recpy_record_methods; | |
207 | recpy_record_type.tp_getset = recpy_record_getset; | |
208 | ||
209 | return PyType_Ready (&recpy_record_type); | |
210 | } | |
211 | ||
212 | /* Implementation of gdb.start_recording (method) -> gdb.Record. */ | |
213 | ||
214 | PyObject * | |
215 | gdbpy_start_recording (PyObject *self, PyObject *args) | |
216 | { | |
217 | const char *method = NULL; | |
218 | const char *format = NULL; | |
219 | PyObject *ret = NULL; | |
220 | ||
221 | if (!PyArg_ParseTuple (args, "|ss", &method, &format)) | |
222 | return NULL; | |
223 | ||
224 | TRY | |
225 | { | |
226 | record_start (method, format, 0); | |
227 | ret = gdbpy_current_recording (self, args); | |
228 | } | |
229 | CATCH (except, RETURN_MASK_ALL) | |
230 | { | |
231 | gdbpy_convert_exception (except); | |
232 | } | |
233 | END_CATCH | |
234 | ||
235 | return ret; | |
236 | } | |
237 | ||
238 | /* Implementation of gdb.current_recording (self) -> gdb.Record. */ | |
239 | ||
240 | PyObject * | |
241 | gdbpy_current_recording (PyObject *self, PyObject *args) | |
242 | { | |
243 | recpy_record_object *ret = NULL; | |
244 | ||
245 | if (find_record_target () == NULL) | |
246 | Py_RETURN_NONE; | |
247 | ||
248 | ret = PyObject_New (recpy_record_object, &recpy_record_type); | |
249 | ret->ptid = inferior_ptid; | |
250 | ret->method = target_record_method (inferior_ptid); | |
251 | ||
252 | return (PyObject *) ret; | |
253 | } | |
254 | ||
255 | /* Implementation of gdb.stop_recording (self) -> None. */ | |
256 | ||
257 | PyObject * | |
258 | gdbpy_stop_recording (PyObject *self, PyObject *args) | |
259 | { | |
260 | PyObject *ret = NULL; | |
261 | ||
262 | TRY | |
263 | { | |
264 | record_stop (0); | |
265 | ret = Py_None; | |
266 | Py_INCREF (Py_None); | |
267 | } | |
268 | CATCH (except, RETURN_MASK_ALL) | |
269 | { | |
270 | gdbpy_convert_exception (except); | |
271 | } | |
272 | END_CATCH | |
273 | ||
274 | return ret; | |
275 | } |