Commit 6f6a9398 authored by Austin Clements's avatar Austin Clements

Merge remote-tracking branch 'origin/dev.debug' into master

Change-Id: I85df2745af666b533f4f6f1d06f7c8e137590b5b
parents 3cb41be8 4c54a047
......@@ -571,9 +571,16 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/ssa.Block %s": "",
"*cmd/compile/internal/ssa.Block %v": "",
"*cmd/compile/internal/ssa.Func %s": "",
"*cmd/compile/internal/ssa.Func %v": "",
"*cmd/compile/internal/ssa.FuncDebug %v": "",
"*cmd/compile/internal/ssa.LocalSlot %+v": "",
"*cmd/compile/internal/ssa.LocalSlot %v": "",
"*cmd/compile/internal/ssa.Register %v": "",
"*cmd/compile/internal/ssa.SparseTreeNode %v": "",
"*cmd/compile/internal/ssa.Value %s": "",
"*cmd/compile/internal/ssa.Value %v": "",
"*cmd/compile/internal/ssa.VarLoc %+v": "",
"*cmd/compile/internal/ssa.VarLoc %v": "",
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
"*cmd/compile/internal/types.Field %p": "",
"*cmd/compile/internal/types.Field %v": "",
......@@ -592,6 +599,7 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Type %p": "",
"*cmd/compile/internal/types.Type %s": "",
"*cmd/compile/internal/types.Type %v": "",
"*cmd/internal/dwarf.Location %#v": "",
"*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "",
"*cmd/internal/obj.Prog %s": "",
......@@ -600,17 +608,21 @@ var knownFormats = map[string]string{
"[16]byte %x": "",
"[]*cmd/compile/internal/gc.Node %v": "",
"[]*cmd/compile/internal/gc.Sig %#v": "",
"[]*cmd/compile/internal/ssa.Block %+v": "",
"[]*cmd/compile/internal/ssa.Value %v": "",
"[][]cmd/compile/internal/ssa.SlotID %v": "",
"[]byte %s": "",
"[]byte %x": "",
"[]cmd/compile/internal/ssa.Edge %v": "",
"[]cmd/compile/internal/ssa.ID %v": "",
"[]cmd/compile/internal/ssa.VarLocList %v": "",
"[]string %v": "",
"bool %v": "",
"byte %08b": "",
"byte %c": "",
"cmd/compile/internal/arm.shift %d": "",
"cmd/compile/internal/gc.Class %d": "",
"cmd/compile/internal/gc.Class %v": "",
"cmd/compile/internal/gc.Ctype %d": "",
"cmd/compile/internal/gc.Ctype %v": "",
"cmd/compile/internal/gc.Level %d": "",
......@@ -630,11 +642,13 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "",
"cmd/compile/internal/ssa.ID %d": "",
"cmd/compile/internal/ssa.ID %v": "",
"cmd/compile/internal/ssa.LocalSlot %v": "",
"cmd/compile/internal/ssa.Location %v": "",
"cmd/compile/internal/ssa.Op %s": "",
"cmd/compile/internal/ssa.Op %v": "",
"cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.VarLocList %v": "",
"cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "",
......@@ -648,6 +662,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/types.EType %d": "",
"cmd/compile/internal/types.EType %s": "",
"cmd/compile/internal/types.EType %v": "",
"cmd/internal/dwarf.Location %#v": "",
"cmd/internal/src.Pos %s": "",
"cmd/internal/src.Pos %v": "",
"error %v": "",
......
......@@ -44,6 +44,7 @@ var (
Debug_vlog bool
Debug_wb int
Debug_pctab string
Debug_locationlist int
)
// Debug arguments.
......@@ -69,6 +70,7 @@ var debugtab = []struct {
{"wb", "print information about write barriers", &Debug_wb},
{"export", "print export data", &Debug_export},
{"pctab", "print named pc-value table", &Debug_pctab},
{"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
}
const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
......@@ -192,6 +194,7 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
flag.BoolVar(&flagDWARF, "dwarf", true, "generate DWARF symbols")
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", false, "add location lists to DWARF in optimized mode")
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
objabi.Flagcount("f", "debug stack frames", &Debug['f'])
objabi.Flagcount("h", "halt on error", &Debug['h'])
......@@ -298,6 +301,9 @@ func Main(archInit func(*Arch)) {
if nBackendWorkers > 1 && !concurrentBackendAllowed() {
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
}
if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
}
// parse -d argument
if debugstr != "" {
......@@ -383,7 +389,7 @@ func Main(archInit func(*Arch)) {
Debug['l'] = 1 - Debug['l']
}
trackScopes = flagDWARF && Debug['l'] == 0 && Debug['N'] != 0
trackScopes = flagDWARF && ((Debug['l'] == 0 && Debug['N'] != 0) || Ctxt.Flag_locationlists)
Widthptr = thearch.LinkArch.PtrSize
Widthreg = thearch.LinkArch.RegSize
......
This diff is collapsed.
......@@ -168,7 +168,7 @@ func (v varsByScopeAndOffset) Less(i, j int) bool {
if v.scopes[i] != v.scopes[j] {
return v.scopes[i] < v.scopes[j]
}
return v.vars[i].Offset < v.vars[j].Offset
return v.vars[i].StackOffset < v.vars[j].StackOffset
}
func (v varsByScopeAndOffset) Swap(i, j int) {
......
......@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
{Func{}, 124, 216},
{Func{}, 128, 224},
{Name{}, 36, 56},
{Param{}, 28, 56},
{Node{}, 76, 128},
......
......@@ -4386,14 +4386,15 @@ func genssa(f *ssa.Func, pp *Progs) {
// Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks())
s.pp = pp
var valueProgs map[*obj.Prog]*ssa.Value
var blockProgs map[*obj.Prog]*ssa.Block
var progToValue map[*obj.Prog]*ssa.Value
var progToBlock map[*obj.Prog]*ssa.Block
var valueToProg []*obj.Prog
var logProgs = e.log
if logProgs {
valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
f.Logf("genssa %s\n", f.Name)
blockProgs[s.pp.next] = f.Blocks[0]
progToBlock[s.pp.next] = f.Blocks[0]
}
if thearch.Use387 {
......@@ -4402,6 +4403,11 @@ func genssa(f *ssa.Func, pp *Progs) {
s.ScratchFpMem = e.scratchFpMem
logLocationLists := Debug_locationlist != 0
if Ctxt.Flag_locationlists {
e.curfn.Func.DebugInfo = ssa.BuildFuncDebug(f, logLocationLists)
valueToProg = make([]*obj.Prog, f.NumValues())
}
// Emit basic blocks
for i, b := range f.Blocks {
s.bstart[b.ID] = s.pp.next
......@@ -4442,15 +4448,19 @@ func genssa(f *ssa.Func, pp *Progs) {
}
case ssa.OpPhi:
CheckLoweredPhi(v)
case ssa.OpRegKill:
// nothing to do
default:
// let the backend handle it
thearch.SSAGenValue(&s, v)
}
if Ctxt.Flag_locationlists {
valueToProg[v.ID] = x
}
if logProgs {
for ; x != s.pp.next; x = x.Link {
valueProgs[x] = v
progToValue[x] = v
}
}
}
......@@ -4468,7 +4478,23 @@ func genssa(f *ssa.Func, pp *Progs) {
thearch.SSAGenBlock(&s, b, next)
if logProgs {
for ; x != s.pp.next; x = x.Link {
blockProgs[x] = b
progToBlock[x] = b
}
}
}
if Ctxt.Flag_locationlists {
for _, locList := range e.curfn.Func.DebugInfo.Variables {
for _, loc := range locList.Locations {
loc.StartProg = valueToProg[loc.Start.ID]
if loc.End == nil {
Fatalf("empty loc %v compiling %v", loc, f.Name)
}
loc.EndProg = valueToProg[loc.End.ID]
if !logLocationLists {
loc.Start = nil
loc.End = nil
}
}
}
}
......@@ -4481,9 +4507,9 @@ func genssa(f *ssa.Func, pp *Progs) {
if logProgs {
for p := pp.Text; p != nil; p = p.Link {
var s string
if v, ok := valueProgs[p]; ok {
if v, ok := progToValue[p]; ok {
s = v.String()
} else if b, ok := blockProgs[p]; ok {
} else if b, ok := progToBlock[p]; ok {
s = b.String()
} else {
s = " " // most value and branch strings are 2-3 characters long
......@@ -4501,9 +4527,9 @@ func genssa(f *ssa.Func, pp *Progs) {
buf.WriteString("<dl class=\"ssa-gen\">")
for p := pp.Text; p != nil; p = p.Link {
buf.WriteString("<dt class=\"ssa-prog-src\">")
if v, ok := valueProgs[p]; ok {
if v, ok := progToValue[p]; ok {
buf.WriteString(v.HTML())
} else if b, ok := blockProgs[p]; ok {
} else if b, ok := progToBlock[p]; ok {
buf.WriteString(b.HTML())
}
buf.WriteString("</dt>")
......@@ -4880,9 +4906,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this string up into two separate variables.
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}
p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
return p, l
}
// Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
......@@ -4897,9 +4923,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
if n.Type.IsEmptyInterface() {
f = ".type"
}
c := e.namedAuto(n.Sym.Name+f, t, n.Pos)
d := e.namedAuto(n.Sym.Name+".data", t, n.Pos)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
c := e.splitSlot(&name, f, 0, t)
d := e.splitSlot(&name, ".data", t.Size(), t)
return c, d
}
// Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
......@@ -4911,10 +4937,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss
lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this slice up into three separate variables.
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}, ssa.LocalSlot{N: c, Type: lenType, Off: 0}
p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
return p, l, c
}
// Return the three parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
......@@ -4933,9 +4959,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
}
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this complex up into two separate variables.
c := e.namedAuto(n.Sym.Name+".real", t, n.Pos)
d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
r := e.splitSlot(&name, ".real", 0, t)
i := e.splitSlot(&name, ".imag", t.Size(), t)
return r, i
}
// Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
......@@ -4951,9 +4977,10 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
}
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this int64 up into two separate variables.
h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos)
l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos)
return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0}
if thearch.LinkArch.ByteOrder == binary.BigEndian {
return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
}
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
}
// Return the two parts of the larger variable.
if thearch.LinkArch.ByteOrder == binary.BigEndian {
......@@ -4966,12 +4993,15 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
n := name.N.(*Node)
st := name.Type
ft := st.FieldType(i)
var offset int64
for f := 0; f < i; f++ {
offset += st.FieldType(f).Size()
}
if n.Class() == PAUTO && !n.Addrtaken() {
// Note: the _ field may appear several times. But
// have no fear, identically-named but distinct Autos are
// ok, albeit maybe confusing for a debugger.
x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos)
return ssa.LocalSlot{N: x, Type: ft, Off: 0}
return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
}
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
}
......@@ -4984,8 +5014,7 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
}
et := at.ElemType()
if n.Class() == PAUTO && !n.Addrtaken() {
x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos)
return ssa.LocalSlot{N: x, Type: et, Off: 0}
return e.splitSlot(&name, "[0]", 0, et)
}
return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
}
......@@ -4994,16 +5023,14 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
return itabsym(it, offset)
}
// namedAuto returns a new AUTO variable with the given name and type.
// These are exposed to the debugger.
func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode {
t := typ
s := &types.Sym{Name: name, Pkg: localpkg}
// splitSlot returns a slot representing the data of parent starting at offset.
func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
n := new(Node)
n.Name = new(Name)
n.Op = ONAME
n.Pos = pos
n.Pos = parent.N.(*Node).Pos
n.Orig = n
s.Def = asTypesNode(n)
......@@ -5016,7 +5043,7 @@ func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode
n.Name.Curfn = e.curfn
e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
dowidth(t)
return n
return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
}
func (e *ssafn) CanSSA(t *types.Type) bool {
......
......@@ -7,6 +7,7 @@
package gc
import (
"cmd/compile/internal/ssa"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types"
"cmd/internal/obj"
......@@ -369,6 +370,7 @@ type Func struct {
Closgen int
Outerfunc *Node // outer function (for closure)
FieldTrack map[*types.Sym]struct{}
DebugInfo *ssa.FuncDebug
Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC
......
......@@ -14,6 +14,11 @@ type Cache struct {
blocks [200]Block
locs [2000]Location
// Storage for DWARF variable locations. Lazily allocated
// since location lists are off by default.
varLocs []VarLoc
curVarLoc int
// Reusable stackAllocState.
// See stackalloc.go's {new,put}StackAllocState.
stackAllocState *stackAllocState
......@@ -38,4 +43,21 @@ func (c *Cache) Reset() {
for i := range xl {
xl[i] = nil
}
xvl := c.varLocs[:c.curVarLoc]
for i := range xvl {
xvl[i] = VarLoc{}
}
c.curVarLoc = 0
}
func (c *Cache) NewVarLoc() *VarLoc {
if c.varLocs == nil {
c.varLocs = make([]VarLoc, 4000)
}
if c.curVarLoc == len(c.varLocs) {
return &VarLoc{}
}
vl := &c.varLocs[c.curVarLoc]
c.curVarLoc++
return vl
}
This diff is collapsed.
......@@ -98,6 +98,7 @@ func decomposeBuiltIn(f *Func) {
delete(f.NamedValues, name)
case t.IsFloat():
// floats are never decomposed, even ones bigger than RegSize
newNames = append(newNames, name)
case t.Size() > f.Config.RegSize:
f.Fatalf("undecomposed named type %v %v", name, t)
default:
......
......@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
return &DummyAuto{t: t, s: "aDummyAuto"}
}
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.Int, s.Off + 8}
return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8}
}
func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.BytePtr, s.Off + 8}
return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off + 8}
}
func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off},
LocalSlot{s.N, dummyTypes.Int, s.Off + 8},
LocalSlot{s.N, dummyTypes.Int, s.Off + 16}
return LocalSlot{N: s.N, Type: s.Type.ElemType().PtrTo(), Off: s.Off},
LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8},
LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 16}
}
func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.Size() == 16 {
return LocalSlot{s.N, dummyTypes.Float64, s.Off}, LocalSlot{s.N, dummyTypes.Float64, s.Off + 8}
return LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off + 8}
}
return LocalSlot{s.N, dummyTypes.Float32, s.Off}, LocalSlot{s.N, dummyTypes.Float32, s.Off + 4}
return LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off + 4}
}
func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.IsSigned() {
return LocalSlot{s.N, dummyTypes.Int32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
return LocalSlot{N: s.N, Type: dummyTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
}
return LocalSlot{s.N, dummyTypes.UInt32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
return LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
}
func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)}
}
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{s.N, s.Type.ElemType(), s.Off}
return LocalSlot{N: s.N, Type: s.Type.ElemType(), Off: s.Off}
}
func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0"
......
......@@ -417,6 +417,7 @@ var genericOps = []opData{
{name: "VarKill", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
{name: "VarLive", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
{name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem
{name: "RegKill"}, // regalloc has determined that the value in this register is dead
// Ops for breaking 64-bit operations on 32-bit architectures
{name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo
......
......@@ -11,6 +11,7 @@ import (
"html"
"io"
"os"
"strings"
)
type HTMLWriter struct {
......@@ -362,6 +363,18 @@ func (v *Value) LongHTML() string {
if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + html.EscapeString(r[v.ID].Name())
}
var names []string
for name, values := range v.Block.Func.NamedValues {
for _, value := range values {
if value == v {
names = append(names, name.Name())
break // drop duplicates.
}
}
}
if len(names) != 0 {
s += " (" + strings.Join(names, ", ") + ")"
}
s += "</span>"
return s
}
......
......@@ -26,12 +26,38 @@ func (r *Register) Name() string {
return r.name
}
// A LocalSlot is a location in the stack frame.
// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node.
// ObjNum returns the register number from cmd/internal/obj/$ARCH that
// corresponds to this register.
func (r *Register) ObjNum() int16 {
return r.objNum
}
// A LocalSlot is a location in the stack frame, which identifies and stores
// part or all of a PPARAM, PPARAMOUT, or PAUTO ONAME node.
// It can represent a whole variable, part of a larger stack slot, or part of a
// variable that has been decomposed into multiple stack slots.
// As an example, a string could have the following configurations:
//
// stack layout LocalSlots
//
// Optimizations are disabled. s is on the stack and represented in its entirety.
// [ ------- s string ---- ] { N: s, Type: string, Off: 0 }
//
// s was not decomposed, but the SSA operates on its parts individually, so
// there is a LocalSlot for each of its fields that points into the single stack slot.
// [ ------- s string ---- ] { N: s, Type: *uint8, Off: 0 }, {N: s, Type: int, Off: 8}
//
// s was decomposed. Each of its fields is in its own stack slot and has its own LocalSLot.
// [ ptr *uint8 ] [ len int] { N: ptr, Type: *uint8, Off: 0, SplitOf: parent, SplitOffset: 0},
// { N: len, Type: int, Off: 0, SplitOf: parent, SplitOffset: 8}
// parent = &{N: s, Type: string}
type LocalSlot struct {
N GCNode // an ONAME *gc.Node representing a variable on the stack
N GCNode // an ONAME *gc.Node representing a stack location.
Type *types.Type // type of slot
Off int64 // offset of slot in N
SplitOf *LocalSlot // slot is a decomposition of SplitOf
SplitOffset int64 // .. at this offset.
}
func (s LocalSlot) Name() string {
......
......@@ -1897,6 +1897,7 @@ const (
OpVarKill
OpVarLive
OpKeepAlive
OpRegKill
OpInt64Make
OpInt64Hi
OpInt64Lo
......@@ -22497,6 +22498,11 @@ var opcodeTable = [...]opInfo{
argLen: 2,
generic: true,
},
{
name: "RegKill",
argLen: 0,
generic: true,
},
{
name: "Int64Make",
argLen: 2,
......
......@@ -242,6 +242,9 @@ type regAllocState struct {
// current state of each (preregalloc) Value
values []valState
// names associated with each Value
valueNames [][]LocalSlot
// ID of SP, SB values
sp, sb ID
......@@ -300,6 +303,13 @@ type startReg struct {
// freeReg frees up register r. Any current user of r is kicked out.
func (s *regAllocState) freeReg(r register) {
s.freeOrResetReg(r, false)
}
// freeOrResetReg frees up register r. Any current user of r is kicked out.
// resetting indicates that the operation is only for bookkeeping,
// e.g. when clearing out state upon entry to a new block.
func (s *regAllocState) freeOrResetReg(r register, resetting bool) {
v := s.regs[r].v
if v == nil {
s.f.Fatalf("tried to free an already free register %d\n", r)
......@@ -309,6 +319,16 @@ func (s *regAllocState) freeReg(r register) {
if s.f.pass.debug > regDebug {
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
}
if !resetting && s.f.Config.ctxt.Flag_locationlists && len(s.valueNames[v.ID]) != 0 {
kill := s.curBlock.NewValue0(src.NoXPos, OpRegKill, types.TypeVoid)
for int(kill.ID) >= len(s.orig) {
s.orig = append(s.orig, nil)
}
for _, name := range s.valueNames[v.ID] {
s.f.NamedValues[name] = append(s.f.NamedValues[name], kill)
}
s.f.setHome(kill, &s.registers[r])
}
s.regs[r] = regState{}
s.values[v.ID].regs &^= regMask(1) << r
s.used &^= regMask(1) << r
......@@ -599,6 +619,17 @@ func (s *regAllocState) init(f *Func) {
s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues())
s.copies = make(map[*Value]bool)
if s.f.Config.ctxt.Flag_locationlists {
s.valueNames = make([][]LocalSlot, f.NumValues())
for slot, values := range f.NamedValues {
if isSynthetic(&slot) {
continue
}
for _, value := range values {
s.valueNames[value.ID] = append(s.valueNames[value.ID], slot)
}
}
}
for _, b := range f.Blocks {
for _, v := range b.Values {
if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() {
......@@ -692,7 +723,9 @@ func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
// Sets the state of the registers to that encoded in regs.
func (s *regAllocState) setState(regs []endReg) {
s.freeRegs(s.used)
for s.used != 0 {
s.freeOrResetReg(pickReg(s.used), true)
}
for _, x := range regs {
s.assignReg(x.r, x.v, x.c)
}
......@@ -735,6 +768,9 @@ func (s *regAllocState) regalloc(f *Func) {
}
for _, b := range f.Blocks {
if s.f.pass.debug > regDebug {
fmt.Printf("Begin processing block %v\n", b)
}
s.curBlock = b
// Initialize regValLiveSet and uses fields for this block.
......@@ -830,9 +866,6 @@ func (s *regAllocState) regalloc(f *Func) {
// This is the complicated case. We have more than one predecessor,
// which means we may have Phi ops.
// Copy phi ops into new schedule.
b.Values = append(b.Values, phis...)
// Start with the final register state of the primary predecessor
idx := s.primary[b.ID]
if idx < 0 {
......@@ -910,6 +943,9 @@ func (s *regAllocState) regalloc(f *Func) {
}
}
// Copy phi ops into new schedule.
b.Values = append(b.Values, phis...)
// Third pass - pick registers for phis whose inputs
// were not in a register.
for i, v := range phis {
......@@ -1005,7 +1041,7 @@ func (s *regAllocState) regalloc(f *Func) {
pidx := e.i
for _, v := range succ.Values {
if v.Op != OpPhi {
break
continue
}
if !s.values[v.ID].needReg {
continue
......@@ -1565,6 +1601,9 @@ func (s *regAllocState) placeSpills() {
for _, b := range f.Blocks {
var m regMask
for _, v := range b.Values {
if v.Op == OpRegKill {
continue
}
if v.Op != OpPhi {
break
}
......@@ -1675,7 +1714,7 @@ func (s *regAllocState) placeSpills() {
for _, b := range f.Blocks {
nphi := 0
for _, v := range b.Values {
if v.Op != OpPhi {
if v.Op != OpRegKill && v.Op != OpPhi {
break
}
nphi++
......@@ -1800,6 +1839,9 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
if v.Op == OpRegKill {
continue
}
if v.Op != OpPhi {
break
}
......@@ -1878,6 +1920,7 @@ func (e *edgeState) process() {
if e.s.f.pass.debug > regDebug {
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
}
e.erase(r)
if _, isReg := loc.(*Register); isReg {
c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
} else {
......@@ -1943,6 +1986,18 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
}
}
_, dstReg := loc.(*Register)
// Pre-clobber destination. This avoids the
// following situation:
// - v is currently held in R0 and stacktmp0.
// - We want to copy stacktmp1 to stacktmp0.
// - We choose R0 as the temporary register.
// During the copy, both R0 and stacktmp0 are
// clobbered, losing both copies of v. Oops!
// Erasing the destination early means R0 will not
// be chosen as the temp register, as it will then
// be the last copy of v.
e.erase(loc)
var x *Value
if c == nil {
if !e.s.values[vid].rematerializeable {
......@@ -1953,8 +2008,8 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
} else {
// Rematerialize into stack slot. Need a free
// register to accomplish this.
e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type)
e.erase(r)
x = v.copyIntoNoXPos(e.p)
e.set(r, vid, x, false, pos)
// Make sure we spill with the size of the slot, not the
......@@ -1976,20 +2031,8 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
} else {
// mem->mem. Use temp register.
// Pre-clobber destination. This avoids the
// following situation:
// - v is currently held in R0 and stacktmp0.
// - We want to copy stacktmp1 to stacktmp0.
// - We choose R0 as the temporary register.
// During the copy, both R0 and stacktmp0 are
// clobbered, losing both copies of v. Oops!
// Erasing the destination early means R0 will not
// be chosen as the temp register, as it will then
// be the last copy of v.
e.erase(loc)
r := e.findRegFor(c.Type)
e.erase(r)
t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
e.set(r, vid, t, false, pos)
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
......@@ -2008,7 +2051,6 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
// set changes the contents of location loc to hold the given value and its cached representative.
func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
e.s.f.setHome(c, loc)
e.erase(loc)
e.contents[loc] = contentRecord{vid, c, final, pos}
a := e.cache[vid]
if len(a) == 0 {
......@@ -2059,6 +2101,16 @@ func (e *edgeState) erase(loc Location) {
fmt.Printf("v%d no longer available in %s:%s\n", vid, loc.Name(), c)
}
a[i], a = a[len(a)-1], a[:len(a)-1]
if e.s.f.Config.ctxt.Flag_locationlists {
if _, isReg := loc.(*Register); isReg && int(c.ID) < len(e.s.valueNames) && len(e.s.valueNames[c.ID]) != 0 {
kill := e.p.NewValue0(src.NoXPos, OpRegKill, types.TypeVoid)
e.s.f.setHome(kill, loc)
for _, name := range e.s.valueNames[c.ID] {
e.s.f.NamedValues[name] = append(e.s.f.NamedValues[name], kill)
}
}
}
break
}
}
......@@ -2118,8 +2170,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
// Allocate a temp location to spill a register to.
// The type of the slot is immaterial - it will not be live across
// any safepoint. Just use a type big enough to hold any register.
t := LocalSlot{e.s.f.fe.Auto(c.Pos, types.Int64), types.Int64, 0}
// TODO: reuse these slots.
t := LocalSlot{N: e.s.f.fe.Auto(c.Pos, types.Int64), Type: types.Int64}
// TODO: reuse these slots. They'll need to be erased first.
e.set(t, vid, x, false, c.Pos)
if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
......
......@@ -24,6 +24,7 @@ func TestSizeof(t *testing.T) {
}{
{Value{}, 68, 112},
{Block{}, 152, 288},
{LocalSlot{}, 32, 48},
{valState{}, 28, 40},
}
......
......@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() {
if v.Op != OpArg {
continue
}
loc := LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt}
loc := LocalSlot{N: v.Aux.(GCNode), Type: v.Type, Off: v.AuxInt}
if f.pass.debug > stackDebug {
fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
}
......
......@@ -10,6 +10,7 @@ import (
"cmd/internal/src"
"fmt"
"math"
"strings"
)
// A Value represents a value in the SSA representation of the program.
......@@ -98,7 +99,7 @@ func (v *Value) AuxValAndOff() ValAndOff {
return ValAndOff(v.AuxInt)
}
// long form print. v# = opcode <type> [aux] args [: reg]
// long form print. v# = opcode <type> [aux] args [: reg] (names)
func (v *Value) LongString() string {
s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
s += " <" + v.Type.String() + ">"
......@@ -110,6 +111,18 @@ func (v *Value) LongString() string {
if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + r[v.ID].Name()
}
var names []string
for name, values := range v.Block.Func.NamedValues {
for _, value := range values {
if value == v {
names = append(names, name.Name())
break // drop duplicates.
}
}
}
if len(names) != 0 {
s += " (" + strings.Join(names, ", ") + ")"
}
return s
}
......
......@@ -15,6 +15,9 @@ import (
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info."
// RangePrefix is the prefix for all the symbols containing DWARF location lists.
const LocPrefix = "go.loc."
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
const RangePrefix = "go.range."
......@@ -23,13 +26,31 @@ type Sym interface {
Len() int64
}
// A Location represents a variable's location at a particular PC range.
// It becomes a location list entry in the DWARF.
type Location struct {
StartPC, EndPC int64
Pieces []Piece
}
// A Piece represents the location of a particular part of a variable.
// It becomes part of a location list entry (a DW_OP_piece) in the DWARF.
type Piece struct {
Length int64
StackOffset int32
RegNum int16
Missing bool
OnStack bool // if true, RegNum is unset.
}
// A Var represents a local variable or a function parameter.
type Var struct {
Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
Offset int32
Scope int32
Type Sym
Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
StackOffset int32
LocationList []Location
Scope int32
Type Sym
}
// A Scope represents a lexical scope. All variables declared within a
......@@ -205,7 +226,7 @@ const (
)
// Index into the abbrevs table below.
// Keep in sync with ispubname() and ispubtype() below.
// Keep in sync with ispubname() and ispubtype() in ld/dwarf.go.
// ispubtype considers >= NULLTYPE public
const (
DW_ABRV_NULL = iota
......@@ -213,7 +234,9 @@ const (
DW_ABRV_FUNCTION
DW_ABRV_VARIABLE
DW_ABRV_AUTO
DW_ABRV_AUTO_LOCLIST
DW_ABRV_PARAM
DW_ABRV_PARAM_LOCLIST
DW_ABRV_LEXICAL_BLOCK_RANGES
DW_ABRV_LEXICAL_BLOCK_SIMPLE
DW_ABRV_STRUCTFIELD
......@@ -297,6 +320,17 @@ var abbrevs = [DW_NABRV]dwAbbrev{
},
},
/* AUTO_LOCLIST */
{
DW_TAG_variable,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_sec_offset},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* PARAM */
{
DW_TAG_formal_parameter,
......@@ -307,6 +341,18 @@ var abbrevs = [DW_NABRV]dwAbbrev{
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* PARAM_LOCLIST */
{
DW_TAG_formal_parameter,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_sec_offset},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* LEXICAL_BLOCK_RANGES */
{
DW_TAG_lexical_block,
......@@ -684,31 +730,30 @@ func HasChildren(die *DWDie) bool {
// PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars.
func PutFunc(ctxt Context, s, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
Uleb128put(ctxt, s, DW_ABRV_FUNCTION)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
Uleb128put(ctxt, info, DW_ABRV_FUNCTION)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
var ev int64
if external {
ev = 1
}
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
if len(scopes) > 0 {
var encbuf [20]byte
if putscope(ctxt, s, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
if putscope(ctxt, info, loc, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
return errors.New("multiple toplevel scopes")
}
}
Uleb128put(ctxt, s, 0)
Uleb128put(ctxt, info, 0)
return nil
}
func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
for _, v := range scopes[curscope].Vars {
putvar(ctxt, s, v, encbuf)
putvar(ctxt, info, loc, v, startPC, encbuf)
}
this := curscope
curscope++
......@@ -719,12 +764,12 @@ func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes [
}
if len(scope.Ranges) == 1 {
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
} else {
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
ctxt.AddAddress(ranges, nil, -1)
ctxt.AddAddress(ranges, startPC, 0)
......@@ -736,32 +781,72 @@ func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes [
ctxt.AddAddress(ranges, nil, 0)
}
curscope = putscope(ctxt, s, ranges, startPC, curscope, scopes, encbuf)
curscope = putscope(ctxt, info, loc, ranges, startPC, curscope, scopes, encbuf)
Uleb128put(ctxt, s, 0)
Uleb128put(ctxt, info, 0)
}
return curscope
}
func putvar(ctxt Context, s Sym, v *Var, encbuf []byte) {
func putvar(ctxt Context, info, loc Sym, v *Var, startPC Sym, encbuf []byte) {
n := v.Name
Uleb128put(ctxt, s, int64(v.Abbrev))
putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.Offset != 0 {
loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.Offset))
loc = append(loc, DW_OP_plus)
Uleb128put(ctxt, info, int64(v.Abbrev))
putattr(ctxt, info, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
if v.Abbrev == DW_ABRV_AUTO_LOCLIST || v.Abbrev == DW_ABRV_PARAM_LOCLIST {
putattr(ctxt, info, v.Abbrev, DW_FORM_sec_offset, DW_CLS_PTR, int64(loc.Len()), loc)
addLocList(ctxt, loc, startPC, v, encbuf)
} else {
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.StackOffset != 0 {
loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.StackOffset))
loc = append(loc, DW_OP_plus)
}
putattr(ctxt, info, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
}
putattr(ctxt, info, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
}
func addLocList(ctxt Context, listSym, startPC Sym, v *Var, encbuf []byte) {
// Base address entry: max ptr followed by the base address.
ctxt.AddInt(listSym, ctxt.PtrSize(), ^0)
ctxt.AddAddress(listSym, startPC, 0)
for _, entry := range v.LocationList {
ctxt.AddInt(listSym, ctxt.PtrSize(), entry.StartPC)
ctxt.AddInt(listSym, ctxt.PtrSize(), entry.EndPC)
locBuf := encbuf[:0]
for _, piece := range entry.Pieces {
if !piece.Missing {
if piece.OnStack {
locBuf = append(locBuf, DW_OP_fbreg)
locBuf = AppendSleb128(locBuf, int64(piece.StackOffset))
} else {
if piece.RegNum < 32 {
locBuf = append(locBuf, DW_OP_reg0+byte(piece.RegNum))
} else {
locBuf = append(locBuf, DW_OP_regx)
locBuf = AppendUleb128(locBuf, uint64(piece.RegNum))
}
}
}
if len(entry.Pieces) > 1 {
locBuf = append(locBuf, DW_OP_piece)
locBuf = AppendUleb128(locBuf, uint64(piece.Length))
}
}
ctxt.AddInt(listSym, 2, int64(len(locBuf)))
ctxt.AddBytes(listSym, locBuf)
}
putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
// End list
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
}
// VarsByOffset attaches the methods of sort.Interface to []*Var,
// sorting in increasing Offset.
// sorting in increasing StackOffset.
type VarsByOffset []*Var
func (s VarsByOffset) Len() int { return len(s) }
func (s VarsByOffset) Less(i, j int) bool { return s[i].Offset < s[j].Offset }
func (s VarsByOffset) Less(i, j int) bool { return s[i].StackOffset < s[j].StackOffset }
func (s VarsByOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
......@@ -330,7 +330,8 @@ type FuncInfo struct {
Autom []*Auto
Pcln Pcln
dwarfSym *LSym
dwarfInfoSym *LSym
dwarfLocSym *LSym
dwarfRangesSym *LSym
GCArgs LSym
......@@ -476,25 +477,26 @@ type Pcdata struct {
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
Headtype objabi.HeadType
Arch *LinkArch
Debugasm bool
Debugvlog bool
Debugpcln string
Flag_shared bool
Flag_dynlink bool
Flag_optimize bool
Bso *bufio.Writer
Pathname string
hashmu sync.Mutex // protects hash
hash map[string]*LSym // name -> sym mapping
statichash map[string]*LSym // name -> sym mapping for static syms
PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go
Imports []string
DiagFunc func(string, ...interface{})
DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
Errors int
Headtype objabi.HeadType
Arch *LinkArch
Debugasm bool
Debugvlog bool
Debugpcln string
Flag_shared bool
Flag_dynlink bool
Flag_optimize bool
Flag_locationlists bool
Bso *bufio.Writer
Pathname string
hashmu sync.Mutex // protects hash
hash map[string]*LSym // name -> sym mapping
statichash map[string]*LSym // name -> sym mapping for static syms
PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go
Imports []string
DiagFunc func(string, ...interface{})
DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
Errors int
Framepointer_enabled bool
......@@ -533,9 +535,10 @@ func (ctxt *Link) FixedFrameSize() int64 {
// LinkArch is the definition of a single architecture.
type LinkArch struct {
*sys.Arch
Init func(*Link)
Preprocess func(*Link, *LSym, ProgAlloc)
Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
Init func(*Link)
Preprocess func(*Link, *LSym, ProgAlloc)
Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
DWARFRegisters map[int16]int16
}
......@@ -465,15 +465,18 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
}
// dwarfSym returns the DWARF symbols for TEXT symbol.
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfRangesSym *LSym) {
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym *LSym) {
if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
if s.Func.dwarfSym == nil {
s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
if s.Func.dwarfInfoSym == nil {
s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
if ctxt.Flag_locationlists {
s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
}
s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
}
return s.Func.dwarfSym, s.Func.dwarfRangesSym
return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym
}
func (s *LSym) Len() int64 {
......@@ -483,15 +486,15 @@ func (s *LSym) Len() int64 {
// populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s.
// The DWARFs symbol must already have been initialized in InitTextSym.
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
dsym, drsym := ctxt.dwarfSym(s)
if dsym.Size != 0 {
info, loc, ranges := ctxt.dwarfSym(s)
if info.Size != 0 {
ctxt.Diag("makeFuncDebugEntry double process %v", s)
}
var scopes []dwarf.Scope
if ctxt.DebugInfo != nil {
scopes = ctxt.DebugInfo(s, curfn)
}
err := dwarf.PutFunc(dwCtxt{ctxt}, dsym, drsym, s.Name, !s.Static(), s, s.Size, scopes)
err := dwarf.PutFunc(dwCtxt{ctxt}, info, loc, ranges, s.Name, !s.Static(), s, s.Size, scopes)
if err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
}
......
......@@ -136,13 +136,17 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s.
dsym, drsym := ctxt.dwarfSym(s)
dsym.Type = objabi.SDWARFINFO
dsym.Set(AttrDuplicateOK, s.DuplicateOK())
drsym.Type = objabi.SDWARFRANGE
drsym.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, dsym)
ctxt.Data = append(ctxt.Data, drsym)
info, loc, ranges := ctxt.dwarfSym(s)
info.Type = objabi.SDWARFINFO
info.Set(AttrDuplicateOK, s.DuplicateOK())
if loc != nil {
loc.Type = objabi.SDWARFLOC
loc.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, loc)
}
ranges.Type = objabi.SDWARFRANGE
ranges.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, info, ranges)
// Set up the function's gcargs and gclocals.
// They will be filled in later if needed.
......
......@@ -1006,3 +1006,120 @@ const (
T_64 = 1 << 6
T_GOTYPE = 1 << 7
)
// https://www.uclibc.org/docs/psABI-x86_64.pdf, figure 3.36
var AMD64DWARFRegisters = map[int16]int16{
REG_AX: 0,
REG_DX: 1,
REG_CX: 2,
REG_BX: 3,
REG_SI: 4,
REG_DI: 5,
REG_BP: 6,
REG_SP: 7,
REG_R8: 8,
REG_R9: 9,
REG_R10: 10,
REG_R11: 11,
REG_R12: 12,
REG_R13: 13,
REG_R14: 14,
REG_R15: 15,
// 16 is "Return Address RA", whatever that is.
// XMM registers. %xmmN => XN.
REG_X0: 17,
REG_X1: 18,
REG_X2: 19,
REG_X3: 20,
REG_X4: 21,
REG_X5: 22,
REG_X6: 23,
REG_X7: 24,
REG_X8: 25,
REG_X9: 26,
REG_X10: 27,
REG_X11: 28,
REG_X12: 29,
REG_X13: 30,
REG_X14: 31,
REG_X15: 32,
// ST registers. %stN => FN.
REG_F0: 33,
REG_F1: 34,
REG_F2: 35,
REG_F3: 36,
REG_F4: 37,
REG_F5: 38,
REG_F6: 39,
REG_F7: 40,
// MMX registers. %mmN => MN.
REG_M0: 41,
REG_M1: 42,
REG_M2: 43,
REG_M3: 44,
REG_M4: 45,
REG_M5: 46,
REG_M6: 47,
REG_M7: 48,
// 48 is flags, which doesn't have a name.
REG_ES: 50,
REG_CS: 51,
REG_SS: 52,
REG_DS: 53,
REG_FS: 54,
REG_GS: 55,
// 58 and 59 are {fs,gs}base, which don't have names.
REG_TR: 62,
REG_LDTR: 63,
// 64-66 are mxcsr, fcw, fsw, which don't have names.
}
// https://www.uclibc.org/docs/psABI-i386.pdf, table 2.14
var X86DWARFRegisters = map[int16]int16{
REG_AX: 0,
REG_CX: 1,
REG_DX: 2,
REG_BX: 3,
REG_SP: 4,
REG_BP: 5,
REG_SI: 6,
REG_DI: 7,
// 8 is "Return Address RA", whatever that is.
// 9 is flags, which doesn't have a name.
// ST registers. %stN => FN.
REG_F0: 11,
REG_F1: 12,
REG_F2: 13,
REG_F3: 14,
REG_F4: 15,
REG_F5: 16,
REG_F6: 17,
REG_F7: 18,
// XMM registers. %xmmN => XN.
REG_X0: 21,
REG_X1: 22,
REG_X2: 23,
REG_X3: 24,
REG_X4: 25,
REG_X5: 26,
REG_X6: 27,
REG_X7: 28,
// MMX registers. %mmN => MN.
REG_M0: 29,
REG_M1: 30,
REG_M2: 31,
REG_M3: 32,
REG_M4: 33,
REG_M5: 34,
REG_M6: 35,
REG_M7: 36,
// 39 is mxcsr, which doesn't have a name.
REG_ES: 40,
REG_CS: 41,
REG_SS: 42,
REG_DS: 43,
REG_FS: 44,
REG_GS: 45,
REG_TR: 48,
REG_LDTR: 49,
}
......@@ -1231,28 +1231,31 @@ var unaryDst = map[obj.As]bool{
}
var Linkamd64 = obj.LinkArch{
Arch: sys.ArchAMD64,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
Arch: sys.ArchAMD64,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
}
var Linkamd64p32 = obj.LinkArch{
Arch: sys.ArchAMD64P32,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
Arch: sys.ArchAMD64P32,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
}
var Link386 = obj.LinkArch{
Arch: sys.Arch386,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
Arch: sys.Arch386,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
}
......@@ -57,4 +57,5 @@ const (
// Debugging data
SDWARFINFO
SDWARFRANGE
SDWARFLOC
)
......@@ -4,9 +4,9 @@ package objabi
import "fmt"
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGE"
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOC"
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72}
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
......
......@@ -592,15 +592,7 @@ func relocsym(ctxt *Link, s *Symbol) {
}
case objabi.R_DWARFREF:
var sectName string
var vaddr int64
switch {
case r.Sym.Sect != nil:
sectName = r.Sym.Sect.Name
vaddr = int64(r.Sym.Sect.Vaddr)
case r.Sym.Type == SDWARFRANGE:
sectName = ".debug_ranges"
default:
if r.Sym.Sect == nil {
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
}
......@@ -615,8 +607,8 @@ func relocsym(ctxt *Link, s *Symbol) {
r.Type = objabi.R_ADDR
}
r.Xsym = ctxt.Syms.ROLookup(sectName, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - vaddr
r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
o = r.Xadd
rs = r.Xsym
......@@ -625,7 +617,7 @@ func relocsym(ctxt *Link, s *Symbol) {
}
break
}
o = Symaddr(r.Sym) + r.Add - vaddr
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
case objabi.R_WEAKADDROFF:
if !r.Sym.Attr.Reachable() {
......@@ -1843,9 +1835,9 @@ func (ctxt *Link) dodata() {
dwarfgeneratedebugsyms(ctxt)
var s *Symbol
var i int
for i, s = range dwarfp {
for ; i < len(dwarfp); i++ {
s := dwarfp[i]
if s.Type != SDWARFSECT {
break
}
......@@ -1862,13 +1854,26 @@ func (ctxt *Link) dodata() {
}
checkdatsize(ctxt, datsize, SDWARFSECT)
if i < len(dwarfp) {
sect = addsection(&Segdwarf, ".debug_info", 04)
for i < len(dwarfp) {
curType := dwarfp[i].Type
var sect *Section
switch curType {
case SDWARFINFO:
sect = addsection(&Segdwarf, ".debug_info", 04)
case SDWARFRANGE:
sect = addsection(&Segdwarf, ".debug_ranges", 04)
case SDWARFLOC:
sect = addsection(&Segdwarf, ".debug_loc", 04)
default:
Errorf(dwarfp[i], "unknown DWARF section %v", curType)
}
sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
for _, s := range dwarfp[i:] {
if s.Type != SDWARFINFO {
for ; i < len(dwarfp); i++ {
s := dwarfp[i]
if s.Type != curType {
break
}
s.Sect = sect
......@@ -1878,7 +1883,7 @@ func (ctxt *Link) dodata() {
datsize += s.Size
}
sect.Length = uint64(datsize) - sect.Vaddr
checkdatsize(ctxt, datsize, SDWARFINFO)
checkdatsize(ctxt, datsize, curType)
}
/* number the sections */
......
......@@ -67,26 +67,15 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
r.Add = ofs
}
/*
* Offsets and sizes of the debug_* sections in the cout file.
*/
var abbrevsym *Symbol
var arangessec *Symbol
var framesec *Symbol
var infosec *Symbol
var linesec *Symbol
var rangesec *Symbol
var gdbscript string
var dwarfp []*Symbol
func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol {
func writeabbrev(ctxt *Link) *Symbol {
s := ctxt.Syms.Lookup(".debug_abbrev", 0)
s.Type = SDWARFSECT
abbrevsym = s
Addbytes(s, dwarf.GetAbbrev())
return append(syms, s)
return s
}
/*
......@@ -993,13 +982,10 @@ func getCompilationDir() string {
func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
var dwarfctxt dwarf.Context = dwctxt{ctxt}
if linesec == nil {
linesec = ctxt.Syms.Lookup(".debug_line", 0)
}
linesec.Type = SDWARFSECT
linesec.R = linesec.R[:0]
ls := ctxt.Syms.Lookup(".debug_line", 0)
ls.Type = SDWARFSECT
ls.R = ls.R[:0]
ls := linesec
syms = append(syms, ls)
var funcs []*Symbol
......@@ -1019,7 +1005,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, linesec)
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, ls)
newattr(dwinfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, s.Value, s)
// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
compDir := getCompilationDir()
......@@ -1178,12 +1164,9 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
var dwarfctxt dwarf.Context = dwctxt{ctxt}
if framesec == nil {
framesec = ctxt.Syms.Lookup(".debug_frame", 0)
}
framesec.Type = SDWARFSECT
framesec.R = framesec.R[:0]
fs := framesec
fs := ctxt.Syms.Lookup(".debug_frame", 0)
fs.Type = SDWARFSECT
fs.R = fs.R[:0]
syms = append(syms, fs)
// Emit the CIE, Section 6.4.1
......@@ -1280,7 +1263,7 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
// ptrsize: address range
Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
if Linkmode == LinkExternal {
adddwarfref(ctxt, fs, framesec, 4)
adddwarfref(ctxt, fs, fs, 4)
} else {
Adduint32(ctxt, fs, 0) // CIE offset
}
......@@ -1292,27 +1275,24 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
}
func writeranges(ctxt *Link, syms []*Symbol) []*Symbol {
if rangesec == nil {
rangesec = ctxt.Syms.Lookup(".debug_ranges", 0)
}
rangesec.Type = SDWARFSECT
rangesec.Attr |= AttrReachable
rangesec.R = rangesec.R[:0]
empty := true
for _, s := range ctxt.Textp {
rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
rangeSym.Attr |= AttrReachable
rangeSym.Type = SDWARFRANGE
rangeSym.Value = rangesec.Size
rangesec.P = append(rangesec.P, rangeSym.P...)
for _, r := range rangeSym.R {
r.Off += int32(rangesec.Size)
rangesec.R = append(rangesec.R, r)
if rangeSym.Size == 0 {
continue
}
rangesec.Size += rangeSym.Size
rangeSym.Attr |= AttrReachable | AttrNotInSymbolTable
rangeSym.Type = SDWARFRANGE
syms = append(syms, rangeSym)
empty = false
}
if rangesec.Size > 0 {
if !empty {
// PE does not like empty sections
rangesec := ctxt.Syms.Lookup(".debug_ranges", 0)
rangesec.Type = SDWARFRANGE
rangesec.Attr |= AttrReachable
rangesec.R = rangesec.R[:0]
syms = append(syms, rangesec)
}
return syms
......@@ -1325,18 +1305,14 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
if infosec == nil {
infosec = ctxt.Syms.Lookup(".debug_info", 0)
}
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol, abbrevsym *Symbol) []*Symbol {
infosec := ctxt.Syms.Lookup(".debug_info", 0)
infosec.R = infosec.R[:0]
infosec.Type = SDWARFINFO
infosec.Attr |= AttrReachable
syms = append(syms, infosec)
if arangessec == nil {
arangessec = ctxt.Syms.Lookup(".dwarfaranges", 0)
}
arangessec := ctxt.Syms.Lookup(".dwarfaranges", 0)
arangessec.R = arangessec.R[:0]
var dwarfctxt dwarf.Context = dwctxt{ctxt}
......@@ -1577,10 +1553,10 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
genasmsym(ctxt, defdwsymb)
syms := writeabbrev(ctxt, nil)
abbrev := writeabbrev(ctxt)
syms := []*Symbol{abbrev}
syms, funcs := writelines(ctxt, syms)
syms = writeframes(ctxt, syms)
syms = writeranges(ctxt, syms)
synthesizestringtypes(ctxt, dwtypes.Child)
synthesizeslicetypes(ctxt, dwtypes.Child)
......@@ -1596,16 +1572,42 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
// (but we need to generate dies before writepub)
infosyms := writeinfo(ctxt, nil, funcs)
infosyms := writeinfo(ctxt, nil, funcs, abbrev)
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
syms = writearanges(ctxt, syms)
syms = writegdbscript(ctxt, syms)
syms = append(syms, infosyms...)
syms = collectlocs(ctxt, syms, funcs)
syms = writeranges(ctxt, syms)
dwarfp = syms
}
func collectlocs(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
empty := true
for _, fn := range funcs {
for _, reloc := range fn.R {
if reloc.Type == objabi.R_DWARFREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
reloc.Sym.Attr |= AttrReachable | AttrNotInSymbolTable
syms = append(syms, reloc.Sym)
empty = false
// One location list entry per function, but many relocations to it. Don't duplicate.
break
}
}
}
// Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
if !empty {
locsym := ctxt.Syms.Lookup(".debug_loc", 0)
locsym.R = locsym.R[:0]
locsym.Type = SDWARFLOC
locsym.Attr |= AttrReachable
syms = append(syms, locsym)
}
return syms
}
/*
* Elf.
*/
......@@ -1618,6 +1620,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_aranges")
Addstring(shstrtab, ".debug_frame")
Addstring(shstrtab, ".debug_info")
Addstring(shstrtab, ".debug_loc")
Addstring(shstrtab, ".debug_line")
Addstring(shstrtab, ".debug_pubnames")
Addstring(shstrtab, ".debug_pubtypes")
......@@ -1625,6 +1628,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_ranges")
if Linkmode == LinkExternal {
Addstring(shstrtab, elfRelType+".debug_info")
Addstring(shstrtab, elfRelType+".debug_loc")
Addstring(shstrtab, elfRelType+".debug_aranges")
Addstring(shstrtab, elfRelType+".debug_line")
Addstring(shstrtab, elfRelType+".debug_frame")
......@@ -1651,6 +1655,10 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
sym = ctxt.Syms.Lookup(".debug_frame", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
sym = ctxt.Syms.Lookup(".debug_loc", 0)
if sym.Sect != nil {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
}
sym = ctxt.Syms.Lookup(".debug_ranges", 0)
if sym.Sect != nil {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
......
......@@ -1808,7 +1808,7 @@ func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
continue
}
if r.Xsym == nil {
Errorf(sym, "missing xsym in relocation")
Errorf(sym, "missing xsym in relocation %#v %#v", r.Sym.Name, sym)
continue
}
if r.Xsym.ElfsymForReloc() == 0 {
......@@ -2596,12 +2596,9 @@ elfobj:
elfshreloc(sect)
}
for _, s := range dwarfp {
if len(s.R) > 0 || s.Type == SDWARFINFO {
if len(s.R) > 0 || s.Type == SDWARFINFO || s.Type == SDWARFLOC {
elfshreloc(s.Sect)
}
if s.Type == SDWARFINFO {
break
}
}
// add a .note.GNU-stack section to mark the stack as non-executable
sh := elfshname(".note.GNU-stack")
......
......@@ -105,6 +105,7 @@ const (
SDWARFSECT
SDWARFINFO
SDWARFRANGE
SDWARFLOC
SSUB = SymKind(1 << 8)
SMASK = SymKind(SSUB - 1)
SHIDDEN = SymKind(1 << 9)
......@@ -124,6 +125,7 @@ var abiSymKindToSymKind = [...]SymKind{
STLSBSS,
SDWARFINFO,
SDWARFRANGE,
SDWARFLOC,
}
// readOnly are the symbol kinds that form read-only sections. In some
......
......@@ -4,9 +4,9 @@ package ld
import "fmt"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGE"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOC"
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419}
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419, 428}
func (i SymKind) String() string {
if i < 0 || i >= SymKind(len(_SymKind_index)-1) {
......
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