1  /* Return backtrace of current program state.
       2     Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library.  If not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <execinfo.h>
      20  #include <stdlib.h>
      21  #include <unwind-link.h>
      22  
      23  struct trace_arg
      24  {
      25    void **array;
      26    struct unwind_link *unwind_link;
      27    int cnt, size;
      28  };
      29  
      30  #ifdef SHARED
      31  /* This function is identical to "_Unwind_GetGR", except that it uses
      32     "unwind_vrs_get" instead of "_Unwind_VRS_Get".  */
      33  static inline _Unwind_Word
      34  unwind_getgr (struct unwind_link *unwind_link,
      35  	      _Unwind_Context *context, int regno)
      36  {
      37    _uw val;
      38    UNWIND_LINK_PTR (unwind_link, _Unwind_VRS_Get)
      39      (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
      40    return val;
      41  }
      42  
      43  /* This macro is identical to the _Unwind_GetIP macro, except that it
      44     uses "unwind_getgr" instead of "_Unwind_GetGR".  */
      45  #define unwind_getip(context) \
      46    (unwind_getgr (arg->unwind_link, context, 15) & ~(_Unwind_Word)1)
      47  
      48  #else /* !SHARED */
      49  # define unwind_getip _Unwind_GetIP
      50  #endif
      51  
      52  static _Unwind_Reason_Code
      53  backtrace_helper (struct _Unwind_Context *ctx, void *a)
      54  {
      55    struct trace_arg *arg = a;
      56  
      57    /* We are first called with address in the __backtrace function.
      58       Skip it.  */
      59    if (arg->cnt != -1)
      60      arg->array[arg->cnt] = (void *) unwind_getip (ctx);
      61    if (++arg->cnt == arg->size)
      62      return _URC_END_OF_STACK;
      63    return _URC_NO_REASON;
      64  }
      65  
      66  int
      67  __backtrace (void **array, int size)
      68  {
      69    struct trace_arg arg =
      70      {
      71       .array = array,
      72       .unwind_link = __libc_unwind_link_get (),
      73       .size = size,
      74       .cnt = -1
      75      };
      76  
      77    if (size <= 0 || arg.unwind_link == NULL)
      78      return 0;
      79  
      80    UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
      81      (backtrace_helper, &arg);
      82  
      83    if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
      84      --arg.cnt;
      85    return arg.cnt != -1 ? arg.cnt : 0;
      86  }
      87  weak_alias (__backtrace, backtrace)
      88  libc_hidden_def (__backtrace)