More updated translations
[binutils-gdb.git] / gdb / python / py-record.c
blob2995dc10b303c85bf2c85c5c8179179f167945b6
1 /* Python interface to record targets.
3 Copyright 2016-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include "py-instruction.h"
21 #include "py-record.h"
22 #include "py-record-btrace.h"
23 #include "py-record-full.h"
24 #include "target.h"
25 #include "gdbthread.h"
27 /* Python Record type. */
29 static PyTypeObject recpy_record_type = {
30 PyVarObject_HEAD_INIT (NULL, 0)
33 /* Python RecordInstruction type. */
35 PyTypeObject recpy_insn_type = {
36 PyVarObject_HEAD_INIT (NULL, 0)
39 /* Python RecordFunctionSegment type. */
41 PyTypeObject recpy_func_type = {
42 PyVarObject_HEAD_INIT (NULL, 0)
45 /* Python RecordGap type. */
47 static PyTypeObject recpy_gap_type = {
48 PyVarObject_HEAD_INIT (NULL, 0)
51 /* Python RecordAuxiliary type. */
53 PyTypeObject recpy_aux_type = {
54 PyVarObject_HEAD_INIT (nullptr, 0)
57 /* Python RecordGap object. */
58 struct recpy_gap_object
60 PyObject_HEAD
62 /* Reason code. */
63 int reason_code;
65 /* Reason message. */
66 const char *reason_string;
68 /* Element number. */
69 Py_ssize_t number;
72 /* Implementation of record.method. */
74 static PyObject *
75 recpy_method (PyObject *self, void* closure)
77 const recpy_record_object * const obj = (recpy_record_object *) self;
79 if (obj->method == RECORD_METHOD_FULL)
80 return recpy_full_method (self, closure);
82 if (obj->method == RECORD_METHOD_BTRACE)
83 return recpy_bt_method (self, closure);
85 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
88 /* Implementation of record.format. */
90 static PyObject *
91 recpy_format (PyObject *self, void* closure)
93 const recpy_record_object * const obj = (recpy_record_object *) self;
95 if (obj->method == RECORD_METHOD_FULL)
96 return recpy_full_format (self, closure);
98 if (obj->method == RECORD_METHOD_BTRACE)
99 return recpy_bt_format (self, closure);
101 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
104 /* Implementation of record.goto (instruction) -> None. */
106 static PyObject *
107 recpy_goto (PyObject *self, PyObject *value)
109 const recpy_record_object * const obj = (recpy_record_object *) self;
111 if (obj->method == RECORD_METHOD_BTRACE)
112 return recpy_bt_goto (self, value);
114 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
117 /* Implementation of record.clear () -> None. */
119 static PyObject *
120 recpy_clear (PyObject *self, PyObject *value)
122 const recpy_record_object * const obj = (recpy_record_object *) self;
124 if (obj->method == RECORD_METHOD_BTRACE)
125 return recpy_bt_clear (self, value);
127 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
130 /* Implementation of record.replay_position [instruction] */
132 static PyObject *
133 recpy_replay_position (PyObject *self, void *closure)
135 const recpy_record_object * const obj = (recpy_record_object *) self;
137 if (obj->method == RECORD_METHOD_BTRACE)
138 return recpy_bt_replay_position (self, closure);
140 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
143 /* Implementation of record.instruction_history [list]. */
145 static PyObject *
146 recpy_instruction_history (PyObject *self, void* closure)
148 const recpy_record_object * const obj = (recpy_record_object *) self;
150 if (obj->method == RECORD_METHOD_BTRACE)
151 return recpy_bt_instruction_history (self, closure);
153 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
156 /* Implementation of record.function_call_history [list]. */
158 static PyObject *
159 recpy_function_call_history (PyObject *self, void* closure)
161 const recpy_record_object * const obj = (recpy_record_object *) self;
163 if (obj->method == RECORD_METHOD_BTRACE)
164 return recpy_bt_function_call_history (self, closure);
166 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
169 /* Implementation of record.begin [instruction]. */
171 static PyObject *
172 recpy_begin (PyObject *self, void* closure)
174 const recpy_record_object * const obj = (recpy_record_object *) self;
176 if (obj->method == RECORD_METHOD_BTRACE)
177 return recpy_bt_begin (self, closure);
179 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
182 /* Implementation of record.end [instruction]. */
184 static PyObject *
185 recpy_end (PyObject *self, void* closure)
187 const recpy_record_object * const obj = (recpy_record_object *) self;
189 if (obj->method == RECORD_METHOD_BTRACE)
190 return recpy_bt_end (self, closure);
192 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
195 /* Create a new gdb.RecordInstruction object. */
197 PyObject *
198 recpy_insn_new (thread_info *thread, enum record_method method,
199 Py_ssize_t number)
201 recpy_element_object * const obj = PyObject_New (recpy_element_object,
202 &recpy_insn_type);
204 if (obj == NULL)
205 return NULL;
207 obj->thread = thread;
208 obj->method = method;
209 obj->number = number;
211 return (PyObject *) obj;
214 /* Implementation of RecordInstruction.sal [gdb.Symtab_and_line]. */
216 static PyObject *
217 recpy_insn_sal (PyObject *self, void *closure)
219 const recpy_element_object * const obj = (recpy_element_object *) self;
221 if (obj->method == RECORD_METHOD_BTRACE)
222 return recpy_bt_insn_sal (self, closure);
224 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
227 /* Implementation of RecordInstruction.pc [int]. */
229 static PyObject *
230 recpy_insn_pc (PyObject *self, void *closure)
232 const recpy_element_object * const obj = (recpy_element_object *) self;
234 if (obj->method == RECORD_METHOD_BTRACE)
235 return recpy_bt_insn_pc (self, closure);
237 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
240 /* Implementation of RecordInstruction.data [buffer]. */
242 static PyObject *
243 recpy_insn_data (PyObject *self, void *closure)
245 const recpy_element_object * const obj = (recpy_element_object *) self;
247 if (obj->method == RECORD_METHOD_BTRACE)
248 return recpy_bt_insn_data (self, closure);
250 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
253 /* Implementation of RecordInstruction.decoded [str]. */
255 static PyObject *
256 recpy_insn_decoded (PyObject *self, void *closure)
258 const recpy_element_object * const obj = (recpy_element_object *) self;
260 if (obj->method == RECORD_METHOD_BTRACE)
261 return recpy_bt_insn_decoded (self, closure);
263 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
266 /* Implementation of RecordInstruction.size [int]. */
268 static PyObject *
269 recpy_insn_size (PyObject *self, void *closure)
271 const recpy_element_object * const obj = (recpy_element_object *) self;
273 if (obj->method == RECORD_METHOD_BTRACE)
274 return recpy_bt_insn_size (self, closure);
276 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
279 /* Implementation of RecordInstruction.is_speculative [bool]. */
281 static PyObject *
282 recpy_insn_is_speculative (PyObject *self, void *closure)
284 const recpy_element_object * const obj = (recpy_element_object *) self;
286 if (obj->method == RECORD_METHOD_BTRACE)
287 return recpy_bt_insn_is_speculative (self, closure);
289 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
292 /* Create a new gdb.RecordFunctionSegment object. */
294 PyObject *
295 recpy_func_new (thread_info *thread, enum record_method method,
296 Py_ssize_t number)
298 recpy_element_object * const obj = PyObject_New (recpy_element_object,
299 &recpy_func_type);
301 if (obj == NULL)
302 return NULL;
304 obj->thread = thread;
305 obj->method = method;
306 obj->number = number;
308 return (PyObject *) obj;
311 /* Implementation of RecordFunctionSegment.level [int]. */
313 static PyObject *
314 recpy_func_level (PyObject *self, void *closure)
316 const recpy_element_object * const obj = (recpy_element_object *) self;
318 if (obj->method == RECORD_METHOD_BTRACE)
319 return recpy_bt_func_level (self, closure);
321 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
324 /* Implementation of RecordFunctionSegment.symbol [gdb.Symbol]. */
326 static PyObject *
327 recpy_func_symbol (PyObject *self, void *closure)
329 const recpy_element_object * const obj = (recpy_element_object *) self;
331 if (obj->method == RECORD_METHOD_BTRACE)
332 return recpy_bt_func_symbol (self, closure);
334 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
337 /* Implementation of RecordFunctionSegment.instructions [list]. */
339 static PyObject *
340 recpy_func_instructions (PyObject *self, void *closure)
342 const recpy_element_object * const obj = (recpy_element_object *) self;
344 if (obj->method == RECORD_METHOD_BTRACE)
345 return recpy_bt_func_instructions (self, closure);
347 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
350 /* Implementation of RecordFunctionSegment.up [RecordFunctionSegment]. */
352 static PyObject *
353 recpy_func_up (PyObject *self, void *closure)
355 const recpy_element_object * const obj = (recpy_element_object *) self;
357 if (obj->method == RECORD_METHOD_BTRACE)
358 return recpy_bt_func_up (self, closure);
360 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
363 /* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment]. */
365 static PyObject *
366 recpy_func_prev (PyObject *self, void *closure)
368 const recpy_element_object * const obj = (recpy_element_object *) self;
370 if (obj->method == RECORD_METHOD_BTRACE)
371 return recpy_bt_func_prev (self, closure);
373 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
376 /* Implementation of RecordFunctionSegment.next [RecordFunctionSegment]. */
378 static PyObject *
379 recpy_func_next (PyObject *self, void *closure)
381 const recpy_element_object * const obj = (recpy_element_object *) self;
383 if (obj->method == RECORD_METHOD_BTRACE)
384 return recpy_bt_func_next (self, closure);
386 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
389 /* Implementation of RecordInstruction.number [int] and
390 RecordFunctionSegment.number [int]. */
392 static PyObject *
393 recpy_element_number (PyObject *self, void* closure)
395 const recpy_element_object * const obj = (recpy_element_object *) self;
397 return gdb_py_object_from_longest (obj->number).release ();
400 /* Implementation of RecordInstruction.__hash__ [int] and
401 RecordFunctionSegment.__hash__ [int]. */
403 static Py_hash_t
404 recpy_element_hash (PyObject *self)
406 const recpy_element_object * const obj = (recpy_element_object *) self;
408 return obj->number;
411 /* Implementation of operator == and != of RecordInstruction,
412 RecordFunctionSegment and RecordAuxiliary. */
414 static PyObject *
415 recpy_element_richcompare (PyObject *self, PyObject *other, int op)
417 const recpy_element_object * const obj1 = (recpy_element_object *) self;
418 const recpy_element_object * const obj2 = (recpy_element_object *) other;
420 if (Py_TYPE (self) != Py_TYPE (other))
422 Py_INCREF (Py_NotImplemented);
423 return Py_NotImplemented;
426 switch (op)
428 case Py_EQ:
429 if (obj1->thread == obj2->thread
430 && obj1->method == obj2->method
431 && obj1->number == obj2->number)
432 Py_RETURN_TRUE;
433 else
434 Py_RETURN_FALSE;
436 case Py_NE:
437 if (obj1->thread != obj2->thread
438 || obj1->method != obj2->method
439 || obj1->number != obj2->number)
440 Py_RETURN_TRUE;
441 else
442 Py_RETURN_FALSE;
444 default:
445 break;
448 Py_INCREF (Py_NotImplemented);
449 return Py_NotImplemented;
452 /* Create a new gdb.RecordGap object. */
454 PyObject *
455 recpy_gap_new (int reason_code, const char *reason_string, Py_ssize_t number)
457 recpy_gap_object * const obj = PyObject_New (recpy_gap_object,
458 &recpy_gap_type);
460 if (obj == NULL)
461 return NULL;
463 obj->reason_code = reason_code;
464 obj->reason_string = reason_string;
465 obj->number = number;
467 return (PyObject *) obj;
470 /* Implementation of RecordGap.number [int]. */
472 static PyObject *
473 recpy_gap_number (PyObject *self, void *closure)
475 const recpy_gap_object * const obj = (const recpy_gap_object *) self;
477 return gdb_py_object_from_longest (obj->number).release ();
480 /* Implementation of RecordGap.error_code [int]. */
482 static PyObject *
483 recpy_gap_reason_code (PyObject *self, void *closure)
485 const recpy_gap_object * const obj = (const recpy_gap_object *) self;
487 return gdb_py_object_from_longest (obj->reason_code).release ();
490 /* Implementation of RecordGap.error_string [str]. */
492 static PyObject *
493 recpy_gap_reason_string (PyObject *self, void *closure)
495 const recpy_gap_object * const obj = (const recpy_gap_object *) self;
497 return PyUnicode_FromString (obj->reason_string);
500 /* Create a new gdb.Auxiliary object. */
502 PyObject *
503 recpy_aux_new (thread_info *thread, enum record_method method,
504 Py_ssize_t number)
506 recpy_element_object * const obj = PyObject_New (recpy_element_object,
507 &recpy_aux_type);
509 if (obj == NULL)
510 return NULL;
512 obj->thread = thread;
513 obj->method = method;
514 obj->number = number;
516 return (PyObject *) obj;
519 /* Implementation of Auxiliary.data [buffer]. */
521 static PyObject *
522 recpy_aux_data (PyObject *self, void *closure)
524 const recpy_element_object * const obj = (recpy_element_object *) self;
526 if (obj->method == RECORD_METHOD_BTRACE)
527 return recpy_bt_aux_data (self, closure);
529 return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
532 /* Record method list. */
534 static PyMethodDef recpy_record_methods[] = {
535 { "goto", recpy_goto, METH_VARARGS,
536 "goto (instruction|function_call) -> None.\n\
537 Rewind to given location."},
538 { "clear", recpy_clear, METH_VARARGS,
539 "clear () -> None.\n\
540 Clears the trace."},
541 { NULL }
544 /* Record member list. */
546 static gdb_PyGetSetDef recpy_record_getset[] = {
547 { "method", recpy_method, NULL, "Current recording method.", NULL },
548 { "format", recpy_format, NULL, "Current recording format.", NULL },
549 { "replay_position", recpy_replay_position, NULL, "Current replay position.",
550 NULL },
551 { "instruction_history", recpy_instruction_history, NULL,
552 "List of instructions in current recording.", NULL },
553 { "function_call_history", recpy_function_call_history, NULL,
554 "List of function calls in current recording.", NULL },
555 { "begin", recpy_begin, NULL,
556 "First instruction in current recording.", NULL },
557 { "end", recpy_end, NULL,
558 "One past the last instruction in current recording. This is typically \
559 the current instruction and is used for e.g. record.goto (record.end).", NULL },
560 { NULL }
563 /* RecordInstruction member list. */
565 static gdb_PyGetSetDef recpy_insn_getset[] = {
566 { "number", recpy_element_number, NULL, "instruction number", NULL},
567 { "sal", recpy_insn_sal, NULL, "associated symbol and line", NULL},
568 { "pc", recpy_insn_pc, NULL, "instruction address", NULL},
569 { "data", recpy_insn_data, NULL, "raw instruction data", NULL},
570 { "decoded", recpy_insn_decoded, NULL, "decoded instruction", NULL},
571 { "size", recpy_insn_size, NULL, "instruction size in byte", NULL},
572 { "is_speculative", recpy_insn_is_speculative, NULL, "if the instruction was \
573 executed speculatively", NULL},
574 { NULL }
577 /* RecordFunctionSegment member list. */
579 static gdb_PyGetSetDef recpy_func_getset[] = {
580 { "number", recpy_element_number, NULL, "function segment number", NULL},
581 { "level", recpy_func_level, NULL, "call stack level", NULL},
582 { "symbol", recpy_func_symbol, NULL, "associated line and symbol", NULL},
583 { "instructions", recpy_func_instructions, NULL, "list of instructions in \
584 this function segment", NULL},
585 { "up", recpy_func_up, NULL, "caller or returned-to function segment", NULL},
586 { "prev", recpy_func_prev, NULL, "previous segment of this function", NULL},
587 { "next", recpy_func_next, NULL, "next segment of this function", NULL},
588 { NULL }
591 /* RecordGap member list. */
593 static gdb_PyGetSetDef recpy_gap_getset[] = {
594 { "number", recpy_gap_number, NULL, "element number", NULL},
595 { "reason_code", recpy_gap_reason_code, NULL, "reason code", NULL},
596 { "reason_string", recpy_gap_reason_string, NULL, "reason string", NULL},
597 { NULL }
600 /* RecordAuxiliary member list. */
602 static gdb_PyGetSetDef recpy_aux_getset[] = {
603 { "number", recpy_element_number, nullptr, "element number", nullptr},
604 { "data", recpy_aux_data, nullptr, "data", nullptr},
605 { nullptr }
608 /* Sets up the record API in the gdb module. */
610 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
611 gdbpy_initialize_record (void)
613 recpy_record_type.tp_new = PyType_GenericNew;
614 recpy_record_type.tp_flags = Py_TPFLAGS_DEFAULT;
615 recpy_record_type.tp_basicsize = sizeof (recpy_record_object);
616 recpy_record_type.tp_name = "gdb.Record";
617 recpy_record_type.tp_doc = "GDB record object";
618 recpy_record_type.tp_methods = recpy_record_methods;
619 recpy_record_type.tp_getset = recpy_record_getset;
621 recpy_insn_type.tp_new = PyType_GenericNew;
622 recpy_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
623 recpy_insn_type.tp_basicsize = sizeof (recpy_element_object);
624 recpy_insn_type.tp_name = "gdb.RecordInstruction";
625 recpy_insn_type.tp_doc = "GDB recorded instruction object";
626 recpy_insn_type.tp_getset = recpy_insn_getset;
627 recpy_insn_type.tp_richcompare = recpy_element_richcompare;
628 recpy_insn_type.tp_hash = recpy_element_hash;
629 recpy_insn_type.tp_base = py_insn_get_insn_type ();
631 recpy_func_type.tp_new = PyType_GenericNew;
632 recpy_func_type.tp_flags = Py_TPFLAGS_DEFAULT;
633 recpy_func_type.tp_basicsize = sizeof (recpy_element_object);
634 recpy_func_type.tp_name = "gdb.RecordFunctionSegment";
635 recpy_func_type.tp_doc = "GDB record function segment object";
636 recpy_func_type.tp_getset = recpy_func_getset;
637 recpy_func_type.tp_richcompare = recpy_element_richcompare;
638 recpy_func_type.tp_hash = recpy_element_hash;
640 recpy_gap_type.tp_new = PyType_GenericNew;
641 recpy_gap_type.tp_flags = Py_TPFLAGS_DEFAULT;
642 recpy_gap_type.tp_basicsize = sizeof (recpy_gap_object);
643 recpy_gap_type.tp_name = "gdb.RecordGap";
644 recpy_gap_type.tp_doc = "GDB recorded gap object";
645 recpy_gap_type.tp_getset = recpy_gap_getset;
647 recpy_aux_type.tp_new = PyType_GenericNew;
648 recpy_aux_type.tp_flags = Py_TPFLAGS_DEFAULT;
649 recpy_aux_type.tp_basicsize = sizeof (recpy_element_object);
650 recpy_aux_type.tp_name = "gdb.RecordAuxiliary";
651 recpy_aux_type.tp_doc = "GDB recorded auxiliary object";
652 recpy_aux_type.tp_getset = recpy_aux_getset;
653 recpy_aux_type.tp_richcompare = recpy_element_richcompare;
654 recpy_aux_type.tp_hash = recpy_element_hash;
656 if (gdbpy_type_ready (&recpy_record_type) < 0
657 || gdbpy_type_ready (&recpy_insn_type) < 0
658 || gdbpy_type_ready (&recpy_func_type) < 0
659 || gdbpy_type_ready (&recpy_gap_type) < 0
660 || gdbpy_type_ready (&recpy_aux_type) < 0)
661 return -1;
662 else
663 return 0;
666 /* Implementation of gdb.start_recording (method) -> gdb.Record. */
668 PyObject *
669 gdbpy_start_recording (PyObject *self, PyObject *args)
671 const char *method = NULL;
672 const char *format = NULL;
674 if (!PyArg_ParseTuple (args, "|ss", &method, &format))
675 return NULL;
679 record_start (method, format, 0);
680 return gdbpy_current_recording (self, args);
682 catch (const gdb_exception &except)
684 return gdbpy_handle_gdb_exception (nullptr, except);
688 /* Implementation of gdb.current_recording (self) -> gdb.Record. */
690 PyObject *
691 gdbpy_current_recording (PyObject *self, PyObject *args)
693 recpy_record_object *ret = NULL;
695 if (find_record_target () == NULL)
696 Py_RETURN_NONE;
698 ret = PyObject_New (recpy_record_object, &recpy_record_type);
699 ret->thread = inferior_thread ();
700 ret->method = target_record_method (ret->thread->ptid);
702 return (PyObject *) ret;
705 /* Implementation of gdb.stop_recording (self) -> None. */
707 PyObject *
708 gdbpy_stop_recording (PyObject *self, PyObject *args)
712 record_stop (0);
714 catch (const gdb_exception &except)
716 return gdbpy_handle_gdb_exception (nullptr, except);
719 Py_RETURN_NONE;
722 GDBPY_INITIALIZE_FILE (gdbpy_initialize_record);