Commit 7ba41e99 authored by Russ Cox's avatar Russ Cox

runtime: convert a few traceback-related functions from proc.c to traceback.go

They were in proc.c mainly because there was no portable
traceback source file. As part of converting them to Go,
move to traceback.go.

In order to get access to the PC of _rt0_go,
rename to runtime.rt0_go.

LGTM=r
R=golang-codereviews, r
CC=dvyukov, golang-codereviews, iant, khr
https://golang.org/cl/139110043
parent 0e07f1c9
......@@ -405,7 +405,17 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" 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)
......
......@@ -6,7 +6,7 @@
#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
......
......@@ -6,7 +6,7 @@
#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
......
......@@ -6,7 +6,7 @@
#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
......
......@@ -7,7 +7,7 @@
#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
......
......@@ -185,8 +185,6 @@ runtime·schedinit(void)
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.
......@@ -244,7 +242,10 @@ runtime·main(void)
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)
......@@ -268,118 +269,12 @@ runtime·main(void)
*(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)
{
......@@ -3373,23 +3268,6 @@ runtime·testSchedLocalQueueSteal(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)
{
......
......@@ -13,4 +13,4 @@ TEXT _rt0_386_darwin(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
......@@ -11,5 +11,5 @@ TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8
JMP AX
TEXT main(SB),NOSPLIT,$-8
MOVQ $_rt0_go(SB), AX
MOVQ $runtime·rt0_go(SB), AX
JMP AX
......@@ -13,4 +13,4 @@ TEXT _rt0_386_dragonfly(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
......@@ -11,5 +11,5 @@ TEXT _rt0_amd64_dragonfly(SB),NOSPLIT,$-8
JMP AX
TEXT main(SB),NOSPLIT,$-8
MOVQ $_rt0_go(SB), AX
MOVQ $runtime·rt0_go(SB), AX
JMP AX
......@@ -13,4 +13,4 @@ TEXT _rt0_386_freebsd(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
......@@ -11,5 +11,5 @@ TEXT _rt0_amd64_freebsd(SB),NOSPLIT,$-8
JMP AX
TEXT main(SB),NOSPLIT,$-8
MOVQ $_rt0_go(SB), AX
MOVQ $runtime·rt0_go(SB), AX
JMP AX
......@@ -10,9 +10,9 @@ TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
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)
......@@ -14,7 +14,7 @@ TEXT _rt0_386_linux(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
TEXT _fallback_vdso(SB),NOSPLIT,$0
INT $0x80
......
......@@ -11,5 +11,5 @@ TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
JMP AX
TEXT main(SB),NOSPLIT,$-8
MOVQ $_rt0_go(SB), AX
MOVQ $runtime·rt0_go(SB), AX
JMP AX
......@@ -56,7 +56,7 @@ TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
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
......
......@@ -19,4 +19,4 @@ TEXT _rt0_386_nacl(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
......@@ -27,4 +27,4 @@ TEXT main(SB),NOSPLIT,$0
// 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)
......@@ -17,4 +17,4 @@ TEXT _rt0_arm_nacl(SB),NOSPLIT,$-4
B main(SB)
TEXT main(SB),NOSPLIT,$0
B _rt0_go(SB)
B runtime·rt0_go(SB)
......@@ -13,4 +13,4 @@ TEXT _rt0_386_netbsd(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
......@@ -11,5 +11,5 @@ TEXT _rt0_amd64_netbsd(SB),NOSPLIT,$-8
JMP AX
TEXT main(SB),NOSPLIT,$-8
MOVQ $_rt0_go(SB), AX
MOVQ $runtime·rt0_go(SB), AX
JMP AX
......@@ -10,4 +10,4 @@ TEXT _rt0_arm_netbsd(SB),NOSPLIT,$-4
MOVW (R13), R0 // argc
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
B _rt0_go(SB)
B runtime·rt0_go(SB)
......@@ -13,4 +13,4 @@ TEXT _rt0_386_openbsd(SB),NOSPLIT,$8
INT $3
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
......@@ -11,5 +11,5 @@ TEXT _rt0_amd64_openbsd(SB),NOSPLIT,$-8
JMP AX
TEXT main(SB),NOSPLIT,$-8
MOVQ $_rt0_go(SB), AX
MOVQ $runtime·rt0_go(SB), AX
JMP AX
......@@ -14,7 +14,7 @@ TEXT _rt0_386_plan9(SB),NOSPLIT,$12
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
......
......@@ -11,7 +11,7 @@ TEXT _rt0_amd64_plan9(SB),NOSPLIT,$24
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
......
......@@ -11,7 +11,7 @@ TEXT _rt0_amd64_solaris(SB),NOSPLIT,$-8
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
......
......@@ -13,7 +13,7 @@ TEXT _rt0_386_windows(SB),NOSPLIT,$12
JMP main(SB)
TEXT main(SB),NOSPLIT,$0
JMP _rt0_go(SB)
JMP runtime·rt0_go(SB)
DATA runtime·iswindows(SB)/4, $1
......
......@@ -12,7 +12,7 @@ TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8
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
......
......@@ -882,7 +882,6 @@ void runtime·netpolllock(PollDesc*);
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);
......
......@@ -138,9 +138,6 @@ func entersyscall()
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)
......@@ -260,4 +257,3 @@ var newproc, deferproc, lessstack struct{} // C/assembly functions
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
......@@ -32,12 +32,7 @@ const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386"
// 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)
......@@ -502,3 +497,117 @@ func callers(skip int, pcbuf *uintptr, m int) int {
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
}
......@@ -13,8 +13,7 @@ var sigtrampPC uintptr
var sigtramp struct{} // assembly function
func init() {
f := sigtramp
sigtrampPC = **(**uintptr)(unsafe.Pointer(&f))
sigtrampPC = funcPC(sigtramp)
systraceback = traceback_windows
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment