(root)/
glibc-2.38/
sysdeps/
microblaze/
backtrace.c
       1  /* Copyright (C) 2005-2023 Free Software Foundation, Inc.
       2  
       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 License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     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 <stdio.h>
      20  #include <stdlib.h>
      21  #include <string.h>
      22  #include <sysdep.h>
      23  #include <signal.h>
      24  #include <execinfo.h>
      25  
      26  extern int
      27  _identify_sighandler (unsigned long fp, unsigned long pc,
      28                        unsigned long *pprev_fp, unsigned long *pprev_pc,
      29                        unsigned long *retaddr);
      30  
      31  static inline long
      32  get_frame_size (unsigned long instr)
      33  {
      34    return abs ((short signed) (instr & 0xFFFF));
      35  }
      36  
      37  static unsigned long *
      38  find_frame_creation (unsigned long *pc)
      39  {
      40    int i;
      41  
      42    /* NOTE: Distance to search is arbitrary.
      43       250 works well for most things,
      44       750 picks up things like tcp_recvmsg,
      45       1000 needed for fat_fill_super.  */
      46    for (i = 0; i < 1000; i++, pc--)
      47      {
      48        unsigned long instr;
      49        unsigned long frame_size;
      50  
      51        instr = *pc;
      52  
      53        /* Is the instruction of the form
      54           addik r1, r1, foo ? */
      55        if ((instr & 0xFFFF0000) != 0x30210000)
      56          continue;
      57  
      58        frame_size = get_frame_size (instr);
      59  
      60        if ((frame_size < 8) || (frame_size & 3))
      61          return NULL;
      62  
      63        return pc;
      64      }
      65    return NULL;
      66  }
      67  
      68  static int
      69  lookup_prev_stack_frame (unsigned long fp, unsigned long pc,
      70                           unsigned long *pprev_fp, unsigned long *pprev_pc,
      71                           unsigned long *retaddr)
      72  {
      73    unsigned long *prologue = NULL;
      74  
      75    int is_signalhandler = _identify_sighandler (fp, pc, pprev_fp,
      76                                                 pprev_pc, retaddr);
      77  
      78    if (!is_signalhandler)
      79      {
      80        prologue = find_frame_creation ((unsigned long *) pc);
      81  
      82        if (prologue)
      83          {
      84            long frame_size = get_frame_size (*prologue);
      85            *pprev_fp = fp + frame_size;
      86            if (*retaddr != 0)
      87              *pprev_pc = *retaddr;
      88            else
      89              *pprev_pc = *(unsigned long *) fp;
      90  
      91            *retaddr = 0;
      92            if (!*pprev_pc || (*pprev_pc & 3))
      93              prologue=0;
      94          }
      95        else
      96          {
      97            *pprev_pc = 0;
      98            *pprev_fp = fp;
      99            *retaddr = 0;
     100          }
     101      }
     102      return (!*pprev_pc || (*pprev_pc & 3)) ? -1 : 0;
     103  }
     104  
     105  int
     106  __backtrace (void **array, int size)
     107  {
     108    unsigned long pc, fp;
     109    unsigned long ppc, pfp;
     110    /* Return address(r15) is required in the signal handler case, since the
     111       return address of the function which causes the signal may not be
     112       recorded in the stack.  */
     113    unsigned long retaddr;
     114  
     115    int count;
     116    int rc = 0;
     117  
     118    if (size <= 0)
     119      return 0;
     120  
     121    __asm__ __volatile__ ("mfs %0, rpc"
     122                          : "=r"(pc));
     123  
     124    __asm__ __volatile__ ("add %0, r1, r0"
     125                          : "=r"(fp));
     126  
     127    array[0] = (void *) pc;
     128    retaddr = 0;
     129    for (count = 1; count < size; count++)
     130      {
     131        rc = lookup_prev_stack_frame (fp, pc, &pfp, &ppc, &retaddr);
     132  
     133        fp = pfp;
     134        pc = ppc;
     135        array[count] = (void *) pc;
     136        if (rc)
     137          return count;
     138      }
     139    return count;
     140  }
     141  
     142  weak_alias (__backtrace, backtrace)
     143  libc_hidden_def (__backtrace)