1 /* Branch trace support for GDB, the GNU debugger.
3 Copyright (C) 2013-2014 Free Software Foundation, Inc.
5 Contributed by Intel Corp. <markus.t.metzger@intel.com>
7 This file is part of GDB.
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.
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.
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/>. */
24 #include "gdbthread.h"
29 #include "exceptions.h"
30 #include "cli/cli-utils.h"
34 #include "filenames.h"
36 #include "frame-unwind.h"
38 /* The target_ops of record-btrace. */
39 static struct target_ops record_btrace_ops;
41 /* A new thread observer enabling branch tracing for the new thread. */
42 static struct observer *record_btrace_thread_observer;
44 /* Temporarily allow memory accesses. */
45 static int record_btrace_allow_memory_access;
47 /* Print a record-btrace debug message. Use do ... while (0) to avoid
48 ambiguities when used in if statements. */
50 #define DEBUG(msg, args...) \
53 if (record_debug != 0) \
54 fprintf_unfiltered (gdb_stdlog, \
55 "[record-btrace] " msg "\n", ##args); \
60 /* Update the branch trace for the current thread and return a pointer to its
61 branch trace information struct.
63 Throws an error if there is no thread or no trace. This function never
66 static struct btrace_thread_info *
69 struct thread_info *tp;
70 struct btrace_thread_info *btinfo;
74 tp = find_thread_ptid (inferior_ptid);
76 error (_("No thread."));
82 if (btinfo->begin == NULL)
83 error (_("No trace."));
88 /* Enable branch tracing for one thread. Warn on errors. */
91 record_btrace_enable_warn (struct thread_info *tp)
93 volatile struct gdb_exception error;
95 TRY_CATCH (error, RETURN_MASK_ERROR)
98 if (error.message != NULL)
99 warning ("%s", error.message);
102 /* Callback function to disable branch tracing for one thread. */
105 record_btrace_disable_callback (void *arg)
107 struct thread_info *tp;
114 /* Enable automatic tracing of new threads. */
117 record_btrace_auto_enable (void)
119 DEBUG ("attach thread observer");
121 record_btrace_thread_observer
122 = observer_attach_new_thread (record_btrace_enable_warn);
125 /* Disable automatic tracing of new threads. */
128 record_btrace_auto_disable (void)
130 /* The observer may have been detached, already. */
131 if (record_btrace_thread_observer == NULL)
134 DEBUG ("detach thread observer");
136 observer_detach_new_thread (record_btrace_thread_observer);
137 record_btrace_thread_observer = NULL;
140 /* The to_open method of target record-btrace. */
143 record_btrace_open (char *args, int from_tty)
145 struct cleanup *disable_chain;
146 struct thread_info *tp;
152 if (!target_has_execution)
153 error (_("The program is not being run."));
155 if (!target_supports_btrace ())
156 error (_("Target does not support branch tracing."));
158 gdb_assert (record_btrace_thread_observer == NULL);
160 disable_chain = make_cleanup (null_cleanup, NULL);
162 if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
166 make_cleanup (record_btrace_disable_callback, tp);
169 record_btrace_auto_enable ();
171 push_target (&record_btrace_ops);
173 observer_notify_record_changed (current_inferior (), 1);
175 discard_cleanups (disable_chain);
178 /* The to_stop_recording method of target record-btrace. */
181 record_btrace_stop_recording (void)
183 struct thread_info *tp;
185 DEBUG ("stop recording");
187 record_btrace_auto_disable ();
190 if (tp->btrace.target != NULL)
194 /* The to_close method of target record-btrace. */
197 record_btrace_close (void)
199 /* Make sure automatic recording gets disabled even if we did not stop
200 recording before closing the record-btrace target. */
201 record_btrace_auto_disable ();
203 /* We already stopped recording. */
206 /* The to_info_record method of target record-btrace. */
209 record_btrace_info (void)
211 struct btrace_thread_info *btinfo;
212 struct thread_info *tp;
213 unsigned int insns, calls;
217 tp = find_thread_ptid (inferior_ptid);
219 error (_("No thread."));
226 btinfo = &tp->btrace;
227 if (btinfo->begin != NULL)
229 struct btrace_call_iterator call;
230 struct btrace_insn_iterator insn;
232 btrace_call_end (&call, btinfo);
233 btrace_call_prev (&call, 1);
234 calls = btrace_call_number (&call);
236 btrace_insn_end (&insn, btinfo);
237 btrace_insn_prev (&insn, 1);
238 insns = btrace_insn_number (&insn);
241 printf_unfiltered (_("Recorded %u instructions in %u functions for thread "
242 "%d (%s).\n"), insns, calls, tp->num,
243 target_pid_to_str (tp->ptid));
245 if (btrace_is_replaying (tp))
246 printf_unfiltered (_("Replay in progress. At instruction %u.\n"),
247 btrace_insn_number (btinfo->replay));
250 /* Print an unsigned int. */
253 ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
255 ui_out_field_fmt (uiout, fld, "%u", val);
258 /* Disassemble a section of the recorded instruction trace. */
261 btrace_insn_history (struct ui_out *uiout,
262 const struct btrace_insn_iterator *begin,
263 const struct btrace_insn_iterator *end, int flags)
265 struct gdbarch *gdbarch;
266 struct btrace_insn_iterator it;
268 DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
269 btrace_insn_number (end));
271 gdbarch = target_gdbarch ();
273 for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
275 const struct btrace_insn *insn;
277 insn = btrace_insn_get (&it);
279 /* Print the instruction index. */
280 ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
281 ui_out_text (uiout, "\t");
283 /* Disassembly with '/m' flag may not produce the expected result.
285 gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->pc + 1);
289 /* The to_insn_history method of target record-btrace. */
292 record_btrace_insn_history (int size, int flags)
294 struct btrace_thread_info *btinfo;
295 struct btrace_insn_history *history;
296 struct btrace_insn_iterator begin, end;
297 struct cleanup *uiout_cleanup;
298 struct ui_out *uiout;
299 unsigned int context, covered;
301 uiout = current_uiout;
302 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
304 context = abs (size);
306 error (_("Bad record instruction-history-size."));
308 btinfo = require_btrace ();
309 history = btinfo->insn_history;
312 struct btrace_insn_iterator *replay;
314 DEBUG ("insn-history (0x%x): %d", flags, size);
316 /* If we're replaying, we start at the replay position. Otherwise, we
317 start at the tail of the trace. */
318 replay = btinfo->replay;
322 btrace_insn_end (&begin, btinfo);
324 /* We start from here and expand in the requested direction. Then we
325 expand in the other direction, as well, to fill up any remaining
330 /* We want the current position covered, as well. */
331 covered = btrace_insn_next (&end, 1);
332 covered += btrace_insn_prev (&begin, context - covered);
333 covered += btrace_insn_next (&end, context - covered);
337 covered = btrace_insn_next (&end, context);
338 covered += btrace_insn_prev (&begin, context - covered);
343 begin = history->begin;
346 DEBUG ("insn-history (0x%x): %d, prev: [%u; %u)", flags, size,
347 btrace_insn_number (&begin), btrace_insn_number (&end));
352 covered = btrace_insn_prev (&begin, context);
357 covered = btrace_insn_next (&end, context);
362 btrace_insn_history (uiout, &begin, &end, flags);
366 printf_unfiltered (_("At the start of the branch trace record.\n"));
368 printf_unfiltered (_("At the end of the branch trace record.\n"));
371 btrace_set_insn_history (btinfo, &begin, &end);
372 do_cleanups (uiout_cleanup);
375 /* The to_insn_history_range method of target record-btrace. */
378 record_btrace_insn_history_range (ULONGEST from, ULONGEST to, int flags)
380 struct btrace_thread_info *btinfo;
381 struct btrace_insn_history *history;
382 struct btrace_insn_iterator begin, end;
383 struct cleanup *uiout_cleanup;
384 struct ui_out *uiout;
385 unsigned int low, high;
388 uiout = current_uiout;
389 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
394 DEBUG ("insn-history (0x%x): [%u; %u)", flags, low, high);
396 /* Check for wrap-arounds. */
397 if (low != from || high != to)
398 error (_("Bad range."));
401 error (_("Bad range."));
403 btinfo = require_btrace ();
405 found = btrace_find_insn_by_number (&begin, btinfo, low);
407 error (_("Range out of bounds."));
409 found = btrace_find_insn_by_number (&end, btinfo, high);
412 /* Silently truncate the range. */
413 btrace_insn_end (&end, btinfo);
417 /* We want both begin and end to be inclusive. */
418 btrace_insn_next (&end, 1);
421 btrace_insn_history (uiout, &begin, &end, flags);
422 btrace_set_insn_history (btinfo, &begin, &end);
424 do_cleanups (uiout_cleanup);
427 /* The to_insn_history_from method of target record-btrace. */
430 record_btrace_insn_history_from (ULONGEST from, int size, int flags)
432 ULONGEST begin, end, context;
434 context = abs (size);
436 error (_("Bad record instruction-history-size."));
445 begin = from - context + 1;
450 end = from + context - 1;
452 /* Check for wrap-around. */
457 record_btrace_insn_history_range (begin, end, flags);
460 /* Print the instruction number range for a function call history line. */
463 btrace_call_history_insn_range (struct ui_out *uiout,
464 const struct btrace_function *bfun)
466 unsigned int begin, end, size;
468 size = VEC_length (btrace_insn_s, bfun->insn);
469 gdb_assert (size > 0);
471 begin = bfun->insn_offset;
472 end = begin + size - 1;
474 ui_out_field_uint (uiout, "insn begin", begin);
475 ui_out_text (uiout, ",");
476 ui_out_field_uint (uiout, "insn end", end);
479 /* Print the source line information for a function call history line. */
482 btrace_call_history_src_line (struct ui_out *uiout,
483 const struct btrace_function *bfun)
492 ui_out_field_string (uiout, "file",
493 symtab_to_filename_for_display (sym->symtab));
495 begin = bfun->lbegin;
501 ui_out_text (uiout, ":");
502 ui_out_field_int (uiout, "min line", begin);
507 ui_out_text (uiout, ",");
508 ui_out_field_int (uiout, "max line", end);
511 /* Disassemble a section of the recorded function trace. */
514 btrace_call_history (struct ui_out *uiout,
515 const struct btrace_thread_info *btinfo,
516 const struct btrace_call_iterator *begin,
517 const struct btrace_call_iterator *end,
518 enum record_print_flag flags)
520 struct btrace_call_iterator it;
522 DEBUG ("ftrace (0x%x): [%u; %u)", flags, btrace_call_number (begin),
523 btrace_call_number (end));
525 for (it = *begin; btrace_call_cmp (&it, end) < 0; btrace_call_next (&it, 1))
527 const struct btrace_function *bfun;
528 struct minimal_symbol *msym;
531 bfun = btrace_call_get (&it);
535 /* Print the function index. */
536 ui_out_field_uint (uiout, "index", bfun->number);
537 ui_out_text (uiout, "\t");
539 if ((flags & RECORD_PRINT_INDENT_CALLS) != 0)
541 int level = bfun->level + btinfo->level, i;
543 for (i = 0; i < level; ++i)
544 ui_out_text (uiout, " ");
548 ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (sym));
549 else if (msym != NULL)
550 ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (msym));
551 else if (!ui_out_is_mi_like_p (uiout))
552 ui_out_field_string (uiout, "function", "??");
554 if ((flags & RECORD_PRINT_INSN_RANGE) != 0)
556 ui_out_text (uiout, _("\tinst "));
557 btrace_call_history_insn_range (uiout, bfun);
560 if ((flags & RECORD_PRINT_SRC_LINE) != 0)
562 ui_out_text (uiout, _("\tat "));
563 btrace_call_history_src_line (uiout, bfun);
566 ui_out_text (uiout, "\n");
570 /* The to_call_history method of target record-btrace. */
573 record_btrace_call_history (int size, int flags)
575 struct btrace_thread_info *btinfo;
576 struct btrace_call_history *history;
577 struct btrace_call_iterator begin, end;
578 struct cleanup *uiout_cleanup;
579 struct ui_out *uiout;
580 unsigned int context, covered;
582 uiout = current_uiout;
583 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
585 context = abs (size);
587 error (_("Bad record function-call-history-size."));
589 btinfo = require_btrace ();
590 history = btinfo->call_history;
593 struct btrace_insn_iterator *replay;
595 DEBUG ("call-history (0x%x): %d", flags, size);
597 /* If we're replaying, we start at the replay position. Otherwise, we
598 start at the tail of the trace. */
599 replay = btinfo->replay;
602 begin.function = replay->function;
603 begin.btinfo = btinfo;
606 btrace_call_end (&begin, btinfo);
608 /* We start from here and expand in the requested direction. Then we
609 expand in the other direction, as well, to fill up any remaining
614 /* We want the current position covered, as well. */
615 covered = btrace_call_next (&end, 1);
616 covered += btrace_call_prev (&begin, context - covered);
617 covered += btrace_call_next (&end, context - covered);
621 covered = btrace_call_next (&end, context);
622 covered += btrace_call_prev (&begin, context- covered);
627 begin = history->begin;
630 DEBUG ("call-history (0x%x): %d, prev: [%u; %u)", flags, size,
631 btrace_call_number (&begin), btrace_call_number (&end));
636 covered = btrace_call_prev (&begin, context);
641 covered = btrace_call_next (&end, context);
646 btrace_call_history (uiout, btinfo, &begin, &end, flags);
650 printf_unfiltered (_("At the start of the branch trace record.\n"));
652 printf_unfiltered (_("At the end of the branch trace record.\n"));
655 btrace_set_call_history (btinfo, &begin, &end);
656 do_cleanups (uiout_cleanup);
659 /* The to_call_history_range method of target record-btrace. */
662 record_btrace_call_history_range (ULONGEST from, ULONGEST to, int flags)
664 struct btrace_thread_info *btinfo;
665 struct btrace_call_history *history;
666 struct btrace_call_iterator begin, end;
667 struct cleanup *uiout_cleanup;
668 struct ui_out *uiout;
669 unsigned int low, high;
672 uiout = current_uiout;
673 uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
678 DEBUG ("call-history (0x%x): [%u; %u)", flags, low, high);
680 /* Check for wrap-arounds. */
681 if (low != from || high != to)
682 error (_("Bad range."));
685 error (_("Bad range."));
687 btinfo = require_btrace ();
689 found = btrace_find_call_by_number (&begin, btinfo, low);
691 error (_("Range out of bounds."));
693 found = btrace_find_call_by_number (&end, btinfo, high);
696 /* Silently truncate the range. */
697 btrace_call_end (&end, btinfo);
701 /* We want both begin and end to be inclusive. */
702 btrace_call_next (&end, 1);
705 btrace_call_history (uiout, btinfo, &begin, &end, flags);
706 btrace_set_call_history (btinfo, &begin, &end);
708 do_cleanups (uiout_cleanup);
711 /* The to_call_history_from method of target record-btrace. */
714 record_btrace_call_history_from (ULONGEST from, int size, int flags)
716 ULONGEST begin, end, context;
718 context = abs (size);
720 error (_("Bad record function-call-history-size."));
729 begin = from - context + 1;
734 end = from + context - 1;
736 /* Check for wrap-around. */
741 record_btrace_call_history_range (begin, end, flags);
744 /* The to_record_is_replaying method of target record-btrace. */
747 record_btrace_is_replaying (void)
749 struct thread_info *tp;
752 if (btrace_is_replaying (tp))
758 /* The to_xfer_partial method of target record-btrace. */
761 record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
762 const char *annex, gdb_byte *readbuf,
763 const gdb_byte *writebuf, ULONGEST offset,
766 struct target_ops *t;
768 /* Filter out requests that don't make sense during replay. */
769 if (!record_btrace_allow_memory_access && record_btrace_is_replaying ())
773 case TARGET_OBJECT_MEMORY:
775 struct target_section *section;
777 /* We do not allow writing memory in general. */
778 if (writebuf != NULL)
779 return TARGET_XFER_E_UNAVAILABLE;
781 /* We allow reading readonly memory. */
782 section = target_section_by_addr (ops, offset);
785 /* Check if the section we found is readonly. */
786 if ((bfd_get_section_flags (section->the_bfd_section->owner,
787 section->the_bfd_section)
788 & SEC_READONLY) != 0)
790 /* Truncate the request to fit into this section. */
791 len = min (len, section->endaddr - offset);
796 return TARGET_XFER_E_UNAVAILABLE;
801 /* Forward the request. */
802 for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
803 if (ops->to_xfer_partial != NULL)
804 return ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
807 return TARGET_XFER_E_UNAVAILABLE;
810 /* The to_insert_breakpoint method of target record-btrace. */
813 record_btrace_insert_breakpoint (struct target_ops *ops,
814 struct gdbarch *gdbarch,
815 struct bp_target_info *bp_tgt)
817 volatile struct gdb_exception except;
820 /* Inserting breakpoints requires accessing memory. Allow it for the
821 duration of this function. */
822 old = record_btrace_allow_memory_access;
823 record_btrace_allow_memory_access = 1;
826 TRY_CATCH (except, RETURN_MASK_ALL)
827 ret = forward_target_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
829 record_btrace_allow_memory_access = old;
831 if (except.reason < 0)
832 throw_exception (except);
837 /* The to_remove_breakpoint method of target record-btrace. */
840 record_btrace_remove_breakpoint (struct target_ops *ops,
841 struct gdbarch *gdbarch,
842 struct bp_target_info *bp_tgt)
844 volatile struct gdb_exception except;
847 /* Removing breakpoints requires accessing memory. Allow it for the
848 duration of this function. */
849 old = record_btrace_allow_memory_access;
850 record_btrace_allow_memory_access = 1;
853 TRY_CATCH (except, RETURN_MASK_ALL)
854 ret = forward_target_remove_breakpoint (ops->beneath, gdbarch, bp_tgt);
856 record_btrace_allow_memory_access = old;
858 if (except.reason < 0)
859 throw_exception (except);
864 /* The to_fetch_registers method of target record-btrace. */
867 record_btrace_fetch_registers (struct target_ops *ops,
868 struct regcache *regcache, int regno)
870 struct btrace_insn_iterator *replay;
871 struct thread_info *tp;
873 tp = find_thread_ptid (inferior_ptid);
874 gdb_assert (tp != NULL);
876 replay = tp->btrace.replay;
879 const struct btrace_insn *insn;
880 struct gdbarch *gdbarch;
883 gdbarch = get_regcache_arch (regcache);
884 pcreg = gdbarch_pc_regnum (gdbarch);
888 /* We can only provide the PC register. */
889 if (regno >= 0 && regno != pcreg)
892 insn = btrace_insn_get (replay);
893 gdb_assert (insn != NULL);
895 regcache_raw_supply (regcache, regno, &insn->pc);
899 struct target_ops *t;
901 for (t = ops->beneath; t != NULL; t = t->beneath)
902 if (t->to_fetch_registers != NULL)
904 t->to_fetch_registers (t, regcache, regno);
910 /* The to_store_registers method of target record-btrace. */
913 record_btrace_store_registers (struct target_ops *ops,
914 struct regcache *regcache, int regno)
916 struct target_ops *t;
918 if (record_btrace_is_replaying ())
919 error (_("This record target does not allow writing registers."));
921 gdb_assert (may_write_registers != 0);
923 for (t = ops->beneath; t != NULL; t = t->beneath)
924 if (t->to_store_registers != NULL)
926 t->to_store_registers (t, regcache, regno);
933 /* The to_prepare_to_store method of target record-btrace. */
936 record_btrace_prepare_to_store (struct target_ops *ops,
937 struct regcache *regcache)
939 struct target_ops *t;
941 if (record_btrace_is_replaying ())
944 for (t = ops->beneath; t != NULL; t = t->beneath)
945 if (t->to_prepare_to_store != NULL)
947 t->to_prepare_to_store (t, regcache);
952 /* Implement stop_reason method for record_btrace_frame_unwind. */
954 static enum unwind_stop_reason
955 record_btrace_frame_unwind_stop_reason (struct frame_info *this_frame,
958 return UNWIND_UNAVAILABLE;
961 /* Implement this_id method for record_btrace_frame_unwind. */
964 record_btrace_frame_this_id (struct frame_info *this_frame, void **this_cache,
965 struct frame_id *this_id)
967 /* Leave there the outer_frame_id value. */
970 /* Implement prev_register method for record_btrace_frame_unwind. */
972 static struct value *
973 record_btrace_frame_prev_register (struct frame_info *this_frame,
977 throw_error (NOT_AVAILABLE_ERROR,
978 _("Registers are not available in btrace record history"));
981 /* Implement sniffer method for record_btrace_frame_unwind. */
984 record_btrace_frame_sniffer (const struct frame_unwind *self,
985 struct frame_info *this_frame,
988 struct thread_info *tp;
989 struct btrace_thread_info *btinfo;
990 struct btrace_insn_iterator *replay;
992 /* THIS_FRAME does not contain a reference to its thread. */
993 tp = find_thread_ptid (inferior_ptid);
994 gdb_assert (tp != NULL);
996 return btrace_is_replaying (tp);
999 /* btrace recording does not store previous memory content, neither the stack
1000 frames content. Any unwinding would return errorneous results as the stack
1001 contents no longer matches the changed PC value restored from history.
1002 Therefore this unwinder reports any possibly unwound registers as
1005 static const struct frame_unwind record_btrace_frame_unwind =
1008 record_btrace_frame_unwind_stop_reason,
1009 record_btrace_frame_this_id,
1010 record_btrace_frame_prev_register,
1012 record_btrace_frame_sniffer
1014 /* Initialize the record-btrace target ops. */
1017 init_record_btrace_ops (void)
1019 struct target_ops *ops;
1021 ops = &record_btrace_ops;
1022 ops->to_shortname = "record-btrace";
1023 ops->to_longname = "Branch tracing target";
1024 ops->to_doc = "Collect control-flow trace and provide the execution history.";
1025 ops->to_open = record_btrace_open;
1026 ops->to_close = record_btrace_close;
1027 ops->to_detach = record_detach;
1028 ops->to_disconnect = record_disconnect;
1029 ops->to_mourn_inferior = record_mourn_inferior;
1030 ops->to_kill = record_kill;
1031 ops->to_create_inferior = find_default_create_inferior;
1032 ops->to_stop_recording = record_btrace_stop_recording;
1033 ops->to_info_record = record_btrace_info;
1034 ops->to_insn_history = record_btrace_insn_history;
1035 ops->to_insn_history_from = record_btrace_insn_history_from;
1036 ops->to_insn_history_range = record_btrace_insn_history_range;
1037 ops->to_call_history = record_btrace_call_history;
1038 ops->to_call_history_from = record_btrace_call_history_from;
1039 ops->to_call_history_range = record_btrace_call_history_range;
1040 ops->to_record_is_replaying = record_btrace_is_replaying;
1041 ops->to_xfer_partial = record_btrace_xfer_partial;
1042 ops->to_remove_breakpoint = record_btrace_remove_breakpoint;
1043 ops->to_insert_breakpoint = record_btrace_insert_breakpoint;
1044 ops->to_fetch_registers = record_btrace_fetch_registers;
1045 ops->to_store_registers = record_btrace_store_registers;
1046 ops->to_prepare_to_store = record_btrace_prepare_to_store;
1047 ops->to_get_unwinder = &record_btrace_frame_unwind;
1048 ops->to_stratum = record_stratum;
1049 ops->to_magic = OPS_MAGIC;
1052 /* Alias for "target record". */
1055 cmd_record_btrace_start (char *args, int from_tty)
1057 if (args != NULL && *args != 0)
1058 error (_("Invalid argument."));
1060 execute_command ("target record-btrace", from_tty);
1063 void _initialize_record_btrace (void);
1065 /* Initialize btrace commands. */
1068 _initialize_record_btrace (void)
1070 add_cmd ("btrace", class_obscure, cmd_record_btrace_start,
1071 _("Start branch trace recording."),
1073 add_alias_cmd ("b", "btrace", class_obscure, 1, &record_cmdlist);
1075 init_record_btrace_ops ();
1076 add_target (&record_btrace_ops);