]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: record proper goroutine state during stack split
authorRuss Cox <rsc@golang.org>
Thu, 27 Jun 2013 15:32:01 +0000 (11:32 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 27 Jun 2013 15:32:01 +0000 (11:32 -0400)
Until now, the goroutine state has been scattered during the
execution of newstack and oldstack. It's all there, and those routines
know how to get back to a working goroutine, but other pieces of
the system, like stack traces, do not. If something does interrupt
the newstack or oldstack execution, the rest of the system can't
understand the goroutine. For example, if newstack decides there
is an overflow and calls throw, the stack tracer wouldn't dump the
goroutine correctly.

For newstack to save a useful state snapshot, it needs to be able
to rewind the PC in the function that triggered the split back to
the beginning of the function. (The PC is a few instructions in, just
after the call to morestack.) To make that possible, we change the
prologues to insert a jmp back to the beginning of the function
after the call to morestack. That is, the prologue used to be roughly:

        TEXT myfunc
                check for split
                jmpcond nosplit
                call morestack
        nosplit:
                sub $xxx, sp

Now an extra instruction is inserted after the call:

        TEXT myfunc
        start:
                check for split
                jmpcond nosplit
                call morestack
                jmp start
        nosplit:
                sub $xxx, sp

The jmp is not executed directly. It is decoded and simulated by
runtime.rewindmorestack to discover the beginning of the function,
and then the call to morestack returns directly to the start label
instead of to the jump instruction. So logically the jmp is still
executed, just not by the cpu.

The prologue thus repeats in the case of a function that needs a
stack split, but against the cost of the split itself, the extra few
instructions are noise. The repeated prologue has the nice effect of
making a stack split double-check that the new stack is big enough:
if morestack happens to return on a too-small stack, we'll now notice
before corruption happens.

The ability for newstack to rewind to the beginning of the function
should help preemption too. If newstack decides that it was called
for preemption instead of a stack split, it now has the goroutine state
correctly paused if rescheduling is needed, and when the goroutine
can run again, it can return to the start label on its original stack
and re-execute the split check.

Here is an example of a split stack overflow showing the full
trace, without any special cases in the stack printer.
(This one was triggered by making the split check incorrect.)

runtime: newstack framesize=0x0 argsize=0x18 sp=0x6aebd0 stack=[0x6b0000, 0x6b0fa0]
        morebuf={pc:0x69f5b sp:0x6aebd8 lr:0x0}
        sched={pc:0x68880 sp:0x6aebd0 lr:0x0 ctxt:0x34e700}
runtime: split stack overflow: 0x6aebd0 < 0x6b0000
fatal error: runtime: split stack overflow

goroutine 1 [stack split]:
runtime.mallocgc(0x290, 0x100000000, 0x1)
        /Users/rsc/g/go/src/pkg/runtime/zmalloc_darwin_amd64.c:21 fp=0x6aebd8
runtime.new()
        /Users/rsc/g/go/src/pkg/runtime/zmalloc_darwin_amd64.c:682 +0x5b fp=0x6aec08
go/build.(*Context).Import(0x5ae340, 0xc210030c71, 0xa, 0xc2100b4380, 0x1b, ...)
        /Users/rsc/g/go/src/pkg/go/build/build.go:424 +0x3a fp=0x6b00a0
main.loadImport(0xc210030c71, 0xa, 0xc2100b4380, 0x1b, 0xc2100b42c0, ...)
        /Users/rsc/g/go/src/cmd/go/pkg.go:249 +0x371 fp=0x6b01a8
main.(*Package).load(0xc21017c800, 0xc2100b42c0, 0xc2101828c0, 0x0, 0x0, ...)
        /Users/rsc/g/go/src/cmd/go/pkg.go:431 +0x2801 fp=0x6b0c98
main.loadPackage(0x369040, 0x7, 0xc2100b42c0, 0x0)
        /Users/rsc/g/go/src/cmd/go/pkg.go:709 +0x857 fp=0x6b0f80
----- stack segment boundary -----
main.(*builder).action(0xc2100902a0, 0x0, 0x0, 0xc2100e6c00, 0xc2100e5750, ...)
        /Users/rsc/g/go/src/cmd/go/build.go:539 +0x437 fp=0x6b14a0
main.(*builder).action(0xc2100902a0, 0x0, 0x0, 0xc21015b400, 0x2, ...)
        /Users/rsc/g/go/src/cmd/go/build.go:528 +0x1d2 fp=0x6b1658
main.(*builder).test(0xc2100902a0, 0xc210092000, 0x0, 0x0, 0xc21008ff60, ...)
        /Users/rsc/g/go/src/cmd/go/test.go:622 +0x1b53 fp=0x6b1f68
----- stack segment boundary -----
main.runTest(0x5a6b20, 0xc21000a020, 0x2, 0x2)
        /Users/rsc/g/go/src/cmd/go/test.go:366 +0xd09 fp=0x6a5cf0
main.main()
        /Users/rsc/g/go/src/cmd/go/main.go:161 +0x4f9 fp=0x6a5f78
runtime.main()
        /Users/rsc/g/go/src/pkg/runtime/proc.c:183 +0x92 fp=0x6a5fa0
runtime.goexit()
        /Users/rsc/g/go/src/pkg/runtime/proc.c:1266 fp=0x6a5fa8

And here is a seg fault during oldstack:

SIGSEGV: segmentation violation
PC=0x1b2a6

runtime.oldstack()
        /Users/rsc/g/go/src/pkg/runtime/stack.c:159 +0x76
runtime.lessstack()
        /Users/rsc/g/go/src/pkg/runtime/asm_amd64.s:270 +0x22

goroutine 1 [stack unsplit]:
fmt.(*pp).printArg(0x2102e64e0, 0xe5c80, 0x2102c9220, 0x73, 0x0, ...)
        /Users/rsc/g/go/src/pkg/fmt/print.go:818 +0x3d3 fp=0x221031e6f8
fmt.(*pp).doPrintf(0x2102e64e0, 0x12fb20, 0x2, 0x221031eb98, 0x1, ...)
        /Users/rsc/g/go/src/pkg/fmt/print.go:1183 +0x15cb fp=0x221031eaf0
fmt.Sprintf(0x12fb20, 0x2, 0x221031eb98, 0x1, 0x1, ...)
        /Users/rsc/g/go/src/pkg/fmt/print.go:234 +0x67 fp=0x221031eb40
flag.(*stringValue).String(0x2102c9210, 0x1, 0x0)
        /Users/rsc/g/go/src/pkg/flag/flag.go:180 +0xb3 fp=0x221031ebb0
flag.(*FlagSet).Var(0x2102f6000, 0x293d38, 0x2102c9210, 0x143490, 0xa, ...)
        /Users/rsc/g/go/src/pkg/flag/flag.go:633 +0x40 fp=0x221031eca0
flag.(*FlagSet).StringVar(0x2102f6000, 0x2102c9210, 0x143490, 0xa, 0x12fa60, ...)
        /Users/rsc/g/go/src/pkg/flag/flag.go:550 +0x91 fp=0x221031ece8
flag.(*FlagSet).String(0x2102f6000, 0x143490, 0xa, 0x12fa60, 0x0, ...)
        /Users/rsc/g/go/src/pkg/flag/flag.go:563 +0x87 fp=0x221031ed38
flag.String(0x143490, 0xa, 0x12fa60, 0x0, 0x161950, ...)
        /Users/rsc/g/go/src/pkg/flag/flag.go:570 +0x6b fp=0x221031ed80
testing.init()
        /Users/rsc/g/go/src/pkg/testing/testing.go:-531 +0xbb fp=0x221031edc0
strings_test.init()
        /Users/rsc/g/go/src/pkg/strings/strings_test.go:1115 +0x62 fp=0x221031ef70
main.init()
        strings/_test/_testmain.go:90 +0x3d fp=0x221031ef78
runtime.main()
        /Users/rsc/g/go/src/pkg/runtime/proc.c:180 +0x8a fp=0x221031efa0
runtime.goexit()
        /Users/rsc/g/go/src/pkg/runtime/proc.c:1269 fp=0x221031efa8

goroutine 2 [runnable]:
runtime.MHeap_Scavenger()
        /Users/rsc/g/go/src/pkg/runtime/mheap.c:438
runtime.goexit()
        /Users/rsc/g/go/src/pkg/runtime/proc.c:1269
created by runtime.main
        /Users/rsc/g/go/src/pkg/runtime/proc.c:166

rax     0x23ccc0
rbx     0x23ccc0
rcx     0x0
rdx     0x38
rdi     0x2102c0170
rsi     0x221032cfe0
rbp     0x221032cfa0
rsp     0x7fff5fbff5b0
r8      0x2102c0120
r9      0x221032cfa0
r10     0x221032c000
r11     0x104ce8
r12     0xe5c80
r13     0x1be82baac718
r14     0x13091135f7d69200
r15     0x0
rip     0x1b2a6
rflags  0x10246
cs      0x2b
fs      0x0
gs      0x0

Fixes #5723.

R=r, dvyukov, go.peter.90, dave, iant
CC=golang-dev
https://golang.org/cl/10360048

27 files changed:
src/cmd/5g/gsubr.c
src/cmd/5l/noop.c
src/cmd/6g/gsubr.c
src/cmd/6l/pass.c
src/cmd/8g/gsubr.c
src/cmd/8l/pass.c
src/libmach/8db.c
src/pkg/runtime/asm_386.s
src/pkg/runtime/asm_amd64.s
src/pkg/runtime/asm_arm.s
src/pkg/runtime/mgc0.c
src/pkg/runtime/mprof.goc
src/pkg/runtime/os_plan9_386.c
src/pkg/runtime/os_plan9_amd64.c
src/pkg/runtime/panic.c
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h
src/pkg/runtime/signal_386.c
src/pkg/runtime/signal_amd64.c
src/pkg/runtime/signal_arm.c
src/pkg/runtime/stack.c
src/pkg/runtime/stack.h
src/pkg/runtime/symtab.c
src/pkg/runtime/sys_arm.c
src/pkg/runtime/sys_x86.c
src/pkg/runtime/traceback_arm.c
src/pkg/runtime/traceback_x86.c

index f89124269cf08830fb7a599160e8717ffdd5cb00..56b27da1361ecd776ac92da82480adfe584690b0 100644 (file)
@@ -32,8 +32,9 @@
 #include <libc.h>
 #include "gg.h"
 
-// TODO(kaib): Can make this bigger if we move
+// TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 5l for all GOOS.
+// At the same time, can raise StackBig in ../../pkg/runtime/stack.h.
 long unmappedzero = 4096;
 
 void
index 63a0d9b8334e80a7d4671025812f70f7326d323d..ace03ffd6bc9d2dc828b1d9dd12c9e59266b951c 100644 (file)
 
 #include       "l.h"
 #include       "../ld/lib.h"
-
-// see ../../runtime/proc.c:/StackGuard
-enum
-{
-       StackBig = 4096,
-       StackSmall = 128,
-};
+#include       "../../pkg/runtime/stack.h"
 
 static Sym*    sym_div;
 static Sym*    sym_divu;
@@ -180,33 +174,7 @@ noops(void)
                                                break;
                                }
        
