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