[PATCH 5/5] Add frame pointer unwinding for aarch64

Ulf Hermann ulf.hermann@qt.io
Thu Apr 27 14:02:00 GMT 2017


On 04/26/2017 04:33 PM, Mark Wielaard wrote:
> On Tue, 2017-04-25 at 15:38 +0200, Ulf Hermann wrote:
>>> My question is about this "initial frame". In our testcase we don't have
>>> this case since the backtrace starts in a function that has some CFI.
>>> But I assume you have some tests that rely on this behavior.
>>
>> Actually the test I provided does exercise this code. The initial
>> __libc_do_syscall() frame does not have CFI. Only raise() has. You can
>> check that by dropping the code for pc & 0x1.
> 
> Maybe I am using the wrong binaries (exec and core), but for me there is
> no difference.

In fact, with the new binaries there is no difference. I was confused, sorry.

However, if you strip .eh_frame and .eh_frame_hdr from the exe (thus triggering the fp unwinding on the first frame), you will see that it skips sigusr2. At the same time it invents another frame 0x403f40 on the main thread. Apparently pthread_join creates two stack frames. As it correctly unwinds the rest, the latter seemed harmless to me.

With .eh_frame and .eh_frame_hdr:

ulf@zebra:~/dev/build-elfutils/tests$ ./backtrace --core=backtrace.aarch64.fp.core -e backtrace.aarch64.fp.exec
0x400000        0x4a3000        /home/ulf/backtrace.aarch64.fp.exec
0x7fb6380000    0x7fb6381000    linux-vdso.so.1
TID 350:
# 0 0x40583c            raise
# 1 0x401aac - 1        sigusr2
# 2 0x401ba8 - 1        stdarg
# 3 0x401c04 - 1        backtracegen
# 4 0x401c10 - 1        start
# 5 0x402f44 - 1        start_thread
# 6 0x41dc70 - 1        __clone
TID 349:
# 0 0x403fcc            pthread_join
# 1 0x401810 - 1        main
# 2 0x406544 - 1        __libc_start_main
# 3 0x401918 - 1        $x
./backtrace: dwfl_thread_getframes: address out of range

Without .eh_frame and .eh_frame_hdr, code from PATCH V2:

ulf@zebra:~/dev/build-elfutils/tests$ ./backtrace --core=backtrace.aarch64.fp.core -e backtrace.aarch64.fp.stripped 
0x400000        0x4a3000        /home/ulf/backtrace.aarch64.fp.exec
0x7fb6380000    0x7fb6381000    linux-vdso.so.1
TID 350:
# 0 0x40583c            (null)
# 1 0x401aac - 1        (null)
# 2 0x401ba8 - 1        (null)
# 3 0x401c04 - 1        (null)
# 4 0x401c10 - 1        (null)
# 5 0x402f44 - 1        (null)
# 6 0x41dc70 - 1        (null)
./backtrace: dwfl_thread_getframes: address out of range
TID 349:
# 0 0x403fcc            (null)
# 1 0x403f40 - 1        (null)
# 2 0x401810 - 1        (null)
# 3 0x406544 - 1        (null)
# 4 0x401918 - 1        (null)
./backtrace: dwfl_thread_getframes: address out of range

Without .eh_frame and .eh_frame_hdr, without initial frame adjustment:

ulf@zebra:~/dev/build-elfutils/tests$ ./backtrace --core=backtrace.aarch64.fp.core -e backtrace.aarch64.fp.stripped 
0x400000        0x4a3000        /home/ulf/backtrace.aarch64.fp.exec
0x7fb6380000    0x7fb6381000    linux-vdso.so.1
TID 350:
# 0 0x40583c            (null)
# 1 0x401ba8 - 1        (null)
# 2 0x401c04 - 1        (null)
# 3 0x401c10 - 1        (null)
# 4 0x402f44 - 1        (null)
# 5 0x41dc70 - 1        (null)
./backtrace: dwfl_thread_getframes: address out of range
TID 349:
# 0 0x403fcc            (null)
# 1 0x401810 - 1        (null)
# 2 0x406544 - 1        (null)
# 3 0x401918 - 1        (null)
./backtrace: dwfl_thread_getframes: address out of range

You have to drop all the asserts from backtrace.c to actually test this:

diff --git a/tests/backtrace.c b/tests/backtrace.c
index 1ff6353..a910a77 100644
--- a/tests/backtrace.c
+++ b/tests/backtrace.c
@@ -71,14 +71,14 @@ static void
 callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
 		 const char *symname, Dwfl *dwfl)
 {
-  static bool seen_main = false;
+//  static bool seen_main = false;
   if (symname && *symname == '.')
     symname++;
-  if (symname && strcmp (symname, "main") == 0)
-    seen_main = true;
+//  if (symname && strcmp (symname, "main") == 0)
+//    seen_main = true;
   if (pc == 0)
     {
-      assert (seen_main);
+//      assert (seen_main);
       return;
     }
   if (check_tid == 0)
@@ -103,11 +103,11 @@ callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
 	       && (strcmp (symname, "__kernel_vsyscall") == 0
 		   || strcmp (symname, "__libc_do_syscall") == 0))
 	reduce_frameno = true;
-      else
-	assert (symname && strcmp (symname, "raise") == 0);
+//      else
+//	assert (symname && strcmp (symname, "raise") == 0);
       break;
     case 1:
-      assert (symname != NULL && strcmp (symname, "sigusr2") == 0);
+//      assert (symname != NULL && strcmp (symname, "sigusr2") == 0);
       break;
     case 2: // x86_64 only
       /* __restore_rt - glibc maybe does not have to have this symbol.  */
@@ -125,11 +125,11 @@ callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
 	}
       /* FALLTHRU */
     case 4:
-      assert (symname != NULL && strcmp (symname, "stdarg") == 0);
+//      assert (symname != NULL && strcmp (symname, "stdarg") == 0);
       break;
     case 5:
       /* Verify we trapped on the very last instruction of child.  */
-      assert (symname != NULL && strcmp (symname, "backtracegen") == 0);
+//      assert (symname != NULL && strcmp (symname, "backtracegen") == 0);
       mod = dwfl_addrmodule (dwfl, pc);
       if (mod)
 	symname2 = dwfl_module_addrname (mod, pc);



More information about the Elfutils-devel mailing list