[Top][All Lists]
[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