GDB failed to detect the outermost frame while showing the backtrace
within a thread:
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Before this patch, the start routines like thread_start had no cfi information.
GDB is then using the prologue unwinder if no cfi information is available.
This unwinder tries to unwind r15 and stops e.g. if r15 was updated or
on some jump-instructions.
On older glibc-versions (before commit "Remove cached PID/TID in clone"
c579f48edb), the thread_start function used
such a jump-instruction and GDB did not fail with an error.
This patch adds cfi information for _start, thread_start and __makecontext_ret
and marks r14 as undefined which marks the frame as outermost frame and GDB
stops the backtrace. Also tested different gcc versions in order to test
_Unwind_Backtrace() in libgcc as this is used by backtrace() in glibc.
ChangeLog:
* sysdeps/s390/s390-64/start.S (_start): Add cfi information for r14.
* sysdeps/s390/s390-32/start.S: (_start): Likewise
* sysdeps/unix/sysv/linux/s390/s390-64/clone.S
(thread_start): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/clone.S
(thread_start): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S
(__makecontext_ret): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
(__makecontext_ret): Likewise.
Building glibc with gcc configured with --enable-default-pie failed on s390
due to assembler messages:
../sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S:44:
Error: junk at end of line, first unrecognized character is `@'
HIDDEN_JUMPTARGET was expanded to exit@PLT@GOTOFF.
If SHARED is not defined, HIDDEN_JUMPTARGET is defined to JUMPTARGET
in sysdeps/s390/s390-32/sysdep.h. There it expanded to exit@PLT
in non SHARED case as PIC is defined if gcc is configured with
--enable-default-pie. Thus I've changed the "ifdef PIC" to "ifdef SHARED"
as we do not want PLTs in the static obj files. I've also changed this
in sysdeps/s390/s390-64/sysdep.h.
I've also adjusted sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S.
If glibc is configured with --disable-hidden-plt, then NO_HIDDEN is defined.
In SHARED case HIDDEN_JUMPTARGET would be expanded to exit@PLT@GOTOFF
instead of __GI_exit@GOTOFF.
Now we jump to:
- __GI_exit if SHARED is defined
- exit@PLT if SHARED and NO_HIDDEN is defined
- exit if both are not defined.
On s390 31bit we have to setup GOT pointer in r12 if we use a PLT stub.
Therefore I use SYSCALL_PIC_SETUP from sysdep.h and added the missing semicolons.
ChangeLog:
[BZ #21537]
* sysdeps/s390/s390-32/sysdep.h (JUMPTARGET, SYSCALL_PIC_SETUP):
Check SHARED instead of PIC.
(SYSCALL_PIC_SETUP): Add missing semicolons.
* sysdeps/s390/s390-64/sysdep.h (JUMPTARGET, SYSCALL_PIC_SETUP):
Check SHARED instead of PIC.
* sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S
(__makecontext_ret): Adjust code to jump to exit.
On s390/s390x backtrace(buffer, size) returns the series of called functions until
"makecontext_ret" and additional entries (up to "size") with "makecontext_ret".
GDB-backtrace is also warning:
"Backtrace stopped: previous frame identical to this frame (corrupt stack?)"
To reproduce this scenario you have to setup a new context with makecontext()
and activate it with setcontext(). See e.g. cf() function in testcase stdlib/tst-makecontext.c.
Or see bug in libgo "Bug 66303 - runtime.Caller() returns infinitely deep stack frames
on s390x " (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66303).
This patch omits the cfi_startproc/cfi_endproc directives in ENTRY/END macro of
__makecontext_ret. Thus no frame information is generated in .eh_frame and backtrace
stops after __makecontext_ret. There is also no .eh_frame info for _start or
thread_start functions.
ChangeLog:
[BZ #18508]
* stdlib/Makefile ($(objpfx)tst-makecontext3):
Depend on $(libdl).
* stdlib/tst-makecontext.c (cf): Test if _Unwind_Backtrace
is not called infinitely times.
(backtrace_helper): New function.
(trace_arg): New struct.
(st1): Enlarge stack size.
* sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S:
(__makecontext_ret): Omit cfi_startproc and cfi_endproc.
* sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S:
Likewise.