diff options
Diffstat (limited to 'libgo/runtime/go-caller.c')
-rw-r--r-- | libgo/runtime/go-caller.c | 150 |
1 files changed, 115 insertions, 35 deletions
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c index b99d20c..7d5df85 100644 --- a/libgo/runtime/go-caller.c +++ b/libgo/runtime/go-caller.c @@ -8,41 +8,99 @@ #include <stdint.h> +#include "backtrace.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. */ + We use the backtrace library to get this. */ + +/* Data structure to gather file/line information. */ + +struct caller +{ + struct __go_string fn; + struct __go_string file; + int line; +}; + +/* Collect file/line information for a PC value. If this is called + more than once, due to inlined functions, we use the last call, as + that is usually the most useful one. */ + +static int +callback (void *data, uintptr_t pc __attribute__ ((unused)), + const char *filename, int lineno, const char *function) +{ + struct caller *c = (struct caller *) data; + + if (function == NULL) + { + c->fn.__data = NULL; + c->fn.__length = 0; + } + else + { + char *s; + + c->fn.__length = __builtin_strlen (function); + s = runtime_malloc (c->fn.__length); + __builtin_memcpy (s, function, c->fn.__length); + c->fn.__data = (unsigned char *) s; + } + + if (filename == NULL) + { + c->file.__data = NULL; + c->file.__length = 0; + } + else + { + char *s; + + c->file.__length = __builtin_strlen (filename); + s = runtime_malloc (c->file.__length); + __builtin_memcpy (s, filename, c->file.__length); + c->file.__data = (unsigned char *) s; + } + + c->line = lineno; + + return 0; +} -/* The function that returns function/file/line information. */ +/* The error callback for backtrace_pcinfo and backtrace_syminfo. */ -typedef _Bool (*infofn_type) (uintptr_t, struct __go_string *, - struct __go_string *, int *); -static infofn_type infofn; +static void +error_callback (void *data __attribute__ ((unused)), + const char *msg, int errnum) +{ + if (errnum == -1) + return; + if (errnum > 0) + runtime_printf ("%s errno %d\n", msg, errnum); + runtime_throw (msg); +} + +/* The backtrace library state. */ -/* The function that returns the value of a symbol, used to get the - entry address of a function. */ +static void *back_state; -typedef _Bool (*symvalfn_type) (struct __go_string, uintptr_t *); -static symvalfn_type symvalfn; +/* A lock to control creating back_state. */ -/* This is called by debug/elf to register the function that returns - function/file/line information. */ +static Lock back_state_lock; -void RegisterDebugLookup (infofn_type, symvalfn_type) - __asm__ ("runtime.RegisterDebugLookup"); +/* Fetch back_state, creating it if necessary. */ -void -RegisterDebugLookup (infofn_type pi, symvalfn_type ps) +struct backtrace_state * +__go_get_backtrace_state () { - infofn = pi; - symvalfn = ps; + runtime_lock (&back_state_lock); + if (back_state == NULL) + back_state = backtrace_create_state (NULL, 1, error_callback, NULL); + runtime_unlock (&back_state_lock); + return back_state; } /* Return function/file/line information for PC. */ @@ -51,19 +109,38 @@ _Bool __go_file_line (uintptr pc, struct __go_string *fn, struct __go_string *file, int *line) { - if (infofn == NULL) - return 0; - return infofn (pc, fn, file, line); + struct caller c; + + runtime_memclr (&c, sizeof c); + backtrace_pcinfo (__go_get_backtrace_state (), pc, callback, + error_callback, &c); + *fn = c.fn; + *file = c.file; + *line = c.line; + return c.file.__length > 0; } -/* Return the value of a symbol. */ +/* Collect symbol information. */ -_Bool -__go_symbol_value (struct __go_string sym, uintptr_t *val) +static void +syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)), + const char *symname __attribute__ ((unused)), + uintptr_t address) +{ + uintptr_t *pval = (uintptr_t *) data; + + *pval = address; +} + +/* Set *VAL to the value of the symbol for PC. */ + +static _Bool +__go_symbol_value (uintptr_t pc, uintptr_t *val) { - if (symvalfn == NULL) - return 0; - return symvalfn (sym, val); + *val = 0; + backtrace_syminfo (__go_get_backtrace_state (), pc, syminfo_callback, + error_callback, &val); + return *val != 0; } /* The values returned by runtime.Caller. */ @@ -112,12 +189,15 @@ FuncForPC (uintptr_t pc) 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; + + if (__go_symbol_value (pc, &val)) + ret->entry = val; + else + ret->entry = 0; + return ret; } |