python: Implement btrace Python bindings for record history.
[deliverable/binutils-gdb.git] / gdb / python / py-record-btrace.c
CommitLineData
75c0bdf4
TW
1/* Python interface to btrace instruction history.
2
3 Copyright 2016-2017 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "gdbcore.h"
22#include "gdbcmd.h"
23#include "gdbthread.h"
24#include "btrace.h"
25#include "py-record-btrace.h"
26#include "disasm.h"
27
28#if defined (IS_PY3K)
29
30#define BTPY_PYSLICE(x) (x)
31
32#else
33
34#define BTPY_PYSLICE(x) ((PySliceObject *) x)
35
36#endif
37
38#define BTPY_REQUIRE_VALID_INSN(obj, iter) \
39 do { \
40 struct thread_info *tinfo = find_thread_ptid (obj->ptid); \
41 if (tinfo == NULL || btrace_is_empty (tinfo)) \
42 return PyErr_Format (gdbpy_gdb_error, _("Empty branch trace."));\
43 if (0 == btrace_find_insn_by_number (&iter, &tinfo->btrace, \
44 obj->number)) \
45 return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));\
46 } while (0)
47
48#define BTPY_REQUIRE_VALID_CALL(obj, iter) \
49 do { \
50 struct thread_info *tinfo = find_thread_ptid (obj->ptid); \
51 if (tinfo == NULL || btrace_is_empty (tinfo)) \
52 return PyErr_Format (gdbpy_gdb_error, _("Empty branch trace."));\
53 if (0 == btrace_find_call_by_number (&iter, &tinfo->btrace, \
54 obj->number)) \
55 return PyErr_Format (gdbpy_gdb_error, _("No such call segment."));\
56 } while (0)
57
58/* This can either be a btrace instruction or a function call segment,
59 depending on the chosen type. */
60
61typedef struct {
62 PyObject_HEAD
63
64 /* The thread this object belongs to. */
65 ptid_t ptid;
66
67 /* Instruction number or function call segment number, depending on the type
68 of this object. */
69 Py_ssize_t number;
70} btpy_object;
71
72/* Python object for btrace record lists. */
73
74typedef struct {
75 PyObject_HEAD
76
77 /* The thread this list belongs to. */
78 ptid_t ptid;
79
80 /* The first index being part of this list. */
81 Py_ssize_t first;
82
83 /* The last index begin part of this list. */
84 Py_ssize_t last;
85
86 /* Stride size. */
87 Py_ssize_t step;
88
89 /* Either &BTPY_CALL_TYPE or &BTPY_INSN_TYPE. */
90 PyTypeObject* element_type;
91} btpy_list_object;
92
93/* Python type for btrace instructions. */
94
95static PyTypeObject btpy_insn_type = {
96 PyVarObject_HEAD_INIT (NULL, 0)
97};
98
99/* Python type for btrace function-calls. */
100
101static PyTypeObject btpy_call_type = {
102 PyVarObject_HEAD_INIT (NULL, 0)
103};
104
105/* Python type for btrace lists. */
106
107static PyTypeObject btpy_list_type = {
108 PyVarObject_HEAD_INIT (NULL, 0)
109};
110
111/* Create a new gdb.BtraceInstruction or gdb.BtraceFunctionCall object,
112 depending on TYPE. */
113
114static PyObject *
115btpy_new (ptid_t ptid, Py_ssize_t number, PyTypeObject* type)
116{
117 btpy_object * const obj = PyObject_New (btpy_object, type);
118
119 if (obj == NULL)
120 return NULL;
121
122 obj->ptid = ptid;
123 obj->number = number;
124
125 return (PyObject *) obj;
126}
127
128/* Create a new gdb.BtraceInstruction object. */
129
130static PyObject *
131btpy_insn_new (ptid_t ptid, Py_ssize_t number)
132{
133 return btpy_new (ptid, number, &btpy_insn_type);
134}
135
136/* Create a new gdb.BtraceFunctionCall object. */
137
138static PyObject *
139btpy_call_new (ptid_t ptid, Py_ssize_t number)
140{
141 return btpy_new (ptid, number, &btpy_call_type);
142}
143
144/* Create a new gdb.BtraceList object. */
145
146static PyObject *
147btpy_list_new (ptid_t ptid, Py_ssize_t first, Py_ssize_t last, Py_ssize_t step,
148 PyTypeObject *element_type)
149{
150 btpy_list_object * const obj = PyObject_New (btpy_list_object,
151 &btpy_list_type);
152
153 if (obj == NULL)
154 return NULL;
155
156 obj->ptid = ptid;
157 obj->first = first;
158 obj->last = last;
159 obj->step = step;
160 obj->element_type = element_type;
161
162 return (PyObject *) obj;
163}
164
165/* Implementation of BtraceInstruction.number [int] and
166 BtraceFunctionCall.number [int]. */
167
168static PyObject *
169btpy_number (PyObject *self, void *closure)
170{
171 const btpy_object * const obj = (btpy_object *) self;
172
173 return PyInt_FromSsize_t (obj->number);
174}
175
176/* Implementation of BtraceInstruction.__hash__ () -> int and
177 BtraceFunctionCall.__hash__ () -> int. */
178
179static Py_hash_t
180btpy_hash (PyObject *self)
181{
182 const btpy_object * const obj = (btpy_object *) self;
183
184 return obj->number;
185}
186
187/* Implementation of BtraceInstruction.error [int]. Returns the
188 error code for gaps. */
189
190static PyObject *
191btpy_insn_error (PyObject *self, void *closure)
192{
193 const btpy_object * const obj = (btpy_object *) self;
194 struct btrace_insn_iterator iter;
195 int error;
196
197 BTPY_REQUIRE_VALID_INSN (obj, iter);
198
199 error = btrace_insn_get_error (&iter);
200
201 if (error == 0)
202 Py_RETURN_NONE;
203
204 return PyInt_FromLong (error);
205}
206
207/* Implementation of BtraceInstruction.sal [gdb.Symtab_and_line].
208 Return the SAL associated with this instruction. */
209
210static PyObject *
211btpy_insn_sal (PyObject *self, void *closure)
212{
213 const btpy_object * const obj = (btpy_object *) self;
214 const struct btrace_insn *insn;
215 struct btrace_insn_iterator iter;
216 PyObject *result = NULL;
217
218 BTPY_REQUIRE_VALID_INSN (obj, iter);
219
220 insn = btrace_insn_get (&iter);
221 if (insn == NULL)
222 Py_RETURN_NONE;
223
224 TRY
225 {
226 result = symtab_and_line_to_sal_object (find_pc_line (insn->pc, 0));
227 }
228 CATCH (except, RETURN_MASK_ALL)
229 {
230 GDB_PY_HANDLE_EXCEPTION (except);
231 }
232 END_CATCH
233
234 return result;
235}
236
237/* Implementation of BtraceInstruction.pc [int]. Returns
238 the instruction address. */
239
240static PyObject *
241btpy_insn_pc (PyObject *self, void *closure)
242{
243 const btpy_object * const obj = (btpy_object *) self;
244 const struct btrace_insn *insn;
245 struct btrace_insn_iterator iter;
246
247 BTPY_REQUIRE_VALID_INSN (obj, iter);
248
249 insn = btrace_insn_get (&iter);
250 if (insn == NULL)
251 Py_RETURN_NONE;
252
253 return gdb_py_long_from_ulongest (insn->pc);
254}
255
256/* Implementation of BtraceInstruction.size [int]. Returns
257 the instruction size. */
258
259static PyObject *
260btpy_insn_size (PyObject *self, void *closure)
261{
262 const btpy_object * const obj = (btpy_object *) self;
263 const struct btrace_insn *insn;
264 struct btrace_insn_iterator iter;
265
266 BTPY_REQUIRE_VALID_INSN (obj, iter);
267
268 insn = btrace_insn_get (&iter);
269 if (insn == NULL)
270 Py_RETURN_NONE;
271
272 return PyInt_FromLong (insn->size);
273}
274
275/* Implementation of BtraceInstruction.is_speculative [bool].
276 Returns if this instruction was executed speculatively. */
277
278static PyObject *
279btpy_insn_is_speculative (PyObject *self, void *closure)
280{
281 const btpy_object * const obj = (btpy_object *) self;
282 const struct btrace_insn *insn;
283 struct btrace_insn_iterator iter;
284
285 BTPY_REQUIRE_VALID_INSN (obj, iter);
286
287 insn = btrace_insn_get (&iter);
288 if (insn == NULL)
289 Py_RETURN_NONE;
290
291 if (insn->flags & BTRACE_INSN_FLAG_SPECULATIVE)
292 Py_RETURN_TRUE;
293 else
294 Py_RETURN_FALSE;
295}
296
297/* Implementation of BtraceInstruction.data [buffer].
298 Returns raw instruction data. */
299
300static PyObject *
301btpy_insn_data (PyObject *self, void *closure)
302{
303 const btpy_object * const obj = (btpy_object *) self;
304 const struct btrace_insn *insn;
305 struct btrace_insn_iterator iter;
306 gdb_byte *buffer = NULL;
307 PyObject *object;
308
309 BTPY_REQUIRE_VALID_INSN (obj, iter);
310
311 insn = btrace_insn_get (&iter);
312 if (insn == NULL)
313 Py_RETURN_NONE;
314
315 TRY
316 {
317 buffer = (gdb_byte *) xmalloc (insn->size);
318 read_memory (insn->pc, buffer, insn->size);
319 }
320 CATCH (except, RETURN_MASK_ALL)
321 {
322 xfree (buffer);
323 GDB_PY_HANDLE_EXCEPTION (except);
324 }
325 END_CATCH
326
327 object = PyBytes_FromStringAndSize ((const char*) buffer, insn->size);
328 xfree (buffer);
329
330 if (object == NULL)
331 return NULL;
332
333 return PyMemoryView_FromObject (object);
334}
335
336/* Implementation of BtraceInstruction.decode [str]. Returns
337 the instruction as human readable string. */
338
339static PyObject *
340btpy_insn_decode (PyObject *self, void *closure)
341{
342 const btpy_object * const obj = (btpy_object *) self;
343 const struct btrace_insn *insn;
344 struct btrace_insn_iterator iter;
345 string_file strfile;
346
347 BTPY_REQUIRE_VALID_INSN (obj, iter);
348
349 insn = btrace_insn_get (&iter);
350 if (insn == NULL)
351 {
352 int error_code = btrace_insn_get_error (&iter);
353 const struct btrace_config *config;
354
355 config = btrace_conf (&find_thread_ptid (obj->ptid)->btrace);
356 return PyBytes_FromString (btrace_decode_error (config->format,
357 error_code));
358 }
359
360 TRY
361 {
362 gdb_print_insn (target_gdbarch (), insn->pc, &strfile, NULL);
363 }
364 CATCH (except, RETURN_MASK_ALL)
365 {
366 gdbpy_convert_exception (except);
367 return NULL;
368 }
369 END_CATCH
370
371
372 return PyBytes_FromString (strfile.string ().c_str ());
373}
374
375/* Implementation of BtraceFunctionCall.level [int]. Returns the
376 call level. */
377
378static PyObject *
379btpy_call_level (PyObject *self, void *closure)
380{
381 const btpy_object * const obj = (btpy_object *) self;
382 const struct btrace_function *func;
383 struct btrace_call_iterator iter;
384
385 BTPY_REQUIRE_VALID_CALL (obj, iter);
386
387 func = btrace_call_get (&iter);
388 if (func == NULL)
389 Py_RETURN_NONE;
390
391 return PyInt_FromLong (iter.btinfo->level + func->level);
392}
393
394/* Implementation of BtraceFunctionCall.symbol [gdb.Symbol]. Returns
395 the symbol associated with this function call. */
396
397static PyObject *
398btpy_call_symbol (PyObject *self, void *closure)
399{
400 const btpy_object * const obj = (btpy_object *) self;
401 const struct btrace_function *func;
402 struct btrace_call_iterator iter;
403
404 BTPY_REQUIRE_VALID_CALL (obj, iter);
405
406 func = btrace_call_get (&iter);
407 if (func == NULL)
408 Py_RETURN_NONE;
409
410 if (func->sym == NULL)
411 Py_RETURN_NONE;
412
413 return symbol_to_symbol_object (func->sym);
414}
415
416/* Implementation of BtraceFunctionCall.instructions [list].
417 Return the list of instructions that belong to this function call. */
418
419static PyObject *
420btpy_call_instructions (PyObject *self, void *closure)
421{
422 const btpy_object * const obj = (btpy_object *) self;
423 const struct btrace_function *func;
424 struct btrace_call_iterator iter;
425 unsigned int len;
426
427 BTPY_REQUIRE_VALID_CALL (obj, iter);
428
429 func = btrace_call_get (&iter);
430 if (func == NULL)
431 Py_RETURN_NONE;
432
433 len = VEC_length (btrace_insn_s, func->insn);
434
435 /* Gaps count as one instruction. */
436 if (len == 0)
437 len = 1;
438
439 return btpy_list_new (obj->ptid, func->insn_offset, func->insn_offset + len,
440 1, &btpy_insn_type);
441}
442
443/* Implementation of BtraceFunctionCall.up [gdb.BtraceRecordCall].
444 Return the caller / returnee of this function. */
445
446static PyObject *
447btpy_call_up (PyObject *self, void *closure)
448{
449 const btpy_object * const obj = (btpy_object *) self;
450 const struct btrace_function *func;
451 struct btrace_call_iterator iter;
452
453 BTPY_REQUIRE_VALID_CALL (obj, iter);
454
455 func = btrace_call_get (&iter);
456 if (func == NULL)
457 Py_RETURN_NONE;
458
459 if (func->up == NULL)
460 Py_RETURN_NONE;
461
462 return btpy_call_new (obj->ptid, func->up->number);
463}
464
465/* Implementation of BtraceFunctionCall.prev_sibling [BtraceFunctionCall].
466 Return a previous segment of this function. */
467
468static PyObject *
469btpy_call_prev_sibling (PyObject *self, void *closure)
470{
471 const btpy_object * const obj = (btpy_object *) self;
472 const struct btrace_function *func;
473 struct btrace_call_iterator iter;
474
475 BTPY_REQUIRE_VALID_CALL (obj, iter);
476
477 func = btrace_call_get (&iter);
478 if (func == NULL)
479 Py_RETURN_NONE;
480
481 if (func->segment.prev == NULL)
482 Py_RETURN_NONE;
483
484 return btpy_call_new (obj->ptid, func->segment.prev->number);
485}
486
487/* Implementation of BtraceFunctionCall.next_sibling [BtraceFunctionCall].
488 Return a following segment of this function. */
489
490static PyObject *
491btpy_call_next_sibling (PyObject *self, void *closure)
492{
493 const btpy_object * const obj = (btpy_object *) self;
494 const struct btrace_function *func;
495 struct btrace_call_iterator iter;
496
497 BTPY_REQUIRE_VALID_CALL (obj, iter);
498
499 func = btrace_call_get (&iter);
500 if (func == NULL)
501 Py_RETURN_NONE;
502
503 if (func->segment.next == NULL)
504 Py_RETURN_NONE;
505
506 return btpy_call_new (obj->ptid, func->segment.next->number);
507}
508
509/* Python rich compare function to allow for equality and inequality checks
510 in Python. */
511
512static PyObject *
513btpy_richcompare (PyObject *self, PyObject *other, int op)
514{
515 const btpy_object * const obj1 = (btpy_object *) self;
516 const btpy_object * const obj2 = (btpy_object *) other;
517
518 if (Py_TYPE (self) != Py_TYPE (other))
519 {
520 Py_INCREF (Py_NotImplemented);
521 return Py_NotImplemented;
522 }
523
524 switch (op)
525 {
526 case Py_EQ:
527 if (ptid_equal (obj1->ptid, obj2->ptid) && obj1->number == obj2->number)
528 Py_RETURN_TRUE;
529 else
530 Py_RETURN_FALSE;
531
532 case Py_NE:
533 if (!ptid_equal (obj1->ptid, obj2->ptid) || obj1->number != obj2->number)
534 Py_RETURN_TRUE;
535 else
536 Py_RETURN_FALSE;
537
538 default:
539 break;
540 }
541
542 Py_INCREF (Py_NotImplemented);
543 return Py_NotImplemented;
544}
545
546/* Implementation of BtraceList.__len__ (self) -> int. */
547
548static Py_ssize_t
549btpy_list_length (PyObject *self)
550{
551 const btpy_list_object * const obj = (btpy_list_object *) self;
552 const Py_ssize_t distance = obj->last - obj->first;
553 const Py_ssize_t result = distance / obj->step;
554
555 if ((distance % obj->step) == 0)
556 return result;
557
558 return result + 1;
559}
560
561/* Implementation of
562 BtraceList.__getitem__ (self, key) -> BtraceInstruction and
563 BtraceList.__getitem__ (self, key) -> BtraceFunctionCall. */
564
565static PyObject *
566btpy_list_item (PyObject *self, Py_ssize_t index)
567{
568 const btpy_list_object * const obj = (btpy_list_object *) self;
569 struct thread_info * const tinfo = find_thread_ptid (obj->ptid);
570
571 if (index < 0 || index >= btpy_list_length (self))
572 return PyErr_Format (PyExc_IndexError, _("Index out of range: %zd."),
573 index);
574
575 return btpy_new (obj->ptid, obj->first + (obj->step * index),
576 obj->element_type);
577}
578
579/* Implementation of BtraceList.__getitem__ (self, slice) -> BtraceList. */
580
581static PyObject *
582btpy_list_slice (PyObject *self, PyObject *value)
583{
584 const btpy_list_object * const obj = (btpy_list_object *) self;
585 const Py_ssize_t length = btpy_list_length (self);
586 Py_ssize_t start, stop, step, slicelength;
587
588 if (PyInt_Check (value))
589 {
590 Py_ssize_t index = PyInt_AsSsize_t (value);
591
592 /* Emulate Python behavior for negative indices. */
593 if (index < 0)
594 index += length;
595
596 return btpy_list_item (self, index);
597 }
598
599 if (!PySlice_Check (value))
600 return PyErr_Format (PyExc_TypeError, _("Index must be int or slice."));
601
602 if (0 != PySlice_GetIndicesEx (BTPY_PYSLICE (value), length, &start, &stop,
603 &step, &slicelength))
604 return NULL;
605
606 return btpy_list_new (obj->ptid, obj->first + obj->step * start,
607 obj->first + obj->step * stop, obj->step * step,
608 obj->element_type);
609}
610
611/* Helper function that returns the position of an element in a BtraceList
612 or -1 if the element is not in the list. */
613
614static LONGEST
615btpy_list_position (PyObject *self, PyObject *value)
616{
617 const btpy_list_object * const list_obj = (btpy_list_object *) self;
618 const btpy_object * const obj = (btpy_object *) value;
619 Py_ssize_t index = obj->number;
620
621 if (list_obj->element_type != Py_TYPE (value))
622 return -1;
623
624 if (!ptid_equal (list_obj->ptid, obj->ptid))
625 return -1;
626
627 if (index < list_obj->first || index > list_obj->last)
628 return -1;
629
630 index -= list_obj->first;
631
632 if (index % list_obj->step != 0)
633 return -1;
634
635 return index / list_obj->step;
636}
637
638/* Implementation of "in" operator for BtraceLists. */
639
640static int
641btpy_list_contains (PyObject *self, PyObject *value)
642{
643 if (btpy_list_position (self, value) < 0)
644 return 0;
645
646 return 1;
647}
648
649/* Implementation of BtraceLists.index (self, value) -> int. */
650
651static PyObject *
652btpy_list_index (PyObject *self, PyObject *value)
653{
654 const LONGEST index = btpy_list_position (self, value);
655
656 if (index < 0)
657 return PyErr_Format (PyExc_ValueError, _("Not in list."));
658
659 return gdb_py_long_from_longest (index);
660}
661
662/* Implementation of BtraceList.count (self, value) -> int. */
663
664static PyObject *
665btpy_list_count (PyObject *self, PyObject *value)
666{
667 /* We know that if an element is in the list, it is so exactly one time,
668 enabling us to reuse the "is element of" check. */
669 return PyInt_FromLong (btpy_list_contains (self, value));
670}
671
672/* Python rich compare function to allow for equality and inequality checks
673 in Python. */
674
675static PyObject *
676btpy_list_richcompare (PyObject *self, PyObject *other, int op)
677{
678 const btpy_list_object * const obj1 = (btpy_list_object *) self;
679 const btpy_list_object * const obj2 = (btpy_list_object *) other;
680
681 if (Py_TYPE (self) != Py_TYPE (other))
682 {
683 Py_INCREF (Py_NotImplemented);
684 return Py_NotImplemented;
685 }
686
687 switch (op)
688 {
689 case Py_EQ:
690 if (ptid_equal (obj1->ptid, obj2->ptid)
691 && obj1->element_type == obj2->element_type
692 && obj1->first == obj2->first
693 && obj1->last == obj2->last
694 && obj1->step == obj2->step)
695 Py_RETURN_TRUE;
696 else
697 Py_RETURN_FALSE;
698
699 case Py_NE:
700 if (!ptid_equal (obj1->ptid, obj2->ptid)
701 || obj1->element_type != obj2->element_type
702 || obj1->first != obj2->first
703 || obj1->last != obj2->last
704 || obj1->step != obj2->step)
705 Py_RETURN_TRUE;
706 else
707 Py_RETURN_FALSE;
708
709 default:
710 break;
711 }
712
713 Py_INCREF (Py_NotImplemented);
714 return Py_NotImplemented;
715}
716
717/* Implementation of
718 BtraceRecord.method [str]. */
719
720PyObject *
721recpy_bt_method (PyObject *self, void *closure)
722{
723 return PyString_FromString ("btrace");
724}
725
726/* Implementation of
727 BtraceRecord.format [str]. */
728
729PyObject *
730recpy_bt_format (PyObject *self, void *closure)
731{
732 const struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
733 const struct btrace_config * config;
734
735 if (tinfo == NULL)
736 Py_RETURN_NONE;
737
738 config = btrace_conf (&tinfo->btrace);
739
740 if (config == NULL)
741 Py_RETURN_NONE;
742
743 return PyString_FromString (btrace_format_short_string (config->format));
744}
745
746/* Implementation of
747 BtraceRecord.replay_position [BtraceInstruction]. */
748
749PyObject *
750recpy_bt_replay_position (PyObject *self, void *closure)
751{
752 const struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
753
754 if (tinfo == NULL)
755 Py_RETURN_NONE;
756
757 if (tinfo->btrace.replay == NULL)
758 Py_RETURN_NONE;
759
760 return btpy_insn_new (inferior_ptid,
761 btrace_insn_number (tinfo->btrace.replay));
762}
763
764/* Implementation of
765 BtraceRecord.begin [BtraceInstruction]. */
766
767PyObject *
768recpy_bt_begin (PyObject *self, void *closure)
769{
770 struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
771 struct btrace_insn_iterator iterator;
772
773 if (tinfo == NULL)
774 Py_RETURN_NONE;
775
776 btrace_fetch (tinfo);
777
778 if (btrace_is_empty (tinfo))
779 Py_RETURN_NONE;
780
781 btrace_insn_begin (&iterator, &tinfo->btrace);
782 return btpy_insn_new (inferior_ptid, btrace_insn_number (&iterator));
783}
784
785/* Implementation of
786 BtraceRecord.end [BtraceInstruction]. */
787
788PyObject *
789recpy_bt_end (PyObject *self, void *closure)
790{
791 struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
792 struct btrace_insn_iterator iterator;
793
794 if (tinfo == NULL)
795 Py_RETURN_NONE;
796
797 btrace_fetch (tinfo);
798
799 if (btrace_is_empty (tinfo))
800 Py_RETURN_NONE;
801
802 btrace_insn_end (&iterator, &tinfo->btrace);
803 return btpy_insn_new (inferior_ptid, btrace_insn_number (&iterator));
804}
805
806/* Implementation of
807 BtraceRecord.instruction_history [list]. */
808
809PyObject *
810recpy_bt_instruction_history (PyObject *self, void *closure)
811{
812 struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
813 struct btrace_insn_iterator iterator;
814 unsigned long first = 0;
815 unsigned long last = 0;
816
817 if (tinfo == NULL)
818 Py_RETURN_NONE;
819
820 btrace_fetch (tinfo);
821
822 if (btrace_is_empty (tinfo))
823 Py_RETURN_NONE;
824
825 btrace_insn_begin (&iterator, &tinfo->btrace);
826 first = btrace_insn_number (&iterator);
827
828 btrace_insn_end (&iterator, &tinfo->btrace);
829 last = btrace_insn_number (&iterator);
830
831 return btpy_list_new (inferior_ptid, first, last, 1, &btpy_insn_type);
832}
833
834/* Implementation of
835 BtraceRecord.function_call_history [list]. */
836
837PyObject *
838recpy_bt_function_call_history (PyObject *self, void *closure)
839{
840 struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
841 struct btrace_call_iterator iterator;
842 unsigned long first = 0;
843 unsigned long last = 0;
844
845 if (tinfo == NULL)
846 Py_RETURN_NONE;
847
848 btrace_fetch (tinfo);
849
850 if (btrace_is_empty (tinfo))
851 Py_RETURN_NONE;
852
853 btrace_call_begin (&iterator, &tinfo->btrace);
854 first = btrace_call_number (&iterator);
855
856 btrace_call_end (&iterator, &tinfo->btrace);
857 last = btrace_call_number (&iterator);
858
859 return btpy_list_new (inferior_ptid, first, last, 1, &btpy_call_type);
860}
861
862/* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None. */
863
864PyObject *
865recpy_bt_goto (PyObject *self, PyObject *args)
866{
867 struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
868 const btpy_object *obj;
869
870 if (tinfo == NULL || btrace_is_empty (tinfo))
871 return PyErr_Format (gdbpy_gdb_error, _("Empty branch trace."));
872
873 if (!PyArg_ParseTuple (args, "O", &obj))
874 return NULL;
875
876 if (Py_TYPE (obj) != &btpy_insn_type)
877 return PyErr_Format (PyExc_TypeError, _("Argument must be instruction."));
878
879 TRY
880 {
881 struct btrace_insn_iterator iter;
882
883 btrace_insn_end (&iter, &tinfo->btrace);
884
885 if (btrace_insn_number (&iter) == obj->number)
886 target_goto_record_end ();
887 else
888 target_goto_record (obj->number);
889 }
890 CATCH (except, RETURN_MASK_ALL)
891 {
892 GDB_PY_HANDLE_EXCEPTION (except);
893 }
894 END_CATCH
895
896 Py_RETURN_NONE;
897}
898
899/* BtraceInstruction members. */
900
901struct PyGetSetDef btpy_insn_getset[] =
902{
903 { "number", btpy_number, NULL, "instruction number", NULL},
904 { "error", btpy_insn_error, NULL, "error number for gaps", NULL},
905 { "sal", btpy_insn_sal, NULL, "associated symbol and line", NULL},
906 { "pc", btpy_insn_pc, NULL, "instruction address", NULL},
907 { "data", btpy_insn_data, NULL, "raw instruction data", NULL},
908 { "decoded", btpy_insn_decode, NULL, "decoded instruction or error message \
909if the instruction is a gap", NULL},
910 { "size", btpy_insn_size, NULL, "instruction size in byte", NULL},
911 { "is_speculative", btpy_insn_is_speculative, NULL, "if the instruction was \
912executed speculatively", NULL},
913 {NULL}
914};
915
916/* BtraceFunctionCall members. */
917
918static PyGetSetDef btpy_call_getset[] =
919{
920 { "number", btpy_number, NULL, "function call number", NULL},
921 { "level", btpy_call_level, NULL, "call stack level", NULL},
922 { "symbol", btpy_call_symbol, NULL, "associated line and symbol", NULL},
923 { "instructions", btpy_call_instructions, NULL, "list of instructions in \
924this function segment", NULL},
925 { "up", btpy_call_up, NULL, "caller or returned-to function segment", NULL},
926 { "prev_sibling", btpy_call_prev_sibling, NULL, "previous segment of this \
927function", NULL},
928 { "next_sibling", btpy_call_next_sibling, NULL, "next segment of this \
929function", NULL},
930 {NULL}
931};
932
933/* BtraceList methods. */
934
935struct PyMethodDef btpy_list_methods[] =
936{
937 { "count", btpy_list_count, METH_O, "count number of occurences"},
938 { "index", btpy_list_index, METH_O, "index of entry"},
939 {NULL}
940};
941
942/* BtraceList sequence methods. */
943
944static PySequenceMethods btpy_list_sequence_methods =
945{
946 NULL
947};
948
949/* BtraceList mapping methods. Necessary for slicing. */
950
951static PyMappingMethods btpy_list_mapping_methods =
952{
953 NULL
954};
955
956/* Sets up the btrace record API. */
957
958int
959gdbpy_initialize_btrace (void)
960{
961 btpy_insn_type.tp_new = PyType_GenericNew;
962 btpy_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
963 btpy_insn_type.tp_basicsize = sizeof (btpy_object);
964 btpy_insn_type.tp_name = "gdb.BtraceInstruction";
965 btpy_insn_type.tp_doc = "GDB btrace instruction object";
966 btpy_insn_type.tp_getset = btpy_insn_getset;
967 btpy_insn_type.tp_richcompare = btpy_richcompare;
968 btpy_insn_type.tp_hash = btpy_hash;
969
970 btpy_call_type.tp_new = PyType_GenericNew;
971 btpy_call_type.tp_flags = Py_TPFLAGS_DEFAULT;
972 btpy_call_type.tp_basicsize = sizeof (btpy_object);
973 btpy_call_type.tp_name = "gdb.BtraceFunctionCall";
974 btpy_call_type.tp_doc = "GDB btrace call object";
975 btpy_call_type.tp_getset = btpy_call_getset;
976 btpy_call_type.tp_richcompare = btpy_richcompare;
977 btpy_call_type.tp_hash = btpy_hash;
978
979 btpy_list_type.tp_new = PyType_GenericNew;
980 btpy_list_type.tp_flags = Py_TPFLAGS_DEFAULT;
981 btpy_list_type.tp_basicsize = sizeof (btpy_list_object);
982 btpy_list_type.tp_name = "gdb.BtraceObjectList";
983 btpy_list_type.tp_doc = "GDB btrace list object";
984 btpy_list_type.tp_methods = btpy_list_methods;
985 btpy_list_type.tp_as_sequence = &btpy_list_sequence_methods;
986 btpy_list_type.tp_as_mapping = &btpy_list_mapping_methods;
987 btpy_list_type.tp_richcompare = btpy_list_richcompare;
988
989 btpy_list_sequence_methods.sq_item = btpy_list_item;
990 btpy_list_sequence_methods.sq_length = btpy_list_length;
991 btpy_list_sequence_methods.sq_contains = btpy_list_contains;
992
993 btpy_list_mapping_methods.mp_subscript = btpy_list_slice;
994
995 if (PyType_Ready (&btpy_insn_type) < 0
996 || PyType_Ready (&btpy_call_type) < 0
997 || PyType_Ready (&btpy_list_type) < 0)
998 return -1;
999 else
1000 return 0;
1001}
This page took 0.057798 seconds and 4 git commands to generate.