]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: handle morestack/lessstack in stack trace
authorRuss Cox <rsc@golang.org>
Thu, 18 Jul 2013 20:53:45 +0000 (16:53 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 18 Jul 2013 20:53:45 +0000 (16:53 -0400)
If we start a garbage collection on g0 during a
stack split or unsplit, we'll see morestack or lessstack
at the top of the stack. Record an argument frame size
for those, and record that they terminate the stack.

R=golang-dev, dvyukov
CC=golang-dev
https://golang.org/cl/11533043

src/pkg/runtime/asm_386.s
src/pkg/runtime/asm_amd64.s
src/pkg/runtime/asm_arm.s
src/pkg/runtime/proc.c
src/pkg/runtime/traceback_arm.c
src/pkg/runtime/traceback_x86.c

index 67c8854c3b0f435cef569943b4b57c39cdf92e72..5238e594370601987aedbdc951abd03f752e3d0a 100644 (file)
@@ -195,7 +195,12 @@ TEXT runtime·mcall(SB), 7, $0-4
  */
 
 // Called during function prolog when more stack is needed.
-TEXT runtime·morestack(SB),7,$0
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),7,$0-0
        // Cannot grow scheduler stack (m->g0).
        get_tls(CX)
        MOVL    m(CX), BX
@@ -288,7 +293,10 @@ TEXT reflect·call(SB), 7, $0-12
 
 
 // Return point when leaving stack.
-TEXT runtime·lessstack(SB), 7, $0
+//
+// Lessstack can appear in stack traces for the same reason
+// as morestack; in that context, it has 0 arguments.
+TEXT runtime·lessstack(SB), 7, $0-0
        // Save return value in m->cret
        get_tls(CX)
        MOVL    m(CX), BX
index 228a4217377e665ea1b0c7096fe0a4f4449759fb..f8f77124d9260e15226a89aadb0b1253b88d11b7 100644 (file)
@@ -186,7 +186,12 @@ TEXT runtime·mcall(SB), 7, $0-8
 
 // Called during function prolog when more stack is needed.
 // Caller has already done get_tls(CX); MOVQ m(CX), BX.
-TEXT runtime·morestack(SB),7,$0
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),7,$0-0
        // Cannot grow scheduler stack (m->g0).
        MOVQ    m_g0(BX), SI
        CMPQ    g(CX), SI
@@ -268,7 +273,10 @@ TEXT reflect·call(SB), 7, $0-20
        RET
 
 // Return point when leaving stack.
-TEXT runtime·lessstack(SB), 7, $0
+//
+// Lessstack can appear in stack traces for the same reason
+// as morestack; in that context, it has 0 arguments.
+TEXT runtime·lessstack(SB), 7, $0-0
        // Save return value in m->cret
        get_tls(CX)
        MOVQ    m(CX), BX
index 3367cb9fbdf6450bc3d2e8f360cf464ae5688f79..be6d29b567cb5cffa4b20eca83788463032b7d81 100644 (file)
@@ -170,7 +170,12 @@ TEXT runtime·mcall(SB), 7, $-4-4
 // NB. we do not save R0 because we've forced 5c to pass all arguments
 // on the stack.
 // using frame size $-4 means do not save LR on stack.
-TEXT runtime·morestack(SB),7,$-4
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),7,$-4-0
        // Cannot grow scheduler stack (m->g0).
        MOVW    m_g0(m), R4
        CMP     g, R4
@@ -197,7 +202,7 @@ TEXT runtime·morestack(SB),7,$-4
        // Call newstack on m->g0's stack.
        MOVW    m_g0(m), g
        MOVW    (g_sched+gobuf_sp)(g), SP
-       B       runtime·newstack(SB)
+       BL      runtime·newstack(SB)
 
 // Called from reflection library.  Mimics morestack,
 // reuses stack growth code to create a frame
@@ -241,14 +246,17 @@ TEXT reflect·call(SB), 7, $-4-12
 
 // Return point when leaving stack.
 // using frame size $-4 means do not save LR on stack.
-TEXT runtime·lessstack(SB), 7, $-4
+//
+// Lessstack can appear in stack traces for the same reason
+// as morestack; in that context, it has 0 arguments.
+TEXT runtime·lessstack(SB), 7, $-4-0
        // Save return value in m->cret
        MOVW    R0, m_cret(m)
 
        // Call oldstack on m->g0's stack.
        MOVW    m_g0(m), g
        MOVW    (g_sched+gobuf_sp)(g), SP
-       B       runtime·oldstack(SB)
+       BL      runtime·oldstack(SB)
 
 // void jmpdefer(fn, sp);
 // called from deferreturn.
