This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch v3 23/23] record-btrace: skip tail calls in back trace
- From: Markus Metzger <markus dot t dot metzger at intel dot com>
- To: jan dot kratochvil at redhat dot com
- Cc: gdb-patches at sourceware dot org
- Date: Mon, 10 Jun 2013 10:04:56 +0200
- Subject: [patch v3 23/23] record-btrace: skip tail calls in back trace
- References: <1370851496-32313-1-git-send-email-markus dot t dot metzger at intel dot com>
The branch trace represents the caller/callee relationship of tail calls. The
caller of a tail call is shown in the back trace and in the function-call
history.
This is not consistent with GDB's normal behavior, where the tail caller is not
shown in the back trace.
It further causes the finish command to fail for tail calls.
This patch skips tail calls when computing the back trace during replay. The
finish command now works also for tail calls.
The tail caller is still shown in the function-call history.
I'm not sure which is the better behavior. I liked seeing the tail caller in
the call stack and I'm not using the finish command very often. On the other
hand, reverse/replay should be as close to live debugging as possible.
2013-06-10 Markus Metzger <markus.t.metzger@intel.com>
* record-btrace.c (record_btrace_frame_sniffer): Skip tail calls.
testsuite/
* gdb.btrace/tailcall.exp: Update. Add stepping tests.
---
gdb/record-btrace.c | 13 ++++++++-----
gdb/testsuite/gdb.btrace/tailcall.exp | 25 +++++++++++++++++++++----
2 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 14791da..ee7a81e 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1119,6 +1119,13 @@ record_btrace_frame_sniffer (const struct frame_unwind *self,
caller = bfun->up;
pc = 0;
+ /* Skip tail calls. */
+ while (caller != NULL && (bfun->flags & BFUN_UP_LINKS_TO_TAILCALL) != 0)
+ {
+ bfun = caller;
+ caller = bfun->up;
+ }
+
/* Determine where to find the PC in the upper function segment. */
if (caller != NULL)
{
@@ -1132,11 +1139,7 @@ record_btrace_frame_sniffer (const struct frame_unwind *self,
insn = VEC_last (btrace_insn_s, caller->insn);
pc = insn->pc;
- /* We link directly to the jump instruction in the case of a tail
- call, since the next instruction will likely be outside of the
- caller function. */
- if ((bfun->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0)
- pc += gdb_insn_length (get_frame_arch (this_frame), pc);
+ pc += gdb_insn_length (get_frame_arch (this_frame), pc);
}
DEBUG ("[frame] sniffed frame for %s on level %d",
diff --git a/gdb/testsuite/gdb.btrace/tailcall.exp b/gdb/testsuite/gdb.btrace/tailcall.exp
index 5cadee0..df8d66a 100644
--- a/gdb/testsuite/gdb.btrace/tailcall.exp
+++ b/gdb/testsuite/gdb.btrace/tailcall.exp
@@ -57,12 +57,29 @@ gdb_test "record goto 4" "
# check the backtrace
gdb_test "backtrace" "
#0.*bar.*at .*x86-tailcall.c:24.*\r
-#1.*foo.*at .*x86-tailcall.c:29.*\r
-#2.*main.*at .*x86-tailcall.c:37.*\r
+#1.*main.*at .*x86-tailcall.c:37.*\r
Backtrace stopped: not enough registers or memory available to unwind further" "backtrace in bar"
# walk the backtrace
gdb_test "up" "
-.*foo \\(\\) at .*x86-tailcall.c:29.*" "up to foo"
-gdb_test "up" "
.*main \\(\\) at .*x86-tailcall.c:37.*" "up to main"
+gdb_test "down" "
+#0.*bar.*at .*x86-tailcall.c:24.*" "down to bar"
+
+# test stepping into and out of tailcalls.
+gdb_test "finish" "
+.*main.*at .*x86-tailcall.c:37.*" "step, 1.1"
+gdb_test "reverse-step" "
+.*bar.*at .*x86-tailcall.c:24.*" "step, 1.2"
+gdb_test "reverse-finish" "
+.*foo \\(\\) at .*x86-tailcall.c:29.*" "step, 1.3"
+gdb_test "reverse-step" "
+.*main.*at .*x86-tailcall.c:37.*" "step, 1.4"
+gdb_test "next" "
+.*main.*at .*x86-tailcall.c:39.*" "step, 1.5"
+gdb_test "reverse-next" "
+.*main.*at .*x86-tailcall.c:37.*" "step, 1.6"
+gdb_test "step" "
+.*foo \\(\\) at .*x86-tailcall.c:29.*" "step, 1.7"
+gdb_test "finish" "
+.*main.*at .*x86-tailcall.c:37.*" "step, 1.8"
--
1.7.1