123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- // 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 <complex.h>
- #include <math.h>
- #include <stdarg.h>
- #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<n; i++) {
- runtime_printpointer((byte*)(uintptr)(p[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<n; i++)
- h /= 10;
- v += h;
- if(v >= 10) {
- e++;
- v /= 10;
- }
- }
- // format +d.dddd+edd
- buf[0] = '+';
- if(s)
- buf[0] = '-';
- for(i=0; i<n; i++) {
- s = v;
- buf[i+2] = s+'0';
- v -= s;
- v *= 10.;
- }
- buf[1] = buf[2];
- buf[2] = '.';
- buf[n+2] = 'e';
- buf[n+3] = '+';
- if(e < 0) {
- e = -e;
- buf[n+3] = '-';
- }
- buf[n+4] = (e/100) + '0';
- buf[n+5] = (e/10)%10 + '0';
- buf[n+6] = (e%10) + '0';
- gwrite(buf, n+7);
- }
- void
- runtime_printcomplex(complex double v)
- {
- gwrite("(", 1);
- runtime_printfloat(creal(v));
- runtime_printfloat(cimag(v));
- gwrite("i)", 2);
- }
- void
- runtime_printuint(uint64 v)
- {
- byte buf[100];
- int32 i;
- for(i=nelem(buf)-1; i>0; 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);
- }
|