index 3ce281fc775a0cb4999c961c87b347e0bc9130f3..331d382476f63d6c0ce8459736348d6077d3b876 100644 (file)
@@ -2499,17 +2499,6 @@ runtime·testSchedLocalQueueSteal(void)
 
 extern void runtime·morestack(void);
 
-bool
-runtime·haszeroargs(uintptr pc)
-{
-       return pc == (uintptr)runtime·goexit ||
-               pc == (uintptr)runtime·mcall ||
-               pc == (uintptr)runtime·mstart ||
-               pc == (uintptr)runtime·lessstack ||
-               pc == (uintptr)runtime·morestack ||
-               pc == (uintptr)_rt0_go;
-}
-
 // Does f mark the top of a goroutine stack?
 bool
 runtime·topofstack(Func *f)
@@ -2517,5 +2506,7 @@ runtime·topofstack(Func *f)
        return f->entry == (uintptr)runtime·goexit ||
                f->entry == (uintptr)runtime·mstart ||
                f->entry == (uintptr)runtime·mcall ||
+               f->entry == (uintptr)runtime·morestack ||
+               f->entry == (uintptr)runtime·lessstack ||
                f->entry == (uintptr)_rt0_go;
 }
index 43dcd1cf8c2c7306b9c3ebac92703da0c96060a8..73ae2225bbe0dad9bbf376bd66add8d7085bf279 100644 (file)
@@ -69,7 +69,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        f = runtime·findfunc(frame.pc);
                        if(f == nil) {
                                runtime·printf("runtime: unknown pc %p after stack split\n", frame.pc);
-                               runtime·throw("unknown pc");
+                               if(callback != nil)
+                                       runtime·throw("unknown pc");
                        }
                        frame.fn = f;
                        continue;
@@ -89,7 +90,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        flr = runtime·findfunc(frame.lr);
                        if(flr == nil) {
                                runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
-                               runtime·throw("unknown caller pc");
+                               if(callback != nil)
+                                       runtime·throw("unknown caller pc");
                        }
                }
                        
@@ -112,7 +114,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        else {
                                runtime·printf("runtime: unknown argument frame size for %s called from %p [%s]\n",
                                        runtime·funcname(f), frame.lr, flr ? runtime·funcname(flr) : "?");
-                               if(!printing)
+                               if(callback != nil)
                                        runtime·throw("invalid stack");
                                frame.arglen = 0;
                        }
@@ -131,7 +133,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                } else {
                        if(f->locals > frame.fp - frame.sp) {
                                runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %s\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, runtime·funcname(f));
-                               runtime·throw("invalid stack");
+                               if(callback != nil)
+                                       runtime·throw("invalid stack");
                        }
                        frame.varp = (byte*)frame.fp - f->locals;
                        frame.varlen = f->locals;
index e99adf5756eaca4367e6144add0ae9992d74f757..10f69c47ec47f79a9eaa7d9cd170001a9c1f03e7 100644 (file)
@@ -83,7 +83,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        f = runtime·findfunc(frame.pc);
                        if(f == nil) {
                                runtime·printf("runtime: unknown pc %p after stack split\n", frame.pc);
-                               runtime·throw("unknown pc");
+                               if(callback != nil)
+                                       runtime·throw("unknown pc");
                        }
                        frame.fn = f;
                        continue;
@@ -104,8 +105,9 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                                frame.lr = ((uintptr*)frame.fp)[-1];
                        flr = runtime·findfunc(frame.lr);
                        if(flr == nil) {
-                               runtime·printf("runtime: unexpected return pc for %s called from %p", runtime·funcname(f), frame.lr);
-                               runtime·throw("unknown caller pc");
+                               runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
+                               if(callback != nil)
+                                       runtime·throw("unknown caller pc");
                        }
                }
 
@@ -128,7 +130,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        else {
                                runtime·printf("runtime: unknown argument frame size for %s called from %p [%s]\n",
                                        runtime·funcname(f), frame.lr, flr ? runtime·funcname(flr) : "?");
-                               if(!printing)
+                               if(callback != nil)
                                        runtime·throw("invalid stack");
                                frame.arglen = 0;
                        }
@@ -147,7 +149,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                } else {
                        if(f->locals > frame.fp - sizeof(uintptr) - frame.sp) {
                                runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %s\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, runtime·funcname(f));
-                               runtime·throw("invalid stack");
+                               if(callback != nil)
+                                       runtime·throw("invalid stack");
                        }
                        frame.varp = (byte*)frame.fp - sizeof(uintptr) - f->locals;
                        frame.varlen = f->locals;