-                               if(p->reg & NOSPLIT) {
-                                       q1 = prg();
-                                       q1->as = AMOVW;
-                                       q1->scond |= C_WBIT;
-                                       q1->line = p->line;
-                                       q1->from.type = D_REG;
-                                       q1->from.reg = REGLINK;
-                                       q1->to.type = D_OREG;
-                                       q1->to.offset = -autosize;
-                                       q1->to.reg = REGSP;
-                                       q1->spadj = autosize;
-                                       q1->link = p->link;
-                                       p->link = q1;
-                               } else if (autosize < StackBig) {
-                                       // split stack check for small functions
-                                       // MOVW                 g_stackguard(g), R1
-                                       // CMP                  R1, $-autosize(SP)
-                                       // MOVW.LO              $autosize, R1
-                                       // MOVW.LO              $args, R2
-                                       // MOVW.LO              R14, R3
-                                       // BL.LO                        runtime.morestack(SB) // modifies LR
-                                       // MOVW.W               R14,$-autosize(SP)
-       
-                                       // TODO(kaib): add more trampolines
-                                       // TODO(kaib): put stackguard in register
-                                       // TODO(kaib): add support for -K and underflow detection
-
+                               if(!(p->reg & NOSPLIT)) {
                                        // MOVW                 g_stackguard(g), R1
                                        p = appendp(p);
                                        p->as = AMOVW;
@@ -215,16 +183,18 @@ noops(void)
                                        p->to.type = D_REG;
                                        p->to.reg = 1;
                                        
-                                       if(autosize < StackSmall) {     
-                                               // CMP                  R1, SP
+                                       if(autosize <= StackSmall) {
+                                               // small stack: SP < stackguard
+                                               //      CMP     stackguard, SP
                                                p = appendp(p);
                                                p->as = ACMP;
                                                p->from.type = D_REG;
                                                p->from.reg = 1;
                                                p->reg = REGSP;
-                                       } else {
-                                               // MOVW         $-autosize(SP), R2
-                                               // CMP  R1, R2
+                                       } else if(autosize <= StackBig) {
+                                               // large stack: SP-framesize < stackguard-StackSmall
+                                               //      MOVW $-autosize(SP), R2
+                                               //      CMP stackguard, R2
                                                p = appendp(p);
                                                p->as = AMOVW;
                                                p->from.type = D_CONST;
@@ -238,103 +208,97 @@ noops(void)
                                                p->from.type = D_REG;
                                                p->from.reg = 1;
                                                p->reg = 2;
+                                       } else {
+                                               // such a large stack we need to protect against wraparound
+                                               // if SP is close to zero.
+                                               //      SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
+                                               // The +StackGuard on both sides is required to keep the left side positive:
+                                               // SP is allowed to be slightly below stackguard. See stack.h.
+                                               //      MOVW $StackGuard(SP), R2
+                                               //      SUB R1, R2
+                                               //      MOVW $(autosize+(StackGuard-StackSmall)), R3
+                                               //      CMP R3, R2
+                                               p = appendp(p);
+                                               p->as = AMOVW;
+                                               p->from.type = D_CONST;
+                                               p->from.reg = REGSP;
+                                               p->from.offset = StackGuard;
+                                               p->to.type = D_REG;
+                                               p->to.reg = 2;
+                                               
+                                               p = appendp(p);
+                                               p->as = ASUB;
+                                               p->from.type = D_REG;
+                                               p->from.reg = 1;
+                                               p->to.type = D_REG;
+                                               p->to.reg = 2;
+                                               
+                                               p = appendp(p);
+                                               p->as = AMOVW;
+                                               p->from.type = D_CONST;
+                                               p->from.offset = autosize + (StackGuard - StackSmall);
+                                               p->to.type = D_REG;
+                                               p->to.reg = 3;
+                                               
+                                               p = appendp(p);
+                                               p->as = ACMP;
+                                               p->from.type = D_REG;
+                                               p->from.reg = 3;
+                                               p->reg = 2;
                                        }
-
-                                       // MOVW.LO              $autosize, R1
+                                       
+                                       // MOVW.LS              $autosize, R1
                                        p = appendp(p);
                                        p->as = AMOVW;
-                                       p->scond = C_SCOND_LO;
+                                       p->scond = C_SCOND_LS;
                                        p->from.type = D_CONST;
                                        p->from.offset = autosize;
                                        p->to.type = D_REG;
                                        p->to.reg = 1;
        
-                                       // MOVW.LO              $args, R2
+                                       // MOVW.LS              $args, R2
                                        p = appendp(p);
                                        p->as = AMOVW;
-                                       p->scond = C_SCOND_LO;
+                                       p->scond = C_SCOND_LS;
                                        p->from.type = D_CONST;
                                        p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
                                        p->to.type = D_REG;
                                        p->to.reg = 2;
        
-                                       // MOVW.LO      R14, R3
+                                       // MOVW.LS      R14, R3
                                        p = appendp(p);
                                        p->as = AMOVW;
-                                       p->scond = C_SCOND_LO;
+                                       p->scond = C_SCOND_LS;
                                        p->from.type = D_REG;
                                        p->from.reg = REGLINK;
                                        p->to.type = D_REG;
                                        p->to.reg = 3;
        
-                                       // BL.LO                runtime.morestack(SB) // modifies LR
+                                       // BL.LS                runtime.morestack(SB) // modifies LR, returns with LO still asserted
                                        p = appendp(p);
                                        p->as = ABL;
-                                       p->scond = C_SCOND_LO;
+                                       p->scond = C_SCOND_LS;
                                        p->to.type = D_BRANCH;
                                        p->to.sym = symmorestack;
                                        p->cond = pmorestack;
-       
-                                       // MOVW.W               R14,$-autosize(SP)
-                                       p = appendp(p);
-                                       p->as = AMOVW;
-                                       p->scond |= C_WBIT;
-                                       p->from.type = D_REG;
-                                       p->from.reg = REGLINK;
-                                       p->to.type = D_OREG;
-                                       p->to.offset = -autosize;
-                                       p->to.reg = REGSP;
-                                       p->spadj = autosize;
-                               } else { // > StackBig
-                                       // MOVW         $autosize, R1
-                                       // MOVW         $args, R2
-                                       // MOVW         R14, R3
-                                       // BL                   runtime.morestack(SB) // modifies LR
-                                       // MOVW.W               R14,$-autosize(SP)
-       
-                                       // MOVW         $autosize, R1
-                                       p = appendp(p);
-                                       p->as = AMOVW;
-                                       p->from.type = D_CONST;
-                                       p->from.offset = autosize;
-                                       p->to.type = D_REG;
-                                       p->to.reg = 1;
-       
-                                       // MOVW         $args, R2
-                                       // also need to store the extra 4 bytes.
-                                       p = appendp(p);
-                                       p->as = AMOVW;
-                                       p->from.type = D_CONST;
-                                       p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
-                                       p->to.type = D_REG;
-                                       p->to.reg = 2;
-       
-                                       // MOVW R14, R3
-                                       p = appendp(p);
-                                       p->as = AMOVW;
-                                       p->from.type = D_REG;
-                                       p->from.reg = REGLINK;
-                                       p->to.type = D_REG;
-                                       p->to.reg = 3;
-       
-                                       // BL           runtime.morestack(SB) // modifies LR
+                                       
+                                       // BLS  start
                                        p = appendp(p);
-                                       p->as = ABL;
+                                       p->as = ABLS;
                                        p->to.type = D_BRANCH;
-                                       p->to.sym = symmorestack;
-                                       p->cond = pmorestack;
-       
-                                       // MOVW.W               R14,$-autosize(SP)
-                                       p = appendp(p);
-                                       p->as = AMOVW;
-                                       p->scond |= C_WBIT;
-                                       p->from.type = D_REG;
-                                       p->from.reg = REGLINK;
-                                       p->to.type = D_OREG;
-                                       p->to.offset = -autosize;
-                                       p->to.reg = REGSP;
-                                       p->spadj = autosize;
+                                       p->cond = cursym->text->link;
                                }
+                               
+                               // MOVW.W               R14,$-autosize(SP)
+                               p = appendp(p);
+                               p->as = AMOVW;
+                               p->scond |= C_WBIT;
+                               p->from.type = D_REG;
+                               p->from.reg = REGLINK;
+                               p->to.type = D_OREG;
+                               p->to.offset = -autosize;
+                               p->to.reg = REGSP;
+                               p->spadj = autosize;
                                break;
        
                        case ARET:
index 5408435fddfa692ccb167484e149b04595b3d342..c49421544215d497b5253442672a2701f3ae5337 100644 (file)
@@ -34,6 +34,7 @@
 
 // TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 6l for all GOOS.
+// At the same time, can raise StackBig in ../../pkg/runtime/stack.h.
 vlong unmappedzero = 4096;
 
 void
index 7de0fddf2911357e46c30671a2b386f30145bcd1..31d42eee45ce7de0ac484dbd5680e06d7c63bd35 100644 (file)
@@ -497,34 +497,61 @@ dostkoff(void)
                                q1->pcond = p;
                        }
 
-                       if(autoffset < StackBig) {  // do we need to call morestack?
-                               if(autoffset <= StackSmall) {
-                                       // small stack
-                                       p = appendp(p);
-                                       p->as = ACMPQ;
-                                       p->from.type = D_SP;
-                                       p->to.type = D_INDIR+D_CX;
-                               } else {
-                                       // large stack
-                                       p = appendp(p);
-                                       p->as = ALEAQ;
-                                       p->from.type = D_INDIR+D_SP;
-                                       p->from.offset = -(autoffset-StackSmall);
-                                       p->to.type = D_AX;
-
-                                       p = appendp(p);
-                                       p->as = ACMPQ;
-                                       p->from.type = D_AX;
-                                       p->to.type = D_INDIR+D_CX;
-                               }
+                       if(autoffset <= StackSmall) {
+                               // small stack: SP <= stackguard
+                               //      CMPQ SP, stackguard
+                               p = appendp(p);
+                               p->as = ACMPQ;
+                               p->from.type = D_SP;
+                               p->to.type = D_INDIR+D_CX;
+                       } else if(autoffset <= StackBig) {
+                               // large stack: SP-framesize <= stackguard-StackSmall
+                               //      LEAQ -xxx(SP), AX
+                               //      CMPQ AX, stackguard
+                               p = appendp(p);
+                               p->as = ALEAQ;
+                               p->from.type = D_INDIR+D_SP;
+                               p->from.offset = -(autoffset-StackSmall);
+                               p->to.type = D_AX;
 
-                               // common
                                p = appendp(p);
-                               p->as = AJHI;
-                               p->to.type = D_BRANCH;
-                               p->to.offset = 4;
-                               q = p;
-                       }
+                               p->as = ACMPQ;
+                               p->from.type = D_AX;
+                               p->to.type = D_INDIR+D_CX;
+                       } else {
+                               // such a large stack we need to protect against wraparound
+                               // if SP is close to zero:
+                               //      SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+                               // The +StackGuard on both sides is required to keep the left side positive:
+                               // SP is allowed to be slightly below stackguard. See stack.h.
+                               //      LEAQ    StackGuard(SP), AX
+                               //      SUBQ    stackguard, AX
+                               //      CMPQ    AX, $(autoffset+(StackGuard-StackSmall))
+                               p = appendp(p);
+                               p->as = ALEAQ;
+                               p->from.type = D_INDIR+D_SP;
+                               p->from.offset = StackGuard;
+                               p->to.type = D_AX;
+                               
+                               p = appendp(p);
+                               p->as = ASUBQ;
+                               p->from.type = D_INDIR+D_CX;
+                               p->from.offset = 0;
+                               p->to.type = D_AX;
+                               
+                               p = appendp(p);
+                               p->as = ACMPQ;
+                               p->from.type = D_AX;
+                               p->to.type = D_CONST;
+                               p->to.offset = autoffset+(StackGuard-StackSmall);
+                       }                                       
+
+                       // common
+                       p = appendp(p);
+                       p->as = AJHI;
+                       p->to.type = D_BRANCH;
+                       p->to.offset = 4;
+                       q = p;
 
                        // If we ask for more stack, we'll get a minimum of StackMin bytes.
                        // We need a stack frame large enough to hold the top-of-stack data,
@@ -591,6 +618,11 @@ dostkoff(void)
                                p->pcond = pmorestack[3];
                                p->to.sym = symmorestack[3];
                        }
