diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go index 09b56ac66f5..d72d797ee5a 100644 --- a/src/cmd/internal/obj/pcln.go +++ b/src/cmd/internal/obj/pcln.go @@ -9,6 +9,11 @@ import ( "log" ) +const ( + PrologueEnd = 2 + iota // overload "is_stmt" to include prologue_end + EpilogueBegin // overload "is_stmt" to include epilogue_end +) + func addvarint(d *Pcdata, v uint32) { for ; v >= 0x80; v >>= 7 { d.P = append(d.P, uint8(v|0x80)) @@ -235,6 +240,7 @@ func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg in // pctostmt returns either, // if phase==0, then whether the current instruction is a step-target (Dwarf is_stmt) +// bit-or'd with whether the current statement is a prologue end or epilogue begin // else (phase == 1), zero. // func pctostmt(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 { @@ -242,14 +248,22 @@ func pctostmt(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg int return 0 // Ignored; also different from initial value of -1, if that ever matters. } s := p.Pos.IsStmt() - if s == src.PosIsStmt { - return 1 + l := p.Pos.Xlogue() + + var is_stmt int32 + + // PrologueEnd, at least, is passed to the next instruction + switch l { + case src.PosPrologueEnd: + is_stmt = PrologueEnd + case src.PosEpilogueBegin: + is_stmt = EpilogueBegin } - if s == src.PosNotStmt { // includes NoSrcPos case - return 0 + + if s != src.PosNotStmt { + is_stmt |= 1 // either PosDefaultStmt from asm, or PosIsStmt from go } - // Line numbers in .s files will have no special setting, therefore default to is_stmt=1. - return 1 + return is_stmt } // pctopcdata computes the pcdata value in effect at p. diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index c2d508d96ec..59a2e20d6b0 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -33,6 +33,7 @@ package x86 import ( "cmd/internal/obj" "cmd/internal/objabi" + "cmd/internal/src" "cmd/internal/sys" "math" "strings" @@ -676,6 +677,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check } + // Delve debugger would like the next instruction to be noted as the end of the function prologue. + // TODO: are there other cases (e.g., wrapper functions) that need marking? + markedPrologue := false + if autoffset != 0 { if autoffset%int32(ctxt.Arch.RegSize) != 0 { ctxt.Diag("unaligned stack size %d", autoffset) @@ -685,6 +690,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.From.Type = obj.TYPE_CONST p.From.Offset = int64(autoffset) p.Spadj = autoffset + p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd) + markedPrologue = true } deltasp := autoffset @@ -700,6 +707,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.To.Reg = REG_SP p.To.Scale = 1 p.To.Offset = int64(autoffset) - int64(bpsize) + if !markedPrologue { + p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd) + } // Move current frame to BP p = obj.Appendp(p, newprog) diff --git a/src/cmd/internal/src/pos.go b/src/cmd/internal/src/pos.go index 1cf68f28b51..110a57b98de 100644 --- a/src/cmd/internal/src/pos.go +++ b/src/cmd/internal/src/pos.go @@ -293,7 +293,7 @@ func (b *PosBase) InliningIndex() int { // A lico is a compact encoding of a LIne and COlumn number. type lico uint32 -// Layout constants: 22 bits for line, 8 bits for column, 2 for isStmt +// Layout constants: 20 bits for line, 8 bits for column, 2 for isStmt, 2 for pro/epilogue // (If this is too tight, we can either make lico 64b wide, // or we can introduce a tiered encoding where we remove column // information as line numbers grow bigger; similar to what gcc @@ -301,13 +301,18 @@ type lico uint32 // The bitfield order is chosen to make IsStmt be the least significant // part of a position; its use is to communicate statement edges through // instruction scrambling in code generation, not to impose an order. +// TODO: Prologue and epilogue are perhaps better handled as psuedoops for the assembler, +// because they have almost no interaction with other uses of the position. const ( - lineBits, lineMax = 22, 1< lineMax { // cannot represent line, use max. line so we have some information @@ -363,6 +376,9 @@ func (x lico) IsStmt() uint { } return uint(x) >> isStmtShift & isStmtMax } +func (x lico) Xlogue() PosXlogue { + return PosXlogue(uint(x) >> xlogueShift & xlogueMax) +} // withNotStmt returns a lico for the same location, but not a statement func (x lico) withNotStmt() lico { @@ -379,6 +395,18 @@ func (x lico) withIsStmt() lico { return x.withStmt(PosIsStmt) } +// withLogue attaches a prologue/epilogue attribute to a lico +func (x lico) withXlogue(xlogue PosXlogue) lico { + if x == 0 { + if xlogue == 0 { + return x + } + // Normalize 0 to "not a statement" + x = lico(PosNotStmt << isStmtShift) + } + return lico(uint(x) & ^uint(xlogueMax<