summaryrefslogtreecommitdiff
path: root/gdb/btrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/btrace.c')
-rw-r--r--gdb/btrace.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 445f0a4c16..10b6db47ee 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -387,16 +387,12 @@ ftrace_new_return (struct btrace_function *prev,
/* There is no call in PREV's back trace. We assume that the
branch trace did not include it. */
- /* Let's find the topmost call function - this skips tail calls. */
+ /* 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;
- /* We maintain levels for a series of returns for which we have
- not seen the calls.
- We start at the preceding function's level in case this has
- already been a return for which we have not seen the call.
- We start at level 0 otherwise, to handle tail calls correctly. */
- bfun->level = std::min (0, prev->level) - 1;
+ bfun->level = prev->level - 1;
/* Fix up the call stack for PREV. */
ftrace_fixup_caller (prev, bfun, BFUN_UP_LINKS_TO_RET);
@@ -406,8 +402,16 @@ ftrace_new_return (struct btrace_function *prev,
else
{
/* There is a call in PREV's back trace to which we should have
- returned. Let's remain at this level. */
- bfun->level = prev->level;
+ returned but didn't. Let's start a new, separate back trace
+ from PREV's level. */
+ bfun->level = prev->level - 1;
+
+ /* We fix up the back trace for PREV but leave other function segments
+ on the same level as they are.
+ This should handle things like schedule () correctly where we're
+ switching contexts. */
+ prev->up = bfun;
+ prev->flags = BFUN_UP_LINKS_TO_RET;
ftrace_debug (bfun, "new return - unknown caller");
}