]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add Callers
authorRuss Cox <rsc@golang.org>
Wed, 24 Mar 2010 00:01:17 +0000 (17:01 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 24 Mar 2010 00:01:17 +0000 (17:01 -0700)
cut copies of traceback from 6 to 1.

R=r
CC=golang-dev
https://golang.org/cl/703041

src/pkg/runtime/386/traceback.c [deleted file]
src/pkg/runtime/Makefile
src/pkg/runtime/amd64/traceback.c
src/pkg/runtime/arm/traceback.c
src/pkg/runtime/extern.go
src/pkg/runtime/runtime.c
src/pkg/runtime/runtime.h

diff --git a/src/pkg/runtime/386/traceback.c b/src/pkg/runtime/386/traceback.c
deleted file mode 100644 (file)
index 6b6a7aa..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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, tracepc;
-       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++) {
-               if(pc == (uint64)·lessstack) {
-                       // printf("--\n");
-                       // pop to earlier stack block
-                       pc = (uintptr)stk->gobuf.pc;
-                       sp = stk->gobuf.sp;
-                       stk = (Stktop*)stk->stackbase;
-               }
-               p = (byte*)pc;
-               tracepc = pc;
-               if(n > 0 && pc != (uint64)goexit)
-                       tracepc--;      // get to CALL instruction
-               f = findfunc(tracepc);
-               if(f == nil) {
-                       // dangerous, but poke around to see if it is a closure
-                       // ADDL $xxx, SP; RET
-                       if(pc > 0x1000 && 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, tracepc));
-               printf("\t%S(", f->name);
-               for(i = 0; i < f->args; i++) {
-                       if(i != 0)
-                               prints(", ");
-                       ·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
-·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)·lessstack) {
-                       pc = (uintptr)stk->gobuf.pc;
-                       sp = stk->gobuf.sp;
-                       stk = (Stktop*)stk->stackbase;
-               }
-
-               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(pc > 0x1000 && 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);
-}
index 71ab072e013d86663827737fec15c86c24be5d5e..8327709736018acc348223251c8e22a94071688d 100644 (file)
@@ -149,3 +149,11 @@ version.go: mkversion
 # for discovering offsets inside structs when debugging
 runtime.acid.$(GOARCH): runtime.h proc.c
        $(QUOTED_GOBIN)/$(CC) $(CFLAGS) -a proc.c >$@
+
+# 386 traceback is really amd64 traceback
+ifeq ($(GOARCH),386)
+
+traceback.$O:  amd64/traceback.c
+       $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+
+endif
index 8fe23f32ee655292ceaf67e0291ab1298a893318..37c06d092d946688d7b75eb8e12340596fd0618a 100644 (file)
 // license that can be found in the LICENSE file.
 
 #include "runtime.h"
+#include "malloc.h"
 
-void
-traceback(byte *pc0, byte *sp, G *g)
+// This code is also used for the 386 tracebacks.
+// Use uintptr for an appropriate word-sized integer.
+
+// Generic traceback.  Handles runtime stack prints (pcbuf == nil)
+// as well as the runtime.Callers function (pcbuf != nil).
+// A little clunky to merge the two but avoids duplicating
+// the code and all its subtlety.
+static int32
+gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
 {
+       byte *p;
+       int32 i, n, iter;
+       uintptr pc, tracepc;
        Stktop *stk;
-       uint64 pc, tracepc;
-       int32 i, n;
        Func *f;
-       byte *p;
-
-       pc = (uint64)pc0;
+       
+       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 = *(uint64*)sp;
-               sp += 8;
+               pc = *(uintptr*)sp;
+               sp += sizeof(uintptr);
        }
-
+       
+       n = 0;
        stk = (Stktop*)g->stackbase;
