OSDN Git Service

runtime: In backtraces, get inline functions, skip split-stack fns.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 30 Jan 2013 22:24:40 +0000 (22:24 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 30 Jan 2013 22:24:40 +0000 (22:24 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@195591 138bc75d-0d04-0410-961f-82ee72b054a4

libgo/runtime/go-caller.c
libgo/runtime/go-callers.c
libgo/runtime/go-traceback.c
libgo/runtime/mprof.goc
libgo/runtime/proc.c
libgo/runtime/runtime.h
libgo/runtime/string.goc

index 63b45f3..d84580f 100644 (file)
@@ -166,16 +166,16 @@ struct caller_ret
 Caller (int skip)
 {
   struct caller_ret ret;
-  uintptr pc;
+  Location loc;
   int32 n;
-  String fn;
 
   runtime_memclr (&ret, sizeof ret);
-  n = runtime_callers (skip + 1, &pc, 1);
+  n = runtime_callers (skip + 1, &loc, 1);
   if (n < 1)
     return ret;
-  ret.pc = pc;
-  __go_file_line (pc, &fn, &ret.file, &ret.line);
+  ret.pc = loc.pc;
+  ret.file = loc.filename;
+  ret.line = loc.lineno;
   ret.ok = 1;
   return ret;
 }
index a19e79f..ea6b5db 100644 (file)
 
 struct callers_data
 {
-  uintptr *pcbuf;
+  Location *locbuf;
   int index;
   int max;
 };
 
-/* Callback function for backtrace_simple.  Just collect the PC
-   values.  Return zero to continue, non-zero to stop.  */
+/* Callback function for backtrace_full.  Just collect the locations.
+   Return zero to continue, non-zero to stop.  */
 
 static int
-callback (void *data, uintptr_t pc)
+callback (void *data, uintptr_t pc, const char *filename, int lineno,
+         const char *function)
 {
   struct callers_data *arg = (struct callers_data *) data;
-
-  arg->pcbuf[arg->index] = pc;
+  Location *loc;
+
+  /* Skip split stack functions.  */
+  if (function != NULL)
+    {
+      const char *p = function;
+
+      if (__builtin_strncmp (p, "___", 3) == 0)
+       ++p;
+      if (__builtin_strncmp (p, "__morestack_", 12) == 0)
+       return 0;
+    }
+
+  loc = &arg->locbuf[arg->index];
+  loc->pc = pc;
+  loc->filename = runtime_gostring ((const byte *) filename);
+  loc->function = runtime_gostring ((const byte *) function);
+  loc->lineno = lineno;
   ++arg->index;
   return arg->index >= arg->max;
 }
@@ -47,15 +64,15 @@ error_callback (void *data __attribute__ ((unused)),
 /* Gather caller PC's.  */
 
 int32
-runtime_callers (int32 skip, uintptr *pcbuf, int32 m)
+runtime_callers (int32 skip, Location *locbuf, int32 m)
 {
   struct callers_data data;
 
-  data.pcbuf = pcbuf;
+  data.locbuf = locbuf;
   data.index = 0;
   data.max = m;
-  backtrace_simple (__go_get_backtrace_state (), skip + 1, callback,
-                   error_callback, &data);
+  backtrace_full (__go_get_backtrace_state (), skip + 1, callback,
+                 error_callback, &data);
   return data.index;
 }
 
@@ -65,8 +82,19 @@ int Callers (int, struct __go_open_array)
 int
 Callers (int skip, struct __go_open_array pc)
 {
+  Location *locbuf;
+  int ret;
+  int i;
+
+  locbuf = (Location *) runtime_mal (pc.__count * sizeof (Location));
+
   /* In the Go 1 release runtime.Callers has an off-by-one error,
      which we can not correct because it would break backward
      compatibility.  Adjust SKIP here to be compatible.  */
-  return runtime_callers (skip - 1, (uintptr *) pc.__values, pc.__count);
+  ret = runtime_callers (skip - 1, locbuf, pc.__count);
+
+  for (i = 0; i < ret; i++)
+    ((uintptr *) pc.__values)[i] = locbuf[i].pc;
+
+  return ret;
 }
index 30a5ed9..f397f07 100644 (file)
 void
 runtime_traceback ()
 {
-  uintptr pcbuf[100];
+  Location locbuf[100];
   int32 c;
 
-  c = runtime_callers (1, pcbuf, sizeof pcbuf / sizeof pcbuf[0]);
-  runtime_printtrace (pcbuf, c, true);
+  c = runtime_callers (1, locbuf, nelem (locbuf));
+  runtime_printtrace (locbuf, c, true);
 }
 
 void
-runtime_printtrace (uintptr *pcbuf, int32 c, bool current)
+runtime_printtrace (Location *locbuf, int32 c, bool current)
 {
   int32 i;
 
   for (i = 0; i < c; ++i)
     {
-      String fn;
-      String file;
-      intgo line;
-
-      if (__go_file_line (pcbuf[i], &fn, &file, &line)
-         && runtime_showframe (fn, current))
+      if (runtime_showframe (locbuf[i].function, current))
        {
-         runtime_printf ("%S\n", fn);
-         runtime_printf ("\t%S:%D\n", file, (int64) line);
+         runtime_printf ("%S\n", locbuf[i].function);
+         runtime_printf ("\t%S:%D\n", locbuf[i].filename,
+                         (int64) locbuf[i].lineno);
        }
     }
 }
index 2cf2afb..c1b09be 100644 (file)
@@ -11,6 +11,7 @@ package runtime
 #include "malloc.h"
 #include "defs.h"
 #include "go-type.h"
+#include "go-string.h"
 
 // NOTE(rsc): Everything here could use cas if contention became an issue.
 static Lock proflock;
@@ -46,7 +47,7 @@ struct Bucket
        };
        uintptr hash;
        uintptr nstk;
-       uintptr stk[1];
+       Location stk[1];
 };
 enum {
        BuckHashSize = 179999,
@@ -58,9 +59,9 @@ static uintptr bucketmem;
 
 // Return the bucket for stk[0:nstk], allocating new bucket if needed.
 static Bucket*
-stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
+stkbucket(int32 typ, Location *stk, int32 nstk, bool alloc)
 {
-       int32 i;
+       int32 i, j;
        uintptr h;
        Bucket *b;
 
@@ -72,7 +73,7 @@ stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
        // Hash stack.
        h = 0;
        for(i=0; i<nstk; i++) {
-               h += stk[i];
+               h += stk[i].pc;
                h += h<<10;
                h ^= h>>6;
        }
@@ -80,10 +81,18 @@ stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
        h ^= h>>11;
 
        i = h%BuckHashSize;
-       for(b = buckhash[i]; b; b=b->next)
-               if(b->typ == typ && b->hash == h && b->nstk == (uintptr)nstk &&
-                  runtime_mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
-                       return b;
+       for(b = buckhash[i]; b; b=b->next) {
+               if(b->typ == typ && b->hash == h && b->nstk == (uintptr)nstk) {
+                       for(j = 0; j < nstk; j++) {
+                               if(b->stk[j].pc != stk[j].pc ||
+                                  b->stk[j].lineno != stk[j].lineno ||
+                                  !__go_strings_equal(b->stk[j].filename, stk[j].filename))
+                                       break;
+                       }
+                       if (j == nstk)
+                               return b;
+               }
+       }
 
        if(!alloc)
                return nil;
@@ -241,7 +250,7 @@ runtime_MProf_Malloc(void *p, uintptr size)
 {
        M *m;
        int32 nstk;
-       uintptr stk[32];
+       Location stk[32];
        Bucket *b;
 
        m = runtime_m();
@@ -298,7 +307,7 @@ runtime_blockevent(int64 cycles, int32 skip)
 {
        int32 nstk;
        int64 rate;
-       uintptr stk[32];
+       Location stk[32];
        Bucket *b;
 
        if(cycles <= 0)
@@ -336,7 +345,7 @@ record(Record *r, Bucket *b)
        r->alloc_objects = b->allocs;
        r->free_objects = b->frees;
        for(i=0; i<b->nstk && i<nelem(r->stk); i++)
-               r->stk[i] = b->stk[i];
+               r->stk[i] = b->stk[i].pc;
        for(; i<nelem(r->stk); i++)
                r->stk[i] = 0;
 }
@@ -396,7 +405,7 @@ func BlockProfile(p Slice) (n int, ok bool) {
                        r->count = b->count;
                        r->cycles = b->cycles;
                        for(i=0; (uintptr)i<b->nstk && (uintptr)i<nelem(r->stk); i++)
-                               r->stk[i] = b->stk[i];
+                               r->stk[i] = b->stk[i].pc;
                        for(; (uintptr)i<nelem(r->stk); i++)
                                r->stk[i] = 0;                  
                }
@@ -413,6 +422,7 @@ struct TRecord {
 func ThreadCreateProfile(p Slice) (n int, ok bool) {
        TRecord *r;
        M *first, *mp;
+       int32 i;
        
        first = runtime_atomicloadp(&runtime_allm);
        n = 0;
@@ -423,7 +433,9 @@ func ThreadCreateProfile(p Slice) (n int, ok bool) {
                ok = true;
                r = (TRecord*)p.__values;
                for(mp=first; mp; mp=mp->alllink) {
-                       runtime_memmove(r->stk, mp->createstack, sizeof r->stk);
+                       for(i = 0; (uintptr)i < nelem(r->stk); i++) {
+                               r->stk[i] = mp->createstack[i].pc;
+                       }
                        r++;
                }
        }
@@ -473,10 +485,14 @@ func Stack(b Slice, all bool) (n int) {
 static void
 saveg(G *gp, TRecord *r)
 {
-       int32 n;
+       int32 n, i;
+       Location locstk[nelem(r->stk)];
 
-       if(gp == runtime_g())
-               n = runtime_callers(0, r->stk, nelem(r->stk));
+       if(gp == runtime_g()) {
+               n = runtime_callers(0, locstk, nelem(r->stk));
+               for(i = 0; i < n; i++)
+                       r->stk[i] = locstk[i].pc;
+       }
        else {
                // FIXME: Not implemented.
                n = 0;
index b2e37f3..6d90076 100644 (file)
@@ -631,7 +631,7 @@ runtime_goroutinetrailer(G *g)
 struct Traceback
 {
        G* gp;
-       uintptr pcbuf[100];
+       Location locbuf[100];
        int32 c;
 };
 
@@ -677,7 +677,7 @@ runtime_tracebackothers(G * volatile me)
                        runtime_gogo(gp);
                }
 
-               runtime_printtrace(tb.pcbuf, tb.c, false);
+               runtime_printtrace(tb.locbuf, tb.c, false);
                runtime_goroutinetrailer(gp);
        }
 }
@@ -692,8 +692,8 @@ gtraceback(G* gp)
 
        traceback = gp->traceback;
        gp->traceback = nil;
-       traceback->c = runtime_callers(1, traceback->pcbuf,
-               sizeof traceback->pcbuf / sizeof traceback->pcbuf[0]);
+       traceback->c = runtime_callers(1, traceback->locbuf,
+               sizeof traceback->locbuf / sizeof traceback->locbuf[0]);
        runtime_gogo(traceback->gp);
 }
 
@@ -1742,13 +1742,14 @@ static struct {
        void (*fn)(uintptr*, int32);
        int32 hz;
        uintptr pcbuf[100];
+       Location locbuf[100];
 } prof;
 
 // Called if we receive a SIGPROF signal.
 void
 runtime_sigprof()
 {
-       int32 n;
+       int32 n, i;
 
        if(prof.fn == nil || prof.hz == 0)
                return;
@@ -1758,7 +1759,9 @@ runtime_sigprof()
                runtime_unlock(&prof);
                return;
        }
-       n = runtime_callers(0, prof.pcbuf, nelem(prof.pcbuf));
+       n = runtime_callers(0, prof.locbuf, nelem(prof.locbuf));
+       for(i = 0; i < n; i++)
+               prof.pcbuf[i] = prof.locbuf[i].pc;
        if(n > 0)
                prof.fn(prof.pcbuf, n);
        runtime_unlock(&prof);
index de72f42..9392df1 100644 (file)
@@ -83,6 +83,8 @@ typedef struct        __go_map_type           MapType;
 
 typedef struct  Traceback      Traceback;
 
+typedef struct Location        Location;
+
 /*
  * Per-CPU declaration.
  */
@@ -155,6 +157,16 @@ struct     GCStats
        uint64  nosyield;
        uint64  nsleep;
 };
+
+// A location in the program, used for backtraces.
+struct Location
+{
+       uintptr pc;
+       String  filename;
+       String  function;
+       intgo   lineno;
+};
+
 struct G
 {
        Defer*  defer;
@@ -226,7 +238,7 @@ struct      M
        MCache  *mcache;
        G*      lockedg;
        G*      idleg;
-       uintptr createstack[32];        // Stack that created this thread.
+       Location createstack[32];       // Stack that created this thread.
        M*      nextwaitm;      // next M waiting for lock
        uintptr waitsema;       // semaphore for parking on locks
        uint32  waitsemacount;
@@ -391,7 +403,8 @@ void        runtime_goroutineheader(G*);
 void   runtime_goroutinetrailer(G*);
 void   runtime_traceback();
 void   runtime_tracebackothers(G*);
-void   runtime_printtrace(uintptr*, int32, bool);
+void   runtime_printtrace(Location*, int32, bool);
+String runtime_gostring(const byte*);
 String runtime_gostringnocopy(const byte*);
 void*  runtime_mstart(void*);
 G*     runtime_malg(int32, byte**, size_t*);
@@ -406,7 +419,7 @@ void        runtime_entersyscall(void) __asm__ (GOSYM_PREFIX "syscall.Entersyscall");
 void   runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall");
 void   siginit(void);
 bool   __go_sigsend(int32 sig);
-int32  runtime_callers(int32, uintptr*, int32);
+int32  runtime_callers(int32, Location*, int32);
 int64  runtime_nanotime(void);
 int64  runtime_cputicks(void);
 int64  runtime_tickspersecond(void);
index 240ab0b..04ecbe6 100644 (file)
@@ -10,6 +10,8 @@ package runtime
 
 #define charntorune(pv, str, len) __go_get_rune(str, len, pv)
 
+const String   runtime_emptystring;
+
 intgo
 runtime_findnull(const byte *s)
 {
@@ -18,6 +20,38 @@ runtime_findnull(const byte *s)
        return __builtin_strlen((const char*) s);
 }
 
+static String
+gostringsize(intgo l, byte** pmem)
+{
+       String s;
+       byte *mem;
+
+       if(l == 0) {
+               *pmem = nil;
+               return runtime_emptystring;
+       }
+       // leave room for NUL for C runtime (e.g., callers of getenv)
+       mem = runtime_mallocgc(l+1, FlagNoPointers, 1, 0);
+       s.str = mem;
+       s.len = l;
+       mem[l] = 0;
+       *pmem = mem;
+       return s;
+}
+
+String
+runtime_gostring(const byte *str)
+{
+       intgo l;
+       String s;
+       byte *mem;
+
+       l = runtime_findnull(str);
+       s = gostringsize(l, &mem);
+       runtime_memmove(mem, str, l);
+       return s;
+}
+
 String
 runtime_gostringnocopy(const byte *str)
 {