+                       
+                       p = appendp(p);
+                       p->as = AJMP;
+                       p->to.type = D_BRANCH;
+                       p->pcond = cursym->text->link;
                }
 
                if(q != P)
index 756bdd2039956b212768c7304d4e26471a501fa8..7ffc77a26810af747a4647cb50949a384719e086 100644 (file)
@@ -34,6 +34,7 @@
 
 // TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 8l for all GOOS.
+// At the same time, can raise StackBig in ../../pkg/runtime/stack.h.
 uint32 unmappedzero = 4096;
 
 #define        CASE(a,b)       (((a)<<16)|((b)<<0))
index f668ca8cf1f38b6a4a024c27ce2e23d5671ecc33..d5bebe1684a50e05fcd9d1f08a34cc9e0762394e 100644 (file)
@@ -526,34 +526,61 @@ dostkoff(void)
                                q1->pcond = p;
                        }
 
-                       if(autoffset < StackBig) {  // do we need to call morestack
-                               if(autoffset <= StackSmall) {
-                                       // small stack
-                                       p = appendp(p);
-                                       p->as = ACMPL;
-                                       p->from.type = D_SP;
-                                       p->to.type = D_INDIR+D_CX;
-                               } else {
-                                       // large stack
-                                       p = appendp(p);
-                                       p->as = ALEAL;
-                                       p->from.type = D_INDIR+D_SP;
-                                       p->from.offset = -(autoffset-StackSmall);
-                                       p->to.type = D_AX;
-
-                                       p = appendp(p);
-                                       p->as = ACMPL;
-                                       p->from.type = D_AX;
-                                       p->to.type = D_INDIR+D_CX;
-                               }
+                       if(autoffset <= StackSmall) {
+                               // small stack: SP <= stackguard
+                               //      CMPL SP, stackguard
+                               p = appendp(p);
+                               p->as = ACMPL;
+                               p->from.type = D_SP;
+                               p->to.type = D_INDIR+D_CX;
+                       } else if(autoffset <= StackBig) {
+                               // large stack: SP-framesize <= stackguard-StackSmall
+                               //      LEAL -(autoffset-StackSmall)(SP), AX
+                               //      CMPL AX, stackguard
+                               p = appendp(p);
+                               p->as = ALEAL;
+                               p->from.type = D_INDIR+D_SP;
+                               p->from.offset = -(autoffset-StackSmall);
+                               p->to.type = D_AX;
 
-                               // common
                                p = appendp(p);
-                               p->as = AJHI;
-                               p->to.type = D_BRANCH;
-                               p->to.offset = 4;
-                               q = p;
-                       }
+                               p->as = ACMPL;
+                               p->from.type = D_AX;
+                               p->to.type = D_INDIR+D_CX;
+                       } else {
+                               // such a large stack we need to protect against wraparound
+                               // if SP is close to zero.
+                               //      SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+                               // The +StackGuard on both sides is required to keep the left side positive:
+                               // SP is allowed to be slightly below stackguard. See stack.h.
+                               //      LEAL    StackGuard(SP), AX
+                               //      SUBL    stackguard, AX
+                               //      CMPL    AX, $(autoffset+(StackGuard-StackSmall))
+                               p = appendp(p);
+                               p->as = ALEAL;
+                               p->from.type = D_INDIR+D_SP;
+                               p->from.offset = StackGuard;
+                               p->to.type = D_AX;
+                               
+                               p = appendp(p);
+                               p->as = ASUBL;
+                               p->from.type = D_INDIR+D_CX;
+                               p->from.offset = 0;
+                               p->to.type = D_AX;
+                               
+                               p = appendp(p);
+                               p->as = ACMPL;
+                               p->from.type = D_AX;
+                               p->to.type = D_CONST;
+                               p->to.offset = autoffset+(StackGuard-StackSmall);
+                       }               
+                                       
+                       // common
+                       p = appendp(p);
+                       p->as = AJHI;
+                       p->to.type = D_BRANCH;
+                       p->to.offset = 4;
+                       q = p;
 
                        p = appendp(p); // save frame size in DI
                        p->as = AMOVL;