-       for(n=0; n<100; n++) {
-               if(pc == (uint64)·lessstack) {
-                       // pop to earlier stack block
-                       // printf("-- stack jump %p => %p\n", sp, stk->gobuf.sp);
+       for(iter = 0; iter < 100 && n < m; iter++) {    // iter avoids looping forever
+               if(pc == (uintptr)·lessstack) {
+                       // Hit top of stack segment.  Unwind to next segment.
                        pc = (uintptr)stk->gobuf.pc;
                        sp = stk->gobuf.sp;
                        stk = (Stktop*)stk->stackbase;
+                       continue;
                }
-               p = (byte*)pc;
-               tracepc = pc;   // used for line number, function
-               if(n > 0 && pc != (uint64)goexit)
-                       tracepc--;      // get to CALL instruction
-               f = findfunc(tracepc);
-               if(f == nil) {
-                       // dangerous, but poke around to see if it is a closure
-                       // ADDQ $xxx, SP; RET
-                       if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) {
-                               sp += *(uint32*)(p+3) + 8;
-                               pc = *(uint64*)(sp - 8);
-                               if(pc <= 0x1000)
-                                       return;
+
+               if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
+                       // Dangerous, but worthwhile: see if this is a closure:
+                       //      ADDQ $wwxxyyzz, SP; RET
+                       //      [48] 81 c4 zz yy xx ww c3
+                       // The 0x48 byte is only on amd64.
+                       p = (byte*)pc;
+                       if(mheap.min < p && p+8 < mheap.max &&  // pointer in allocated memory
+                          (sizeof(uintptr) != 8 || *p++ == 0x48) &&  // skip 0x48 byte on amd64
+                          p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
+                               sp += *(uint32*)(p+2);
+                               pc = *(uintptr*)sp;
+                               sp += sizeof(uintptr);
                                continue;
                        }
-                       printf("%p unknown pc\n", pc);
-                       return;
+                       // Unknown pc; stop.
+                       break;
                }
-               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, tracepc));
-               printf("\t%S(", f->name);
-               for(i = 0; i < f->args; i++) {
-                       if(i != 0)
-                               prints(", ");
-                       ·printhex(((uint32*)sp)[i]);
-                       if(i >= 4) {
-                               prints(", ...");
-                               break;
+               // Found an actual function worth reporting.
+               if(skip > 0)
+                       skip--;
+               else if(pcbuf != nil)
+                       pcbuf[n++] = pc;
+               else {
+                       // Print during crash.
+                       //      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));
+                       tracepc = pc;   // back up to CALL instruction for funcline.
+                       if(n > 0 && pc > f->entry)
+                               tracepc--;
+                       printf(" %S:%d\n", f->src, funcline(f, tracepc));
+                       printf("\t%S(", f->name);
+                       for(i = 0; i < f->args; i++) {
+                               if(i != 0)
+                                       prints(", ");
+                               ·printhex(((uintptr*)sp)[i]);
+                               if(i >= 4) {
+                                       prints(", ...");
+                                       break;
+                               }
                        }
+                       prints(")\n");
+                       n++;
                }
-               prints(")\n");
-
-               pc = *(uintptr*)(sp-sizeof(uintptr));
-               if(pc <= 0x1000)
-                       return;
+               
+               if(f->frame < sizeof(uintptr))  // assembly functions lie
+                       sp += sizeof(uintptr);
+               else
+                       sp += f->frame;
+               pc = *((uintptr*)sp - 1);
        }
-       prints("...\n");
+       return n;
 }
 
-// func caller(n int) (pc uint64, file string, line int, ok bool)
 void
-·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool)
+traceback(byte *pc0, byte *sp, G *g)
 {
-       uint64 pc;
-       byte *sp;
-       byte *p;
-       Stktop *stk;
-       Func *f;
-
-       // our caller's pc, sp.
-       sp = (byte*)&n;
-       pc = *(uint64*)(sp-8);
-       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)·lessstack) {
-                       pc = (uintptr)stk->gobuf.pc;
-                       sp = stk->gobuf.sp;
-                       stk = (Stktop*)stk->stackbase;
-               }
+       gentraceback(pc0, sp, g, 0, nil, 100);
+}
 
-               if(f->frame < sizeof(uintptr))  // assembly functions lie
-                       sp += sizeof(uintptr);
-               else
-                       sp += f->frame;
+int32
+callers(int32 skip, uintptr *pcbuf, int32 m)
+{
+       byte *pc, *sp;
 
-       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;
-                       // ADDQ $xxx, SP; RET
-                       if(pc > 0x1000 && p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) {
-                               sp += *(uint32*)(p+3) + 8;
-                               goto loop;
-                       }
-                       goto error;
-               }
-       }
+       // our caller's pc, sp.
+       sp = (byte*)&skip;
+       pc = *(byte**)(sp-sizeof(uintptr));
 
-       retpc = pc;
-       retfile = f->src;
-       retline = funcline(f, pc-1);
-       retbool = true;
-       FLUSH(&retpc);
-       FLUSH(&retfile);
-       FLUSH(&retline);
-       FLUSH(&retbool);
+       return gentraceback(pc, sp, g, skip, pcbuf, m);
 }
index 5c68c15c265af7d2da6c7ad0ccbc8a8766751c24..edddafe865e7c566e81cde99db989c8d8ed41dcd 100644 (file)
 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(", ");
-//                     ·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
-·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool)
+int32
+callers(int32 skip, uintptr *pcbuf, int32 m)
 {
-//     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);
+       return 0;
 }
index b4d903c30c92b4b5ddf045c1bed26dbd5f950ee7..2ee20cd35a5dd80caff4b46fc4e57bb2dcd8ea68 100644 (file)
@@ -10,8 +10,6 @@
 */
 package runtime
 
-// These functions are implemented in the base runtime library, ../../runtime/.
-
 // Gosched yields the processor, allowing other goroutines to run.  It does not
 // suspend the current goroutine, so execution resumes automatically.
 func Gosched()
index ed1bdcab8a55a9fc11f99c1b485c6f2a124c5cb8..f4882d8bdfb958f8eaf26d65239f6627861c09f4 100644 (file)
@@ -481,3 +481,29 @@ nanotime(void)
        gettime(&sec, &usec);
        return sec*1000000000 + (int64)usec*1000;
 }
+
+void
+·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
+{
+       Func *f;
+
+       if(callers(skip, &retpc, 1) == 0 || (f = findfunc(retpc-1)) == nil) {
+               retfile = emptystring;
+               retline = 0;
+               retbool = false;
+       } else {
+               retfile = f->src;
+               retline = funcline(f, retpc-1);
+               retbool = true;
+       }
+       FLUSH(&retfile);
+       FLUSH(&retline);
+       FLUSH(&retbool);
+}
+
+void
+·Callers(int32 skip, Slice pc, int32 retn)
+{
+       retn = callers(skip, (uintptr*)pc.array, pc.len);
+       FLUSH(&retn);
+}
index 194503ec8a34ac4aae84be2a5428a7e1bd0d3698..622f68038851619ab679adb4e5bc4f8f86b79745 100644 (file)
@@ -407,6 +407,7 @@ void        newproc1(byte*, byte*, int32, int32);
 void   siginit(void);
 bool   sigsend(int32 sig);
 void   gettime(int64*, int32*);
+int32  callers(int32, uintptr*, int32);
 int64  nanotime(void);
 
 #pragma        varargck        argpos  printf  1