(root)/
glibc-2.38/
sysdeps/
i386/
backtrace.c
       1  /* Return backtrace of current program state.
       2     Copyright (C) 1998-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    void *lastebp, *lastesp;
      29  };
      30  
      31  static _Unwind_Reason_Code
      32  backtrace_helper (struct _Unwind_Context *ctx, void *a)
      33  {
      34    struct trace_arg *arg = a;
      35  
      36    /* We are first called with address in the __backtrace function.
      37       Skip it.  */
      38    if (arg->cnt != -1)
      39      arg->array[arg->cnt]
      40        = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
      41    if (++arg->cnt == arg->size)
      42      return _URC_END_OF_STACK;
      43  
      44    /* %ebp is DWARF2 register 5 on IA-32.  */
      45    arg->lastebp
      46      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetGR) (ctx, 5);
      47    arg->lastesp
      48      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
      49    return _URC_NO_REASON;
      50  }
      51  
      52  
      53  /* This is a global variable set at program start time.  It marks the
      54     highest used stack address.  */
      55  extern void *__libc_stack_end;
      56  
      57  
      58  /* This is the stack layout we see with every stack frame
      59     if not compiled without frame pointer.
      60  
      61              +-----------------+        +-----------------+
      62      %ebp -> | %ebp last frame--------> | %ebp last frame--->...
      63              |                 |        |                 |
      64              | return address  |        | return address  |
      65              +-----------------+        +-----------------+
      66  
      67     First try as far to get as far as possible using
      68     _Unwind_Backtrace which handles -fomit-frame-pointer
      69     as well, but requires .eh_frame info.  Then fall back to
      70     walking the stack manually.  */
      71  
      72  struct layout
      73  {
      74    struct layout *ebp;
      75    void *ret;
      76  };
      77  
      78  
      79  int
      80  __backtrace (void **array, int size)
      81  {
      82    struct trace_arg arg =
      83      {
      84       .array = array,
      85       .unwind_link = __libc_unwind_link_get (),
      86       .size = size,
      87       .cnt = -1,
      88      };
      89  
      90    if (size <= 0 || arg.unwind_link == NULL)
      91      return 0;
      92  
      93    UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
      94      (backtrace_helper, &arg);
      95  
      96    if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
      97      --arg.cnt;
      98    else if (arg.cnt < size)
      99      {
     100        struct layout *ebp = (struct layout *) arg.lastebp;
     101  
     102        while (arg.cnt < size)
     103  	{
     104  	  /* Check for out of range.  */
     105  	  if ((void *) ebp < arg.lastesp || (void *) ebp > __libc_stack_end
     106  	      || ((long) ebp & 3))
     107  	    break;
     108  
     109  	  array[arg.cnt++] = ebp->ret;
     110  	  ebp = ebp->ebp;
     111  	}
     112      }
     113    return arg.cnt != -1 ? arg.cnt : 0;
     114  }
     115  weak_alias (__backtrace, backtrace)
     116  libc_hidden_def (__backtrace)