Home | History | Annotate | Line # | Download | only in python
py-record.c revision 1.1
      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 "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 
     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 PyTypeObject recpy_gap_type = {
     48   PyVarObject_HEAD_INIT (NULL, 0)
     49 };
     50 
     51 /* Python RecordGap object.  */
     52 typedef struct
     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 } recpy_gap_object;
     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 (ptid_t ptid, enum record_method method, Py_ssize_t number)
    180 {
    181   recpy_element_object * const obj = PyObject_New (recpy_element_object,
    182 						   &recpy_insn_type);
    183 
    184   if (obj == NULL)
    185    return NULL;
    186 
    187   obj->ptid = ptid;
    188   obj->method = method;
    189   obj->number = number;
    190 
    191   return (PyObject *) obj;
    192 }
    193 
    194 /* Implementation of RecordInstruction.sal [gdb.Symtab_and_line].  */
    195 
    196 static PyObject *
    197 recpy_insn_sal (PyObject *self, void *closure)
    198 {
    199   const recpy_element_object * const obj = (recpy_element_object *) self;
    200 
    201   if (obj->method == RECORD_METHOD_BTRACE)
    202     return recpy_bt_insn_sal (self, closure);
    203 
    204   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    205 }
    206 
    207 /* Implementation of RecordInstruction.pc [int].  */
    208 
    209 static PyObject *
    210 recpy_insn_pc (PyObject *self, void *closure)
    211 {
    212   const recpy_element_object * const obj = (recpy_element_object *) self;
    213 
    214   if (obj->method == RECORD_METHOD_BTRACE)
    215     return recpy_bt_insn_pc (self, closure);
    216 
    217   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    218 }
    219 
    220 /* Implementation of RecordInstruction.data [buffer].  */
    221 
    222 static PyObject *
    223 recpy_insn_data (PyObject *self, void *closure)
    224 {
    225   const recpy_element_object * const obj = (recpy_element_object *) self;
    226 
    227   if (obj->method == RECORD_METHOD_BTRACE)
    228     return recpy_bt_insn_data (self, closure);
    229 
    230   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    231 }
    232 
    233 /* Implementation of RecordInstruction.decoded [str].  */
    234 
    235 static PyObject *
    236 recpy_insn_decoded (PyObject *self, void *closure)
    237 {
    238   const recpy_element_object * const obj = (recpy_element_object *) self;
    239 
    240   if (obj->method == RECORD_METHOD_BTRACE)
    241     return recpy_bt_insn_decoded (self, closure);
    242 
    243   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    244 }
    245 
    246 /* Implementation of RecordInstruction.size [int].  */
    247 
    248 static PyObject *
    249 recpy_insn_size (PyObject *self, void *closure)
    250 {
    251   const recpy_element_object * const obj = (recpy_element_object *) self;
    252 
    253   if (obj->method == RECORD_METHOD_BTRACE)
    254     return recpy_bt_insn_size (self, closure);
    255 
    256   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    257 }
    258 
    259 /* Implementation of RecordInstruction.is_speculative [bool].  */
    260 
    261 static PyObject *
    262 recpy_insn_is_speculative (PyObject *self, void *closure)
    263 {
    264   const recpy_element_object * const obj = (recpy_element_object *) self;
    265 
    266   if (obj->method == RECORD_METHOD_BTRACE)
    267     return recpy_bt_insn_is_speculative (self, closure);
    268 
    269   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    270 }
    271 
    272 /* Create a new gdb.RecordFunctionSegment object.  */
    273 
    274 PyObject *
    275 recpy_func_new (ptid_t ptid, enum record_method method, Py_ssize_t number)
    276 {
    277   recpy_element_object * const obj = PyObject_New (recpy_element_object,
    278 						   &recpy_func_type);
    279 
    280   if (obj == NULL)
    281    return NULL;
    282 
    283   obj->ptid = ptid;
    284   obj->method = method;
    285   obj->number = number;
    286 
    287   return (PyObject *) obj;
    288 }
    289 
    290 /* Implementation of RecordFunctionSegment.level [int].  */
    291 
    292 static PyObject *
    293 recpy_func_level (PyObject *self, void *closure)
    294 {
    295   const recpy_element_object * const obj = (recpy_element_object *) self;
    296 
    297   if (obj->method == RECORD_METHOD_BTRACE)
    298     return recpy_bt_func_level (self, closure);
    299 
    300   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    301 }
    302 
    303 /* Implementation of RecordFunctionSegment.symbol [gdb.Symbol].  */
    304 
    305 static PyObject *
    306 recpy_func_symbol (PyObject *self, void *closure)
    307 {
    308   const recpy_element_object * const obj = (recpy_element_object *) self;
    309 
    310   if (obj->method == RECORD_METHOD_BTRACE)
    311     return recpy_bt_func_symbol (self, closure);
    312 
    313   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    314 }
    315 
    316 /* Implementation of RecordFunctionSegment.instructions [list].  */
    317 
    318 static PyObject *
    319 recpy_func_instructions (PyObject *self, void *closure)
    320 {
    321   const recpy_element_object * const obj = (recpy_element_object *) self;
    322 
    323   if (obj->method == RECORD_METHOD_BTRACE)
    324     return recpy_bt_func_instructions (self, closure);
    325 
    326   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    327 }
    328 
    329 /* Implementation of RecordFunctionSegment.up [RecordFunctionSegment].  */
    330 
    331 static PyObject *
    332 recpy_func_up (PyObject *self, void *closure)
    333 {
    334   const recpy_element_object * const obj = (recpy_element_object *) self;
    335 
    336   if (obj->method == RECORD_METHOD_BTRACE)
    337     return recpy_bt_func_up (self, closure);
    338 
    339   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    340 }
    341 
    342 /* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment].  */
    343 
    344 static PyObject *
    345 recpy_func_prev (PyObject *self, void *closure)
    346 {
    347   const recpy_element_object * const obj = (recpy_element_object *) self;
    348 
    349   if (obj->method == RECORD_METHOD_BTRACE)
    350     return recpy_bt_func_prev (self, closure);
    351 
    352   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    353 }
    354 
    355 /* Implementation of RecordFunctionSegment.next [RecordFunctionSegment].  */
    356 
    357 static PyObject *
    358 recpy_func_next (PyObject *self, void *closure)
    359 {
    360   const recpy_element_object * const obj = (recpy_element_object *) self;
    361 
    362   if (obj->method == RECORD_METHOD_BTRACE)
    363     return recpy_bt_func_next (self, closure);
    364 
    365   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
    366 }
    367 
    368 /* Implementation of RecordInstruction.number [int] and
    369    RecordFunctionSegment.number [int].  */
    370 
    371 static PyObject *
    372 recpy_element_number (PyObject *self, void* closure)
    373 {
    374   const recpy_element_object * const obj = (recpy_element_object *) self;
    375 
    376   return PyInt_FromSsize_t (obj->number);
    377 }
    378 
    379 /* Implementation of RecordInstruction.__hash__ [int] and
    380    RecordFunctionSegment.__hash__ [int].  */
    381 
    382 static Py_hash_t
    383 recpy_element_hash (PyObject *self)
    384 {
    385   const recpy_element_object * const obj = (recpy_element_object *) self;
    386 
    387   return obj->number;
    388 }
    389 
    390 /* Implementation of operator == and != of RecordInstruction and
    391    RecordFunctionSegment.  */
    392 
    393 static PyObject *
    394 recpy_element_richcompare (PyObject *self, PyObject *other, int op)
    395 {
    396   const recpy_element_object * const obj1 = (recpy_element_object *) self;
    397   const recpy_element_object * const obj2 = (recpy_element_object *) other;
    398 
    399   if (Py_TYPE (self) != Py_TYPE (other))
    400     {
    401       Py_INCREF (Py_NotImplemented);
    402       return Py_NotImplemented;
    403     }
    404 
    405   switch (op)
    406   {
    407     case Py_EQ:
    408       if (ptid_equal (obj1->ptid, obj2->ptid)
    409 	  && obj1->method == obj2->method
    410 	  && obj1->number == obj2->number)
    411 	Py_RETURN_TRUE;
    412       else
    413 	Py_RETURN_FALSE;
    414 
    415     case Py_NE:
    416       if (!ptid_equal (obj1->ptid, obj2->ptid)
    417 	  || obj1->method != obj2->method
    418 	  || obj1->number != obj2->number)
    419 	Py_RETURN_TRUE;
    420       else
    421 	Py_RETURN_FALSE;
    422 
    423     default:
    424       break;
    425   }
    426 
    427   Py_INCREF (Py_NotImplemented);
    428   return Py_NotImplemented;
    429 }
    430 
    431 /* Create a new gdb.RecordGap object.  */
    432 
    433 PyObject *
    434 recpy_gap_new (int reason_code, const char *reason_string, Py_ssize_t number)
    435 {
    436   recpy_gap_object * const obj = PyObject_New (recpy_gap_object,
    437 					       &recpy_gap_type);
    438 
    439   if (obj == NULL)
    440    return NULL;
    441 
    442   obj->reason_code = reason_code;
    443   obj->reason_string = reason_string;
    444   obj->number = number;
    445 
    446   return (PyObject *) obj;
    447 }
    448 
    449 /* Implementation of RecordGap.number [int].  */
    450 
    451 static PyObject *
    452 recpy_gap_number (PyObject *self, void *closure)
    453 {
    454   const recpy_gap_object * const obj = (const recpy_gap_object *) self;
    455 
    456   return PyInt_FromSsize_t (obj->number);
    457 }
    458 
    459 /* Implementation of RecordGap.error_code [int].  */
    460 
    461 static PyObject *
    462 recpy_gap_reason_code (PyObject *self, void *closure)
    463 {
    464   const recpy_gap_object * const obj = (const recpy_gap_object *) self;
    465 
    466   return PyInt_FromLong (obj->reason_code);
    467 }
    468 
    469 /* Implementation of RecordGap.error_string [str].  */
    470 
    471 static PyObject *
    472 recpy_gap_reason_string (PyObject *self, void *closure)
    473 {
    474   const recpy_gap_object * const obj = (const recpy_gap_object *) self;
    475 
    476   return PyString_FromString (obj->reason_string);
    477 }
    478 
    479 /* Record method list.  */
    480 
    481 static PyMethodDef recpy_record_methods[] = {
    482   { "goto", recpy_goto, METH_VARARGS,
    483     "goto (instruction|function_call) -> None.\n\
    484 Rewind to given location."},
    485   { NULL }
    486 };
    487 
    488 /* Record member list.  */
    489 
    490 static gdb_PyGetSetDef recpy_record_getset[] = {
    491   { "method", recpy_method, NULL, "Current recording method.", NULL },
    492   { "format", recpy_format, NULL, "Current recording format.", NULL },
    493   { "replay_position", recpy_replay_position, NULL, "Current replay position.",
    494     NULL },
    495   { "instruction_history", recpy_instruction_history, NULL,
    496     "List of instructions in current recording.", NULL },
    497   { "function_call_history", recpy_function_call_history, NULL,
    498     "List of function calls in current recording.", NULL },
    499   { "begin", recpy_begin, NULL,
    500     "First instruction in current recording.", NULL },
    501   { "end", recpy_end, NULL,
    502     "One past the last instruction in current recording.  This is typically \
    503 the current instruction and is used for e.g. record.goto (record.end).", NULL },
    504   { NULL }
    505 };
    506 
    507 /* RecordInstruction member list.  */
    508 
    509 static gdb_PyGetSetDef recpy_insn_getset[] = {
    510   { "number", recpy_element_number, NULL, "instruction number", NULL},
    511   { "sal", recpy_insn_sal, NULL, "associated symbol and line", NULL},
    512   { "pc", recpy_insn_pc, NULL, "instruction address", NULL},
    513   { "data", recpy_insn_data, NULL, "raw instruction data", NULL},
    514   { "decoded", recpy_insn_decoded, NULL, "decoded instruction", NULL},
    515   { "size", recpy_insn_size, NULL, "instruction size in byte", NULL},
    516   { "is_speculative", recpy_insn_is_speculative, NULL, "if the instruction was \
    517   executed speculatively", NULL},
    518   { NULL }
    519 };
    520 
    521 /* RecordFunctionSegment member list.  */
    522 
    523 static gdb_PyGetSetDef recpy_func_getset[] = {
    524   { "number", recpy_element_number, NULL, "function segment number", NULL},
    525   { "level", recpy_func_level, NULL, "call stack level", NULL},
    526   { "symbol", recpy_func_symbol, NULL, "associated line and symbol", NULL},
    527   { "instructions", recpy_func_instructions, NULL, "list of instructions in \
    528 this function segment", NULL},
    529   { "up", recpy_func_up, NULL, "caller or returned-to function segment", NULL},
    530   { "prev", recpy_func_prev, NULL, "previous segment of this function", NULL},
    531   { "next", recpy_func_next, NULL, "next segment of this function", NULL},
    532   { NULL }
    533 };
    534 
    535 /* RecordGap member list.  */
    536 
    537 static gdb_PyGetSetDef recpy_gap_getset[] = {
    538   { "number", recpy_gap_number, NULL, "element number", NULL},
    539   { "reason_code", recpy_gap_reason_code, NULL, "reason code", NULL},
    540   { "reason_string", recpy_gap_reason_string, NULL, "reason string", NULL},
    541   { NULL }
    542 };
    543 
    544 /* Sets up the record API in the gdb module.  */
    545 
    546 int
    547 gdbpy_initialize_record (void)
    548 {
    549   recpy_record_type.tp_new = PyType_GenericNew;
    550   recpy_record_type.tp_flags = Py_TPFLAGS_DEFAULT;
    551   recpy_record_type.tp_basicsize = sizeof (recpy_record_object);
    552   recpy_record_type.tp_name = "gdb.Record";
    553   recpy_record_type.tp_doc = "GDB record object";
    554   recpy_record_type.tp_methods = recpy_record_methods;
    555   recpy_record_type.tp_getset = recpy_record_getset;
    556 
    557   recpy_insn_type.tp_new = PyType_GenericNew;
    558   recpy_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
    559   recpy_insn_type.tp_basicsize = sizeof (recpy_element_object);
    560   recpy_insn_type.tp_name = "gdb.RecordInstruction";
    561   recpy_insn_type.tp_doc = "GDB recorded instruction object";
    562   recpy_insn_type.tp_getset = recpy_insn_getset;
    563   recpy_insn_type.tp_richcompare = recpy_element_richcompare;
    564   recpy_insn_type.tp_hash = recpy_element_hash;
    565   recpy_insn_type.tp_base = &py_insn_type;
    566 
    567   recpy_func_type.tp_new = PyType_GenericNew;
    568   recpy_func_type.tp_flags = Py_TPFLAGS_DEFAULT;
    569   recpy_func_type.tp_basicsize = sizeof (recpy_element_object);
    570   recpy_func_type.tp_name = "gdb.RecordFunctionSegment";
    571   recpy_func_type.tp_doc = "GDB record function segment object";
    572   recpy_func_type.tp_getset = recpy_func_getset;
    573   recpy_func_type.tp_richcompare = recpy_element_richcompare;
    574   recpy_func_type.tp_hash = recpy_element_hash;
    575 
    576   recpy_gap_type.tp_new = PyType_GenericNew;
    577   recpy_gap_type.tp_flags = Py_TPFLAGS_DEFAULT;
    578   recpy_gap_type.tp_basicsize = sizeof (recpy_gap_object);
    579   recpy_gap_type.tp_name = "gdb.RecordGap";
    580   recpy_gap_type.tp_doc = "GDB recorded gap object";
    581   recpy_gap_type.tp_getset = recpy_gap_getset;
    582 
    583   if (PyType_Ready (&recpy_record_type) < 0
    584       || PyType_Ready (&recpy_insn_type) < 0
    585       || PyType_Ready (&recpy_func_type) < 0
    586       || PyType_Ready (&recpy_gap_type) < 0)
    587     return -1;
    588   else
    589     return 0;
    590 }
    591 
    592 /* Implementation of gdb.start_recording (method) -> gdb.Record.  */
    593 
    594 PyObject *
    595 gdbpy_start_recording (PyObject *self, PyObject *args)
    596 {
    597   const char *method = NULL;
    598   const char *format = NULL;
    599   PyObject *ret = NULL;
    600 
    601   if (!PyArg_ParseTuple (args, "|ss", &method, &format))
    602     return NULL;
    603 
    604   TRY
    605     {
    606       record_start (method, format, 0);
    607       ret = gdbpy_current_recording (self, args);
    608     }
    609   CATCH (except, RETURN_MASK_ALL)
    610     {
    611       gdbpy_convert_exception (except);
    612     }
    613   END_CATCH
    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->ptid = inferior_ptid;
    630   ret->method = target_record_method (inferior_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   PyObject *ret = NULL;
    641 
    642   TRY
    643     {
    644       record_stop (0);
    645       ret = Py_None;
    646       Py_INCREF (Py_None);
    647     }
    648   CATCH (except, RETURN_MASK_ALL)
    649     {
    650       gdbpy_convert_exception (except);
    651     }
    652   END_CATCH
    653 
    654   return ret;
    655 }
    656