diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-07 01:16:20 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-07 01:16:20 +0000 |
commit | 0effc3f961337abd0edb7c1a3dcd4b98636c085c (patch) | |
tree | 28d4e50a31f7428050763b36e3c7bbdeeb541a0f /libgo/runtime | |
parent | 1f3d0afc2623f1728a73971d415ca2991f7b9c18 (diff) | |
download | gcc-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.c | 125 | ||||
-rw-r--r-- | libgo/runtime/go-callers.c | 12 | ||||
-rw-r--r-- | libgo/runtime/mprof.goc | 4 | ||||
-rw-r--r-- | libgo/runtime/runtime.c | 19 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 9 |
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 |