Commit 27741f93 by Ian Lance Taylor

runtime: In backtraces, get inline functions, skip split-stack fns.

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