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