1 /* Python interface to record targets. 2 3 Copyright 2016-2023 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 static PyTypeObject recpy_gap_type = { 49 PyVarObject_HEAD_INIT (NULL, 0) 50 }; 51 52 /* Python RecordGap object. */ 53 struct recpy_gap_object 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 }; 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 gdb_py_object_from_longest (obj->number).release (); 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 gdb_py_object_from_longest (obj->number).release (); 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 gdb_py_object_from_longest (obj->reason_code).release (); 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 PyUnicode_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_get_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