On Tue, 12 Dec 2006 16:26:34 +0100, Andrew Haley wrote:
...
> It's certainly an inconsistency in the specification, which says that
> null-termination is supported, and this implies that you can't put a zero in
> there.
I tested now that you can put the zero there for both the libgcc unwinder and
for gdb(1) [tested only Fedora Core gdb-6.5-13.fc6],
attached, on x86_64 compile [gcc-4.1.1-30] and run by:
gcc -o fp0-x86_64 -O9 -fomit-frame-pointer -Wall fp0-x86_64.c -ggdb3;
./fp0-x86_64
The output provided at the end of this mail.
Therefore I believe this sentence is wrong and it should be removed:
http://www.x86-64.org/documentation/abi.pdf (draft 0.98) Page 28
(29/124)
%rbp ... but the user code should mark the deepest stack frame by
%setting the frame pointer to zero.
On the other hand the right stack terminator for libgcc unwinder is `PC == 0':
unwind-dw2.c:uw_frame_state_for ():
if (context->ra == 0)
return _URC_END_OF_STACK;
And gdb should just get updated to behave the same way.
libunwind already assumed end of stack on `PC == 0' before and I do not expect
any platform would consider `PC == 0' as a valid _return_address_ (which is
usually several bytes after any starting function address due to the call
instruction).
...
> "All of these" might be the right way to go. That is, keep
> null-terminating the stack, strengthen the rules about what you might
> do with %ebp, and extend debuginfo.
For best compatibility null terminate the stack but by CFI and its indicated
return address. Do not use %rbp (frame pointer register) in any way (regarding
the stack termination condition).
Believe only CFI-specified CFA address, unrelated to %rbp content.
Regards,
Jan
------------------------------------------------------------------------------
GNU gdb Red Hat Linux (6.5-13.fc6rh)
This GDB was configured as "x86_64-redhat-linux-gnu"...Using host libthread_db
library "/lib64/libthread_db.so.1".
(gdb) b 12
Breakpoint 1 at 0x40060b: file fp0-x86_64.c, line 12.
(gdb) r
Starting program: /root/jkratoch/redhat/unwind/fp0-x86_64
Breakpoint 1, backtracer () at fp0-x86_64.c:12
12 int i = backtrace (buf, 512);
(gdb) bt
#0 backtracer () at fp0-x86_64.c:12
#1 0x0000000000400739 in badone () at fp0-x86_64.c:31
#2 0x000000000040074e in main () at fp0-x86_64.c:47
(gdb) p/x $rbp
$1 = 0x7fff6ed61ca0
(gdb) up
#1 0x0000000000400739 in badone () at fp0-x86_64.c:31
31 backtracer ();
(gdb) p/x $rbp
$2 = 0x0
(gdb) c
Continuing.
dummy
5
/root/jkratoch/redhat/unwind/fp0-x86_64[0x40062c]
/root/jkratoch/redhat/unwind/fp0-x86_64[0x400739]
/root/jkratoch/redhat/unwind/fp0-x86_64[0x40074e]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x301e81da44]
/root/jkratoch/redhat/unwind/fp0-x86_64[0x400559]
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400684 in backtracer () at fp0-x86_64.c:21
21 RAFA(1);
(gdb) q
#include <pthread.h>
#include <execinfo.h>
#include <stdio.h>
#include <unistd.h>
static void backtracer (void) __attribute__((__noinline__));
static void backtracer (void)
{
void *buf[512];
puts("dummy");
int i = backtrace (buf, 512);
printf ("%d\n", i);
fflush (stdout);
backtrace_symbols_fd (buf, i, STDOUT_FILENO);
#define RAFA(level) \
printf("RA (%d) = %p, FA (%d) = %p\n", \
level, __builtin_return_address (level), \
level, __builtin_frame_address (level))
RAFA(0);
RAFA(1);
RAFA(2);
RAFA(3);
RAFA(4);
RAFA(5);
}
static int badone (void) __attribute__((__noinline__));
static int badone (void)
{
backtracer ();
return 0;
}
asm(
" .text \n"
"clearstack: \n"
" pushq $0 \n"
" popq %rax \n"
" ret \n"
);
extern void clearstack(void);
int main (void)
{
clearstack ();
badone ();
return 0;
}