gdb/btrace.c - gdb
Global variables defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "btrace.h"
- #include "gdbthread.h"
- #include "inferior.h"
- #include "target.h"
- #include "record.h"
- #include "symtab.h"
- #include "disasm.h"
- #include "source.h"
- #include "filenames.h"
- #include "xml-support.h"
- #include "regcache.h"
- #define DEBUG(msg, args...) \
- do \
- { \
- if (record_debug != 0) \
- fprintf_unfiltered (gdb_stdlog, \
- "[btrace] " msg "\n", ##args); \
- } \
- while (0)
- #define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args)
- static const char *
- ftrace_print_function_name (const struct btrace_function *bfun)
- {
- struct minimal_symbol *msym;
- struct symbol *sym;
- msym = bfun->msym;
- sym = bfun->sym;
- if (sym != NULL)
- return SYMBOL_PRINT_NAME (sym);
- if (msym != NULL)
- return MSYMBOL_PRINT_NAME (msym);
- return "<unknown>";
- }
- static const char *
- ftrace_print_filename (const struct btrace_function *bfun)
- {
- struct symbol *sym;
- const char *filename;
- sym = bfun->sym;
- if (sym != NULL)
- filename = symtab_to_filename_for_display (symbol_symtab (sym));
- else
- filename = "<unknown>";
- return filename;
- }
- static const char *
- ftrace_print_insn_addr (const struct btrace_insn *insn)
- {
- if (insn == NULL)
- return "<nil>";
- return core_addr_to_string_nz (insn->pc);
- }
- static void
- ftrace_debug (const struct btrace_function *bfun, const char *prefix)
- {
- const char *fun, *file;
- unsigned int ibegin, iend;
- int lbegin, lend, level;
- fun = ftrace_print_function_name (bfun);
- file = ftrace_print_filename (bfun);
- level = bfun->level;
- lbegin = bfun->lbegin;
- lend = bfun->lend;
- ibegin = bfun->insn_offset;
- iend = ibegin + VEC_length (btrace_insn_s, bfun->insn);
- DEBUG_FTRACE ("%s: fun = %s, file = %s, level = %d, lines = [%d; %d], "
- "insn = [%u; %u)", prefix, fun, file, level, lbegin, lend,
- ibegin, iend);
- }
- static int
- ftrace_function_switched (const struct btrace_function *bfun,
- const struct minimal_symbol *mfun,
- const struct symbol *fun)
- {
- struct minimal_symbol *msym;
- struct symbol *sym;
- msym = bfun->msym;
- sym = bfun->sym;
-
- if (mfun != NULL && msym != NULL
- && strcmp (MSYMBOL_LINKAGE_NAME (mfun), MSYMBOL_LINKAGE_NAME (msym)) != 0)
- return 1;
-
- if (fun != NULL && sym != NULL)
- {
- const char *bfname, *fname;
-
- if (strcmp (SYMBOL_LINKAGE_NAME (fun), SYMBOL_LINKAGE_NAME (sym)) != 0)
- return 1;
-
- bfname = symtab_to_fullname (symbol_symtab (sym));
- fname = symtab_to_fullname (symbol_symtab (fun));
- if (filename_cmp (fname, bfname) != 0)
- return 1;
- }
-
- if (!(msym == NULL && sym == NULL) && mfun == NULL && fun == NULL)
- return 1;
-
- if (msym == NULL && sym == NULL && !(mfun == NULL && fun == NULL))
- return 1;
- return 0;
- }
- static int
- ftrace_skip_file (const struct btrace_function *bfun, const char *fullname)
- {
- struct symbol *sym;
- const char *bfile;
- sym = bfun->sym;
- if (sym == NULL)
- return 1;
- bfile = symtab_to_fullname (symbol_symtab (sym));
- return (filename_cmp (bfile, fullname) != 0);
- }
- static struct btrace_function *
- ftrace_new_function (struct btrace_function *prev,
- struct minimal_symbol *mfun,
- struct symbol *fun)
- {
- struct btrace_function *bfun;
- bfun = xzalloc (sizeof (*bfun));
- bfun->msym = mfun;
- bfun->sym = fun;
- bfun->flow.prev = prev;
-
- bfun->lbegin = INT_MAX;
- bfun->lend = INT_MIN;
- if (prev == NULL)
- {
-
- bfun->number = 1;
- bfun->insn_offset = 1;
- }
- else
- {
- gdb_assert (prev->flow.next == NULL);
- prev->flow.next = bfun;
- bfun->number = prev->number + 1;
- bfun->insn_offset = (prev->insn_offset
- + VEC_length (btrace_insn_s, prev->insn));
- }
- return bfun;
- }
- static void
- ftrace_update_caller (struct btrace_function *bfun,
- struct btrace_function *caller,
- enum btrace_function_flag flags)
- {
- if (bfun->up != NULL)
- ftrace_debug (bfun, "updating caller");
- bfun->up = caller;
- bfun->flags = flags;
- ftrace_debug (bfun, "set caller");
- }
- static void
- ftrace_fixup_caller (struct btrace_function *bfun,
- struct btrace_function *caller,
- enum btrace_function_flag flags)
- {
- struct btrace_function *prev, *next;
- ftrace_update_caller (bfun, caller, flags);
-
- for (prev = bfun->segment.prev; prev != NULL; prev = prev->segment.prev)
- ftrace_update_caller (prev, caller, flags);
- for (next = bfun->segment.next; next != NULL; next = next->segment.next)
- ftrace_update_caller (next, caller, flags);
- }
- static struct btrace_function *
- ftrace_new_call (struct btrace_function *caller,
- struct minimal_symbol *mfun,
- struct symbol *fun)
- {
- struct btrace_function *bfun;
- bfun = ftrace_new_function (caller, mfun, fun);
- bfun->up = caller;
- bfun->level = caller->level + 1;
- ftrace_debug (bfun, "new call");
- return bfun;
- }
- static struct btrace_function *
- ftrace_new_tailcall (struct btrace_function *caller,
- struct minimal_symbol *mfun,
- struct symbol *fun)
- {
- struct btrace_function *bfun;
- bfun = ftrace_new_function (caller, mfun, fun);
- bfun->up = caller;
- bfun->level = caller->level + 1;
- bfun->flags |= BFUN_UP_LINKS_TO_TAILCALL;
- ftrace_debug (bfun, "new tail call");
- return bfun;
- }
- static struct btrace_function *
- ftrace_find_caller (struct btrace_function *bfun,
- struct minimal_symbol *mfun,
- struct symbol *fun)
- {
- for (; bfun != NULL; bfun = bfun->up)
- {
-
- if (ftrace_function_switched (bfun, mfun, fun))
- continue;
-
- break;
- }
- return bfun;
- }
- static struct btrace_function *
- ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
- {
- for (; bfun != NULL; bfun = bfun->up)
- {
- struct btrace_insn *last;
- CORE_ADDR pc;
-
- gdb_assert (!VEC_empty (btrace_insn_s, bfun->insn));
- last = VEC_last (btrace_insn_s, bfun->insn);
- pc = last->pc;
- if (gdbarch_insn_is_call (gdbarch, pc))
- break;
- }
- return bfun;
- }
- static struct btrace_function *
- ftrace_new_return (struct gdbarch *gdbarch,
- struct btrace_function *prev,
- struct minimal_symbol *mfun,
- struct symbol *fun)
- {
- struct btrace_function *bfun, *caller;
- bfun = ftrace_new_function (prev, mfun, fun);
-
- caller = ftrace_find_caller (prev->up, mfun, fun);
- if (caller != NULL)
- {
-
- gdb_assert (caller->segment.next == NULL);
- caller->segment.next = bfun;
- bfun->segment.prev = caller;
-
- bfun->level = caller->level;
-
- bfun->up = caller->up;
- bfun->flags = caller->flags;
- ftrace_debug (bfun, "new return");
- }
- else
- {
-
-
- caller = ftrace_find_call (gdbarch, prev->up);
- if (caller == NULL)
- {
-
-
- while (prev->up != NULL)
- prev = prev->up;
-
- bfun->level = min (0, prev->level) - 1;
-
- ftrace_fixup_caller (prev, bfun, BFUN_UP_LINKS_TO_RET);
- ftrace_debug (bfun, "new return - no caller");
- }
- else
- {
-
- bfun->level = prev->level;
- ftrace_debug (bfun, "new return - unknown caller");
- }
- }
- return bfun;
- }
- static struct btrace_function *
- ftrace_new_switch (struct btrace_function *prev,
- struct minimal_symbol *mfun,
- struct symbol *fun)
- {
- struct btrace_function *bfun;
-
- bfun = ftrace_new_function (prev, mfun, fun);
-
- bfun->level = prev->level;
- ftrace_debug (bfun, "new switch");
- return bfun;
- }
- static struct btrace_function *
- ftrace_update_function (struct gdbarch *gdbarch,
- struct btrace_function *bfun, CORE_ADDR pc)
- {
- struct bound_minimal_symbol bmfun;
- struct minimal_symbol *mfun;
- struct symbol *fun;
- struct btrace_insn *last;
-
- fun = find_pc_function (pc);
- bmfun = lookup_minimal_symbol_by_pc (pc);
- mfun = bmfun.minsym;
- if (fun == NULL && mfun == NULL)
- DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc));
-
- if (bfun == NULL)
- return ftrace_new_function (bfun, mfun, fun);
-
- last = NULL;
- if (!VEC_empty (btrace_insn_s, bfun->insn))
- last = VEC_last (btrace_insn_s, bfun->insn);
- if (last != NULL)
- {
- CORE_ADDR lpc;
- lpc = last->pc;
-
- if (gdbarch_insn_is_ret (gdbarch, lpc))
- return ftrace_new_return (gdbarch, bfun, mfun, fun);
-
- if (gdbarch_insn_is_call (gdbarch, lpc))
- {
- int size;
- size = gdb_insn_length (gdbarch, lpc);
-
- if (lpc + size != pc)
- return ftrace_new_call (bfun, mfun, fun);
- }
- }
-
- if (ftrace_function_switched (bfun, mfun, fun))
- {
- DEBUG_FTRACE ("switching from %s in %s at %s",
- ftrace_print_insn_addr (last),
- ftrace_print_function_name (bfun),
- ftrace_print_filename (bfun));
- if (last != NULL)
- {
- CORE_ADDR start, lpc;
- start = get_pc_function_start (pc);
-
- if (start == 0)
- start = pc;
- lpc = last->pc;
-
- if (start == pc && gdbarch_insn_is_jump (gdbarch, lpc))
- return ftrace_new_tailcall (bfun, mfun, fun);
- }
- return ftrace_new_switch (bfun, mfun, fun);
- }
- return bfun;
- }
- static void
- ftrace_update_lines (struct btrace_function *bfun, CORE_ADDR pc)
- {
- struct symtab_and_line sal;
- const char *fullname;
- sal = find_pc_line (pc, 0);
- if (sal.symtab == NULL || sal.line == 0)
- {
- DEBUG_FTRACE ("no lines at %s", core_addr_to_string_nz (pc));
- return;
- }
-
- fullname = symtab_to_fullname (sal.symtab);
- if (ftrace_skip_file (bfun, fullname))
- {
- DEBUG_FTRACE ("ignoring file at %s, file=%s",
- core_addr_to_string_nz (pc), fullname);
- return;
- }
-
- bfun->lbegin = min (bfun->lbegin, sal.line);
- bfun->lend = max (bfun->lend, sal.line);
- if (record_debug > 1)
- ftrace_debug (bfun, "update lines");
- }
- static void
- ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
- {
- struct btrace_insn *insn;
- insn = VEC_safe_push (btrace_insn_s, bfun->insn, NULL);
- insn->pc = pc;
- if (record_debug > 1)
- ftrace_debug (bfun, "update insn");
- }
- static void
- btrace_compute_ftrace (struct btrace_thread_info *btinfo,
- VEC (btrace_block_s) *btrace)
- {
- struct btrace_function *begin, *end;
- struct gdbarch *gdbarch;
- unsigned int blk;
- int level;
- DEBUG ("compute ftrace");
- gdbarch = target_gdbarch ();
- begin = btinfo->begin;
- end = btinfo->end;
- level = begin != NULL ? -btinfo->level : INT_MAX;
- blk = VEC_length (btrace_block_s, btrace);
- while (blk != 0)
- {
- btrace_block_s *block;
- CORE_ADDR pc;
- blk -= 1;
- block = VEC_index (btrace_block_s, btrace, blk);
- pc = block->begin;
- for (;;)
- {
- int size;
-
- if (block->end < pc)
- {
- warning (_("Recorded trace may be corrupted around %s."),
- core_addr_to_string_nz (pc));
- break;
- }
- end = ftrace_update_function (gdbarch, end, pc);
- if (begin == NULL)
- begin = end;
-
- if (blk != 0)
- level = min (level, end->level);
- ftrace_update_insns (end, pc);
- ftrace_update_lines (end, pc);
-
- if (block->end == pc)
- break;
- size = gdb_insn_length (gdbarch, pc);
-
- if (size <= 0)
- {
- warning (_("Recorded trace may be incomplete around %s."),
- core_addr_to_string_nz (pc));
- break;
- }
- pc += size;
-
- if (blk == 0)
- level = min (level, end->level);
- }
- }
- btinfo->begin = begin;
- btinfo->end = end;
-
- btinfo->level = -level;
- }
- static void
- btrace_add_pc (struct thread_info *tp)
- {
- VEC (btrace_block_s) *btrace;
- struct btrace_block *block;
- struct regcache *regcache;
- struct cleanup *cleanup;
- CORE_ADDR pc;
- regcache = get_thread_regcache (tp->ptid);
- pc = regcache_read_pc (regcache);
- btrace = NULL;
- cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
- block = VEC_safe_push (btrace_block_s, btrace, NULL);
- block->begin = pc;
- block->end = pc;
- btrace_compute_ftrace (&tp->btrace, btrace);
- do_cleanups (cleanup);
- }
- void
- btrace_enable (struct thread_info *tp)
- {
- if (tp->btrace.target != NULL)
- return;
- if (!target_supports_btrace ())
- error (_("Target does not support branch tracing."));
- DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
- tp->btrace.target = target_enable_btrace (tp->ptid);
-
- if (tp->btrace.target != NULL)
- btrace_add_pc (tp);
- }
- void
- btrace_disable (struct thread_info *tp)
- {
- struct btrace_thread_info *btp = &tp->btrace;
- int errcode = 0;
- if (btp->target == NULL)
- return;
- DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
- target_disable_btrace (btp->target);
- btp->target = NULL;
- btrace_clear (tp);
- }
- void
- btrace_teardown (struct thread_info *tp)
- {
- struct btrace_thread_info *btp = &tp->btrace;
- int errcode = 0;
- if (btp->target == NULL)
- return;
- DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
- target_teardown_btrace (btp->target);
- btp->target = NULL;
- btrace_clear (tp);
- }
- static int
- btrace_stitch_trace (VEC (btrace_block_s) **btrace,
- const struct btrace_thread_info *btinfo)
- {
- struct btrace_function *last_bfun;
- struct btrace_insn *last_insn;
- btrace_block_s *first_new_block;
-
- if (VEC_empty (btrace_block_s, *btrace))
- return 0;
- last_bfun = btinfo->end;
- gdb_assert (last_bfun != NULL);
-
- first_new_block = VEC_last (btrace_block_s, *btrace);
- last_insn = VEC_last (btrace_insn_s, last_bfun->insn);
-
- if (first_new_block->end == last_insn->pc
- && VEC_length (btrace_block_s, *btrace) == 1)
- {
- VEC_pop (btrace_block_s, *btrace);
- return 0;
- }
- DEBUG ("stitching %s to %s", ftrace_print_insn_addr (last_insn),
- core_addr_to_string_nz (first_new_block->end));
-
- if (first_new_block->end < last_insn->pc)
- {
- warning (_("Error while trying to read delta trace. Falling back to "
- "a full read."));
- return -1;
- }
-
- gdb_assert (first_new_block->begin == 0);
- first_new_block->begin = last_insn->pc;
-
- DEBUG ("pruning insn at %s for stitching",
- ftrace_print_insn_addr (last_insn));
- VEC_pop (btrace_insn_s, last_bfun->insn);
-
- return 0;
- }
- static void
- btrace_clear_history (struct btrace_thread_info *btinfo)
- {
- xfree (btinfo->insn_history);
- xfree (btinfo->call_history);
- xfree (btinfo->replay);
- btinfo->insn_history = NULL;
- btinfo->call_history = NULL;
- btinfo->replay = NULL;
- }
- void
- btrace_fetch (struct thread_info *tp)
- {
- struct btrace_thread_info *btinfo;
- struct btrace_target_info *tinfo;
- VEC (btrace_block_s) *btrace;
- struct cleanup *cleanup;
- int errcode;
- DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
- btrace = NULL;
- btinfo = &tp->btrace;
- tinfo = btinfo->target;
- if (tinfo == NULL)
- return;
-
- if (btinfo->replay != NULL)
- return;
- cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
-
- if (btinfo->end != NULL)
- {
- errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_DELTA);
- if (errcode == 0)
- {
-
- errcode = btrace_stitch_trace (&btrace, btinfo);
- }
- else
- {
-
- errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_NEW);
-
- if (errcode == 0 && !VEC_empty (btrace_block_s, btrace))
- btrace_clear (tp);
- }
-
- if (errcode != 0)
- {
- btrace_clear (tp);
- errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_ALL);
- }
- }
- else
- errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_ALL);
-
- if (errcode != 0)
- error (_("Failed to read branch trace."));
-
- if (!VEC_empty (btrace_block_s, btrace))
- {
- btrace_clear_history (btinfo);
- btrace_compute_ftrace (btinfo, btrace);
- }
- do_cleanups (cleanup);
- }
- void
- btrace_clear (struct thread_info *tp)
- {
- struct btrace_thread_info *btinfo;
- struct btrace_function *it, *trash;
- DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
-
- reinit_frame_cache ();
- btinfo = &tp->btrace;
- it = btinfo->begin;
- while (it != NULL)
- {
- trash = it;
- it = it->flow.next;
- xfree (trash);
- }
- btinfo->begin = NULL;
- btinfo->end = NULL;
- btrace_clear_history (btinfo);
- }
- void
- btrace_free_objfile (struct objfile *objfile)
- {
- struct thread_info *tp;
- DEBUG ("free objfile");
- ALL_NON_EXITED_THREADS (tp)
- btrace_clear (tp);
- }
- #if defined (HAVE_LIBEXPAT)
- static void
- check_xml_btrace_version (struct gdb_xml_parser *parser,
- const struct gdb_xml_element *element,
- void *user_data, VEC (gdb_xml_value_s) *attributes)
- {
- const char *version = xml_find_attribute (attributes, "version")->value;
- if (strcmp (version, "1.0") != 0)
- gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version);
- }
- static void
- parse_xml_btrace_block (struct gdb_xml_parser *parser,
- const struct gdb_xml_element *element,
- void *user_data, VEC (gdb_xml_value_s) *attributes)
- {
- VEC (btrace_block_s) **btrace;
- struct btrace_block *block;
- ULONGEST *begin, *end;
- btrace = user_data;
- block = VEC_safe_push (btrace_block_s, *btrace, NULL);
- begin = xml_find_attribute (attributes, "begin")->value;
- end = xml_find_attribute (attributes, "end")->value;
- block->begin = *begin;
- block->end = *end;
- }
- static const struct gdb_xml_attribute block_attributes[] = {
- { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
- { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
- { NULL, GDB_XML_AF_NONE, NULL, NULL }
- };
- static const struct gdb_xml_attribute btrace_attributes[] = {
- { "version", GDB_XML_AF_NONE, NULL, NULL },
- { NULL, GDB_XML_AF_NONE, NULL, NULL }
- };
- static const struct gdb_xml_element btrace_children[] = {
- { "block", block_attributes, NULL,
- GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL },
- { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
- };
- static const struct gdb_xml_element btrace_elements[] = {
- { "btrace", btrace_attributes, btrace_children, GDB_XML_EF_NONE,
- check_xml_btrace_version, NULL },
- { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
- };
- #endif
- VEC (btrace_block_s) *
- parse_xml_btrace (const char *buffer)
- {
- VEC (btrace_block_s) *btrace = NULL;
- struct cleanup *cleanup;
- int errcode;
- #if defined (HAVE_LIBEXPAT)
- cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
- errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements,
- buffer, &btrace);
- if (errcode != 0)
- error (_("Error parsing branch trace."));
-
- discard_cleanups (cleanup);
- #else
- error (_("Cannot process branch trace. XML parsing is not supported."));
- #endif
- return btrace;
- }
- const struct btrace_insn *
- btrace_insn_get (const struct btrace_insn_iterator *it)
- {
- const struct btrace_function *bfun;
- unsigned int index, end;
- index = it->index;
- bfun = it->function;
-
- end = VEC_length (btrace_insn_s, bfun->insn);
- gdb_assert (0 < end);
- gdb_assert (index < end);
- return VEC_index (btrace_insn_s, bfun->insn, index);
- }
- unsigned int
- btrace_insn_number (const struct btrace_insn_iterator *it)
- {
- const struct btrace_function *bfun;
- bfun = it->function;
- return bfun->insn_offset + it->index;
- }
- void
- btrace_insn_begin (struct btrace_insn_iterator *it,
- const struct btrace_thread_info *btinfo)
- {
- const struct btrace_function *bfun;
- bfun = btinfo->begin;
- if (bfun == NULL)
- error (_("No trace."));
- it->function = bfun;
- it->index = 0;
- }
- void
- btrace_insn_end (struct btrace_insn_iterator *it,
- const struct btrace_thread_info *btinfo)
- {
- const struct btrace_function *bfun;
- unsigned int length;
- bfun = btinfo->end;
- if (bfun == NULL)
- error (_("No trace."));
-
- length = VEC_length (btrace_insn_s, bfun->insn);
- it->function = bfun;
- it->index = length - 1;
- }
- unsigned int
- btrace_insn_next (struct btrace_insn_iterator *it, unsigned int stride)
- {
- const struct btrace_function *bfun;
- unsigned int index, steps;
- bfun = it->function;
- steps = 0;
- index = it->index;
- while (stride != 0)
- {
- unsigned int end, space, adv;
- end = VEC_length (btrace_insn_s, bfun->insn);
- gdb_assert (0 < end);
- gdb_assert (index < end);
-
- space = end - index;
-
- adv = min (space, stride);
- stride -= adv;
- index += adv;
- steps += adv;
-
- if (index == end)
- {
- const struct btrace_function *next;
- next = bfun->flow.next;
- if (next == NULL)
- {
-
- index -= 1;
- steps -= 1;
- break;
- }
-
- bfun = next;
- index = 0;
- }
-
- gdb_assert (adv > 0);
- }
-
- it->function = bfun;
- it->index = index;
- return steps;
- }
- unsigned int
- btrace_insn_prev (struct btrace_insn_iterator *it, unsigned int stride)
- {
- const struct btrace_function *bfun;
- unsigned int index, steps;
- bfun = it->function;
- steps = 0;
- index = it->index;
- while (stride != 0)
- {
- unsigned int adv;
-
- if (index == 0)
- {
- const struct btrace_function *prev;
- prev = bfun->flow.prev;
- if (prev == NULL)
- break;
-
- bfun = prev;
- index = VEC_length (btrace_insn_s, bfun->insn);
-
- gdb_assert (index > 0);
- }
-
- adv = min (index, stride);
- stride -= adv;
- index -= adv;
- steps += adv;
-
- gdb_assert (adv > 0);
- }
-
- it->function = bfun;
- it->index = index;
- return steps;
- }
- int
- btrace_insn_cmp (const struct btrace_insn_iterator *lhs,
- const struct btrace_insn_iterator *rhs)
- {
- unsigned int lnum, rnum;
- lnum = btrace_insn_number (lhs);
- rnum = btrace_insn_number (rhs);
- return (int) (lnum - rnum);
- }
- int
- btrace_find_insn_by_number (struct btrace_insn_iterator *it,
- const struct btrace_thread_info *btinfo,
- unsigned int number)
- {
- const struct btrace_function *bfun;
- unsigned int end;
- for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
- if (bfun->insn_offset <= number)
- break;
- if (bfun == NULL)
- return 0;
- end = bfun->insn_offset + VEC_length (btrace_insn_s, bfun->insn);
- if (end <= number)
- return 0;
- it->function = bfun;
- it->index = number - bfun->insn_offset;
- return 1;
- }
- const struct btrace_function *
- btrace_call_get (const struct btrace_call_iterator *it)
- {
- return it->function;
- }
- unsigned int
- btrace_call_number (const struct btrace_call_iterator *it)
- {
- const struct btrace_thread_info *btinfo;
- const struct btrace_function *bfun;
- unsigned int insns;
- btinfo = it->btinfo;
- bfun = it->function;
- if (bfun != NULL)
- return bfun->number;
-
- bfun = btinfo->end;
- insns = VEC_length (btrace_insn_s, bfun->insn);
-
- if (insns == 1)
- return bfun->number;
-
- return bfun->number + 1;
- }
- void
- btrace_call_begin (struct btrace_call_iterator *it,
- const struct btrace_thread_info *btinfo)
- {
- const struct btrace_function *bfun;
- bfun = btinfo->begin;
- if (bfun == NULL)
- error (_("No trace."));
- it->btinfo = btinfo;
- it->function = bfun;
- }
- void
- btrace_call_end (struct btrace_call_iterator *it,
- const struct btrace_thread_info *btinfo)
- {
- const struct btrace_function *bfun;
- bfun = btinfo->end;
- if (bfun == NULL)
- error (_("No trace."));
- it->btinfo = btinfo;
- it->function = NULL;
- }
- unsigned int
- btrace_call_next (struct btrace_call_iterator *it, unsigned int stride)
- {
- const struct btrace_function *bfun;
- unsigned int steps;
- bfun = it->function;
- steps = 0;
- while (bfun != NULL)
- {
- const struct btrace_function *next;
- unsigned int insns;
- next = bfun->flow.next;
- if (next == NULL)
- {
-
- insns = VEC_length (btrace_insn_s, bfun->insn);
- if (insns == 1)
- steps -= 1;
- }
- if (stride == steps)
- break;
- bfun = next;
- steps += 1;
- }
- it->function = bfun;
- return steps;
- }
- unsigned int
- btrace_call_prev (struct btrace_call_iterator *it, unsigned int stride)
- {
- const struct btrace_thread_info *btinfo;
- const struct btrace_function *bfun;
- unsigned int steps;
- bfun = it->function;
- steps = 0;
- if (bfun == NULL)
- {
- unsigned int insns;
- btinfo = it->btinfo;
- bfun = btinfo->end;
- if (bfun == NULL)
- return 0;
-
- insns = VEC_length (btrace_insn_s, bfun->insn);
- if (insns == 1)
- bfun = bfun->flow.prev;
- if (bfun == NULL)
- return 0;
- steps += 1;
- }
- while (steps < stride)
- {
- const struct btrace_function *prev;
- prev = bfun->flow.prev;
- if (prev == NULL)
- break;
- bfun = prev;
- steps += 1;
- }
- it->function = bfun;
- return steps;
- }
- int
- btrace_call_cmp (const struct btrace_call_iterator *lhs,
- const struct btrace_call_iterator *rhs)
- {
- unsigned int lnum, rnum;
- lnum = btrace_call_number (lhs);
- rnum = btrace_call_number (rhs);
- return (int) (lnum - rnum);
- }
- int
- btrace_find_call_by_number (struct btrace_call_iterator *it,
- const struct btrace_thread_info *btinfo,
- unsigned int number)
- {
- const struct btrace_function *bfun;
- for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
- {
- unsigned int bnum;
- bnum = bfun->number;
- if (number == bnum)
- {
- it->btinfo = btinfo;
- it->function = bfun;
- return 1;
- }
-
- }
- return 0;
- }
- void
- btrace_set_insn_history (struct btrace_thread_info *btinfo,
- const struct btrace_insn_iterator *begin,
- const struct btrace_insn_iterator *end)
- {
- if (btinfo->insn_history == NULL)
- btinfo->insn_history = xzalloc (sizeof (*btinfo->insn_history));
- btinfo->insn_history->begin = *begin;
- btinfo->insn_history->end = *end;
- }
- void
- btrace_set_call_history (struct btrace_thread_info *btinfo,
- const struct btrace_call_iterator *begin,
- const struct btrace_call_iterator *end)
- {
- gdb_assert (begin->btinfo == end->btinfo);
- if (btinfo->call_history == NULL)
- btinfo->call_history = xzalloc (sizeof (*btinfo->call_history));
- btinfo->call_history->begin = *begin;
- btinfo->call_history->end = *end;
- }
- int
- btrace_is_replaying (struct thread_info *tp)
- {
- return tp->btrace.replay != NULL;
- }
- int
- btrace_is_empty (struct thread_info *tp)
- {
- struct btrace_insn_iterator begin, end;
- struct btrace_thread_info *btinfo;
- btinfo = &tp->btrace;
- if (btinfo->begin == NULL)
- return 1;
- btrace_insn_begin (&begin, btinfo);
- btrace_insn_end (&end, btinfo);
- return btrace_insn_cmp (&begin, &end) == 0;
- }