OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgfortran/] [runtime/] [backtrace.c] - Rev 736

Go to most recent revision | Compare with Previous | Blame | View Log

/* Copyright (C) 2006, 2007, 2009, 2011, 2012 Free Software Foundation, Inc.
   Contributed by François-Xavier Coudert
 
This file is part of the GNU Fortran runtime library (libgfortran).
 
Libgfortran is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
Libgfortran is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
 
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */
 
#include "libgfortran.h"
 
#include <string.h>
#include <stdlib.h>
 
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
 
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
 
#include <limits.h>
 
#include "unwind.h"
 
 
/* Macros for common sets of capabilities: can we fork and exec, and
   can we use pipes to communicate with the subprocess.  */
#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
		  && defined(HAVE_WAIT))
#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
		  && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
 
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
 
 
/* GDB style #NUM index for each stack frame.  */
 
static void 
bt_header (int num)
{
  st_printf ("#%d  ", num);
}
 
 
/* fgets()-like function that reads a line from a fd, without
   needing to malloc() a buffer, and does not use locks, hence should
   be async-signal-safe.  */
 
static char *
fd_gets (char *s, int size, int fd)
{
  for (int i = 0; i < size; i++)
    {
      char c;
      ssize_t nread = read (fd, &c, 1);
      if (nread == 1)
	{
	  s[i] = c;
	  if (c == '\n')
	    {
	      if (i + 1 < size)
		s[i+1] = '\0';
	      else
		s[i] = '\0';
	      break;
	    }
	}
      else
	{
	  s[i] = '\0';
	  if (i == 0)
	    return NULL;
	  break;
	}
    }
  return s;
}
 
 
extern char *addr2line_path;
 
/* Struct containing backtrace state.  */
typedef struct
{
  int frame_number;
  int direct_output;
  int outfd;
  int infd;
  int error;
}
bt_state;
 
static _Unwind_Reason_Code
trace_function (struct _Unwind_Context *context, void *state_ptr)
{
  bt_state* state = (bt_state*) state_ptr;
  _Unwind_Ptr ip;
#ifdef HAVE_GETIPINFO
  int ip_before_insn = 0;
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
 
  /* If the unwinder gave us a 'return' address, roll it back a little
     to ensure we get the correct line number for the call itself.  */
  if (! ip_before_insn)
    --ip;
#else  
  ip = _Unwind_GetIP (context);
#endif
 
  if (state->direct_output)
    {
      bt_header(state->frame_number);
      st_printf ("%p\n", (void*) ip);
    }
  else
    {
      char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
      char *p;
      const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
      write (state->outfd, addr, strlen (addr));
      write (state->outfd, "\n", 1);
 
      if (! fd_gets (func, sizeof(func), state->infd))
	{
	  state->error = 1;
	  goto done;
	}
      if (! fd_gets (file, sizeof(file), state->infd))
	{
	  state->error = 1;
	  goto done;
	}
 
	for (p = func; *p != '\n' && *p != '\r'; p++)
	  ;
	*p = '\0';
 
	/* _start is a setup routine that calls main(), and main() is
	   the frontend routine that calls some setup stuff and then
	   calls MAIN__, so at this point we should stop.  */
	if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
	  return _URC_END_OF_STACK;
 
	bt_header (state->frame_number);
	estr_write ("0x");
	estr_write (addr);
 
	if (func[0] != '?' && func[1] != '?')
	  {
	    estr_write (" in ");
	    estr_write (func);
	  }
 
	if (strncmp (file, "??", 2) == 0)
	  estr_write ("\n");
	else
	  {
	    estr_write (" at ");
	    estr_write (file);
	  }
    }
 
 done:
 
  state->frame_number++;
 
  return _URC_NO_REASON;
}
 
 
/* Display the backtrace.  */
 
void
show_backtrace (void)
{
  bt_state state;
  state.frame_number = 0;
  state.error = 0;
 
  estr_write ("\nBacktrace for this error:\n");
 
#if CAN_PIPE
 
  if (addr2line_path == NULL)
    goto fallback_noerr;
 
  /* We attempt to extract file and line information from addr2line.  */
  do
  {
    /* Local variables.  */
    int f[2], pid, inp[2];
 
    /* Don't output an error message if something goes wrong, we'll simply
       fall back to printing the addresses.  */
    if (pipe (f) != 0)
      break;
    if (pipe (inp) != 0)
      break;
    if ((pid = fork ()) == -1)
      break;
 
    if (pid == 0)
      {
	/* Child process.  */
#define NUM_FIXEDARGS 7
	char *arg[NUM_FIXEDARGS];
	char *newenv[] = { NULL };
 
	close (f[0]);
 
	close (inp[1]);
	if (dup2 (inp[0], STDIN_FILENO) == -1)
	  _exit (1);
	close (inp[0]);
 
	close (STDERR_FILENO);
 
	if (dup2 (f[1], STDOUT_FILENO) == -1)
	  _exit (1);
	close (f[1]);
 
	arg[0] = addr2line_path;
	arg[1] = (char *) "-e";
	arg[2] = full_exe_path ();
	arg[3] = (char *) "-f";
	arg[4] = (char *) "-s";
	arg[5] = (char *) "-C";
	arg[6] = NULL;
	execve (addr2line_path, arg, newenv);
	_exit (1);
#undef NUM_FIXEDARGS
      }
 
    /* Father process.  */
    close (f[1]);
    close (inp[0]);
 
    state.outfd = inp[1];
    state.infd = f[0];
    state.direct_output = 0;
    _Unwind_Backtrace (trace_function, &state);
    if (state.error)
      goto fallback;
    close (inp[1]);
    wait (NULL);
    return;
 
fallback:
    estr_write ("** Something went wrong while running addr2line. **\n"
		"** Falling back to a simpler backtrace scheme. **\n");
  }
  while (0);
 
#endif /* CAN_PIPE */
 
fallback_noerr:
  /* Fallback to the simple backtrace without addr2line.  */
  state.direct_output = 1;
  _Unwind_Backtrace (trace_function, &state);
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.