Importing Upstream version 4.8.2
[platform/upstream/gcc48.git] / libgo / runtime / go-callers.c
1 /* go-callers.c -- get callers for Go.
2
3    Copyright 2012 The Go Authors. All rights reserved.
4    Use of this source code is governed by a BSD-style
5    license that can be found in the LICENSE file.  */
6
7 #include "config.h"
8
9 #include "backtrace.h"
10
11 #include "runtime.h"
12 #include "array.h"
13
14 /* Argument passed to callback function.  */
15
16 struct callers_data
17 {
18   Location *locbuf;
19   int skip;
20   int index;
21   int max;
22 };
23
24 /* Callback function for backtrace_full.  Just collect the locations.
25    Return zero to continue, non-zero to stop.  */
26
27 static int
28 callback (void *data, uintptr_t pc, const char *filename, int lineno,
29           const char *function)
30 {
31   struct callers_data *arg = (struct callers_data *) data;
32   Location *loc;
33
34   /* Skip split stack functions.  */
35   if (function != NULL)
36     {
37       const char *p;
38
39       p = function;
40       if (__builtin_strncmp (p, "___", 3) == 0)
41         ++p;
42       if (__builtin_strncmp (p, "__morestack_", 12) == 0)
43         return 0;
44     }
45   else if (filename != NULL)
46     {
47       const char *p;
48
49       p = strrchr (filename, '/');
50       if (p == NULL)
51         p = filename;
52       if (__builtin_strncmp (p, "/morestack.S", 12) == 0)
53         return 0;
54     }
55
56   /* Skip thunks and recover functions.  There is no equivalent to
57      these functions in the gc toolchain, so returning them here means
58      significantly different results for runtime.Caller(N).  */
59   if (function != NULL)
60     {
61       const char *p;
62
63       p = __builtin_strchr (function, '.');
64       if (p != NULL && __builtin_strncmp (p + 1, "$thunk", 6) == 0)
65         return 0;
66       p = __builtin_strrchr (function, '$');
67       if (p != NULL && __builtin_strcmp(p, "$recover") == 0)
68         return 0;
69     }
70
71   if (arg->skip > 0)
72     {
73       --arg->skip;
74       return 0;
75     }
76
77   loc = &arg->locbuf[arg->index];
78   loc->pc = pc;
79
80   /* The libbacktrace library says that these strings might disappear,
81      but with the current implementation they won't.  We can't easily
82      allocate memory here, so for now assume that we can save a
83      pointer to the strings.  */
84   loc->filename = runtime_gostringnocopy ((const byte *) filename);
85   loc->function = runtime_gostringnocopy ((const byte *) function);
86
87   loc->lineno = lineno;
88   ++arg->index;
89   return arg->index >= arg->max;
90 }
91
92 /* Error callback.  */
93
94 static void
95 error_callback (void *data __attribute__ ((unused)),
96                 const char *msg, int errnum)
97 {
98   if (errnum != 0)
99     runtime_printf ("%s errno %d\n", msg, errnum);
100   runtime_throw (msg);
101 }
102
103 /* Gather caller PC's.  */
104
105 int32
106 runtime_callers (int32 skip, Location *locbuf, int32 m)
107 {
108   struct callers_data data;
109
110   data.locbuf = locbuf;
111   data.skip = skip + 1;
112   data.index = 0;
113   data.max = m;
114   backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
115                   &data);
116   return data.index;
117 }
118
119 int Callers (int, struct __go_open_array)
120   __asm__ (GOSYM_PREFIX "runtime.Callers");
121
122 int
123 Callers (int skip, struct __go_open_array pc)
124 {
125   Location *locbuf;
126   int ret;
127   int i;
128
129   locbuf = (Location *) runtime_mal (pc.__count * sizeof (Location));
130
131   /* In the Go 1 release runtime.Callers has an off-by-one error,
132      which we can not correct because it would break backward
133      compatibility.  Normally we would add 1 to SKIP here, but we
134      don't so that we are compatible.  */
135   ret = runtime_callers (skip, locbuf, pc.__count);
136
137   for (i = 0; i < ret; i++)
138     ((uintptr *) pc.__values)[i] = locbuf[i].pc;
139
140   return ret;
141 }