summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2014-01-29 12:56:09 +0100
committerMarkus Metzger <markus.t.metzger@intel.com>2015-02-09 09:46:49 +0100
commit7d5c24b3ae60b6cfa41ebf9329b2f7832053b0f6 (patch)
tree3eb45782a6a59d4d86ebef71ec5716b170754ce1
parent76235df10b96f85815d799b586a6bb32bc89c90f (diff)
downloadbinutils-gdb-7d5c24b3ae60b6cfa41ebf9329b2f7832053b0f6.tar.gz
btrace: extend struct btrace_insn
Add the instruction's size as well as a coarse classification to struct btrace_insn. Use the information in ftrace_update_function and ftrace_find_call. 2015-02-09 Markus Metzger <markus.t.metzger@intel.com> * btrace.h (btrace_insn_class): New. (btrace_insn) <size, iclass>: New. * btrace.c (ftrace_find_call): Update parameters. Update users. Use instruction classification. (ftrace_new_return): Update parameters. Update users. (ftrace_update_function): Update parameters. Update users. Use instruction classification. (ftrace_update_insns): Update parameters. Update users. (ftrace_classify_insn): New. (btrace_compute_ftrace_bts): Fill in new btrace_insn fields. Add TRY_CATCH around call to gdb_insn_length.
-rw-r--r--gdb/ChangeLog14
-rw-r--r--gdb/btrace.c111
-rw-r--r--gdb/btrace.h22
3 files changed, 97 insertions, 50 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b0a09083ad4..40c6a516b8c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,19 @@
2015-02-09 Markus Metzger <markus.t.metzger@intel.com>
+ * btrace.h (btrace_insn_class): New.
+ (btrace_insn) <size, iclass>: New.
+ * btrace.c (ftrace_find_call): Update parameters. Update users.
+ Use instruction classification.
+ (ftrace_new_return): Update parameters. Update users.
+ (ftrace_update_function): Update parameters. Update users. Use
+ instruction classification.
+ (ftrace_update_insns): Update parameters. Update users.
+ (ftrace_classify_insn): New.
+ (btrace_compute_ftrace_bts): Fill in new btrace_insn fields. Add
+ TRY_CATCH around call to gdb_insn_length.
+
+2015-02-09 Markus Metzger <markus.t.metzger@intel.com>
+
* btrace.c (btrace_compute_ftrace_bts, btrace_compute_ftrace):
Update parameters. Update users.
diff --git a/gdb/btrace.c b/gdb/btrace.c
index e96499eaf1b..72e85670d1d 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -330,20 +330,18 @@ ftrace_find_caller (struct btrace_function *bfun,
tail calls ending with a jump). */
static struct btrace_function *
-ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
+ftrace_find_call (struct btrace_function *bfun)
{
for (; bfun != NULL; bfun = bfun->up)
{
struct btrace_insn *last;
- CORE_ADDR pc;
/* We do not allow empty function segments. */
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))
+ if (last->iclass == BTRACE_INSN_CALL)
break;
}
@@ -355,8 +353,7 @@ ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
MFUN and FUN are the symbol information we have for this function. */
static struct btrace_function *
-ftrace_new_return (struct gdbarch *gdbarch,
- struct btrace_function *prev,
+ftrace_new_return (struct btrace_function *prev,
struct minimal_symbol *mfun,
struct symbol *fun)
{
@@ -391,7 +388,7 @@ ftrace_new_return (struct gdbarch *gdbarch,
wrong or that the call is simply not included in the trace. */
/* Let's search for some actual call. */
- caller = ftrace_find_call (gdbarch, prev->up);
+ caller = ftrace_find_call (prev->up);
if (caller == NULL)
{
/* There is no call in PREV's back trace. We assume that the
@@ -454,8 +451,7 @@ ftrace_new_switch (struct btrace_function *prev,
Return the chronologically latest function segment, never NULL. */
static struct btrace_function *
-ftrace_update_function (struct gdbarch *gdbarch,
- struct btrace_function *bfun, CORE_ADDR pc)
+ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc)
{
struct bound_minimal_symbol bmfun;
struct minimal_symbol *mfun;
@@ -485,24 +481,29 @@ ftrace_update_function (struct gdbarch *gdbarch,
if (last != NULL)
{
- CORE_ADDR lpc;
+ switch (last->iclass)
+ {
+ case BTRACE_INSN_RETURN:
+ return ftrace_new_return (bfun, mfun, fun);
- lpc = last->pc;
+ case BTRACE_INSN_CALL:
+ /* Ignore calls to the next instruction. They are used for PIC. */
+ if (last->pc + last->size == pc)
+ break;
- /* Check for returns. */
- if (gdbarch_insn_is_ret (gdbarch, lpc))
- return ftrace_new_return (gdbarch, bfun, mfun, fun);
+ return ftrace_new_call (bfun, mfun, fun);
- /* Check for calls. */
- if (gdbarch_insn_is_call (gdbarch, lpc))
- {
- int size;
+ case BTRACE_INSN_JUMP:
+ {
+ CORE_ADDR start;
- size = gdb_insn_length (gdbarch, lpc);
+ start = get_pc_function_start (pc);
- /* Ignore calls to the next instruction. They are used for PIC. */
- if (lpc + size != pc)
- return ftrace_new_call (bfun, mfun, fun);
+ /* If we can't determine the function for PC, we treat a jump at
+ the end of the block as tail call. */
+ if (start == 0 || start == pc)
+ return ftrace_new_tailcall (bfun, mfun, fun);
+ }
}
}
@@ -514,24 +515,6 @@ ftrace_update_function (struct gdbarch *gdbarch,
ftrace_print_function_name (bfun),
ftrace_print_filename (bfun));
- if (last != NULL)
- {
- CORE_ADDR start, lpc;
-
- start = get_pc_function_start (pc);
-
- /* If we can't determine the function for PC, we treat a jump at
- the end of the block as tail call. */
- if (start == 0)
- start = pc;
-
- lpc = last->pc;
-
- /* Jumps indicate optimized tail calls. */
- if (start == pc && gdbarch_insn_is_jump (gdbarch, lpc))
- return ftrace_new_tailcall (bfun, mfun, fun);
- }
-
return ftrace_new_switch (bfun, mfun, fun);
}
@@ -574,17 +557,37 @@ ftrace_update_lines (struct btrace_function *bfun, CORE_ADDR pc)
/* Add the instruction at PC to BFUN's instructions. */
static void
-ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
+ftrace_update_insns (struct btrace_function *bfun,
+ const struct btrace_insn *insn)
{
- struct btrace_insn *insn;
-
- insn = VEC_safe_push (btrace_insn_s, bfun->insn, NULL);
- insn->pc = pc;
+ VEC_safe_push (btrace_insn_s, bfun->insn, insn);
if (record_debug > 1)
ftrace_debug (bfun, "update insn");
}
+/* Classify the instruction at PC. */
+
+static enum btrace_insn_class
+ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ volatile struct gdb_exception error;
+ enum btrace_insn_class iclass;
+
+ iclass = BTRACE_INSN_OTHER;
+ TRY_CATCH (error, RETURN_MASK_ERROR)
+ {
+ if (gdbarch_insn_is_call (gdbarch, pc))
+ iclass = BTRACE_INSN_CALL;
+ else if (gdbarch_insn_is_ret (gdbarch, pc))
+ iclass = BTRACE_INSN_RETURN;
+ else if (gdbarch_insn_is_jump (gdbarch, pc))
+ iclass = BTRACE_INSN_JUMP;
+ }
+
+ return iclass;
+}
+
/* Compute the function branch trace from BTS trace. */
static void
@@ -616,6 +619,8 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
for (;;)
{
+ volatile struct gdb_exception error;
+ struct btrace_insn insn;
int size;
/* We should hit the end of the block. Warn if we went too far. */
@@ -626,7 +631,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
break;
}
- end = ftrace_update_function (gdbarch, end, pc);
+ end = ftrace_update_function (end, pc);
if (begin == NULL)
begin = end;
@@ -635,16 +640,22 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
if (blk != 0)
level = min (level, end->level);
- ftrace_update_insns (end, pc);
+ size = 0;
+ TRY_CATCH (error, RETURN_MASK_ERROR)
+ size = gdb_insn_length (gdbarch, pc);
+
+ insn.pc = pc;
+ insn.size = size;
+ insn.iclass = ftrace_classify_insn (gdbarch, pc);
+
+ ftrace_update_insns (end, &insn);
ftrace_update_lines (end, pc);
/* We're done once we pushed the instruction at the end. */
if (block->end == pc)
break;
- size = gdb_insn_length (gdbarch, pc);
-
- /* Make sure we terminate if we fail to compute the size. */
+ /* We can't continue if we fail to compute the size. */
if (size <= 0)
{
warning (_("Recorded trace may be incomplete around %s."),
diff --git a/gdb/btrace.h b/gdb/btrace.h
index fde06199729..694d5047855 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -31,6 +31,22 @@
struct thread_info;
struct btrace_function;
+/* A coarse instruction classification. */
+enum btrace_insn_class
+{
+ /* The instruction is something not listed below. */
+ BTRACE_INSN_OTHER,
+
+ /* The instruction is a function call. */
+ BTRACE_INSN_CALL,
+
+ /* The instruction is a function return. */
+ BTRACE_INSN_RETURN,
+
+ /* The instruction is an unconditional jump. */
+ BTRACE_INSN_JUMP
+};
+
/* A branch trace instruction.
This represents a single instruction in a branch trace. */
@@ -38,6 +54,12 @@ struct btrace_insn
{
/* The address of this instruction. */
CORE_ADDR pc;
+
+ /* The size of this instruction in bytes. */
+ gdb_byte size;
+
+ /* The instruction class of this instruction. */
+ enum btrace_insn_class iclass;
};
/* A vector of branch trace instructions. */