// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include #include #include #include "runtime.h" #include "array.h" #include "go-type.h" //static Lock debuglock; // Clang requires this function to not be inlined (see below). static void go_vprintf(const char*, va_list) __attribute__((noinline)); // write to goroutine-local buffer if diverting output, // or else standard error. static void gwrite(const void *v, intgo n) { G* g = runtime_g(); if(g == nil || g->writebuf == nil) { // Avoid -D_FORTIFY_SOURCE problems. int rv __attribute__((unused)); rv = runtime_write(2, v, n); return; } if(g->writenbuf == 0) return; if(n > g->writenbuf) n = g->writenbuf; runtime_memmove(g->writebuf, v, n); g->writebuf += n; g->writenbuf -= n; } void runtime_dump(byte *p, int32 n) { int32 i; for(i=0; i>4)); runtime_printpointer((byte*)(uintptr)(p[i]&0xf)); if((i&15) == 15) runtime_prints("\n"); else runtime_prints(" "); } if(n & 15) runtime_prints("\n"); } void runtime_prints(const char *s) { gwrite(s, runtime_findnull((const byte*)s)); } #if defined (__clang__) && (defined (__i386__) || defined (__x86_64__)) // LLVM's code generator does not currently support split stacks for vararg // functions, so we disable the feature for this function under Clang. This // appears to be OK as long as: // - this function only calls non-inlined, internal-linkage (hence no dynamic // loader) functions compiled with split stacks (i.e. go_vprintf), which can // allocate more stack space as required; // - this function itself does not occupy more than BACKOFF bytes of stack space // (see libgcc/config/i386/morestack.S). // These conditions are currently known to be satisfied by Clang on x86-32 and // x86-64. Note that signal handlers receive slightly less stack space than they // would normally do if they happen to be called while this function is being // run. If this turns out to be a problem we could consider increasing BACKOFF. void runtime_printf(const char *s, ...) __attribute__((no_split_stack)); int32 runtime_snprintf(byte *buf, int32 n, const char *s, ...) __attribute__((no_split_stack)); #endif void runtime_printf(const char *s, ...) { va_list va; va_start(va, s); go_vprintf(s, va); va_end(va); } int32 runtime_snprintf(byte *buf, int32 n, const char *s, ...) { G *g = runtime_g(); va_list va; int32 m; g->writebuf = buf; g->writenbuf = n-1; va_start(va, s); go_vprintf(s, va); va_end(va); *g->writebuf = '\0'; m = g->writebuf - buf; g->writenbuf = 0; g->writebuf = nil; return m; } // Very simple printf. Only for debugging prints. // Do not add to this without checking with Rob. static void go_vprintf(const char *s, va_list va) { const char *p, *lp; //runtime_lock(&debuglock); lp = p = s; for(; *p; p++) { if(*p != '%') continue; if(p > lp) gwrite(lp, p-lp); p++; switch(*p) { case 'a': runtime_printslice(va_arg(va, Slice)); break; case 'c': runtime_printbyte(va_arg(va, int32)); break; case 'd': runtime_printint(va_arg(va, int32)); break; case 'D': runtime_printint(va_arg(va, int64)); break; case 'e': runtime_printeface(va_arg(va, Eface)); break; case 'f': runtime_printfloat(va_arg(va, float64)); break; case 'C': runtime_printcomplex(va_arg(va, complex double)); break; case 'i': runtime_printiface(va_arg(va, Iface)); break; case 'p': runtime_printpointer(va_arg(va, void*)); break; case 's': runtime_prints(va_arg(va, char*)); break; case 'S': runtime_printstring(va_arg(va, String)); break; case 't': runtime_printbool(va_arg(va, int)); break; case 'U': runtime_printuint(va_arg(va, uint64)); break; case 'x': runtime_printhex(va_arg(va, uint32)); break; case 'X': runtime_printhex(va_arg(va, uint64)); break; } lp = p+1; } if(p > lp) gwrite(lp, p-lp); //runtime_unlock(&debuglock); } void runtime_printpc(void *p __attribute__ ((unused))) { runtime_prints("PC="); runtime_printhex((uint64)(uintptr)runtime_getcallerpc(p)); } void runtime_printbool(_Bool v) { if(v) { gwrite("true", 4); return; } gwrite("false", 5); } void runtime_printbyte(int8 c) { gwrite(&c, 1); } void runtime_printfloat(double v) { byte buf[20]; int32 e, s, i, n; float64 h; if(ISNAN(v)) { gwrite("NaN", 3); return; } if(isinf(v)) { if(signbit(v)) { gwrite("-Inf", 4); } else { gwrite("+Inf", 4); } return; } n = 7; // digits printed e = 0; // exp s = 0; // sign if(v == 0) { if(isinf(1/v) && 1/v < 0) s = 1; } else { // sign if(v < 0) { v = -v; s = 1; } // normalize while(v >= 10) { e++; v /= 10; } while(v < 1) { e--; v *= 10; } // round h = 5; for(i=0; i= 10) { e++; v /= 10; } } // format +d.dddd+edd buf[0] = '+'; if(s) buf[0] = '-'; for(i=0; i0; i--) { buf[i] = v%10 + '0'; if(v < 10) break; v = v/10; } gwrite(buf+i, nelem(buf)-i); } void runtime_printint(int64 v) { if(v < 0) { gwrite("-", 1); v = -v; } runtime_printuint(v); } void runtime_printhex(uint64 v) { static const char *dig = "0123456789abcdef"; byte buf[100]; int32 i; i=nelem(buf); for(; v>0; v/=16) buf[--i] = dig[v%16]; if(i == nelem(buf)) buf[--i] = '0'; buf[--i] = 'x'; buf[--i] = '0'; gwrite(buf+i, nelem(buf)-i); } void runtime_printpointer(void *p) { runtime_printhex((uintptr)p); } void runtime_printstring(String v) { // if(v.len > runtime_maxstring) { // gwrite("[string too long]", 17); // return; // } if(v.len > 0) gwrite(v.str, v.len); } void __go_print_space(void) { gwrite(" ", 1); } void __go_print_nl(void) { gwrite("\n", 1); }