Blame sysdeps/microblaze/backtrace.c

Packit Service 82fcde
/* Copyright (C) 2005-2018 Free Software Foundation, Inc.
Packit Service 82fcde
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public License as
Packit Service 82fcde
   published by the Free Software Foundation; either version 2.1 of the
Packit Service 82fcde
   License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
#include <signal.h>
Packit Service 82fcde
#include <execinfo.h>
Packit Service 82fcde
Packit Service 82fcde
extern int
Packit Service 82fcde
_identify_sighandler (unsigned long fp, unsigned long pc,
Packit Service 82fcde
                      unsigned long *pprev_fp, unsigned long *pprev_pc,
Packit Service 82fcde
                      unsigned long *retaddr);
Packit Service 82fcde
Packit Service 82fcde
static inline long
Packit Service 82fcde
get_frame_size (unsigned long instr)
Packit Service 82fcde
{
Packit Service 82fcde
  return abs ((short signed) (instr & 0xFFFF));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static unsigned long *
Packit Service 82fcde
find_frame_creation (unsigned long *pc)
Packit Service 82fcde
{
Packit Service 82fcde
  int i;
Packit Service 82fcde
Packit Service 82fcde
  /* NOTE: Distance to search is arbitrary.
Packit Service 82fcde
     250 works well for most things,
Packit Service 82fcde
     750 picks up things like tcp_recvmsg,
Packit Service 82fcde
     1000 needed for fat_fill_super.  */
Packit Service 82fcde
  for (i = 0; i < 1000; i++, pc--)
Packit Service 82fcde
    {
Packit Service 82fcde
      unsigned long instr;
Packit Service 82fcde
      unsigned long frame_size;
Packit Service 82fcde
Packit Service 82fcde
      instr = *pc;
Packit Service 82fcde
Packit Service 82fcde
      /* Is the instruction of the form
Packit Service 82fcde
         addik r1, r1, foo ? */
Packit Service 82fcde
      if ((instr & 0xFFFF0000) != 0x30210000)
Packit Service 82fcde
        continue;
Packit Service 82fcde
Packit Service 82fcde
      frame_size = get_frame_size (instr);
Packit Service 82fcde
Packit Service 82fcde
      if ((frame_size < 8) || (frame_size & 3))
Packit Service 82fcde
        return NULL;
Packit Service 82fcde
Packit Service 82fcde
      return pc;
Packit Service 82fcde
    }
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
lookup_prev_stack_frame (unsigned long fp, unsigned long pc,
Packit Service 82fcde
                         unsigned long *pprev_fp, unsigned long *pprev_pc,
Packit Service 82fcde
                         unsigned long *retaddr)
Packit Service 82fcde
{
Packit Service 82fcde
  unsigned long *prologue = NULL;
Packit Service 82fcde
Packit Service 82fcde
  int is_signalhandler = _identify_sighandler (fp, pc, pprev_fp,
Packit Service 82fcde
                                               pprev_pc, retaddr);
Packit Service 82fcde
Packit Service 82fcde
  if (!is_signalhandler)
Packit Service 82fcde
    {
Packit Service 82fcde
      prologue = find_frame_creation ((unsigned long *) pc);
Packit Service 82fcde
Packit Service 82fcde
      if (prologue)
Packit Service 82fcde
        {
Packit Service 82fcde
          long frame_size = get_frame_size (*prologue);
Packit Service 82fcde
          *pprev_fp = fp + frame_size;
Packit Service 82fcde
          if (*retaddr != 0)
Packit Service 82fcde
            *pprev_pc = *retaddr;
Packit Service 82fcde
          else
Packit Service 82fcde
            *pprev_pc = *(unsigned long *) fp;
Packit Service 82fcde
Packit Service 82fcde
          *retaddr = 0;
Packit Service 82fcde
          if (!*pprev_pc || (*pprev_pc & 3))
Packit Service 82fcde
            prologue=0;
Packit Service 82fcde
        }
Packit Service 82fcde
      else
Packit Service 82fcde
        {
Packit Service 82fcde
          *pprev_pc = 0;
Packit Service 82fcde
          *pprev_fp = fp;
Packit Service 82fcde
          *retaddr = 0;
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
    return (!*pprev_pc || (*pprev_pc & 3)) ? -1 : 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
__backtrace (void **array, int size)
Packit Service 82fcde
{
Packit Service 82fcde
  unsigned long pc, fp;
Packit Service 82fcde
  unsigned long ppc, pfp;
Packit Service 82fcde
  /* Return address(r15) is required in the signal handler case, since the
Packit Service 82fcde
     return address of the function which causes the signal may not be
Packit Service 82fcde
     recorded in the stack.  */
Packit Service 82fcde
  unsigned long retaddr;
Packit Service 82fcde
Packit Service 82fcde
  int count;
Packit Service 82fcde
  int rc = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (size <= 0)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  __asm__ __volatile__ ("mfs %0, rpc"
Packit Service 82fcde
                        : "=r"(pc));
Packit Service 82fcde
Packit Service 82fcde
  __asm__ __volatile__ ("add %0, r1, r0"
Packit Service 82fcde
                        : "=r"(fp));
Packit Service 82fcde
Packit Service 82fcde
  array[0] = (void *) pc;
Packit Service 82fcde
  retaddr = 0;
Packit Service 82fcde
  for (count = 1; count < size; count++)
Packit Service 82fcde
    {
Packit Service 82fcde
      rc = lookup_prev_stack_frame (fp, pc, &pfp, &ppc, &retaddr);
Packit Service 82fcde
Packit Service 82fcde
      fp = pfp;
Packit Service 82fcde
      pc = ppc;
Packit Service 82fcde
      array[count] = (void *) pc;
Packit Service 82fcde
      if (rc)
Packit Service 82fcde
        return count;
Packit Service 82fcde
    }
Packit Service 82fcde
  return count;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
weak_alias (__backtrace, backtrace)
Packit Service 82fcde
libc_hidden_def (__backtrace)