diff options
| author | Austin Clements <austin@google.com> | 2015-01-14 11:09:50 -0500 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2015-02-02 19:36:05 +0000 |
| commit | 3c0fee10dbe82771dcaa956a95bdfabdced5fff7 (patch) | |
| tree | 67ece87374bc9a50bd912d1012b7f62cf50e6aa8 /src/liblink | |
| parent | 20a6ff7261adecc1ba0dc3f3cd6a29054fdf90b7 (diff) | |
| download | go-3c0fee10dbe82771dcaa956a95bdfabdced5fff7.tar.xz | |
cmd/6g, liblink, runtime: support saving base pointers
This adds a "framepointer" GOEXPERIMENT that that makes the amd64
toolchain maintain base pointer chains in the same way that gcc
-fno-omit-frame-pointer does. Go doesn't use these saved base
pointers, but this does enable external tools like Linux perf and
VTune to unwind Go stacks when collecting system-wide profiles.
This requires support in the compilers to not clobber BP, support in
liblink for generating the BP-saving function prologue and unwinding
epilogue, and support in the runtime to save BPs across preemption, to
skip saved BPs during stack unwinding and, and to adjust saved BPs
during stack moving.
As with other GOEXPERIMENTs, everything from the toolchain to the
runtime must be compiled with this experiment enabled. To do this,
run make.bash (or all.bash) with GOEXPERIMENT=framepointer.
Change-Id: I4024853beefb9539949e5ca381adfdd9cfada544
Reviewed-on: https://go-review.googlesource.com/2992
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/liblink')
| -rw-r--r-- | src/liblink/go.c | 2 | ||||
| -rw-r--r-- | src/liblink/obj6.c | 52 |
2 files changed, 50 insertions, 4 deletions
diff --git a/src/liblink/go.c b/src/liblink/go.c index e31c71ab92..3bc780b852 100644 --- a/src/liblink/go.c +++ b/src/liblink/go.c @@ -21,7 +21,7 @@ static struct { int *val; } exper[] = { {"fieldtrack", &fieldtrack_enabled}, - {"basepointer", &framepointer_enabled}, + {"framepointer", &framepointer_enabled}, }; static void diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c index 696026300c..0ccb03924f 100644 --- a/src/liblink/obj6.c +++ b/src/liblink/obj6.c @@ -379,7 +379,7 @@ preprocess(Link *ctxt, LSym *cursym) { Prog *p, *q, *p1, *p2; int32 autoffset, deltasp; - int a, pcsize; + int a, pcsize, bpsize; vlong textstksiz, textarg; if(ctxt->tlsg == nil) @@ -403,6 +403,18 @@ preprocess(Link *ctxt, LSym *cursym) if(autoffset < 0) autoffset = 0; + if(framepointer_enabled && autoffset > 0) { + // Make room for to save a base pointer. If autoffset == 0, + // this might do something special like a tail jump to + // another function, so in that case we omit this. + bpsize = ctxt->arch->ptrsize; + autoffset += bpsize; + textstksiz += bpsize; + p->to.offset = ((uint64)p->to.offset & (0xffffffffull<<32)) | (uint32)autoffset; + } else { + bpsize = 0; + } + cursym->args = p->to.offset>>32; cursym->locals = textstksiz; @@ -447,6 +459,28 @@ preprocess(Link *ctxt, LSym *cursym) if(q != nil) q->pcond = p; deltasp = autoffset; + + if(bpsize > 0) { + // Save caller's BP + p = appendp(ctxt, p); + p->as = AMOVQ; + p->from.type = TYPE_REG; + p->from.reg = REG_BP; + p->to.type = TYPE_MEM; + p->to.reg = REG_SP; + p->to.scale = 1; + p->to.offset = autoffset - bpsize; + + // Move current frame to BP + p = appendp(ctxt, p); + p->as = ALEAQ; + p->from.type = TYPE_MEM; + p->from.reg = REG_SP; + p->from.scale = 1; + p->from.offset = autoffset - bpsize; + p->to.type = TYPE_REG; + p->to.reg = REG_BP; + } if(cursym->text->from.scale & WRAPPER) { // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame @@ -580,12 +614,12 @@ preprocess(Link *ctxt, LSym *cursym) pcsize = p->mode/8; a = p->from.name; if(a == NAME_AUTO) - p->from.offset += deltasp; + p->from.offset += deltasp - bpsize; if(a == NAME_PARAM) p->from.offset += deltasp + pcsize; a = p->to.name; if(a == NAME_AUTO) - p->to.offset += deltasp; + p->to.offset += deltasp - bpsize; if(a == NAME_PARAM) p->to.offset += deltasp + pcsize; @@ -630,6 +664,18 @@ preprocess(Link *ctxt, LSym *cursym) ctxt->diag("unbalanced PUSH/POP"); if(autoffset) { + if(bpsize > 0) { + // Restore caller's BP + p->as = AMOVQ; + p->from.type = TYPE_MEM; + p->from.reg = REG_SP; + p->from.scale = 1; + p->from.offset = autoffset - bpsize; + p->to.type = TYPE_REG; + p->to.reg = REG_BP; + p = appendp(ctxt, p); + } + p->as = AADJSP; p->from.type = TYPE_CONST; p->from.offset = -autoffset; |
