aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/extern.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-08-28 10:46:59 -0400
committerRuss Cox <rsc@golang.org>2014-08-28 10:46:59 -0400
commit6179aca54825867db3ab15bfff28fbda73e49378 (patch)
treeed3dc9d0aa018e90985d6ad7483ed974aa7394cf /src/pkg/runtime/extern.go
parentb53b47f5ac9e11fdcd3f704bc2cb0828bdee6958 (diff)
downloadgo-6179aca54825867db3ab15bfff28fbda73e49378.tar.xz
runtime: convert runtime1.goc, noasm_arm.goc to Go
LGTM=dvyukov R=golang-codereviews, bradfitz, dvyukov CC=golang-codereviews, iant, khr https://golang.org/cl/135070043
Diffstat (limited to 'src/pkg/runtime/extern.go')
-rw-r--r--src/pkg/runtime/extern.go69
1 files changed, 66 insertions, 3 deletions
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index 1a2d9c21a2..0e48bb9d88 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -75,6 +75,8 @@ of the run-time system.
*/
package runtime
+import "unsafe"
+
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
//
@@ -84,28 +86,89 @@ package runtime
// If all other goroutines exit, the program crashes.
func Goexit()
+// We assume that all architectures turn faults and the like
+// into apparent calls to runtime.sigpanic. If we see a "call"
+// to runtime.sigpanic, we do not back up the PC to find the
+// line number of the CALL instruction, because there is no CALL.
+var sigpanic byte
+
// Caller reports file and line number information about function invocations on
// the calling goroutine's stack. The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller. (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call. The boolean ok is false if it was not possible to recover the information.
-func Caller(skip int) (pc uintptr, file string, line int, ok bool)
+func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
+ // Ask for two PCs: the one we were asked for
+ // and what it called, so that we can see if it
+ // "called" sigpanic.
+ var rpc [2]uintptr
+ if callers(int32(1+skip-1), &rpc[0], 2) < 2 {
+ return
+ }
+ f := findfunc(rpc[1])
+ if f == nil {
+ // TODO(rsc): Probably a bug?
+ // The C version said "have retpc at least"
+ // but actually returned pc=0.
+ ok = true
+ return
+ }
+ pc = rpc[1]
+ xpc := pc
+ g := findfunc(rpc[0])
+ if xpc > f.entry && (g == nil || g.entry != uintptr(unsafe.Pointer(&sigpanic))) {
+ xpc--
+ }
+ line = int(funcline(f, xpc, &file))
+ ok = true
+ return
+}
+
+func findfunc(uintptr) *_func
+
+//go:noescape
+func funcline(*_func, uintptr, *string) int32
// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack. The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
-func Callers(skip int, pc []uintptr) int
+func Callers(skip int, pc []uintptr) int {
+ // runtime.callers uses pc.array==nil as a signal
+ // to print a stack trace. Pick off 0-length pc here
+ // so that we don't let a nil pc slice get to it.
+ if len(pc) == 0 {
+ return 0
+ }
+ return int(callers(int32(skip), &pc[0], int32(len(pc))))
+}
+
+//go:noescape
+func callers(int32, *uintptr, int32) int32
func getgoroot() string
+func environ() []string
+
+func gogetenv(key string) string {
+ env := environ()
+ if env == nil {
+ gothrow("getenv before env init")
+ }
+ for _, s := range env {
+ if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key {
+ return s[len(key)+1:]
+ }
+ }
+ return ""
+}
// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
- s := getgoroot()
+ s := gogetenv("GOROOT")
if s != "" {
return s
}