libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Libunwind-devel] [RFC] _ULx86_64_tdep_trace returns off-by-one addr


From: Lassi Tuura
Subject: Re: [Libunwind-devel] [RFC] _ULx86_64_tdep_trace returns off-by-one addresses
Date: Mon, 5 Dec 2011 07:44:43 +0100

Good morning Paul & co,

> Aside from the inconsistency, this gives wrong address for the
> __restore_rt frame:

Having thought about this some more, I remembered there is actually a
comment to this effect in the linux kernel sources, albeit for 32-bit
because 64-bit uses SA_RESTORER.

http://lxr.linux.no/linux+v3.1.4/arch/x86/vdso/vdso32/sigreturn.S#L58

  58.LSTARTFDEDLSI1:
  59        .long .LSTARTFDEDLSI1-.LSTARTFRAMEDLSI1 /* CIE pointer */
  60        /* HACK: The dwarf2 unwind routines will subtract 1 from the
  61           return address to get an address in the middle of the
  62           presumed call instruction.  Since we didn't get here via
  63           a call, we need to include the nop before the real start
  64           to make up for it.  */
  65        .long .LSTART_sigreturn-1-.     /* PC-relative start address */
  66        .long .LEND_sigreturn-.LSTART_sigreturn+1

For 64-bit the comments are in GLIBC, mirroring the kernel comment:

http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86_64/sigaction.c#l97

  97    The unwind information starts a byte before __restore_rt, so that
  98    it is found when unwinding, to get an address the unwinder assumes
  99    will be in the middle of a call instruction.  [...]

And indeed the FDE starts one byte before the function:

$ objdump --no-show-raw -d /lib64/libc.so.6 | grep -A3 -e ' <__restore_rt>:'
00000039564302d0 <__restore_rt>:
  39564302d0:   mov    $0xf,%rax
  39564302d7:   syscall 
  39564302d9:   nopl   0x0(%rax)

$ readelf -Wwf /lib64/libc.so.6 | fgrep 302cf..                             
00002098 0000007c 0000001c FDE cie=00002080 pc=39564302cf..39564302d9

I suppose in fast trace under "case UNW_X86_64_FRAME_SIGRETURN" we could
maybe fix things up with something like:

  /* In x86_64 the signal frame is usually __restore_rt, and we didn't
     get there by a call, it's just set up to look like that on stack.
     Because of d->use_prev_instr we ended up reporting an address one
     byte before the function at previous frame. Fix that up now. */
  if (depth)
    buffer[depth-1] = (uint64_t) buffer[depth-1]+1;

Does that seem like a sensible idea to anyone? I'll try to check if this an
ok strategy for platforms other than linux, but I need to dust my VMs first.

Regards,
Lassi


reply via email to

[Prev in Thread] Current Thread [Next in Thread]