// Create new entry for this inline
inlinedFn := base.Ctxt.InlTree.InlinedFunction(inlIdx)
callXPos := base.Ctxt.InlTree.CallPos(inlIdx)
- callPos := base.Ctxt.PosTable.Pos(callXPos)
- callFileSym := base.Ctxt.Lookup(callPos.Base().SymFilename())
+ callPos := base.Ctxt.InnermostPos(callXPos)
absFnSym := base.Ctxt.DwFixups.AbsFuncDwarfSym(inlinedFn)
ic := dwarf.InlCall{
InlIndex: inlIdx,
- CallFile: callFileSym,
- CallLine: uint32(callPos.RelLine()),
+ CallPos: callPos,
AbsFunSym: absFnSym,
Root: parCallIdx == -1,
}
import (
"bytes"
+ "cmd/internal/src"
"errors"
"fmt"
"internal/buildcfg"
type FnState struct {
Name string
Info Sym
- Filesym Sym
Loc Sym
Ranges Sym
Absfn Sym
StartPC Sym
+ StartPos src.Pos
Size int64
- StartLine int32
External bool
Scopes []Scope
InlCalls InlCalls
// index into ctx.InlTree describing the call inlined here
InlIndex int
- // Symbol of file containing inlined call site (really *obj.LSym).
- CallFile Sym
-
- // Line number of inlined call site.
- CallLine uint32
+ // Position of the inlined call site.
+ CallPos src.Pos
// Dwarf abstract subroutine symbol (really *obj.LSym).
AbsFunSym Sym
RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int)
RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32)
AddString(s Sym, v string)
- AddFileRef(s Sym, f interface{})
Logf(format string, args ...interface{})
}
// 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)
+ // TODO(mdempsky): Shouldn't we write out StartPos.FileIndex() too?
+ putattr(ctxt, s.Absfn, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
var ev int64
if s.External {
}
// Emit call file, line attrs.
- ctxt.AddFileRef(s.Info, ic.CallFile)
+ putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, int64(1+ic.CallPos.FileIndex()), nil) // 1-based file table
form := int(expandPseudoForm(DW_FORM_udata_pseudo))
- putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallLine), nil)
+ putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallPos.RelLine()), nil)
// Variables associated with this inlined routine instance.
vars := ic.InlVars
if isWrapper {
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)
+ putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, int64(1+s.StartPos.FileIndex()), nil) // 1-based file index
+ putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
var ev int64
if s.External {
line := int64(1)
pc := s.Func().Text.Pc
var lastpc int64 // last PC written to line table, not last PC in func
- name := ""
+ fileIndex := 1
prologue, wrotePrologue := false, false
// Walk the progs, generating the DWARF table.
for p := s.Func().Text; p != nil; p = p.Link {
continue
}
newStmt := p.Pos.IsStmt() != src.PosNotStmt
- newName, newLine := ctxt.getFileSymbolAndLine(p.Pos)
+ newFileIndex, newLine := ctxt.getFileIndexAndLine(p.Pos)
+ newFileIndex++ // 1 indexing for the table
// Output debug info.
wrote := false
- if name != newName {
- newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
+ if newFileIndex != fileIndex {
dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
- dwarf.Uleb128put(dctxt, lines, int64(newFile))
- name = newName
+ dwarf.Uleb128put(dctxt, lines, int64(newFileIndex))
+ fileIndex = newFileIndex
wrote = true
}
if prologue && !wrotePrologue {
r.Type = objabi.R_DWARFSECREF
}
-func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
- ls := s.(*LSym)
- rsym := f.(*LSym)
- fidx := c.Link.PosTable.FileIndex(rsym.Name)
- // Note the +1 here -- the value we're writing is going to be an
- // index into the DWARF line table file section, whose entries
- // are numbered starting at 1, not 0.
- ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
-}
-
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
ls := s.(*LSym)
return ls.Size
return s.Size
}
-// fileSymbol returns a symbol corresponding to the source file of the
-// first instruction (prog) of the specified function. This will
-// presumably be the file in which the function is defined.
-func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
- p := fn.Func().Text
- if p != nil {
- f, _ := ctxt.getFileSymbolAndLine(p.Pos)
- fsym := ctxt.Lookup(f)
- return fsym
+// textPos returns the source position of the first instruction (prog)
+// of the specified function.
+func textPos(fn *LSym) src.XPos {
+ if p := fn.Func().Text; p != nil {
+ return p.Pos
}
- return nil
+ return src.NoXPos
}
// populateDWARF fills in the DWARF Debugging Information Entries for
}
var err error
dwctxt := dwCtxt{ctxt}
- filesym := ctxt.fileSymbol(s)
+ startPos := ctxt.InnermostPos(textPos(s))
+ if !startPos.IsKnown() || startPos.RelLine() != uint(s.Func().StartLine) {
+ panic("bad startPos")
+ }
fnstate := &dwarf.FnState{
Name: s.Name,
Info: info,
- Filesym: filesym,
Loc: loc,
Ranges: ranges,
Absfn: absfunc,
StartPC: s,
Size: s.Size,
- StartLine: s.Func().StartLine,
+ StartPos: startPos,
External: !s.Static(),
Scopes: scopes,
InlCalls: inlcalls,
s.NewFuncInfo()
}
scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
- _, startLine := ctxt.getFileSymbolAndLine(curfn.Pos())
dwctxt := dwCtxt{ctxt}
fnstate := dwarf.FnState{
Name: s.Name,
Info: absfn,
Absfn: absfn,
- StartLine: startLine,
+ StartPos: ctxt.InnermostPos(curfn.Pos()),
External: !s.Static(),
Scopes: scopes,
UseBASEntries: ctxt.UseBASEntries,
ctxt.Imports = append(ctxt.Imports, goobj.ImportedPkg{Pkg: pkg, Fingerprint: fingerprint})
}
-// getFileSymbolAndLine returns the relative file symbol and relative line
-// number for a position (i.e., as adjusted by a //line directive). This is the
-// file/line visible in the final binary (pcfile, pcln, etc).
-func (ctxt *Link) getFileSymbolAndLine(xpos src.XPos) (f string, l int32) {
- pos := ctxt.InnermostPos(xpos)
- if !pos.IsKnown() {
- pos = src.Pos{}
- }
- return pos.SymFilename(), int32(pos.RelLine())
-}
-
// getFileIndexAndLine returns the relative file index (local to the CU), and
// the relative line number for a position (i.e., as adjusted by a //line
// directive). This is the file/line visible in the final binary (pcfile, pcln,
// etc).
func (ctxt *Link) getFileIndexAndLine(xpos src.XPos) (int, int32) {
- f, l := ctxt.getFileSymbolAndLine(xpos)
- return ctxt.PosTable.FileIndex(f), l
+ pos := ctxt.InnermostPos(xpos)
+ if !pos.IsKnown() {
+ pos = src.Pos{}
+ }
+ return pos.FileIndex(), int32(pos.RelLine())
}
}
for _, test := range tests {
- f, l := ctxt.getFileSymbolAndLine(ctxt.PosTable.XPos(test.pos))
- got := fmt.Sprintf("%s:%d", f, l)
- if got != src.FileSymPrefix+test.want {
+ fileIndex, line := ctxt.getFileIndexAndLine(ctxt.PosTable.XPos(test.pos))
+
+ file := "??"
+ if fileIndex >= 0 {
+ file = ctxt.PosTable.FileTable()[fileIndex]
+ }
+ got := fmt.Sprintf("%s:%d", file, line)
+
+ if got != test.want {
t.Errorf("ctxt.getFileSymbolAndLine(%v) = %q, want %q", test.pos, got, test.want)
}
}
// startLine should be the same line number that would be displayed via
// pcln, etc for the declaration (i.e., relative line number, as
// adjusted by //line).
- _, startLine := ctxt.getFileSymbolAndLine(start)
+ _, startLine := ctxt.getFileIndexAndLine(start)
s.Func().FuncID = objabi.GetFuncID(s.Name, flag&WRAPPER != 0 || flag&ABIWRAPPER != 0)
s.Func().FuncFlag = ctxt.toFuncFlag(flag)
if call.Func != nil {
fn(fsym, call.Func)
}
- f, _ := ctxt.getFileSymbolAndLine(call.Pos)
- if filesym := ctxt.Lookup(f); filesym != nil {
- fn(fsym, filesym)
- }
}
auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym, fninfo.sehUnwindInfoSym}
// AbsFilename() returns the absolute filename recorded with the position's base.
func (p Pos) AbsFilename() string { return p.base.AbsFilename() }
-// SymFilename() returns the absolute filename recorded with the position's base,
-// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol.
-func (p Pos) SymFilename() string { return p.base.SymFilename() }
+// FileIndex returns the file index of the position's base's absolute
+// filename within the PosTable that it was registered.
+func (p Pos) FileIndex() int { return p.base.FileIndex() }
func (p Pos) String() string {
return p.Format(true, true)
pos Pos // position at which the relative position is (line, col)
filename string // file name used to open source file, for error messages
absFilename string // absolute file name, for PC-Line tables
- symFilename string // cached symbol file name, to avoid repeated string concatenation
line, col uint // relative line, column number at pos
inl int // inlining index (see cmd/internal/obj/inl.go)
+ fileIndex int // index of absFilename within PosTable.FileTable
}
// NewFileBase returns a new *PosBase for a file with the given (relative and
base := &PosBase{
filename: filename,
absFilename: absFilename,
- symFilename: FileSymPrefix + absFilename,
line: 1,
col: 1,
inl: -1,
+ fileIndex: -1,
}
base.pos = MakePos(base, 1, 1)
return base
//
// at position pos.
func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase {
- return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1}
+ return &PosBase{pos, filename, absFilename, line, col, -1, -1}
}
-// NewInliningBase returns a copy of the old PosBase with the given inlining
-// index. If old == nil, the resulting PosBase has no filename.
-func NewInliningBase(old *PosBase, inlTreeIndex int) *PosBase {
- if old == nil {
- base := &PosBase{line: 1, col: 1, inl: inlTreeIndex}
- base.pos = MakePos(base, 1, 1)
- return base
+// NewInliningBase returns a copy of the orig PosBase with the given inlining
+// index. If orig == nil, NewInliningBase panics.
+func NewInliningBase(orig *PosBase, inlTreeIndex int) *PosBase {
+ if orig == nil {
+ panic("no old PosBase")
}
- copy := *old
- base := ©
+ base := *orig
base.inl = inlTreeIndex
- if old == old.pos.base {
- base.pos.base = base
+ base.fileIndex = -1
+ if orig == orig.pos.base {
+ base.pos.base = &base
}
- return base
+ return &base
}
var noPos Pos
return ""
}
+// FileSymPrefix is the linker symbol prefix that used to be used for
+// linker pseudo-symbols representing file names.
const FileSymPrefix = "gofile.."
-// SymFilename returns the absolute filename recorded with the base,
-// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol.
-// If b is nil, SymFilename returns FileSymPrefix + "??".
-func (b *PosBase) SymFilename() string {
+// FileIndex returns the index of the base's absolute filename within
+// its PosTable's FileTable. It panics if it hasn't been registered
+// with a PosTable. If b == nil, the result is -1.
+func (b *PosBase) FileIndex() int {
if b != nil {
- return b.symFilename
+ if b.fileIndex < 0 {
+ panic("PosBase has no file index")
+ }
+ return b.fileIndex
}
- return FileSymPrefix + "??"
+ return -1
}
// Line returns the line number recorded with the base.
// XPos returns the corresponding XPos for the given pos,
// adding pos to t if necessary.
func (t *PosTable) XPos(pos Pos) XPos {
- m := t.indexMap
- if m == nil {
- // Create new list and map and populate with nil
- // base so that NoPos always gets index 0.
+ return XPos{t.baseIndex(pos.base), pos.lico}
+}
+
+func (t *PosTable) baseIndex(base *PosBase) int32 {
+ if base == nil {
+ return 0
+ }
+
+ if i, ok := t.indexMap[base]; ok {
+ return int32(i)
+ }
+
+ if base.fileIndex >= 0 {
+ panic("PosBase already registered with a PosTable")
+ }
+
+ if t.indexMap == nil {
t.baseList = append(t.baseList, nil)
- m = map[*PosBase]int{nil: 0}
- t.indexMap = m
+ t.indexMap = make(map[*PosBase]int)
t.nameMap = make(map[string]int)
}
- i, ok := m[pos.base]
+
+ i := len(t.baseList)
+ t.indexMap[base] = i
+ t.baseList = append(t.baseList, base)
+
+ fileIndex, ok := t.nameMap[base.absFilename]
if !ok {
- i = len(t.baseList)
- t.baseList = append(t.baseList, pos.base)
- t.indexMap[pos.base] = i
- if _, ok := t.nameMap[pos.base.symFilename]; !ok {
- t.nameMap[pos.base.symFilename] = len(t.nameMap)
- }
+ fileIndex = len(t.nameMap)
+ t.nameMap[base.absFilename] = fileIndex
}
- return XPos{int32(i), pos.lico}
+ base.fileIndex = fileIndex
+
+ return int32(i)
}
// Pos returns the corresponding Pos for the given p.
return Pos{base, p.lico}
}
-// FileIndex returns the index of the given filename(symbol) in the PosTable, or -1 if not found.
-func (t *PosTable) FileIndex(filename string) int {
- if v, ok := t.nameMap[filename]; ok {
- return v
- }
- return -1
-}
-
// FileTable returns a slice of all files used to build this package.
func (t *PosTable) FileTable() []string {
// Create a LUT of the global package level file indices. This table is what
}
}
- if len(tab.baseList) != len(tab.indexMap) {
- t.Errorf("table length discrepancy: %d != %d", len(tab.baseList), len(tab.indexMap))
+ if len(tab.baseList) != 1+len(tab.indexMap) { // indexMap omits nil
+ t.Errorf("table length discrepancy: %d != 1+%d", len(tab.baseList), len(tab.indexMap))
}
const wantLen = 4
// At the moment these interfaces are only used in the compiler.
-func (c dwctxt) AddFileRef(s dwarf.Sym, f interface{}) {
- panic("should be used only in the compiler")
-}
-
func (c dwctxt) CurrentOffset(s dwarf.Sym) int64 {
panic("should be used only in the compiler")
}