Home | History | Annotate | Line # | Download | only in python
      1 /* Python interface to record targets.
      2 
      3    Copyright 2016-2024 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 "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"
     26 
     27 /* Python Record type.  */
     28 
     29 static PyTypeObject recpy_record_type = {
     30   PyVarObject_HEAD_INIT (NULL, 0)
     31 };
     32 
     33 /* Python RecordInstruction type.  */
     34 
     35 PyTypeObject recpy_insn_type = {
     36   PyVarObject_HEAD_INIT (NULL, 0)
     37 };
     38 
     39 /* Python RecordFunctionSegment type.  */
     40 
     41 PyTypeObject recpy_func_type = {
     42   PyVarObject_HEAD_INIT (NULL, 0)
     43 };
     44 
     45 /* Python RecordGap type.  */
     46 
     47 static PyTypeObject recpy_gap_type = {
     48   PyVarObject_HEAD_INIT (NULL, 0)
     49 };
     50 
     51 /* Python RecordGap object.  */
     52 struct recpy_gap_object
     53 {
     54   PyObject_HEAD
     55 
     56   /* Reason code.  */
     57   int reason_code;
     58 
     59   /* Reason message.  */
     60   const char *reason_string;
     61 
     62   /* Element number.  */
     63   Py_ssize_t number;
     64 };
     65 
     66 /* Implementation of record.method.  */
     67 
     68 static PyObject *
     69 recpy_method (PyObject *self, void* closure)
     70 {
     71   const recpy_record_object * const obj = (recpy_record_object *) self;
     72 
     73   if (obj->method == RECORD_METHOD_FULL)
     74     return recpy_full_method (self, closure);
     75 
     76   if (obj->method == RECORD_METHOD_BTRACE)
     77     return recpy_bt_method (self, closure);
     78 
     79   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
     80 }
     81 
     82 /* Implementation of record.format.  */
     83 
     84 static PyObject *
     85 recpy_format (PyObject *self, void* closure)
     86 {
     87   const recpy_record_object * const obj = (recpy_record_object *) self;
     88 
     89   if (obj->method == RECORD_METHOD_FULL)
     90     return recpy_full_format (self, closure);
     91 
     92   if (obj->method == RECORD_METHOD_BTRACE)
     93     return recpy_bt_format (self, closure);
     94 
     95   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
     96 }
     97 
     98 /* Implementation of record.goto (instruction) -> None.  */
     99 
    100 static PyObject *
    101 recpy_goto (PyObject *self, PyObject *value)
    102 {
    103   const recpy_record_object * const obj = (recpy_record_object *) self;
    104 
    105   if (obj->method == RECORD_METHOD_BTRACE)
    106     return recpy_bt_goto (self, value);
    107 
    108   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    109 }
    110 
    111 /* Implementation of record.replay_position [instruction]  */
    112 
    113 static PyObject *
    114 recpy_replay_position (PyObject *self, void *closure)
    115 {
    116   const recpy_record_object * const obj = (recpy_record_object *) self;
    117 
    118   if (obj->method == RECORD_METHOD_BTRACE)
    119     return recpy_bt_replay_position (self, closure);
    120 
    121   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    122 }
    123 
    124 /* Implementation of record.instruction_history [list].  */
    125 
    126 static PyObject *
    127 recpy_instruction_history (PyObject *self, void* closure)
    128 {
    129   const recpy_record_object * const obj = (recpy_record_object *) self;
    130 
    131   if (obj->method == RECORD_METHOD_BTRACE)
    132     return recpy_bt_instruction_history (self, closure);
    133 
    134   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    135 }
    136 
    137 /* Implementation of record.function_call_history [list].  */
    138 
    139 static PyObject *
    140 recpy_function_call_history (PyObject *self, void* closure)
    141 {
    142   const recpy_record_object * const obj = (recpy_record_object *) self;
    143 
    144   if (obj->method == RECORD_METHOD_BTRACE)
    145     return recpy_bt_function_call_history (self, closure);
    146 
    147   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    148 }
    149 
    150 /* Implementation of record.begin [instruction].  */
    151 
    152 static PyObject *
    153 recpy_begin (PyObject *self, void* closure)
    154 {
    155   const recpy_record_object * const obj = (recpy_record_object *) self;
    156 
    157   if (obj->method == RECORD_METHOD_BTRACE)
    158     return recpy_bt_begin (self, closure);
    159 
    160   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    161 }
    162 
    163 /* Implementation of record.end [instruction].  */
    164 
    165 static PyObject *
    166 recpy_end (PyObject *self, void* closure)
    167 {
    168   const recpy_record_object * const obj = (recpy_record_object *) self;
    169 
    170   if (obj->method == RECORD_METHOD_BTRACE)
    171     return recpy_bt_end (self, closure);
    172 
    173   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    174 }
    175 
    176 /* Create a new gdb.RecordInstruction object.  */
    177 
    178 PyObject *
    179 recpy_insn_new (thread_info *thread, enum record_method method,
    180 		Py_ssize_t number)
    181 {
    182   recpy_element_object * const obj = PyObject_New (recpy_element_object,
    183 						   &recpy_insn_type);
    184 
    185   if (obj == NULL)
    186    return NULL;
    187 
    188   obj->thread = thread;
    189   obj->method = method;
    190   obj->number = number;
    191 
    192   return (PyObject *) obj;
    193 }
    194 
    195 /* Implementation of RecordInstruction.sal [gdb.Symtab_and_line].  */
    196 
    197 static PyObject *
    198 recpy_insn_sal (PyObject *self, void *closure)
    199 {
    200   const recpy_element_object * const obj = (recpy_element_object *) self;
    201 
    202   if (obj->method == RECORD_METHOD_BTRACE)
    203     return recpy_bt_insn_sal (self, closure);
    204 
    205   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    206 }
    207 
    208 /* Implementation of RecordInstruction.pc [int].  */
    209 
    210 static PyObject *
    211 recpy_insn_pc (PyObject *self, void *closure)
    212 {
    213   const recpy_element_object * const obj = (recpy_element_object *) self;
    214 
    215   if (obj->method == RECORD_METHOD_BTRACE)
    216     return recpy_bt_insn_pc (self, closure);
    217 
    218   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    219 }
    220 
    221 /* Implementation of RecordInstruction.data [buffer].  */
    222 
    223 static PyObject *
    224 recpy_insn_data (PyObject *self, void *closure)
    225 {
    226   const recpy_element_object * const obj = (recpy_element_object *) self;
    227 
    228   if (obj->method == RECORD_METHOD_BTRACE)
    229     return recpy_bt_insn_data (self, closure);
    230 
    231   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    232 }
    233 
    234 /* Implementation of RecordInstruction.decoded [str].  */
    235 
    236 static PyObject *
    237 recpy_insn_decoded (PyObject *self, void *closure)
    238 {
    239   const recpy_element_object * const obj = (recpy_element_object *) self;
    240 
    241   if (obj->method == RECORD_METHOD_BTRACE)
    242     return recpy_bt_insn_decoded (self, closure);
    243 
    244   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    245 }
    246 
    247 /* Implementation of RecordInstruction.size [int].  */
    248 
    249 static PyObject *
    250 recpy_insn_size (PyObject *self, void *closure)
    251 {
    252   const recpy_element_object * const obj = (recpy_element_object *) self;
    253 
    254   if (obj->method == RECORD_METHOD_BTRACE)
    255     return recpy_bt_insn_size (self, closure);
    256 
    257   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    258 }
    259 
    260 /* Implementation of RecordInstruction.is_speculative [bool].  */
    261 
    262 static PyObject *
    263 recpy_insn_is_speculative (PyObject *self, void *closure)
    264 {
    265   const recpy_element_object * const obj = (recpy_element_object *) self;
    266 
    267   if (obj->method == RECORD_METHOD_BTRACE)
    268     return recpy_bt_insn_is_speculative (self, closure);
    269 
    270   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    271 }
    272 
    273 /* Create a new gdb.RecordFunctionSegment object.  */
    274 
    275 PyObject *
    276 recpy_func_new (thread_info *thread, enum record_method method,
    277 		Py_ssize_t number)
    278 {
    279   recpy_element_object * const obj = PyObject_New (recpy_element_object,
    280 						   &recpy_func_type);
    281 
    282   if (obj == NULL)
    283    return NULL;
    284 
    285   obj->thread = thread;
    286   obj->method = method;
    287   obj->number = number;
    288 
    289   return (PyObject *) obj;
    290 }
    291 
    292 /* Implementation of RecordFunctionSegment.level [int].  */
    293 
    294 static PyObject *
    295 recpy_func_level (PyObject *self, void *closure)
    296 {
    297   const recpy_element_object * const obj = (recpy_element_object *) self;
    298 
    299   if (obj->method == RECORD_METHOD_BTRACE)
    300     return recpy_bt_func_level (self, closure);
    301 
    302   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    303 }
    304 
    305 /* Implementation of RecordFunctionSegment.symbol [gdb.Symbol].  */
    306 
    307 static PyObject *
    308 recpy_func_symbol (PyObject *self, void *closure)
    309 {
    310   const recpy_element_object * const obj = (recpy_element_object *) self;
    311 
    312   if (obj->method == RECORD_METHOD_BTRACE)
    313     return recpy_bt_func_symbol (self, closure);
    314 
    315   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    316 }
    317 
    318 /* Implementation of RecordFunctionSegment.instructions [list].  */
    319 
    320 static PyObject *
    321 recpy_func_instructions (PyObject *self, void *closure)
    322 {
    323   const recpy_element_object * const obj = (recpy_element_object *) self;
    324 
    325   if (obj->method == RECORD_METHOD_BTRACE)
    326     return recpy_bt_func_instructions (self, closure);
    327 
    328   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    329 }
    330 
    331 /* Implementation of RecordFunctionSegment.up [RecordFunctionSegment].  */
    332 
    333 static PyObject *
    334 recpy_func_up (PyObject *self, void *closure)
    335 {
    336   const recpy_element_object * const obj = (recpy_element_object *) self;
    337 
    338   if (obj->method == RECORD_METHOD_BTRACE)
    339     return recpy_bt_func_up (self, closure);
    340 
    341   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    342 }
    343 
    344 /* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment].  */
    345 
    346 static PyObject *
    347 recpy_func_prev (PyObject *self, void *closure)
    348 {
    349   const recpy_element_object * const obj = (recpy_element_object *) self;
    350 
    351   if (obj->method == RECORD_METHOD_BTRACE)
    352     return recpy_bt_func_prev (self, closure);
    353 
    354   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    355 }
    356 
    357 /* Implementation of RecordFunctionSegment.next [RecordFunctionSegment].  */
    358 
    359 static PyObject *
    360 recpy_func_next (PyObject *self, void *closure)
    361 {
    362   const recpy_element_object * const obj = (recpy_element_object *) self;
    363 
    364   if (obj->method == RECORD_METHOD_BTRACE)
    365     return recpy_bt_func_next (self, closure);
    366 
    367   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    368 }
    369 
    370 /* Implementation of RecordInstruction.number [int] and
    371    RecordFunctionSegment.number [int].  */
    372 
    373 static PyObject *
    374 recpy_element_number (PyObject *self, void* closure)
    375 {
    376   const recpy_element_object * const obj = (recpy_element_object *) self;
    377 
    378   return gdb_py_object_from_longest (obj->number).release ();
    379 }
    380 
    381 /* Implementation of RecordInstruction.__hash__ [int] and
    382    RecordFunctionSegment.__hash__ [int].  */
    383 
    384 static Py_hash_t
    385 recpy_element_hash (PyObject *self)
    386 {
    387   const recpy_element_object * const obj = (recpy_element_object *) self;
    388 
    389   return obj->number;
    390 }
    391 
    392 /* Implementation of operator == and != of RecordInstruction and
    393    RecordFunctionSegment.  */
    394 
    395 static PyObject *
    396 recpy_element_richcompare (PyObject *self, PyObject *other, int op)
    397 {
    398   const recpy_element_object * const obj1 = (recpy_element_object *) self;
    399   const recpy_element_object * const obj2 = (recpy_element_object *) other;
    400 
    401   if (Py_TYPE (self) != Py_TYPE (other))
    402     {
    403       Py_INCREF (Py_NotImplemented);
    404       return Py_NotImplemented;
    405     }
    406 
    407   switch (op)
    408   {
    409     case Py_EQ:
    410       if (obj1->thread == obj2->thread
    411 	  && obj1->method == obj2->method
    412 	  && obj1->number == obj2->number)
    413 	Py_RETURN_TRUE;
    414       else
    415 	Py_RETURN_FALSE;
    416 
    417     case Py_NE:
    418       if (obj1->thread != obj2->thread
    419 	  || obj1->method != obj2->method
    420 	  || obj1->number != obj2->number)
    421 	Py_RETURN_TRUE;
    422       else
    423 	Py_RETURN_FALSE;
    424 
    425     default:
    426       break;
    427   }
    428 
    429   Py_INCREF (Py_NotImplemented);
    430   return Py_NotImplemented;
    431 }
    432 
    433 /* Create a new gdb.RecordGap object.  */
    434 
    435 PyObject *
    436 recpy_gap_new (int reason_code, const char *reason_string, Py_ssize_t number)
    437 {
    438   recpy_gap_object * const obj = PyObject_New (recpy_gap_object,
    439 					       &recpy_gap_type);
    440 
    441   if (obj == NULL)
    442    return NULL;
    443 
    444   obj->reason_code = reason_code;
    445   obj->reason_string = reason_string;
    446   obj->number = number;
    447 
    448   return (PyObject *) obj;
    449 }
    450 
    451 /* Implementation of RecordGap.number [int].  */
    452 
    453 static PyObject *
    454 recpy_gap_number (PyObject *self, void *closure)
    455 {
    456   const recpy_gap_object * const obj = (const recpy_gap_object *) self;
    457 
    458   return gdb_py_object_from_longest (obj->number).release ();
    459 }
    460 
    461 /* Implementation of RecordGap.error_code [int].  */
    462 
    463 static PyObject *
    464 recpy_gap_reason_code (PyObject *self, void *closure)
    465 {
    466   const recpy_gap_object * const obj = (const recpy_gap_object *) self;
    467 
    468   return gdb_py_object_from_longest (obj->reason_code).release ();
    469 }
    470 
    471 /* Implementation of RecordGap.error_string [str].  */
    472 
    473 static PyObject *
    474 recpy_gap_reason_string (PyObject *self, void *closure)
    475 {
    476   const recpy_gap_object * const obj = (const recpy_gap_object *) self;
    477 
    478   return PyUnicode_FromString (obj->reason_string);
    479 }
    480 
    481 /* Record method list.  */
    482 
    483 static PyMethodDef recpy_record_methods[] = {
    484   { "goto", recpy_goto, METH_VARARGS,
    485     "goto (instruction|function_call) -> None.\n\
    486 Rewind to given location."},
    487   { NULL }
    488 };
    489 
    490 /* Record member list.  */
    491 
    492 static gdb_PyGetSetDef recpy_record_getset[] = {
    493   { "method", recpy_method, NULL, "Current recording method.", NULL },
    494   { "format", recpy_format, NULL, "Current recording format.", NULL },
    495   { "replay_position", recpy_replay_position, NULL, "Current replay position.",
    496     NULL },
    497   { "instruction_history", recpy_instruction_history, NULL,
    498     "List of instructions in current recording.", NULL },
    499   { "function_call_history", recpy_function_call_history, NULL,
    500     "List of function calls in current recording.", NULL },
    501   { "begin", recpy_begin, NULL,
    502     "First instruction in current recording.", NULL },
    503   { "end", recpy_end, NULL,
    504     "One past the last instruction in current recording.  This is typically \
    505 the current instruction and is used for e.g. record.goto (record.end).", NULL },
    506   { NULL }
    507 };
    508 
    509 /* RecordInstruction member list.  */
    510 
    511 static gdb_PyGetSetDef recpy_insn_getset[] = {
    512   { "number", recpy_element_number, NULL, "instruction number", NULL},
    513   { "sal", recpy_insn_sal, NULL, "associated symbol and line", NULL},
    514   { "pc", recpy_insn_pc, NULL, "instruction address", NULL},
    515   { "data", recpy_insn_data, NULL, "raw instruction data", NULL},
    516   { "decoded", recpy_insn_decoded, NULL, "decoded instruction", NULL},
    517   { "size", recpy_insn_size, NULL, "instruction size in byte", NULL},
    518   { "is_speculative", recpy_insn_is_speculative, NULL, "if the instruction was \
    519   executed speculatively", NULL},
    520   { NULL }
    521 };
    522 
    523 /* RecordFunctionSegment member list.  */
    524 
    525 static gdb_PyGetSetDef recpy_func_getset[] = {
    526   { "number", recpy_element_number, NULL, "function segment number", NULL},
    527   { "level", recpy_func_level, NULL, "call stack level", NULL},
    528   { "symbol", recpy_func_symbol, NULL, "associated line and symbol", NULL},
    529   { "instructions", recpy_func_instructions, NULL, "list of instructions in \
    530 this function segment", NULL},
    531   { "up", recpy_func_up, NULL, "caller or returned-to function segment", NULL},
    532   { "prev", recpy_func_prev, NULL, "previous segment of this function", NULL},
    533   { "next", recpy_func_next, NULL, "next segment of this function", NULL},
    534   { NULL }
    535 };
    536 
    537 /* RecordGap member list.  */
    538 
    539 static gdb_PyGetSetDef recpy_gap_getset[] = {
    540   { "number", recpy_gap_number, NULL, "element number", NULL},
    541   { "reason_code", recpy_gap_reason_code, NULL, "reason code", NULL},
    542   { "reason_string", recpy_gap_reason_string, NULL, "reason string", NULL},
    543   { NULL }
    544 };
    545 
    546 /* Sets up the record API in the gdb module.  */
    547 
    548 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
    549 gdbpy_initialize_record (void)
    550 {
    551   recpy_record_type.tp_new = PyType_GenericNew;
    552   recpy_record_type.tp_flags = Py_TPFLAGS_DEFAULT;
    553   recpy_record_type.tp_basicsize = sizeof (recpy_record_object);
    554   recpy_record_type.tp_name = "gdb.Record";
    555   recpy_record_type.tp_doc = "GDB record object";
    556   recpy_record_type.tp_methods = recpy_record_methods;
    557   recpy_record_type.tp_getset = recpy_record_getset;
    558 
    559   recpy_insn_type.tp_new = PyType_GenericNew;
    560   recpy_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
    561   recpy_insn_type.tp_basicsize = sizeof (recpy_element_object);
    562   recpy_insn_type.tp_name = "gdb.RecordInstruction";
    563   recpy_insn_type.tp_doc = "GDB recorded instruction object";
    564   recpy_insn_type.tp_getset = recpy_insn_getset;
    565   recpy_insn_type.tp_richcompare = recpy_element_richcompare;
    566   recpy_insn_type.tp_hash = recpy_element_hash;
    567   recpy_insn_type.tp_base = py_insn_get_insn_type ();
    568 
    569   recpy_func_type.tp_new = PyType_GenericNew;
    570   recpy_func_type.tp_flags = Py_TPFLAGS_DEFAULT;
    571   recpy_func_type.tp_basicsize = sizeof (recpy_element_object);
    572   recpy_func_type.tp_name = "gdb.RecordFunctionSegment";
    573   recpy_func_type.tp_doc = "GDB record function segment object";
    574   recpy_func_type.tp_getset = recpy_func_getset;
    575   recpy_func_type.tp_richcompare = recpy_element_richcompare;
    576   recpy_func_type.tp_hash = recpy_element_hash;
    577 
    578   recpy_gap_type.tp_new = PyType_GenericNew;
    579   recpy_gap_type.tp_flags = Py_TPFLAGS_DEFAULT;
    580   recpy_gap_type.tp_basicsize = sizeof (recpy_gap_object);
    581   recpy_gap_type.tp_name = "gdb.RecordGap";
    582   recpy_gap_type.tp_doc = "GDB recorded gap object";
    583   recpy_gap_type.tp_getset = recpy_gap_getset;
    584 
    585   if (PyType_Ready (&recpy_record_type) < 0
    586       || PyType_Ready (&recpy_insn_type) < 0
    587       || PyType_Ready (&recpy_func_type) < 0
    588       || PyType_Ready (&recpy_gap_type) < 0)
    589     return -1;
    590   else
    591     return 0;
    592 }
    593 
    594 /* Implementation of gdb.start_recording (method) -> gdb.Record.  */
    595 
    596 PyObject *
    597 gdbpy_start_recording (PyObject *self, PyObject *args)
    598 {
    599   const char *method = NULL;
    600   const char *format = NULL;
    601   PyObject *ret = NULL;
    602 
    603   if (!PyArg_ParseTuple (args, "|ss", &method, &format))
    604     return NULL;
    605 
    606   try
    607     {
    608       record_start (method, format, 0);
    609       ret = gdbpy_current_recording (self, args);
    610     }
    611   catch (const gdb_exception &except)
    612     {
    613       gdbpy_convert_exception (except);
    614     }
    615 
    616   return ret;
    617 }
    618 
    619 /* Implementation of gdb.current_recording (self) -> gdb.Record.  */
    620 
    621 PyObject *
    622 gdbpy_current_recording (PyObject *self, PyObject *args)
    623 {
    624   recpy_record_object *ret = NULL;
    625 
    626   if (find_record_target () == NULL)
    627     Py_RETURN_NONE;
    628 
    629   ret = PyObject_New (recpy_record_object, &recpy_record_type);
    630   ret->thread = inferior_thread ();
    631   ret->method = target_record_method (ret->thread->ptid);
    632 
    633   return (PyObject *) ret;
    634 }
    635 
    636 /* Implementation of gdb.stop_recording (self) -> None.  */
    637 
    638 PyObject *
    639 gdbpy_stop_recording (PyObject *self, PyObject *args)
    640 {
    641   try
    642     {
    643       record_stop (0);
    644     }
    645   catch (const gdb_exception &except)
    646     {
    647       GDB_PY_HANDLE_EXCEPTION (except);
    648     }
    649 
    650   Py_RETURN_NONE;
    651 }
    652 
    653 GDBPY_INITIALIZE_FILE (gdbpy_initialize_record);
    654