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