(root)/
glibc-2.38/
stdlib/
tst-makecontext.c
       1  /* Copyright (C) 2006-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <stdlib.h>
      20  #include <stdio.h>
      21  #include <ucontext.h>
      22  #include <assert.h>
      23  #include <unwind.h>
      24  #include <dlfcn.h>
      25  #include <gnu/lib-names.h>
      26  
      27  ucontext_t ucp;
      28  char st1[16384];
      29  __thread int thr;
      30  
      31  int somevar = -76;
      32  long othervar = -78L;
      33  
      34  struct trace_arg
      35  {
      36    int cnt, size;
      37  };
      38  
      39  static _Unwind_Reason_Code
      40  backtrace_helper (struct _Unwind_Context *ctx, void *a)
      41  {
      42    struct trace_arg *arg = a;
      43    if (++arg->cnt == arg->size)
      44      return _URC_END_OF_STACK;
      45    return _URC_NO_REASON;
      46  }
      47  
      48  void
      49  cf (int i)
      50  {
      51    struct trace_arg arg = { .size = 100, .cnt = -1 };
      52    void *handle;
      53    _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
      54  
      55    if (i != othervar || thr != 94)
      56      {
      57        printf ("i %d thr %d\n", i, thr);
      58        exit (1);
      59      }
      60  
      61    /* Test if callback function of _Unwind_Backtrace is not called infinitely
      62       times. See Bug 18508 or gcc bug "Bug 66303 - runtime.Caller() returns
      63       infinitely deep stack frames on s390x.".
      64       The go runtime calls backtrace_full() in
      65       <gcc-src>/libbacktrace/backtrace.c, which uses _Unwind_Backtrace().  */
      66    handle = dlopen (LIBGCC_S_SO, RTLD_LAZY);
      67    if (handle != NULL)
      68      {
      69        unwind_backtrace = dlsym (handle, "_Unwind_Backtrace");
      70        if (unwind_backtrace != NULL)
      71  	{
      72  	  unwind_backtrace (backtrace_helper, &arg);
      73  	  assert (arg.cnt != -1 && arg.cnt < 100);
      74  	}
      75        dlclose (handle);
      76      }
      77  
      78    /* Since uc_link below has been set to NULL, setcontext is supposed to
      79       terminate the process normally after this function returns.  */
      80  }
      81  
      82  int
      83  do_test (void)
      84  {
      85    if (getcontext (&ucp) != 0)
      86      {
      87        if (errno == ENOSYS)
      88  	{
      89  	  puts ("context handling not supported");
      90  	  return 0;
      91  	}
      92  
      93        puts ("getcontext failed");
      94        return 1;
      95      }
      96    thr = 94;
      97    ucp.uc_link = NULL;
      98    ucp.uc_stack.ss_sp = st1;
      99    ucp.uc_stack.ss_size = sizeof st1;
     100    makecontext (&ucp, (void (*) (void)) cf, 1, somevar - 2);
     101    if (setcontext (&ucp) != 0)
     102      {
     103        puts ("setcontext failed");
     104        return 1;
     105      }
     106    return 2;
     107  }
     108  
     109  #define TEST_FUNCTION do_test ()
     110  #include "../test-skeleton.c"