" wincallbackcontext struct{};" +
                        " _select struct{}; " +
                        "); " +
-                       "const ( cb_max = 2000 )"
+                       "const (" +
+                       " cb_max = 2000;" +
+                       " _Gidle = 1;" +
+                       " _Grunnable = 2;" +
+                       " _Grunning = 3;" +
+                       " _Gsyscall = 4;" +
+                       " _Gwaiting = 5;" +
+                       " _Gdead = 6;" +
+                       " _Genqueue = 7;" +
+                       " _Gcopystack = 8;" +
+                       ")"
                f, err = parser.ParseFile(fset, filename, src, 0)
                if err != nil {
                        log.Fatalf("incorrect generated file: %s", err)
 
 #include "funcdata.h"
 #include "../../cmd/ld/textflag.h"
 
-TEXT _rt0_go(SB),NOSPLIT,$0
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
        // copy arguments forward on an even stack
        MOVL    argc+0(FP), AX
        MOVL    argv+4(FP), BX
 
 #include "funcdata.h"
 #include "../../cmd/ld/textflag.h"
 
-TEXT _rt0_go(SB),NOSPLIT,$0
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
        // copy arguments forward on an even stack
        MOVQ    DI, AX          // argc
        MOVQ    SI, BX          // argv
 
 #include "funcdata.h"
 #include "../../cmd/ld/textflag.h"
 
-TEXT _rt0_go(SB),NOSPLIT,$0
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
        // copy arguments forward on an even stack
        MOVL    argc+0(FP), AX
        MOVL    argv+4(FP), BX
 
 #include "../../cmd/ld/textflag.h"
 
 // using frame size $-4 means do not save LR on stack.
-TEXT _rt0_go(SB),NOSPLIT,$-4
+TEXT runtime·rt0_go(SB),NOSPLIT,$-4
        MOVW    $0xcafebabe, R12
 
        // copy arguments forward on an even stack
 
        if(p != nil && !runtime·strcmp(p, (byte*)"0"))
                runtime·copystack = false;
 
-       mstats.enablegc = 1;
-
        if(runtime·buildVersion.str == nil) {
                // Condition should never trigger.  This code just serves
                // to ensure runtime·buildVersion is kept in the resulting binary.
 
        if(g->m != &runtime·m0)
                runtime·throw("runtime·main not on m0");
+
        runtime·init();
+       mstats.enablegc = 1; // now that runtime is initialized, GC is okay
+
        main·init();
 
        if(g->defer != &d || d.fn != &initDone)
                *(int32*)runtime·main = 0;
 }
 
-void
-runtime·goroutineheader(G *gp)
-{
-       String status;
-       int64 waitfor;
-       uint32 gpstatus;
-
-       gpstatus = runtime·readgstatus(gp);
-       switch(gpstatus) {
-       case Gidle:
-               status = runtime·gostringnocopy((byte*)"idle");
-               break;
-       case Grunnable:
-               status = runtime·gostringnocopy((byte*)"runnable");
-               break;
-       case Grunning:
-               status = runtime·gostringnocopy((byte*)"running");
-               break;
-       case Gsyscall:
-               status = runtime·gostringnocopy((byte*)"syscall");
-               break;
-       case Gwaiting:
-               if(gp->waitreason.str != nil)
-                       status = gp->waitreason;
-               else
-                       status = runtime·gostringnocopy((byte*)"waiting");
-               break;
-       case Gscan:
-               status = runtime·gostringnocopy((byte*)"scan");
-               break;
-       case Gscanrunnable:
-               status =  runtime·gostringnocopy((byte*)"scanrunnable");
-               break;
-       case Gscanrunning:
-               status = runtime·gostringnocopy((byte*)"scanrunning");
-               break;
-       case Gscansyscall:
-               status = runtime·gostringnocopy((byte*)"scansyscall");
-               break;
-       case Gscanenqueue:
-               status = runtime·gostringnocopy((byte*)"scanenqueue");
-               break;
-       case Gscanwaiting:
-               if(gp->waitreason.str != nil)
-                       status = gp->waitreason;
-               else
-                       status = runtime·gostringnocopy((byte*)"scanwaiting");
-               break;
-       case Gcopystack:
-               status = runtime·gostringnocopy((byte*)"copystack");
-               break;
-       default:
-               status = runtime·gostringnocopy((byte*)"???");
-               break;
-       }
-
-       // approx time the G is blocked, in minutes
-       waitfor = 0;
-       gpstatus = gpstatus&~Gscan; // drop the scan bit
-       if((gpstatus == Gwaiting || gpstatus == Gsyscall) && gp->waitsince != 0)
-               waitfor = (runtime·nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
-
-       runtime·printf("goroutine %D [%S", gp->goid, status);
-       if(waitfor >= 1)
-               runtime·printf(", %D minutes", waitfor);
-       if(gp->lockedm != nil)
-               runtime·printf(", locked to thread");
-       runtime·printf("]:\n");
-}
-
 static void
 dumpgstatus(G* gp)
 {
        runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
 }
 
-void
-runtime·tracebackothers(G *me)
-{
-       G *gp;
-       int32 traceback;
-       uintptr i;
-       uint32 status;
-
-       traceback = runtime·gotraceback(nil);
-       
-       // Show the current goroutine first, if we haven't already.
-       if((gp = g->m->curg) != nil && gp != me) {
-               runtime·printf("\n");
-               runtime·goroutineheader(gp);
-               runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
-       }
-
-       runtime·lock(&allglock);
-       for(i = 0; i < runtime·allglen; i++) {
-               gp = runtime·allg[i];
-               if(gp == me || gp == g->m->curg || runtime·readgstatus(gp) == Gdead)
-                       continue;
-               if(gp->issystem && traceback < 2)
-                       continue;
-               runtime·printf("\n");
-               runtime·goroutineheader(gp);
-               status = runtime·readgstatus(gp);
-               if((status&~Gscan) == Grunning){
-                       runtime·printf("\tgoroutine running on other thread; stack unavailable\n");
-                       runtime·printcreatedby(gp);
-               } else
-                       runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
-       }
-       runtime·unlock(&allglock);
-}
-
 static void
 checkmcount(void)
 {
        }
 }
 
-extern void runtime·morestack(void);
-uintptr runtime·externalthreadhandlerp;
-
-// Does f mark the top of a goroutine stack?
-bool
-runtime·topofstack(Func *f)
-{
-       return f->entry == (uintptr)runtime·goexit ||
-               f->entry == (uintptr)runtime·mstart ||
-               f->entry == (uintptr)runtime·mcall ||
-               f->entry == (uintptr)runtime·onM ||
-               f->entry == (uintptr)runtime·morestack ||
-               f->entry == (uintptr)runtime·lessstack ||
-               f->entry == (uintptr)_rt0_go ||
-               (runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp);
-}
-
 void
 runtime·setmaxthreads_m(void)
 {
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
        MOVW    (R13), R0       // argc
        MOVW    $4(R13), R1             // argv
        MOVM.DB.W [R0-R1], (R13)
-       B       _rt0_go(SB)
+       B       runtime·rt0_go(SB)
 
 TEXT main(SB),NOSPLIT,$-4
        MOVM.DB.W [R0-R1], (R13)
-       MOVW    $_rt0_go(SB), R4
+       MOVW    $runtime·rt0_go(SB), R4
        B               (R4)
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
 TEXT _fallback_vdso(SB),NOSPLIT,$0
        INT     $0x80
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
        SUB     $4, R13 // fake a stack frame for runtime·setup_auxv
        BL      runtime·setup_auxv(SB)
        ADD     $4, R13
-       B       _rt0_go(SB)
+       B       runtime·rt0_go(SB)
 
 TEXT bad_abi<>(SB),NOSPLIT,$-4
        // give diagnosis and exit
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        // Uncomment for fake time like on Go Playground.
        //MOVQ  $1257894000000000000, AX
        //MOVQ  AX, runtime·timens(SB)
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        B       main(SB)
 
 TEXT main(SB),NOSPLIT,$0
-       B       _rt0_go(SB)
+       B       runtime·rt0_go(SB)
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
        MOVW    (R13), R0       // argc
        MOVW    $4(R13), R1             // argv
        MOVM.DB.W [R0-R1], (R13)
-       B _rt0_go(SB)
+       B runtime·rt0_go(SB)
 
        INT     $3
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
        MOVL    AX, 0(SP)
        LEAL    inargv+0(FP), AX
        MOVL    AX, 4(SP)
-       CALL    _rt0_go(SB)
+       CALL    runtime·rt0_go(SB)
 
 DATA  runtime·isplan9(SB)/4, $1
 GLOBL runtime·isplan9(SB), $4
 
        MOVL    $1, _nprivates(SB)
        MOVL    inargc-8(FP), DI
        LEAQ    inargv+0(FP), SI
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
 DATA runtime·isplan9(SB)/4, $1
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
 DATA runtime·issolaris(SB)/4, $1
 
        JMP     main(SB)
 
 TEXT main(SB),NOSPLIT,$0
-       JMP     _rt0_go(SB)
+       JMP     runtime·rt0_go(SB)
 
 
 DATA  runtime·iswindows(SB)/4, $1
 
        JMP     AX
 
 TEXT main(SB),NOSPLIT,$-8
-       MOVQ    $_rt0_go(SB), AX
+       MOVQ    $runtime·rt0_go(SB), AX
        JMP     AX
 
 DATA  runtime·iswindows(SB)/4, $1
 
 void   runtime·netpollunlock(PollDesc*);
 void   runtime·crash(void);
 void   runtime·parsedebugvars(void);
-void   _rt0_go(void);
 void*  runtime·funcdata(Func*, int32);
 void   runtime·setmaxthreads_m(void);
 G*     runtime·timejump(void);
 
 func entersyscallblock()
 func exitsyscall()
 
-func goroutineheader(gp *g)
-func tracebackothers(gp *g)
-
 func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
 func gogo(buf *gobuf)
 func gosave(buf *gobuf)
 func funcspdelta(*_func, uintptr) int32 // symtab.c
 func funcarglen(*_func, uintptr) int32  // symtab.c
 const _ArgsSizeUnknown = -0x80000000    // funcdata.h
-func topofstack(*_func) bool            // proc.c
 
 
 // jmpdeferPC is the PC at the beginning of the jmpdefer assembly function.
 // The traceback needs to recognize it on link register architectures.
-var jmpdeferPC uintptr
-
-func init() {
-       f := jmpdefer
-       jmpdeferPC = **(**uintptr)(unsafe.Pointer(&f))
-}
+var jmpdeferPC = funcPC(jmpdefer)
 
 // System-specific hook. See traceback_windows.go
 var systraceback func(*_func, *stkframe, *g, bool, func(*stkframe, unsafe.Pointer) bool, unsafe.Pointer) (changed, aborted bool)
 func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int {
        return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, false)
 }
+
+var gStatusStrings = [...]string{
+       _Gidle:      "idle",
+       _Grunnable:  "runnable",
+       _Grunning:   "running",
+       _Gsyscall:   "syscall",
+       _Gwaiting:   "waiting",
+       _Gdead:      "dead",
+       _Genqueue:   "enqueue",
+       _Gcopystack: "copystack",
+}
+
+var gScanStatusStrings = [...]string{
+       0:          "scan",
+       _Grunnable: "scanrunnable",
+       _Grunning:  "scanrunning",
+       _Gsyscall:  "scansyscall",
+       _Gwaiting:  "scanwaiting",
+       _Gdead:     "scandead",
+       _Genqueue:  "scanenqueue",
+}
+
+func goroutineheader(gp *g) {
+       gpstatus := readgstatus(gp)
+
+       // Basic string status
+       var status string
+       if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
+               status = gStatusStrings[gpstatus]
+       } else if gpstatus&_Gscan != 0 && 0 <= gpstatus&^_Gscan && gpstatus&^_Gscan < uint32(len(gStatusStrings)) {
+               status = gStatusStrings[gpstatus&^_Gscan]
+       } else {
+               status = "???"
+       }
+
+       // Override.
+       if (gpstatus == _Gwaiting || gpstatus == _Gscanwaiting) && gp.waitreason != "" {
+               status = gp.waitreason
+       }
+
+       // approx time the G is blocked, in minutes
+       var waitfor int64
+       gpstatus &^= _Gscan // drop the scan bit
+       if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
+               waitfor = (nanotime() - gp.waitsince) / 60e9
+       }
+       print("goroutine ", gp.goid, " [", status)
+       if waitfor >= 1 {
+               print(", ", waitfor, " minutes")
+       }
+       if gp.lockedm != nil {
+               print(", locked to thread")
+       }
+       print("]:\n")
+}
+
+func tracebackothers(me *g) {
+       level := gotraceback(nil)
+
+       // Show the current goroutine first, if we haven't already.
+       g := getg()
+       gp := g.m.curg
+       if gp != nil && gp != me {
+               print("\n")
+               goroutineheader(gp)
+               traceback(^uintptr(0), ^uintptr(0), 0, gp)
+       }
+
+       lock(&allglock)
+       for _, gp := range allgs {
+               if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || gp.issystem && level < 2 {
+                       continue
+               }
+               print("\n")
+               goroutineheader(gp)
+               if readgstatus(gp)&^_Gscan == _Grunning {
+                       print("\tgoroutine running on other thread; stack unavailable\n")
+                       printcreatedby(gp)
+               } else {
+                       traceback(^uintptr(0), ^uintptr(0), 0, gp)
+               }
+       }
+       unlock(&allglock)
+}
+
+func goexit()
+func mstart()
+func morestack()
+func rt0_go()
+
+var (
+       goexitPC    = funcPC(goexit)
+       mstartPC    = funcPC(mstart)
+       mcallPC     = funcPC(mcall)
+       onMPC       = funcPC(onM)
+       morestackPC = funcPC(morestack)
+       lessstackPC = funcPC(lessstack)
+       rt0_goPC    = funcPC(rt0_go)
+
+       externalthreadhandlerp uintptr // initialized elsewhere
+)
+
+// Does f mark the top of a goroutine stack?
+func topofstack(f *_func) bool {
+       pc := f.entry
+       return pc == goexitPC ||
+               pc == mstartPC ||
+               pc == mcallPC ||
+               pc == onMPC ||
+               pc == morestackPC ||
+               pc == lessstackPC ||
+               pc == rt0_goPC ||
+               externalthreadhandlerp != 0 && pc == externalthreadhandlerp
+}
 
 var sigtramp struct{} // assembly function
 
 func init() {
-       f := sigtramp
-       sigtrampPC = **(**uintptr)(unsafe.Pointer(&f))
+       sigtrampPC = funcPC(sigtramp)
        systraceback = traceback_windows
 }