1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include <complex.h>
6 #include <math.h>
7 #include <stdarg.h>
8 #include "runtime.h"
9 #include "array.h"
10 #include "go-type.h"
11
12 //static Lock debuglock;
13
14 // Clang requires this function to not be inlined (see below).
15 static void go_vprintf(const char*, va_list)
16 __attribute__((noinline));
17
18 // write to goroutine-local buffer if diverting output,
19 // or else standard error.
20 static void
gwrite(const void * v,intgo n)21 gwrite(const void *v, intgo n)
22 {
23 G* g = runtime_g();
24
25 if(g == nil || g->writebuf == nil) {
26 // Avoid -D_FORTIFY_SOURCE problems.
27 int rv __attribute__((unused));
28
29 rv = runtime_write(2, v, n);
30 return;
31 }
32
33 if(g->writenbuf == 0)
34 return;
35
36 if(n > g->writenbuf)
37 n = g->writenbuf;
38 runtime_memmove(g->writebuf, v, n);
39 g->writebuf += n;
40 g->writenbuf -= n;
41 }
42
43 void
runtime_dump(byte * p,int32 n)44 runtime_dump(byte *p, int32 n)
45 {
46 int32 i;
47
48 for(i=0; i<n; i++) {
49 runtime_printpointer((byte*)(uintptr)(p[i]>>4));
50 runtime_printpointer((byte*)(uintptr)(p[i]&0xf));
51 if((i&15) == 15)
52 runtime_prints("\n");
53 else
54 runtime_prints(" ");
55 }
56 if(n & 15)
57 runtime_prints("\n");
58 }
59
60 void
runtime_prints(const char * s)61 runtime_prints(const char *s)
62 {
63 gwrite(s, runtime_findnull((const byte*)s));
64 }
65
66 #if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
67 // LLVM's code generator does not currently support split stacks for vararg
68 // functions, so we disable the feature for this function under Clang. This
69 // appears to be OK as long as:
70 // - this function only calls non-inlined, internal-linkage (hence no dynamic
71 // loader) functions compiled with split stacks (i.e. go_vprintf), which can
72 // allocate more stack space as required;
73 // - this function itself does not occupy more than BACKOFF bytes of stack space
74 // (see libgcc/config/i386/morestack.S).
75 // These conditions are currently known to be satisfied by Clang on x86-32 and
76 // x86-64. Note that signal handlers receive slightly less stack space than they
77 // would normally do if they happen to be called while this function is being
78 // run. If this turns out to be a problem we could consider increasing BACKOFF.
79
80 void
81 runtime_printf(const char *s, ...)
82 __attribute__((no_split_stack));
83
84 int32
85 runtime_snprintf(byte *buf, int32 n, const char *s, ...)
86 __attribute__((no_split_stack));
87
88 #endif
89
90 void
runtime_printf(const char * s,...)91 runtime_printf(const char *s, ...)
92 {
93 va_list va;
94
95 va_start(va, s);
96 go_vprintf(s, va);
97 va_end(va);
98 }
99
100 int32
runtime_snprintf(byte * buf,int32 n,const char * s,...)101 runtime_snprintf(byte *buf, int32 n, const char *s, ...)
102 {
103 G *g = runtime_g();
104 va_list va;
105 int32 m;
106
107 g->writebuf = buf;
108 g->writenbuf = n-1;
109 va_start(va, s);
110 go_vprintf(s, va);
111 va_end(va);
112 *g->writebuf = '\0';
113 m = g->writebuf - buf;
114 g->writenbuf = 0;
115 g->writebuf = nil;
116 return m;
117 }
118
119 // Very simple printf. Only for debugging prints.
120 // Do not add to this without checking with Rob.
121 static void
go_vprintf(const char * s,va_list va)122 go_vprintf(const char *s, va_list va)
123 {
124 const char *p, *lp;
125
126 //runtime_lock(&debuglock);
127
128 lp = p = s;
129 for(; *p; p++) {
130 if(*p != '%')
131 continue;
132 if(p > lp)
133 gwrite(lp, p-lp);
134 p++;
135 switch(*p) {
136 case 'a':
137 runtime_printslice(va_arg(va, Slice));
138 break;
139 case 'c':
140 runtime_printbyte(va_arg(va, int32));
141 break;
142 case 'd':
143 runtime_printint(va_arg(va, int32));
144 break;
145 case 'D':
146 runtime_printint(va_arg(va, int64));
147 break;
148 case 'e':
149 runtime_printeface(va_arg(va, Eface));
150 break;
151 case 'f':
152 runtime_printfloat(va_arg(va, float64));
153 break;
154 case 'C':
155 runtime_printcomplex(va_arg(va, complex double));
156 break;
157 case 'i':
158 runtime_printiface(va_arg(va, Iface));
159 break;
160 case 'p':
161 runtime_printpointer(va_arg(va, void*));
162 break;
163 case 's':
164 runtime_prints(va_arg(va, char*));
165 break;
166 case 'S':
167 runtime_printstring(va_arg(va, String));
168 break;
169 case 't':
170 runtime_printbool(va_arg(va, int));
171 break;
172 case 'U':
173 runtime_printuint(va_arg(va, uint64));
174 break;
175 case 'x':
176 runtime_printhex(va_arg(va, uint32));
177 break;
178 case 'X':
179 runtime_printhex(va_arg(va, uint64));
180 break;
181 }
182 lp = p+1;
183 }
184 if(p > lp)
185 gwrite(lp, p-lp);
186
187 //runtime_unlock(&debuglock);
188 }
189
190 void
runtime_printpc(void * p)191 runtime_printpc(void *p __attribute__ ((unused)))
192 {
193 runtime_prints("PC=");
194 runtime_printhex((uint64)(uintptr)runtime_getcallerpc(p));
195 }
196
197 void
runtime_printbool(_Bool v)198 runtime_printbool(_Bool v)
199 {
200 if(v) {
201 gwrite("true", 4);
202 return;
203 }
204 gwrite("false", 5);
205 }
206
207 void
runtime_printbyte(int8 c)208 runtime_printbyte(int8 c)
209 {
210 gwrite(&c, 1);
211 }
212
213 void
runtime_printfloat(double v)214 runtime_printfloat(double v)
215 {
216 byte buf[20];
217 int32 e, s, i, n;
218 float64 h;
219
220 if(ISNAN(v)) {
221 gwrite("NaN", 3);
222 return;
223 }
224 if(isinf(v)) {
225 if(signbit(v)) {
226 gwrite("-Inf", 4);
227 } else {
228 gwrite("+Inf", 4);
229 }
230 return;
231 }
232
233 n = 7; // digits printed
234 e = 0; // exp
235 s = 0; // sign
236 if(v == 0) {
237 if(isinf(1/v) && 1/v < 0)
238 s = 1;
239 } else {
240 // sign
241 if(v < 0) {
242 v = -v;
243 s = 1;
244 }
245
246 // normalize
247 while(v >= 10) {
248 e++;
249 v /= 10;
250 }
251 while(v < 1) {
252 e--;
253 v *= 10;
254 }
255
256 // round
257 h = 5;
258 for(i=0; i<n; i++)
259 h /= 10;
260
261 v += h;
262 if(v >= 10) {
263 e++;
264 v /= 10;
265 }
266 }
267
268 // format +d.dddd+edd
269 buf[0] = '+';
270 if(s)
271 buf[0] = '-';
272 for(i=0; i<n; i++) {
273 s = v;
274 buf[i+2] = s+'0';
275 v -= s;
276 v *= 10.;
277 }
278 buf[1] = buf[2];
279 buf[2] = '.';
280
281 buf[n+2] = 'e';
282 buf[n+3] = '+';
283 if(e < 0) {
284 e = -e;
285 buf[n+3] = '-';
286 }
287
288 buf[n+4] = (e/100) + '0';
289 buf[n+5] = (e/10)%10 + '0';
290 buf[n+6] = (e%10) + '0';
291 gwrite(buf, n+7);
292 }
293
294 void
runtime_printcomplex(complex double v)295 runtime_printcomplex(complex double v)
296 {
297 gwrite("(", 1);
298 runtime_printfloat(creal(v));
299 runtime_printfloat(cimag(v));
300 gwrite("i)", 2);
301 }
302
303 void
runtime_printuint(uint64 v)304 runtime_printuint(uint64 v)
305 {
306 byte buf[100];
307 int32 i;
308
309 for(i=nelem(buf)-1; i>0; i--) {
310 buf[i] = v%10 + '0';
311 if(v < 10)
312 break;
313 v = v/10;
314 }
315 gwrite(buf+i, nelem(buf)-i);
316 }
317
318 void
runtime_printint(int64 v)319 runtime_printint(int64 v)
320 {
321 if(v < 0) {
322 gwrite("-", 1);
323 v = -v;
324 }
325 runtime_printuint(v);
326 }
327
328 void
runtime_printhex(uint64 v)329 runtime_printhex(uint64 v)
330 {
331 static const char *dig = "0123456789abcdef";
332 byte buf[100];
333 int32 i;
334
335 i=nelem(buf);
336 for(; v>0; v/=16)
337 buf[--i] = dig[v%16];
338 if(i == nelem(buf))
339 buf[--i] = '0';
340 buf[--i] = 'x';
341 buf[--i] = '0';
342 gwrite(buf+i, nelem(buf)-i);
343 }
344
345 void
runtime_printpointer(void * p)346 runtime_printpointer(void *p)
347 {
348 runtime_printhex((uintptr)p);
349 }
350
351 void
runtime_printstring(String v)352 runtime_printstring(String v)
353 {
354 // if(v.len > runtime_maxstring) {
355 // gwrite("[string too long]", 17);
356 // return;
357 // }
358 if(v.len > 0)
359 gwrite(v.str, v.len);
360 }
361
362 void
__go_print_space(void)363 __go_print_space(void)
364 {
365 gwrite(" ", 1);
366 }
367
368 void
__go_print_nl(void)369 __go_print_nl(void)
370 {
371 gwrite("\n", 1);
372 }
373