@@ -583,6 +610,10 @@ dostkoff(void)
                        p->pcond = pmorestack;
                        p->to.sym = symmorestack;
 
+                       p = appendp(p);
+                       p->as = AJMP;
+                       p->to.type = D_BRANCH;
+                       p->pcond = cursym->text->link;
                }
 
                if(q != P)
index 9ef02c4289cb1e3f627ca4232386579c821baeb9..824c9fb1a91d2df7cce8f05961b9ed5d74124e33 100644 (file)
@@ -202,6 +202,11 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
                        break;
 
                if(s.value == morestack) {
+                       // This code is old and won't work anymore.
+                       // But no one uses it anyway.
+                       // Leave it obviously broken until someone needs it.
+                       werrstr("morestack not implemented correctly");
+                       return -1;
                        // In the middle of morestack.
                        // Caller is m->morepc.
                        // Caller's caller is in m->morearg.
index 89db4137044a71a15fdae29f50d3e096d19b1af8..cd1514e1e049db556f42eb2d00dadf03bd727bfe 100644 (file)
@@ -200,8 +200,6 @@ TEXT runtime·morestack(SB),7,$0
        CMPL    g(CX), SI
        JNE     2(PC)
        INT     $3
-       
-       MOVL    DX, m_cret(BX)
 
        // frame size in DI
        // arg size in AX
@@ -220,9 +218,13 @@ TEXT runtime·morestack(SB),7,$0
        MOVL    g(CX), SI
        MOVL    SI, (m_morebuf+gobuf_g)(BX)
 
-       // Set m->morepc to f's PC.
-       MOVL    0(SP), AX
-       MOVL    AX, m_morepc(BX)
+       // Set g->sched to context in f.
+       MOVL    0(SP), AX       // f's PC
+       MOVL    AX, (g_sched+gobuf_pc)(SI)
+       MOVL    SI, (g_sched+gobuf_g)(SI)
+       LEAL    4(SP), AX       // f's SP
+       MOVL    AX, (g_sched+gobuf_sp)(SI)
+       MOVL    DX, (g_sched+gobuf_ctxt)(SI)
 
        // Call newstack on m->g0's stack.
        MOVL    m_g0(BX), BP
@@ -262,7 +264,7 @@ TEXT reflect·call(SB), 7, $0
        MOVL    8(SP), DX       // arg frame
        MOVL    12(SP), CX      // arg size
 
-       MOVL    AX, m_morepc(BX)        // f's PC
+       MOVL    AX, m_cret(BX)  // f's PC
        MOVL    DX, m_moreargp(BX)      // f's argument pointer
        MOVL    CX, m_moreargsize(BX)   // f's argument size
        MOVL    $1, m_moreframesize(BX) // f's frame size
index f6919c6d03f37b403299d26fcbe8f80f36308c26..0b7c3ded06ccb1d020308345f7a685d14b60a4fa 100644 (file)
@@ -186,8 +186,6 @@ TEXT runtime·morestack(SB),7,$0
        CMPQ    g(CX), SI
        JNE     2(PC)
        INT     $3
-       
-       MOVQ    DX, m_cret(BX)
 
        // Called from f.
        // Set m->morebuf to f's caller.
@@ -200,9 +198,13 @@ TEXT runtime·morestack(SB),7,$0
        MOVQ    g(CX), SI
        MOVQ    SI, (m_morebuf+gobuf_g)(BX)
 
-       // Set m->morepc to f's PC.
-       MOVQ    0(SP), AX
-       MOVQ    AX, m_morepc(BX)
+       // Set g->sched to context in f.
+       MOVQ    0(SP), AX // f's PC
+       MOVQ    AX, (g_sched+gobuf_pc)(SI)
+       MOVQ    SI, (g_sched+gobuf_g)(SI)
+       LEAQ    8(SP), AX // f's SP
+       MOVQ    AX, (g_sched+gobuf_sp)(SI)
+       MOVQ    DX, (g_sched+gobuf_ctxt)(SI)
 
        // Call newstack on m->g0's stack.
        MOVQ    m_g0(BX), BP
@@ -240,7 +242,7 @@ TEXT reflect·call(SB), 7, $0
        MOVQ    16(SP), DX      // arg frame
        MOVL    24(SP), CX      // arg size
 
-       MOVQ    AX, m_morepc(BX)        // f's PC
+       MOVQ    AX, m_cret(BX)  // f's PC
        MOVQ    DX, m_moreargp(BX)      // argument frame pointer
        MOVL    CX, m_moreargsize(BX)   // f's argument size
        MOVL    $1, m_moreframesize(BX) // f's frame size
index 5442e69ad14616accd0361deb3302d0168026815..fd88b46b90c04194351c497d49cd37b1e6232cc6 100644 (file)
@@ -126,6 +126,7 @@ TEXT runtime·gogo(SB), 7, $-4
        MOVW    R11, gobuf_ret(R1)
        MOVW    R11, gobuf_lr(R1)
        MOVW    R11, gobuf_ctxt(R1)
+       CMP     R11, R11 // set condition codes for == test, needed by stack split
        MOVW    gobuf_pc(R1), PC
 
 // void mcall(void (*fn)(G*))
@@ -138,6 +139,8 @@ TEXT runtime·mcall(SB), 7, $-4
        // Save caller state in g->sched.
        MOVW    SP, (g_sched+gobuf_sp)(g)
        MOVW    LR, (g_sched+gobuf_pc)(g)
+       MOVW    $0, R11
+       MOVW    R11, (g_sched+gobuf_lr)(g)
        MOVW    g, (g_sched+gobuf_g)(g)
 
        // Switch to m->g0 & its stack, call fn.
@@ -169,11 +172,16 @@ TEXT runtime·morestack(SB),7,$-4
        CMP     g, R4
        BL.EQ   runtime·abort(SB)
 
-       // Save in m.
-       MOVW    R7, m_cret(m) // function context
        MOVW    R1, m_moreframesize(m)
        MOVW    R2, m_moreargsize(m)
 
+       // Called from f.
+       // Set g->sched to context in f.
+       MOVW    R7, (g_sched+gobuf_ctxt)(g)
+       MOVW    SP, (g_sched+gobuf_sp)(g)
+       MOVW    LR, (g_sched+gobuf_pc)(g)
+       MOVW    R3, (g_sched+gobuf_lr)(g)
+
        // Called from f.
        // Set m->morebuf to f's caller.
        MOVW    R3, (m_morebuf+gobuf_pc)(m)     // f's caller's PC
@@ -182,9 +190,6 @@ TEXT runtime·morestack(SB),7,$-4
        MOVW    R3, m_moreargp(m)       
        MOVW    g, (m_morebuf+gobuf_g)(m)
 
-       // Set m->morepc to f's PC.
-       MOVW    LR, m_morepc(m)
-
        // Call newstack on m->g0's stack.
        MOVW    m_g0(m), g
        MOVW    (g_sched+gobuf_sp)(g), SP
@@ -212,7 +217,7 @@ TEXT reflect·call(SB), 7, $-4
        MOVW    8(SP), R1                       // arg frame
        MOVW    12(SP), R2                      // arg size
 
-       MOVW    R0, m_morepc(m)                 // f's PC
+       MOVW    R0, m_cret(m)                   // f's PC
        MOVW    R1, m_moreargp(m)               // f's argument pointer
        MOVW    R2, m_moreargsize(m)            // f's argument size
        MOVW    $1, R3
index 4be0eeb0dbdc1852b7d923715a0eca82405ad25e..c9ac557154ccb827dd64389d2546b40990b53462 100644 (file)
@@ -1464,7 +1464,7 @@ addstackroots(G *gp)
        if(ScanStackByFrames) {
                USED(stk);
                USED(guard);
-               runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, addframeroots, nil);
+               runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, addframeroots, nil, false);
        } else {
                USED(pc);
                n = 0;
@@ -2011,6 +2011,8 @@ runtime·gc(int32 force)
                } else {
                        // switch to g0, call gc(&a), then switch back
                        g->param = &a;
+                       g->status = Gwaiting;
+                       g->waitreason = "garbage collection";
                        runtime·mcall(mgc);
                }
                // record a new start time in case we're going around again
