]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/record-btrace.c
record-btrace, frame: supply target-specific unwinder
[thirdparty/binutils-gdb.git] / gdb / record-btrace.c
1 /* Branch trace support for GDB, the GNU debugger.
2
3 Copyright (C) 2013-2014 Free Software Foundation, Inc.
4
5 Contributed by Intel Corp. <markus.t.metzger@intel.com>
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "defs.h"
23 #include "record.h"
24 #include "gdbthread.h"
25 #include "target.h"
26 #include "gdbcmd.h"
27 #include "disasm.h"
28 #include "observer.h"
29 #include "exceptions.h"
30 #include "cli/cli-utils.h"
31 #include "source.h"
32 #include "ui-out.h"
33 #include "symtab.h"
34 #include "filenames.h"
35 #include "regcache.h"
36 #include "frame-unwind.h"
37
38 /* The target_ops of record-btrace. */
39 static struct target_ops record_btrace_ops;
40
41 /* A new thread observer enabling branch tracing for the new thread. */
42 static struct observer *record_btrace_thread_observer;
43
44 /* Print a record-btrace debug message. Use do ... while (0) to avoid
45 ambiguities when used in if statements. */
46
47 #define DEBUG(msg, args...) \
48 do \
49 { \
50 if (record_debug != 0) \
51 fprintf_unfiltered (gdb_stdlog, \
52 "[record-btrace] " msg "\n", ##args); \
53 } \
54 while (0)
55
56
57 /* Update the branch trace for the current thread and return a pointer to its
58 branch trace information struct.
59
60 Throws an error if there is no thread or no trace. This function never
61 returns NULL. */
62
63 static struct btrace_thread_info *
64 require_btrace (void)
65 {
66 struct thread_info *tp;
67 struct btrace_thread_info *btinfo;
68
69 DEBUG ("require");
70
71 tp = find_thread_ptid (inferior_ptid);
72 if (tp == NULL)
73 error (_("No thread."));
74
75 btrace_fetch (tp);
76
77 btinfo = &tp->btrace;
78
79 if (btinfo->begin == NULL)
80 error (_("No trace."));
81
82 return btinfo;
83 }
84
85 /* Enable branch tracing for one thread. Warn on errors. */
86
87 static void
88 record_btrace_enable_warn (struct thread_info *tp)
89 {
90 volatile struct gdb_exception error;
91
92 TRY_CATCH (error, RETURN_MASK_ERROR)
93 btrace_enable (tp);
94
95 if (error.message != NULL)
96 warning ("%s", error.message);
97 }
98
99 /* Callback function to disable branch tracing for one thread. */
100
101 static void
102 record_btrace_disable_callback (void *arg)
103 {
104 struct thread_info *tp;
105
106 tp = arg;
107
108 btrace_disable (tp);
109 }
110
111 /* Enable automatic tracing of new threads. */
112
113 static void
114 record_btrace_auto_enable (void)
115 {
116 DEBUG ("attach thread observer");
117
118 record_btrace_thread_observer
119 = observer_attach_new_thread (record_btrace_enable_warn);
120 }
121
122 /* Disable automatic tracing of new threads. */
123
124 static void
125 record_btrace_auto_disable (void)
126 {
127 /* The observer may have been detached, already. */
128 if (record_btrace_thread_observer == NULL)
129 return;
130
131 DEBUG ("detach thread observer");
132
133 observer_detach_new_thread (record_btrace_thread_observer);
134 record_btrace_thread_observer = NULL;
135 }
136
137 /* The to_open method of target record-btrace. */
138
139 static void
140 record_btrace_open (char *args, int from_tty)
141 {
142 struct cleanup *disable_chain;
143 struct thread_info *tp;
144
145 DEBUG ("open");
146
147 record_preopen ();
148
149 if (!target_has_execution)
150 error (_("The program is not being run."));
151
152 if (!target_supports_btrace ())
153 error (_("Target does not support branch tracing."));
154
155 gdb_assert (record_btrace_thread_observer == NULL);
156
157 disable_chain = make_cleanup (null_cleanup, NULL);
158 ALL_THREADS (tp)
159 if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
160 {
161 btrace_enable (tp);
162
163 make_cleanup (record_btrace_disable_callback, tp);
164 }
165
166 record_btrace_auto_enable ();
167
168 push_target (&record_btrace_ops);
169
170 observer_notify_record_changed (current_inferior (), 1);
171
172 discard_cleanups (disable_chain);
173 }
174
175 /* The to_stop_recording method of target record-btrace. */
176
177 static void
178 record_btrace_stop_recording (void)
179 {
180 struct thread_info *tp;
181
182 DEBUG ("stop recording");
183
184 record_btrace_auto_disable ();
185
186 ALL_THREADS (tp)
187 if (tp->btrace.target != NULL)
188 btrace_disable (tp);
189 }
190
191 /* The to_close method of target record-btrace. */
192
193 static void
194 record_btrace_close (void)
195 {
196 /* Make sure automatic recording gets disabled even if we did not stop
197 recording before closing the record-btrace target. */
198 record_btrace_auto_disable ();
199
200 /* We already stopped recording. */
201 }
202
203 /* The to_info_record method of target record-btrace. */
204
205 static void
206 record_btrace_info (void)
207 {
208 struct btrace_thread_info *btinfo;
209 struct thread_info *tp;
210 unsigned int insns, calls;
211
212 DEBUG ("info");
213
214 tp = find_thread_ptid (inferior_ptid);
215 if (tp == NULL)
216 error (_("No thread."));
217
218 btrace_fetch (tp);
219
220 insns = 0;
221 calls = 0;
222
223 btinfo = &tp->btrace;
224 if (btinfo->begin != NULL)
225 {
226 struct btrace_call_iterator call;
227 struct btrace_insn_iterator insn;
228
229 btrace_call_end (&call, btinfo);
230 btrace_call_prev (&call, 1);
231 calls = btrace_call_number (&call);
232
233 btrace_insn_end (&insn, btinfo);
234 btrace_insn_prev (&insn, 1);
235 insns = btrace_insn_number (&insn);
236 }
237
238 printf_unfiltered (_("Recorded %u instructions in %u functions for thread "
239 "%d (%s).\n"), insns, calls, tp->num,
240 target_pid_to_str (tp->ptid));
241
242 if (btrace_is_replaying (tp))
243 printf_unfiltered (_("Replay in progress. At instruction %u.\n"),
244 btrace_insn_number (btinfo->replay));
245 }
246
247 /* Print an unsigned int. */
248
249 static void
250 ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
251 {
252 ui_out_field_fmt (uiout, fld, "%u", val);
253 }
254
255 /* Disassemble a section of the recorded instruction trace. */
256
257 static void
258 btrace_insn_history (struct ui_out *uiout,
259 const struct btrace_insn_iterator *begin,
260 const struct btrace_insn_iterator *end, int flags)
261 {
262 struct gdbarch *gdbarch;
263 struct btrace_insn_iterator it;
264
265 DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
266 btrace_insn_number (end));
267
268 gdbarch = target_gdbarch ();
269
270 for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
271 {
272 const struct btrace_insn *insn;
273
274 insn = btrace_insn_get (&it);
275
276 /* Print the instruction index. */
277 ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
278 ui_out_text (uiout, "\t");
279
280 /* Disassembly with '/m' flag may not produce the expected result.
281 See PR gdb/11833. */
282 gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->pc + 1);
283 }
284 }
285
286 /* The to_insn_history method of target record-btrace. */
287
288 static void
289 record_btrace_insn_history (int size, int flags)
290 {
291 struct btrace_thread_info *btinfo;
292 struct btrace_insn_history *history;
293 struct btrace_insn_iterator begin, end;
294 struct cleanup *uiout_cleanup;
295 struct ui_out *uiout;
296 unsigned int context, covered;
297
298 uiout = current_uiout;
299 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
300 "insn history");
301 context = abs (size);
302 if (context == 0)
303 error (_("Bad record instruction-history-size."));
304
305 btinfo = require_btrace ();
306 history = btinfo->insn_history;
307 if (history == NULL)
308 {
309 struct btrace_insn_iterator *replay;
310
311 DEBUG ("insn-history (0x%x): %d", flags, size);
312
313 /* If we're replaying, we start at the replay position. Otherwise, we
314 start at the tail of the trace. */
315 replay = btinfo->replay;
316 if (replay != NULL)
317 begin = *replay;
318 else
319 btrace_insn_end (&begin, btinfo);
320
321 /* We start from here and expand in the requested direction. Then we
322 expand in the other direction, as well, to fill up any remaining
323 context. */
324 end = begin;
325 if (size < 0)
326 {
327 /* We want the current position covered, as well. */
328 covered = btrace_insn_next (&end, 1);
329 covered += btrace_insn_prev (&begin, context - covered);
330 covered += btrace_insn_next (&end, context - covered);
331 }
332 else
333 {
334 covered = btrace_insn_next (&end, context);
335 covered += btrace_insn_prev (&begin, context - covered);
336 }
337 }
338 else
339 {
340 begin = history->begin;
341 end = history->end;
342
343 DEBUG ("insn-history (0x%x): %d, prev: [%u; %u)", flags, size,
344 btrace_insn_number (&begin), btrace_insn_number (&end));
345
346 if (size < 0)
347 {
348 end = begin;
349 covered = btrace_insn_prev (&begin, context);
350 }
351 else
352 {
353 begin = end;
354 covered = btrace_insn_next (&end, context);
355 }
356 }
357
358 if (covered > 0)
359 btrace_insn_history (uiout, &begin, &end, flags);
360 else
361 {
362 if (size < 0)
363 printf_unfiltered (_("At the start of the branch trace record.\n"));
364 else
365 printf_unfiltered (_("At the end of the branch trace record.\n"));
366 }
367
368 btrace_set_insn_history (btinfo, &begin, &end);
369 do_cleanups (uiout_cleanup);
370 }
371
372 /* The to_insn_history_range method of target record-btrace. */
373
374 static void
375 record_btrace_insn_history_range (ULONGEST from, ULONGEST to, int flags)
376 {
377 struct btrace_thread_info *btinfo;
378 struct btrace_insn_history *history;
379 struct btrace_insn_iterator begin, end;
380 struct cleanup *uiout_cleanup;
381 struct ui_out *uiout;
382 unsigned int low, high;
383 int found;
384
385 uiout = current_uiout;
386 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
387 "insn history");
388 low = from;
389 high = to;
390
391 DEBUG ("insn-history (0x%x): [%u; %u)", flags, low, high);
392
393 /* Check for wrap-arounds. */
394 if (low != from || high != to)
395 error (_("Bad range."));
396
397 if (high < low)
398 error (_("Bad range."));
399
400 btinfo = require_btrace ();
401
402 found = btrace_find_insn_by_number (&begin, btinfo, low);
403 if (found == 0)
404 error (_("Range out of bounds."));
405
406 found = btrace_find_insn_by_number (&end, btinfo, high);
407 if (found == 0)
408 {
409 /* Silently truncate the range. */
410 btrace_insn_end (&end, btinfo);
411 }
412 else
413 {
414 /* We want both begin and end to be inclusive. */
415 btrace_insn_next (&end, 1);
416 }
417
418 btrace_insn_history (uiout, &begin, &end, flags);
419 btrace_set_insn_history (btinfo, &begin, &end);
420
421 do_cleanups (uiout_cleanup);
422 }
423
424 /* The to_insn_history_from method of target record-btrace. */
425
426 static void
427 record_btrace_insn_history_from (ULONGEST from, int size, int flags)
428 {
429 ULONGEST begin, end, context;
430
431 context = abs (size);
432 if (context == 0)
433 error (_("Bad record instruction-history-size."));
434
435 if (size < 0)
436 {
437 end = from;
438
439 if (from < context)
440 begin = 0;
441 else
442 begin = from - context + 1;
443 }
444 else
445 {
446 begin = from;
447 end = from + context - 1;
448
449 /* Check for wrap-around. */
450 if (end < begin)
451 end = ULONGEST_MAX;
452 }
453
454 record_btrace_insn_history_range (begin, end, flags);
455 }
456
457 /* Print the instruction number range for a function call history line. */
458
459 static void
460 btrace_call_history_insn_range (struct ui_out *uiout,
461 const struct btrace_function *bfun)
462 {
463 unsigned int begin, end, size;
464
465 size = VEC_length (btrace_insn_s, bfun->insn);
466 gdb_assert (size > 0);
467
468 begin = bfun->insn_offset;
469 end = begin + size - 1;
470
471 ui_out_field_uint (uiout, "insn begin", begin);
472 ui_out_text (uiout, ",");
473 ui_out_field_uint (uiout, "insn end", end);
474 }
475
476 /* Print the source line information for a function call history line. */
477
478 static void
479 btrace_call_history_src_line (struct ui_out *uiout,
480 const struct btrace_function *bfun)
481 {
482 struct symbol *sym;
483 int begin, end;
484
485 sym = bfun->sym;
486 if (sym == NULL)
487 return;
488
489 ui_out_field_string (uiout, "file",
490 symtab_to_filename_for_display (sym->symtab));
491
492 begin = bfun->lbegin;
493 end = bfun->lend;
494
495 if (end < begin)
496 return;
497
498 ui_out_text (uiout, ":");
499 ui_out_field_int (uiout, "min line", begin);
500
501 if (end == begin)
502 return;
503
504 ui_out_text (uiout, ",");
505 ui_out_field_int (uiout, "max line", end);
506 }
507
508 /* Disassemble a section of the recorded function trace. */
509
510 static void
511 btrace_call_history (struct ui_out *uiout,
512 const struct btrace_thread_info *btinfo,
513 const struct btrace_call_iterator *begin,
514 const struct btrace_call_iterator *end,
515 enum record_print_flag flags)
516 {
517 struct btrace_call_iterator it;
518
519 DEBUG ("ftrace (0x%x): [%u; %u)", flags, btrace_call_number (begin),
520 btrace_call_number (end));
521
522 for (it = *begin; btrace_call_cmp (&it, end) < 0; btrace_call_next (&it, 1))
523 {
524 const struct btrace_function *bfun;
525 struct minimal_symbol *msym;
526 struct symbol *sym;
527
528 bfun = btrace_call_get (&it);
529 msym = bfun->msym;
530 sym = bfun->sym;
531
532 /* Print the function index. */
533 ui_out_field_uint (uiout, "index", bfun->number);
534 ui_out_text (uiout, "\t");
535
536 if ((flags & RECORD_PRINT_INDENT_CALLS) != 0)
537 {
538 int level = bfun->level + btinfo->level, i;
539
540 for (i = 0; i < level; ++i)
541 ui_out_text (uiout, " ");
542 }
543
544 if (sym != NULL)
545 ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (sym));
546 else if (msym != NULL)
547 ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (msym));
548 else if (!ui_out_is_mi_like_p (uiout))
549 ui_out_field_string (uiout, "function", "??");
550
551 if ((flags & RECORD_PRINT_INSN_RANGE) != 0)
552 {
553 ui_out_text (uiout, _("\tinst "));
554 btrace_call_history_insn_range (uiout, bfun);
555 }
556
557 if ((flags & RECORD_PRINT_SRC_LINE) != 0)
558 {
559 ui_out_text (uiout, _("\tat "));
560 btrace_call_history_src_line (uiout, bfun);
561 }
562
563 ui_out_text (uiout, "\n");
564 }
565 }
566
567 /* The to_call_history method of target record-btrace. */
568
569 static void
570 record_btrace_call_history (int size, int flags)
571 {
572 struct btrace_thread_info *btinfo;
573 struct btrace_call_history *history;
574 struct btrace_call_iterator begin, end;
575 struct cleanup *uiout_cleanup;
576 struct ui_out *uiout;
577 unsigned int context, covered;
578
579 uiout = current_uiout;
580 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
581 "insn history");
582 context = abs (size);
583 if (context == 0)
584 error (_("Bad record function-call-history-size."));
585
586 btinfo = require_btrace ();
587 history = btinfo->call_history;
588 if (history == NULL)
589 {
590 struct btrace_insn_iterator *replay;
591
592 DEBUG ("call-history (0x%x): %d", flags, size);
593
594 /* If we're replaying, we start at the replay position. Otherwise, we
595 start at the tail of the trace. */
596 replay = btinfo->replay;
597 if (replay != NULL)
598 {
599 begin.function = replay->function;
600 begin.btinfo = btinfo;
601 }
602 else
603 btrace_call_end (&begin, btinfo);
604
605 /* We start from here and expand in the requested direction. Then we
606 expand in the other direction, as well, to fill up any remaining
607 context. */
608 end = begin;
609 if (size < 0)
610 {
611 /* We want the current position covered, as well. */
612 covered = btrace_call_next (&end, 1);
613 covered += btrace_call_prev (&begin, context - covered);
614 covered += btrace_call_next (&end, context - covered);
615 }
616 else
617 {
618 covered = btrace_call_next (&end, context);
619 covered += btrace_call_prev (&begin, context- covered);
620 }
621 }
622 else
623 {
624 begin = history->begin;
625 end = history->end;
626
627 DEBUG ("call-history (0x%x): %d, prev: [%u; %u)", flags, size,
628 btrace_call_number (&begin), btrace_call_number (&end));
629
630 if (size < 0)
631 {
632 end = begin;
633 covered = btrace_call_prev (&begin, context);
634 }
635 else
636 {
637 begin = end;
638 covered = btrace_call_next (&end, context);
639 }
640 }
641
642 if (covered > 0)
643 btrace_call_history (uiout, btinfo, &begin, &end, flags);
644 else
645 {
646 if (size < 0)
647 printf_unfiltered (_("At the start of the branch trace record.\n"));
648 else
649 printf_unfiltered (_("At the end of the branch trace record.\n"));
650 }
651
652 btrace_set_call_history (btinfo, &begin, &end);
653 do_cleanups (uiout_cleanup);
654 }
655
656 /* The to_call_history_range method of target record-btrace. */
657
658 static void
659 record_btrace_call_history_range (ULONGEST from, ULONGEST to, int flags)
660 {
661 struct btrace_thread_info *btinfo;
662 struct btrace_call_history *history;
663 struct btrace_call_iterator begin, end;
664 struct cleanup *uiout_cleanup;
665 struct ui_out *uiout;
666 unsigned int low, high;
667 int found;
668
669 uiout = current_uiout;
670 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
671 "func history");
672 low = from;
673 high = to;
674
675 DEBUG ("call-history (0x%x): [%u; %u)", flags, low, high);
676
677 /* Check for wrap-arounds. */
678 if (low != from || high != to)
679 error (_("Bad range."));
680
681 if (high < low)
682 error (_("Bad range."));
683
684 btinfo = require_btrace ();
685
686 found = btrace_find_call_by_number (&begin, btinfo, low);
687 if (found == 0)
688 error (_("Range out of bounds."));
689
690 found = btrace_find_call_by_number (&end, btinfo, high);
691 if (found == 0)
692 {
693 /* Silently truncate the range. */
694 btrace_call_end (&end, btinfo);
695 }
696 else
697 {
698 /* We want both begin and end to be inclusive. */
699 btrace_call_next (&end, 1);
700 }
701
702 btrace_call_history (uiout, btinfo, &begin, &end, flags);
703 btrace_set_call_history (btinfo, &begin, &end);
704
705 do_cleanups (uiout_cleanup);
706 }
707
708 /* The to_call_history_from method of target record-btrace. */
709
710 static void
711 record_btrace_call_history_from (ULONGEST from, int size, int flags)
712 {
713 ULONGEST begin, end, context;
714
715 context = abs (size);
716 if (context == 0)
717 error (_("Bad record function-call-history-size."));
718
719 if (size < 0)
720 {
721 end = from;
722
723 if (from < context)
724 begin = 0;
725 else
726 begin = from - context + 1;
727 }
728 else
729 {
730 begin = from;
731 end = from + context - 1;
732
733 /* Check for wrap-around. */
734 if (end < begin)
735 end = ULONGEST_MAX;
736 }
737
738 record_btrace_call_history_range (begin, end, flags);
739 }
740
741 /* The to_record_is_replaying method of target record-btrace. */
742
743 static int
744 record_btrace_is_replaying (void)
745 {
746 struct thread_info *tp;
747
748 ALL_THREADS (tp)
749 if (btrace_is_replaying (tp))
750 return 1;
751
752 return 0;
753 }
754
755 /* The to_fetch_registers method of target record-btrace. */
756
757 static void
758 record_btrace_fetch_registers (struct target_ops *ops,
759 struct regcache *regcache, int regno)
760 {
761 struct btrace_insn_iterator *replay;
762 struct thread_info *tp;
763
764 tp = find_thread_ptid (inferior_ptid);
765 gdb_assert (tp != NULL);
766
767 replay = tp->btrace.replay;
768 if (replay != NULL)
769 {
770 const struct btrace_insn *insn;
771 struct gdbarch *gdbarch;
772 int pcreg;
773
774 gdbarch = get_regcache_arch (regcache);
775 pcreg = gdbarch_pc_regnum (gdbarch);
776 if (pcreg < 0)
777 return;
778
779 /* We can only provide the PC register. */
780 if (regno >= 0 && regno != pcreg)
781 return;
782
783 insn = btrace_insn_get (replay);
784 gdb_assert (insn != NULL);
785
786 regcache_raw_supply (regcache, regno, &insn->pc);
787 }
788 else
789 {
790 struct target_ops *t;
791
792 for (t = ops->beneath; t != NULL; t = t->beneath)
793 if (t->to_fetch_registers != NULL)
794 {
795 t->to_fetch_registers (t, regcache, regno);
796 break;
797 }
798 }
799 }
800
801 /* The to_store_registers method of target record-btrace. */
802
803 static void
804 record_btrace_store_registers (struct target_ops *ops,
805 struct regcache *regcache, int regno)
806 {
807 struct target_ops *t;
808
809 if (record_btrace_is_replaying ())
810 error (_("This record target does not allow writing registers."));
811
812 gdb_assert (may_write_registers != 0);
813
814 for (t = ops->beneath; t != NULL; t = t->beneath)
815 if (t->to_store_registers != NULL)
816 {
817 t->to_store_registers (t, regcache, regno);
818 return;
819 }
820
821 noprocess ();
822 }
823
824 /* The to_prepare_to_store method of target record-btrace. */
825
826 static void
827 record_btrace_prepare_to_store (struct target_ops *ops,
828 struct regcache *regcache)
829 {
830 struct target_ops *t;
831
832 if (record_btrace_is_replaying ())
833 return;
834
835 for (t = ops->beneath; t != NULL; t = t->beneath)
836 if (t->to_prepare_to_store != NULL)
837 {
838 t->to_prepare_to_store (t, regcache);
839 return;
840 }
841 }
842
843 /* Implement stop_reason method for record_btrace_frame_unwind. */
844
845 static enum unwind_stop_reason
846 record_btrace_frame_unwind_stop_reason (struct frame_info *this_frame,
847 void **this_cache)
848 {
849 return UNWIND_UNAVAILABLE;
850 }
851
852 /* Implement this_id method for record_btrace_frame_unwind. */
853
854 static void
855 record_btrace_frame_this_id (struct frame_info *this_frame, void **this_cache,
856 struct frame_id *this_id)
857 {
858 /* Leave there the outer_frame_id value. */
859 }
860
861 /* Implement prev_register method for record_btrace_frame_unwind. */
862
863 static struct value *
864 record_btrace_frame_prev_register (struct frame_info *this_frame,
865 void **this_cache,
866 int regnum)
867 {
868 throw_error (NOT_AVAILABLE_ERROR,
869 _("Registers are not available in btrace record history"));
870 }
871
872 /* Implement sniffer method for record_btrace_frame_unwind. */
873
874 static int
875 record_btrace_frame_sniffer (const struct frame_unwind *self,
876 struct frame_info *this_frame,
877 void **this_cache)
878 {
879 struct thread_info *tp;
880 struct btrace_thread_info *btinfo;
881 struct btrace_insn_iterator *replay;
882
883 /* THIS_FRAME does not contain a reference to its thread. */
884 tp = find_thread_ptid (inferior_ptid);
885 gdb_assert (tp != NULL);
886
887 return btrace_is_replaying (tp);
888 }
889
890 /* btrace recording does not store previous memory content, neither the stack
891 frames content. Any unwinding would return errorneous results as the stack
892 contents no longer matches the changed PC value restored from history.
893 Therefore this unwinder reports any possibly unwound registers as
894 <unavailable>. */
895
896 static const struct frame_unwind record_btrace_frame_unwind =
897 {
898 NORMAL_FRAME,
899 record_btrace_frame_unwind_stop_reason,
900 record_btrace_frame_this_id,
901 record_btrace_frame_prev_register,
902 NULL,
903 record_btrace_frame_sniffer
904 };
905 /* Initialize the record-btrace target ops. */
906
907 static void
908 init_record_btrace_ops (void)
909 {
910 struct target_ops *ops;
911
912 ops = &record_btrace_ops;
913 ops->to_shortname = "record-btrace";
914 ops->to_longname = "Branch tracing target";
915 ops->to_doc = "Collect control-flow trace and provide the execution history.";
916 ops->to_open = record_btrace_open;
917 ops->to_close = record_btrace_close;
918 ops->to_detach = record_detach;
919 ops->to_disconnect = record_disconnect;
920 ops->to_mourn_inferior = record_mourn_inferior;
921 ops->to_kill = record_kill;
922 ops->to_create_inferior = find_default_create_inferior;
923 ops->to_stop_recording = record_btrace_stop_recording;
924 ops->to_info_record = record_btrace_info;
925 ops->to_insn_history = record_btrace_insn_history;
926 ops->to_insn_history_from = record_btrace_insn_history_from;
927 ops->to_insn_history_range = record_btrace_insn_history_range;
928 ops->to_call_history = record_btrace_call_history;
929 ops->to_call_history_from = record_btrace_call_history_from;
930 ops->to_call_history_range = record_btrace_call_history_range;
931 ops->to_record_is_replaying = record_btrace_is_replaying;
932 ops->to_fetch_registers = record_btrace_fetch_registers;
933 ops->to_store_registers = record_btrace_store_registers;
934 ops->to_prepare_to_store = record_btrace_prepare_to_store;
935 ops->to_get_unwinder = &record_btrace_frame_unwind;
936 ops->to_stratum = record_stratum;
937 ops->to_magic = OPS_MAGIC;
938 }
939
940 /* Alias for "target record". */
941
942 static void
943 cmd_record_btrace_start (char *args, int from_tty)
944 {
945 if (args != NULL && *args != 0)
946 error (_("Invalid argument."));
947
948 execute_command ("target record-btrace", from_tty);
949 }
950
951 void _initialize_record_btrace (void);
952
953 /* Initialize btrace commands. */
954
955 void
956 _initialize_record_btrace (void)
957 {
958 add_cmd ("btrace", class_obscure, cmd_record_btrace_start,
959 _("Start branch trace recording."),
960 &record_cmdlist);
961 add_alias_cmd ("b", "btrace", class_obscure, 1, &record_cmdlist);
962
963 init_record_btrace_ops ();
964 add_target (&record_btrace_ops);
965 }