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