summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-01-30 22:24:40 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-01-30 22:24:40 +0000
commit051dc824954265bd097b1abeeef4c0c9b29bffbd (patch)
tree1764d8d318ba67622aefbf3e311749a6744bfa02
parent53486a83200dcd6ef17ca09e1d77db3664acbe2b (diff)
downloadgcc-051dc824954265bd097b1abeeef4c0c9b29bffbd.tar.gz
runtime: In backtraces, get inline functions, skip split-stack fns.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@195591 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libgo/runtime/go-caller.c10
-rw-r--r--libgo/runtime/go-callers.c50
-rw-r--r--libgo/runtime/go-traceback.c20
-rw-r--r--libgo/runtime/mprof.goc48
-rw-r--r--libgo/runtime/proc.c15
-rw-r--r--libgo/runtime/runtime.h19
-rw-r--r--libgo/runtime/string.goc34
7 files changed, 143 insertions, 53 deletions
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
index 63b45f368c2..d84580fa594 100644
--- a/libgo/runtime/go-caller.c
+++ b/libgo/runtime/go-caller.c
@@ -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;
}
diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c
index a19e79f053b..ea6b5db1bcb 100644
--- a/libgo/runtime/go-callers.c
+++ b/libgo/runtime/go-callers.c
@@ -15,20 +15,37 @@
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;
}
diff --git a/libgo/runtime/go-traceback.c b/libgo/runtime/go-traceback.c
index 30a5ed91c44..f397f075231 100644
--- a/libgo/runtime/go-traceback.c
+++ b/libgo/runtime/go-traceback.c
@@ -13,29 +13,25 @@
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);
}
}
}
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
index 2cf2afba433..c1b09bea7f5 100644
--- a/libgo/runtime/mprof.goc
+++ b/libgo/runtime/mprof.goc
@@ -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;
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index b2e37f39150..6d9007614b9 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -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);
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index de72f42bc55..9392df162bf 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -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);
diff --git a/libgo/runtime/string.goc b/libgo/runtime/string.goc
index 240ab0ba5e4..04ecbe6f73a 100644
--- a/libgo/runtime/string.goc
+++ b/libgo/runtime/string.goc
@@ -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)
{