Commit 385cd668 authored by Gerrit Code Review's avatar Gerrit Code Review

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

parents 9aea0e89 6f6a9398
...@@ -571,9 +571,16 @@ var knownFormats = map[string]string{ ...@@ -571,9 +571,16 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/ssa.Block %s": "", "*cmd/compile/internal/ssa.Block %s": "",
"*cmd/compile/internal/ssa.Block %v": "", "*cmd/compile/internal/ssa.Block %v": "",
"*cmd/compile/internal/ssa.Func %s": "", "*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.SparseTreeNode %v": "",
"*cmd/compile/internal/ssa.Value %s": "", "*cmd/compile/internal/ssa.Value %s": "",
"*cmd/compile/internal/ssa.Value %v": "", "*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/ssa.sparseTreeMapEntry %v": "",
"*cmd/compile/internal/types.Field %p": "", "*cmd/compile/internal/types.Field %p": "",
"*cmd/compile/internal/types.Field %v": "", "*cmd/compile/internal/types.Field %v": "",
...@@ -592,6 +599,7 @@ var knownFormats = map[string]string{ ...@@ -592,6 +599,7 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Type %p": "", "*cmd/compile/internal/types.Type %p": "",
"*cmd/compile/internal/types.Type %s": "", "*cmd/compile/internal/types.Type %s": "",
"*cmd/compile/internal/types.Type %v": "", "*cmd/compile/internal/types.Type %v": "",
"*cmd/internal/dwarf.Location %#v": "",
"*cmd/internal/obj.Addr %v": "", "*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "", "*cmd/internal/obj.LSym %v": "",
"*cmd/internal/obj.Prog %s": "", "*cmd/internal/obj.Prog %s": "",
...@@ -600,17 +608,21 @@ var knownFormats = map[string]string{ ...@@ -600,17 +608,21 @@ var knownFormats = map[string]string{
"[16]byte %x": "", "[16]byte %x": "",
"[]*cmd/compile/internal/gc.Node %v": "", "[]*cmd/compile/internal/gc.Node %v": "",
"[]*cmd/compile/internal/gc.Sig %#v": "", "[]*cmd/compile/internal/gc.Sig %#v": "",
"[]*cmd/compile/internal/ssa.Block %+v": "",
"[]*cmd/compile/internal/ssa.Value %v": "", "[]*cmd/compile/internal/ssa.Value %v": "",
"[][]cmd/compile/internal/ssa.SlotID %v": "",
"[]byte %s": "", "[]byte %s": "",
"[]byte %x": "", "[]byte %x": "",
"[]cmd/compile/internal/ssa.Edge %v": "", "[]cmd/compile/internal/ssa.Edge %v": "",
"[]cmd/compile/internal/ssa.ID %v": "", "[]cmd/compile/internal/ssa.ID %v": "",
"[]cmd/compile/internal/ssa.VarLocList %v": "",
"[]string %v": "", "[]string %v": "",
"bool %v": "", "bool %v": "",
"byte %08b": "", "byte %08b": "",
"byte %c": "", "byte %c": "",
"cmd/compile/internal/arm.shift %d": "", "cmd/compile/internal/arm.shift %d": "",
"cmd/compile/internal/gc.Class %d": "", "cmd/compile/internal/gc.Class %d": "",
"cmd/compile/internal/gc.Class %v": "",
"cmd/compile/internal/gc.Ctype %d": "", "cmd/compile/internal/gc.Ctype %d": "",
"cmd/compile/internal/gc.Ctype %v": "", "cmd/compile/internal/gc.Ctype %v": "",
"cmd/compile/internal/gc.Level %d": "", "cmd/compile/internal/gc.Level %d": "",
...@@ -630,11 +642,13 @@ var knownFormats = map[string]string{ ...@@ -630,11 +642,13 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.Edge %v": "", "cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "", "cmd/compile/internal/ssa.GCNode %v": "",
"cmd/compile/internal/ssa.ID %d": "", "cmd/compile/internal/ssa.ID %d": "",
"cmd/compile/internal/ssa.ID %v": "",
"cmd/compile/internal/ssa.LocalSlot %v": "", "cmd/compile/internal/ssa.LocalSlot %v": "",
"cmd/compile/internal/ssa.Location %v": "", "cmd/compile/internal/ssa.Location %v": "",
"cmd/compile/internal/ssa.Op %s": "", "cmd/compile/internal/ssa.Op %s": "",
"cmd/compile/internal/ssa.Op %v": "", "cmd/compile/internal/ssa.Op %v": "",
"cmd/compile/internal/ssa.ValAndOff %s": "", "cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.VarLocList %v": "",
"cmd/compile/internal/ssa.rbrank %d": "", "cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "", "cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "", "cmd/compile/internal/ssa.register %d": "",
...@@ -648,6 +662,7 @@ var knownFormats = map[string]string{ ...@@ -648,6 +662,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/types.EType %d": "", "cmd/compile/internal/types.EType %d": "",
"cmd/compile/internal/types.EType %s": "", "cmd/compile/internal/types.EType %s": "",
"cmd/compile/internal/types.EType %v": "", "cmd/compile/internal/types.EType %v": "",
"cmd/internal/dwarf.Location %#v": "",
"cmd/internal/src.Pos %s": "", "cmd/internal/src.Pos %s": "",
"cmd/internal/src.Pos %v": "", "cmd/internal/src.Pos %v": "",
"error %v": "", "error %v": "",
......
...@@ -44,6 +44,7 @@ var ( ...@@ -44,6 +44,7 @@ var (
Debug_vlog bool Debug_vlog bool
Debug_wb int Debug_wb int
Debug_pctab string Debug_pctab string
Debug_locationlist int
) )
// Debug arguments. // Debug arguments.
...@@ -69,6 +70,7 @@ var debugtab = []struct { ...@@ -69,6 +70,7 @@ var debugtab = []struct {
{"wb", "print information about write barriers", &Debug_wb}, {"wb", "print information about write barriers", &Debug_wb},
{"export", "print export data", &Debug_export}, {"export", "print export data", &Debug_export},
{"pctab", "print named pc-value table", &Debug_pctab}, {"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>] const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
...@@ -192,6 +194,7 @@ func Main(archInit func(*Arch)) { ...@@ -192,6 +194,7 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)") 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.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
flag.BoolVar(&flagDWARF, "dwarf", true, "generate DWARF symbols") 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("e", "no limit on number of errors reported", &Debug['e'])
objabi.Flagcount("f", "debug stack frames", &Debug['f']) objabi.Flagcount("f", "debug stack frames", &Debug['f'])
objabi.Flagcount("h", "halt on error", &Debug['h']) objabi.Flagcount("h", "halt on error", &Debug['h'])
...@@ -298,6 +301,9 @@ func Main(archInit func(*Arch)) { ...@@ -298,6 +301,9 @@ func Main(archInit func(*Arch)) {
if nBackendWorkers > 1 && !concurrentBackendAllowed() { if nBackendWorkers > 1 && !concurrentBackendAllowed() {
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args) 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 // parse -d argument
if debugstr != "" { if debugstr != "" {
...@@ -383,7 +389,7 @@ func Main(archInit func(*Arch)) { ...@@ -383,7 +389,7 @@ func Main(archInit func(*Arch)) {
Debug['l'] = 1 - Debug['l'] 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 Widthptr = thearch.LinkArch.PtrSize
Widthreg = thearch.LinkArch.RegSize Widthreg = thearch.LinkArch.RegSize
......
This diff is collapsed.
...@@ -168,7 +168,7 @@ func (v varsByScopeAndOffset) Less(i, j int) bool { ...@@ -168,7 +168,7 @@ func (v varsByScopeAndOffset) Less(i, j int) bool {
if v.scopes[i] != v.scopes[j] { if v.scopes[i] != v.scopes[j] {
return 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) { func (v varsByScopeAndOffset) Swap(i, j int) {
......
...@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) { ...@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Func{}, 124, 216}, {Func{}, 128, 224},
{Name{}, 36, 56}, {Name{}, 36, 56},
{Param{}, 28, 56}, {Param{}, 28, 56},
{Node{}, 76, 128}, {Node{}, 76, 128},
......
...@@ -4401,14 +4401,15 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4401,14 +4401,15 @@ func genssa(f *ssa.Func, pp *Progs) {
// Remember where each block starts. // Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks()) s.bstart = make([]*obj.Prog, f.NumBlocks())
s.pp = pp s.pp = pp
var valueProgs map[*obj.Prog]*ssa.Value var progToValue map[*obj.Prog]*ssa.Value
var blockProgs map[*obj.Prog]*ssa.Block var progToBlock map[*obj.Prog]*ssa.Block
var valueToProg []*obj.Prog
var logProgs = e.log var logProgs = e.log
if logProgs { if logProgs {
valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues()) progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks()) progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
f.Logf("genssa %s\n", f.Name) f.Logf("genssa %s\n", f.Name)
blockProgs[s.pp.next] = f.Blocks[0] progToBlock[s.pp.next] = f.Blocks[0]
} }
if thearch.Use387 { if thearch.Use387 {
...@@ -4417,6 +4418,11 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4417,6 +4418,11 @@ func genssa(f *ssa.Func, pp *Progs) {
s.ScratchFpMem = e.scratchFpMem 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 // Emit basic blocks
for i, b := range f.Blocks { for i, b := range f.Blocks {
s.bstart[b.ID] = s.pp.next s.bstart[b.ID] = s.pp.next
...@@ -4457,15 +4463,19 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4457,15 +4463,19 @@ func genssa(f *ssa.Func, pp *Progs) {
} }
case ssa.OpPhi: case ssa.OpPhi:
CheckLoweredPhi(v) CheckLoweredPhi(v)
case ssa.OpRegKill:
// nothing to do
default: default:
// let the backend handle it // let the backend handle it
thearch.SSAGenValue(&s, v) thearch.SSAGenValue(&s, v)
} }
if Ctxt.Flag_locationlists {
valueToProg[v.ID] = x
}
if logProgs { if logProgs {
for ; x != s.pp.next; x = x.Link { for ; x != s.pp.next; x = x.Link {
valueProgs[x] = v progToValue[x] = v
} }
} }
} }
...@@ -4483,7 +4493,23 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4483,7 +4493,23 @@ func genssa(f *ssa.Func, pp *Progs) {
thearch.SSAGenBlock(&s, b, next) thearch.SSAGenBlock(&s, b, next)
if logProgs { if logProgs {
for ; x != s.pp.next; x = x.Link { 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
}
} }
} }
} }
...@@ -4496,9 +4522,9 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4496,9 +4522,9 @@ func genssa(f *ssa.Func, pp *Progs) {
if logProgs { if logProgs {
for p := pp.Text; p != nil; p = p.Link { for p := pp.Text; p != nil; p = p.Link {
var s string var s string
if v, ok := valueProgs[p]; ok { if v, ok := progToValue[p]; ok {
s = v.String() s = v.String()
} else if b, ok := blockProgs[p]; ok { } else if b, ok := progToBlock[p]; ok {
s = b.String() s = b.String()
} else { } else {
s = " " // most value and branch strings are 2-3 characters long s = " " // most value and branch strings are 2-3 characters long
...@@ -4516,9 +4542,9 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4516,9 +4542,9 @@ func genssa(f *ssa.Func, pp *Progs) {
buf.WriteString("<dl class=\"ssa-gen\">") buf.WriteString("<dl class=\"ssa-gen\">")
for p := pp.Text; p != nil; p = p.Link { for p := pp.Text; p != nil; p = p.Link {
buf.WriteString("<dt class=\"ssa-prog-src\">") buf.WriteString("<dt class=\"ssa-prog-src\">")
if v, ok := valueProgs[p]; ok { if v, ok := progToValue[p]; ok {
buf.WriteString(v.HTML()) buf.WriteString(v.HTML())
} else if b, ok := blockProgs[p]; ok { } else if b, ok := progToBlock[p]; ok {
buf.WriteString(b.HTML()) buf.WriteString(b.HTML())
} }
buf.WriteString("</dt>") buf.WriteString("</dt>")
...@@ -4895,9 +4921,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { ...@@ -4895,9 +4921,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
lenType := types.Types[TINT] lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this string up into two separate variables. // Split this string up into two separate variables.
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos) p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos) l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0} return p, l
} }
// Return the two parts of the larger variable. // 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)} return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
...@@ -4912,9 +4938,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot ...@@ -4912,9 +4938,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
if n.Type.IsEmptyInterface() { if n.Type.IsEmptyInterface() {
f = ".type" f = ".type"
} }
c := e.namedAuto(n.Sym.Name+f, t, n.Pos) c := e.splitSlot(&name, f, 0, t)
d := e.namedAuto(n.Sym.Name+".data", t, n.Pos) d := e.splitSlot(&name, ".data", t.Size(), t)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0} return c, d
} }
// Return the two parts of the larger variable. // 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)} return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
...@@ -4926,10 +4952,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss ...@@ -4926,10 +4952,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss
lenType := types.Types[TINT] lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this slice up into three separate variables. // Split this slice up into three separate variables.
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos) p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos) l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos) c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
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} return p, l, c
} }
// Return the three parts of the larger variable. // Return the three parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
...@@ -4948,9 +4974,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) ...@@ -4948,9 +4974,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
} }
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this complex up into two separate variables. // Split this complex up into two separate variables.
c := e.namedAuto(n.Sym.Name+".real", t, n.Pos) r := e.splitSlot(&name, ".real", 0, t)
d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos) i := e.splitSlot(&name, ".imag", t.Size(), t)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0} return r, i
} }
// Return the two parts of the larger variable. // 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} return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
...@@ -4966,9 +4992,10 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { ...@@ -4966,9 +4992,10 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
} }
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this int64 up into two separate variables. // Split this int64 up into two separate variables.
h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos) if thearch.LinkArch.ByteOrder == binary.BigEndian {
l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos) return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0} }
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
} }
// Return the two parts of the larger variable. // Return the two parts of the larger variable.
if thearch.LinkArch.ByteOrder == binary.BigEndian { if thearch.LinkArch.ByteOrder == binary.BigEndian {
...@@ -4981,12 +5008,15 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot { ...@@ -4981,12 +5008,15 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
n := name.N.(*Node) n := name.N.(*Node)
st := name.Type st := name.Type
ft := st.FieldType(i) ft := st.FieldType(i)
var offset int64
for f := 0; f < i; f++ {
offset += st.FieldType(f).Size()
}
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Note: the _ field may appear several times. But // Note: the _ field may appear several times. But
// have no fear, identically-named but distinct Autos are // have no fear, identically-named but distinct Autos are
// ok, albeit maybe confusing for a debugger. // ok, albeit maybe confusing for a debugger.
x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos) return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
return ssa.LocalSlot{N: x, Type: ft, Off: 0}
} }
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)} return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
} }
...@@ -4999,8 +5029,7 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot { ...@@ -4999,8 +5029,7 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
} }
et := at.ElemType() et := at.ElemType()
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos) return e.splitSlot(&name, "[0]", 0, et)
return ssa.LocalSlot{N: x, Type: et, Off: 0}
} }
return ssa.LocalSlot{N: n, Type: et, Off: name.Off} return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
} }
...@@ -5009,16 +5038,14 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym { ...@@ -5009,16 +5038,14 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
return itabsym(it, offset) return itabsym(it, offset)
} }
// namedAuto returns a new AUTO variable with the given name and type. // splitSlot returns a slot representing the data of parent starting at offset.
// These are exposed to the debugger. func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode { s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
t := typ
s := &types.Sym{Name: name, Pkg: localpkg}
n := new(Node) n := new(Node)
n.Name = new(Name) n.Name = new(Name)
n.Op = ONAME n.Op = ONAME
n.Pos = pos n.Pos = parent.N.(*Node).Pos
n.Orig = n n.Orig = n
s.Def = asTypesNode(n) s.Def = asTypesNode(n)
...@@ -5031,7 +5058,7 @@ func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode ...@@ -5031,7 +5058,7 @@ func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode
n.Name.Curfn = e.curfn n.Name.Curfn = e.curfn
e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n) e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
dowidth(t) 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 { func (e *ssafn) CanSSA(t *types.Type) bool {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package gc package gc
import ( import (
"cmd/compile/internal/ssa"
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
...@@ -369,6 +370,7 @@ type Func struct { ...@@ -369,6 +370,7 @@ type Func struct {
Closgen int Closgen int
Outerfunc *Node // outer function (for closure) Outerfunc *Node // outer function (for closure)
FieldTrack map[*types.Sym]struct{} FieldTrack map[*types.Sym]struct{}
DebugInfo *ssa.FuncDebug
Ntype *Node // signature Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc) Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC Closure *Node // OCLOSURE <-> ODCLFUNC
......
...@@ -14,6 +14,11 @@ type Cache struct { ...@@ -14,6 +14,11 @@ type Cache struct {
blocks [200]Block blocks [200]Block
locs [2000]Location locs [2000]Location
// Storage for DWARF variable locations. Lazily allocated
// since location lists are off by default.
varLocs []VarLoc
curVarLoc int
// Reusable stackAllocState. // Reusable stackAllocState.
// See stackalloc.go's {new,put}StackAllocState. // See stackalloc.go's {new,put}StackAllocState.
stackAllocState *stackAllocState stackAllocState *stackAllocState
...@@ -38,4 +43,21 @@ func (c *Cache) Reset() { ...@@ -38,4 +43,21 @@ func (c *Cache) Reset() {
for i := range xl { for i := range xl {
xl[i] = nil 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) { ...@@ -98,6 +98,7 @@ func decomposeBuiltIn(f *Func) {
delete(f.NamedValues, name) delete(f.NamedValues, name)
case t.IsFloat(): case t.IsFloat():
// floats are never decomposed, even ones bigger than RegSize // floats are never decomposed, even ones bigger than RegSize
newNames = append(newNames, name)
case t.Size() > f.Config.RegSize: case t.Size() > f.Config.RegSize:
f.Fatalf("undecomposed named type %v %v", name, t) f.Fatalf("undecomposed named type %v %v", name, t)
default: default:
......
...@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode { ...@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
return &DummyAuto{t: t, s: "aDummyAuto"} return &DummyAuto{t: t, s: "aDummyAuto"}
} }
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) { 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) { 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) { func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off}, return LocalSlot{N: s.N, Type: s.Type.ElemType().PtrTo(), Off: s.Off},
LocalSlot{s.N, dummyTypes.Int, s.Off + 8}, LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8},
LocalSlot{s.N, dummyTypes.Int, s.Off + 16} LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 16}
} }
func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) { func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.Size() == 16 { 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) { func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.IsSigned() { 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 { 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 { 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 { func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0" return "unknown.go:0"
......
...@@ -420,6 +420,7 @@ var genericOps = []opData{ ...@@ -420,6 +420,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: "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: "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: "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 // Ops for breaking 64-bit operations on 32-bit architectures
{name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo {name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"html" "html"
"io" "io"
"os" "os"
"strings"
) )
type HTMLWriter struct { type HTMLWriter struct {
...@@ -362,6 +363,18 @@ func (v *Value) LongHTML() string { ...@@ -362,6 +363,18 @@ func (v *Value) LongHTML() string {
if int(v.ID) < len(r) && r[v.ID] != nil { if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + html.EscapeString(r[v.ID].Name()) 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>" s += "</span>"
return s return s
} }
......
...@@ -26,12 +26,38 @@ func (r *Register) Name() string { ...@@ -26,12 +26,38 @@ func (r *Register) Name() string {
return r.name return r.name
} }
// A LocalSlot is a location in the stack frame. // ObjNum returns the register number from cmd/internal/obj/$ARCH that
// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node. // 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 { 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 Type *types.Type // type of slot
Off int64 // offset of slot in N 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 { func (s LocalSlot) Name() string {
......
...@@ -1903,6 +1903,7 @@ const ( ...@@ -1903,6 +1903,7 @@ const (
OpVarKill OpVarKill
OpVarLive OpVarLive
OpKeepAlive OpKeepAlive
OpRegKill
OpInt64Make OpInt64Make
OpInt64Hi OpInt64Hi
OpInt64Lo OpInt64Lo
...@@ -22557,6 +22558,11 @@ var opcodeTable = [...]opInfo{ ...@@ -22557,6 +22558,11 @@ var opcodeTable = [...]opInfo{
argLen: 2, argLen: 2,
generic: true, generic: true,
}, },
{
name: "RegKill",
argLen: 0,
generic: true,
},
{ {
name: "Int64Make", name: "Int64Make",
argLen: 2, argLen: 2,
......
...@@ -242,6 +242,9 @@ type regAllocState struct { ...@@ -242,6 +242,9 @@ type regAllocState struct {
// current state of each (preregalloc) Value // current state of each (preregalloc) Value
values []valState values []valState
// names associated with each Value
valueNames [][]LocalSlot
// ID of SP, SB values // ID of SP, SB values
sp, sb ID sp, sb ID
...@@ -300,6 +303,13 @@ type startReg struct { ...@@ -300,6 +303,13 @@ type startReg struct {
// freeReg frees up register r. Any current user of r is kicked out. // freeReg frees up register r. Any current user of r is kicked out.
func (s *regAllocState) freeReg(r register) { 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 v := s.regs[r].v
if v == nil { if v == nil {
s.f.Fatalf("tried to free an already free register %d\n", r) s.f.Fatalf("tried to free an already free register %d\n", r)
...@@ -309,6 +319,16 @@ func (s *regAllocState) freeReg(r register) { ...@@ -309,6 +319,16 @@ func (s *regAllocState) freeReg(r register) {
if s.f.pass.debug > regDebug { if s.f.pass.debug > regDebug {
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c) 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.regs[r] = regState{}
s.values[v.ID].regs &^= regMask(1) << r s.values[v.ID].regs &^= regMask(1) << r
s.used &^= regMask(1) << r s.used &^= regMask(1) << r
...@@ -599,6 +619,17 @@ func (s *regAllocState) init(f *Func) { ...@@ -599,6 +619,17 @@ func (s *regAllocState) init(f *Func) {
s.values = make([]valState, f.NumValues()) s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues()) s.orig = make([]*Value, f.NumValues())
s.copies = make(map[*Value]bool) 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 _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() { if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() {
...@@ -692,7 +723,9 @@ func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool { ...@@ -692,7 +723,9 @@ func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
// Sets the state of the registers to that encoded in regs. // Sets the state of the registers to that encoded in regs.
func (s *regAllocState) setState(regs []endReg) { func (s *regAllocState) setState(regs []endReg) {
s.freeRegs(s.used) for s.used != 0 {
s.freeOrResetReg(pickReg(s.used), true)
}
for _, x := range regs { for _, x := range regs {
s.assignReg(x.r, x.v, x.c) s.assignReg(x.r, x.v, x.c)
} }
...@@ -735,6 +768,9 @@ func (s *regAllocState) regalloc(f *Func) { ...@@ -735,6 +768,9 @@ func (s *regAllocState) regalloc(f *Func) {
} }
for _, b := range f.Blocks { for _, b := range f.Blocks {
if s.f.pass.debug > regDebug {
fmt.Printf("Begin processing block %v\n", b)
}
s.curBlock = b s.curBlock = b
// Initialize regValLiveSet and uses fields for this block. // Initialize regValLiveSet and uses fields for this block.
...@@ -830,9 +866,6 @@ func (s *regAllocState) regalloc(f *Func) { ...@@ -830,9 +866,6 @@ func (s *regAllocState) regalloc(f *Func) {
// This is the complicated case. We have more than one predecessor, // This is the complicated case. We have more than one predecessor,
// which means we may have Phi ops. // 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 // Start with the final register state of the primary predecessor
idx := s.primary[b.ID] idx := s.primary[b.ID]
if idx < 0 { if idx < 0 {
...@@ -910,6 +943,9 @@ func (s *regAllocState) regalloc(f *Func) { ...@@ -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 // Third pass - pick registers for phis whose inputs
// were not in a register. // were not in a register.
for i, v := range phis { for i, v := range phis {
...@@ -1005,7 +1041,7 @@ func (s *regAllocState) regalloc(f *Func) { ...@@ -1005,7 +1041,7 @@ func (s *regAllocState) regalloc(f *Func) {
pidx := e.i pidx := e.i
for _, v := range succ.Values { for _, v := range succ.Values {
if v.Op != OpPhi { if v.Op != OpPhi {
break continue
} }
if !s.values[v.ID].needReg { if !s.values[v.ID].needReg {
continue continue
...@@ -1565,6 +1601,9 @@ func (s *regAllocState) placeSpills() { ...@@ -1565,6 +1601,9 @@ func (s *regAllocState) placeSpills() {
for _, b := range f.Blocks { for _, b := range f.Blocks {
var m regMask var m regMask
for _, v := range b.Values { for _, v := range b.Values {
if v.Op == OpRegKill {
continue
}
if v.Op != OpPhi { if v.Op != OpPhi {
break break
} }
...@@ -1675,7 +1714,7 @@ func (s *regAllocState) placeSpills() { ...@@ -1675,7 +1714,7 @@ func (s *regAllocState) placeSpills() {
for _, b := range f.Blocks { for _, b := range f.Blocks {
nphi := 0 nphi := 0
for _, v := range b.Values { for _, v := range b.Values {
if v.Op != OpPhi { if v.Op != OpRegKill && v.Op != OpPhi {
break break
} }
nphi++ nphi++
...@@ -1800,6 +1839,9 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive ...@@ -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. // Phis need their args to end up in a specific location.
for _, v := range e.b.Values { for _, v := range e.b.Values {
if v.Op == OpRegKill {
continue
}
if v.Op != OpPhi { if v.Op != OpPhi {
break break
} }
...@@ -1878,6 +1920,7 @@ func (e *edgeState) process() { ...@@ -1878,6 +1920,7 @@ func (e *edgeState) process() {
if e.s.f.pass.debug > regDebug { if e.s.f.pass.debug > regDebug {
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c) fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
} }
e.erase(r)
if _, isReg := loc.(*Register); isReg { if _, isReg := loc.(*Register); isReg {
c = e.p.NewValue1(d.pos, OpCopy, c.Type, c) c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
} else { } else {
...@@ -1943,6 +1986,18 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP ...@@ -1943,6 +1986,18 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
} }
} }
_, dstReg := loc.(*Register) _, 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 var x *Value
if c == nil { if c == nil {
if !e.s.values[vid].rematerializeable { if !e.s.values[vid].rematerializeable {
...@@ -1953,8 +2008,8 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP ...@@ -1953,8 +2008,8 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
} else { } else {
// Rematerialize into stack slot. Need a free // Rematerialize into stack slot. Need a free
// register to accomplish this. // register to accomplish this.
e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type) r := e.findRegFor(v.Type)
e.erase(r)
x = v.copyIntoNoXPos(e.p) x = v.copyIntoNoXPos(e.p)
e.set(r, vid, x, false, pos) e.set(r, vid, x, false, pos)
// Make sure we spill with the size of the slot, not the // 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 ...@@ -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) x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
} else { } else {
// mem->mem. Use temp register. // 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) r := e.findRegFor(c.Type)
e.erase(r)
t := e.p.NewValue1(pos, OpLoadReg, c.Type, c) t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
e.set(r, vid, t, false, pos) e.set(r, vid, t, false, pos)
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t) 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 ...@@ -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. // 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) { func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
e.s.f.setHome(c, loc) e.s.f.setHome(c, loc)
e.erase(loc)
e.contents[loc] = contentRecord{vid, c, final, pos} e.contents[loc] = contentRecord{vid, c, final, pos}
a := e.cache[vid] a := e.cache[vid]
if len(a) == 0 { if len(a) == 0 {
...@@ -2059,6 +2101,16 @@ func (e *edgeState) erase(loc Location) { ...@@ -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) 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] 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 break
} }
} }
...@@ -2118,8 +2170,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location { ...@@ -2118,8 +2170,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
// Allocate a temp location to spill a register to. // Allocate a temp location to spill a register to.
// The type of the slot is immaterial - it will not be live across // 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. // 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} t := LocalSlot{N: e.s.f.fe.Auto(c.Pos, types.Int64), Type: types.Int64}
// TODO: reuse these slots. // TODO: reuse these slots. They'll need to be erased first.
e.set(t, vid, x, false, c.Pos) e.set(t, vid, x, false, c.Pos)
if e.s.f.pass.debug > regDebug { if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString()) fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
......
...@@ -24,6 +24,7 @@ func TestSizeof(t *testing.T) { ...@@ -24,6 +24,7 @@ func TestSizeof(t *testing.T) {
}{ }{
{Value{}, 68, 112}, {Value{}, 68, 112},
{Block{}, 152, 288}, {Block{}, 152, 288},
{LocalSlot{}, 32, 48},
{valState{}, 28, 40}, {valState{}, 28, 40},
} }
......
...@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() { ...@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() {
if v.Op != OpArg { if v.Op != OpArg {
continue 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 { if f.pass.debug > stackDebug {
fmt.Printf("stackalloc %s to %s\n", v, loc.Name()) fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
"math" "math"
"strings"
) )
// A Value represents a value in the SSA representation of the program. // A Value represents a value in the SSA representation of the program.
...@@ -98,7 +99,7 @@ func (v *Value) AuxValAndOff() ValAndOff { ...@@ -98,7 +99,7 @@ func (v *Value) AuxValAndOff() ValAndOff {
return ValAndOff(v.AuxInt) 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 { func (v *Value) LongString() string {
s := fmt.Sprintf("v%d = %s", v.ID, v.Op) s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
s += " <" + v.Type.String() + ">" s += " <" + v.Type.String() + ">"
...@@ -110,6 +111,18 @@ func (v *Value) LongString() string { ...@@ -110,6 +111,18 @@ func (v *Value) LongString() string {
if int(v.ID) < len(r) && r[v.ID] != nil { if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + r[v.ID].Name() 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 return s
} }
......
...@@ -15,6 +15,9 @@ import ( ...@@ -15,6 +15,9 @@ import (
// InfoPrefix is the prefix for all the symbols containing DWARF info entries. // InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info." 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. // RangePrefix is the prefix for all the symbols containing DWARF range lists.
const RangePrefix = "go.range." const RangePrefix = "go.range."
...@@ -23,11 +26,29 @@ type Sym interface { ...@@ -23,11 +26,29 @@ type Sym interface {
Len() int64 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. // A Var represents a local variable or a function parameter.
type Var struct { type Var struct {
Name string Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
Offset int32 StackOffset int32
LocationList []Location
Scope int32 Scope int32
Type Sym Type Sym
} }
...@@ -205,7 +226,7 @@ const ( ...@@ -205,7 +226,7 @@ const (
) )
// Index into the abbrevs table below. // 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 // ispubtype considers >= NULLTYPE public
const ( const (
DW_ABRV_NULL = iota DW_ABRV_NULL = iota
...@@ -213,7 +234,9 @@ const ( ...@@ -213,7 +234,9 @@ const (
DW_ABRV_FUNCTION DW_ABRV_FUNCTION
DW_ABRV_VARIABLE DW_ABRV_VARIABLE
DW_ABRV_AUTO DW_ABRV_AUTO
DW_ABRV_AUTO_LOCLIST
DW_ABRV_PARAM DW_ABRV_PARAM
DW_ABRV_PARAM_LOCLIST
DW_ABRV_LEXICAL_BLOCK_RANGES DW_ABRV_LEXICAL_BLOCK_RANGES
DW_ABRV_LEXICAL_BLOCK_SIMPLE DW_ABRV_LEXICAL_BLOCK_SIMPLE
DW_ABRV_STRUCTFIELD DW_ABRV_STRUCTFIELD
...@@ -297,6 +320,17 @@ var abbrevs = [DW_NABRV]dwAbbrev{ ...@@ -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 */ /* PARAM */
{ {
DW_TAG_formal_parameter, DW_TAG_formal_parameter,
...@@ -307,6 +341,18 @@ var abbrevs = [DW_NABRV]dwAbbrev{ ...@@ -307,6 +341,18 @@ var abbrevs = [DW_NABRV]dwAbbrev{
{DW_AT_type, DW_FORM_ref_addr}, {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 */ /* LEXICAL_BLOCK_RANGES */
{ {
DW_TAG_lexical_block, DW_TAG_lexical_block,
...@@ -684,31 +730,30 @@ func HasChildren(die *DWDie) bool { ...@@ -684,31 +730,30 @@ func HasChildren(die *DWDie) bool {
// PutFunc writes a DIE for a function to s. // PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars. // 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 { func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
Uleb128put(ctxt, s, DW_ABRV_FUNCTION) Uleb128put(ctxt, info, DW_ABRV_FUNCTION)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name) putattr(ctxt, info, 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, info, 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, info, 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}) putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
var ev int64 var ev int64
if external { if external {
ev = 1 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 { if len(scopes) > 0 {
var encbuf [20]byte 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") return errors.New("multiple toplevel scopes")
} }
} }
Uleb128put(ctxt, info, 0)
Uleb128put(ctxt, s, 0)
return nil 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 { for _, v := range scopes[curscope].Vars {
putvar(ctxt, s, v, encbuf) putvar(ctxt, info, loc, v, startPC, encbuf)
} }
this := curscope this := curscope
curscope++ curscope++
...@@ -719,12 +764,12 @@ func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes [ ...@@ -719,12 +764,12 @@ func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes [
} }
if len(scope.Ranges) == 1 { if len(scope.Ranges) == 1 {
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE) Uleb128put(ctxt, info, 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, info, 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) putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
} else { } else {
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES) Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), 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, nil, -1)
ctxt.AddAddress(ranges, startPC, 0) ctxt.AddAddress(ranges, startPC, 0)
...@@ -736,32 +781,72 @@ func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes [ ...@@ -736,32 +781,72 @@ func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes [
ctxt.AddAddress(ranges, nil, 0) 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 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 n := v.Name
Uleb128put(ctxt, s, int64(v.Abbrev)) Uleb128put(ctxt, info, int64(v.Abbrev))
putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n) 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) loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.Offset != 0 { if v.StackOffset != 0 {
loc = append(loc, DW_OP_consts) loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.Offset)) loc = AppendSleb128(loc, int64(v.StackOffset))
loc = append(loc, DW_OP_plus) loc = append(loc, DW_OP_plus)
} }
putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc) putattr(ctxt, info, 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) }
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)
}
// End list
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
} }
// VarsByOffset attaches the methods of sort.Interface to []*Var, // VarsByOffset attaches the methods of sort.Interface to []*Var,
// sorting in increasing Offset. // sorting in increasing StackOffset.
type VarsByOffset []*Var type VarsByOffset []*Var
func (s VarsByOffset) Len() int { return len(s) } 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] } func (s VarsByOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
...@@ -330,7 +330,8 @@ type FuncInfo struct { ...@@ -330,7 +330,8 @@ type FuncInfo struct {
Autom []*Auto Autom []*Auto
Pcln Pcln Pcln Pcln
dwarfSym *LSym dwarfInfoSym *LSym
dwarfLocSym *LSym
dwarfRangesSym *LSym dwarfRangesSym *LSym
GCArgs LSym GCArgs LSym
...@@ -484,6 +485,7 @@ type Link struct { ...@@ -484,6 +485,7 @@ type Link struct {
Flag_shared bool Flag_shared bool
Flag_dynlink bool Flag_dynlink bool
Flag_optimize bool Flag_optimize bool
Flag_locationlists bool
Bso *bufio.Writer Bso *bufio.Writer
Pathname string Pathname string
hashmu sync.Mutex // protects hash hashmu sync.Mutex // protects hash
...@@ -538,4 +540,5 @@ type LinkArch struct { ...@@ -538,4 +540,5 @@ type LinkArch struct {
Assemble func(*Link, *LSym, ProgAlloc) Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog, ProgAlloc) Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination. 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 ...@@ -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. // 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 { if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s) ctxt.Diag("dwarfSym of non-TEXT %v", s)
} }
if s.Func.dwarfSym == nil { if s.Func.dwarfInfoSym == nil {
s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name) 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) 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 { func (s *LSym) Len() int64 {
...@@ -483,15 +486,15 @@ 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. // populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s.
// The DWARFs symbol must already have been initialized in InitTextSym. // The DWARFs symbol must already have been initialized in InitTextSym.
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) { func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
dsym, drsym := ctxt.dwarfSym(s) info, loc, ranges := ctxt.dwarfSym(s)
if dsym.Size != 0 { if info.Size != 0 {
ctxt.Diag("makeFuncDebugEntry double process %v", s) ctxt.Diag("makeFuncDebugEntry double process %v", s)
} }
var scopes []dwarf.Scope var scopes []dwarf.Scope
if ctxt.DebugInfo != nil { if ctxt.DebugInfo != nil {
scopes = ctxt.DebugInfo(s, curfn) 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 { if err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
} }
......
...@@ -136,13 +136,17 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) { ...@@ -136,13 +136,17 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
ctxt.Text = append(ctxt.Text, s) ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s. // Set up DWARF entries for s.
dsym, drsym := ctxt.dwarfSym(s) info, loc, ranges := ctxt.dwarfSym(s)
dsym.Type = objabi.SDWARFINFO info.Type = objabi.SDWARFINFO
dsym.Set(AttrDuplicateOK, s.DuplicateOK()) info.Set(AttrDuplicateOK, s.DuplicateOK())
drsym.Type = objabi.SDWARFRANGE if loc != nil {
drsym.Set(AttrDuplicateOK, s.DuplicateOK()) loc.Type = objabi.SDWARFLOC
ctxt.Data = append(ctxt.Data, dsym) loc.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, drsym) 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. // Set up the function's gcargs and gclocals.
// They will be filled in later if needed. // They will be filled in later if needed.
......
...@@ -1006,3 +1006,120 @@ const ( ...@@ -1006,3 +1006,120 @@ const (
T_64 = 1 << 6 T_64 = 1 << 6
T_GOTYPE = 1 << 7 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,
}
...@@ -1237,6 +1237,7 @@ var Linkamd64 = obj.LinkArch{ ...@@ -1237,6 +1237,7 @@ var Linkamd64 = obj.LinkArch{
Assemble: span6, Assemble: span6,
Progedit: progedit, Progedit: progedit,
UnaryDst: unaryDst, UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
} }
var Linkamd64p32 = obj.LinkArch{ var Linkamd64p32 = obj.LinkArch{
...@@ -1246,6 +1247,7 @@ var Linkamd64p32 = obj.LinkArch{ ...@@ -1246,6 +1247,7 @@ var Linkamd64p32 = obj.LinkArch{
Assemble: span6, Assemble: span6,
Progedit: progedit, Progedit: progedit,
UnaryDst: unaryDst, UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
} }
var Link386 = obj.LinkArch{ var Link386 = obj.LinkArch{
...@@ -1255,4 +1257,5 @@ var Link386 = obj.LinkArch{ ...@@ -1255,4 +1257,5 @@ var Link386 = obj.LinkArch{
Assemble: span6, Assemble: span6,
Progedit: progedit, Progedit: progedit,
UnaryDst: unaryDst, UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
} }
...@@ -57,4 +57,5 @@ const ( ...@@ -57,4 +57,5 @@ const (
// Debugging data // Debugging data
SDWARFINFO SDWARFINFO
SDWARFRANGE SDWARFRANGE
SDWARFLOC
) )
...@@ -4,9 +4,9 @@ package objabi ...@@ -4,9 +4,9 @@ package objabi
import "fmt" 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 { func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) { if i >= SymKind(len(_SymKind_index)-1) {
......
...@@ -592,15 +592,7 @@ func relocsym(ctxt *Link, s *Symbol) { ...@@ -592,15 +592,7 @@ func relocsym(ctxt *Link, s *Symbol) {
} }
case objabi.R_DWARFREF: case objabi.R_DWARFREF:
var sectName string if r.Sym.Sect == nil {
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:
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name) Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
} }
...@@ -615,8 +607,8 @@ func relocsym(ctxt *Link, s *Symbol) { ...@@ -615,8 +607,8 @@ func relocsym(ctxt *Link, s *Symbol) {
r.Type = objabi.R_ADDR r.Type = objabi.R_ADDR
} }
r.Xsym = ctxt.Syms.ROLookup(sectName, 0) r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - vaddr r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
o = r.Xadd o = r.Xadd
rs = r.Xsym rs = r.Xsym
...@@ -625,7 +617,7 @@ func relocsym(ctxt *Link, s *Symbol) { ...@@ -625,7 +617,7 @@ func relocsym(ctxt *Link, s *Symbol) {
} }
break break
} }
o = Symaddr(r.Sym) + r.Add - vaddr o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
case objabi.R_WEAKADDROFF: case objabi.R_WEAKADDROFF:
if !r.Sym.Attr.Reachable() { if !r.Sym.Attr.Reachable() {
...@@ -1843,9 +1835,9 @@ func (ctxt *Link) dodata() { ...@@ -1843,9 +1835,9 @@ func (ctxt *Link) dodata() {
dwarfgeneratedebugsyms(ctxt) dwarfgeneratedebugsyms(ctxt)
var s *Symbol
var i int var i int
for i, s = range dwarfp { for ; i < len(dwarfp); i++ {
s := dwarfp[i]
if s.Type != SDWARFSECT { if s.Type != SDWARFSECT {
break break
} }
...@@ -1862,13 +1854,26 @@ func (ctxt *Link) dodata() { ...@@ -1862,13 +1854,26 @@ func (ctxt *Link) dodata() {
} }
checkdatsize(ctxt, datsize, SDWARFSECT) checkdatsize(ctxt, datsize, SDWARFSECT)
if i < len(dwarfp) { for i < len(dwarfp) {
curType := dwarfp[i].Type
var sect *Section
switch curType {
case SDWARFINFO:
sect = addsection(&Segdwarf, ".debug_info", 04) 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 sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align)) datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize) sect.Vaddr = uint64(datsize)
for _, s := range dwarfp[i:] { for ; i < len(dwarfp); i++ {
if s.Type != SDWARFINFO { s := dwarfp[i]
if s.Type != curType {
break break
} }
s.Sect = sect s.Sect = sect
...@@ -1878,7 +1883,7 @@ func (ctxt *Link) dodata() { ...@@ -1878,7 +1883,7 @@ func (ctxt *Link) dodata() {
datsize += s.Size datsize += s.Size
} }
sect.Length = uint64(datsize) - sect.Vaddr sect.Length = uint64(datsize) - sect.Vaddr
checkdatsize(ctxt, datsize, SDWARFINFO) checkdatsize(ctxt, datsize, curType)
} }
/* number the sections */ /* number the sections */
......
...@@ -67,26 +67,15 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64 ...@@ -67,26 +67,15 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
r.Add = ofs 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 gdbscript string
var dwarfp []*Symbol var dwarfp []*Symbol
func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol { func writeabbrev(ctxt *Link) *Symbol {
s := ctxt.Syms.Lookup(".debug_abbrev", 0) s := ctxt.Syms.Lookup(".debug_abbrev", 0)
s.Type = SDWARFSECT s.Type = SDWARFSECT
abbrevsym = s
Addbytes(s, dwarf.GetAbbrev()) Addbytes(s, dwarf.GetAbbrev())
return append(syms, s) return s
} }
/* /*
...@@ -993,13 +982,10 @@ func getCompilationDir() string { ...@@ -993,13 +982,10 @@ func getCompilationDir() string {
func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) { func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
var dwarfctxt dwarf.Context = dwctxt{ctxt} var dwarfctxt dwarf.Context = dwctxt{ctxt}
if linesec == nil { ls := ctxt.Syms.Lookup(".debug_line", 0)
linesec = ctxt.Syms.Lookup(".debug_line", 0) ls.Type = SDWARFSECT
} ls.R = ls.R[:0]
linesec.Type = SDWARFSECT
linesec.R = linesec.R[:0]
ls := linesec
syms = append(syms, ls) syms = append(syms, ls)
var funcs []*Symbol var funcs []*Symbol
...@@ -1019,7 +1005,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) { ...@@ -1019,7 +1005,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0) 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_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) 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. // OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
compDir := getCompilationDir() compDir := getCompilationDir()
...@@ -1178,12 +1164,9 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte { ...@@ -1178,12 +1164,9 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
func writeframes(ctxt *Link, syms []*Symbol) []*Symbol { func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
var dwarfctxt dwarf.Context = dwctxt{ctxt} var dwarfctxt dwarf.Context = dwctxt{ctxt}
if framesec == nil { fs := ctxt.Syms.Lookup(".debug_frame", 0)
framesec = ctxt.Syms.Lookup(".debug_frame", 0) fs.Type = SDWARFSECT
} fs.R = fs.R[:0]
framesec.Type = SDWARFSECT
framesec.R = framesec.R[:0]
fs := framesec
syms = append(syms, fs) syms = append(syms, fs)
// Emit the CIE, Section 6.4.1 // Emit the CIE, Section 6.4.1
...@@ -1280,7 +1263,7 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol { ...@@ -1280,7 +1263,7 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
// ptrsize: address range // ptrsize: address range
Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself) Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
if Linkmode == LinkExternal { if Linkmode == LinkExternal {
adddwarfref(ctxt, fs, framesec, 4) adddwarfref(ctxt, fs, fs, 4)
} else { } else {
Adduint32(ctxt, fs, 0) // CIE offset Adduint32(ctxt, fs, 0) // CIE offset
} }
...@@ -1292,27 +1275,24 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol { ...@@ -1292,27 +1275,24 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
} }
func writeranges(ctxt *Link, syms []*Symbol) []*Symbol { func writeranges(ctxt *Link, syms []*Symbol) []*Symbol {
if rangesec == nil { empty := true
rangesec = ctxt.Syms.Lookup(".debug_ranges", 0)
}
rangesec.Type = SDWARFSECT
rangesec.Attr |= AttrReachable
rangesec.R = rangesec.R[:0]
for _, s := range ctxt.Textp { for _, s := range ctxt.Textp {
rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version)) rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
rangeSym.Attr |= AttrReachable if rangeSym.Size == 0 {
rangeSym.Type = SDWARFRANGE continue
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)
} }
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 // 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) syms = append(syms, rangesec)
} }
return syms return syms
...@@ -1325,18 +1305,14 @@ const ( ...@@ -1325,18 +1305,14 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1 COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
) )
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol { func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol, abbrevsym *Symbol) []*Symbol {
if infosec == nil { infosec := ctxt.Syms.Lookup(".debug_info", 0)
infosec = ctxt.Syms.Lookup(".debug_info", 0)
}
infosec.R = infosec.R[:0] infosec.R = infosec.R[:0]
infosec.Type = SDWARFINFO infosec.Type = SDWARFINFO
infosec.Attr |= AttrReachable infosec.Attr |= AttrReachable
syms = append(syms, infosec) syms = append(syms, infosec)
if arangessec == nil { arangessec := ctxt.Syms.Lookup(".dwarfaranges", 0)
arangessec = ctxt.Syms.Lookup(".dwarfaranges", 0)
}
arangessec.R = arangessec.R[:0] arangessec.R = arangessec.R[:0]
var dwarfctxt dwarf.Context = dwctxt{ctxt} var dwarfctxt dwarf.Context = dwctxt{ctxt}
...@@ -1577,10 +1553,10 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1577,10 +1553,10 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
genasmsym(ctxt, defdwsymb) genasmsym(ctxt, defdwsymb)
syms := writeabbrev(ctxt, nil) abbrev := writeabbrev(ctxt)
syms := []*Symbol{abbrev}
syms, funcs := writelines(ctxt, syms) syms, funcs := writelines(ctxt, syms)
syms = writeframes(ctxt, syms) syms = writeframes(ctxt, syms)
syms = writeranges(ctxt, syms)
synthesizestringtypes(ctxt, dwtypes.Child) synthesizestringtypes(ctxt, dwtypes.Child)
synthesizeslicetypes(ctxt, dwtypes.Child) synthesizeslicetypes(ctxt, dwtypes.Child)
...@@ -1596,16 +1572,42 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1596,16 +1572,42 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT // Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
// (but we need to generate dies before writepub) // (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_pubnames", ispubname, syms)
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms) syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
syms = writearanges(ctxt, syms) syms = writearanges(ctxt, syms)
syms = writegdbscript(ctxt, syms) syms = writegdbscript(ctxt, syms)
syms = append(syms, infosyms...) syms = append(syms, infosyms...)
syms = collectlocs(ctxt, syms, funcs)
syms = writeranges(ctxt, syms)
dwarfp = 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. * Elf.
*/ */
...@@ -1618,6 +1620,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) { ...@@ -1618,6 +1620,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_aranges") Addstring(shstrtab, ".debug_aranges")
Addstring(shstrtab, ".debug_frame") Addstring(shstrtab, ".debug_frame")
Addstring(shstrtab, ".debug_info") Addstring(shstrtab, ".debug_info")
Addstring(shstrtab, ".debug_loc")
Addstring(shstrtab, ".debug_line") Addstring(shstrtab, ".debug_line")
Addstring(shstrtab, ".debug_pubnames") Addstring(shstrtab, ".debug_pubnames")
Addstring(shstrtab, ".debug_pubtypes") Addstring(shstrtab, ".debug_pubtypes")
...@@ -1625,6 +1628,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) { ...@@ -1625,6 +1628,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_ranges") Addstring(shstrtab, ".debug_ranges")
if Linkmode == LinkExternal { if Linkmode == LinkExternal {
Addstring(shstrtab, elfRelType+".debug_info") Addstring(shstrtab, elfRelType+".debug_info")
Addstring(shstrtab, elfRelType+".debug_loc")
Addstring(shstrtab, elfRelType+".debug_aranges") Addstring(shstrtab, elfRelType+".debug_aranges")
Addstring(shstrtab, elfRelType+".debug_line") Addstring(shstrtab, elfRelType+".debug_line")
Addstring(shstrtab, elfRelType+".debug_frame") Addstring(shstrtab, elfRelType+".debug_frame")
...@@ -1651,6 +1655,10 @@ func dwarfaddelfsectionsyms(ctxt *Link) { ...@@ -1651,6 +1655,10 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum) putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
sym = ctxt.Syms.Lookup(".debug_frame", 0) sym = ctxt.Syms.Lookup(".debug_frame", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum) 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) sym = ctxt.Syms.Lookup(".debug_ranges", 0)
if sym.Sect != nil { if sym.Sect != nil {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum) putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
......
...@@ -1808,7 +1808,7 @@ func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) { ...@@ -1808,7 +1808,7 @@ func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
continue continue
} }
if r.Xsym == nil { if r.Xsym == nil {
Errorf(sym, "missing xsym in relocation") Errorf(sym, "missing xsym in relocation %#v %#v", r.Sym.Name, sym)
continue continue
} }
if r.Xsym.ElfsymForReloc() == 0 { if r.Xsym.ElfsymForReloc() == 0 {
...@@ -2596,12 +2596,9 @@ elfobj: ...@@ -2596,12 +2596,9 @@ elfobj:
elfshreloc(sect) elfshreloc(sect)
} }
for _, s := range dwarfp { 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) elfshreloc(s.Sect)
} }
if s.Type == SDWARFINFO {
break
}
} }
// add a .note.GNU-stack section to mark the stack as non-executable // add a .note.GNU-stack section to mark the stack as non-executable
sh := elfshname(".note.GNU-stack") sh := elfshname(".note.GNU-stack")
......
...@@ -105,6 +105,7 @@ const ( ...@@ -105,6 +105,7 @@ const (
SDWARFSECT SDWARFSECT
SDWARFINFO SDWARFINFO
SDWARFRANGE SDWARFRANGE
SDWARFLOC
SSUB = SymKind(1 << 8) SSUB = SymKind(1 << 8)
SMASK = SymKind(SSUB - 1) SMASK = SymKind(SSUB - 1)
SHIDDEN = SymKind(1 << 9) SHIDDEN = SymKind(1 << 9)
...@@ -124,6 +125,7 @@ var abiSymKindToSymKind = [...]SymKind{ ...@@ -124,6 +125,7 @@ var abiSymKindToSymKind = [...]SymKind{
STLSBSS, STLSBSS,
SDWARFINFO, SDWARFINFO,
SDWARFRANGE, SDWARFRANGE,
SDWARFLOC,
} }
// readOnly are the symbol kinds that form read-only sections. In some // readOnly are the symbol kinds that form read-only sections. In some
......
...@@ -4,9 +4,9 @@ package ld ...@@ -4,9 +4,9 @@ package ld
import "fmt" 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 { func (i SymKind) String() string {
if i < 0 || i >= SymKind(len(_SymKind_index)-1) { 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