Skip to content

Commit

Permalink
cmd/compile,cmd/link: set DW_AT_decl_line for function declarations
Browse files Browse the repository at this point in the history
DW_AT_decl_line provides the line number of function declarations (the
line containing the func keyword). This is the equivalent to CL 429638,
but provided via DWARF.

Note that the file of declarations (DW_AT_decl_file) is already provided
for non-inlined functions. It is omitted for inlined functions because
those DWARF subprograms may be generated outside of their source
compilation unit, where referencing the file table is difficult.

Fixes #57308.

Change-Id: I3ad12e1f366c4465c2a588297988a5825ef7efec
Reviewed-on: https://go-review.googlesource.com/c/go/+/458195
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Cherry Mui <[email protected]>
Auto-Submit: Michael Pratt <[email protected]>
Run-TryBot: Michael Pratt <[email protected]>
Reviewed-by: Than McIntosh <[email protected]>
  • Loading branch information
prattmic authored and gopherbot committed Jan 30, 2023
1 parent ee5ce77 commit 9e45b1d
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 14 deletions.
7 changes: 3 additions & 4 deletions src/cmd/compile/internal/dwarfgen/dwarf.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"cmd/internal/src"
)

func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) (scopes []dwarf.Scope, inlcalls dwarf.InlCalls, startPos src.XPos) {
fn := curfn.(*ir.Func)

if fn.Nname != nil {
Expand Down Expand Up @@ -124,12 +124,11 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
varScopes = append(varScopes, findScope(fn.Marks, pos))
}

scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
var inlcalls dwarf.InlCalls
scopes = assembleScopes(fnsym, fn, dwarfVars, varScopes)
if base.Flag.GenDwarfInl > 0 {
inlcalls = assembleInlines(fnsym, dwarfVars)
}
return scopes, inlcalls
return scopes, inlcalls, fn.Pos()
}

func declPos(decl *ir.Name) src.XPos {
Expand Down
7 changes: 7 additions & 0 deletions src/cmd/internal/dwarf/dwarf.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ type FnState struct {
Absfn Sym
StartPC Sym
Size int64
StartLine int32
External bool
Scopes []Scope
InlCalls InlCalls
Expand Down Expand Up @@ -458,6 +459,7 @@ var abbrevs = [DW_NABRV]dwAbbrev{
{DW_AT_high_pc, DW_FORM_addr},
{DW_AT_frame_base, DW_FORM_block1},
{DW_AT_decl_file, DW_FORM_data4},
{DW_AT_decl_line, DW_FORM_udata},
{DW_AT_external, DW_FORM_flag},
},
},
Expand All @@ -482,6 +484,7 @@ var abbrevs = [DW_NABRV]dwAbbrev{
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_inline, DW_FORM_data1},
{DW_AT_decl_line, DW_FORM_udata},
{DW_AT_external, DW_FORM_flag},
},
},
Expand Down Expand Up @@ -1254,6 +1257,8 @@ func PutAbstractFunc(ctxt Context, s *FnState) error {
// DW_AT_inlined value
putattr(ctxt, s.Absfn, abbrev, DW_FORM_data1, DW_CLS_CONSTANT, int64(DW_INL_inlined), nil)

putattr(ctxt, s.Absfn, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartLine), nil)

var ev int64
if s.External {
ev = 1
Expand Down Expand Up @@ -1446,6 +1451,8 @@ func PutDefaultFunc(ctxt Context, s *FnState, isWrapper bool) error {
putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
} else {
ctxt.AddFileRef(s.Info, s.Filesym)
putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartLine), nil)

