]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/record-btrace.c
record-btrace: add record goto target methods
[thirdparty/binutils-gdb.git] / gdb / record-btrace.c
CommitLineData
afedecd3
MM
1/* Branch trace support for GDB, the GNU debugger.
2
ecd75fc8 3 Copyright (C) 2013-2014 Free Software Foundation, Inc.
afedecd3
MM
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"
1f3ef581 35#include "regcache.h"
cecac1ab 36#include "frame-unwind.h"
afedecd3
MM
37
38/* The target_ops of record-btrace. */
39static struct target_ops record_btrace_ops;
40
41/* A new thread observer enabling branch tracing for the new thread. */
42static struct observer *record_btrace_thread_observer;
43
633785ff
MM
44/* Temporarily allow memory accesses. */
45static int record_btrace_allow_memory_access;
46
afedecd3
MM
47/* Print a record-btrace debug message. Use do ... while (0) to avoid
48 ambiguities when used in if statements. */
49
50#define DEBUG(msg, args...) \
51 do \
52 { \
53 if (record_debug != 0) \
54 fprintf_unfiltered (gdb_stdlog, \
55 "[record-btrace] " msg "\n", ##args); \
56 } \
57 while (0)
58
59
60/* Update the branch trace for the current thread and return a pointer to its
066ce621 61 thread_info.
afedecd3
MM
62
63 Throws an error if there is no thread or no trace. This function never
64 returns NULL. */
65
066ce621
MM
66static struct thread_info *
67require_btrace_thread (void)
afedecd3
MM
68{
69 struct thread_info *tp;
70 struct btrace_thread_info *btinfo;
71
72 DEBUG ("require");
73
74 tp = find_thread_ptid (inferior_ptid);
75 if (tp == NULL)
76 error (_("No thread."));
77
78 btrace_fetch (tp);
79
80 btinfo = &tp->btrace;
81
23a7fe75 82 if (btinfo->begin == NULL)
afedecd3
MM
83 error (_("No trace."));
84
066ce621
MM
85 return tp;
86}
87
88/* Update the branch trace for the current thread and return a pointer to its
89 branch trace information struct.
90
91 Throws an error if there is no thread or no trace. This function never
92 returns NULL. */
93
94static struct btrace_thread_info *
95require_btrace (void)
96{
97 struct thread_info *tp;
98
99 tp = require_btrace_thread ();
100
101 return &tp->btrace;
afedecd3
MM
102}
103
104/* Enable branch tracing for one thread. Warn on errors. */
105
106static void
107record_btrace_enable_warn (struct thread_info *tp)
108{
109 volatile struct gdb_exception error;
110
111 TRY_CATCH (error, RETURN_MASK_ERROR)
112 btrace_enable (tp);
113
114 if (error.message != NULL)
115 warning ("%s", error.message);
116}
117
118/* Callback function to disable branch tracing for one thread. */
119
120static void
121record_btrace_disable_callback (void *arg)
122{
123 struct thread_info *tp;
124
125 tp = arg;
126
127 btrace_disable (tp);
128}
129
130/* Enable automatic tracing of new threads. */
131
132static void
133record_btrace_auto_enable (void)
134{
135 DEBUG ("attach thread observer");
136
137 record_btrace_thread_observer
138 = observer_attach_new_thread (record_btrace_enable_warn);
139}
140
141/* Disable automatic tracing of new threads. */
142
143static void
144record_btrace_auto_disable (void)
145{
146 /* The observer may have been detached, already. */
147 if (record_btrace_thread_observer == NULL)
148 return;
149
150 DEBUG ("detach thread observer");
151
152 observer_detach_new_thread (record_btrace_thread_observer);
153 record_btrace_thread_observer = NULL;
154}
155
156/* The to_open method of target record-btrace. */
157
158static void
159record_btrace_open (char *args, int from_tty)
160{
161 struct cleanup *disable_chain;
162 struct thread_info *tp;
163
164 DEBUG ("open");
165
8213266a 166 record_preopen ();
afedecd3
MM
167
168 if (!target_has_execution)
169 error (_("The program is not being run."));
170
171 if (!target_supports_btrace ())
172 error (_("Target does not support branch tracing."));
173
174 gdb_assert (record_btrace_thread_observer == NULL);
175
176 disable_chain = make_cleanup (null_cleanup, NULL);
177 ALL_THREADS (tp)
178 if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
179 {
180 btrace_enable (tp);
181
182 make_cleanup (record_btrace_disable_callback, tp);
183 }
184
185 record_btrace_auto_enable ();
186
187 push_target (&record_btrace_ops);
188
189 observer_notify_record_changed (current_inferior (), 1);
190
191 discard_cleanups (disable_chain);
192}
193
194/* The to_stop_recording method of target record-btrace. */
195
196static void
197record_btrace_stop_recording (void)
198{
199 struct thread_info *tp;
200
201 DEBUG ("stop recording");
202
203 record_btrace_auto_disable ();
204
205 ALL_THREADS (tp)
206 if (tp->btrace.target != NULL)
207 btrace_disable (tp);
208}
209
210/* The to_close method of target record-btrace. */
211
212static void
460014f5 213record_btrace_close (void)
afedecd3 214{
99c819ee
MM
215 /* Make sure automatic recording gets disabled even if we did not stop
216 recording before closing the record-btrace target. */
217 record_btrace_auto_disable ();
218
afedecd3
MM
219 /* We already stopped recording. */
220}
221
222/* The to_info_record method of target record-btrace. */
223
224static void
225record_btrace_info (void)
226{
227 struct btrace_thread_info *btinfo;
228 struct thread_info *tp;
23a7fe75 229 unsigned int insns, calls;
afedecd3
MM
230
231 DEBUG ("info");
232
233 tp = find_thread_ptid (inferior_ptid);
234 if (tp == NULL)
235 error (_("No thread."));
236
237 btrace_fetch (tp);
238
23a7fe75
MM
239 insns = 0;
240 calls = 0;
241
afedecd3 242 btinfo = &tp->btrace;
23a7fe75
MM
243 if (btinfo->begin != NULL)
244 {
245 struct btrace_call_iterator call;
246 struct btrace_insn_iterator insn;
247
248 btrace_call_end (&call, btinfo);
249 btrace_call_prev (&call, 1);
5de9129b 250 calls = btrace_call_number (&call);
23a7fe75
MM
251
252 btrace_insn_end (&insn, btinfo);
253 btrace_insn_prev (&insn, 1);
5de9129b 254 insns = btrace_insn_number (&insn);
23a7fe75 255 }
afedecd3
MM
256
257 printf_unfiltered (_("Recorded %u instructions in %u functions for thread "
23a7fe75 258 "%d (%s).\n"), insns, calls, tp->num,
afedecd3 259 target_pid_to_str (tp->ptid));
07bbe694
MM
260
261 if (btrace_is_replaying (tp))
262 printf_unfiltered (_("Replay in progress. At instruction %u.\n"),
263 btrace_insn_number (btinfo->replay));
afedecd3
MM
264}
265
266/* Print an unsigned int. */
267
268static void
269ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
270{
271 ui_out_field_fmt (uiout, fld, "%u", val);
272}
273
274/* Disassemble a section of the recorded instruction trace. */
275
276static void
23a7fe75
MM
277btrace_insn_history (struct ui_out *uiout,
278 const struct btrace_insn_iterator *begin,
279 const struct btrace_insn_iterator *end, int flags)
afedecd3
MM
280{
281 struct gdbarch *gdbarch;
23a7fe75 282 struct btrace_insn_iterator it;
afedecd3 283
23a7fe75
MM
284 DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
285 btrace_insn_number (end));
afedecd3
MM
286
287 gdbarch = target_gdbarch ();
288
23a7fe75 289 for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
afedecd3 290 {
23a7fe75
MM
291 const struct btrace_insn *insn;
292
293 insn = btrace_insn_get (&it);
294
afedecd3 295 /* Print the instruction index. */
23a7fe75 296 ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
afedecd3
MM
297 ui_out_text (uiout, "\t");
298
299 /* Disassembly with '/m' flag may not produce the expected result.
300 See PR gdb/11833. */
23a7fe75 301 gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->pc + 1);
afedecd3
MM
302 }
303}
304
305/* The to_insn_history method of target record-btrace. */
306
307static void
308record_btrace_insn_history (int size, int flags)
309{
310 struct btrace_thread_info *btinfo;
23a7fe75
MM
311 struct btrace_insn_history *history;
312 struct btrace_insn_iterator begin, end;
afedecd3
MM
313 struct cleanup *uiout_cleanup;
314 struct ui_out *uiout;
23a7fe75 315 unsigned int context, covered;
afedecd3
MM
316
317 uiout = current_uiout;
318 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
319 "insn history");
afedecd3 320 context = abs (size);
afedecd3
MM
321 if (context == 0)
322 error (_("Bad record instruction-history-size."));
323
23a7fe75
MM
324 btinfo = require_btrace ();
325 history = btinfo->insn_history;
326 if (history == NULL)
afedecd3 327 {
07bbe694 328 struct btrace_insn_iterator *replay;
afedecd3 329
23a7fe75 330 DEBUG ("insn-history (0x%x): %d", flags, size);
afedecd3 331
07bbe694
MM
332 /* If we're replaying, we start at the replay position. Otherwise, we
333 start at the tail of the trace. */
334 replay = btinfo->replay;
335 if (replay != NULL)
336 begin = *replay;
337 else
338 btrace_insn_end (&begin, btinfo);
339
340 /* We start from here and expand in the requested direction. Then we
341 expand in the other direction, as well, to fill up any remaining
342 context. */
343 end = begin;
344 if (size < 0)
345 {
346 /* We want the current position covered, as well. */
347 covered = btrace_insn_next (&end, 1);
348 covered += btrace_insn_prev (&begin, context - covered);
349 covered += btrace_insn_next (&end, context - covered);
350 }
351 else
352 {
353 covered = btrace_insn_next (&end, context);
354 covered += btrace_insn_prev (&begin, context - covered);
355 }
afedecd3
MM
356 }
357 else
358 {
23a7fe75
MM
359 begin = history->begin;
360 end = history->end;
afedecd3 361
23a7fe75
MM
362 DEBUG ("insn-history (0x%x): %d, prev: [%u; %u)", flags, size,
363 btrace_insn_number (&begin), btrace_insn_number (&end));
afedecd3 364
23a7fe75
MM
365 if (size < 0)
366 {
367 end = begin;
368 covered = btrace_insn_prev (&begin, context);
369 }
370 else
371 {
372 begin = end;
373 covered = btrace_insn_next (&end, context);
374 }
afedecd3
MM
375 }
376
23a7fe75
MM
377 if (covered > 0)
378 btrace_insn_history (uiout, &begin, &end, flags);
379 else
380 {
381 if (size < 0)
382 printf_unfiltered (_("At the start of the branch trace record.\n"));
383 else
384 printf_unfiltered (_("At the end of the branch trace record.\n"));
385 }
afedecd3 386
23a7fe75 387 btrace_set_insn_history (btinfo, &begin, &end);
afedecd3
MM
388 do_cleanups (uiout_cleanup);
389}
390
391/* The to_insn_history_range method of target record-btrace. */
392
393static void
394record_btrace_insn_history_range (ULONGEST from, ULONGEST to, int flags)
395{
396 struct btrace_thread_info *btinfo;
23a7fe75
MM
397 struct btrace_insn_history *history;
398 struct btrace_insn_iterator begin, end;
afedecd3
MM
399 struct cleanup *uiout_cleanup;
400 struct ui_out *uiout;
23a7fe75
MM
401 unsigned int low, high;
402 int found;
afedecd3
MM
403
404 uiout = current_uiout;
405 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
406 "insn history");
23a7fe75
MM
407 low = from;
408 high = to;
afedecd3 409
23a7fe75 410 DEBUG ("insn-history (0x%x): [%u; %u)", flags, low, high);
afedecd3
MM
411
412 /* Check for wrap-arounds. */
23a7fe75 413 if (low != from || high != to)
afedecd3
MM
414 error (_("Bad range."));
415
0688d04e 416 if (high < low)
afedecd3
MM
417 error (_("Bad range."));
418
23a7fe75 419 btinfo = require_btrace ();
afedecd3 420
23a7fe75
MM
421 found = btrace_find_insn_by_number (&begin, btinfo, low);
422 if (found == 0)
423 error (_("Range out of bounds."));
afedecd3 424
23a7fe75
MM
425 found = btrace_find_insn_by_number (&end, btinfo, high);
426 if (found == 0)
0688d04e
MM
427 {
428 /* Silently truncate the range. */
429 btrace_insn_end (&end, btinfo);
430 }
431 else
432 {
433 /* We want both begin and end to be inclusive. */
434 btrace_insn_next (&end, 1);
435 }
afedecd3 436
23a7fe75
MM
437 btrace_insn_history (uiout, &begin, &end, flags);
438 btrace_set_insn_history (btinfo, &begin, &end);
afedecd3
MM
439
440 do_cleanups (uiout_cleanup);
441}
442
443/* The to_insn_history_from method of target record-btrace. */
444
445static void
446record_btrace_insn_history_from (ULONGEST from, int size, int flags)
447{
448 ULONGEST begin, end, context;
449
450 context = abs (size);
0688d04e
MM
451 if (context == 0)
452 error (_("Bad record instruction-history-size."));
afedecd3
MM
453
454 if (size < 0)
455 {
456 end = from;
457
458 if (from < context)
459 begin = 0;
460 else
0688d04e 461 begin = from - context + 1;
afedecd3
MM
462 }
463 else
464 {
465 begin = from;
0688d04e 466 end = from + context - 1;
afedecd3
MM
467
468 /* Check for wrap-around. */
469 if (end < begin)
470 end = ULONGEST_MAX;
471 }
472
473 record_btrace_insn_history_range (begin, end, flags);
474}
475
476/* Print the instruction number range for a function call history line. */
477
478static void
23a7fe75
MM
479btrace_call_history_insn_range (struct ui_out *uiout,
480 const struct btrace_function *bfun)
afedecd3 481{
7acbe133
MM
482 unsigned int begin, end, size;
483
484 size = VEC_length (btrace_insn_s, bfun->insn);
485 gdb_assert (size > 0);
afedecd3 486
23a7fe75 487 begin = bfun->insn_offset;
7acbe133 488 end = begin + size - 1;
afedecd3 489
23a7fe75 490 ui_out_field_uint (uiout, "insn begin", begin);
8710b709 491 ui_out_text (uiout, ",");
23a7fe75 492 ui_out_field_uint (uiout, "insn end", end);
afedecd3
MM
493}
494
495/* Print the source line information for a function call history line. */
496
497static void
23a7fe75
MM
498btrace_call_history_src_line (struct ui_out *uiout,
499 const struct btrace_function *bfun)
afedecd3
MM
500{
501 struct symbol *sym;
23a7fe75 502 int begin, end;
afedecd3
MM
503
504 sym = bfun->sym;
505 if (sym == NULL)
506 return;
507
508 ui_out_field_string (uiout, "file",
509 symtab_to_filename_for_display (sym->symtab));
510
23a7fe75
MM
511 begin = bfun->lbegin;
512 end = bfun->lend;
513
514 if (end < begin)
afedecd3
MM
515 return;
516
517 ui_out_text (uiout, ":");
23a7fe75 518 ui_out_field_int (uiout, "min line", begin);
afedecd3 519
23a7fe75 520 if (end == begin)
afedecd3
MM
521 return;
522
8710b709 523 ui_out_text (uiout, ",");
23a7fe75 524 ui_out_field_int (uiout, "max line", end);
afedecd3
MM
525}
526
527/* Disassemble a section of the recorded function trace. */
528
529static void
23a7fe75 530btrace_call_history (struct ui_out *uiout,
8710b709 531 const struct btrace_thread_info *btinfo,
23a7fe75
MM
532 const struct btrace_call_iterator *begin,
533 const struct btrace_call_iterator *end,
afedecd3
MM
534 enum record_print_flag flags)
535{
23a7fe75 536 struct btrace_call_iterator it;
afedecd3 537
23a7fe75
MM
538 DEBUG ("ftrace (0x%x): [%u; %u)", flags, btrace_call_number (begin),
539 btrace_call_number (end));
afedecd3 540
23a7fe75 541 for (it = *begin; btrace_call_cmp (&it, end) < 0; btrace_call_next (&it, 1))
afedecd3 542 {
23a7fe75
MM
543 const struct btrace_function *bfun;
544 struct minimal_symbol *msym;
545 struct symbol *sym;
546
547 bfun = btrace_call_get (&it);
548 msym = bfun->msym;
549 sym = bfun->sym;
550
afedecd3 551 /* Print the function index. */
23a7fe75 552 ui_out_field_uint (uiout, "index", bfun->number);
afedecd3
MM
553 ui_out_text (uiout, "\t");
554
8710b709
MM
555 if ((flags & RECORD_PRINT_INDENT_CALLS) != 0)
556 {
557 int level = bfun->level + btinfo->level, i;
558
559 for (i = 0; i < level; ++i)
560 ui_out_text (uiout, " ");
561 }
562
563 if (sym != NULL)
564 ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (sym));
565 else if (msym != NULL)
566 ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (msym));
567 else if (!ui_out_is_mi_like_p (uiout))
568 ui_out_field_string (uiout, "function", "??");
569
1e038f67 570 if ((flags & RECORD_PRINT_INSN_RANGE) != 0)
afedecd3 571 {
8710b709 572 ui_out_text (uiout, _("\tinst "));
23a7fe75 573 btrace_call_history_insn_range (uiout, bfun);
afedecd3
MM
574 }
575
1e038f67 576 if ((flags & RECORD_PRINT_SRC_LINE) != 0)
afedecd3 577 {
8710b709 578 ui_out_text (uiout, _("\tat "));
23a7fe75 579 btrace_call_history_src_line (uiout, bfun);
afedecd3
MM
580 }
581
afedecd3
MM
582 ui_out_text (uiout, "\n");
583 }
584}
585
586/* The to_call_history method of target record-btrace. */
587
588static void
589record_btrace_call_history (int size, int flags)
590{
591 struct btrace_thread_info *btinfo;
23a7fe75
MM
592 struct btrace_call_history *history;
593 struct btrace_call_iterator begin, end;
afedecd3
MM
594 struct cleanup *uiout_cleanup;
595 struct ui_out *uiout;
23a7fe75 596 unsigned int context, covered;
afedecd3
MM
597
598 uiout = current_uiout;
599 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
600 "insn history");
afedecd3 601 context = abs (size);
afedecd3
MM
602 if (context == 0)
603 error (_("Bad record function-call-history-size."));
604
23a7fe75
MM
605 btinfo = require_btrace ();
606 history = btinfo->call_history;
607 if (history == NULL)
afedecd3 608 {
07bbe694 609 struct btrace_insn_iterator *replay;
afedecd3 610
23a7fe75 611 DEBUG ("call-history (0x%x): %d", flags, size);
afedecd3 612
07bbe694
MM
613 /* If we're replaying, we start at the replay position. Otherwise, we
614 start at the tail of the trace. */
615 replay = btinfo->replay;
616 if (replay != NULL)
617 {
618 begin.function = replay->function;
619 begin.btinfo = btinfo;
620 }
621 else
622 btrace_call_end (&begin, btinfo);
623
624 /* We start from here and expand in the requested direction. Then we
625 expand in the other direction, as well, to fill up any remaining
626 context. */
627 end = begin;
628 if (size < 0)
629 {
630 /* We want the current position covered, as well. */
631 covered = btrace_call_next (&end, 1);
632 covered += btrace_call_prev (&begin, context - covered);
633 covered += btrace_call_next (&end, context - covered);
634 }
635 else
636 {
637 covered = btrace_call_next (&end, context);
638 covered += btrace_call_prev (&begin, context- covered);
639 }
afedecd3
MM
640 }
641 else
642 {
23a7fe75
MM
643 begin = history->begin;
644 end = history->end;
afedecd3 645
23a7fe75
MM
646 DEBUG ("call-history (0x%x): %d, prev: [%u; %u)", flags, size,
647 btrace_call_number (&begin), btrace_call_number (&end));
afedecd3 648
23a7fe75
MM
649 if (size < 0)
650 {
651 end = begin;
652 covered = btrace_call_prev (&begin, context);
653 }
654 else
655 {
656 begin = end;
657 covered = btrace_call_next (&end, context);
658 }
afedecd3
MM
659 }
660
23a7fe75 661 if (covered > 0)
8710b709 662 btrace_call_history (uiout, btinfo, &begin, &end, flags);
23a7fe75
MM
663 else
664 {
665 if (size < 0)
666 printf_unfiltered (_("At the start of the branch trace record.\n"));
667 else
668 printf_unfiltered (_("At the end of the branch trace record.\n"));
669 }
afedecd3 670
23a7fe75 671 btrace_set_call_history (btinfo, &begin, &end);
afedecd3
MM
672 do_cleanups (uiout_cleanup);
673}
674
675/* The to_call_history_range method of target record-btrace. */
676
677static void
678record_btrace_call_history_range (ULONGEST from, ULONGEST to, int flags)
679{
680 struct btrace_thread_info *btinfo;
23a7fe75
MM
681 struct btrace_call_history *history;
682 struct btrace_call_iterator begin, end;
afedecd3
MM
683 struct cleanup *uiout_cleanup;
684 struct ui_out *uiout;
23a7fe75
MM
685 unsigned int low, high;
686 int found;
afedecd3
MM
687
688 uiout = current_uiout;
689 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
690 "func history");
23a7fe75
MM
691 low = from;
692 high = to;
afedecd3 693
23a7fe75 694 DEBUG ("call-history (0x%x): [%u; %u)", flags, low, high);
afedecd3
MM
695
696 /* Check for wrap-arounds. */
23a7fe75 697 if (low != from || high != to)
afedecd3
MM
698 error (_("Bad range."));
699
0688d04e 700 if (high < low)
afedecd3
MM
701 error (_("Bad range."));
702
23a7fe75 703 btinfo = require_btrace ();
afedecd3 704
23a7fe75
MM
705 found = btrace_find_call_by_number (&begin, btinfo, low);
706 if (found == 0)
707 error (_("Range out of bounds."));
afedecd3 708
23a7fe75
MM
709 found = btrace_find_call_by_number (&end, btinfo, high);
710 if (found == 0)
0688d04e
MM
711 {
712 /* Silently truncate the range. */
713 btrace_call_end (&end, btinfo);
714 }
715 else
716 {
717 /* We want both begin and end to be inclusive. */
718 btrace_call_next (&end, 1);
719 }
afedecd3 720
8710b709 721 btrace_call_history (uiout, btinfo, &begin, &end, flags);
23a7fe75 722 btrace_set_call_history (btinfo, &begin, &end);
afedecd3
MM
723
724 do_cleanups (uiout_cleanup);
725}
726
727/* The to_call_history_from method of target record-btrace. */
728
729static void
730record_btrace_call_history_from (ULONGEST from, int size, int flags)
731{
732 ULONGEST begin, end, context;
733
734 context = abs (size);
0688d04e
MM
735 if (context == 0)
736 error (_("Bad record function-call-history-size."));
afedecd3
MM
737
738 if (size < 0)
739 {
740 end = from;
741
742 if (from < context)
743 begin = 0;
744 else
0688d04e 745 begin = from - context + 1;
afedecd3
MM
746 }
747 else
748 {
749 begin = from;
0688d04e 750 end = from + context - 1;
afedecd3
MM
751
752 /* Check for wrap-around. */
753 if (end < begin)
754 end = ULONGEST_MAX;
755 }
756
757 record_btrace_call_history_range (begin, end, flags);
758}
759
07bbe694
MM
760/* The to_record_is_replaying method of target record-btrace. */
761
762static int
763record_btrace_is_replaying (void)
764{
765 struct thread_info *tp;
766
767 ALL_THREADS (tp)
768 if (btrace_is_replaying (tp))
769 return 1;
770
771 return 0;
772}
773
633785ff
MM
774/* The to_xfer_partial method of target record-btrace. */
775
776static LONGEST
777record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
778 const char *annex, gdb_byte *readbuf,
779 const gdb_byte *writebuf, ULONGEST offset,
780 ULONGEST len)
781{
782 struct target_ops *t;
783
784 /* Filter out requests that don't make sense during replay. */
785 if (!record_btrace_allow_memory_access && record_btrace_is_replaying ())
786 {
787 switch (object)
788 {
789 case TARGET_OBJECT_MEMORY:
790 {
791 struct target_section *section;
792
793 /* We do not allow writing memory in general. */
794 if (writebuf != NULL)
795 return TARGET_XFER_E_UNAVAILABLE;
796
797 /* We allow reading readonly memory. */
798 section = target_section_by_addr (ops, offset);
799 if (section != NULL)
800 {
801 /* Check if the section we found is readonly. */
802 if ((bfd_get_section_flags (section->the_bfd_section->owner,
803 section->the_bfd_section)
804 & SEC_READONLY) != 0)
805 {
806 /* Truncate the request to fit into this section. */
807 len = min (len, section->endaddr - offset);
808 break;
809 }
810 }
811
812 return TARGET_XFER_E_UNAVAILABLE;
813 }
814 }
815 }
816
817 /* Forward the request. */
818 for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
819 if (ops->to_xfer_partial != NULL)
820 return ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
821 offset, len);
822
823 return TARGET_XFER_E_UNAVAILABLE;
824}
825
826/* The to_insert_breakpoint method of target record-btrace. */
827
828static int
829record_btrace_insert_breakpoint (struct target_ops *ops,
830 struct gdbarch *gdbarch,
831 struct bp_target_info *bp_tgt)
832{
833 volatile struct gdb_exception except;
834 int old, ret;
835
836 /* Inserting breakpoints requires accessing memory. Allow it for the
837 duration of this function. */
838 old = record_btrace_allow_memory_access;
839 record_btrace_allow_memory_access = 1;
840
841 ret = 0;
842 TRY_CATCH (except, RETURN_MASK_ALL)
843 ret = forward_target_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
844
845 record_btrace_allow_memory_access = old;
846
847 if (except.reason < 0)
848 throw_exception (except);
849
850 return ret;
851}
852
853/* The to_remove_breakpoint method of target record-btrace. */
854
855static int
856record_btrace_remove_breakpoint (struct target_ops *ops,
857 struct gdbarch *gdbarch,
858 struct bp_target_info *bp_tgt)
859{
860 volatile struct gdb_exception except;
861 int old, ret;
862
863 /* Removing breakpoints requires accessing memory. Allow it for the
864 duration of this function. */
865 old = record_btrace_allow_memory_access;
866 record_btrace_allow_memory_access = 1;
867
868 ret = 0;
869 TRY_CATCH (except, RETURN_MASK_ALL)
870 ret = forward_target_remove_breakpoint (ops->beneath, gdbarch, bp_tgt);
871
872 record_btrace_allow_memory_access = old;
873
874 if (except.reason < 0)
875 throw_exception (except);
876
877 return ret;
878}
879
1f3ef581
MM
880/* The to_fetch_registers method of target record-btrace. */
881
882static void
883record_btrace_fetch_registers (struct target_ops *ops,
884 struct regcache *regcache, int regno)
885{
886 struct btrace_insn_iterator *replay;
887 struct thread_info *tp;
888
889 tp = find_thread_ptid (inferior_ptid);
890 gdb_assert (tp != NULL);
891
892 replay = tp->btrace.replay;
893 if (replay != NULL)
894 {
895 const struct btrace_insn *insn;
896 struct gdbarch *gdbarch;
897 int pcreg;
898
899 gdbarch = get_regcache_arch (regcache);
900 pcreg = gdbarch_pc_regnum (gdbarch);
901 if (pcreg < 0)
902 return;
903
904 /* We can only provide the PC register. */
905 if (regno >= 0 && regno != pcreg)
906 return;
907
908 insn = btrace_insn_get (replay);
909 gdb_assert (insn != NULL);
910
911 regcache_raw_supply (regcache, regno, &insn->pc);
912 }
913 else
914 {
915 struct target_ops *t;
916
917 for (t = ops->beneath; t != NULL; t = t->beneath)
918 if (t->to_fetch_registers != NULL)
919 {
920 t->to_fetch_registers (t, regcache, regno);
921 break;
922 }
923 }
924}
925
926/* The to_store_registers method of target record-btrace. */
927
928static void
929record_btrace_store_registers (struct target_ops *ops,
930 struct regcache *regcache, int regno)
931{
932 struct target_ops *t;
933
934 if (record_btrace_is_replaying ())
935 error (_("This record target does not allow writing registers."));
936
937 gdb_assert (may_write_registers != 0);
938
939 for (t = ops->beneath; t != NULL; t = t->beneath)
940 if (t->to_store_registers != NULL)
941 {
942 t->to_store_registers (t, regcache, regno);
943 return;
944 }
945
946 noprocess ();
947}
948
949/* The to_prepare_to_store method of target record-btrace. */
950
951static void
952record_btrace_prepare_to_store (struct target_ops *ops,
953 struct regcache *regcache)
954{
955 struct target_ops *t;
956
957 if (record_btrace_is_replaying ())
958 return;
959
960 for (t = ops->beneath; t != NULL; t = t->beneath)
961 if (t->to_prepare_to_store != NULL)
962 {
963 t->to_prepare_to_store (t, regcache);
964 return;
965 }
966}
967
cecac1ab
MM
968/* Implement stop_reason method for record_btrace_frame_unwind. */
969
970static enum unwind_stop_reason
971record_btrace_frame_unwind_stop_reason (struct frame_info *this_frame,
972 void **this_cache)
973{
974 return UNWIND_UNAVAILABLE;
975}
976
977/* Implement this_id method for record_btrace_frame_unwind. */
978
979static void
980record_btrace_frame_this_id (struct frame_info *this_frame, void **this_cache,
981 struct frame_id *this_id)
982{
983 /* Leave there the outer_frame_id value. */
984}
985
986/* Implement prev_register method for record_btrace_frame_unwind. */
987
988static struct value *
989record_btrace_frame_prev_register (struct frame_info *this_frame,
990 void **this_cache,
991 int regnum)
992{
993 throw_error (NOT_AVAILABLE_ERROR,
994 _("Registers are not available in btrace record history"));
995}
996
997/* Implement sniffer method for record_btrace_frame_unwind. */
998
999static int
1000record_btrace_frame_sniffer (const struct frame_unwind *self,
1001 struct frame_info *this_frame,
1002 void **this_cache)
1003{
1004 struct thread_info *tp;
1005 struct btrace_thread_info *btinfo;
1006 struct btrace_insn_iterator *replay;
1007
1008 /* THIS_FRAME does not contain a reference to its thread. */
1009 tp = find_thread_ptid (inferior_ptid);
1010 gdb_assert (tp != NULL);
1011
1012 return btrace_is_replaying (tp);
1013}
1014
1015/* btrace recording does not store previous memory content, neither the stack
1016 frames content. Any unwinding would return errorneous results as the stack
1017 contents no longer matches the changed PC value restored from history.
1018 Therefore this unwinder reports any possibly unwound registers as
1019 <unavailable>. */
1020
1021static const struct frame_unwind record_btrace_frame_unwind =
1022{
1023 NORMAL_FRAME,
1024 record_btrace_frame_unwind_stop_reason,
1025 record_btrace_frame_this_id,
1026 record_btrace_frame_prev_register,
1027 NULL,
1028 record_btrace_frame_sniffer
1029};
b2f4cfde
MM
1030
1031/* The to_resume method of target record-btrace. */
1032
1033static void
1034record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
1035 enum gdb_signal signal)
1036{
1037 /* As long as we're not replaying, just forward the request. */
1038 if (!record_btrace_is_replaying ())
1039 {
1040 for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
1041 if (ops->to_resume != NULL)
1042 return ops->to_resume (ops, ptid, step, signal);
1043
1044 error (_("Cannot find target for stepping."));
1045 }
1046
1047 error (_("You can't do this from here. Do 'record goto end', first."));
1048}
1049
1050/* The to_wait method of target record-btrace. */
1051
1052static ptid_t
1053record_btrace_wait (struct target_ops *ops, ptid_t ptid,
1054 struct target_waitstatus *status, int options)
1055{
1056 /* As long as we're not replaying, just forward the request. */
1057 if (!record_btrace_is_replaying ())
1058 {
1059 for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
1060 if (ops->to_wait != NULL)
1061 return ops->to_wait (ops, ptid, status, options);
1062
1063 error (_("Cannot find target for waiting."));
1064 }
1065
1066 error (_("You can't do this from here. Do 'record goto end', first."));
1067}
1068
e2887aa3
MM
1069/* The to_find_new_threads method of target record-btrace. */
1070
1071static void
1072record_btrace_find_new_threads (struct target_ops *ops)
1073{
1074 /* Don't expect new threads if we're replaying. */
1075 if (record_btrace_is_replaying ())
1076 return;
1077
1078 /* Forward the request. */
1079 for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
1080 if (ops->to_find_new_threads != NULL)
1081 {
1082 ops->to_find_new_threads (ops);
1083 break;
1084 }
1085}
1086
1087/* The to_thread_alive method of target record-btrace. */
1088
1089static int
1090record_btrace_thread_alive (struct target_ops *ops, ptid_t ptid)
1091{
1092 /* We don't add or remove threads during replay. */
1093 if (record_btrace_is_replaying ())
1094 return find_thread_ptid (ptid) != NULL;
1095
1096 /* Forward the request. */
1097 for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
1098 if (ops->to_thread_alive != NULL)
1099 return ops->to_thread_alive (ops, ptid);
1100
1101 return 0;
1102}
1103
066ce621
MM
1104/* Set the replay branch trace instruction iterator. If IT is NULL, replay
1105 is stopped. */
1106
1107static void
1108record_btrace_set_replay (struct thread_info *tp,
1109 const struct btrace_insn_iterator *it)
1110{
1111 struct btrace_thread_info *btinfo;
1112
1113 btinfo = &tp->btrace;
1114
1115 if (it == NULL || it->function == NULL)
1116 {
1117 if (btinfo->replay == NULL)
1118 return;
1119
1120 xfree (btinfo->replay);
1121 btinfo->replay = NULL;
1122 }
1123 else
1124 {
1125 if (btinfo->replay == NULL)
1126 btinfo->replay = xmalloc (sizeof (*btinfo->replay));
1127 else if (btrace_insn_cmp (btinfo->replay, it) == 0)
1128 return;
1129
1130 *btinfo->replay = *it;
1131 }
1132
1133 /* Clear the function call and instruction histories so we start anew
1134 from the new replay position. */
1135 xfree (btinfo->insn_history);
1136 xfree (btinfo->call_history);
1137
1138 btinfo->insn_history = NULL;
1139 btinfo->call_history = NULL;
1140
1141 registers_changed_ptid (tp->ptid);
1142}
1143
1144/* The to_goto_record_begin method of target record-btrace. */
1145
1146static void
1147record_btrace_goto_begin (void)
1148{
1149 struct thread_info *tp;
1150 struct btrace_insn_iterator begin;
1151
1152 tp = require_btrace_thread ();
1153
1154 btrace_insn_begin (&begin, &tp->btrace);
1155 record_btrace_set_replay (tp, &begin);
1156
1157 print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
1158}
1159
1160/* The to_goto_record_end method of target record-btrace. */
1161
1162static void
1163record_btrace_goto_end (void)
1164{
1165 struct thread_info *tp;
1166
1167 tp = require_btrace_thread ();
1168
1169 record_btrace_set_replay (tp, NULL);
1170
1171 print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
1172}
1173
1174/* The to_goto_record method of target record-btrace. */
1175
1176static void
1177record_btrace_goto (ULONGEST insn)
1178{
1179 struct thread_info *tp;
1180 struct btrace_insn_iterator it;
1181 unsigned int number;
1182 int found;
1183
1184 number = insn;
1185
1186 /* Check for wrap-arounds. */
1187 if (number != insn)
1188 error (_("Instruction number out of range."));
1189
1190 tp = require_btrace_thread ();
1191
1192 found = btrace_find_insn_by_number (&it, &tp->btrace, number);
1193 if (found == 0)
1194 error (_("No such instruction."));
1195
1196 record_btrace_set_replay (tp, &it);
1197
1198 print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
1199}
1200
afedecd3
MM
1201/* Initialize the record-btrace target ops. */
1202
1203static void
1204init_record_btrace_ops (void)
1205{
1206 struct target_ops *ops;
1207
1208 ops = &record_btrace_ops;
1209 ops->to_shortname = "record-btrace";
1210 ops->to_longname = "Branch tracing target";
1211 ops->to_doc = "Collect control-flow trace and provide the execution history.";
1212 ops->to_open = record_btrace_open;
1213 ops->to_close = record_btrace_close;
1214 ops->to_detach = record_detach;
1215 ops->to_disconnect = record_disconnect;
1216 ops->to_mourn_inferior = record_mourn_inferior;
1217 ops->to_kill = record_kill;
1218 ops->to_create_inferior = find_default_create_inferior;
1219 ops->to_stop_recording = record_btrace_stop_recording;
1220 ops->to_info_record = record_btrace_info;
1221 ops->to_insn_history = record_btrace_insn_history;
1222 ops->to_insn_history_from = record_btrace_insn_history_from;
1223 ops->to_insn_history_range = record_btrace_insn_history_range;
1224 ops->to_call_history = record_btrace_call_history;
1225 ops->to_call_history_from = record_btrace_call_history_from;
1226 ops->to_call_history_range = record_btrace_call_history_range;
07bbe694 1227 ops->to_record_is_replaying = record_btrace_is_replaying;
633785ff
MM
1228 ops->to_xfer_partial = record_btrace_xfer_partial;
1229 ops->to_remove_breakpoint = record_btrace_remove_breakpoint;
1230 ops->to_insert_breakpoint = record_btrace_insert_breakpoint;
1f3ef581
MM
1231 ops->to_fetch_registers = record_btrace_fetch_registers;
1232 ops->to_store_registers = record_btrace_store_registers;
1233 ops->to_prepare_to_store = record_btrace_prepare_to_store;
cecac1ab 1234 ops->to_get_unwinder = &record_btrace_frame_unwind;
b2f4cfde
MM
1235 ops->to_resume = record_btrace_resume;
1236 ops->to_wait = record_btrace_wait;
e2887aa3
MM
1237 ops->to_find_new_threads = record_btrace_find_new_threads;
1238 ops->to_thread_alive = record_btrace_thread_alive;
066ce621
MM
1239 ops->to_goto_record_begin = record_btrace_goto_begin;
1240 ops->to_goto_record_end = record_btrace_goto_end;
1241 ops->to_goto_record = record_btrace_goto;
afedecd3
MM
1242 ops->to_stratum = record_stratum;
1243 ops->to_magic = OPS_MAGIC;
1244}
1245
1246/* Alias for "target record". */
1247
1248static void
1249cmd_record_btrace_start (char *args, int from_tty)
1250{
1251 if (args != NULL && *args != 0)
1252 error (_("Invalid argument."));
1253
1254 execute_command ("target record-btrace", from_tty);
1255}
1256
1257void _initialize_record_btrace (void);
1258
1259/* Initialize btrace commands. */
1260
1261void
1262_initialize_record_btrace (void)
1263{
1264 add_cmd ("btrace", class_obscure, cmd_record_btrace_start,
1265 _("Start branch trace recording."),
1266 &record_cmdlist);
1267 add_alias_cmd ("b", "btrace", class_obscure, 1, &record_cmdlist);
1268
1269 init_record_btrace_ops ();
1270 add_target (&record_btrace_ops);
1271}