@@ -2042,6 +2044,7 @@ mgc(G *gp)
 {
        gc(gp->param);
        gp->param = nil;
+       gp->status = Grunning;
        runtime·gogo(&gp->sched);
 }
 
index 9a54002e4bebb80f9527f8fe58371e19f38a6fc2..0d89a267b9e98abfb26757afdda290f95a8f23ec 100644 (file)
@@ -478,7 +478,7 @@ saveg(uintptr pc, uintptr sp, G *gp, TRecord *r)
 {
        int32 n;
        
-       n = runtime·gentraceback((uintptr)pc, (uintptr)sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil);
+       n = runtime·gentraceback((uintptr)pc, (uintptr)sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil, false);
        if(n < nelem(r->stk))
                r->stk[n] = 0;
 }
index 84b6a1d37d8691a5bb29766d74770f3738d8e4f4..a174771db34cfd15ef55ab6bf9a3244c625bc551 100644 (file)
@@ -88,6 +88,8 @@ runtime·sighandler(void *v, int8 *s, G *gp)
                return NDFLT;
 
 Throw:
+       m->throwing = 1;
+       m->caughtsig = gp;
        runtime·startpanic();
 
        runtime·printf("%s\n", s);
index de81b1264bb86b495521a68c055f173cb637c20c..30f31e99693bd285e0c9a59e82fa2e385741bc9a 100644 (file)
@@ -96,6 +96,8 @@ runtime·sighandler(void *v, int8 *s, G *gp)
                return NDFLT;
 
 Throw:
+       m->throwing = 1;
+       m->caughtsig = gp;
        runtime·startpanic();
 
        runtime·printf("%s\n", s);
index f6e9dba4e6b60753775bd0c76f73425e691e242e..963063a8e85fcf9ac3c29342f595334a11d3c6d7 100644 (file)
@@ -277,6 +277,7 @@ recovery(G *gp)
        else
                gp->sched.sp = (uintptr)argp - 2*sizeof(uintptr);
        gp->sched.pc = pc;
+       gp->sched.lr = 0;
        gp->sched.ret = 1;
        runtime·gogo(&gp->sched);
 }
index c121466ce9b4124f9fdcbe7f0882986d2790d2a3..e6844032a605af2421f143f26baab8f45462c626 100644 (file)
@@ -234,14 +234,25 @@ runtime·tracebackothers(G *me)
        int32 traceback;
 
        traceback = runtime·gotraceback(nil);
+       
+       // Show the current goroutine first, if we haven't already.
+       if((gp = m->curg) != nil && gp != me) {
+               runtime·printf("\n");
+               runtime·goroutineheader(gp);
+               runtime·traceback(gp->sched.pc, gp->sched.sp, gp->sched.lr, gp);
+       }
+
        for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
-               if(gp == me || gp->status == Gdead)
+               if(gp == me || gp == m->curg || gp->status == Gdead)
                        continue;
                if(gp->issystem && traceback < 2)
                        continue;
                runtime·printf("\n");
                runtime·goroutineheader(gp);
-               runtime·traceback(gp->sched.pc, gp->sched.sp, 0, gp);
+               if(gp->status == Grunning)
+                       runtime·printf("\tgoroutine running on other thread; stack unavailable\n");
+               else
+                       runtime·traceback(gp->sched.pc, gp->sched.sp, gp->sched.lr, gp);
        }
 }
 
@@ -656,6 +667,7 @@ runtime·newextram(void)
        gp = runtime·malg(4096);
        gp->sched.pc = (uintptr)runtime·goexit;
        gp->sched.sp = gp->stackbase;
+       gp->sched.lr = 0;
        gp->sched.g = gp;
        gp->status = Gsyscall;
        mp->curg = gp;
