| /* go-caller.c -- runtime.Caller and runtime.FuncForPC for Go. |
| |
| Copyright 2009 The Go Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style |
| license that can be found in the LICENSE file. */ |
| |
| /* Implement runtime.Caller. */ |
| |
| #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__ ("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 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 |
| { |
| uintptr_t pc; |
| struct __go_string file; |
| int line; |
| _Bool ok; |
| }; |
| |
| struct caller_ret Caller (int n) asm ("runtime.Caller"); |
| |
| Func *FuncForPC (uintptr_t) asm ("runtime.FuncForPC"); |
| |
| /* Implement runtime.Caller. */ |
| |
| struct caller_ret |
| Caller (int skip) |
| { |
| struct caller_ret ret; |
| uintptr pc; |
| int32 n; |
| struct __go_string fn; |
| |
| 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. */ |
| |
| Func * |
| FuncForPC (uintptr_t pc) |
| { |
| Func *ret; |
| struct __go_string fn; |
| struct __go_string file; |
| int line; |
| uintptr_t val; |
| |
| 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 |
| { |
| struct __go_string retfile; |
| int retline; |
| }; |
| |
| struct funcline_go_return |
| runtime_funcline_go (Func *f, uintptr targetpc) |
| __asm__ ("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; |
| } |