This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 07/11] [SQUASH] btrace: Adjust struct btrace_function::up.
- From: Tim Wiederhake <tim dot wiederhake at intel dot com>
- To: gdb-patches at sourceware dot org
- Cc: markus dot t dot metzger at intel dot com
- Date: Fri, 17 Feb 2017 14:26:25 +0100
- Subject: [PATCH 07/11] [SQUASH] btrace: Adjust struct btrace_function::up.
- Authentication-results: sourceware.org; auth=none
- References: <1487337989-6367-1-git-send-email-tim.wiederhake@intel.com>
This patch stands alone for easier review and is meant to be squashed together
for committing. ChangeLog will be added to the squashed commit.
2017-02-17 Tim Wiederhake <tim.wiederhake@intel.com>
---
gdb/btrace.c | 138 ++++++++++++++++++++++++------------------
gdb/btrace.h | 6 +-
gdb/python/py-record-btrace.c | 4 +-
gdb/record-btrace.c | 18 +++---
4 files changed, 97 insertions(+), 69 deletions(-)
diff --git a/gdb/btrace.c b/gdb/btrace.c
index cc22737..880a703 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -156,6 +156,16 @@ ftrace_call_num_insn (const struct btrace_function* bfun)
return VEC_length (btrace_insn_s, bfun->insn);
}
+static struct btrace_function *
+ftrace_find_call_by_number (const struct btrace_thread_info *btinfo,
+ unsigned int number)
+{
+ if (number == 0 || number > VEC_length (btrace_fun_s, btinfo->functions))
+ return NULL;
+
+ return VEC_index (btrace_fun_s, btinfo->functions, number - 1);
+}
+
/* Return non-zero if BFUN does not match MFUN and FUN,
return zero otherwise. */
@@ -249,10 +259,10 @@ ftrace_update_caller (struct btrace_function *bfun,
struct btrace_function *caller,
enum btrace_function_flag flags)
{
- if (bfun->up != NULL)
+ if (bfun->up != 0)
ftrace_debug (bfun, "updating caller");
- bfun->up = caller;
+ bfun->up = caller->number;
bfun->flags = flags;
ftrace_debug (bfun, "set caller");
@@ -287,10 +297,10 @@ ftrace_new_call (struct btrace_thread_info *btinfo,
struct minimal_symbol *mfun,
struct symbol *fun)
{
- struct btrace_function *bfun;
+ const unsigned int last = VEC_length (btrace_fun_s, btinfo->functions);
+ struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun);
- bfun = ftrace_new_function (btinfo, mfun, fun);
- bfun->up = btinfo->end;
+ bfun->up = last;
bfun->level += 1;
ftrace_debug (bfun, "new call");
@@ -306,10 +316,10 @@ ftrace_new_tailcall (struct btrace_thread_info *btinfo,
struct minimal_symbol *mfun,
struct symbol *fun)
{
- struct btrace_function *bfun;
+ const unsigned int last = VEC_length (btrace_fun_s, btinfo->functions);
+ struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun);
- bfun = ftrace_new_function (btinfo, mfun, fun);
- bfun->up = btinfo->end;
+ bfun->up = last;
bfun->level += 1;
bfun->flags |= BFUN_UP_LINKS_TO_TAILCALL;
@@ -321,57 +331,58 @@ ftrace_new_tailcall (struct btrace_thread_info *btinfo,
/* Return the caller of BFUN or NULL if there is none. This function skips
tail calls in the call chain. */
static struct btrace_function *
-ftrace_get_caller (struct btrace_function *bfun)
+ftrace_get_caller (struct btrace_thread_info *btinfo,
+ struct btrace_function *bfun)
{
- for (; bfun != NULL; bfun = bfun->up)
+ for (; bfun != NULL; bfun = ftrace_find_call_by_number (btinfo, bfun->up))
if ((bfun->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0)
- return bfun->up;
+ return ftrace_find_call_by_number (btinfo, bfun->up);
return NULL;
}
-/* Find the innermost caller in the back trace of BFUN with MFUN/FUN
- symbol information. */
+/* Find the innermost caller with MFUN/FUN symbol information in the back trace
+ of the function call segment with number NUMBER. */
static struct btrace_function *
ftrace_find_caller (struct btrace_thread_info *btinfo,
- struct btrace_function *bfun,
+ unsigned int number,
struct minimal_symbol *mfun,
struct symbol *fun)
{
- for (; bfun != NULL; bfun = bfun->up)
+ struct btrace_function *bfun;
+
+ while ((bfun = ftrace_find_call_by_number (btinfo, number)) != NULL)
{
- /* Skip functions with incompatible symbol information. */
- if (ftrace_function_switched (bfun, mfun, fun))
- continue;
+ if (!ftrace_function_switched (bfun, mfun, fun))
+ break;
- /* This is the function segment we're looking for. */
- break;
+ number = bfun->up;
}
return bfun;
}
-/* Find the innermost caller in the back trace of BFUN, skipping all
- function segments that do not end with a call instruction (e.g.
- tail calls ending with a jump). */
+/* Find the innermost caller in the back trace of the function call segment
+ with number NUMBER, skipping all function call segments that do not end
+ with a call instruction (e.g. tail calls ending with a jump). */
static struct btrace_function *
-ftrace_find_call (struct btrace_thread_info *btinfo,
- struct btrace_function *bfun)
+ftrace_find_call (struct btrace_thread_info *btinfo, unsigned int number)
{
- for (; bfun != NULL; bfun = bfun->up)
- {
- struct btrace_insn *last;
+ struct btrace_function *bfun;
- /* Skip gaps. */
- if (bfun->errcode != 0)
- continue;
+ while ((bfun = ftrace_find_call_by_number (btinfo, number)) != NULL)
+ {
+ if (bfun->errcode == 0)
+ {
+ struct btrace_insn *last = VEC_last (btrace_insn_s, bfun->insn);
- last = VEC_last (btrace_insn_s, bfun->insn);
+ if (last->iclass == BTRACE_INSN_CALL)
+ break;
+ }
- if (last->iclass == BTRACE_INSN_CALL)
- break;
+ number = bfun->up;
}
return bfun;
@@ -425,8 +436,9 @@ ftrace_new_return (struct btrace_thread_info *btinfo,
/* Let's find the topmost function and add a new caller for it.
This should handle a series of initial tail calls. */
- while (prev->up != NULL)
- prev = prev->up;
+ for (caller = prev; caller != NULL;
+ caller = ftrace_find_call_by_number (btinfo, prev->up))
+ prev = caller;
bfun->level = prev->level - 1;
@@ -446,7 +458,7 @@ ftrace_new_return (struct btrace_thread_info *btinfo,
on the same level as they are.
This should handle things like schedule () correctly where we're
switching contexts. */
- prev->up = bfun;
+ prev->up = bfun->number;
prev->flags = BFUN_UP_LINKS_TO_RET;
ftrace_debug (bfun, "new return - unknown caller");
@@ -649,7 +661,8 @@ ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
match. */
static int
-ftrace_match_backtrace (struct btrace_function *lhs,
+ftrace_match_backtrace (struct btrace_thread_info *btinfo,
+ struct btrace_function *lhs,
struct btrace_function *rhs)
{
int matches;
@@ -659,8 +672,8 @@ ftrace_match_backtrace (struct btrace_function *lhs,
if (ftrace_function_switched (lhs, rhs->msym, rhs->sym))
return 0;
- lhs = ftrace_get_caller (lhs);
- rhs = ftrace_get_caller (rhs);
+ lhs = ftrace_get_caller (btinfo, lhs);
+ rhs = ftrace_get_caller (btinfo, rhs);
}
return matches;
@@ -735,20 +748,26 @@ ftrace_connect_bfun (struct btrace_thread_info *btinfo,
ftrace_fixup_level (next, prev->level - next->level);
/* If we run out of back trace for one, let's use the other's. */
- if (prev->up == NULL)
+ if (prev->up == 0)
{
- if (next->up != NULL)
+ btrace_function_flags flags = next->flags;
+
+ next = ftrace_find_call_by_number (btinfo, next->up);
+ if (next != NULL)
{
DEBUG_FTRACE ("using next's callers");
- ftrace_fixup_caller (btinfo, prev, next->up, next->flags);
+ ftrace_fixup_caller (btinfo, prev, next, flags);
}
}
- else if (next->up == NULL)
+ else if (next->up == 0)
{
- if (prev->up != NULL)
+ btrace_function_flags flags = prev->flags;
+
+ prev = ftrace_find_call_by_number (btinfo, prev->up);
+ if (prev != NULL)
{
DEBUG_FTRACE ("using prev's callers");
- ftrace_fixup_caller (btinfo, next, prev->up, prev->flags);
+ ftrace_fixup_caller (btinfo, next, prev, flags);
}
}
else
@@ -766,26 +785,27 @@ ftrace_connect_bfun (struct btrace_thread_info *btinfo,
if ((prev->flags & BFUN_UP_LINKS_TO_TAILCALL) != 0)
{
struct btrace_function *caller;
- btrace_function_flags flags;
+ btrace_function_flags flags = prev->flags;
/* We checked NEXT->UP above so CALLER can't be NULL. */
- caller = next->up;
- flags = next->flags;
+ caller = ftrace_find_call_by_number (btinfo, next->up);
DEBUG_FTRACE ("adding prev's tail calls to next");
- ftrace_fixup_caller (btinfo, next, prev->up, prev->flags);
+ prev = ftrace_find_call_by_number (btinfo, prev->up);
+ ftrace_fixup_caller (btinfo, next, prev, flags);
- for (prev = prev->up; prev != NULL; prev = prev->up)
+ for (; prev != NULL;
+ prev = ftrace_find_call_by_number (btinfo, prev->up))
{
/* At the end of PREV's back trace, continue with CALLER. */
- if (prev->up == NULL)
+ if (prev->up == 0)
{
DEBUG_FTRACE ("fixing up link for tailcall chain");
ftrace_debug (prev, "..top");
ftrace_debug (caller, "..up");
- ftrace_fixup_caller (btinfo, prev, caller, flags);
+ ftrace_fixup_caller (btinfo, prev, caller, next->flags);
/* If we skipped any tail calls, this may move CALLER to a
different function level.
@@ -830,8 +850,8 @@ ftrace_connect_backtrace (struct btrace_thread_info *btinfo,
prev = lhs;
next = rhs;
- lhs = ftrace_get_caller (lhs);
- rhs = ftrace_get_caller (rhs);
+ lhs = ftrace_get_caller (btinfo, lhs);
+ rhs = ftrace_get_caller (btinfo, rhs);
ftrace_connect_bfun (btinfo, prev, next);
}
@@ -860,12 +880,14 @@ ftrace_bridge_gap (struct btrace_thread_info *btinfo,
/* We search the back traces of LHS and RHS for valid connections and connect
the two functon segments that give the longest combined back trace. */
- for (cand_l = lhs; cand_l != NULL; cand_l = ftrace_get_caller (cand_l))
- for (cand_r = rhs; cand_r != NULL; cand_r = ftrace_get_caller (cand_r))
+ for (cand_l = lhs; cand_l != NULL;
+ cand_l = ftrace_get_caller (btinfo, cand_l))
+ for (cand_r = rhs; cand_r != NULL;
+ cand_r = ftrace_get_caller (btinfo, cand_r))
{
int matches;
- matches = ftrace_match_backtrace (cand_l, cand_r);
+ matches = ftrace_match_backtrace (btinfo, cand_l, cand_r);
if (best_matches < matches)
{
best_matches = matches;
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 92435e7..2b28ff8 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -152,8 +152,10 @@ struct btrace_function
/* The previous and next function in control flow order. */
struct btrace_func_link flow;
- /* The directly preceding function segment in a (fake) call stack. */
- struct btrace_function *up;
+ /* The function segment number of the directly preceding function segment in
+ a (fake) call stack. Will be zero if there is no such function segment in
+ the record. */
+ unsigned int up;
/* The instructions in this function segment.
The instruction vector will be empty if the function segment
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 6158f31..14ad5b7 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -456,10 +456,10 @@ btpy_call_up (PyObject *self, void *closure)
if (func == NULL)
Py_RETURN_NONE;
- if (func->up == NULL)
+ if (func->up == 0)
Py_RETURN_NONE;
- return btpy_call_new (obj->ptid, func->up->number);
+ return btpy_call_new (obj->ptid, func->up);
}
/* Implementation of BtraceFunctionCall.prev_sibling [BtraceFunctionCall].
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 87fbcba..791963c 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1584,7 +1584,7 @@ record_btrace_frame_unwind_stop_reason (struct frame_info *this_frame,
bfun = cache->bfun;
gdb_assert (bfun != NULL);
- if (bfun->up == NULL)
+ if (bfun->up == 0)
return UNWIND_UNAVAILABLE;
return UNWIND_NO_REASON;
@@ -1643,11 +1643,12 @@ record_btrace_frame_prev_register (struct frame_info *this_frame,
bfun = cache->bfun;
gdb_assert (bfun != NULL);
- caller = bfun->up;
- if (caller == NULL)
+ if (bfun->up == 0)
throw_error (NOT_AVAILABLE_ERROR,
_("No caller in btrace record history"));
+ caller = VEC_index (btrace_fun_s, cache->tp->btrace.functions, bfun->up - 1);
+
if ((bfun->flags & BFUN_UP_LINKS_TO_RET) != 0)
{
insn = VEC_index (btrace_insn_s, caller->insn, 0);
@@ -1701,7 +1702,7 @@ record_btrace_frame_sniffer (const struct frame_unwind *self,
callee = btrace_get_frame_function (next);
if (callee != NULL && (callee->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0)
- bfun = callee->up;
+ bfun = VEC_index (btrace_fun_s, tp->btrace.functions, callee->up - 1);
}
if (bfun == NULL)
@@ -1728,6 +1729,7 @@ record_btrace_tailcall_frame_sniffer (const struct frame_unwind *self,
{
const struct btrace_function *bfun, *callee;
struct btrace_frame_cache *cache;
+ struct thread_info *tinfo;
struct frame_info *next;
next = get_next_frame (this_frame);
@@ -1741,16 +1743,18 @@ record_btrace_tailcall_frame_sniffer (const struct frame_unwind *self,
if ((callee->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0)
return 0;
- bfun = callee->up;
- if (bfun == NULL)
+ if (callee->up == 0)
return 0;
+ tinfo = find_thread_ptid (inferior_ptid);
+ bfun = VEC_index (btrace_fun_s, tinfo->btrace.functions, callee->up - 1);
+
DEBUG ("[frame] sniffed tailcall frame for %s on level %d",
btrace_get_bfun_name (bfun), bfun->level);
/* This is our frame. Initialize the frame cache. */
cache = bfcache_new (this_frame);
- cache->tp = find_thread_ptid (inferior_ptid);
+ cache->tp = tinfo;
cache->bfun = bfun;
*this_cache = cache;
--
2.7.4