mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: output DWARF lexical blocks for local variables
Change compiler and linker to emit DWARF lexical blocks in debug_info. Version of debug_info is updated from DWARF v.2 to DWARF v.3 since version 2 does not allow lexical blocks with discontinuous ranges. Second attempt at https://go-review.googlesource.com/#/c/29591/ Remaining open problems: - scope information is removed from inlined functions - variables in debug_info 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, before its declaration. Updates golang/go#12899, golang/go#6913 Change-Id: I0e260a45b564d14a87b88974eb16c5387cb410a5 Reviewed-on: https://go-review.googlesource.com/36879 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
7165bcc6ba
commit
c8b889cc48
21 changed files with 890 additions and 110 deletions
|
|
@ -6,6 +6,7 @@ package gc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/src"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -191,7 +192,7 @@ func genhash(sym *types.Sym, t *types.Type) {
|
||||||
|
|
||||||
lineno = autogeneratedPos // less confusing than end of input
|
lineno = autogeneratedPos // less confusing than end of input
|
||||||
dclcontext = PEXTERN
|
dclcontext = PEXTERN
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
|
|
||||||
// func sym(p *T, h uintptr) uintptr
|
// func sym(p *T, h uintptr) uintptr
|
||||||
fn := nod(ODCLFUNC, nil, nil)
|
fn := nod(ODCLFUNC, nil, nil)
|
||||||
|
|
@ -210,7 +211,7 @@ func genhash(sym *types.Sym, t *types.Type) {
|
||||||
n = anonfield(types.Types[TUINTPTR]) // return value
|
n = anonfield(types.Types[TUINTPTR]) // return value
|
||||||
tfn.Rlist.Append(n)
|
tfn.Rlist.Append(n)
|
||||||
|
|
||||||
funchdr(fn)
|
funchdr(fn, src.NoPos)
|
||||||
fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
|
fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
|
||||||
|
|
||||||
// genhash is only called for types that have equality but
|
// genhash is only called for types that have equality but
|
||||||
|
|
@ -299,13 +300,13 @@ func genhash(sym *types.Sym, t *types.Type) {
|
||||||
dumplist("genhash body", fn.Nbody)
|
dumplist("genhash body", fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
funcbody(fn)
|
funcbody(fn, src.NoPos)
|
||||||
Curfn = fn
|
Curfn = fn
|
||||||
fn.Func.SetDupok(true)
|
fn.Func.SetDupok(true)
|
||||||
fn = typecheck(fn, Etop)
|
fn = typecheck(fn, Etop)
|
||||||
typecheckslice(fn.Nbody.Slice(), Etop)
|
typecheckslice(fn.Nbody.Slice(), Etop)
|
||||||
|
popdcl(src.NoPos)
|
||||||
Curfn = nil
|
Curfn = nil
|
||||||
popdcl()
|
|
||||||
if debug_dclstack != 0 {
|
if debug_dclstack != 0 {
|
||||||
testdclstack()
|
testdclstack()
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +370,7 @@ func geneq(sym *types.Sym, t *types.Type) {
|
||||||
|
|
||||||
lineno = autogeneratedPos // less confusing than end of input
|
lineno = autogeneratedPos // less confusing than end of input
|
||||||
dclcontext = PEXTERN
|
dclcontext = PEXTERN
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
|
|
||||||
// func sym(p, q *T) bool
|
// func sym(p, q *T) bool
|
||||||
fn := nod(ODCLFUNC, nil, nil)
|
fn := nod(ODCLFUNC, nil, nil)
|
||||||
|
|
@ -388,7 +389,7 @@ func geneq(sym *types.Sym, t *types.Type) {
|
||||||
n = anonfield(types.Types[TBOOL])
|
n = anonfield(types.Types[TBOOL])
|
||||||
tfn.Rlist.Append(n)
|
tfn.Rlist.Append(n)
|
||||||
|
|
||||||
funchdr(fn)
|
funchdr(fn, src.NoPos)
|
||||||
fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
|
fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
|
||||||
|
|
||||||
// geneq is only called for types that have equality but
|
// geneq is only called for types that have equality but
|
||||||
|
|
@ -491,13 +492,13 @@ func geneq(sym *types.Sym, t *types.Type) {
|
||||||
dumplist("geneq body", fn.Nbody)
|
dumplist("geneq body", fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
funcbody(fn)
|
funcbody(fn, src.NoPos)
|
||||||
Curfn = fn
|
Curfn = fn
|
||||||
fn.Func.SetDupok(true)
|
fn.Func.SetDupok(true)
|
||||||
fn = typecheck(fn, Etop)
|
fn = typecheck(fn, Etop)
|
||||||
typecheckslice(fn.Nbody.Slice(), Etop)
|
typecheckslice(fn.Nbody.Slice(), Etop)
|
||||||
|
popdcl(src.NoPos)
|
||||||
Curfn = nil
|
Curfn = nil
|
||||||
popdcl()
|
|
||||||
if debug_dclstack != 0 {
|
if debug_dclstack != 0 {
|
||||||
testdclstack()
|
testdclstack()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ func Import(imp *types.Pkg, in *bufio.Reader) {
|
||||||
|
|
||||||
if f := p.funcList[i]; f != nil {
|
if f := p.funcList[i]; f != nil {
|
||||||
// function not yet imported - read body and set it
|
// function not yet imported - read body and set it
|
||||||
funchdr(f)
|
funchdr(f, src.NoPos)
|
||||||
body := p.stmtList()
|
body := p.stmtList()
|
||||||
if body == nil {
|
if body == nil {
|
||||||
// Make sure empty body is not interpreted as
|
// Make sure empty body is not interpreted as
|
||||||
|
|
@ -198,7 +198,7 @@ func Import(imp *types.Pkg, in *bufio.Reader) {
|
||||||
body = []*Node{nod(OEMPTY, nil, nil)}
|
body = []*Node{nod(OEMPTY, nil, nil)}
|
||||||
}
|
}
|
||||||
f.Func.Inl.Set(body)
|
f.Func.Inl.Set(body)
|
||||||
funcbody(f)
|
funcbody(f, src.NoPos)
|
||||||
} else {
|
} else {
|
||||||
// function already imported - read body but discard declarations
|
// function already imported - read body but discard declarations
|
||||||
dclcontext = PDISCARD // throw away any declarations
|
dclcontext = PDISCARD // throw away any declarations
|
||||||
|
|
@ -1091,54 +1091,54 @@ func (p *importer) node() *Node {
|
||||||
return nodl(p.pos(), op, p.expr(), nil)
|
return nodl(p.pos(), op, p.expr(), nil)
|
||||||
|
|
||||||
case OIF:
|
case OIF:
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
n := nodl(p.pos(), OIF, nil, nil)
|
n := nodl(p.pos(), OIF, nil, nil)
|
||||||
n.Ninit.Set(p.stmtList())
|
n.Ninit.Set(p.stmtList())
|
||||||
n.Left = p.expr()
|
n.Left = p.expr()
|
||||||
n.Nbody.Set(p.stmtList())
|
n.Nbody.Set(p.stmtList())
|
||||||
n.Rlist.Set(p.stmtList())
|
n.Rlist.Set(p.stmtList())
|
||||||
popdcl()
|
popdcl(src.NoPos)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OFOR:
|
case OFOR:
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
n := nodl(p.pos(), OFOR, nil, nil)
|
n := nodl(p.pos(), OFOR, nil, nil)
|
||||||
n.Ninit.Set(p.stmtList())
|
n.Ninit.Set(p.stmtList())
|
||||||
n.Left, n.Right = p.exprsOrNil()
|
n.Left, n.Right = p.exprsOrNil()
|
||||||
n.Nbody.Set(p.stmtList())
|
n.Nbody.Set(p.stmtList())
|
||||||
popdcl()
|
popdcl(src.NoPos)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ORANGE:
|
case ORANGE:
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
n := nodl(p.pos(), ORANGE, nil, nil)
|
n := nodl(p.pos(), ORANGE, nil, nil)
|
||||||
n.List.Set(p.stmtList())
|
n.List.Set(p.stmtList())
|
||||||
n.Right = p.expr()
|
n.Right = p.expr()
|
||||||
n.Nbody.Set(p.stmtList())
|
n.Nbody.Set(p.stmtList())
|
||||||
popdcl()
|
popdcl(src.NoPos)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OSELECT, OSWITCH:
|
case OSELECT, OSWITCH:
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
n := nodl(p.pos(), op, nil, nil)
|
n := nodl(p.pos(), op, nil, nil)
|
||||||
n.Ninit.Set(p.stmtList())
|
n.Ninit.Set(p.stmtList())
|
||||||
n.Left, _ = p.exprsOrNil()
|
n.Left, _ = p.exprsOrNil()
|
||||||
n.List.Set(p.stmtList())
|
n.List.Set(p.stmtList())
|
||||||
popdcl()
|
popdcl(src.NoPos)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
// case OCASE, OXCASE:
|
// case OCASE, OXCASE:
|
||||||
// unreachable - mapped to OXCASE case below by exporter
|
// unreachable - mapped to OXCASE case below by exporter
|
||||||
|
|
||||||
case OXCASE:
|
case OXCASE:
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
n := nodl(p.pos(), OXCASE, nil, nil)
|
n := nodl(p.pos(), OXCASE, nil, nil)
|
||||||
n.Xoffset = int64(block)
|
n.Xoffset = int64(block)
|
||||||
n.List.Set(p.exprList())
|
n.List.Set(p.exprList())
|
||||||
// TODO(gri) eventually we must declare variables for type switch
|
// TODO(gri) eventually we must declare variables for type switch
|
||||||
// statements (type switch statements are not yet exported)
|
// statements (type switch statements are not yet exported)
|
||||||
n.Nbody.Set(p.stmtList())
|
n.Nbody.Set(p.stmtList())
|
||||||
popdcl()
|
popdcl(src.NoPos)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
// case OFALL:
|
// case OFALL:
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package gc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/src"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ func closurehdr(ntype *Node) {
|
||||||
n.Func.Depth = funcdepth
|
n.Func.Depth = funcdepth
|
||||||
n.Func.Outerfunc = Curfn
|
n.Func.Outerfunc = Curfn
|
||||||
|
|
||||||
funchdr(n)
|
funchdr(n, src.NoPos)
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -58,7 +59,7 @@ func closurebody(body []*Node) *Node {
|
||||||
func_ := Curfn
|
func_ := Curfn
|
||||||
func_.Nbody.Set(body)
|
func_.Nbody.Set(body)
|
||||||
func_.Func.Endlineno = lineno
|
func_.Func.Endlineno = lineno
|
||||||
funcbody(func_)
|
funcbody(func_, src.NoPos)
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -226,8 +227,10 @@ func makeclosure(func_ *Node) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
xfunc.Nbody.Set(func_.Nbody.Slice())
|
xfunc.Nbody.Set(func_.Nbody.Slice())
|
||||||
|
xfunc.Func.scopes = func_.Func.scopes
|
||||||
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
|
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
|
||||||
func_.Func.Dcl = nil
|
func_.Func.Dcl = nil
|
||||||
|
func_.Func.scopes.Scopes = 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")
|
||||||
}
|
}
|
||||||
|
|
@ -609,6 +612,7 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||||
xfunc.Func.Nname.Sym.SetExported(true) // disable export
|
xfunc.Func.Nname.Sym.SetExported(true) // disable export
|
||||||
xfunc.Func.Nname.Name.Param.Ntype = xtype
|
xfunc.Func.Nname.Name.Param.Ntype = xtype
|
||||||
xfunc.Func.Nname.Name.Defn = xfunc
|
xfunc.Func.Nname.Name.Defn = xfunc
|
||||||
|
xfunc.Func.scopes.Scopes = []src.Scope{src.Scope{}}
|
||||||
declare(xfunc.Func.Nname, PFUNC)
|
declare(xfunc.Func.Nname, PFUNC)
|
||||||
|
|
||||||
// Declare and initialize variable holding receiver.
|
// Declare and initialize variable holding receiver.
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ var block int32 // current block number
|
||||||
// Sym definitions, and only a subset of its fields are actually used.
|
// Sym definitions, and only a subset of its fields are actually used.
|
||||||
var dclstack *types.Sym
|
var dclstack *types.Sym
|
||||||
|
|
||||||
|
// lastPopdclPos is the last pos passed to popdcl
|
||||||
|
var lastPopdclPos src.Pos
|
||||||
|
|
||||||
func dcopy(a, b *types.Sym) {
|
func dcopy(a, b *types.Sym) {
|
||||||
a.Pkg = b.Pkg
|
a.Pkg = b.Pkg
|
||||||
a.Name = b.Name
|
a.Name = b.Name
|
||||||
|
|
@ -59,7 +62,7 @@ func pushdcl(s *types.Sym) *types.Sym {
|
||||||
|
|
||||||
// popdcl pops the innermost block scope and restores all symbol declarations
|
// popdcl pops the innermost block scope and restores all symbol declarations
|
||||||
// to their previous state.
|
// to their previous state.
|
||||||
func popdcl() {
|
func popdcl(pos src.Pos) {
|
||||||
d := dclstack
|
d := dclstack
|
||||||
for ; d != nil && d.Name != ""; d = d.Link {
|
for ; d != nil && d.Name != ""; d = d.Link {
|
||||||
s := d.Pkg.Lookup(d.Name)
|
s := d.Pkg.Lookup(d.Name)
|
||||||
|
|
@ -74,16 +77,29 @@ func popdcl() {
|
||||||
|
|
||||||
dclstack = d.Link // pop mark
|
dclstack = d.Link // pop mark
|
||||||
block = d.Block
|
block = d.Block
|
||||||
|
|
||||||
|
if Curfn != nil {
|
||||||
|
Curfn.Func.scopes.Close(&Ctxt.PosTable, pos)
|
||||||
|
lastPopdclPos = pos
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// markdcl records the start of a new block scope for declarations.
|
// markdcl records the start of a new block scope for declarations.
|
||||||
func markdcl() {
|
func markdcl(pos src.Pos) {
|
||||||
d := push()
|
d := push()
|
||||||
d.Name = "" // used as a mark in fifo
|
d.Name = "" // used as a mark in fifo
|
||||||
d.Block = block
|
d.Block = block
|
||||||
|
|
||||||
blockgen++
|
blockgen++
|
||||||
block = blockgen
|
block = blockgen
|
||||||
|
|
||||||
|
if Curfn != nil {
|
||||||
|
Curfn.Func.scopes.Open(&Ctxt.PosTable, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep around for debugging
|
// keep around for debugging
|
||||||
|
|
@ -451,14 +467,14 @@ func ifacedcl(n *Node) {
|
||||||
// and declare the arguments.
|
// and declare the arguments.
|
||||||
// called in extern-declaration context
|
// called in extern-declaration context
|
||||||
// returns in auto-declaration context.
|
// returns in auto-declaration context.
|
||||||
func funchdr(n *Node) {
|
func funchdr(n *Node, pos src.Pos) {
|
||||||
// change the declaration context from extern to auto
|
// change the declaration context from extern to auto
|
||||||
if funcdepth == 0 && dclcontext != PEXTERN {
|
if funcdepth == 0 && dclcontext != PEXTERN {
|
||||||
Fatalf("funchdr: dclcontext = %d", dclcontext)
|
Fatalf("funchdr: dclcontext = %d", dclcontext)
|
||||||
}
|
}
|
||||||
|
|
||||||
dclcontext = PAUTO
|
dclcontext = PAUTO
|
||||||
funcstart(n)
|
funcstart(n, pos)
|
||||||
|
|
||||||
if n.Func.Nname != nil {
|
if n.Func.Nname != nil {
|
||||||
funcargs(n.Func.Nname.Name.Param.Ntype)
|
funcargs(n.Func.Nname.Name.Param.Ntype)
|
||||||
|
|
@ -596,22 +612,22 @@ var funcdepth int32 // len(funcstack) during parsing, but then forced to be th
|
||||||
|
|
||||||
// start the function.
|
// start the function.
|
||||||
// called before funcargs; undone at end of funcbody.
|
// called before funcargs; undone at end of funcbody.
|
||||||
func funcstart(n *Node) {
|
func funcstart(n *Node, pos src.Pos) {
|
||||||
markdcl()
|
|
||||||
funcstack = append(funcstack, Curfn)
|
funcstack = append(funcstack, Curfn)
|
||||||
funcdepth++
|
funcdepth++
|
||||||
Curfn = n
|
Curfn = n
|
||||||
|
markdcl(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// finish the body.
|
// finish the body.
|
||||||
// called in auto-declaration context.
|
// called in auto-declaration context.
|
||||||
// returns in extern-declaration context.
|
// returns in extern-declaration context.
|
||||||
func funcbody(n *Node) {
|
func funcbody(n *Node, pos src.Pos) {
|
||||||
// change the declaration context from auto to extern
|
// change the declaration context from auto to extern
|
||||||
if dclcontext != PAUTO {
|
if dclcontext != PAUTO {
|
||||||
Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
|
Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
|
||||||
}
|
}
|
||||||
popdcl()
|
popdcl(pos)
|
||||||
funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
|
funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
|
||||||
funcdepth--
|
funcdepth--
|
||||||
if funcdepth == 0 {
|
if funcdepth == 0 {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
||||||
import "cmd/compile/internal/types"
|
import (
|
||||||
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/src"
|
||||||
|
)
|
||||||
|
|
||||||
// a function named init is a special case.
|
// a function named init is a special case.
|
||||||
// it is called by the initialization before
|
// it is called by the initialization before
|
||||||
|
|
@ -92,7 +95,7 @@ func fninit(n []*Node) {
|
||||||
fn.Func.Nname.Name.Defn = fn
|
fn.Func.Nname.Name.Defn = fn
|
||||||
fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil)
|
fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil)
|
||||||
declare(fn.Func.Nname, PFUNC)
|
declare(fn.Func.Nname, PFUNC)
|
||||||
funchdr(fn)
|
funchdr(fn, src.NoPos)
|
||||||
|
|
||||||
// (3)
|
// (3)
|
||||||
a := nod(OIF, nil, nil)
|
a := nod(OIF, nil, nil)
|
||||||
|
|
@ -152,7 +155,7 @@ func fninit(n []*Node) {
|
||||||
exportsym(fn.Func.Nname)
|
exportsym(fn.Func.Nname)
|
||||||
|
|
||||||
fn.Nbody.Set(r)
|
fn.Nbody.Set(r)
|
||||||
funcbody(fn)
|
funcbody(fn, src.NoPos)
|
||||||
|
|
||||||
Curfn = fn
|
Curfn = fn
|
||||||
fn = typecheck(fn, Etop)
|
fn = typecheck(fn, Etop)
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
|
||||||
declare(f.Func.Nname, PFUNC)
|
declare(f.Func.Nname, PFUNC)
|
||||||
}
|
}
|
||||||
|
|
||||||
funchdr(f)
|
funchdr(f, fun.Pos())
|
||||||
|
|
||||||
if fun.Body != nil {
|
if fun.Body != nil {
|
||||||
if f.Noescape() {
|
if f.Noescape() {
|
||||||
|
|
@ -347,7 +347,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
funcbody(f)
|
funcbody(f, fun.Pos())
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
@ -777,14 +777,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 {
|
||||||
markdcl()
|
markdcl(stmt.Pos())
|
||||||
nodes := p.stmts(stmt.List)
|
nodes := p.stmts(stmt.List)
|
||||||
popdcl()
|
popdcl(stmt.Rbrace)
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
|
func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
|
||||||
markdcl()
|
markdcl(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))
|
||||||
|
|
@ -801,12 +801,12 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
|
||||||
n.Rlist.Set1(e)
|
n.Rlist.Set1(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
popdcl()
|
popdcl(lastPopdclPos)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
|
func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
|
||||||
markdcl()
|
markdcl(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 {
|
||||||
|
|
@ -835,12 +835,12 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.Nbody.Set(p.blockStmt(stmt.Body))
|
n.Nbody.Set(p.blockStmt(stmt.Body))
|
||||||
popdcl()
|
popdcl(stmt.Body.Rbrace)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
|
func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
|
||||||
markdcl()
|
markdcl(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))
|
||||||
|
|
@ -854,17 +854,17 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
|
||||||
tswitch = nil
|
tswitch = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
n.List.Set(p.caseClauses(stmt.Body, tswitch))
|
n.List.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace))
|
||||||
|
|
||||||
popdcl()
|
popdcl(stmt.Rbrace)
|
||||||
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)
|
||||||
markdcl()
|
markdcl(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))
|
||||||
|
|
@ -878,7 +878,11 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node
|
||||||
}
|
}
|
||||||
n.Xoffset = int64(block)
|
n.Xoffset = int64(block)
|
||||||
n.Nbody.Set(p.stmts(clause.Body))
|
n.Nbody.Set(p.stmts(clause.Body))
|
||||||
popdcl()
|
if i+1 < len(clauses) {
|
||||||
|
popdcl(clauses[i+1].Pos())
|
||||||
|
} else {
|
||||||
|
popdcl(rbrace)
|
||||||
|
}
|
||||||
nodes = append(nodes, n)
|
nodes = append(nodes, n)
|
||||||
}
|
}
|
||||||
return nodes
|
return nodes
|
||||||
|
|
@ -886,22 +890,26 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node
|
||||||
|
|
||||||
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)
|
||||||
markdcl()
|
markdcl(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(block)
|
n.Xoffset = int64(block)
|
||||||
n.Nbody.Set(p.stmts(clause.Body))
|
n.Nbody.Set(p.stmts(clause.Body))
|
||||||
popdcl()
|
if i+1 < len(clauses) {
|
||||||
|
popdcl(clauses[i+1].Pos())
|
||||||
|
} else {
|
||||||
|
popdcl(rbrace)
|
||||||
|
}
|
||||||
nodes = append(nodes, n)
|
nodes = append(nodes, n)
|
||||||
}
|
}
|
||||||
return nodes
|
return nodes
|
||||||
|
|
|
||||||
|
|
@ -310,13 +310,18 @@ func compile(fn *Node) {
|
||||||
pp.Free()
|
pp.Free()
|
||||||
}
|
}
|
||||||
|
|
||||||
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 := Linksym(fn.Func.Nname.Sym); fnsym != expect {
|
if expect := Linksym(fn.Func.Nname.Sym); fnsym != expect {
|
||||||
Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
|
Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
|
||||||
}
|
}
|
||||||
|
|
||||||
var vars []*dwarf.Var
|
scopes := make([]dwarf.Scope, len(fn.Func.scopes.Scopes))
|
||||||
|
|
||||||
|
for i := range scopes {
|
||||||
|
scopes[i] = dwarf.Scope{Scope: fn.Func.scopes.Scopes[i]}
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -363,8 +368,14 @@ func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var scope int32 = 0
|
||||||
|
// Only record scope information when inlining is disabled.
|
||||||
|
if Debug['l'] == 0 {
|
||||||
|
scope = findScope(n.Pos, scopes)
|
||||||
|
}
|
||||||
|
|
||||||
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
||||||
vars = append(vars, &dwarf.Var{
|
scopes[scope].Vars = append(scopes[scope].Vars, &dwarf.Var{
|
||||||
Name: n.Sym.Name,
|
Name: n.Sym.Name,
|
||||||
Abbrev: abbrev,
|
Abbrev: abbrev,
|
||||||
Offset: int32(offs),
|
Offset: int32(offs),
|
||||||
|
|
@ -373,9 +384,13 @@ func debuginfo(fnsym *obj.LSym, curfn interface{}) []*dwarf.Var {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stable sort so that ties are broken with declaration order.
|
// Stable sort so that ties are broken with declaration order.
|
||||||
sort.Stable(dwarf.VarsByOffset(vars))
|
for i := range scopes {
|
||||||
|
sort.Stable(dwarf.VarsByOffset(scopes[i].Vars))
|
||||||
|
}
|
||||||
|
|
||||||
return vars
|
scopeRanges(fnsym, scopes)
|
||||||
|
|
||||||
|
return scopes
|
||||||
}
|
}
|
||||||
|
|
||||||
// fieldtrack adds R_USEFIELD relocations to fnsym to record any
|
// fieldtrack adds R_USEFIELD relocations to fnsym to record any
|
||||||
|
|
|
||||||
91
src/cmd/compile/internal/gc/scope.go
Normal file
91
src/cmd/compile/internal/gc/scope.go
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// findScope returns the most specific scope containing pos.
|
||||||
|
func findScope(pos src.XPos, scopes []dwarf.Scope) int32 {
|
||||||
|
if !pos.IsKnown() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
for i := len(scopes) - 1; i > 0; i-- {
|
||||||
|
if pos.After(scopes[i].Start) && pos.Before(scopes[i].End) {
|
||||||
|
return int32(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type scopedProg struct {
|
||||||
|
p *obj.Prog
|
||||||
|
scope int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// scopeRanges calculates scope ranges for symbol fnsym.
|
||||||
|
func scopeRanges(fnsym *obj.LSym, scopes []dwarf.Scope) {
|
||||||
|
var sp []scopedProg
|
||||||
|
|
||||||
|
for p := fnsym.Text; p != nil; p = p.Link {
|
||||||
|
sp = append(sp, scopedProg{p, -1})
|
||||||
|
}
|
||||||
|
|
||||||
|
for scopeID := int32(len(scopes) - 1); scopeID >= 0; scopeID-- {
|
||||||
|
if scope := &scopes[scopeID]; scope.Start.IsKnown() && scope.End.IsKnown() {
|
||||||
|
scopeProgs(sp, scopeID, scope.Start, scope.End)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scopedProgsToRanges(sp, scopes, fnsym.Size)
|
||||||
|
|
||||||
|
// Propagate scope's pc ranges to parent
|
||||||
|
for i := len(scopes) - 1; i > 0; i-- {
|
||||||
|
cur := &scopes[i]
|
||||||
|
if scopes[i].Parent != 0 {
|
||||||
|
parent := &scopes[scopes[i].Parent]
|
||||||
|
parent.UnifyRanges(cur)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scopeProgs marks all scopedProgs between start and end that don't already
|
||||||
|
// belong to a scope as belonging to scopeId.
|
||||||
|
func scopeProgs(sp []scopedProg, scopeId int32, start, end src.XPos) {
|
||||||
|
for i := range sp {
|
||||||
|
if sp[i].scope >= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if pos := sp[i].p.Pos; pos.After(start) && pos.Before(end) {
|
||||||
|
sp[i].scope = scopeId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scopedProgsToRanges scans sp and collects in the Ranges field of each
|
||||||
|
// scope the start and end instruction of the scope.
|
||||||
|
func scopedProgsToRanges(sp []scopedProg, scopes []dwarf.Scope, symSize int64) {
|
||||||
|
var curscope int32 = -1
|
||||||
|
for i := range sp {
|
||||||
|
if sp[i].scope == curscope {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if curscope >= 0 {
|
||||||
|
curranges := scopes[curscope].Ranges
|
||||||
|
curranges[len(curranges)-1].End = sp[i].p.Pc
|
||||||
|
}
|
||||||
|
curscope = sp[i].scope
|
||||||
|
if curscope >= 0 {
|
||||||
|
scopes[curscope].Ranges = append(scopes[curscope].Ranges, dwarf.Range{Start: sp[i].p.Pc, End: -1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if curscope >= 0 {
|
||||||
|
curranges := scopes[curscope].Ranges
|
||||||
|
curranges[len(curranges)-1].End = symSize
|
||||||
|
}
|
||||||
|
}
|
||||||
410
src/cmd/compile/internal/gc/scope_test.go
Normal file
410
src/cmd/compile/internal/gc/scope_test.go
Normal file
|
|
@ -0,0 +1,410 @@
|
||||||
|
// Copyright 2016 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/objfile"
|
||||||
|
"debug/dwarf"
|
||||||
|
"internal/testenv"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testline struct {
|
||||||
|
// line is one line of go source
|
||||||
|
line string
|
||||||
|
|
||||||
|
// scopes is a list of scope IDs of all the lexical scopes that this line
|
||||||
|
// of code belongs to.
|
||||||
|
// Scope IDs are assigned by traversing the tree of lexical blocks of a
|
||||||
|
// function in pre-order
|
||||||
|
// Scope IDs are function specific, i.e. scope 0 is always the root scope
|
||||||
|
// of the function that this line belongs to. Empty scopes are not assigned
|
||||||
|
// an ID (because they are not saved in debug_info).
|
||||||
|
// Scope 0 is always omitted from this list since all lines always belong
|
||||||
|
// to it.
|
||||||
|
scopes []int
|
||||||
|
|
||||||
|
// vars is the list of variables that belong in scopes[len(scopes)-1].
|
||||||
|
// Local variables are prefixed with "var ", formal parameters with "arg ".
|
||||||
|
// Must be ordered alphabetically.
|
||||||
|
// Set to nil to skip the check.
|
||||||
|
vars []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var testfile = []testline{
|
||||||
|
{line: "package main"},
|
||||||
|
{line: "func f1(x int) { }"},
|
||||||
|
{line: "func f2(x int) { }"},
|
||||||
|
{line: "func f3(x int) { }"},
|
||||||
|
{line: "func f4(x int) { }"},
|
||||||
|
{line: "func f5(x int) { }"},
|
||||||
|
{line: "func f6(x int) { }"},
|
||||||
|
{line: "func gret1() int { return 2 }"},
|
||||||
|
{line: "func gretbool() bool { return true }"},
|
||||||
|
{line: "func gret3() (int, int, int) { return 0, 1, 2 }"},
|
||||||
|
{line: "var v = []int{ 0, 1, 2 }"},
|
||||||
|
{line: "var ch = make(chan int)"},
|
||||||
|
{line: "var floatch = make(chan float64)"},
|
||||||
|
{line: "var iface interface{}"},
|
||||||
|
{line: "func TestNestedFor() {", vars: []string{"var a int"}},
|
||||||
|
{line: " a := 0"},
|
||||||
|
{line: " f1(a)"},
|
||||||
|
{line: " for i := 0; i < 5; i++ {", scopes: []int{1}, vars: []string{"var i int"}},
|
||||||
|
{line: " f2(i)", scopes: []int{1}},
|
||||||
|
{line: " for i := 0; i < 5; i++ {", scopes: []int{1, 2}, vars: []string{"var i int"}},
|
||||||
|
{line: " f3(i)", scopes: []int{1, 2}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " f4(i)", scopes: []int{1}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " f5(a)"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestOas2() {", vars: []string{}},
|
||||||
|
{line: " if a, b, c := gret3(); a != 1 {", scopes: []int{1}, vars: []string{"var a int", "var b int", "var c int"}},
|
||||||
|
{line: " f1(a)", scopes: []int{1}},
|
||||||
|
{line: " f1(b)", scopes: []int{1}},
|
||||||
|
{line: " f1(c)", scopes: []int{1}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " for i, x := range v {", scopes: []int{2}, vars: []string{"var i int", "var x int"}},
|
||||||
|
{line: " f1(i)", scopes: []int{2}},
|
||||||
|
{line: " f1(x)", scopes: []int{2}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " if a, ok := <- ch; ok {", scopes: []int{3}, vars: []string{"var a int", "var ok bool"}},
|
||||||
|
{line: " f1(a)", scopes: []int{3}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " if a, ok := iface.(int); ok {", scopes: []int{4}, vars: []string{"var a int", "var ok bool"}},
|
||||||
|
{line: " f1(a)", scopes: []int{4}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestIfElse() {"},
|
||||||
|
{line: " if x := gret1(); x != 0 {", scopes: []int{1}, vars: []string{"var x int"}},
|
||||||
|
{line: " a := 0", scopes: []int{1, 2}, vars: []string{"var a int"}},
|
||||||
|
{line: " f1(a); f1(x)", scopes: []int{1, 2}},
|
||||||
|
{line: " } else {"},
|
||||||
|
{line: " b := 1", scopes: []int{1, 3}, vars: []string{"var b int"}},
|
||||||
|
{line: " f1(b); f1(x+1)", scopes: []int{1, 3}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestSwitch() {", vars: []string{}},
|
||||||
|
{line: " switch x := gret1(); x {", scopes: []int{1}, vars: []string{"var x int"}},
|
||||||
|
{line: " case 0:", scopes: []int{1}},
|
||||||
|
{line: " i := x + 5", scopes: []int{1, 2}, vars: []string{"var i int"}},
|
||||||
|
{line: " f1(x); f1(i)", scopes: []int{1, 2}},
|
||||||
|
{line: " case 1:", scopes: []int{1}},
|
||||||
|
{line: " j := x + 10", scopes: []int{1, 3}, vars: []string{"var j int"}},
|
||||||
|
{line: " f1(x); f1(j)", scopes: []int{1, 3}},
|
||||||
|
{line: " case 2:", scopes: []int{1}},
|
||||||
|
{line: " k := x + 2", scopes: []int{1, 4}, vars: []string{"var k int"}},
|
||||||
|
{line: " f1(x); f1(k)", scopes: []int{1, 4}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestTypeSwitch() {", vars: []string{}},
|
||||||
|
{line: " switch x := iface.(type) {"},
|
||||||
|
{line: " case int:"},
|
||||||
|
{line: " f1(x)", scopes: []int{1}, vars: []string{"var x int"}},
|
||||||
|
{line: " case uint8:"},
|
||||||
|
{line: " f1(int(x))", scopes: []int{2}, vars: []string{"var x uint8"}},
|
||||||
|
{line: " case float64:"},
|
||||||
|
{line: " f1(int(x)+1)", scopes: []int{3}, vars: []string{"var x float64"}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestSelectScope() {"},
|
||||||
|
{line: " select {"},
|
||||||
|
{line: " case i := <- ch:"},
|
||||||
|
{line: " f1(i)", scopes: []int{1}, vars: []string{"var i int"}},
|
||||||
|
{line: " case f := <- floatch:"},
|
||||||
|
{line: " f1(int(f))", scopes: []int{2}, vars: []string{"var f float64"}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestBlock() {", vars: []string{"var a int"}},
|
||||||
|
{line: " a := 1"},
|
||||||
|
{line: " {"},
|
||||||
|
{line: " b := 2", scopes: []int{1}, vars: []string{"var b int"}},
|
||||||
|
{line: " f1(b)", scopes: []int{1}},
|
||||||
|
{line: " f1(a)", scopes: []int{1}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestDiscontiguousRanges() {", vars: []string{"var a int"}},
|
||||||
|
{line: " a := 0"},
|
||||||
|
{line: " f1(a)"},
|
||||||
|
{line: " {"},
|
||||||
|
{line: " b := 0", scopes: []int{1}, vars: []string{"var b int"}},
|
||||||
|
{line: " f2(b)", scopes: []int{1}},
|
||||||
|
{line: " if gretbool() {", scopes: []int{1}},
|
||||||
|
{line: " c := 0", scopes: []int{1, 2}, vars: []string{"var c int"}},
|
||||||
|
{line: " f3(c)", scopes: []int{1, 2}},
|
||||||
|
{line: " } else {"},
|
||||||
|
{line: " c := 1.1", scopes: []int{1, 3}, vars: []string{"var c float64"}},
|
||||||
|
{line: " f4(int(c))", scopes: []int{1, 3}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " f5(b)", scopes: []int{1}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " f6(a)"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func TestClosureScope() {", vars: []string{"var a int", "var b int", "var f func(int)"}},
|
||||||
|
{line: " a := 1; b := 1"},
|
||||||
|
{line: " f := func(c int) {", scopes: []int{0}, vars: []string{"arg c int", "var a int", "var d int"}},
|
||||||
|
{line: " d := 3"},
|
||||||
|
{line: " f1(a); f1(c); f1(d)"},
|
||||||
|
{line: " if e := 3; e != 0 {", scopes: []int{1}, vars: []string{"var e int"}},
|
||||||
|
{line: " f1(e)", scopes: []int{1}},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " }"},
|
||||||
|
{line: " f(3); f1(b)"},
|
||||||
|
{line: "}"},
|
||||||
|
{line: "func main() {"},
|
||||||
|
{line: " TestNestedFor()"},
|
||||||
|
{line: " TestOas2()"},
|
||||||
|
{line: " TestIfElse()"},
|
||||||
|
{line: " TestSwitch()"},
|
||||||
|
{line: " TestTypeSwitch()"},
|
||||||
|
{line: " TestSelectScope()"},
|
||||||
|
{line: " TestBlock()"},
|
||||||
|
{line: " TestDiscontiguousRanges()"},
|
||||||
|
{line: " TestClosureScope()"},
|
||||||
|
{line: "}"},
|
||||||
|
}
|
||||||
|
|
||||||
|
const detailOutput = false
|
||||||
|
|
||||||
|
// Compiles testfile checks that the description of lexical blocks emitted
|
||||||
|
// by the linker in debug_info, for each function in the main package,
|
||||||
|
// corresponds to what we expect it to be.
|
||||||
|
func TestScopeRanges(t *testing.T) {
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
dir, err := ioutil.TempDir("", "TestScopeRanges")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create directory: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
src, f := gobuild(t, dir, testfile)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// the compiler uses forward slashes for paths even on windows
|
||||||
|
src = strings.Replace(src, "\\", "/", -1)
|
||||||
|
|
||||||
|
pcln, err := f.PCLineTable()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dwarfData, err := f.DWARF()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dwarfReader := dwarfData.Reader()
|
||||||
|
|
||||||
|
lines := make(map[line][]*lexblock)
|
||||||
|
|
||||||
|
for {
|
||||||
|
entry, err := dwarfReader.Next()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Tag != dwarf.TagSubprogram {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name, ok := entry.Val(dwarf.AttrName).(string)
|
||||||
|
if !ok || !strings.HasPrefix(name, "main.Test") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var scope lexblock
|
||||||
|
ctxt := scopexplainContext{
|
||||||
|
dwarfData: dwarfData,
|
||||||
|
dwarfReader: dwarfReader,
|
||||||
|
scopegen: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
readScope(&ctxt, &scope, entry)
|
||||||
|
|
||||||
|
scope.markLines(pcln, lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
anyerror := false
|
||||||
|
for i := range testfile {
|
||||||
|
tgt := testfile[i].scopes
|
||||||
|
out := lines[line{src, i + 1}]
|
||||||
|
|
||||||
|
if detailOutput {
|
||||||
|
t.Logf("%s // %v", testfile[i].line, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
scopesok := checkScopes(tgt, out)
|
||||||
|
if !scopesok {
|
||||||
|
t.Logf("mismatch at line %d %q: expected: %v got: %v\n", i, testfile[i].line, tgt, scopesToString(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
varsok := true
|
||||||
|
if testfile[i].vars != nil {
|
||||||
|
if len(out) > 0 {
|
||||||
|
varsok = checkVars(testfile[i].vars, out[len(out)-1].vars)
|
||||||
|
if !varsok {
|
||||||
|
t.Logf("variable mismatch at line %d %q for scope %d: expected: %v got: %v\n", i, testfile[i].line, out[len(out)-1].id, testfile[i].vars, out[len(out)-1].vars)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anyerror = anyerror || !scopesok || !varsok
|
||||||
|
}
|
||||||
|
|
||||||
|
if anyerror {
|
||||||
|
t.Fatalf("mismatched output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func scopesToString(v []*lexblock) string {
|
||||||
|
r := make([]string, len(v))
|
||||||
|
for i, s := range v {
|
||||||
|
r[i] = strconv.Itoa(s.id)
|
||||||
|
}
|
||||||
|
return "[ " + strings.Join(r, ", ") + " ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkScopes(tgt []int, out []*lexblock) bool {
|
||||||
|
if len(out) > 0 {
|
||||||
|
// omit scope 0
|
||||||
|
out = out[1:]
|
||||||
|
}
|
||||||
|
if len(tgt) != len(out) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range tgt {
|
||||||
|
if tgt[i] != out[i].id {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkVars(tgt, out []string) bool {
|
||||||
|
if len(tgt) != len(out) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range tgt {
|
||||||
|
if tgt[i] != out[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type lexblock struct {
|
||||||
|
id int
|
||||||
|
ranges [][2]uint64
|
||||||
|
vars []string
|
||||||
|
scopes []lexblock
|
||||||
|
}
|
||||||
|
|
||||||
|
type line struct {
|
||||||
|
file string
|
||||||
|
lineno int
|
||||||
|
}
|
||||||
|
|
||||||
|
type scopexplainContext struct {
|
||||||
|
dwarfData *dwarf.Data
|
||||||
|
dwarfReader *dwarf.Reader
|
||||||
|
scopegen int
|
||||||
|
lines map[line][]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// readScope reads the DW_TAG_lexical_block or the DW_TAG_subprogram in
|
||||||
|
// entry and writes a description in scope.
|
||||||
|
// Nested DW_TAG_lexical_block entries are read recursively.
|
||||||
|
func readScope(ctxt *scopexplainContext, scope *lexblock, entry *dwarf.Entry) {
|
||||||
|
if lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64); ok {
|
||||||
|
highpc, _ := entry.Val(dwarf.AttrHighpc).(uint64)
|
||||||
|
scope.ranges = [][2]uint64{[2]uint64{lowpc, highpc}}
|
||||||
|
} else {
|
||||||
|
ranges, err := ctxt.dwarfData.Ranges(entry)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
scope.ranges = ranges
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
e, err := ctxt.dwarfReader.Next()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
switch e.Tag {
|
||||||
|
case 0:
|
||||||
|
sort.Strings(scope.vars)
|
||||||
|
return
|
||||||
|
case dwarf.TagFormalParameter:
|
||||||
|
typ, err := ctxt.dwarfData.Type(e.Val(dwarf.AttrType).(dwarf.Offset))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
scope.vars = append(scope.vars, "arg "+e.Val(dwarf.AttrName).(string)+" "+typ.String())
|
||||||
|
case dwarf.TagVariable:
|
||||||
|
typ, err := ctxt.dwarfData.Type(e.Val(dwarf.AttrType).(dwarf.Offset))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
scope.vars = append(scope.vars, "var "+e.Val(dwarf.AttrName).(string)+" "+typ.String())
|
||||||
|
case dwarf.TagLexDwarfBlock:
|
||||||
|
scope.scopes = append(scope.scopes, lexblock{id: ctxt.scopegen})
|
||||||
|
ctxt.scopegen++
|
||||||
|
readScope(ctxt, &scope.scopes[len(scope.scopes)-1], e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// markLines marks all lines that belong to this scope with this scope
|
||||||
|
// Recursively calls markLines for all children scopes.
|
||||||
|
func (scope *lexblock) markLines(pcln objfile.Liner, lines map[line][]*lexblock) {
|
||||||
|
for _, r := range scope.ranges {
|
||||||
|
for pc := r[0]; pc < r[1]; pc++ {
|
||||||
|
file, lineno, _ := pcln.PCToLine(pc)
|
||||||
|
l := line{file, lineno}
|
||||||
|
if len(lines[l]) == 0 || lines[l][len(lines[l])-1] != scope {
|
||||||
|
lines[l] = append(lines[l], scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range scope.scopes {
|
||||||
|
scope.scopes[i].markLines(pcln, lines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gobuild(t *testing.T, dir string, testfile []testline) (string, *objfile.File) {
|
||||||
|
src := filepath.Join(dir, "test.go")
|
||||||
|
dst := filepath.Join(dir, "out.o")
|
||||||
|
|
||||||
|
f, err := os.Create(src)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for i := range testfile {
|
||||||
|
f.Write([]byte(testfile[i].line))
|
||||||
|
f.Write([]byte{'\n'})
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", dst, src)
|
||||||
|
if b, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
t.Logf("build: %s\n", string(b))
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg, err := objfile.Open(dst)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return src, pkg
|
||||||
|
}
|
||||||
|
|
@ -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{}, 96, 160},
|
{Func{}, 112, 192},
|
||||||
{Name{}, 36, 56},
|
{Name{}, 36, 56},
|
||||||
{Param{}, 28, 56},
|
{Param{}, 28, 56},
|
||||||
{Node{}, 84, 136},
|
{Node{}, 84, 136},
|
||||||
|
|
|
||||||
|
|
@ -1687,7 +1687,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym, iface
|
||||||
lineno = autogeneratedPos
|
lineno = autogeneratedPos
|
||||||
|
|
||||||
dclcontext = PEXTERN
|
dclcontext = PEXTERN
|
||||||
markdcl()
|
markdcl(src.NoPos)
|
||||||
|
|
||||||
this := namedfield(".this", rcvr)
|
this := namedfield(".this", rcvr)
|
||||||
this.Left.Name.Param.Ntype = this.Right
|
this.Left.Name.Param.Ntype = this.Right
|
||||||
|
|
@ -1717,7 +1717,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym, iface
|
||||||
fn.Func.Nname.Name.Param.Ntype = t
|
fn.Func.Nname.Name.Param.Ntype = t
|
||||||
fn.Func.Nname.Sym.SetExported(true) // prevent export; see closure.go
|
fn.Func.Nname.Sym.SetExported(true) // prevent export; see closure.go
|
||||||
declare(fn.Func.Nname, PFUNC)
|
declare(fn.Func.Nname, PFUNC)
|
||||||
funchdr(fn)
|
funchdr(fn, src.NoPos)
|
||||||
|
|
||||||
// arg list
|
// arg list
|
||||||
var args []*Node
|
var args []*Node
|
||||||
|
|
@ -1782,9 +1782,9 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym, iface
|
||||||
dumplist("genwrapper body", fn.Nbody)
|
dumplist("genwrapper body", fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
funcbody(fn)
|
funcbody(fn, src.NoPos)
|
||||||
Curfn = fn
|
Curfn = fn
|
||||||
popdcl()
|
popdcl(src.NoPos)
|
||||||
if debug_dclstack != 0 {
|
if debug_dclstack != 0 {
|
||||||
testdclstack()
|
testdclstack()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -321,9 +321,10 @@ 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
|
||||||
|
scopes src.Scopes // lexical scopes of the function
|
||||||
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{}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ package gc
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
|
"cmd/internal/src"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -3661,7 +3662,7 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
|
||||||
|
|
||||||
oldfn := Curfn
|
oldfn := Curfn
|
||||||
Curfn = nil
|
Curfn = nil
|
||||||
funchdr(fn)
|
funchdr(fn, src.NoPos)
|
||||||
|
|
||||||
a = nod(n.Op, nil, nil)
|
a = nod(n.Op, nil, nil)
|
||||||
a.List.Set(printargs)
|
a.List.Set(printargs)
|
||||||
|
|
@ -3670,7 +3671,7 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
|
||||||
|
|
||||||
fn.Nbody.Set1(a)
|
fn.Nbody.Set1(a)
|
||||||
|
|
||||||
funcbody(fn)
|
funcbody(fn, src.NoPos)
|
||||||
|
|
||||||
fn = typecheck(fn, Etop)
|
fn = typecheck(fn, Etop)
|
||||||
typecheckslice(fn.Nbody.Slice(), Etop)
|
typecheckslice(fn.Nbody.Slice(), Etop)
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,20 @@
|
||||||
package dwarf
|
package dwarf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmd/internal/src"
|
||||||
|
"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.
|
||||||
|
|
@ -26,6 +32,63 @@ type Var struct {
|
||||||
Type Sym
|
Type Sym
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A Scope represents a lexical scope, all variables contained in 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 {
|
||||||
|
src.Scope
|
||||||
|
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 len(out) == 0 {
|
||||||
|
out = append(out, cur)
|
||||||
|
} else {
|
||||||
|
last := &out[len(out)-1]
|
||||||
|
if cur.Start > last.End {
|
||||||
|
out = append(out, cur)
|
||||||
|
} else if cur.End > last.End {
|
||||||
|
last.End = cur.End
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -153,6 +216,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
|
||||||
|
|
@ -243,6 +308,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,
|
||||||
|
|
@ -520,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)
|
||||||
|
|
@ -550,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
|
||||||
|
|
@ -601,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)
|
||||||
|
|
@ -611,29 +693,72 @@ 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 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyscope := len(scope.Vars) == 0 || len(scope.Ranges) == 0
|
||||||
|
|
||||||
|
if !emptyscope {
|
||||||
|
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 _, pcrange := range scope.Ranges {
|
||||||
|
ctxt.AddAddress(ranges, nil, pcrange.Start)
|
||||||
|
ctxt.AddAddress(ranges, nil, pcrange.End)
|
||||||
|
}
|
||||||
|
ctxt.AddAddress(ranges, nil, 0)
|
||||||
|
ctxt.AddAddress(ranges, nil, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curscope = putscope(ctxt, s, ranges, startPC, curscope, scopes, encbuf)
|
||||||
|
|
||||||
|
if !emptyscope {
|
||||||
|
Uleb128put(ctxt, s, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return curscope
|
||||||
}
|
}
|
||||||
|
|
||||||
// VarsByOffset attaches the methods of sort.Interface to []*Var,
|
// VarsByOffset attaches the methods of sort.Interface to []*Var,
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ 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 {
|
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)
|
||||||
|
|
|
||||||
|
|
@ -483,6 +483,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)
|
||||||
|
|
@ -739,7 +740,7 @@ type Link struct {
|
||||||
Armsize int32
|
Armsize int32
|
||||||
Pc int64
|
Pc int64
|
||||||
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
|
||||||
Cursym *LSym
|
Cursym *LSym
|
||||||
Version int
|
Version int
|
||||||
Errors int
|
Errors int
|
||||||
|
|
|
||||||
|
|
@ -542,10 +542,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)
|
||||||
|
|
@ -555,6 +559,10 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
|
||||||
r.Type = R_DWARFREF
|
r.Type = R_DWARFREF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *LSym) Len() int64 {
|
||||||
|
return s.Size
|
||||||
|
}
|
||||||
|
|
||||||
// makeFuncDebugEntry makes a DWARF Debugging Information Entry
|
// makeFuncDebugEntry makes a DWARF Debugging Information Entry
|
||||||
// for TEXT symbol s.
|
// for TEXT symbol s.
|
||||||
func makeFuncDebugEntry(ctxt *Link, curfn interface{}, s *LSym) {
|
func makeFuncDebugEntry(ctxt *Link, curfn interface{}, s *LSym) {
|
||||||
|
|
@ -564,10 +572,21 @@ func makeFuncDebugEntry(ctxt *Link, curfn interface{}, s *LSym) {
|
||||||
}
|
}
|
||||||
dsym.Type = SDWARFINFO
|
dsym.Type = SDWARFINFO
|
||||||
dsym.Set(AttrDuplicateOK, s.DuplicateOK())
|
dsym.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||||
var vars []*dwarf.Var
|
|
||||||
if ctxt.DebugInfo != nil {
|
drsym := ctxt.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
|
||||||
vars = ctxt.DebugInfo(s, curfn)
|
if drsym.Size != 0 {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
dwarf.PutFunc(dwCtxt{ctxt}, dsym, s.Name, s.Version == 0, s, s.Size, vars)
|
drsym.Type = SDWARFRANGE
|
||||||
ctxt.Data = append(ctxt.Data, dsym)
|
drsym.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||||
|
|
||||||
|
var scopes []dwarf.Scope
|
||||||
|
if ctxt.DebugInfo != nil {
|
||||||
|
scopes = ctxt.DebugInfo(s, curfn)
|
||||||
|
}
|
||||||
|
err := dwarf.PutFunc(dwCtxt{ctxt}, dsym, drsym, s.Name, s.Version == 0, s, s.Size, scopes)
|
||||||
|
if err != nil {
|
||||||
|
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
|
||||||
|
}
|
||||||
|
ctxt.Data = append(ctxt.Data, dsym, drsym)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
src/cmd/internal/src/scope.go
Normal file
36
src/cmd/internal/src/scope.go
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
// 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 src
|
||||||
|
|
||||||
|
// Scope represents a lexical scope.
|
||||||
|
type Scope struct {
|
||||||
|
Start, End XPos
|
||||||
|
Parent int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes represents a tree of lexical scopes
|
||||||
|
type Scopes struct {
|
||||||
|
Scopes []Scope // lexical scopes
|
||||||
|
curscope int32 // current scope index (during noding)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open starts a new scope, scopes.Curscope is the parent.
|
||||||
|
func (scopes *Scopes) Open(posTable *PosTable, pos Pos) {
|
||||||
|
scope := Scope{Parent: scopes.curscope, Start: NoXPos, End: NoXPos}
|
||||||
|
if pos.IsKnown() {
|
||||||
|
scope.Start = posTable.XPos(pos)
|
||||||
|
}
|
||||||
|
scopes.Scopes = append(scopes.Scopes, scope)
|
||||||
|
scopes.curscope = int32(len(scopes.Scopes) - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close ends the current scope.
|
||||||
|
func (scopes *Scopes) Close(posTable *PosTable, pos Pos) {
|
||||||
|
scope := &scopes.Scopes[scopes.curscope]
|
||||||
|
if pos.IsKnown() {
|
||||||
|
scope.End = posTable.XPos(pos)
|
||||||
|
}
|
||||||
|
scopes.curscope = scope.Parent
|
||||||
|
}
|
||||||
|
|
@ -570,9 +570,18 @@ func relocsym(ctxt *Link, s *Symbol) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case obj.R_DWARFREF:
|
case obj.R_DWARFREF:
|
||||||
if r.Sym.Sect == nil {
|
sectName := ""
|
||||||
|
vaddr := int64(0)
|
||||||
|
if r.Sym.Sect != nil {
|
||||||
|
sectName = r.Sym.Sect.Name
|
||||||
|
vaddr = int64(r.Sym.Sect.Vaddr)
|
||||||
|
} else if r.Sym.Type == obj.SDWARFRANGE {
|
||||||
|
sectName = ".debug_ranges"
|
||||||
|
vaddr = 0
|
||||||
|
} else {
|
||||||
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
|
||||||
|
|
@ -584,8 +593,9 @@ func relocsym(ctxt *Link, s *Symbol) {
|
||||||
r.Type = obj.R_ADDR
|
r.Type = obj.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 {
|
||||||
|
|
@ -593,7 +603,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 obj.R_WEAKADDROFF:
|
case obj.R_WEAKADDROFF:
|
||||||
if !r.Sym.Attr.Reachable() {
|
if !r.Sym.Attr.Reachable() {
|
||||||
|
|
@ -1822,6 +1832,7 @@ func (ctxt *Link) dodata() {
|
||||||
if s.Type != obj.SDWARFSECT {
|
if s.Type != obj.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 @@
|
||||||
// - 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
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -1288,6 +1288,34 @@ 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 = obj.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 |= AttrHidden
|
||||||
|
rangeSym.Attr |= AttrReachable
|
||||||
|
rangeSym.Type = obj.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
|
||||||
*/
|
*/
|
||||||
|
|
@ -1318,7 +1346,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)
|
||||||
|
|
@ -1531,6 +1559,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)
|
||||||
|
|
@ -1572,6 +1601,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")
|
||||||
|
|
@ -1599,6 +1629,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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue