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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgfortran/] [runtime/] [backtrace.c] - Blame information for rev 775

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

Line No. Rev Author Line
1 733 jeremybenn
/* Copyright (C) 2006, 2007, 2009, 2011, 2012 Free Software Foundation, Inc.
2
   Contributed by François-Xavier Coudert
3
 
4
This file is part of the GNU Fortran runtime library (libgfortran).
5
 
6
Libgfortran is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 3, or (at your option)
9
any later version.
10
 
11
Libgfortran is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
Under Section 7 of GPL version 3, you are granted additional
17
permissions described in the GCC Runtime Library Exception, version
18
3.1, as published by the Free Software Foundation.
19
 
20
You should have received a copy of the GNU General Public License and
21
a copy of the GCC Runtime Library Exception along with this program;
22
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23
<http://www.gnu.org/licenses/>.  */
24
 
25
#include "libgfortran.h"
26
 
27
#include <string.h>
28
#include <stdlib.h>
29
 
30
#ifdef HAVE_UNISTD_H
31
#include <unistd.h>
32
#endif
33
 
34
#ifdef HAVE_SYS_WAIT_H
35
#include <sys/wait.h>
36
#endif
37
 
38
#include <limits.h>
39
 
40
#include "unwind.h"
41
 
42
 
43
/* Macros for common sets of capabilities: can we fork and exec, and
44
   can we use pipes to communicate with the subprocess.  */
45
#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
46
                  && defined(HAVE_WAIT))
47
#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
48
                  && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
49
 
50
#ifndef PATH_MAX
51
#define PATH_MAX 4096
52
#endif
53
 
54
 
55
/* GDB style #NUM index for each stack frame.  */
56
 
57
static void
58
bt_header (int num)
59
{
60
  st_printf ("#%d  ", num);
61
}
62
 
63
 
64
/* fgets()-like function that reads a line from a fd, without
65
   needing to malloc() a buffer, and does not use locks, hence should
66
   be async-signal-safe.  */
67
 
68
static char *
69
fd_gets (char *s, int size, int fd)
70
{
71
  for (int i = 0; i < size; i++)
72
    {
73
      char c;
74
      ssize_t nread = read (fd, &c, 1);
75
      if (nread == 1)
76
        {
77
          s[i] = c;
78
          if (c == '\n')
79
            {
80
              if (i + 1 < size)
81
                s[i+1] = '\0';
82
              else
83
                s[i] = '\0';
84
              break;
85
            }
86
        }
87
      else
88
        {
89
          s[i] = '\0';
90
          if (i == 0)
91
            return NULL;
92
          break;
93
        }
94
    }
95
  return s;
96
}
97
 
98
 
99
extern char *addr2line_path;
100
 
101
/* Struct containing backtrace state.  */
102
typedef struct
103
{
104
  int frame_number;
105
  int direct_output;
106
  int outfd;
107
  int infd;
108
  int error;
109
}
110
bt_state;
111
 
112
static _Unwind_Reason_Code
113
trace_function (struct _Unwind_Context *context, void *state_ptr)
114
{
115
  bt_state* state = (bt_state*) state_ptr;
116
  _Unwind_Ptr ip;
117
#ifdef HAVE_GETIPINFO
118
  int ip_before_insn = 0;
119
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
120
 
121
  /* If the unwinder gave us a 'return' address, roll it back a little
122
     to ensure we get the correct line number for the call itself.  */
123
  if (! ip_before_insn)
124
    --ip;
125
#else  
126
  ip = _Unwind_GetIP (context);
127
#endif
128
 
129
  if (state->direct_output)
130
    {
131
      bt_header(state->frame_number);
132
      st_printf ("%p\n", (void*) ip);
133
    }
134
  else
135
    {
136
      char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
137
      char *p;
138
      const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
139
      write (state->outfd, addr, strlen (addr));
140
      write (state->outfd, "\n", 1);
141
 
142
      if (! fd_gets (func, sizeof(func), state->infd))
143
        {
144
          state->error = 1;
145
          goto done;
146
        }
147
      if (! fd_gets (file, sizeof(file), state->infd))
148
        {
149
          state->error = 1;
150
          goto done;
151
        }
152
 
153
        for (p = func; *p != '\n' && *p != '\r'; p++)
154
          ;
155
        *p = '\0';
156
 
157
        /* _start is a setup routine that calls main(), and main() is
158
           the frontend routine that calls some setup stuff and then
159
           calls MAIN__, so at this point we should stop.  */
160
        if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
161
          return _URC_END_OF_STACK;
162
 
163
        bt_header (state->frame_number);
164
        estr_write ("0x");
165
        estr_write (addr);
166
 
167
        if (func[0] != '?' && func[1] != '?')
168
          {
169
            estr_write (" in ");
170
            estr_write (func);
171
          }
172
 
173
        if (strncmp (file, "??", 2) == 0)
174
          estr_write ("\n");
175
        else
176
          {
177
            estr_write (" at ");
178
            estr_write (file);
179
          }
180
    }
181
 
182
 done:
183
 
184
  state->frame_number++;
185
 
186
  return _URC_NO_REASON;
187
}
188
 
189
 
190
/* Display the backtrace.  */
191
 
192
void
193
show_backtrace (void)
194
{
195
  bt_state state;
196
  state.frame_number = 0;
197
  state.error = 0;
198
 
199
  estr_write ("\nBacktrace for this error:\n");
200
 
201
#if CAN_PIPE
202
 
203
  if (addr2line_path == NULL)
204
    goto fallback_noerr;
205
 
206
  /* We attempt to extract file and line information from addr2line.  */
207
  do
208
  {
209
    /* Local variables.  */
210
    int f[2], pid, inp[2];
211
 
212
    /* Don't output an error message if something goes wrong, we'll simply
213
       fall back to printing the addresses.  */
214
    if (pipe (f) != 0)
215
      break;
216
    if (pipe (inp) != 0)
217
      break;
218
    if ((pid = fork ()) == -1)
219
      break;
220
 
221
    if (pid == 0)
222
      {
223
        /* Child process.  */
224
#define NUM_FIXEDARGS 7
225
        char *arg[NUM_FIXEDARGS];
226
        char *newenv[] = { NULL };
227
 
228
        close (f[0]);
229
 
230
        close (inp[1]);
231
        if (dup2 (inp[0], STDIN_FILENO) == -1)
232
          _exit (1);
233
        close (inp[0]);
234
 
235
        close (STDERR_FILENO);
236
 
237
        if (dup2 (f[1], STDOUT_FILENO) == -1)
238
          _exit (1);
239
        close (f[1]);
240
 
241
        arg[0] = addr2line_path;
242
        arg[1] = (char *) "-e";
243
        arg[2] = full_exe_path ();
244
        arg[3] = (char *) "-f";
245
        arg[4] = (char *) "-s";
246
        arg[5] = (char *) "-C";
247
        arg[6] = NULL;
248
        execve (addr2line_path, arg, newenv);
249
        _exit (1);
250
#undef NUM_FIXEDARGS
251
      }
252
 
253
    /* Father process.  */
254
    close (f[1]);
255
    close (inp[0]);
256
 
257
    state.outfd = inp[1];
258
    state.infd = f[0];
259
    state.direct_output = 0;
260
    _Unwind_Backtrace (trace_function, &state);
261
    if (state.error)
262
      goto fallback;
263
    close (inp[1]);
264
    wait (NULL);
265
    return;
266
 
267
fallback:
268
    estr_write ("** Something went wrong while running addr2line. **\n"
269
                "** Falling back to a simpler backtrace scheme. **\n");
270
  }
271
  while (0);
272
 
273
#endif /* CAN_PIPE */
274
 
275
fallback_noerr:
276
  /* Fallback to the simple backtrace without addr2line.  */
277
  state.direct_output = 1;
278
  _Unwind_Backtrace (trace_function, &state);
279
}

powered by: WebSVN 2.1.0

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