summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/386/traceback.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/386/traceback.c')
-rw-r--r--src/pkg/runtime/386/traceback.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/pkg/runtime/386/traceback.c b/src/pkg/runtime/386/traceback.c
new file mode 100644
index 000000000..05724d9ac
--- /dev/null
+++ b/src/pkg/runtime/386/traceback.c
@@ -0,0 +1,148 @@
+// 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.
+
+#include "runtime.h"
+
+// TODO(rsc): Move this into portable code, with calls to a
+// machine-dependent isclosure() function.
+
+void
+traceback(byte *pc0, byte *sp, G *g)
+{
+ Stktop *stk;
+ uintptr pc;
+ int32 i, n;
+ Func *f;
+ byte *p;
+
+ pc = (uintptr)pc0;
+
+ // If the PC is zero, it's likely a nil function call.
+ // Start in the caller's frame.
+ if(pc == 0) {
+ pc = *(uintptr*)sp;
+ sp += sizeof(uintptr);
+ }
+
+ stk = (Stktop*)g->stackbase;
+ for(n=0; n<100; n++) {
+ while(pc == (uintptr)retfromnewstack) {
+ // pop to earlier stack block
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ pc = *(uintptr*)(sp+sizeof(uintptr));
+ sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call
+ }
+ f = findfunc(pc);
+ if(f == nil) {
+ // dangerous, but poke around to see if it is a closure
+ p = (byte*)pc;
+ // ADDL $xxx, SP; RET
+ if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
+ sp += *(uint32*)(p+2) + 8;
+ pc = *(uintptr*)(sp - 8);
+ if(pc <= 0x1000)
+ return;
+ continue;
+ }
+ printf("%p unknown pc\n", pc);
+ return;
+ }
+ if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie
+ sp += sizeof(uintptr);
+ else
+ sp += f->frame;
+
+ // print this frame
+ // main+0xf /home/rsc/go/src/runtime/x.go:23
+ // main(0x1, 0x2, 0x3)
+ printf("%S", f->name);
+ if(pc > f->entry)
+ printf("+%p", (uintptr)(pc - f->entry));
+ printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr.
+ printf("\t%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ prints(", ");
+ sys·printhex(((uint32*)sp)[i]);
+ if(i >= 4) {
+ prints(", ...");
+ break;
+ }
+ }
+ prints(")\n");
+
+ pc = *(uintptr*)(sp-sizeof(uintptr));
+ if(pc <= 0x1000)
+ return;
+ }
+ prints("...\n");
+}
+
+// func caller(n int) (pc uintptr, file string, line int, ok bool)
+void
+runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool)
+{
+ uintptr pc;
+ byte *sp;
+ byte *p;
+ Stktop *stk;
+ Func *f;
+
+ // our caller's pc, sp.
+ sp = (byte*)&n;
+ pc = *((uintptr*)sp - 1);
+ if((f = findfunc(pc)) == nil) {
+ error:
+ retpc = 0;
+ retline = 0;
+ retfile = emptystring;
+ retbool = false;
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+ return;
+ }
+
+ // now unwind n levels
+ stk = (Stktop*)g->stackbase;
+ while(n-- > 0) {
+ while(pc == (uintptr)retfromnewstack) {
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ pc = *((uintptr*)sp + 1);
+ sp += 2*sizeof(uintptr);
+ }
+
+ if(f->frame < sizeof(uintptr)) // assembly functions lie
+ sp += sizeof(uintptr);
+ else
+ sp += f->frame;
+
+ loop:
+ pc = *((uintptr*)sp - 1);
+ if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
+ // dangerous, but let's try this.
+ // see if it is a closure.
+ p = (byte*)pc;
+ // ADDL $xxx, SP; RET
+ if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
+ sp += *(uint32*)(p+2) + sizeof(uintptr);
+ goto loop;
+ }
+ goto error;
+ }
+ }
+
+ retpc = pc;
+ retfile = f->src;
+ retline = funcline(f, pc-1);
+ retbool = true;
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+}
+