summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory LEOCADIE <gregory.leocadie@datadoghq.com>2022-12-08 11:54:29 +0100
committerDave Watson <dade.watson@gmail.com>2023-01-11 08:56:12 -0800
commit8f54c55ea44f1906c23b5f01aea92b548b1e8839 (patch)
tree0cca4806f29ff3227c0e2707bc90e365d10dd0c0
parenta1f3955072af16a3bc9e3c99db6ea73854a170d5 (diff)
downloadlibunwind-8f54c55ea44f1906c23b5f01aea92b548b1e8839.tar.gz
Fix bug + add test
-rw-r--r--src/mi/backtrace.c20
-rw-r--r--tests/Gtest-trace.c59
-rw-r--r--tests/check-namespace.sh.in1
3 files changed, 77 insertions, 3 deletions
diff --git a/src/mi/backtrace.c b/src/mi/backtrace.c
index 00e4de8d..8fea3444 100644
--- a/src/mi/backtrace.c
+++ b/src/mi/backtrace.c
@@ -92,14 +92,28 @@ unw_backtrace2 (void **buffer, int size, unw_context_t* uc2)
if (unlikely (unw_init_local2 (&cursor, &uc, UNW_INIT_SIGNAL_FRAME) < 0))
return 0;
- int n = size;
+ // get the first ip from the context
+ unw_word_t ip;
+
+ if (unw_get_reg (&cursor, UNW_REG_IP, &ip) < 0)
+ return 0;
+ buffer[0] = (void *) (uintptr_t)ip;
+
+ // update buffer info to collect the rest of the IPs
+ buffer = buffer+1;
+ int remaining_size = size-1;
+
+ int n = remaining_size;
+
+ // returns the number of frames collected by tdep_trace or slow_backtrace
+ // and add 1 to it (the one we retrieved above)
if (unlikely (tdep_trace (&cursor, buffer, &n) < 0))
{
- return slow_backtrace (buffer, size, &uc, UNW_INIT_SIGNAL_FRAME);
+ return slow_backtrace (buffer, remaining_size, &uc, UNW_INIT_SIGNAL_FRAME) + 1;
}
- return n;
+ return n + 1;
}
#ifdef CONFIG_WEAK_BACKTRACE
diff --git a/tests/Gtest-trace.c b/tests/Gtest-trace.c
index fa207fca..e0a5d64d 100644
--- a/tests/Gtest-trace.c
+++ b/tests/Gtest-trace.c
@@ -140,6 +140,64 @@ do_backtrace (void)
}
void
+do_backtrace_with_context(void *context)
+{
+ unw_word_t ip;
+ int ret = -UNW_ENOINFO;
+ int depth = 0;
+ int i, m;
+
+ if (verbose)
+ printf ("\tnormal trace:\n");
+
+ if (unw_init_local2 (&cursor, (unw_context_t*)context, UNW_INIT_SIGNAL_FRAME) < 0)
+ panic ("unw_init_local2 failed!\n");
+
+ do
+ {
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ addresses[0][depth] = (void *) ip;
+ }
+ while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
+
+ if (ret < 0)
+ {
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
+ ++num_errors;
+ }
+
+ if (verbose)
+ for (i = 0; i < depth; ++i)
+ printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
+
+ if (verbose)
+ printf ("\n\tvia unw_backtrace2():\n");
+
+ m = unw_backtrace2 (addresses[1], 128, (unw_context_t*)context);
+
+ if (verbose)
+ for (i = 0; i < m; ++i)
+ printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
+
+ if (m != depth+1)
+ {
+ printf ("FAILURE: unw_step() loop and unw_backtrace2() depths differ: %d vs. %d\n", depth, m);
+ ++num_errors;
+ }
+
+ if (m == depth + 1)
+ for (i = 0; i < depth; ++i)
+ /* Allow one in difference in comparison, trace returns adjusted addresses. */
+ if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1)
+ {
+ printf ("FAILURE: unw_step() loop and uwn_backtrace2() addresses differ at %d: %p vs. %p\n",
+ i, addresses[0][i], addresses[1][i]);
+ ++num_errors;
+ }
+}
+
+void
foo (long val UNUSED)
{
do_backtrace ();
@@ -222,6 +280,7 @@ sighandler (int signal, void *siginfo UNUSED, void *context)
printf ("\n");
}
do_backtrace();
+ do_backtrace_with_context(context);
}
int
diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in
index 656e3818..a1b28a7b 100644
--- a/tests/check-namespace.sh.in
+++ b/tests/check-namespace.sh.in
@@ -137,6 +137,7 @@ check_local_unw_abi () {
match unw_backtrace
@CONFIG_WEAK_BACKTRACE_TRUE@match backtrace
+ match unw_backtrace2
case ${plat} in
arm)