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 extern void runtime_printlock(void)
13   __asm__(GOSYM_PREFIX "runtime.printlock");
14 extern void runtime_printunlock(void)
15   __asm__(GOSYM_PREFIX "runtime.printunlock");
16 extern void gwrite(Slice)
17   __asm__(GOSYM_PREFIX "runtime.gwrite");
18 extern void runtime_printint(int64)
19   __asm__(GOSYM_PREFIX "runtime.printint");
20 extern void runtime_printuint(uint64)
21   __asm__(GOSYM_PREFIX "runtime.printuint");
22 extern void runtime_printhex(uint64)
23   __asm__(GOSYM_PREFIX "runtime.printhex");
24 extern void runtime_printfloat(float64)
25   __asm__(GOSYM_PREFIX "runtime.printfloat");
26 extern void runtime_printcomplex(complex double)
27   __asm__(GOSYM_PREFIX "runtime.printcomplex");
28 extern void runtime_printbool(_Bool)
29   __asm__(GOSYM_PREFIX "runtime.printbool");
30 extern void runtime_printstring(String)
31   __asm__(GOSYM_PREFIX "runtime.printstring");
32 extern void runtime_printpointer(void *)
33   __asm__(GOSYM_PREFIX "runtime.printpointer");
34 extern void runtime_printslice(Slice)
35   __asm__(GOSYM_PREFIX "runtime.printslice");
36 extern void runtime_printeface(Eface)
37   __asm__(GOSYM_PREFIX "runtime.printeface");
38 extern void runtime_printiface(Iface)
39   __asm__(GOSYM_PREFIX "runtime.printiface");
40 
41 // Clang requires this function to not be inlined (see below).
42 static void go_vprintf(const char*, va_list)
43 __attribute__((noinline));
44 
45 static void
runtime_prints(const char * s)46 runtime_prints(const char *s)
47 {
48 	Slice sl;
49 
50 	// Use memcpy to avoid const-cast warning.
51 	memcpy(&sl.__values, &s, sizeof(char*));
52 	sl.__count = runtime_findnull((const byte*)s);
53 	sl.__capacity = sl.__count;
54 	gwrite(sl);
55 }
56 
57 static void
runtime_printbyte(int8 c)58 runtime_printbyte(int8 c)
59 {
60 	Slice sl;
61 
62 	sl.__values = &c;
63 	sl.__count = 1;
64 	sl.__capacity = 1;
65 	gwrite(sl);
66 }
67 
68 #if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
69 // LLVM's code generator does not currently support split stacks for vararg
70 // functions, so we disable the feature for this function under Clang. This
71 // appears to be OK as long as:
72 // - this function only calls non-inlined, internal-linkage (hence no dynamic
73 //   loader) functions compiled with split stacks (i.e. go_vprintf), which can
74 //   allocate more stack space as required;
75 // - this function itself does not occupy more than BACKOFF bytes of stack space
76 //   (see libgcc/config/i386/morestack.S).
77 // These conditions are currently known to be satisfied by Clang on x86-32 and
78 // x86-64. Note that signal handlers receive slightly less stack space than they
79 // would normally do if they happen to be called while this function is being
80 // run. If this turns out to be a problem we could consider increasing BACKOFF.
81 
82 void
83 runtime_printf(const char *s, ...)
84 __attribute__((no_split_stack));
85 
86 int32
87 runtime_snprintf(byte *buf, int32 n, const char *s, ...)
88 __attribute__((no_split_stack));
89 
90 #endif
91 
92 void
runtime_printf(const char * s,...)93 runtime_printf(const char *s, ...)
94 {
95 	va_list va;
96 
97 	va_start(va, s);
98 	go_vprintf(s, va);
99 	va_end(va);
100 }
101 
102 int32
runtime_snprintf(byte * buf,int32 n,const char * s,...)103 runtime_snprintf(byte *buf, int32 n, const char *s, ...)
104 {
105 	G *g = runtime_g();
106 	va_list va;
107 	int32 m;
108 
109 	g->writebuf.__values = buf;
110 	g->writebuf.__count = 0;
111 	g->writebuf.__capacity = n-1;
112 	va_start(va, s);
113 	go_vprintf(s, va);
114 	va_end(va);
115 	m = g->writebuf.__count;
116 	((byte*)g->writebuf.__values)[m] = '\0';
117 	g->writebuf.__values = nil;
118 	g->writebuf.__count = 0;
119 	g->writebuf.__capacity = 0;
120 	return m;
121 }
122 
123 // Very simple printf.  Only for debugging prints.
124 // Do not add to this without checking with Rob.
125 static void
go_vprintf(const char * s,va_list va)126 go_vprintf(const char *s, va_list va)
127 {
128 	const char *p, *lp;
129 	Slice sl;
130 
131 	runtime_printlock();
132 
133 	lp = p = s;
134 	for(; *p; p++) {
135 		if(*p != '%')
136 			continue;
137 		if(p > lp) {
138 			// Use memcpy to avoid const-cast warning.
139 			memcpy(&sl.__values, &lp, sizeof(char*));
140 			sl.__count = p - lp;
141 			sl.__capacity = p - lp;
142 			gwrite(sl);
143 		}
144 		p++;
145 		switch(*p) {
146 		case 'a':
147 			runtime_printslice(va_arg(va, Slice));
148 			break;
149 		case 'c':
150 			runtime_printbyte(va_arg(va, int32));
151 			break;
152 		case 'd':
153 			runtime_printint(va_arg(va, int32));
154 			break;
155 		case 'D':
156 			runtime_printint(va_arg(va, int64));
157 			break;
158 		case 'e':
159 			runtime_printeface(va_arg(va, Eface));
160 			break;
161 		case 'f':
162 			runtime_printfloat(va_arg(va, float64));
163 			break;
164 		case 'C':
165 			runtime_printcomplex(va_arg(va, complex double));
166 			break;
167 		case 'i':
168 			runtime_printiface(va_arg(va, Iface));
169 			break;
170 		case 'p':
171 			runtime_printpointer(va_arg(va, void*));
172 			break;
173 		case 's':
174 			runtime_prints(va_arg(va, char*));
175 			break;
176 		case 'S':
177 			runtime_printstring(va_arg(va, String));
178 			break;
179 		case 't':
180 			runtime_printbool(va_arg(va, int));
181 			break;
182 		case 'U':
183 			runtime_printuint(va_arg(va, uint64));
184 			break;
185 		case 'x':
186 			runtime_printhex(va_arg(va, uint32));
187 			break;
188 		case 'X':
189 			runtime_printhex(va_arg(va, uint64));
190 			break;
191 		}
192 		lp = p+1;
193 	}
194 	if(p > lp) {
195 		// Use memcpy to avoid const-cast warning.
196 		memcpy(&sl.__values, &lp, sizeof(char*));
197 		sl.__count = p - lp;
198 		sl.__capacity = p - lp;
199 		gwrite(sl);
200 	}
201 
202 	runtime_printunlock();
203 }
204