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