import (
"cmd/internal/dwarf"
+ "cmd/internal/src"
"fmt"
)
func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
dctxt := dwCtxt{ctxt}
- // The Pcfile table is used to generate the debug_lines section, and the file
- // indices for that data could differ from the files we write out for the
- // debug_lines section. Here we generate a LUT between those two indices.
- fileNums := make(map[int32]int64)
- for i, filename := range s.Func.Pcln.File {
- if symbolIndex := ctxt.PosTable.FileIndex(filename); symbolIndex >= 0 {
- fileNums[int32(i)] = int64(symbolIndex) + 1
- } else {
- panic(fmt.Sprintf("First time we've seen filename: %q", filename))
- }
- }
-
// Set up the debug_lines state machine.
// NB: This state machine is reset to this state when we've finished
// generating the line table. See below.
// TODO: Once delve can support multiple DW_LNS_end_statements, we don't have
// to do this.
- is_stmt := uint8(1)
+ stmt := true
+ line := int64(1)
pc := s.Func.Text.Pc
- line := 1
- file := 1
-
- // The linker will insert the DW_LNE_set_address once determined; therefore,
- // it's omitted here.
-
- // Generate the actual line information.
- // We use the pcline and pcfile to generate this section, and it's suboptimal.
- // Likely better would be to generate this dirrectly from the progs and not
- // parse those tables.
- // TODO: Generate from the progs if it's faster.
- pcfile := NewPCIter(uint32(ctxt.Arch.Arch.MinLC))
- pcline := NewPCIter(uint32(ctxt.Arch.Arch.MinLC))
- pcstmt := NewPCIter(uint32(ctxt.Arch.Arch.MinLC))
- pcfile.Init(s.Func.Pcln.Pcfile.P)
- pcline.Init(s.Func.Pcln.Pcline.P)
- var pctostmtData Pcdata
- funcpctab(ctxt, &pctostmtData, s, "pctostmt", pctostmt, nil)
- pcstmt.Init(pctostmtData.P)
- var thispc uint32
-
- for !pcfile.Done && !pcline.Done {
- // Only changed if it advanced
- if int32(file) != pcfile.Value {
- dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
- dwarf.Uleb128put(dctxt, lines, fileNums[pcfile.Value])
- file = int(pcfile.Value)
+ name := ""
+ prologue, wrotePrologue := false, false
+
+ // Walk the progs, generating the DWARF table.
+ for p := s.Func.Text; p != nil; p = p.Link {
+ prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
+ // If we're not at a real instruction, keep looping!
+ if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == pc) {
+ continue
}
+ newStmt := p.Pos.IsStmt() != src.PosNotStmt
+ newName, newLine := linkgetlineFromPos(ctxt, p.Pos)
- // Only changed if it advanced
- if is_stmt != uint8(pcstmt.Value) {
- new_stmt := uint8(pcstmt.Value)
- switch new_stmt &^ 1 {
- case PrologueEnd:
- dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
- case EpilogueBegin:
- // TODO if there is a use for this, add it.
- // Don't forget to increase OPCODE_BASE by 1 and add entry for standard_opcode_lengths[11]
- panic("unsupported EpilogueBegin")
- }
- new_stmt &= 1
- if is_stmt != new_stmt {
- is_stmt = new_stmt
- dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
- }
+ // Output debug info.
+ wrote := false
+ if name != newName {
+ newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
+ dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
+ dwarf.Uleb128put(dctxt, lines, int64(newFile))
+ name = newName
+ wrote = true
}
-
- // putpcldelta makes a row in the DWARF matrix, always, even if line is unchanged.
- putpclcdelta(ctxt, dctxt, lines, uint64(s.Func.Text.Pc+int64(thispc)-pc), int64(pcline.Value)-int64(line))
-
- pc = s.Func.Text.Pc + int64(thispc)
- line = int(pcline.Value)
-
- // Take the minimum step forward for the three iterators
- thispc = pcfile.NextPC
- if pcline.NextPC < thispc {
- thispc = pcline.NextPC
+ if prologue && !wrotePrologue {
+ dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
+ wrotePrologue = true
+ wrote = true
}
- if !pcstmt.Done && pcstmt.NextPC < thispc {
- thispc = pcstmt.NextPC
+ if stmt != newStmt {
+ dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
+ stmt = newStmt
+ wrote = true
}
- if pcfile.NextPC == thispc {
- pcfile.Next()
- }
- if !pcstmt.Done && pcstmt.NextPC == thispc {
- pcstmt.Next()
- }
- if pcline.NextPC == thispc {
- pcline.Next()
+ if line != int64(newLine) || wrote {
+ pcdelta := (p.Pc - pc) / int64(ctxt.Arch.MinLC)
+ putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
+ line, pc = int64(newLine), p.Pc
}
}
// file = 1
// line = 1
// column = 0
- // is_stmt = set in header, we assume true
+ // stmt = set in header, we assume true
// basic_block = false
// Careful readers of the DWARF specification will note that we don't reset
// the address of the state machine -- but this will happen at the beginning
- // of the NEXT block of opcodes. (See the SetAddress call above.)
+ // of the NEXT block of opcodes.
dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
dwarf.Uleb128put(dctxt, lines, 1)
dctxt.AddUint8(lines, dwarf.DW_LNS_advance_line)
dwarf.Sleb128put(dctxt, lines, int64(1-line))
- if is_stmt != 1 {
+ if !stmt {
dctxt.AddUint8(lines, dwarf.DW_LNS_negate_stmt)
}
dctxt.AddUint8(lines, dwarf.DW_LNS_copy)
package obj
import (
- "cmd/internal/src"
"encoding/binary"
"log"
)
return oldval + p.Spadj
}
-// pctostmt returns either,
-// if phase==0, then whether the current instruction is a step-target (Dwarf is_stmt)
-// bit-or'd with whether the current statement is a prologue end or epilogue begin
-// else (phase == 1), zero.
-//
-func pctostmt(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
- if phase == 1 {
- return 0 // Ignored; also different from initial value of -1, if that ever matters.
- }
- s := p.Pos.IsStmt()
- l := p.Pos.Xlogue()
-
- var is_stmt int32
-
- // PrologueEnd, at least, is passed to the next instruction
- switch l {
- case src.PosPrologueEnd:
- is_stmt = PrologueEnd
- case src.PosEpilogueBegin:
- is_stmt = EpilogueBegin
- }
-
- if s != src.PosNotStmt {
- is_stmt |= 1 // either PosDefaultStmt from asm, or PosIsStmt from go
- }
- return is_stmt
-}
-
// pctopcdata computes the pcdata value in effect at p.
// A PCDATA instruction sets the value in effect at future
// non-PCDATA instructions.