aboutsummaryrefslogtreecommitdiff
path: root/libgo/runtime
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-03-07 01:16:20 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-03-07 01:16:20 +0000
commit0effc3f961337abd0edb7c1a3dcd4b98636c085c (patch)
tree28d4e50a31f7428050763b36e3c7bbdeeb541a0f /libgo/runtime
parent1f3d0afc2623f1728a73971d415ca2991f7b9c18 (diff)
downloadgcc-0effc3f961337abd0edb7c1a3dcd4b98636c085c.zip
gcc-0effc3f961337abd0edb7c1a3dcd4b98636c085c.tar.gz
gcc-0effc3f961337abd0edb7c1a3dcd4b98636c085c.tar.bz2
libgo: Implement and use runtime.Caller, runtime.Func.FileLine.
From-SVN: r185025
Diffstat (limited to 'libgo/runtime')
-rw-r--r--libgo/runtime/go-caller.c125
-rw-r--r--libgo/runtime/go-callers.c12
-rw-r--r--libgo/runtime/mprof.goc4
-rw-r--r--libgo/runtime/runtime.c19
-rw-r--r--libgo/runtime/runtime.h9
5 files changed, 130 insertions, 39 deletions
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
index b18759f..f2bebeb 100644
--- a/libgo/runtime/go-caller.c
+++ b/libgo/runtime/go-caller.c
@@ -8,8 +8,64 @@
#include <stdint.h>
+#include "runtime.h"
#include "go-string.h"
+/* Get the function name, file name, and line number for a PC value.
+ We use the DWARF debug information to get this. Rather than write
+ a whole new library in C, we use the existing Go library.
+ Unfortunately, the Go library is only available if the debug/elf
+ package is imported (we use debug/elf for both ELF and Mach-O, in
+ this case). We arrange for the debug/elf package to register
+ itself, and tweak the various packages that need this information
+ to import debug/elf where possible. */
+
+/* The function that returns function/file/line information. */
+
+typedef _Bool (*infofn_type) (uintptr_t, struct __go_string *,
+ struct __go_string *, int *);
+static infofn_type infofn;
+
+/* The function that returns the value of a symbol, used to get the
+ entry address of a function. */
+
+typedef _Bool (*symvalfn_type) (struct __go_string, uintptr_t *);
+static symvalfn_type symvalfn;
+
+/* This is called by debug/elf to register the function that returns
+ function/file/line information. */
+
+void RegisterDebugLookup (infofn_type, symvalfn_type)
+ __asm__ ("libgo_runtime.runtime.RegisterDebugLookup");
+
+void
+RegisterDebugLookup (infofn_type pi, symvalfn_type ps)
+{
+ infofn = pi;
+ symvalfn = ps;
+}
+
+/* Return function/file/line information for PC. */
+
+_Bool
+__go_file_line (uintptr_t pc, struct __go_string *fn, struct __go_string *file,
+ int *line)
+{
+ if (infofn == NULL)
+ return 0;
+ return infofn (pc, fn, file, line);
+}
+
+/* Return the value of a symbol. */
+
+_Bool
+__go_symbol_value (struct __go_string sym, uintptr_t *val)
+{
+ if (symvalfn == NULL)
+ return 0;
+ return symvalfn (sym, val);
+}
+
/* The values returned by runtime.Caller. */
struct caller_ret
@@ -20,32 +76,71 @@ struct caller_ret
_Bool ok;
};
-/* Implement runtime.Caller. */
-
struct caller_ret Caller (int n) asm ("libgo_runtime.runtime.Caller");
+Func *FuncForPC (uintptr_t) asm ("libgo_runtime.runtime.FuncForPC");
+
+/* Implement runtime.Caller. */
+
struct caller_ret
-Caller (int n __attribute__ ((unused)))
+Caller (int skip)
{
struct caller_ret ret;
+ uintptr pc;
+ int32 n;
+ struct __go_string fn;
- /* A proper implementation needs to dig through the debugging
- information. */
- ret.pc = (uint64_t) (uintptr_t) __builtin_return_address (0);
- ret.file.__data = NULL;
- ret.file.__length = 0;
- ret.line = 0;
- ret.ok = 0;
-
+ runtime_memclr (&ret, sizeof ret);
+ n = runtime_callers (skip + 1, &pc, 1);
+ if (n < 1)
+ return ret;
+ ret.pc = pc;
+ ret.ok = __go_file_line (pc, &fn, &ret.file, &ret.line);
return ret;
}
/* Implement runtime.FuncForPC. */
-void *FuncForPC (uintptr_t) asm ("libgo_runtime.runtime.FuncForPC");
+Func *
+FuncForPC (uintptr_t pc)
+{
+ Func *ret;
+ struct __go_string fn;
+ struct __go_string file;
+ int line;
+ uintptr_t val;
-void *
-FuncForPC(uintptr_t pc __attribute__ ((unused)))
+ if (!__go_file_line (pc, &fn, &file, &line))
+ return NULL;
+ if (!__go_symbol_value (fn, &val))
+ return NULL;
+
+ ret = (Func *) runtime_malloc (sizeof (*ret));
+ ret->name = fn;
+ ret->entry = val;
+ return ret;
+}
+
+/* Look up the file and line information for a PC within a
+ function. */
+
+struct funcline_go_return
{
- return NULL;
+ struct __go_string retfile;
+ int retline;
+};
+
+struct funcline_go_return
+runtime_funcline_go (Func *f, uintptr targetpc)
+ __asm__ ("libgo_runtime.runtime.funcline_go");
+
+struct funcline_go_return
+runtime_funcline_go (Func *f __attribute__((unused)), uintptr targetpc)
+{
+ struct funcline_go_return ret;
+ struct __go_string fn;
+
+ if (!__go_file_line (targetpc, &fn, &ret.retfile, &ret.retline))
+ runtime_memclr (&ret, sizeof ret);
+ return ret;
}
diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c
index 0089c67..09556c3 100644
--- a/libgo/runtime/go-callers.c
+++ b/libgo/runtime/go-callers.c
@@ -25,8 +25,13 @@ backtrace (struct _Unwind_Context *context, void *varg)
{
struct callers_data *arg = (struct callers_data *) varg;
uintptr pc;
+ int ip_before_insn = 0;
+#ifdef HAVE_GETIPINFO
+ pc = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
pc = _Unwind_GetIP (context);
+#endif
/* FIXME: If PC is in the __morestack routine, we should ignore
it. */
@@ -37,6 +42,11 @@ backtrace (struct _Unwind_Context *context, void *varg)
return _URC_END_OF_STACK;
else
{
+ /* Here PC will be the return address. We actually want the
+ address of the call instruction, so back up one byte and
+ count on the lookup routines handling that correctly. */
+ if (!ip_before_insn)
+ --pc;
arg->pcbuf[arg->index] = pc;
++arg->index;
}
@@ -48,7 +58,7 @@ runtime_callers (int32 skip, uintptr *pcbuf, int32 m)
{
struct callers_data arg;
- arg.skip = skip;
+ arg.skip = skip + 1;
arg.pcbuf = pcbuf;
arg.index = 0;
arg.max = m;
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
index e40dd61..c61c65c 100644
--- a/libgo/runtime/mprof.goc
+++ b/libgo/runtime/mprof.goc
@@ -225,11 +225,7 @@ runtime_MProf_Malloc(void *p, uintptr size)
return;
m->nomemprof++;
-#if 0
nstk = runtime_callers(1, stk, 32);
-#else
- nstk = 0;
-#endif
runtime_lock(&proflock);
b = stkbucket(stk, nstk, true);
b->recent_allocs++;
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c
index 78c865b..d1ce26d 100644
--- a/libgo/runtime/runtime.c
+++ b/libgo/runtime/runtime.c
@@ -211,22 +211,3 @@ runtime_cputicks(void)
return 0;
#endif
}
-
-struct funcline_go_return
-{
- String retfile;
- int32 retline;
-};
-
-struct funcline_go_return
-runtime_funcline_go(void *f, uintptr targetpc)
- __asm__("libgo_runtime.runtime.funcline_go");
-
-struct funcline_go_return
-runtime_funcline_go(void *f __attribute__((unused)),
- uintptr targetpc __attribute__((unused)))
-{
- struct funcline_go_return ret;
- runtime_memclr(&ret, sizeof ret);
- return ret;
-}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 40c59a8..e012e18 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -48,6 +48,7 @@ typedef unsigned int uintptr __attribute__ ((mode (pointer)));
typedef uint8 bool;
typedef uint8 byte;
+typedef struct Func Func;
typedef struct G G;
typedef union Lock Lock;
typedef struct M M;
@@ -201,6 +202,14 @@ enum
#define NSIG 32
#endif
+// NOTE(rsc): keep in sync with extern.go:/type.Func.
+// Eventually, the loaded symbol table should be closer to this form.
+struct Func
+{
+ String name;
+ uintptr entry; // entry pc
+};
+
/* Macros. */
#ifdef GOOS_windows