@@ -1830,7 +1842,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
                runtime·unlock(&prof);
                return;
        }
-       n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil);
+       n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
        if(n > 0)
                prof.fn(prof.pcbuf, n);
        runtime·unlock(&prof);
@@ -2446,12 +2458,16 @@ 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;
 }
 
index 5422258a69cbb35f5ac6c9d03ac840c21b28b6db..4fb022c39cdb697a7a9f8f126195db45f28e8469 100644 (file)
@@ -269,9 +269,7 @@ struct      G
 };
 struct M
 {
-       // The offsets of these fields are known to (hard-coded in) libmach.
        G*      g0;             // goroutine with scheduling stack
-       void    (*morepc)(void);
        void*   moreargp;       // argument pointer for more stack
        Gobuf   morebuf;        // gobuf arg to morestack
 
@@ -284,6 +282,7 @@ struct      M
        uintptr tls[4];         // thread-local storage (for x86 extern register)
        void    (*mstartfn)(void);
        G*      curg;           // current running goroutine
+       G*      caughtsig;      // goroutine running during fatal signal
        P*      p;              // attached P for executing Go code (nil if not executing Go code)
        P*      nextp;
        int32   id;
@@ -676,7 +675,7 @@ struct Stkframe
        uintptr varlen; // number of bytes at varp
 };
 
-int32  runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*);
+int32  runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool);
 void   runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
 void   runtime·tracebackothers(G*);
 bool   runtime·haszeroargs(uintptr pc);
@@ -803,6 +802,7 @@ int32       runtime·mcount(void);
 int32  runtime·gcount(void);
 void   runtime·mcall(void(*)(G*));
 uint32 runtime·fastrand1(void);
+void   runtime·rewindmorestack(Gobuf*);
 
 void runtime·setmg(M*, G*);
 void runtime·newextram(void);
@@ -1015,7 +1015,7 @@ Hmap*     runtime·makemap_c(MapType*, int64);
 Hchan* runtime·makechan_c(ChanType*, int64);
 void   runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*);
 void   runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
-bool   runtime·showframe(Func*, bool);
+bool   runtime·showframe(Func*, G*);
 
 void   runtime·ifaceE2I(InterfaceType*, Eface, Iface*);
 
index e18f523b0cf7ef617446d72790ffe0851aaa958c..0d8fc706f139815f04513e15e93d8dbcdd4322a2 100644 (file)
@@ -96,6 +96,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
                return;
 
 Throw:
+       m->throwing = 1;
+       m->caughtsig = gp;
        runtime·startpanic();
 
        if(sig < 0 || sig >= NSIG)
@@ -113,6 +115,7 @@ Throw:
        if(runtime·gotraceback(&crash)){
                runtime·traceback(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
                runtime·tracebackothers(gp);
+               runtime·printf("\n");
                runtime·dumpregs(info, ctxt);
        }
        
index b17510b1c765dd46f0a7a238fdcd67c1aa21c156..f566fe16fd45e1b96856bb495265b36d55e99486 100644 (file)
@@ -106,6 +106,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
                return;
 
 Throw:
+       m->throwing = 1;
+       m->caughtsig = gp;
        runtime·startpanic();
 
        if(sig < 0 || sig >= NSIG)
@@ -123,6 +125,7 @@ Throw:
        if(runtime·gotraceback(&crash)){
                runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
                runtime·tracebackothers(gp);
+               runtime·printf("\n");
                runtime·dumpregs(info, ctxt);
        }
        
index 635daeb5d57046cb859bdda8e114b783bf2fe6d6..febd157891e5988eac5d1cc1e6d861ea1c385f61 100644 (file)
@@ -94,6 +94,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
                return;
 
 Throw:
+       m->throwing = 1;
+       m->caughtsig = gp;
        if(runtime·panicking)  // traceback already printed
                runtime·exit(2);
        runtime·panicking = 1;
index abfe0cfe43fcaf46a90944759b3b5cfa87563e9a..9dba008b13b82b4c9a3c13890e1e70da5cefcfca 100644 (file)
@@ -7,6 +7,11 @@
 #include "malloc.h"
 #include "stack.h"
 
+enum
+{
+       StackDebug = 0,
+};
+
 typedef struct StackCacheNode StackCacheNode;
 struct StackCacheNode
 {
@@ -128,20 +133,29 @@ void
 runtime·oldstack(void)
 {
        Stktop *top;
-       Gobuf label;
        uint32 argsize;
        byte *sp, *old;
        uintptr *src, *dst, *dstend;
        G *gp;
        int64 goid;
 
-//printf("oldstack m->cret=%p\n", m->cret);
-
        gp = m->curg;
        top = (Stktop*)gp->stackbase;
        old = (byte*)gp->stackguard - StackGuard;
        sp = (byte*)top;
        argsize = top->argsize;
+
+       if(StackDebug) {
+               runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n",
+                       top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (uintptr)argsize);
+       }
+       
+       gp->sched = top->gobuf;
+       gp->sched.ret = m->cret;
+       m->cret = 0; // drop reference
+       gp->status = Gwaiting;
+       gp->waitreason = "stack unsplit";
+
        if(argsize > 0) {
                sp -= argsize;
                dst = (uintptr*)top->argp;
@@ -153,16 +167,15 @@ runtime·oldstack(void)
        goid = top->gobuf.g->goid;      // fault if g is bad, before gogo
        USED(goid);
 
-       label = top->gobuf;
        gp->stackbase = top->stackbase;
        gp->stackguard = top->stackguard;
        gp->stackguard0 = gp->stackguard;
+
        if(top->free != 0)
                runtime·stackfree(old, top->free);
 
-       label.ret = m->cret;
-       m->cret = 0;  // drop reference
-       runtime·gogo(&label);
+       gp->status = Grunning;
+       runtime·gogo(&gp->sched);
 }
 
 // Called from reflect·call or from runtime·morestack when a new
@@ -186,11 +199,31 @@ runtime·newstack(void)
        framesize = m->moreframesize;
        argsize = m->moreargsize;
        gp = m->curg;
+       gp->status = Gwaiting;
+       gp->waitreason = "stack split";
+       reflectcall = framesize==1;
+
+       if(!reflectcall)
+               runtime·rewindmorestack(&gp->sched);
 
-       if(m->morebuf.sp < gp->stackguard - StackGuard) {
-               runtime·printf("runtime: split stack overflow: %p < %p\n", m->morebuf.sp, gp->stackguard - StackGuard);
+       sp = m->morebuf.sp;
+       if(thechar == '6' || thechar == '8') {
+               // The call to morestack cost a word.
+               sp -= sizeof(uintptr);
+       }
+       if(StackDebug || sp < gp->stackguard - StackGuard) {
+               runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p stack=[%p, %p]\n"
+                       "\tmorebuf={pc:%p sp:%p lr:%p}\n"
+                       "\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
+                       (uintptr)framesize, (uintptr)argsize, sp, gp->stackguard - StackGuard, gp->stackbase,
+                       m->morebuf.pc, m->morebuf.sp, m->morebuf.lr,
+                       gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt);
+       }
+       if(sp < gp->stackguard - StackGuard) {
+               runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stackguard - StackGuard);
                runtime·throw("runtime: split stack overflow");
        }
+
        if(argsize % sizeof(uintptr) != 0) {
                runtime·printf("runtime: stack split with misaligned argsize %d\n", argsize);
                runtime·throw("runtime: stack split argsize");
@@ -221,9 +254,8 @@ runtime·newstack(void)
                free = framesize;
        }
 
-       if(0) {
-               runtime·printf("newstack framesize=%d argsize=%d morepc=%p moreargp=%p gobuf=%p, %p top=%p old=%p\n",
-                       framesize, argsize, m->morepc, m->moreargp, m->morebuf.pc, m->morebuf.sp, top, gp->stackbase);
+       if(StackDebug) {
+               runtime·printf("\t-> new stack [%p, %p]\n", stk, top);
        }
 
        top->stackbase = gp->stackbase;
@@ -234,6 +266,7 @@ runtime·newstack(void)
        top->free = free;
        m->moreargp = nil;
        m->morebuf.pc = (uintptr)nil;
+       m->morebuf.lr = (uintptr)nil;
        m->morebuf.sp = (uintptr)nil;
 
        // copy flag from panic
@@ -266,12 +299,12 @@ runtime·newstack(void)
        label.pc = (uintptr)runtime·lessstack;
        label.g = m->curg;
        if(reflectcall)
-               runtime·gostartcallfn(&label, (FuncVal*)m->morepc);
+               runtime·gostartcallfn(&label, (FuncVal*)m->cret);
        else {
-               // The stack growth code saves ctxt (not ret) in m->cret.
-               runtime·gostartcall(&label, m->morepc, (void*)m->cret);
-               m->cret = 0;
+               runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt);
+               gp->sched.ctxt = nil;
        }
+       gp->status = Grunning;
        runtime·gogo(&label);
 
        *(int32*)345 = 123;     // never return
index a349c1f1be4bd8bdf35e1e08ddba44cdd7af7ded..b6924c198ef44e675b329a9ed41a2cc91d37e7e7 100644 (file)
@@ -79,13 +79,11 @@ enum {
        StackMin = 4096,
        FixedStack = StackMin + StackSystem,
 
-       // Functions that need frames bigger than this call morestack
-       // unconditionally.  That is, on entry to a function it is assumed
-       // that the amount of space available in the current stack segment
-       // couldn't possibly be bigger than StackBig.  If stack segments
-       // do run with more space than StackBig, the space may not be
-       // used efficiently.  As a result, StackBig should not be significantly
-       // smaller than StackMin or StackExtra.
+       // Functions that need frames bigger than this use an extra
+       // instruction to do the stack split check, to avoid overflow
+       // in case SP - framesize wraps below zero.
+       // This value can be no bigger than the size of the unmapped
+       // space at zero.
        StackBig = 4096,
 
        // The stack guard is a pointer this many bytes above the
index 9fa2ac3db418bb02bcc3ea809a9169c3fac54fc9..7fd700e36ac323f891a8802a03a71639183e1872 100644 (file)
@@ -646,11 +646,11 @@ contains(String s, int8 *p)
 }
 
 bool
-runtime·showframe(Func *f, bool current)
+runtime·showframe(Func *f, G *gp)
 {
        static int32 traceback = -1;
 
-       if(current && m->throwing > 0)
+       if(m->throwing && gp != nil && (gp == m->curg || gp == m->caughtsig))
                return 1;
        if(traceback < 0)
                traceback = runtime·gotraceback(nil);
index 68ea49a557d3b29d4019a4b540a5b5f801b1ed09..a65560e5b5a4e71f63bc74c25e4b91c4202fba1d 100644 (file)
@@ -15,3 +15,21 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
        gobuf->pc = (uintptr)fn;
        gobuf->ctxt = ctxt;
 }
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+void
+runtime·rewindmorestack(Gobuf *gobuf)
+{
+       uint32 inst;
+
+       inst = *(uint32*)gobuf->pc;
+       if((gobuf->pc&3) == 0 && (inst>>24) == 0x9a) {
+               //runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>6) + 8);
+               gobuf->pc += ((int32)(inst<<8)>>6) + 8;
+               return;
+       }
+       runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst);
+       runtime·throw("runtime: misuse of rewindmorestack");
+}
index c786a0c9f87967f5de0bff36bcdefa008a6de41c..e68ff514a224de31906107e801ea1325106f2051 100644 (file)
@@ -19,3 +19,24 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
        gobuf->pc = (uintptr)fn;
        gobuf->ctxt = ctxt;
 }
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+void
+runtime·rewindmorestack(Gobuf *gobuf)
+{
+       byte *pc;
+       
+       pc = (byte*)gobuf->pc;
+       if(pc[0] == 0xe9) { // jmp 4-byte offset
+               gobuf->pc = gobuf->pc + 5 + *(int32*)(pc+1);
+               return;
+       }
+       if(pc[0] == 0xeb) { // jmp 1-byte offset
+               gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1);
+               return;
+       }
+       runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]);
+       runtime·throw("runtime: misuse of rewindmorestack");
+}
index 04914f091266d5dce264d238bc99f73123a4c0c4..c4d78872bb7a3dad8e4821a4eb1371fe3af75afa 100644 (file)
@@ -8,7 +8,6 @@
 
 void runtime·deferproc(void);
 void runtime·newproc(void);
