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"
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
66 const char *reason_string
;
72 /* Implementation of record.method. */
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. */
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. */
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. */
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] */
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]. */
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]. */
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]. */
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]. */
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. */
198 recpy_insn_new (thread_info
*thread
, enum record_method method
,
201 recpy_element_object
* const obj
= PyObject_New (recpy_element_object
,
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]. */
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]. */
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]. */
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]. */
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]. */
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]. */
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. */
295 recpy_func_new (thread_info
*thread
, enum record_method method
,
298 recpy_element_object
* const obj
= PyObject_New (recpy_element_object
,
304 obj
->thread
= thread
;
305 obj
->method
= method
;
306 obj
->number
= number
;
308 return (PyObject
*) obj
;
311 /* Implementation of RecordFunctionSegment.level [int]. */
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]. */
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]. */
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]. */
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]. */
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]. */
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]. */
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]. */
404 recpy_element_hash (PyObject
*self
)
406 const recpy_element_object
* const obj
= (recpy_element_object
*) self
;
411 /* Implementation of operator == and != of RecordInstruction,
412 RecordFunctionSegment and RecordAuxiliary. */
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
;
429 if (obj1
->thread
== obj2
->thread
430 && obj1
->method
== obj2
->method
431 && obj1
->number
== obj2
->number
)
437 if (obj1
->thread
!= obj2
->thread
438 || obj1
->method
!= obj2
->method
439 || obj1
->number
!= obj2
->number
)
448 Py_INCREF (Py_NotImplemented
);
449 return Py_NotImplemented
;
452 /* Create a new gdb.RecordGap object. */
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
,
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]. */
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]. */
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]. */
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. */
503 recpy_aux_new (thread_info
*thread
, enum record_method method
,
506 recpy_element_object
* const obj
= PyObject_New (recpy_element_object
,
512 obj
->thread
= thread
;
513 obj
->method
= method
;
514 obj
->number
= number
;
516 return (PyObject
*) obj
;
519 /* Implementation of Auxiliary.data [buffer]. */
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\
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.",
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
},
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
},
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
},
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
},
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},
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)
666 /* Implementation of gdb.start_recording (method) -> gdb.Record. */
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
))
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. */
691 gdbpy_current_recording (PyObject
*self
, PyObject
*args
)
693 recpy_record_object
*ret
= NULL
;
695 if (find_record_target () == NULL
)
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. */
708 gdbpy_stop_recording (PyObject
*self
, PyObject
*args
)
714 catch (const gdb_exception
&except
)
716 return gdbpy_handle_gdb_exception (nullptr, except
);
722 GDBPY_INITIALIZE_FILE (gdbpy_initialize_record
);