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