1 /* Test backtrace and backtrace_symbols for signal frames, where a
2    system call was interrupted by a signal.
3    Copyright (C) 2011-2022 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5 
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10 
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15 
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <https://www.gnu.org/licenses/>.  */
19 
20 #include <execinfo.h>
21 #include <search.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <signal.h>
27 #include <unistd.h>
28 
29 #include "tst-backtrace.h"
30 
31 #ifndef SIGACTION_FLAGS
32 # define SIGACTION_FLAGS 0
33 #endif
34 
35 /* The backtrace should include at least handle_signal, a signal
36    trampoline, read, 3 * fn, and do_test.  */
37 #define NUM_FUNCTIONS 7
38 
39 void
handle_signal(int signum)40 handle_signal (int signum)
41 {
42   void *addresses[NUM_FUNCTIONS];
43   char **symbols;
44   int n;
45   int i;
46 
47   /* Get the backtrace addresses.  */
48   n = backtrace (addresses, sizeof (addresses) / sizeof (addresses[0]));
49   printf ("Obtained backtrace with %d functions\n", n);
50   /*  Check that there are at least seven functions.  */
51   if (n < NUM_FUNCTIONS)
52     {
53       FAIL ();
54       return;
55     }
56   /* Convert them to symbols.  */
57   symbols = backtrace_symbols (addresses, n);
58   /* Check that symbols were obtained.  */
59   if (symbols == NULL)
60     {
61       FAIL ();
62       return;
63     }
64   for (i = 0; i < n; ++i)
65     printf ("Function %d: %s\n", i, symbols[i]);
66   /* Check that the function names obtained are accurate.  */
67   if (!match (symbols[0], "handle_signal"))
68     {
69       FAIL ();
70       return;
71     }
72 
73   /* Do not check name for signal trampoline or cancellable syscall
74      wrappers (__syscall_cancel*).  */
75   for (; i < n - 1; i++)
76     if (match (symbols[i], "read"))
77       break;
78   if (i == n - 1)
79     {
80       FAIL ();
81       return;
82     }
83 
84   for (; i < n - 1; i++)
85     if (!match (symbols[i], "fn"))
86       {
87 	FAIL ();
88 	return;
89       }
90   /* Symbol names are not available for static functions, so we do not
91      check do_test.  */
92 
93   /* Check that backtrace does not return more than what fits in the array
94      (bug 25423).  */
95   for (int j = 0; j < NUM_FUNCTIONS; j++)
96     {
97       n = backtrace (addresses, j);
98       if (n > j)
99 	{
100 	  FAIL ();
101 	  return;
102 	}
103     }
104 }
105 
106 NO_INLINE int
fn(int c,int flags)107 fn (int c, int flags)
108 {
109   pid_t parent_pid, child_pid;
110   int pipefd[2];
111   char r[1];
112   struct sigaction act;
113 
114   if (c > 0)
115     {
116       fn (c - 1, flags);
117       return x;
118     }
119 
120   memset (&act, 0, sizeof (act));
121   act.sa_handler = handle_signal;
122   act.sa_flags = flags;
123   sigemptyset (&act.sa_mask);
124   sigaction (SIGUSR1, &act, NULL);
125   parent_pid = getpid ();
126   if (pipe (pipefd) == -1)
127     abort ();
128 
129   child_pid = fork ();
130   if (child_pid == (pid_t) -1)
131     abort ();
132   else if (child_pid == 0)
133     {
134       sleep (1);
135       kill (parent_pid, SIGUSR1);
136       _exit (0);
137     }
138 
139   /* In the parent.  */
140   read (pipefd[0], r, 1);
141 
142   return 0;
143 }
144 
145 NO_INLINE int
do_test(void)146 do_test (void)
147 {
148   fn (2, SIGACTION_FLAGS);
149   return ret;
150 }
151 
152 #include <support/test-driver.c>
153