runtime: runtime.Caller should succeed even without debug info.
[gcc.git] / libgo / runtime / go-caller.c
1 /* go-caller.c -- runtime.Caller and runtime.FuncForPC for Go.
2
3 Copyright 2009 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 /* Implement runtime.Caller. */
8
9 #include <stdint.h>
10
11 #include "backtrace.h"
12
13 #include "runtime.h"
14 #include "go-string.h"
15
16 /* Get the function name, file name, and line number for a PC value.
17 We use the backtrace library to get this. */
18
19 /* Data structure to gather file/line information. */
20
21 struct caller
22 {
23 struct __go_string fn;
24 struct __go_string file;
25 int line;
26 };
27
28 /* Collect file/line information for a PC value. If this is called
29 more than once, due to inlined functions, we use the last call, as
30 that is usually the most useful one. */
31
32 static int
33 callback (void *data, uintptr_t pc __attribute__ ((unused)),
34 const char *filename, int lineno, const char *function)
35 {
36 struct caller *c = (struct caller *) data;
37
38 if (function == NULL)
39 {
40 c->fn.__data = NULL;
41 c->fn.__length = 0;
42 }
43 else
44 {
45 char *s;
46
47 c->fn.__length = __builtin_strlen (function);
48 s = runtime_malloc (c->fn.__length);
49 __builtin_memcpy (s, function, c->fn.__length);
50 c->fn.__data = (unsigned char *) s;
51 }
52
53 if (filename == NULL)
54 {
55 c->file.__data = NULL;
56 c->file.__length = 0;
57 }
58 else
59 {
60 char *s;
61
62 c->file.__length = __builtin_strlen (filename);
63 s = runtime_malloc (c->file.__length);
64 __builtin_memcpy (s, filename, c->file.__length);
65 c->file.__data = (unsigned char *) s;
66 }
67
68 c->line = lineno;
69
70 return 0;
71 }
72
73 /* The error callback for backtrace_pcinfo and backtrace_syminfo. */
74
75 static void
76 error_callback (void *data __attribute__ ((unused)),
77 const char *msg, int errnum)
78 {
79 if (errnum == -1)
80 return;
81 if (errnum > 0)
82 runtime_printf ("%s errno %d\n", msg, errnum);
83 runtime_throw (msg);
84 }
85
86 /* The backtrace library state. */
87
88 static void *back_state;
89
90 /* A lock to control creating back_state. */
91
92 static Lock back_state_lock;
93
94 /* Fetch back_state, creating it if necessary. */
95
96 struct backtrace_state *
97 __go_get_backtrace_state ()
98 {
99 runtime_lock (&back_state_lock);
100 if (back_state == NULL)
101 back_state = backtrace_create_state (NULL, 1, error_callback, NULL);
102 runtime_unlock (&back_state_lock);
103 return back_state;
104 }
105
106 /* Return function/file/line information for PC. */
107
108 _Bool
109 __go_file_line (uintptr pc, struct __go_string *fn, struct __go_string *file,
110 int *line)
111 {
112 struct caller c;
113
114 runtime_memclr (&c, sizeof c);
115 backtrace_pcinfo (__go_get_backtrace_state (), pc, callback,
116 error_callback, &c);
117 *fn = c.fn;
118 *file = c.file;
119 *line = c.line;
120 return c.file.__length > 0;
121 }
122
123 /* Collect symbol information. */
124
125 static void
126 syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
127 const char *symname __attribute__ ((unused)),
128 uintptr_t address)
129 {
130 uintptr_t *pval = (uintptr_t *) data;
131
132 *pval = address;
133 }
134
135 /* Set *VAL to the value of the symbol for PC. */
136
137 static _Bool
138 __go_symbol_value (uintptr_t pc, uintptr_t *val)
139 {
140 *val = 0;
141 backtrace_syminfo (__go_get_backtrace_state (), pc, syminfo_callback,
142 error_callback, &val);
143 return *val != 0;
144 }
145
146 /* The values returned by runtime.Caller. */
147
148 struct caller_ret
149 {
150 uintptr_t pc;
151 struct __go_string file;
152 int line;
153 _Bool ok;
154 };
155
156 struct caller_ret Caller (int n) asm ("runtime.Caller");
157
158 Func *FuncForPC (uintptr_t) asm ("runtime.FuncForPC");
159
160 /* Implement runtime.Caller. */
161
162 struct caller_ret
163 Caller (int skip)
164 {
165 struct caller_ret ret;
166 uintptr pc;
167 int32 n;
168 struct __go_string fn;
169
170 runtime_memclr (&ret, sizeof ret);
171 n = runtime_callers (skip + 1, &pc, 1);
172 if (n < 1)
173 return ret;
174 ret.pc = pc;
175 __go_file_line (pc, &fn, &ret.file, &ret.line);
176 ret.ok = 1;
177 return ret;
178 }
179
180 /* Implement runtime.FuncForPC. */
181
182 Func *
183 FuncForPC (uintptr_t pc)
184 {
185 Func *ret;
186 struct __go_string fn;
187 struct __go_string file;
188 int line;
189 uintptr_t val;
190
191 if (!__go_file_line (pc, &fn, &file, &line))
192 return NULL;
193
194 ret = (Func *) runtime_malloc (sizeof (*ret));
195 ret->name = fn;
196
197 if (__go_symbol_value (pc, &val))
198 ret->entry = val;
199 else
200 ret->entry = 0;
201
202 return ret;
203 }
204
205 /* Look up the file and line information for a PC within a
206 function. */
207
208 struct funcline_go_return
209 {
210 struct __go_string retfile;
211 int retline;
212 };
213
214 struct funcline_go_return
215 runtime_funcline_go (Func *f, uintptr targetpc)
216 __asm__ ("runtime.funcline_go");
217
218 struct funcline_go_return
219 runtime_funcline_go (Func *f __attribute__((unused)), uintptr targetpc)
220 {
221 struct funcline_go_return ret;
222 struct __go_string fn;
223
224 if (!__go_file_line (targetpc, &fn, &ret.retfile, &ret.retline))
225 runtime_memclr (&ret, sizeof ret);
226 return ret;
227 }