Commit 2ad41a30 authored by Alessandro Arzilli's avatar Alessandro Arzilli Committed by Matthew Dempsky

cmd/compile: output DWARF lexical blocks for local variables

Change compiler and linker to emit DWARF lexical blocks in .debug_info
section when compiling with -N -l.

Version of debug_info is updated from DWARF v2 to DWARF v3 since
version 2 does not allow lexical blocks with discontinuous PC ranges.

Remaining open problems:
- scope information is removed from inlined functions
- variables records do not have DW_AT_start_scope attributes so a
variable will shadow other variables with the same name as soon as its
containing scope begins, even before its declaration.

Updates #6913.
Updates #12899.

Change-Id: Idc6808788512ea20e7e45bcf782453acb416fb49
Reviewed-on: https://go-review.googlesource.com/40095
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 0f0a51f1
...@@ -5,19 +5,21 @@ ...@@ -5,19 +5,21 @@
package gc package gc
import ( import (
"cmd/compile/internal/syntax"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"fmt" "fmt"
) )
// function literals aka closures func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
func closurehdr(ntype *Node) { ntype := p.typeExpr(expr.Type)
n := nod(OCLOSURE, nil, nil)
n := p.nod(expr, OCLOSURE, nil, nil)
n.Func.SetIsHiddenClosure(Curfn != nil) n.Func.SetIsHiddenClosure(Curfn != nil)
n.Func.Ntype = ntype n.Func.Ntype = ntype
n.Func.Depth = funcdepth n.Func.Depth = funcdepth
n.Func.Outerfunc = Curfn n.Func.Outerfunc = Curfn
funchdr(n) old := p.funchdr(n, expr.Pos())
// steal ntype's argument names and // steal ntype's argument names and
// leave a fresh copy in their place. // leave a fresh copy in their place.
...@@ -25,8 +27,8 @@ func closurehdr(ntype *Node) { ...@@ -25,8 +27,8 @@ func closurehdr(ntype *Node) {
// refer to the variables in the external // refer to the variables in the external
// function declared below; see walkclosure. // function declared below; see walkclosure.
n.List.Set(ntype.List.Slice()) n.List.Set(ntype.List.Slice())
n.Rlist.Set(ntype.Rlist.Slice()) n.Rlist.Set(ntype.Rlist.Slice())
ntype.List.Set(nil) ntype.List.Set(nil)
ntype.Rlist.Set(nil) ntype.Rlist.Set(nil)
for _, n1 := range n.List.Slice() { for _, n1 := range n.List.Slice() {
...@@ -48,23 +50,23 @@ func closurehdr(ntype *Node) { ...@@ -48,23 +50,23 @@ func closurehdr(ntype *Node) {
} }
ntype.Rlist.Append(nod(ODCLFIELD, name, n2.Right)) ntype.Rlist.Append(nod(ODCLFIELD, name, n2.Right))
} }
}
func closurebody(body []*Node) *Node { body := p.stmts(expr.Body.List)
lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace)
if len(body) == 0 { if len(body) == 0 {
body = []*Node{nod(OEMPTY, nil, nil)} body = []*Node{nod(OEMPTY, nil, nil)}
} }
func_ := Curfn n.Nbody.Set(body)
func_.Nbody.Set(body) n.Func.Endlineno = lineno
func_.Func.Endlineno = lineno p.funcbody(n, expr.Body.Rbrace, old)
funcbody(func_)
// closure-specific variables are hanging off the // closure-specific variables are hanging off the
// ordinary ones in the symbol table; see oldname. // ordinary ones in the symbol table; see oldname.
// unhook them. // unhook them.
// make the list of pointers for the closure call. // make the list of pointers for the closure call.
for _, v := range func_.Func.Cvars.Slice() { for _, v := range n.Func.Cvars.Slice() {
// Unlink from v1; see comment in syntax.go type Param for these fields. // Unlink from v1; see comment in syntax.go type Param for these fields.
v1 := v.Name.Defn v1 := v.Name.Defn
v1.Name.Param.Innermost = v.Name.Param.Outer v1.Name.Param.Innermost = v.Name.Param.Outer
...@@ -100,7 +102,7 @@ func closurebody(body []*Node) *Node { ...@@ -100,7 +102,7 @@ func closurebody(body []*Node) *Node {
v.Name.Param.Outer = oldname(v.Sym) v.Name.Param.Outer = oldname(v.Sym)
} }
return func_ return n
} }
func typecheckclosure(func_ *Node, top int) { func typecheckclosure(func_ *Node, top int) {
...@@ -227,7 +229,11 @@ func makeclosure(func_ *Node) *Node { ...@@ -227,7 +229,11 @@ func makeclosure(func_ *Node) *Node {
xfunc.Nbody.Set(func_.Nbody.Slice()) xfunc.Nbody.Set(func_.Nbody.Slice())
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...) xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
xfunc.Func.Parents = func_.Func.Parents
xfunc.Func.Marks = func_.Func.Marks
func_.Func.Dcl = nil func_.Func.Dcl = nil
func_.Func.Parents = nil
func_.Func.Marks = nil
if xfunc.Nbody.Len() == 0 { if xfunc.Nbody.Len() == 0 {
Fatalf("empty body - won't generate any code") Fatalf("empty body - won't generate any code")
} }
......
...@@ -216,6 +216,9 @@ var flagDWARF bool ...@@ -216,6 +216,9 @@ var flagDWARF bool
// when the race detector is enabled. // when the race detector is enabled.
var instrumenting bool var instrumenting bool
// Whether we are tracking lexical scopes for DWARF.
var trackScopes bool
var debuglive int var debuglive int
var Ctxt *obj.Link var Ctxt *obj.Link
......
...@@ -380,6 +380,8 @@ func Main(archInit func(*Arch)) { ...@@ -380,6 +380,8 @@ func Main(archInit func(*Arch)) {
Debug['l'] = 1 - Debug['l'] Debug['l'] = 1 - Debug['l']
} }
trackScopes = flagDWARF && Debug['l'] == 0 && Debug['N'] != 0
Widthptr = thearch.LinkArch.PtrSize Widthptr = thearch.LinkArch.PtrSize
Widthreg = thearch.LinkArch.RegSize Widthreg = thearch.LinkArch.RegSize
......
...@@ -75,6 +75,62 @@ type noder struct { ...@@ -75,6 +75,62 @@ type noder struct {
linknames []linkname linknames []linkname
pragcgobuf string pragcgobuf string
err chan syntax.Error err chan syntax.Error
scope ScopeID
}
func (p *noder) funchdr(n *Node, pos src.Pos) ScopeID {
old := p.scope
p.scope = 0
funchdr(n)
return old
}
func (p *noder) funcbody(n *Node, pos src.Pos, old ScopeID) {
funcbody(n)
p.scope = old
}
func (p *noder) openScope(pos src.Pos) {
types.Markdcl()
if trackScopes {
Curfn.Func.Parents = append(Curfn.Func.Parents, p.scope)
p.scope = ScopeID(len(Curfn.Func.Parents))
p.markScope(pos)
}
}
func (p *noder) closeScope(pos src.Pos) {
types.Popdcl()
if trackScopes {
p.scope = Curfn.Func.Parents[p.scope-1]
p.markScope(pos)
}
}
func (p *noder) markScope(pos src.Pos) {
xpos := Ctxt.PosTable.XPos(pos)
if i := len(Curfn.Func.Marks); i > 0 && Curfn.Func.Marks[i-1].Pos == xpos {
Curfn.Func.Marks[i-1].Scope = p.scope
} else {
Curfn.Func.Marks = append(Curfn.Func.Marks, Mark{xpos, p.scope})
}
}
// closeAnotherScope is like closeScope, but it reuses the same mark
// position as the last closeScope call. This is useful for "for" and
// "if" statements, as their implicit blocks always end at the same
// position as an explicit block.
func (p *noder) closeAnotherScope() {
types.Popdcl()
if trackScopes {
p.scope = Curfn.Func.Parents[p.scope-1]
Curfn.Func.Marks[len(Curfn.Func.Marks)-1].Scope = p.scope
}
} }
// linkname records a //go:linkname directive. // linkname records a //go:linkname directive.
...@@ -326,8 +382,9 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { ...@@ -326,8 +382,9 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
declare(f.Func.Nname, PFUNC) declare(f.Func.Nname, PFUNC)
} }
funchdr(f) oldScope := p.funchdr(f, fun.Pos())
endPos := fun.Pos()
if fun.Body != nil { if fun.Body != nil {
if f.Noescape() { if f.Noescape() {
yyerrorl(f.Pos, "can only use //go:noescape with external func implementations") yyerrorl(f.Pos, "can only use //go:noescape with external func implementations")
...@@ -339,6 +396,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { ...@@ -339,6 +396,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
} }
f.Nbody.Set(body) f.Nbody.Set(body)
endPos = fun.Body.Rbrace
lineno = Ctxt.PosTable.XPos(fun.Body.Rbrace) lineno = Ctxt.PosTable.XPos(fun.Body.Rbrace)
f.Func.Endlineno = lineno f.Func.Endlineno = lineno
} else { } else {
...@@ -347,8 +405,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { ...@@ -347,8 +405,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
} }
} }
funcbody(f) p.funcbody(f, endPos, oldScope)
return f return f
} }
...@@ -439,10 +496,7 @@ func (p *noder) expr(expr syntax.Expr) *Node { ...@@ -439,10 +496,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
case *syntax.KeyValueExpr: case *syntax.KeyValueExpr:
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value))) return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit: case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type)) return p.funcLit(expr)
body := p.stmts(expr.Body.List)
lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace)
return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr: case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil) return p.nod(expr, OPAREN, p.expr(expr.X), nil)
case *syntax.SelectorExpr: case *syntax.SelectorExpr:
...@@ -774,14 +828,14 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node { ...@@ -774,14 +828,14 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
} }
func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node { func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
types.Markdcl() p.openScope(stmt.Pos())
nodes := p.stmts(stmt.List) nodes := p.stmts(stmt.List)
types.Popdcl() p.closeScope(stmt.Rbrace)
return nodes return nodes
} }
func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node { func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
types.Markdcl() p.openScope(stmt.Pos())
n := p.nod(stmt, OIF, nil, nil) n := p.nod(stmt, OIF, nil, nil)
if stmt.Init != nil { if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init)) n.Ninit.Set1(p.stmt(stmt.Init))
...@@ -798,12 +852,12 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node { ...@@ -798,12 +852,12 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
n.Rlist.Set1(e) n.Rlist.Set1(e)
} }
} }
types.Popdcl() p.closeAnotherScope()
return n return n
} }
func (p *noder) forStmt(stmt *syntax.ForStmt) *Node { func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
types.Markdcl() p.openScope(stmt.Pos())
var n *Node var n *Node
if r, ok := stmt.Init.(*syntax.RangeClause); ok { if r, ok := stmt.Init.(*syntax.RangeClause); ok {
if stmt.Cond != nil || stmt.Post != nil { if stmt.Cond != nil || stmt.Post != nil {
...@@ -832,12 +886,12 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node { ...@@ -832,12 +886,12 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
} }
} }
n.Nbody.Set(p.blockStmt(stmt.Body)) n.Nbody.Set(p.blockStmt(stmt.Body))
types.Popdcl() p.closeAnotherScope()
return n return n
} }
func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node { func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
types.Markdcl() p.openScope(stmt.Pos())
n := p.nod(stmt, OSWITCH, nil, nil) n := p.nod(stmt, OSWITCH, nil, nil)
if stmt.Init != nil { if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init)) n.Ninit.Set1(p.stmt(stmt.Init))
...@@ -850,18 +904,21 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node { ...@@ -850,18 +904,21 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
if tswitch != nil && (tswitch.Op != OTYPESW || tswitch.Left == nil) { if tswitch != nil && (tswitch.Op != OTYPESW || tswitch.Left == nil) {
tswitch = nil tswitch = nil
} }
n.List.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace))
n.List.Set(p.caseClauses(stmt.Body, tswitch)) p.closeScope(stmt.Rbrace)
types.Popdcl()
return n return n
} }
func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node { func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node, rbrace src.Pos) []*Node {
var nodes []*Node var nodes []*Node
for _, clause := range clauses { for i, clause := range clauses {
p.lineno(clause) p.lineno(clause)
types.Markdcl() if i > 0 {
p.closeScope(clause.Pos())
}
p.openScope(clause.Pos())
n := p.nod(clause, OXCASE, nil, nil) n := p.nod(clause, OXCASE, nil, nil)
if clause.Cases != nil { if clause.Cases != nil {
n.List.Set(p.exprList(clause.Cases)) n.List.Set(p.exprList(clause.Cases))
...@@ -875,32 +932,40 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node ...@@ -875,32 +932,40 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node
} }
n.Xoffset = int64(types.Block) n.Xoffset = int64(types.Block)
n.Nbody.Set(p.stmts(clause.Body)) n.Nbody.Set(p.stmts(clause.Body))
types.Popdcl()
nodes = append(nodes, n) nodes = append(nodes, n)
} }
if len(clauses) > 0 {
p.closeScope(rbrace)
}
return nodes return nodes
} }
func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node { func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node {
n := p.nod(stmt, OSELECT, nil, nil) n := p.nod(stmt, OSELECT, nil, nil)
n.List.Set(p.commClauses(stmt.Body)) n.List.Set(p.commClauses(stmt.Body, stmt.Rbrace))
return n return n
} }
func (p *noder) commClauses(clauses []*syntax.CommClause) []*Node { func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace src.Pos) []*Node {
var nodes []*Node var nodes []*Node
for _, clause := range clauses { for i, clause := range clauses {
p.lineno(clause) p.lineno(clause)
types.Markdcl() if i > 0 {
p.closeScope(clause.Pos())
}
p.openScope(clause.Pos())
n := p.nod(clause, OXCASE, nil, nil) n := p.nod(clause, OXCASE, nil, nil)
if clause.Comm != nil { if clause.Comm != nil {
n.List.Set1(p.stmt(clause.Comm)) n.List.Set1(p.stmt(clause.Comm))
} }
n.Xoffset = int64(types.Block) n.Xoffset = int64(types.Block)
n.Nbody.Set(p.stmts(clause.Body)) n.Nbody.Set(p.stmts(clause.Body))
types.Popdcl()
nodes = append(nodes, n) nodes = append(nodes, n)
} }
if len(clauses) > 0 {
p.closeScope(rbrace)
}
return nodes return nodes
} }
......
...@@ -299,13 +299,15 @@ func compileFunctions() { ...@@ -299,13 +299,15 @@ func compileFunctions() {
} }
} }
func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var { func debuginfo(fnsym *obj.LSym, curfn interface{}) []dwarf.Scope {
fn := curfn.(*Node) fn := curfn.(*Node)
if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect { if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
Fatalf("unexpected fnsym: %v != %v", fnsym, expect) Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
} }
var vars []*dwarf.Var var dwarfVars []*dwarf.Var
var varScopes []ScopeID
for _, n := range fn.Func.Dcl { for _, n := range fn.Func.Dcl {
if n.Op != ONAME { // might be OTYPE or OLITERAL if n.Op != ONAME { // might be OTYPE or OLITERAL
continue continue
...@@ -353,18 +355,26 @@ func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var { ...@@ -353,18 +355,26 @@ func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var {
} }
typename := dwarf.InfoPrefix + gotype.Name[len("type."):] typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
vars = append(vars, &dwarf.Var{ dwarfVars = append(dwarfVars, &dwarf.Var{
Name: n.Sym.Name, Name: n.Sym.Name,
Abbrev: abbrev, Abbrev: abbrev,
Offset: int32(offs), Offset: int32(offs),
Type: Ctxt.Lookup(typename), Type: Ctxt.Lookup(typename),
}) })
}
// Stable sort so that ties are broken with declaration order. var scope ScopeID
sort.Stable(dwarf.VarsByOffset(vars)) if !n.Name.Captured() && !n.Name.Byval() {
// n.Pos of captured variables is their first
// use in the closure but they should always
// be assigned to scope 0 instead.
// TODO(mdempsky): Verify this.
scope = findScope(fn.Func.Marks, n.Pos)
}
varScopes = append(varScopes, scope)
}
return vars return assembleScopes(fnsym, fn, dwarfVars, varScopes)
} }
// fieldtrack adds R_USEFIELD relocations to fnsym to record any // fieldtrack adds R_USEFIELD relocations to fnsym to record any
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gc
import (
"cmd/internal/dwarf"
"cmd/internal/obj"
"cmd/internal/src"
"sort"
)
// See golang.org/issue/20390.
func xposBefore(p, q src.XPos) bool {
return Ctxt.PosTable.Pos(p).Before(Ctxt.PosTable.Pos(q))
}
func findScope(marks []Mark, pos src.XPos) ScopeID {
i := sort.Search(len(marks), func(i int) bool {
return xposBefore(pos, marks[i].Pos)
})
if i == 0 {
return 0
}
return marks[i-1].Scope
}
func assembleScopes(fnsym *obj.LSym, fn *Node, dwarfVars []*dwarf.Var, varScopes []ScopeID) []dwarf.Scope {
// Initialize the DWARF scope tree based on lexical scopes.
dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents))
for i, parent := range fn.Func.Parents {
dwarfScopes[i+1].Parent = int32(parent)
}
scopeVariables(dwarfVars, varScopes, dwarfScopes)
scopePCs(fnsym, fn.Func.Marks, dwarfScopes)
return compactScopes(dwarfScopes)
}
// scopeVariables assigns DWARF variable records to their scopes.
func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ScopeID, dwarfScopes []dwarf.Scope) {
sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes})
i0 := 0
for i := range dwarfVars {
if varScopes[i] == varScopes[i0] {
continue
}
dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:i]
i0 = i
}
if i0 < len(dwarfVars) {
dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:]
}
}
// A scopedPCs represents a non-empty half-open interval of PCs that
// share a common source position.
type scopedPCs struct {
start, end int64
pos src.XPos
scope ScopeID
}
// scopePCs assigns PC ranges to their scopes.
func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
// If there aren't any child scopes (in particular, when scope
// tracking is disabled), we can skip a whole lot of work.
if len(marks) == 0 {
return
}
// Break function text into scopedPCs.
var pcs []scopedPCs
p0 := fnsym.Func.Text
for p := fnsym.Func.Text; p != nil; p = p.Link {
if p.Pos == p0.Pos {
continue
}
if p0.Pc < p.Pc {
pcs = append(pcs, scopedPCs{start: p0.Pc, end: p.Pc, pos: p0.Pos})
}
p0 = p
}
if p0.Pc < fnsym.Size {
pcs = append(pcs, scopedPCs{start: p0.Pc, end: fnsym.Size, pos: p0.Pos})
}
// Sort PCs by source position, and walk in parallel with
// scope marks to assign a lexical scope to each PC interval.
sort.Sort(pcsByPos(pcs))
var marki int
var scope ScopeID
for i := range pcs {
for marki < len(marks) && !xposBefore(pcs[i].pos, marks[marki].Pos) {
scope = marks[marki].Scope
marki++
}
pcs[i].scope = scope
}
// Re-sort to create sorted PC ranges for each DWARF scope.
sort.Sort(pcsByPC(pcs))
for _, pc := range pcs {
r := &dwarfScopes[pc.scope].Ranges
if i := len(*r); i > 0 && (*r)[i-1].End == pc.start {
(*r)[i-1].End = pc.end
} else {
*r = append(*r, dwarf.Range{Start: pc.start, End: pc.end})
}
}
}
func compactScopes(dwarfScopes []dwarf.Scope) []dwarf.Scope {
// Forward pass to collapse empty scopes into parents.
remap := make([]int32, len(dwarfScopes))
j := int32(1)
for i := 1; i < len(dwarfScopes); i++ {
s := &dwarfScopes[i]
s.Parent = remap[s.Parent]
if len(s.Vars) == 0 {
dwarfScopes[s.Parent].UnifyRanges(s)
remap[i] = s.Parent
continue
}
remap[i] = j
dwarfScopes[j] = *s
j++
}
dwarfScopes = dwarfScopes[:j]
// Reverse pass to propagate PC ranges to parent scopes.
for i := len(dwarfScopes) - 1; i > 0; i-- {
s := &dwarfScopes[i]
dwarfScopes[s.Parent].UnifyRanges(s)
}
return dwarfScopes
}
type pcsByPC []scopedPCs
func (s pcsByPC) Len() int { return len(s) }
func (s pcsByPC) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s pcsByPC) Less(i, j int) bool {
return s[i].start < s[j].start
}
type pcsByPos []scopedPCs
func (s pcsByPos) Len() int { return len(s) }
func (s pcsByPos) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s pcsByPos) Less(i, j int) bool {
return xposBefore(s[i].pos, s[j].pos)
}
type varsByScopeAndOffset struct {
vars []*dwarf.Var
scopes []ScopeID
}
func (v varsByScopeAndOffset) Len() int {
return len(v.vars)
}
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
}
func (v varsByScopeAndOffset) Swap(i, j int) {
v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
v.scopes[i], v.scopes[j] = v.scopes[j], v.scopes[i]
}
This diff is collapsed.
...@@ -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{}, 100, 168}, {Func{}, 124, 216},
{Name{}, 36, 56}, {Name{}, 36, 56},
{Param{}, 28, 56}, {Param{}, 28, 56},
{Node{}, 76, 128}, {Node{}, 76, 128},
......
...@@ -351,12 +351,21 @@ type Param struct { ...@@ -351,12 +351,21 @@ type Param struct {
// Func holds Node fields used only with function-like nodes. // Func holds Node fields used only with function-like nodes.
type Func struct { type Func struct {
Shortname *types.Sym Shortname *types.Sym
Enter Nodes // for example, allocate and initialize memory for escaping parameters Enter Nodes // for example, allocate and initialize memory for escaping parameters
Exit Nodes Exit Nodes
Cvars Nodes // closure params Cvars Nodes // closure params
Dcl []*Node // autodcl for this func/closure Dcl []*Node // autodcl for this func/closure
Inldcl Nodes // copy of dcl for use in inlining Inldcl Nodes // copy of dcl for use in inlining
// Parents records the parent scope of each scope within a
// function. The root scope (0) has no parent, so the i'th
// scope's parent is stored at Parents[i-1].
Parents []ScopeID
// Marks records scope boundary changes.
Marks []Mark
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{}
...@@ -380,6 +389,19 @@ type Func struct { ...@@ -380,6 +389,19 @@ type Func struct {
flags bitset8 flags bitset8
} }
// A Mark represents a scope boundary.
type Mark struct {
// Pos is the position of the token that marks the scope
// change.
Pos src.XPos
// Scope identifies the innermost scope to the right of Pos.
Scope ScopeID
}
// A ScopeID represents a lexical scope within a function.
type ScopeID int32
const ( const (
funcDupok = 1 << iota // duplicate definitions ok funcDupok = 1 << iota // duplicate definitions ok
funcWrapper // is method wrapper funcWrapper // is method wrapper
......
...@@ -8,14 +8,19 @@ ...@@ -8,14 +8,19 @@
package dwarf package dwarf
import ( import (
"errors"
"fmt" "fmt"
) )
// 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 range lists.
const RangePrefix = "go.range."
// Sym represents a symbol. // Sym represents a symbol.
type Sym interface { type Sym interface {
Len() int64
} }
// A Var represents a local variable or a function parameter. // A Var represents a local variable or a function parameter.
...@@ -23,9 +28,62 @@ type Var struct { ...@@ -23,9 +28,62 @@ 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 Offset int32
Scope int32
Type Sym Type Sym
} }
// A Scope represents a lexical scope. All variables declared within a
// scope will only be visible to instructions covered by the scope.
// Lexical scopes are contiguous in source files but can end up being
// compiled to discontiguous blocks of instructions in the executable.
// The Ranges field lists all the blocks of instructions that belong
// in this scope.
type Scope struct {
Parent int32
Ranges []Range
Vars []*Var
}
// A Range represents a half-open interval [Start, End).
type Range struct {
Start, End int64
}
// UnifyRanges merges the list of ranges of c into the list of ranges of s
func (s *Scope) UnifyRanges(c *Scope) {
out := make([]Range, 0, len(s.Ranges)+len(c.Ranges))
i, j := 0, 0
for {
var cur Range
if i < len(s.Ranges) && j < len(c.Ranges) {
if s.Ranges[i].Start < c.Ranges[j].Start {
cur = s.Ranges[i]
i++
} else {
cur = c.Ranges[j]
j++
}
} else if i < len(s.Ranges) {
cur = s.Ranges[i]
i++
} else if j < len(c.Ranges) {
cur = c.Ranges[j]
j++
} else {
break
}
if n := len(out); n > 0 && cur.Start <= out[n-1].End {
out[n-1].End = cur.End
} else {
out = append(out, cur)
}
}
s.Ranges = out
}
// A Context specifies how to add data to a Sym. // A Context specifies how to add data to a Sym.
type Context interface { type Context interface {
PtrSize() int PtrSize() int
...@@ -156,6 +214,8 @@ const ( ...@@ -156,6 +214,8 @@ const (
DW_ABRV_VARIABLE DW_ABRV_VARIABLE
DW_ABRV_AUTO DW_ABRV_AUTO
DW_ABRV_PARAM DW_ABRV_PARAM
DW_ABRV_LEXICAL_BLOCK_RANGES
DW_ABRV_LEXICAL_BLOCK_SIMPLE
DW_ABRV_STRUCTFIELD DW_ABRV_STRUCTFIELD
DW_ABRV_FUNCTYPEPARAM DW_ABRV_FUNCTYPEPARAM
DW_ABRV_DOTDOTDOT DW_ABRV_DOTDOTDOT
...@@ -247,6 +307,25 @@ var abbrevs = [DW_NABRV]dwAbbrev{ ...@@ -247,6 +307,25 @@ var abbrevs = [DW_NABRV]dwAbbrev{
}, },
}, },
/* LEXICAL_BLOCK_RANGES */
{
DW_TAG_lexical_block,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_ranges, DW_FORM_data4}, // replace with DW_FORM_sec_offset in DWARFv4.
},
},
/* LEXICAL_BLOCK_SIMPLE */
{
DW_TAG_lexical_block,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_low_pc, DW_FORM_addr},
{DW_AT_high_pc, DW_FORM_addr},
},
},
/* STRUCTFIELD */ /* STRUCTFIELD */
{ {
DW_TAG_member, DW_TAG_member,
...@@ -525,8 +604,8 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da ...@@ -525,8 +604,8 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
ctxt.AddInt(s, 2, value) ctxt.AddInt(s, 2, value)
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
if cls == DW_CLS_PTR { // DW_AT_stmt_list if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges
ctxt.AddSectionOffset(s, 4, data, 0) ctxt.AddSectionOffset(s, 4, data, value)
break break
} }
ctxt.AddInt(s, 4, value) ctxt.AddInt(s, 4, value)
...@@ -555,15 +634,13 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da ...@@ -555,15 +634,13 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
ctxt.AddInt(s, 1, 0) ctxt.AddInt(s, 1, 0)
} }
// In DWARF 2 (which is what we claim to generate), // In DWARF 3 the ref_addr is always 32 bits, unless emitting a large
// the ref_addr is the same size as a normal address.
// In DWARF 3 it is always 32 bits, unless emitting a large
// (> 4 GB of debug info aka "64-bit") unit, which we don't implement. // (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
case DW_FORM_ref_addr: // reference to a DIE in the .info section case DW_FORM_ref_addr: // reference to a DIE in the .info section
if data == nil { if data == nil {
return fmt.Errorf("dwarf: null reference in %d", abbrev) return fmt.Errorf("dwarf: null reference in %d", abbrev)
} else { } else {
ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, 0) ctxt.AddSectionOffset(s, 4, data, 0)
} }
case DW_FORM_ref1, // reference within the compilation unit case DW_FORM_ref1, // reference within the compilation unit
...@@ -606,7 +683,7 @@ func HasChildren(die *DWDie) bool { ...@@ -606,7 +683,7 @@ 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 Sym, name string, external bool, startPC Sym, size int64, vars []*Var) { func PutFunc(ctxt Context, s, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
Uleb128put(ctxt, s, DW_ABRV_FUNCTION) 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_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, 0, startPC)
...@@ -616,29 +693,67 @@ func PutFunc(ctxt Context, s Sym, name string, external bool, startPC Sym, size ...@@ -616,29 +693,67 @@ func PutFunc(ctxt Context, s Sym, name string, external bool, startPC Sym, size
ev = 1 ev = 1
} }
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0) putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
names := make(map[string]bool) if len(scopes) > 0 {
var encbuf [20]byte var encbuf [20]byte
for _, v := range vars { if putscope(ctxt, s, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
var n string return errors.New("multiple toplevel scopes")
if names[v.Name] {
n = fmt.Sprintf("%s#%d", v.Name, len(names))
} else {
n = v.Name
}
names[n] = true
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)
} }
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)
} }
Uleb128put(ctxt, s, 0) Uleb128put(ctxt, s, 0)
return nil
}
func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
for _, v := range scopes[curscope].Vars {
putvar(ctxt, s, v, encbuf)
}
this := curscope
curscope++
for curscope < int32(len(scopes)) {
scope := scopes[curscope]
if scope.Parent != this {
return curscope
}
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)
} else {
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_data4, DW_CLS_PTR, ranges.Len(), ranges)
ctxt.AddAddress(ranges, nil, -1)
ctxt.AddAddress(ranges, startPC, 0)
for _, r := range scope.Ranges {
ctxt.AddAddress(ranges, nil, r.Start)
ctxt.AddAddress(ranges, nil, r.End)
}
ctxt.AddAddress(ranges, nil, 0)
ctxt.AddAddress(ranges, nil, 0)
}
curscope = putscope(ctxt, s, ranges, startPC, curscope, scopes, encbuf)
Uleb128put(ctxt, s, 0)
}
return curscope
}
func putvar(ctxt Context, s Sym, v *Var, 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)
}
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)
} }
// VarsByOffset attaches the methods of sort.Interface to []*Var, // VarsByOffset attaches the methods of sort.Interface to []*Var,
......
...@@ -120,7 +120,8 @@ func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) { ...@@ -120,7 +120,8 @@ func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
// WriteAddr writes an address of size siz into s at offset off. // WriteAddr writes an address of size siz into s at offset off.
// rsym and roff specify the relocation for the address. // rsym and roff specify the relocation for the address.
func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) { func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
if siz != ctxt.Arch.PtrSize { // Allow 4-byte addresses for DWARF.
if siz != ctxt.Arch.PtrSize && siz != 4 {
ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name) ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
} }
s.prepwrite(ctxt, off, siz) s.prepwrite(ctxt, off, siz)
......
...@@ -324,12 +324,15 @@ type LSym struct { ...@@ -324,12 +324,15 @@ type LSym struct {
// A FuncInfo contains extra fields for STEXT symbols. // A FuncInfo contains extra fields for STEXT symbols.
type FuncInfo struct { type FuncInfo struct {
Args int32 Args int32
Locals int32 Locals int32
Text *Prog Text *Prog
Autom []*Auto Autom []*Auto
Pcln Pcln Pcln Pcln
dwarfSym *LSym
dwarfSym *LSym
dwarfRangesSym *LSym
GCArgs LSym GCArgs LSym
GCLocals LSym GCLocals LSym
} }
...@@ -490,7 +493,7 @@ type Link struct { ...@@ -490,7 +493,7 @@ type Link struct {
InlTree InlTree // global inlining tree used by gc/inl.go InlTree InlTree // global inlining tree used by gc/inl.go
Imports []string Imports []string
DiagFunc func(string, ...interface{}) DiagFunc func(string, ...interface{})
DebugInfo func(fn *LSym, curfn interface{}) []*dwarf.Var // if non-nil, curfn is a *gc.Node DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
Errors int Errors int
Framepointer_enabled bool Framepointer_enabled bool
......
...@@ -447,10 +447,14 @@ func (c dwCtxt) SymValue(s dwarf.Sym) int64 { ...@@ -447,10 +447,14 @@ func (c dwCtxt) SymValue(s dwarf.Sym) int64 {
return 0 return 0
} }
func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
rsym := data.(*LSym)
ls := s.(*LSym) ls := s.(*LSym)
size := c.PtrSize() size := c.PtrSize()
ls.WriteAddr(c.Link, ls.Size, size, rsym, value) if data != nil {
rsym := data.(*LSym)
ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
} else {
ls.WriteInt(c.Link, ls.Size, size, value)
}
} }
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
ls := s.(*LSym) ls := s.(*LSym)
...@@ -460,27 +464,35 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64 ...@@ -460,27 +464,35 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
r.Type = objabi.R_DWARFREF r.Type = objabi.R_DWARFREF
} }
// dwarfSym returns the DWARF symbol for TEXT symbol. // dwarfSym returns the DWARF symbols for TEXT symbol.
func (ctxt *Link) dwarfSym(s *LSym) *LSym { func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, 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.dwarfSym == nil {
s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name) s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
} }
return s.Func.dwarfSym return s.Func.dwarfSym, s.Func.dwarfRangesSym
} }
// populateDWARF fills in the DWARF Debugging Information Entry for TEXT symbol s. func (s *LSym) Len() int64 {
// The DWARF symbol must already have been initialized in InitTextSym. return s.Size
}
// 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) { func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
dsym := ctxt.dwarfSym(s) dsym, drsym := ctxt.dwarfSym(s)
if dsym.Size != 0 { if dsym.Size != 0 {
ctxt.Diag("makeFuncDebugEntry double process %v", s) ctxt.Diag("makeFuncDebugEntry double process %v", s)
} }
var vars []*dwarf.Var var scopes []dwarf.Scope
if ctxt.DebugInfo != nil { if ctxt.DebugInfo != nil {
vars = ctxt.DebugInfo(s, curfn) scopes = ctxt.DebugInfo(s, curfn)
}
err := dwarf.PutFunc(dwCtxt{ctxt}, dsym, drsym, s.Name, !s.Static(), s, s.Size, scopes)
if err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
} }
dwarf.PutFunc(dwCtxt{ctxt}, dsym, s.Name, !s.Static(), s, s.Size, vars)
} }
...@@ -135,11 +135,14 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) { ...@@ -135,11 +135,14 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
s.Type = objabi.STEXT s.Type = objabi.STEXT
ctxt.Text = append(ctxt.Text, s) ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entry for s. // Set up DWARF entries for s.
dsym := ctxt.dwarfSym(s) dsym, drsym := ctxt.dwarfSym(s)
dsym.Type = objabi.SDWARFINFO dsym.Type = objabi.SDWARFINFO
dsym.Set(AttrDuplicateOK, s.DuplicateOK()) 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, dsym)
ctxt.Data = append(ctxt.Data, drsym)
// 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.
......
...@@ -56,4 +56,5 @@ const ( ...@@ -56,4 +56,5 @@ const (
STLSBSS STLSBSS
// Debugging data // Debugging data
SDWARFINFO SDWARFINFO
SDWARFRANGE
) )
...@@ -4,9 +4,9 @@ package objabi ...@@ -4,9 +4,9 @@ package objabi
import "fmt" import "fmt"
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFO" const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGE"
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61} var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72}
func (i SymKind) String() string { func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) { if i >= SymKind(len(_SymKind_index)-1) {
......
...@@ -574,9 +574,18 @@ func relocsym(ctxt *Link, s *Symbol) { ...@@ -574,9 +574,18 @@ func relocsym(ctxt *Link, s *Symbol) {
} }
case objabi.R_DWARFREF: case objabi.R_DWARFREF:
if r.Sym.Sect == nil { 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:
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name) Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
} }
if Linkmode == LinkExternal { if Linkmode == LinkExternal {
r.Done = 0 r.Done = 0
// PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL
...@@ -588,8 +597,9 @@ func relocsym(ctxt *Link, s *Symbol) { ...@@ -588,8 +597,9 @@ func relocsym(ctxt *Link, s *Symbol) {
r.Type = objabi.R_ADDR r.Type = objabi.R_ADDR
} }
r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0) r.Xsym = ctxt.Syms.ROLookup(sectName, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) r.Xadd = r.Add + Symaddr(r.Sym) - vaddr
o = r.Xadd o = r.Xadd
rs = r.Xsym rs = r.Xsym
if Iself && SysArch.Family == sys.AMD64 { if Iself && SysArch.Family == sys.AMD64 {
...@@ -597,7 +607,7 @@ func relocsym(ctxt *Link, s *Symbol) { ...@@ -597,7 +607,7 @@ func relocsym(ctxt *Link, s *Symbol) {
} }
break break
} }
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr) o = Symaddr(r.Sym) + r.Add - vaddr
case objabi.R_WEAKADDROFF: case objabi.R_WEAKADDROFF:
if !r.Sym.Attr.Reachable() { if !r.Sym.Attr.Reachable() {
...@@ -1821,6 +1831,7 @@ func (ctxt *Link) dodata() { ...@@ -1821,6 +1831,7 @@ func (ctxt *Link) dodata() {
if s.Type != SDWARFSECT { if s.Type != SDWARFSECT {
break break
} }
sect = addsection(&Segdwarf, s.Name, 04) sect = addsection(&Segdwarf, s.Name, 04)
sect.Align = 1 sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align)) datsize = Rnd(datsize, int64(sect.Align))
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
// - assign global variables and types to their packages // - assign global variables and types to their packages
// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg // - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
// ptype struct '[]uint8' and qualifiers need to be quoted away // ptype struct '[]uint8' and qualifiers need to be quoted away
// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
// - file:line info for variables // - file:line info for variables
// - make strings a typedef so prettyprinters can see the underlying string type // - make strings a typedef so prettyprinters can see the underlying string type
...@@ -76,6 +75,7 @@ var arangessec *Symbol ...@@ -76,6 +75,7 @@ var arangessec *Symbol
var framesec *Symbol var framesec *Symbol
var infosec *Symbol var infosec *Symbol
var linesec *Symbol var linesec *Symbol
var rangesec *Symbol
var gdbscript string var gdbscript string
...@@ -1291,6 +1291,33 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol { ...@@ -1291,6 +1291,33 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
return syms return syms
} }
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]
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)
}
rangesec.Size += rangeSym.Size
}
if rangesec.Size > 0 {
// PE does not like empty sections
syms = append(syms, rangesec)
}
return syms
}
/* /*
* Walk DWarfDebugInfoEntries, and emit .debug_info * Walk DWarfDebugInfoEntries, and emit .debug_info
*/ */
...@@ -1321,7 +1348,7 @@ func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol { ...@@ -1321,7 +1348,7 @@ func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
// Fields marked with (*) must be changed for 64-bit dwarf // Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above. // This must match COMPUNITHEADERSIZE above.
Adduint32(ctxt, s, 0) // unit_length (*), will be filled in later. Adduint32(ctxt, s, 0) // unit_length (*), will be filled in later.
Adduint16(ctxt, s, 2) // dwarf version (appendix F) Adduint16(ctxt, s, 3) // dwarf version (appendix F)
// debug_abbrev_offset (*) // debug_abbrev_offset (*)
adddwarfref(ctxt, s, abbrevsym, 4) adddwarfref(ctxt, s, abbrevsym, 4)
...@@ -1553,6 +1580,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) { ...@@ -1553,6 +1580,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
syms := writeabbrev(ctxt, nil) syms := writeabbrev(ctxt, nil)
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)
...@@ -1594,6 +1622,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) { ...@@ -1594,6 +1622,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_pubnames") Addstring(shstrtab, ".debug_pubnames")
Addstring(shstrtab, ".debug_pubtypes") Addstring(shstrtab, ".debug_pubtypes")
Addstring(shstrtab, ".debug_gdb_scripts") Addstring(shstrtab, ".debug_gdb_scripts")
Addstring(shstrtab, ".debug_ranges")
if Linkmode == LinkExternal { if Linkmode == LinkExternal {
Addstring(shstrtab, elfRelType+".debug_info") Addstring(shstrtab, elfRelType+".debug_info")
Addstring(shstrtab, elfRelType+".debug_aranges") Addstring(shstrtab, elfRelType+".debug_aranges")
...@@ -1601,6 +1630,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) { ...@@ -1601,6 +1630,7 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, elfRelType+".debug_frame") Addstring(shstrtab, elfRelType+".debug_frame")
Addstring(shstrtab, elfRelType+".debug_pubnames") Addstring(shstrtab, elfRelType+".debug_pubnames")
Addstring(shstrtab, elfRelType+".debug_pubtypes") Addstring(shstrtab, elfRelType+".debug_pubtypes")
Addstring(shstrtab, elfRelType+".debug_ranges")
} }
} }
...@@ -1621,6 +1651,10 @@ func dwarfaddelfsectionsyms(ctxt *Link) { ...@@ -1621,6 +1651,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_ranges", 0)
if sym.Sect != nil {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
}
} }
/* /*
......
...@@ -89,6 +89,10 @@ func (s *Symbol) ElfsymForReloc() int32 { ...@@ -89,6 +89,10 @@ func (s *Symbol) ElfsymForReloc() int32 {
} }
} }
func (s *Symbol) Len() int64 {
return s.Size
}
// Attribute is a set of common symbol attributes. // Attribute is a set of common symbol attributes.
type Attribute int16 type Attribute int16
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ld
import (
"internal/testenv"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
)
func TestNooptCgoBuild(t *testing.T) {
testenv.MustHaveGoBuild(t)
testenv.MustHaveCGO(t)
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
cmd := exec.Command("go", "build", "-gcflags=-N -l", "-o", filepath.Join(dir, "a.out"))
cmd.Dir = filepath.Join(runtime.GOROOT(), "src", "runtime", "testdata", "testprogcgo")
out, err := cmd.CombinedOutput()
if err != nil {
t.Logf("go build output: %s", out)
t.Fatal(err)
}
}
...@@ -104,6 +104,7 @@ const ( ...@@ -104,6 +104,7 @@ const (
SHOSTOBJ SHOSTOBJ
SDWARFSECT SDWARFSECT
SDWARFINFO SDWARFINFO
SDWARFRANGE
SSUB = SymKind(1 << 8) SSUB = SymKind(1 << 8)
SMASK = SymKind(SSUB - 1) SMASK = SymKind(SSUB - 1)
SHIDDEN = SymKind(1 << 9) SHIDDEN = SymKind(1 << 9)
...@@ -122,6 +123,7 @@ var abiSymKindToSymKind = [...]SymKind{ ...@@ -122,6 +123,7 @@ var abiSymKindToSymKind = [...]SymKind{
SNOPTRBSS, SNOPTRBSS,
STLSBSS, STLSBSS,
SDWARFINFO, SDWARFINFO,
SDWARFRANGE,
} }
// 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 = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFO" const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGE"
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} 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}
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