var ev int64
if s.External {
ev = 1
Expand Down
12 changes: 10 additions & 2 deletions src/cmd/internal/obj/dwarf.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,9 @@ func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string)
var scopes []dwarf.Scope
var inlcalls dwarf.InlCalls
if ctxt.DebugInfo != nil {
scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
// Don't need startPos because s.Func().StartLine is populated,
// as s is in this package.
scopes, inlcalls, _ = ctxt.DebugInfo(s, info, curfn)
}
var err error
dwctxt := dwCtxt{ctxt}
Expand All @@ -368,6 +370,7 @@ func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string)
Absfn: absfunc,
StartPC: s,
Size: s.Size,
StartLine: s.Func().StartLine,
External: !s.Static(),
Scopes: scopes,
InlCalls: inlcalls,
Expand Down Expand Up @@ -427,15 +430,20 @@ func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath str
if s.Func() == nil {
s.NewFuncInfo()
}
scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
scopes, _, startPos := ctxt.DebugInfo(s, absfn, curfn)
_, startLine := ctxt.getFileSymbolAndLine(startPos)
dwctxt := dwCtxt{ctxt}
// TODO(prattmic): this returns nil for symbols outside of the current
// package because s.Func() is empty. This doesn't matter because
// PutAbstractFunc doesn't use Filesym. Use startPos or remove.
filesym := ctxt.fileSymbol(s)
fnstate := dwarf.FnState{
Name: s.Name,
Importpath: myimportpath,
Info: absfn,
Filesym: filesym,
Absfn: absfn,
StartLine: startLine,
External: !s.Static(),
Scopes: scopes,
UseBASEntries: ctxt.UseBASEntries,
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/internal/obj/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ type Link struct {
Imports []goobj.ImportedPkg
DiagFunc func(string, ...interface{})
DiagFlush func()
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls, src.XPos) // if non-nil, curfn is a *ir.Func
GenAbstractFunc func(fn *LSym)
Errors int

Expand Down
27 changes: 20 additions & 7 deletions src/cmd/link/internal/ld/dwarf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,10 +334,12 @@ func main() {
}
}

func varDeclCoordsAndSubrogramDeclFile(t *testing.T, testpoint string, expectFile string, expectLine int, directive string) {
// expectLine is the expected line for main.
func varDeclCoordsAndSubprogramDeclFile(t *testing.T, testpoint string, expectFile string, expectLine int, directive string) {
t.Parallel()

prog := fmt.Sprintf("package main\n%s\nfunc main() {\n\nvar i int\ni = i\n}\n", directive)
const iLineOffset = 2

dir := t.TempDir()

Expand Down Expand Up @@ -385,9 +387,12 @@ func varDeclCoordsAndSubrogramDeclFile(t *testing.T, testpoint string, expectFil
}

// Verify line/file attributes.
line := iEntry.Val(dwarf.AttrDeclLine)
if line == nil || line.(int64) != int64(expectLine) {
t.Errorf("DW_AT_decl_line for i is %v, want %d", line, expectLine)
line, lineOK := iEntry.Val(dwarf.AttrDeclLine).(int64)
if !lineOK {
t.Errorf("missing or invalid DW_AT_decl_line for i")
}
if line != int64(expectLine+iLineOffset) {
t.Errorf("DW_AT_decl_line for i is %v, want %d", line, expectLine+iLineOffset)
}

fileIdx, fileIdxOK := maindie.Val(dwarf.AttrDeclFile).(int64)
Expand All @@ -402,6 +407,14 @@ func varDeclCoordsAndSubrogramDeclFile(t *testing.T, testpoint string, expectFil
if base != expectFile {
t.Errorf("DW_AT_decl_file for main is %v, want %v", base, expectFile)
}

line, lineOK = maindie.Val(dwarf.AttrDeclLine).(int64)
if !lineOK {
t.Errorf("missing or invalid DW_AT_decl_line for main")
}
if line != int64(expectLine) {
t.Errorf("DW_AT_decl_line for main is %v, want %d", line, expectLine)
}
}

func TestVarDeclCoordsAndSubrogramDeclFile(t *testing.T) {
Expand All @@ -411,7 +424,7 @@ func TestVarDeclCoordsAndSubrogramDeclFile(t *testing.T) {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}

varDeclCoordsAndSubrogramDeclFile(t, "TestVarDeclCoords", "test.go", 5, "")
varDeclCoordsAndSubprogramDeclFile(t, "TestVarDeclCoords", "test.go", 3, "")
}

func TestVarDeclCoordsWithLineDirective(t *testing.T) {
Expand All @@ -421,8 +434,8 @@ func TestVarDeclCoordsWithLineDirective(t *testing.T) {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}

varDeclCoordsAndSubrogramDeclFile(t, "TestVarDeclCoordsWithLineDirective",
"foobar.go", 202, "//line /foobar.go:200")
varDeclCoordsAndSubprogramDeclFile(t, "TestVarDeclCoordsWithLineDirective",
"foobar.go", 200, "//line /foobar.go:200")
}

func TestInlinedRoutineRecords(t *testing.T) {
Expand Down

0 comments on commit 9e45b1d

Please sign in to comment.