(root)/
glibc-2.38/
debug/
tst-backtrace5.c
       1  /* Test backtrace and backtrace_symbols for signal frames, where a
       2     system call was interrupted by a signal.
       3     Copyright (C) 2011-2023 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
      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
     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
     146  do_test (void)
     147  {
     148    fn (2, SIGACTION_FLAGS);
     149    return ret;
     150  }
     151  
     152  #include <support/test-driver.c>