1 /* Python interface to btrace instruction history.
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 "gdbcore.h"
21 #include "cli/cli-cmds.h"
22 #include "gdbthread.h"
23 #include "btrace.h"
24 #include "py-record.h"
25 #include "py-record-btrace.h"
26 #include "record-btrace.h"
27 #include "disasm.h"
28 #include "gdbarch.h"
29
30 /* Python object for btrace record lists. */
31
32 struct btpy_list_object {
33 PyObject_HEAD
34
35 /* The thread this list belongs to. */
36 thread_info *thread;
37
38 /* The first index being part of this list. */
39 Py_ssize_t first;
40
41 /* The last index begin part of this list. */
42 Py_ssize_t last;
43
44 /* Stride size. */
45 Py_ssize_t step;
46
47 /* Either &BTPY_CALL_TYPE or &RECPY_INSN_TYPE. */
48 PyTypeObject* element_type;
49 };
50
51 /* Python type for btrace lists. */
52
53 static PyTypeObject btpy_list_type = {
54 PyVarObject_HEAD_INIT (NULL, 0)
55 };
56
57 /* Returns either a btrace_insn for the given Python gdb.RecordInstruction
58 object or sets an appropriate Python exception and returns NULL. */
59
60 static const btrace_insn *
btrace_insn_from_recpy_insn(const PyObject * const pyobject)61 btrace_insn_from_recpy_insn (const PyObject * const pyobject)
62 {
63 const btrace_insn *insn;
64 const recpy_element_object *obj;
65 thread_info *tinfo;
66 btrace_insn_iterator iter;
67
68 if (Py_TYPE (pyobject) != &recpy_insn_type)
69 {
70 PyErr_Format (gdbpy_gdb_error, _("Must be gdb.RecordInstruction"));
71 return NULL;
72 }
73
74 obj = (const recpy_element_object *) pyobject;
75 tinfo = obj->thread;
76
77 if (tinfo == NULL || btrace_is_empty (tinfo))
78 {
79 PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
80 return NULL;
81 }
82
83 if (btrace_find_insn_by_number (&iter, &tinfo->btrace, obj->number) == 0)
84 {
85 PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
86 return NULL;
87 }
88
89 insn = btrace_insn_get (&iter);
90 if (insn == NULL)
91 {
92 PyErr_Format (gdbpy_gdb_error, _("Not a valid instruction."));
93 return NULL;
94 }
95
96 return insn;
97 }
98
99 /* Returns either a btrace_function for the given Python
100 gdb.RecordFunctionSegment object or sets an appropriate Python exception and
101 returns NULL. */
102
103 static const btrace_function *
btrace_func_from_recpy_func(const PyObject * const pyobject)104 btrace_func_from_recpy_func (const PyObject * const pyobject)
105 {
106 const btrace_function *func;
107 const recpy_element_object *obj;
108 thread_info *tinfo;
109 btrace_call_iterator iter;
110
111 if (Py_TYPE (pyobject) != &recpy_func_type)
112 {
113 PyErr_Format (gdbpy_gdb_error, _("Must be gdb.RecordFunctionSegment"));
114 return NULL;
115 }
116
117 obj = (const recpy_element_object *) pyobject;
118 tinfo = obj->thread;
119
120 if (tinfo == NULL || btrace_is_empty (tinfo))
121 {
122 PyErr_Format (gdbpy_gdb_error, _("No such function segment."));
123 return NULL;
124 }
125
126 if (btrace_find_call_by_number (&iter, &tinfo->btrace, obj->number) == 0)
127 {
128 PyErr_Format (gdbpy_gdb_error, _("No such function segment."));
129 return NULL;
130 }
131
132 func = btrace_call_get (&iter);
133 if (func == NULL)
134 {
135 PyErr_Format (gdbpy_gdb_error, _("Not a valid function segment."));
136 return NULL;
137 }
138
139 return func;
140 }
141
142 /* Looks at the recorded item with the number NUMBER and create a
143 gdb.RecordInstruction or gdb.RecordGap object for it accordingly. */
144
145 static PyObject *
btpy_insn_or_gap_new(thread_info * tinfo,Py_ssize_t number)146 btpy_insn_or_gap_new (thread_info *tinfo, Py_ssize_t number)
147 {
148 btrace_insn_iterator iter;
149 int err_code;
150
151 btrace_find_insn_by_number (&iter, &tinfo->btrace, number);
152 err_code = btrace_insn_get_error (&iter);
153
154 if (err_code != 0)
155 {
156 const btrace_config *config;
157 const char *err_string;
158
159 config = btrace_conf (&tinfo->btrace);
160 err_string = btrace_decode_error (config->format, err_code);
161
162 return recpy_gap_new (err_code, err_string, number);
163 }
164
165 return recpy_insn_new (tinfo, RECORD_METHOD_BTRACE, number);
166 }
167
168 /* Create a new gdb.BtraceList object. */
169
170 static PyObject *
btpy_list_new(thread_info * thread,Py_ssize_t first,Py_ssize_t last,Py_ssize_t step,PyTypeObject * element_type)171 btpy_list_new (thread_info *thread, Py_ssize_t first, Py_ssize_t last,
172 Py_ssize_t step, PyTypeObject *element_type)
173 {
174 btpy_list_object * const obj = PyObject_New (btpy_list_object,
175 &btpy_list_type);
176
177 if (obj == NULL)
178 return NULL;
179
180 obj->thread = thread;
181 obj->first = first;
182 obj->last = last;
183 obj->step = step;
184 obj->element_type = element_type;
185
186 return (PyObject *) obj;
187 }
188
189 /* Implementation of RecordInstruction.sal [gdb.Symtab_and_line] for btrace.
190 Returns the SAL associated with this instruction. */
191
192 PyObject *
recpy_bt_insn_sal(PyObject * self,void * closure)193 recpy_bt_insn_sal (PyObject *self, void *closure)
194 {
195 const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
196 PyObject *result = NULL;
197
198 if (insn == NULL)
199 return NULL;
200
201 try
202 {
203 result = symtab_and_line_to_sal_object (find_pc_line (insn->pc, 0));
204 }
205 catch (const gdb_exception &except)
206 {
207 GDB_PY_HANDLE_EXCEPTION (except);
208 }
209
210 return result;
211 }
212
213 /* Implementation of RecordInstruction.pc [int] for btrace.
214 Returns the instruction address. */
215
216 PyObject *
recpy_bt_insn_pc(PyObject * self,void * closure)217 recpy_bt_insn_pc (PyObject *self, void *closure)
218 {
219 const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
220
221 if (insn == NULL)
222 return NULL;
223
224 return gdb_py_object_from_ulongest (insn->pc).release ();
225 }
226
227 /* Implementation of RecordInstruction.size [int] for btrace.
228 Returns the instruction size. */
229
230 PyObject *
recpy_bt_insn_size(PyObject * self,void * closure)231 recpy_bt_insn_size (PyObject *self, void *closure)
232 {
233 const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
234
235 if (insn == NULL)
236 return NULL;
237
238 return gdb_py_object_from_longest (insn->size).release ();
239 }
240
241 /* Implementation of RecordInstruction.is_speculative [bool] for btrace.
242 Returns if this instruction was executed speculatively. */
243
244 PyObject *
recpy_bt_insn_is_speculative(PyObject * self,void * closure)245 recpy_bt_insn_is_speculative (PyObject *self, void *closure)
246 {
247 const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
248
249 if (insn == NULL)
250 return NULL;
251
252 if (insn->flags & BTRACE_INSN_FLAG_SPECULATIVE)
253 Py_RETURN_TRUE;
254 else
255 Py_RETURN_FALSE;
256 }
257
258 /* Implementation of RecordInstruction.data [buffer] for btrace.
259 Returns raw instruction data. */
260
261 PyObject *
recpy_bt_insn_data(PyObject * self,void * closure)262 recpy_bt_insn_data (PyObject *self, void *closure)
263 {
264 const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
265 gdb::byte_vector buffer;
266 PyObject *object;
267
268 if (insn == NULL)
269 return NULL;
270
271 try
272 {
273 buffer.resize (insn->size);
274 read_memory (insn->pc, buffer.data (), insn->size);
275 }
276 catch (const gdb_exception &except)
277 {
278 GDB_PY_HANDLE_EXCEPTION (except);
279 }
280
281 object = PyBytes_FromStringAndSize ((const char *) buffer.data (),
282 insn->size);
283
284 if (object == NULL)
285 return NULL;
286
287 return PyMemoryView_FromObject (object);
288 }
289
290 /* Implementation of RecordInstruction.decoded [str] for btrace.
291 Returns the instruction as human readable string. */
292
293 PyObject *
recpy_bt_insn_decoded(PyObject * self,void * closure)294 recpy_bt_insn_decoded (PyObject *self, void *closure)
295 {
296 const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
297 string_file strfile;
298
299 if (insn == NULL)
300 return NULL;
301
302 try
303 {
304 gdb_print_insn (current_inferior ()->arch (), insn->pc, &strfile, NULL);
305 }
306 catch (const gdb_exception &except)
307 {
308 gdbpy_convert_exception (except);
309 return NULL;
310 }
311
312 return PyBytes_FromString (strfile.string ().c_str ());
313 }
314
315 /* Implementation of RecordFunctionSegment.level [int] for btrace.
316 Returns the call level. */
317
318 PyObject *
recpy_bt_func_level(PyObject * self,void * closure)319 recpy_bt_func_level (PyObject *self, void *closure)
320 {
321 const btrace_function * const func = btrace_func_from_recpy_func (self);
322 thread_info *tinfo;
323
324 if (func == NULL)
325 return NULL;
326
327 tinfo = ((recpy_element_object *) self)->thread;
328 return gdb_py_object_from_longest (tinfo->btrace.level
329 + func->level).release ();
330 }
331
332 /* Implementation of RecordFunctionSegment.symbol [gdb.Symbol] for btrace.
333 Returns the symbol associated with this function call. */
334
335 PyObject *
recpy_bt_func_symbol(PyObject * self,void * closure)336 recpy_bt_func_symbol (PyObject *self, void *closure)
337 {
338 const btrace_function * const func = btrace_func_from_recpy_func (self);
339
340 if (func == NULL)
341 return NULL;
342
343 if (func->sym == NULL)
344 Py_RETURN_NONE;
345
346 return symbol_to_symbol_object (func->sym);
347 }
348
349 /* Implementation of RecordFunctionSegment.instructions [list] for btrace.
350 Returns the list of instructions that belong to this function call. */
351
352 PyObject *
recpy_bt_func_instructions(PyObject * self,void * closure)353 recpy_bt_func_instructions (PyObject *self, void *closure)
354 {
355 const btrace_function * const func = btrace_func_from_recpy_func (self);
356 unsigned int len;
357
358 if (func == NULL)
359 return NULL;
360
361 len = func->insn.size ();
362
363 /* Gaps count as one instruction. */
364 if (len == 0)
365 len = 1;
366
367 return btpy_list_new (((recpy_element_object *) self)->thread,
368 func->insn_offset, func->insn_offset + len, 1,
369 &recpy_insn_type);
370 }
371
372 /* Implementation of RecordFunctionSegment.up [RecordFunctionSegment] for
373 btrace. Returns the caller / returnee of this function. */
374
375 PyObject *
recpy_bt_func_up(PyObject * self,void * closure)376 recpy_bt_func_up (PyObject *self, void *closure)
377 {
378 const btrace_function * const func = btrace_func_from_recpy_func (self);
379
380 if (func == NULL)
381 return NULL;
382
383 if (func->up == 0)
384 Py_RETURN_NONE;
385
386 return recpy_func_new (((recpy_element_object *) self)->thread,
387 RECORD_METHOD_BTRACE, func->up);
388 }
389
390 /* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment] for
391 btrace. Returns a previous segment of this function. */
392
393 PyObject *
recpy_bt_func_prev(PyObject * self,void * closure)394 recpy_bt_func_prev (PyObject *self, void *closure)
395 {
396 const btrace_function * const func = btrace_func_from_recpy_func (self);
397
398 if (func == NULL)
399 return NULL;
400
401 if (func->prev == 0)
402 Py_RETURN_NONE;
403
404 return recpy_func_new (((recpy_element_object *) self)->thread,
405 RECORD_METHOD_BTRACE, func->prev);
406 }
407
408 /* Implementation of RecordFunctionSegment.next [RecordFunctionSegment] for
409 btrace. Returns a following segment of this function. */
410
411 PyObject *
recpy_bt_func_next(PyObject * self,void * closure)412 recpy_bt_func_next (PyObject *self, void *closure)
413 {
414 const btrace_function * const func = btrace_func_from_recpy_func (self);
415
416 if (func == NULL)
417 return NULL;
418
419 if (func->next == 0)
420 Py_RETURN_NONE;
421
422 return recpy_func_new (((recpy_element_object *) self)->thread,
423 RECORD_METHOD_BTRACE, func->next);
424 }
425
426 /* Implementation of BtraceList.__len__ (self) -> int. */
427
428 static Py_ssize_t
btpy_list_length(PyObject * self)429 btpy_list_length (PyObject *self)
430 {
431 const btpy_list_object * const obj = (btpy_list_object *) self;
432 const Py_ssize_t distance = obj->last - obj->first;
433 const Py_ssize_t result = distance / obj->step;
434
435 if ((distance % obj->step) == 0)
436 return result;
437
438 return result + 1;
439 }
440
441 /* Implementation of
442 BtraceList.__getitem__ (self, key) -> BtraceInstruction and
443 BtraceList.__getitem__ (self, key) -> BtraceFunctionCall. */
444
445 static PyObject *
btpy_list_item(PyObject * self,Py_ssize_t index)446 btpy_list_item (PyObject *self, Py_ssize_t index)
447 {
448 const btpy_list_object * const obj = (btpy_list_object *) self;
449 Py_ssize_t number;
450
451 if (index < 0 || index >= btpy_list_length (self))
452 return PyErr_Format (PyExc_IndexError, _("Index out of range: %zd."),
453 index);
454
455 number = obj->first + (obj->step * index);
456
457 if (obj->element_type == &recpy_insn_type)
458 return recpy_insn_new (obj->thread, RECORD_METHOD_BTRACE, number);
459 else
460 return recpy_func_new (obj->thread, RECORD_METHOD_BTRACE, number);
461 }
462
463 /* Implementation of BtraceList.__getitem__ (self, slice) -> BtraceList. */
464
465 static PyObject *
btpy_list_slice(PyObject * self,PyObject * value)466 btpy_list_slice (PyObject *self, PyObject *value)
467 {
468 const btpy_list_object * const obj = (btpy_list_object *) self;
469 const Py_ssize_t length = btpy_list_length (self);
470 Py_ssize_t start, stop, step, slicelength;
471
472 if (PyLong_Check (value))
473 {
474 Py_ssize_t index = PyLong_AsSsize_t (value);
475
476 /* Emulate Python behavior for negative indices. */
477 if (index < 0)
478 index += length;
479
480 return btpy_list_item (self, index);
481 }
482
483 if (!PySlice_Check (value))
484 return PyErr_Format (PyExc_TypeError, _("Index must be int or slice."));
485
486 if (0 != PySlice_GetIndicesEx (value, length, &start, &stop,
487 &step, &slicelength))
488 return NULL;
489
490 return btpy_list_new (obj->thread, obj->first + obj->step * start,
491 obj->first + obj->step * stop, obj->step * step,
492 obj->element_type);
493 }
494
495 /* Helper function that returns the position of an element in a BtraceList
496 or -1 if the element is not in the list. */
497
498 static LONGEST
btpy_list_position(PyObject * self,PyObject * value)499 btpy_list_position (PyObject *self, PyObject *value)
500 {
501 const btpy_list_object * const list_obj = (btpy_list_object *) self;
502 const recpy_element_object * const obj = (const recpy_element_object *) value;
503 Py_ssize_t index = obj->number;
504
505 if (list_obj->element_type != Py_TYPE (value))
506 return -1;
507
508 if (list_obj->thread != obj->thread)
509 return -1;
510
511 if (index < list_obj->first || index > list_obj->last)
512 return -1;
513
514 index -= list_obj->first;
515
516 if (index % list_obj->step != 0)
517 return -1;
518
519 return index / list_obj->step;
520 }
521
522 /* Implementation of "in" operator for BtraceLists. */
523
524 static int
btpy_list_contains(PyObject * self,PyObject * value)525 btpy_list_contains (PyObject *self, PyObject *value)
526 {
527 if (btpy_list_position (self, value) < 0)
528 return 0;
529
530 return 1;
531 }
532
533 /* Implementation of BtraceLists.index (self, value) -> int. */
534
535 static PyObject *
btpy_list_index(PyObject * self,PyObject * value)536 btpy_list_index (PyObject *self, PyObject *value)
537 {
538 const LONGEST index = btpy_list_position (self, value);
539
540 if (index < 0)
541 return PyErr_Format (PyExc_ValueError, _("Not in list."));
542
543 return gdb_py_object_from_longest (index).release ();
544 }
545
546 /* Implementation of BtraceList.count (self, value) -> int. */
547
548 static PyObject *
btpy_list_count(PyObject * self,PyObject * value)549 btpy_list_count (PyObject *self, PyObject *value)
550 {
551 /* We know that if an element is in the list, it is so exactly one time,
552 enabling us to reuse the "is element of" check. */
553 return gdb_py_object_from_longest (btpy_list_contains (self,
554 value)).release ();
555 }
556
557 /* Python rich compare function to allow for equality and inequality checks
558 in Python. */
559
560 static PyObject *
btpy_list_richcompare(PyObject * self,PyObject * other,int op)561 btpy_list_richcompare (PyObject *self, PyObject *other, int op)
562 {
563 const btpy_list_object * const obj1 = (btpy_list_object *) self;
564 const btpy_list_object * const obj2 = (btpy_list_object *) other;
565
566 if (Py_TYPE (self) != Py_TYPE (other))
567 {
568 Py_INCREF (Py_NotImplemented);
569 return Py_NotImplemented;
570 }
571
572 switch (op)
573 {
574 case Py_EQ:
575 if (obj1->thread == obj2->thread
576 && obj1->element_type == obj2->element_type
577 && obj1->first == obj2->first
578 && obj1->last == obj2->last
579 && obj1->step == obj2->step)
580 Py_RETURN_TRUE;
581 else
582 Py_RETURN_FALSE;
583
584 case Py_NE:
585 if (obj1->thread != obj2->thread
586 || obj1->element_type != obj2->element_type
587 || obj1->first != obj2->first
588 || obj1->last != obj2->last
589 || obj1->step != obj2->step)
590 Py_RETURN_TRUE;
591 else
592 Py_RETURN_FALSE;
593
594 default:
595 break;
596 }
597
598 Py_INCREF (Py_NotImplemented);
599 return Py_NotImplemented;
600 }
601
602 /* Implementation of
603 BtraceRecord.method [str]. */
604
605 PyObject *
recpy_bt_method(PyObject * self,void * closure)606 recpy_bt_method (PyObject *self, void *closure)
607 {
608 return PyUnicode_FromString ("btrace");
609 }
610
611 /* Implementation of
612 BtraceRecord.format [str]. */
613
614 PyObject *
recpy_bt_format(PyObject * self,void * closure)615 recpy_bt_format (PyObject *self, void *closure)
616 {
617 const recpy_record_object * const record = (recpy_record_object *) self;
618 const struct thread_info * const tinfo = record->thread;
619 const struct btrace_config * config;
620
621 if (tinfo == NULL)
622 Py_RETURN_NONE;
623
624 config = btrace_conf (&tinfo->btrace);
625
626 if (config == NULL)
627 Py_RETURN_NONE;
628
629 return PyUnicode_FromString (btrace_format_short_string (config->format));
630 }
631
632 /* Implementation of
633 BtraceRecord.replay_position [BtraceInstruction]. */
634
635 PyObject *
recpy_bt_replay_position(PyObject * self,void * closure)636 recpy_bt_replay_position (PyObject *self, void *closure)
637 {
638 const recpy_record_object * const record = (recpy_record_object *) self;
639 thread_info * tinfo = record->thread;
640
641 if (tinfo == NULL)
642 Py_RETURN_NONE;
643
644 if (tinfo->btrace.replay == NULL)
645 Py_RETURN_NONE;
646
647 return btpy_insn_or_gap_new (tinfo,
648 btrace_insn_number (tinfo->btrace.replay));
649 }
650
651 /* Implementation of
652 BtraceRecord.begin [BtraceInstruction]. */
653
654 PyObject *
recpy_bt_begin(PyObject * self,void * closure)655 recpy_bt_begin (PyObject *self, void *closure)
656 {
657 const recpy_record_object * const record = (recpy_record_object *) self;
658 thread_info *const tinfo = record->thread;
659 struct btrace_insn_iterator iterator;
660
661 if (tinfo == NULL)
662 Py_RETURN_NONE;
663
664 btrace_fetch (tinfo, record_btrace_get_cpu ());
665
666 if (btrace_is_empty (tinfo))
667 Py_RETURN_NONE;
668
669 btrace_insn_begin (&iterator, &tinfo->btrace);
670 return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator));
671 }
672
673 /* Implementation of
674 BtraceRecord.end [BtraceInstruction]. */
675
676 PyObject *
recpy_bt_end(PyObject * self,void * closure)677 recpy_bt_end (PyObject *self, void *closure)
678 {
679 const recpy_record_object * const record = (recpy_record_object *) self;
680 thread_info *const tinfo = record->thread;
681 struct btrace_insn_iterator iterator;
682
683 if (tinfo == NULL)
684 Py_RETURN_NONE;
685
686 btrace_fetch (tinfo, record_btrace_get_cpu ());
687
688 if (btrace_is_empty (tinfo))
689 Py_RETURN_NONE;
690
691 btrace_insn_end (&iterator, &tinfo->btrace);
692 return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator));
693 }
694
695 /* Implementation of
696 BtraceRecord.instruction_history [list]. */
697
698 PyObject *
recpy_bt_instruction_history(PyObject * self,void * closure)699 recpy_bt_instruction_history (PyObject *self, void *closure)
700 {
701 const recpy_record_object * const record = (recpy_record_object *) self;
702 thread_info *const tinfo = record->thread;
703 struct btrace_insn_iterator iterator;
704 unsigned long first = 0;
705 unsigned long last = 0;
706
707 if (tinfo == NULL)
708 Py_RETURN_NONE;
709
710 btrace_fetch (tinfo, record_btrace_get_cpu ());
711
712 if (btrace_is_empty (tinfo))
713 Py_RETURN_NONE;
714
715 btrace_insn_begin (&iterator, &tinfo->btrace);
716 first = btrace_insn_number (&iterator);
717
718 btrace_insn_end (&iterator, &tinfo->btrace);
719 last = btrace_insn_number (&iterator);
720
721 return btpy_list_new (tinfo, first, last, 1, &recpy_insn_type);
722 }
723
724 /* Implementation of
725 BtraceRecord.function_call_history [list]. */
726
727 PyObject *
recpy_bt_function_call_history(PyObject * self,void * closure)728 recpy_bt_function_call_history (PyObject *self, void *closure)
729 {
730 const recpy_record_object * const record = (recpy_record_object *) self;
731 thread_info *const tinfo = record->thread;
732 struct btrace_call_iterator iterator;
733 unsigned long first = 0;
734 unsigned long last = 0;
735
736 if (tinfo == NULL)
737 Py_RETURN_NONE;
738
739 btrace_fetch (tinfo, record_btrace_get_cpu ());
740
741 if (btrace_is_empty (tinfo))
742 Py_RETURN_NONE;
743
744 btrace_call_begin (&iterator, &tinfo->btrace);
745 first = btrace_call_number (&iterator);
746
747 btrace_call_end (&iterator, &tinfo->btrace);
748 last = btrace_call_number (&iterator);
749
750 return btpy_list_new (tinfo, first, last, 1, &recpy_func_type);
751 }
752
753 /* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None. */
754
755 PyObject *
recpy_bt_goto(PyObject * self,PyObject * args)756 recpy_bt_goto (PyObject *self, PyObject *args)
757 {
758 const recpy_record_object * const record = (recpy_record_object *) self;
759 thread_info *const tinfo = record->thread;
760 const recpy_element_object *obj;
761 PyObject *parse_obj;
762
763 if (tinfo == NULL || btrace_is_empty (tinfo))
764 return PyErr_Format (gdbpy_gdb_error, _("Empty branch trace."));
765
766 if (!PyArg_ParseTuple (args, "O", &parse_obj))
767 return NULL;
768
769 if (Py_TYPE (parse_obj) != &recpy_insn_type)
770 return PyErr_Format (PyExc_TypeError, _("Argument must be instruction."));
771 obj = (const recpy_element_object *) parse_obj;
772
773 try
774 {
775 struct btrace_insn_iterator iter;
776
777 btrace_insn_end (&iter, &tinfo->btrace);
778
779 if (btrace_insn_number (&iter) == obj->number)
780 target_goto_record_end ();
781 else
782 target_goto_record (obj->number);
783 }
784 catch (const gdb_exception &except)
785 {
786 GDB_PY_HANDLE_EXCEPTION (except);
787 }
788
789 Py_RETURN_NONE;
790 }
791
792 /* BtraceList methods. */
793
794 static PyMethodDef btpy_list_methods[] =
795 {
796 { "count", btpy_list_count, METH_O, "count number of occurrences"},
797 { "index", btpy_list_index, METH_O, "index of entry"},
798 {NULL}
799 };
800
801 /* BtraceList sequence methods. */
802
803 static PySequenceMethods btpy_list_sequence_methods =
804 {
805 NULL
806 };
807
808 /* BtraceList mapping methods. Necessary for slicing. */
809
810 static PyMappingMethods btpy_list_mapping_methods =
811 {
812 NULL
813 };
814
815 /* Sets up the btrace record API. */
816
817 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_btrace(void)818 gdbpy_initialize_btrace (void)
819 {
820 btpy_list_type.tp_new = PyType_GenericNew;
821 btpy_list_type.tp_flags = Py_TPFLAGS_DEFAULT;
822 btpy_list_type.tp_basicsize = sizeof (btpy_list_object);
823 btpy_list_type.tp_name = "gdb.BtraceObjectList";
824 btpy_list_type.tp_doc = "GDB btrace list object";
825 btpy_list_type.tp_methods = btpy_list_methods;
826 btpy_list_type.tp_as_sequence = &btpy_list_sequence_methods;
827 btpy_list_type.tp_as_mapping = &btpy_list_mapping_methods;
828 btpy_list_type.tp_richcompare = btpy_list_richcompare;
829
830 btpy_list_sequence_methods.sq_item = btpy_list_item;
831 btpy_list_sequence_methods.sq_length = btpy_list_length;
832 btpy_list_sequence_methods.sq_contains = btpy_list_contains;
833
834 btpy_list_mapping_methods.mp_subscript = btpy_list_slice;
835
836 return PyType_Ready (&btpy_list_type);
837 }
838
839 GDBPY_INITIALIZE_FILE (gdbpy_initialize_btrace);
840