mirror of
https://github.com/golang/go
synced 2024-11-18 13:04:46 -07:00
cmd/link: make PCIter available to compiler
I'm branching this off cl/187117, and will be reworking that diff stack. Testing: I've run go build -toolexec 'toolstash -cmp' Change-Id: I922a97d0f25d52ea70cd974008a063d4e7af34a7 Reviewed-on: https://go-review.googlesource.com/c/go/+/188023 Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
8b6fa668ee
commit
8f816259ee
@ -384,3 +384,69 @@ func linkpcln(ctxt *Link, cursym *LSym) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PCIter iterates over encoded pcdata tables.
|
||||
type PCIter struct {
|
||||
p []byte
|
||||
PC uint32
|
||||
NextPC uint32
|
||||
PCScale uint32
|
||||
Value int32
|
||||
start bool
|
||||
Done bool
|
||||
}
|
||||
|
||||
// newPCIter creates a PCIter with a scale factor for the PC step size.
|
||||
func NewPCIter(pcScale uint32) *PCIter {
|
||||
it := new(PCIter)
|
||||
it.PCScale = pcScale
|
||||
return it
|
||||
}
|
||||
|
||||
// Next advances it to the Next pc.
|
||||
func (it *PCIter) Next() {
|
||||
it.PC = it.NextPC
|
||||
if it.Done {
|
||||
return
|
||||
}
|
||||
if len(it.p) == 0 {
|
||||
it.Done = true
|
||||
return
|
||||
}
|
||||
|
||||
// Value delta
|
||||
val, n := binary.Varint(it.p)
|
||||
if n <= 0 {
|
||||
log.Fatalf("bad Value varint in pciterNext: read %v", n)
|
||||
}
|
||||
it.p = it.p[n:]
|
||||
|
||||
if val == 0 && !it.start {
|
||||
it.Done = true
|
||||
return
|
||||
}
|
||||
|
||||
it.start = false
|
||||
it.Value += int32(val)
|
||||
|
||||
// pc delta
|
||||
pc, n := binary.Uvarint(it.p)
|
||||
if n <= 0 {
|
||||
log.Fatalf("bad pc varint in pciterNext: read %v", n)
|
||||
}
|
||||
it.p = it.p[n:]
|
||||
|
||||
it.NextPC = it.PC + uint32(pc)*it.PCScale
|
||||
}
|
||||
|
||||
// init prepares it to iterate over p,
|
||||
// and advances it to the first pc.
|
||||
func (it *PCIter) Init(p []byte) {
|
||||
it.p = p
|
||||
it.PC = 0
|
||||
it.NextPC = 0
|
||||
it.Value = -1
|
||||
it.start = true
|
||||
it.Done = false
|
||||
it.Next()
|
||||
}
|
||||
|
@ -1212,42 +1212,42 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
|
||||
file := 1
|
||||
ls.AddAddr(ctxt.Arch, s)
|
||||
|
||||
pcfile := newPCIter(ctxt)
|
||||
pcline := newPCIter(ctxt)
|
||||
pcstmt := newPCIter(ctxt)
|
||||
pcfile := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
pcline := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
pcstmt := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
for i, s := range unit.lib.Textp {
|
||||
finddebugruntimepath(s)
|
||||
|
||||
pcfile.init(s.FuncInfo.Pcfile.P)
|
||||
pcline.init(s.FuncInfo.Pcline.P)
|
||||
pcfile.Init(s.FuncInfo.Pcfile.P)
|
||||
pcline.Init(s.FuncInfo.Pcline.P)
|
||||
|
||||
isStmtSym := dwarfFuncSym(ctxt, s, dwarf.IsStmtPrefix, false)
|
||||
if isStmtSym != nil && len(isStmtSym.P) > 0 {
|
||||
pcstmt.init(isStmtSym.P)
|
||||
pcstmt.Init(isStmtSym.P)
|
||||
} else {
|
||||
// Assembly files lack a pcstmt section, we assume that every instruction
|
||||
// is a valid statement.
|
||||
pcstmt.done = true
|
||||
pcstmt.value = 1
|
||||
pcstmt.Done = true
|
||||
pcstmt.Value = 1
|
||||
}
|
||||
|
||||
var thispc uint32
|
||||
// TODO this loop looks like it could exit with work remaining.
|
||||
for !pcfile.done && !pcline.done {
|
||||
for !pcfile.Done && !pcline.Done {
|
||||
// Only changed if it advanced
|
||||
if int32(file) != pcfile.value {
|
||||
if int32(file) != pcfile.Value {
|
||||
ls.AddUint8(dwarf.DW_LNS_set_file)
|
||||
idx, ok := fileNums[int(pcfile.value)]
|
||||
idx, ok := fileNums[int(pcfile.Value)]
|
||||
if !ok {
|
||||
Exitf("pcln table file missing from DWARF line table")
|
||||
}
|
||||
dwarf.Uleb128put(dwarfctxt, ls, int64(idx))
|
||||
file = int(pcfile.value)
|
||||
file = int(pcfile.Value)
|
||||
}
|
||||
|
||||
// Only changed if it advanced
|
||||
if is_stmt != uint8(pcstmt.value) {
|
||||
new_stmt := uint8(pcstmt.value)
|
||||
if is_stmt != uint8(pcstmt.Value) {
|
||||
new_stmt := uint8(pcstmt.Value)
|
||||
switch new_stmt &^ 1 {
|
||||
case obj.PrologueEnd:
|
||||
ls.AddUint8(uint8(dwarf.DW_LNS_set_prologue_end))
|
||||
@ -1263,28 +1263,28 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
|
||||
}
|
||||
|
||||
// putpcldelta makes a row in the DWARF matrix, always, even if line is unchanged.
|
||||
putpclcdelta(ctxt, dwarfctxt, ls, uint64(s.Value+int64(thispc)-pc), int64(pcline.value)-int64(line))
|
||||
putpclcdelta(ctxt, dwarfctxt, ls, uint64(s.Value+int64(thispc)-pc), int64(pcline.Value)-int64(line))
|
||||
|
||||
pc = s.Value + int64(thispc)
|
||||
line = int(pcline.value)
|
||||
line = int(pcline.Value)
|
||||
|
||||
// Take the minimum step forward for the three iterators
|
||||
thispc = pcfile.nextpc
|
||||
if pcline.nextpc < thispc {
|
||||
thispc = pcline.nextpc
|
||||
thispc = pcfile.NextPC
|
||||
if pcline.NextPC < thispc {
|
||||
thispc = pcline.NextPC
|
||||
}
|
||||
if !pcstmt.done && pcstmt.nextpc < thispc {
|
||||
thispc = pcstmt.nextpc
|
||||
if !pcstmt.Done && pcstmt.NextPC < thispc {
|
||||
thispc = pcstmt.NextPC
|
||||
}
|
||||
|
||||
if pcfile.nextpc == thispc {
|
||||
pcfile.next()
|
||||
if pcfile.NextPC == thispc {
|
||||
pcfile.Next()
|
||||
}
|
||||
if !pcstmt.done && pcstmt.nextpc == thispc {
|
||||
pcstmt.next()
|
||||
if !pcstmt.Done && pcstmt.NextPC == thispc {
|
||||
pcstmt.Next()
|
||||
}
|
||||
if pcline.nextpc == thispc {
|
||||
pcline.next()
|
||||
if pcline.NextPC == thispc {
|
||||
pcline.Next()
|
||||
}
|
||||
}
|
||||
if is_stmt == 0 && i < len(unit.lib.Textp)-1 {
|
||||
@ -1451,7 +1451,7 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
||||
fs.AddBytes(zeros[:pad])
|
||||
|
||||
var deltaBuf []byte
|
||||
pcsp := newPCIter(ctxt)
|
||||
pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.FuncInfo == nil {
|
||||
continue
|
||||
@ -1467,19 +1467,19 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
||||
deltaBuf = append(deltaBuf, dwarf.DW_CFA_undefined)
|
||||
deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
|
||||
}
|
||||
for pcsp.init(s.FuncInfo.Pcsp.P); !pcsp.done; pcsp.next() {
|
||||
nextpc := pcsp.nextpc
|
||||
for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() {
|
||||
nextpc := pcsp.NextPC
|
||||
|
||||
// pciterinit goes up to the end of the function,
|
||||
// but DWARF expects us to stop just before the end.
|
||||
if int64(nextpc) == s.Size {
|
||||
nextpc--
|
||||
if nextpc < pcsp.pc {
|
||||
if nextpc < pcsp.PC {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
spdelta := int64(pcsp.value)
|
||||
spdelta := int64(pcsp.Value)
|
||||
if !haslinkregister(ctxt) {
|
||||
// Return address has been pushed onto stack.
|
||||
spdelta += int64(ctxt.Arch.PtrSize)
|
||||
@ -1489,7 +1489,7 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
||||
// TODO(bryanpkc): This is imprecise. In general, the instruction
|
||||
// that stores the return address to the stack frame is not the
|
||||
// same one that allocates the frame.
|
||||
if pcsp.value > 0 {
|
||||
if pcsp.Value > 0 {
|
||||
// The return address is preserved at (CFA-frame_size)
|
||||
// after a stack frame has been allocated.
|
||||
deltaBuf = append(deltaBuf, dwarf.DW_CFA_offset_extended_sf)
|
||||
@ -1503,7 +1503,7 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
deltaBuf = appendPCDeltaCFA(ctxt.Arch, deltaBuf, int64(nextpc)-int64(pcsp.pc), spdelta)
|
||||
deltaBuf = appendPCDeltaCFA(ctxt.Arch, deltaBuf, int64(nextpc)-int64(pcsp.PC), spdelta)
|
||||
}
|
||||
pad := int(Rnd(int64(len(deltaBuf)), int64(ctxt.Arch.PtrSize))) - len(deltaBuf)
|
||||
deltaBuf = append(deltaBuf, zeros[:pad]...)
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loadelf"
|
||||
@ -2137,24 +2138,24 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
|
||||
|
||||
endr := len(s.R)
|
||||
var ch1 chain
|
||||
pcsp := newPCIter(ctxt)
|
||||
pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
var r *sym.Reloc
|
||||
for pcsp.init(s.FuncInfo.Pcsp.P); !pcsp.done; pcsp.next() {
|
||||
for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() {
|
||||
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
|
||||
|
||||
// Check stack size in effect for this span.
|
||||
if int32(limit)-pcsp.value < 0 {
|
||||
stkbroke(ctxt, up, int(int32(limit)-pcsp.value))
|
||||
if int32(limit)-pcsp.Value < 0 {
|
||||
stkbroke(ctxt, up, int(int32(limit)-pcsp.Value))
|
||||
return -1
|
||||
}
|
||||
|
||||
// Process calls in this span.
|
||||
for ; ri < endr && uint32(s.R[ri].Off) < pcsp.nextpc; ri++ {
|
||||
for ; ri < endr && uint32(s.R[ri].Off) < pcsp.NextPC; ri++ {
|
||||
r = &s.R[ri]
|
||||
switch r.Type {
|
||||
// Direct call.
|
||||
case objabi.R_CALL, objabi.R_CALLARM, objabi.R_CALLARM64, objabi.R_CALLPOWER, objabi.R_CALLMIPS:
|
||||
ch.limit = int(int32(limit) - pcsp.value - int32(callsize(ctxt)))
|
||||
ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
|
||||
ch.sym = r.Sym
|
||||
if stkcheck(ctxt, &ch, depth+1) < 0 {
|
||||
return -1
|
||||
@ -2165,7 +2166,7 @@ func stkcheck(ctxt *Link, up *chain, depth int) int {
|
||||
// Arrange the data structures to report both calls, so that
|
||||
// if there is an error, stkprint shows all the steps involved.
|
||||
case objabi.R_CALLIND:
|
||||
ch.limit = int(int32(limit) - pcsp.value - int32(callsize(ctxt)))
|
||||
ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
|
||||
|
||||
ch.sym = nil
|
||||
ch1.limit = ch.limit - callsize(ctxt) // for morestack in called prologue
|
||||
|
@ -5,6 +5,7 @@
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"cmd/internal/sys"
|
||||
@ -16,72 +17,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PCIter iterates over encoded pcdata tables.
|
||||
type PCIter struct {
|
||||
p []byte
|
||||
pc uint32
|
||||
nextpc uint32
|
||||
pcscale uint32
|
||||
value int32
|
||||
start bool
|
||||
done bool
|
||||
}
|
||||
|
||||
// newPCIter creates a PCIter and configures it for ctxt's architecture.
|
||||
func newPCIter(ctxt *Link) *PCIter {
|
||||
it := new(PCIter)
|
||||
it.pcscale = uint32(ctxt.Arch.MinLC)
|
||||
return it
|
||||
}
|
||||
|
||||
// next advances it to the next pc.
|
||||
func (it *PCIter) next() {
|
||||
it.pc = it.nextpc
|
||||
if it.done {
|
||||
return
|
||||
}
|
||||
if len(it.p) == 0 {
|
||||
it.done = true
|
||||
return
|
||||
}
|
||||
|
||||
// value delta
|
||||
val, n := binary.Varint(it.p)
|
||||
if n <= 0 {
|
||||
log.Fatalf("bad value varint in pciternext: read %v", n)
|
||||
}
|
||||
it.p = it.p[n:]
|
||||
|
||||
if val == 0 && !it.start {
|
||||
it.done = true
|
||||
return
|
||||
}
|
||||
|
||||
it.start = false
|
||||
it.value += int32(val)
|
||||
|
||||
// pc delta
|
||||
pc, n := binary.Uvarint(it.p)
|
||||
if n <= 0 {
|
||||
log.Fatalf("bad pc varint in pciternext: read %v", n)
|
||||
}
|
||||
it.p = it.p[n:]
|
||||
|
||||
it.nextpc = it.pc + uint32(pc)*it.pcscale
|
||||
}
|
||||
|
||||
// init prepares it to iterate over p,
|
||||
// and advances it to the first pc.
|
||||
func (it *PCIter) init(p []byte) {
|
||||
it.p = p
|
||||
it.pc = 0
|
||||
it.nextpc = 0
|
||||
it.value = -1
|
||||
it.start = true
|
||||
it.done = false
|
||||
it.next()
|
||||
}
|
||||
|
||||
func ftabaddstring(ftab *sym.Symbol, s string) int32 {
|
||||
start := len(ftab.P)
|
||||
ftab.Grow(int64(start + len(s) + 1)) // make room for s plus trailing NUL
|
||||
@ -109,10 +44,10 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
|
||||
buf := make([]byte, binary.MaxVarintLen32)
|
||||
newval := int32(-1)
|
||||
var out sym.Pcdata
|
||||
it := newPCIter(ctxt)
|
||||
for it.init(d.P); !it.done; it.next() {
|
||||
it := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
for it.Init(d.P); !it.Done; it.Next() {
|
||||
// value delta
|
||||
oldval := it.value
|
||||
oldval := it.Value
|
||||
|
||||
var val int32
|
||||
if oldval == -1 {
|
||||
@ -132,7 +67,7 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
|
||||
out.P = append(out.P, buf[:n]...)
|
||||
|
||||
// pc delta
|
||||
pc := (it.nextpc - it.pc) / it.pcscale
|
||||
pc := (it.NextPC - it.PC) / it.PCScale
|
||||
n = binary.PutUvarint(buf, uint64(pc))
|
||||
out.P = append(out.P, buf[:n]...)
|
||||
}
|
||||
@ -337,10 +272,10 @@ func (ctxt *Link) pclntab() {
|
||||
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
|
||||
if false {
|
||||
// Sanity check the new numbering
|
||||
it := newPCIter(ctxt)
|
||||
for it.init(pcln.Pcfile.P); !it.done; it.next() {
|
||||
if it.value < 1 || it.value > int32(len(ctxt.Filesyms)) {
|
||||
Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(ctxt.Filesyms))
|
||||
it := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
|
||||
for it.Init(pcln.Pcfile.P); !it.Done; it.Next() {
|
||||
if it.Value < 1 || it.Value > int32(len(ctxt.Filesyms)) {
|
||||
Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.Value, len(ctxt.Filesyms))
|
||||
errorexit()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user