-void runtime·newstack(void);
 void runtime·morestack(void);
 void runtime·sigpanic(void);
 void _div(void);
@@ -17,9 +16,9 @@ void _divu(void);
 void _modu(void);
 
 int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
 {
-       int32 i, n, skip0;
+       int32 i, n, nprint, skip0;
        uintptr x, tracepc;
        bool waspanic, printing;
        Func *f, *f2;
@@ -28,6 +27,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 
        skip0 = skip;
 
+       nprint = 0;
        runtime·memclr((byte*)&frame, sizeof frame);
        frame.pc = pc0;
        frame.lr = lr0;
@@ -58,7 +58,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        frame.sp = stk->gobuf.sp;
                        frame.lr = 0;
                        frame.fp = 0;
-                       if(printing && runtime·showframe(nil, gp == m->curg))
+                       if(printing && runtime·showframe(nil, gp))
                                runtime·printf("----- stack segment boundary -----\n");
                        stk = (Stktop*)stk->stackbase;
                        continue;
@@ -97,7 +97,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        frame.arglen = f2->frame; // conservative overestimate
                else {
                        runtime·printf("runtime: unknown argument frame size for %S\n", f->name);
-                       runtime·throw("invalid stack");
+                       if(!printing)
+                               runtime·throw("invalid stack");
                }
 
                // Derive location and size of local variables.
@@ -130,15 +131,13 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                if(callback != nil)
                        callback(&frame, v);
                if(printing) {
-                       if(runtime·showframe(f, gp == m->curg)) {
+                       if(printall || runtime·showframe(f, gp)) {
                                // Print during crash.
                                //      main(0x1, 0x2, 0x3)
                                //              /home/rsc/go/src/runtime/x.go:23 +0xf
                                tracepc = frame.pc;     // back up to CALL instruction for funcline.
                                if(n > 0 && frame.pc > f->entry && !waspanic)
                                        tracepc -= sizeof(uintptr);
-                               if(m->throwing && gp == m->curg)
-                                       runtime·printf("[fp=%p] ", frame.fp);
                                runtime·printf("%S(", f->name);
                                for(i = 0; i < f->args/sizeof(uintptr); i++) {
                                        if(i != 0)
@@ -153,7 +152,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                                runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
                                if(frame.pc > f->entry)
                                        runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
+                               if(m->throwing && gp == m->curg)
+                                       runtime·printf(" fp=%p", frame.fp);
                                runtime·printf("\n");
+                               nprint++;
                        }
                }
                n++;
@@ -161,28 +163,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
        skipped:
                waspanic = f->entry == (uintptr)runtime·sigpanic;
 
-               if(printing && f->entry == (uintptr)runtime·newstack && gp == m->g0) {
-                       runtime·printf("----- newstack called from goroutine %D -----\n", m->curg->goid);
-                       frame.pc = (uintptr)m->morepc;
-                       frame.sp = (uintptr)m->moreargp - sizeof(void*);
-                       frame.lr = m->morebuf.pc;
-                       frame.fp = m->morebuf.sp;
-                       gp = m->curg;
-                       stk = (Stktop*)gp->stackbase;
-                       continue;
-               }
-               
-               if(printing && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
-                       runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
-                       gp = m->curg;
-                       stk = (Stktop*)gp->stackbase;
-                       frame.sp = stk->gobuf.sp;
-                       frame.pc = stk->gobuf.pc;
-                       frame.fp = 0;
-                       frame.lr = 0;
-                       continue;
-               }       
-               
                // Do not unwind past the bottom of the stack.
                if(frame.pc == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)_rt0_go)
                        break;
@@ -214,19 +194,29 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                }
        }
        
