xref: /aosp_15_r20/external/elfutils/tests/backtrace-child.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Test child for parent backtrace test.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2013, 2016 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker 
5*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker    it under the terms of the GNU General Public License as published by
7*7304104dSAndroid Build Coastguard Worker    the Free Software Foundation; either version 3 of the License, or
8*7304104dSAndroid Build Coastguard Worker    (at your option) any later version.
9*7304104dSAndroid Build Coastguard Worker 
10*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
11*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
12*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*7304104dSAndroid Build Coastguard Worker    GNU General Public License for more details.
14*7304104dSAndroid Build Coastguard Worker 
15*7304104dSAndroid Build Coastguard Worker    You should have received a copy of the GNU General Public License
16*7304104dSAndroid Build Coastguard Worker    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17*7304104dSAndroid Build Coastguard Worker 
18*7304104dSAndroid Build Coastguard Worker /* Command line syntax: ./backtrace-child [--ptraceme|--gencore]
19*7304104dSAndroid Build Coastguard Worker    --ptraceme will call ptrace (PTRACE_TRACEME) in the two threads.
20*7304104dSAndroid Build Coastguard Worker    --gencore will call abort () at its end.
21*7304104dSAndroid Build Coastguard Worker    Main thread will signal SIGUSR2.  Other thread will signal SIGUSR1.
22*7304104dSAndroid Build Coastguard Worker    There used to be a difference between x86_64 and other architectures.
23*7304104dSAndroid Build Coastguard Worker    To test getting a signal at the very first instruction of a function:
24*7304104dSAndroid Build Coastguard Worker      PC will get changed to function 'jmp' by backtrace.c function
25*7304104dSAndroid Build Coastguard Worker      prepare_thread.  Then SIGUSR2 will be signalled to backtrace-child
26*7304104dSAndroid Build Coastguard Worker      which will invoke function sigusr2.
27*7304104dSAndroid Build Coastguard Worker      This is all done so that signal interrupts execution of the very first
28*7304104dSAndroid Build Coastguard Worker      instruction of a function.  Properly handled unwind should not slip into
29*7304104dSAndroid Build Coastguard Worker      the previous unrelated function.
30*7304104dSAndroid Build Coastguard Worker      The tested functionality is arch-independent but the code reproducing it
31*7304104dSAndroid Build Coastguard Worker      has to be arch-specific.
32*7304104dSAndroid Build Coastguard Worker    On non-x86_64:
33*7304104dSAndroid Build Coastguard Worker      sigusr2 gets called by normal function call from function stdarg.
34*7304104dSAndroid Build Coastguard Worker    On any arch then sigusr2 calls raise (SIGUSR1) for --ptraceme.
35*7304104dSAndroid Build Coastguard Worker    abort () is called otherwise, expected for --gencore core dump.
36*7304104dSAndroid Build Coastguard Worker 
37*7304104dSAndroid Build Coastguard Worker    Expected x86_64 output:
38*7304104dSAndroid Build Coastguard Worker    TID 10276:
39*7304104dSAndroid Build Coastguard Worker    # 0 0x7f7ab61e9e6b      raise
40*7304104dSAndroid Build Coastguard Worker    # 1 0x7f7ab661af47 - 1  main
41*7304104dSAndroid Build Coastguard Worker    # 2 0x7f7ab5e3bb45 - 1  __libc_start_main
42*7304104dSAndroid Build Coastguard Worker    # 3 0x7f7ab661aa09 - 1  _start
43*7304104dSAndroid Build Coastguard Worker    TID 10278:
44*7304104dSAndroid Build Coastguard Worker    # 0 0x7f7ab61e9e6b      raise
45*7304104dSAndroid Build Coastguard Worker    # 1 0x7f7ab661ab3c - 1  sigusr2
46*7304104dSAndroid Build Coastguard Worker    # 2 0x7f7ab5e4fa60      __restore_rt
47*7304104dSAndroid Build Coastguard Worker    # 3 0x7f7ab661ab47      jmp
48*7304104dSAndroid Build Coastguard Worker    # 4 0x7f7ab661ac92 - 1  stdarg
49*7304104dSAndroid Build Coastguard Worker    # 5 0x7f7ab661acba - 1  backtracegen
50*7304104dSAndroid Build Coastguard Worker    # 6 0x7f7ab661acd1 - 1  start
51*7304104dSAndroid Build Coastguard Worker    # 7 0x7f7ab61e2c53 - 1  start_thread
52*7304104dSAndroid Build Coastguard Worker    # 8 0x7f7ab5f0fdbd - 1  __clone
53*7304104dSAndroid Build Coastguard Worker 
54*7304104dSAndroid Build Coastguard Worker    Expected non-x86_64 (i386) output; __kernel_vsyscall are skipped if found:
55*7304104dSAndroid Build Coastguard Worker    TID 10408:
56*7304104dSAndroid Build Coastguard Worker    # 0 0xf779f430          __kernel_vsyscall
57*7304104dSAndroid Build Coastguard Worker    # 1 0xf7771466 - 1      raise
58*7304104dSAndroid Build Coastguard Worker    # 2 0xf77c1d07 - 1      main
59*7304104dSAndroid Build Coastguard Worker    # 3 0xf75bd963 - 1      __libc_start_main
60*7304104dSAndroid Build Coastguard Worker    # 4 0xf77c1761 - 1      _start
61*7304104dSAndroid Build Coastguard Worker    TID 10412:
62*7304104dSAndroid Build Coastguard Worker    # 0 0xf779f430          __kernel_vsyscall
63*7304104dSAndroid Build Coastguard Worker    # 1 0xf7771466 - 1      raise
64*7304104dSAndroid Build Coastguard Worker    # 2 0xf77c18f4 - 1      sigusr2
65*7304104dSAndroid Build Coastguard Worker    # 3 0xf77c1a10 - 1      stdarg
66*7304104dSAndroid Build Coastguard Worker    # 4 0xf77c1a2c - 1      backtracegen
67*7304104dSAndroid Build Coastguard Worker    # 5 0xf77c1a48 - 1      start
68*7304104dSAndroid Build Coastguard Worker    # 6 0xf77699da - 1      start_thread
69*7304104dSAndroid Build Coastguard Worker    # 7 0xf769bbfe - 1      __clone
70*7304104dSAndroid Build Coastguard Worker 
71*7304104dSAndroid Build Coastguard Worker    But the raise jmp patching was unreliable. It depends on the CFI for the raise()
72*7304104dSAndroid Build Coastguard Worker    function in glibc to be the same as for the jmp() function. This is not always
73*7304104dSAndroid Build Coastguard Worker    the case. Some newer glibc versions rewrote raise() and now the CFA is calculated
74*7304104dSAndroid Build Coastguard Worker    differently. So we disable raise jmp patching everywhere.
75*7304104dSAndroid Build Coastguard Worker    */
76*7304104dSAndroid Build Coastguard Worker 
77*7304104dSAndroid Build Coastguard Worker #ifdef __x86_64__
78*7304104dSAndroid Build Coastguard Worker /* #define RAISE_JMP_PATCHING 1 */
79*7304104dSAndroid Build Coastguard Worker #endif
80*7304104dSAndroid Build Coastguard Worker 
81*7304104dSAndroid Build Coastguard Worker #include <config.h>
82*7304104dSAndroid Build Coastguard Worker #include <assert.h>
83*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
84*7304104dSAndroid Build Coastguard Worker #include <errno.h>
85*7304104dSAndroid Build Coastguard Worker #include <string.h>
86*7304104dSAndroid Build Coastguard Worker #include <pthread.h>
87*7304104dSAndroid Build Coastguard Worker #include <stdio.h>
88*7304104dSAndroid Build Coastguard Worker #include <unistd.h>
89*7304104dSAndroid Build Coastguard Worker 
90*7304104dSAndroid Build Coastguard Worker #ifndef __linux__
91*7304104dSAndroid Build Coastguard Worker 
92*7304104dSAndroid Build Coastguard Worker int
main(int argc,char ** argv)93*7304104dSAndroid Build Coastguard Worker main (int argc __attribute__ ((unused)), char **argv)
94*7304104dSAndroid Build Coastguard Worker {
95*7304104dSAndroid Build Coastguard Worker   fprintf (stderr, "%s: Unwinding not supported for this architecture\n",
96*7304104dSAndroid Build Coastguard Worker            argv[0]);
97*7304104dSAndroid Build Coastguard Worker   return 77;
98*7304104dSAndroid Build Coastguard Worker }
99*7304104dSAndroid Build Coastguard Worker 
100*7304104dSAndroid Build Coastguard Worker #else /* __linux__ */
101*7304104dSAndroid Build Coastguard Worker #include <sys/ptrace.h>
102*7304104dSAndroid Build Coastguard Worker #include <signal.h>
103*7304104dSAndroid Build Coastguard Worker 
104*7304104dSAndroid Build Coastguard Worker #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
105*7304104dSAndroid Build Coastguard Worker #define NOINLINE_NOCLONE __attribute__ ((noinline, noclone))
106*7304104dSAndroid Build Coastguard Worker #else
107*7304104dSAndroid Build Coastguard Worker #define NOINLINE_NOCLONE __attribute__ ((noinline))
108*7304104dSAndroid Build Coastguard Worker #endif
109*7304104dSAndroid Build Coastguard Worker 
110*7304104dSAndroid Build Coastguard Worker #define NORETURN __attribute__ ((noreturn))
111*7304104dSAndroid Build Coastguard Worker #define UNUSED __attribute__ ((unused))
112*7304104dSAndroid Build Coastguard Worker #define USED __attribute__ ((used))
113*7304104dSAndroid Build Coastguard Worker 
114*7304104dSAndroid Build Coastguard Worker static int ptraceme, gencore;
115*7304104dSAndroid Build Coastguard Worker 
116*7304104dSAndroid Build Coastguard Worker /* Execution will arrive here from jmp by an artificial ptrace-spawn signal.  */
117*7304104dSAndroid Build Coastguard Worker 
118*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE void
sigusr2(int signo)119*7304104dSAndroid Build Coastguard Worker sigusr2 (int signo)
120*7304104dSAndroid Build Coastguard Worker {
121*7304104dSAndroid Build Coastguard Worker   assert (signo == SIGUSR2);
122*7304104dSAndroid Build Coastguard Worker   if (! gencore)
123*7304104dSAndroid Build Coastguard Worker     {
124*7304104dSAndroid Build Coastguard Worker       raise (SIGUSR1);
125*7304104dSAndroid Build Coastguard Worker       /* Do not return as stack may be invalid due to ptrace-patched PC to the
126*7304104dSAndroid Build Coastguard Worker 	 jmp function.  */
127*7304104dSAndroid Build Coastguard Worker       pthread_exit (NULL);
128*7304104dSAndroid Build Coastguard Worker       /* Not reached.  */
129*7304104dSAndroid Build Coastguard Worker       abort ();
130*7304104dSAndroid Build Coastguard Worker     }
131*7304104dSAndroid Build Coastguard Worker   /* Here we dump the core for --gencore.  */
132*7304104dSAndroid Build Coastguard Worker   raise (SIGABRT);
133*7304104dSAndroid Build Coastguard Worker   /* Avoid tail call optimization for the raise call.  */
134*7304104dSAndroid Build Coastguard Worker   asm volatile ("");
135*7304104dSAndroid Build Coastguard Worker }
136*7304104dSAndroid Build Coastguard Worker 
137*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE void
dummy1(void)138*7304104dSAndroid Build Coastguard Worker dummy1 (void)
139*7304104dSAndroid Build Coastguard Worker {
140*7304104dSAndroid Build Coastguard Worker   asm volatile ("");
141*7304104dSAndroid Build Coastguard Worker }
142*7304104dSAndroid Build Coastguard Worker 
143*7304104dSAndroid Build Coastguard Worker #ifdef RAISE_JMP_PATCHING
144*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE USED void
jmp(void)145*7304104dSAndroid Build Coastguard Worker jmp (void)
146*7304104dSAndroid Build Coastguard Worker {
147*7304104dSAndroid Build Coastguard Worker   /* Not reached, signal will get ptrace-spawn to jump into sigusr2.  */
148*7304104dSAndroid Build Coastguard Worker   abort ();
149*7304104dSAndroid Build Coastguard Worker }
150*7304104dSAndroid Build Coastguard Worker #endif
151*7304104dSAndroid Build Coastguard Worker 
152*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE void
dummy2(void)153*7304104dSAndroid Build Coastguard Worker dummy2 (void)
154*7304104dSAndroid Build Coastguard Worker {
155*7304104dSAndroid Build Coastguard Worker   asm volatile ("");
156*7304104dSAndroid Build Coastguard Worker }
157*7304104dSAndroid Build Coastguard Worker 
158*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE NORETURN void
stdarg(int f UNUSED,...)159*7304104dSAndroid Build Coastguard Worker stdarg (int f UNUSED, ...)
160*7304104dSAndroid Build Coastguard Worker {
161*7304104dSAndroid Build Coastguard Worker   sighandler_t sigusr2_orig = signal (SIGUSR2, sigusr2);
162*7304104dSAndroid Build Coastguard Worker   assert (sigusr2_orig == SIG_DFL);
163*7304104dSAndroid Build Coastguard Worker   errno = 0;
164*7304104dSAndroid Build Coastguard Worker   if (ptraceme)
165*7304104dSAndroid Build Coastguard Worker     {
166*7304104dSAndroid Build Coastguard Worker       long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
167*7304104dSAndroid Build Coastguard Worker       assert (l == 0);
168*7304104dSAndroid Build Coastguard Worker     }
169*7304104dSAndroid Build Coastguard Worker #ifdef RAISE_JMP_PATCHING
170*7304104dSAndroid Build Coastguard Worker   if (! gencore)
171*7304104dSAndroid Build Coastguard Worker     {
172*7304104dSAndroid Build Coastguard Worker       /* Execution will get PC patched into function jmp.  */
173*7304104dSAndroid Build Coastguard Worker       raise (SIGUSR1);
174*7304104dSAndroid Build Coastguard Worker     }
175*7304104dSAndroid Build Coastguard Worker #endif
176*7304104dSAndroid Build Coastguard Worker   sigusr2 (SIGUSR2);
177*7304104dSAndroid Build Coastguard Worker   /* Not reached.  */
178*7304104dSAndroid Build Coastguard Worker   abort ();
179*7304104dSAndroid Build Coastguard Worker }
180*7304104dSAndroid Build Coastguard Worker 
181*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE void
dummy3(void)182*7304104dSAndroid Build Coastguard Worker dummy3 (void)
183*7304104dSAndroid Build Coastguard Worker {
184*7304104dSAndroid Build Coastguard Worker   asm volatile ("");
185*7304104dSAndroid Build Coastguard Worker }
186*7304104dSAndroid Build Coastguard Worker 
187*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE void
backtracegen(void)188*7304104dSAndroid Build Coastguard Worker backtracegen (void)
189*7304104dSAndroid Build Coastguard Worker {
190*7304104dSAndroid Build Coastguard Worker   stdarg (1);
191*7304104dSAndroid Build Coastguard Worker   /* Here should be no instruction after the stdarg call as it is noreturn
192*7304104dSAndroid Build Coastguard Worker      function.  It must be stdarg so that it is a call and not jump (jump as
193*7304104dSAndroid Build Coastguard Worker      a tail-call).  */
194*7304104dSAndroid Build Coastguard Worker }
195*7304104dSAndroid Build Coastguard Worker 
196*7304104dSAndroid Build Coastguard Worker static NOINLINE_NOCLONE void
dummy4(void)197*7304104dSAndroid Build Coastguard Worker dummy4 (void)
198*7304104dSAndroid Build Coastguard Worker {
199*7304104dSAndroid Build Coastguard Worker   asm volatile ("");
200*7304104dSAndroid Build Coastguard Worker }
201*7304104dSAndroid Build Coastguard Worker 
202*7304104dSAndroid Build Coastguard Worker static void *
start(void * arg UNUSED)203*7304104dSAndroid Build Coastguard Worker start (void *arg UNUSED)
204*7304104dSAndroid Build Coastguard Worker {
205*7304104dSAndroid Build Coastguard Worker   backtracegen ();
206*7304104dSAndroid Build Coastguard Worker   /* Not reached.  */
207*7304104dSAndroid Build Coastguard Worker   abort ();
208*7304104dSAndroid Build Coastguard Worker }
209*7304104dSAndroid Build Coastguard Worker 
210*7304104dSAndroid Build Coastguard Worker int
main(int argc UNUSED,char ** argv)211*7304104dSAndroid Build Coastguard Worker main (int argc UNUSED, char **argv)
212*7304104dSAndroid Build Coastguard Worker {
213*7304104dSAndroid Build Coastguard Worker   setbuf (stdout, NULL);
214*7304104dSAndroid Build Coastguard Worker   assert (*argv++);
215*7304104dSAndroid Build Coastguard Worker   ptraceme = (*argv && strcmp (*argv, "--ptraceme") == 0);
216*7304104dSAndroid Build Coastguard Worker   argv += ptraceme;
217*7304104dSAndroid Build Coastguard Worker   gencore = (*argv && strcmp (*argv, "--gencore") == 0);
218*7304104dSAndroid Build Coastguard Worker   argv += gencore;
219*7304104dSAndroid Build Coastguard Worker   assert (!*argv);
220*7304104dSAndroid Build Coastguard Worker   /* These dummy* functions are there so that each of their surrounding
221*7304104dSAndroid Build Coastguard Worker      functions has some unrelated code around.  The purpose of some of the
222*7304104dSAndroid Build Coastguard Worker      tests is verify unwinding the very first / after the very last instruction
223*7304104dSAndroid Build Coastguard Worker      does not inappropriately slip into the unrelated code around.  */
224*7304104dSAndroid Build Coastguard Worker   dummy1 ();
225*7304104dSAndroid Build Coastguard Worker   dummy2 ();
226*7304104dSAndroid Build Coastguard Worker   dummy3 ();
227*7304104dSAndroid Build Coastguard Worker   dummy4 ();
228*7304104dSAndroid Build Coastguard Worker   if (gencore)
229*7304104dSAndroid Build Coastguard Worker     printf ("%ld\n", (long) getpid ());
230*7304104dSAndroid Build Coastguard Worker   pthread_t thread;
231*7304104dSAndroid Build Coastguard Worker   int i = pthread_create (&thread, NULL, start, NULL);
232*7304104dSAndroid Build Coastguard Worker   // pthread_* functions do not set errno.
233*7304104dSAndroid Build Coastguard Worker   assert (i == 0);
234*7304104dSAndroid Build Coastguard Worker   if (ptraceme)
235*7304104dSAndroid Build Coastguard Worker     {
236*7304104dSAndroid Build Coastguard Worker       errno = 0;
237*7304104dSAndroid Build Coastguard Worker       long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
238*7304104dSAndroid Build Coastguard Worker       assert (l == 0);
239*7304104dSAndroid Build Coastguard Worker     }
240*7304104dSAndroid Build Coastguard Worker   if (gencore)
241*7304104dSAndroid Build Coastguard Worker     pthread_join (thread, NULL);
242*7304104dSAndroid Build Coastguard Worker   else
243*7304104dSAndroid Build Coastguard Worker     raise (SIGUSR2);
244*7304104dSAndroid Build Coastguard Worker   return 0;
245*7304104dSAndroid Build Coastguard Worker }
246*7304104dSAndroid Build Coastguard Worker 
247*7304104dSAndroid Build Coastguard Worker #endif /* ! __linux__ */
248*7304104dSAndroid Build Coastguard Worker 
249