-       if(printing && (frame.pc = gp->gopc) != 0 && (f = runtime·findfunc(frame.pc)) != nil
-                       && runtime·showframe(f, gp == m->curg) && gp->goid != 1) {
+       if(pcbuf == nil && callback == nil)
+               n = nprint;
+
+       return n;               
+}
+
+static void
+printcreatedby(G *gp)
+{
+       uintptr pc, tracepc;
+       Func *f;
+
+       if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
+               && runtime·showframe(f, gp) && gp->goid != 1) {
                runtime·printf("created by %S\n", f->name);
-               tracepc = frame.pc;     // back up to CALL instruction for funcline.
-               if(n > 0 && frame.pc > f->entry)
+               tracepc = pc;   // back up to CALL instruction for funcline.
+               if(pc > f->entry)
                        tracepc -= sizeof(uintptr);
                runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
-               if(frame.pc > f->entry)
-                       runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
+               if(pc > f->entry)
+                       runtime·printf(" +%p", (uintptr)(pc - f->entry));
                runtime·printf("\n");
        }
-
-       return n;               
 }
 
 void
@@ -238,7 +228,12 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
                sp = gp->sched.sp;
                lr = 0;
        }
-       runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil);
+
+       // Print traceback. By default, omits runtime frames.
+       // If that means we print nothing at all, repeat forcing all frames printed.
+       if(runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, false) == 0)
+               runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, true);
+       printcreatedby(gp);
 }
 
 // func caller(n int) (pc uintptr, file string, line int, ok bool)
@@ -250,5 +245,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
        sp = runtime·getcallersp(&skip);
        pc = (uintptr)runtime·getcallerpc(&skip);
 
-       return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil);
+       return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil, false);
 }
index ec666470054eca8083cce9a7e35b1632f459f495..739d93aa8c2130e144926885a20c775ca8339c8b 100644 (file)
@@ -10,7 +10,6 @@
 
 void runtime·deferproc(void);
 void runtime·newproc(void);
-void runtime·newstack(void);
 void runtime·morestack(void);
 void runtime·sigpanic(void);
 
@@ -22,9 +21,9 @@ void runtime·sigpanic(void);
 // collector (callback != nil).  A little clunky to merge these, but avoids
 // duplicating the code and all its subtlety.
 int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
 {
-       int32 i, n, sawnewstack;
+       int32 i, n, nprint;
        uintptr tracepc;
        bool waspanic, printing;
        Func *f, *f2;
@@ -33,6 +32,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 
        USED(lr0);
 
+       nprint = 0;
        runtime·memclr((byte*)&frame, sizeof frame);
        frame.pc = pc0;
        frame.sp = sp0;
@@ -47,7 +47,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
        }
 
        n = 0;
-       sawnewstack = 0;
        stk = (Stktop*)gp->stackbase;
        while(n < max) {
                // Typically:
@@ -63,7 +62,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        frame.sp = stk->gobuf.sp;
                        frame.lr = 0;
                        frame.fp = 0;
-                       if(printing && runtime·showframe(nil, gp == m->curg))
+                       if(printing && runtime·showframe(nil, gp))
                                runtime·printf("----- stack segment boundary -----\n");
                        stk = (Stktop*)stk->stackbase;
                        continue;
@@ -101,7 +100,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        frame.arglen = f2->frame; // conservative overestimate
                else {
                        runtime·printf("runtime: unknown argument frame size for %S\n", f->name);
-                       runtime·throw("invalid stack");
+                       if(!printing)
+                               runtime·throw("invalid stack");
                }
 
                // Derive location and size of local variables.
@@ -133,7 +133,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                if(callback != nil)
                        callback(&frame, v);
                if(printing) {
-                       if(runtime·showframe(f, gp == m->curg)) {
+                       if(printall || runtime·showframe(f, gp)) {
                                // Print during crash.
                                //      main(0x1, 0x2, 0x3)
                                //              /home/rsc/go/src/runtime/x.go:23 +0xf
@@ -141,8 +141,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                                tracepc = frame.pc;     // back up to CALL instruction for funcline.
                                if(n > 0 && frame.pc > f->entry && !waspanic)
                                        tracepc--;
-                               if(m->throwing && gp == m->curg)
-                                       runtime·printf("[fp=%p] ", frame.fp);
                                runtime·printf("%S(", f->name);
                                for(i = 0; i < f->args/sizeof(uintptr); i++) {
                                        if(i != 0)
@@ -157,7 +155,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                                runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
                                if(frame.pc > f->entry)
                                        runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
+                               if(m->throwing && gp == m->curg)
+                                       runtime·printf(" fp=%p", frame.fp);
                                runtime·printf("\n");
+                               nprint++;
                        }
                }
                n++;
@@ -168,36 +169,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
                        frame.fp += 2*sizeof(uintptr);
 
-               if(f->entry == (uintptr)runtime·newstack)
-                       sawnewstack = 1;
-
-               if(printing && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) {
-                       // The fact that we saw newstack means that morestack
-                       // has managed to record its information in m, so we can
-                       // use it to keep unwinding the stack.
-                       runtime·printf("----- morestack called from goroutine %D -----\n", m->curg->goid);
-                       frame.pc = (uintptr)m->morepc;
-                       frame.sp = m->morebuf.sp - sizeof(void*);
-                       frame.lr = m->morebuf.pc;
-                       frame.fp = m->morebuf.sp;
-                       sawnewstack = 0;
-                       gp = m->curg;
-                       stk = (Stktop*)gp->stackbase;
-                       continue;
-               }
-
-               if(printing && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
-                       // Lessstack is running on scheduler stack.  Switch to original goroutine.
-                       runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
-                       gp = m->curg;
-                       stk = (Stktop*)gp->stackbase;
-                       frame.sp = stk->gobuf.sp;
-                       frame.pc = stk->gobuf.pc;
-                       frame.fp = 0;
-                       frame.lr = 0;
-                       continue;
-               }
-
                // Do not unwind past the bottom of the stack.
                if(frame.pc == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)_rt0_go)
                        break;
@@ -209,20 +180,29 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                frame.fp = 0;
        }
        
+       if(pcbuf == nil && callback == nil)
+               n = nprint;
+       
+       return n;
+}
+
+static void
+printcreatedby(G *gp)
+{
+       uintptr pc, tracepc;
+       Func *f;
+
        // Show what created goroutine, except main goroutine (goid 1).
-       if(printing && (frame.pc = gp->gopc) != 0 && (f = runtime·findfunc(frame.pc)) != nil
-                       && runtime·showframe(f, gp == m->curg) && gp->goid != 1) {
+       if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && gp->goid != 1) {
                runtime·printf("created by %S\n", f->name);
-               tracepc = frame.pc;     // back up to CALL instruction for funcline.
-               if(n > 0 && frame.pc > f->entry)
+               tracepc = pc;   // back up to CALL instruction for funcline.
+               if(pc > f->entry)
                        tracepc--;
                runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
-               if(frame.pc > f->entry)
-                       runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
+               if(pc > f->entry)
+                       runtime·printf(" +%p", (uintptr)(pc - f->entry));
                runtime·printf("\n");
        }
-       
-       return n;
 }
 
 void
@@ -235,7 +215,12 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
                pc = gp->sched.pc;
                sp = gp->sched.sp;
        }
-       runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil);
+       
+       // Print traceback. By default, omits runtime frames.
+       // If that means we print nothing at all, repeat forcing all frames printed.
+       if(runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, false) == 0)
+               runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, true);
+       printcreatedby(gp);
 }
 
 int32
@@ -246,5 +231,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
        sp = runtime·getcallersp(&skip);
        pc = (uintptr)runtime·getcallerpc(&skip);
 
-       return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil);
+       return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil, false);
 }