aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/newlink/pclntab_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/newlink/pclntab_test.go')
-rw-r--r--src/cmd/newlink/pclntab_test.go340
1 files changed, 0 insertions, 340 deletions
diff --git a/src/cmd/newlink/pclntab_test.go b/src/cmd/newlink/pclntab_test.go
deleted file mode 100644
index ea80806742..0000000000
--- a/src/cmd/newlink/pclntab_test.go
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright 2014 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 main
-
-import (
- "bytes"
- "cmd/internal/goobj"
- "fmt"
- "math/rand"
- "sort"
- "strings"
- "testing"
-)
-
-// Test of pcln table encoding.
-// testdata/genpcln.go generates an assembly file with
-// pseudorandom values for the data that pclntab stores.
-// This test recomputes the same pseudorandom stream
-// and checks that the final linked binary uses those values
-// as well.
-func TestPclntab(t *testing.T) {
- p := &Prog{
- GOOS: "darwin",
- GOARCH: "amd64",
- Error: func(s string) { t.Error(s) },
- StartSym: "start",
- omitRuntime: true,
- }
- var buf bytes.Buffer
- p.link(&buf, "testdata/pclntab.6")
- if p.NumError > 0 {
- return
- }
-
- // The algorithm for computing values here must match
- // the one in testdata/genpcln.go.
- for f := 0; f < 3; f++ {
- file := "input"
- line := 1
- rnd := rand.New(rand.NewSource(int64(f)))
- args := rnd.Intn(100) * 8
- frame := 32 + rnd.Intn(32)/8*8
- size := 200 + rnd.Intn(100)*8
-
- name := fmt.Sprintf("func%d", f)
- r, off, fargs, fframe, ok := findFunc(t, p, name)
- if !ok {
- continue // error already printed
- }
- if fargs != args {
- t.Errorf("%s: args=%d, want %d", name, fargs, args)
- }
- if fframe != frame+8 {
- t.Errorf("%s: frame=%d, want %d", name, fframe, frame+8)
- }
-
- // Check FUNCDATA 1.
- fdata, ok := loadFuncdata(t, r, name, off, 1)
- if ok {
- fsym := p.Syms[goobj.SymID{Name: fmt.Sprintf("funcdata%d", f)}]
- if fsym == nil {
- t.Errorf("funcdata%d is missing in binary", f)
- } else if fdata != fsym.Addr {
- t.Errorf("%s: funcdata 1 = %#x, want %#x", name, fdata, fsym.Addr)
- }
- }
-
- // Walk code checking pcdata values.
- spadj := 0
- pcdata1 := -1
- pcdata2 := -1
-
- checkPCSP(t, r, name, off, 0, 0)
- checkPCData(t, r, name, off, 0, 0, -1)
- checkPCData(t, r, name, off, 0, 1, -1)
- checkPCData(t, r, name, off, 0, 2, -1)
-
- firstpc := 4
- for i := 0; i < size; i++ {
- pc := firstpc + i // skip SP adjustment to allocate frame
- if i >= 0x100 && t.Failed() {
- break
- }
- // Possible SP adjustment.
- checkPCSP(t, r, name, off, pc, frame+spadj)
- if rnd.Intn(100) == 0 {
- checkPCFileLine(t, r, name, off, pc, file, line)
- checkPCData(t, r, name, off, pc, 1, pcdata1)
- checkPCData(t, r, name, off, pc, 2, pcdata2)
- i += 1
- pc = firstpc + i
- checkPCFileLine(t, r, name, off, pc-1, file, line)
- checkPCData(t, r, name, off, pc-1, 1, pcdata1)
- checkPCData(t, r, name, off, pc-1, 2, pcdata2)
- checkPCSP(t, r, name, off, pc-1, frame+spadj)
-
- if spadj <= -32 || spadj < 32 && rnd.Intn(2) == 0 {
- spadj += 8
- } else {
- spadj -= 8
- }
- checkPCSP(t, r, name, off, pc, frame+spadj)
- }
-
- // Possible PCFile change.
- if rnd.Intn(100) == 0 {
- file = fmt.Sprintf("file%d.s", rnd.Intn(10))
- line = rnd.Intn(100) + 1
- }
-
- // Possible PCLine change.
- if rnd.Intn(10) == 0 {
- line = rnd.Intn(1000) + 1
- }
-
- // Possible PCData $1 change.
- if rnd.Intn(100) == 0 {
- pcdata1 = rnd.Intn(1000)
- }
-
- // Possible PCData $2 change.
- if rnd.Intn(100) == 0 {
- pcdata2 = rnd.Intn(1000)
- }
-
- if i == 0 {
- checkPCFileLine(t, r, name, off, 0, file, line)
- checkPCFileLine(t, r, name, off, pc-1, file, line)
- }
- checkPCFileLine(t, r, name, off, pc, file, line)
- checkPCData(t, r, name, off, pc, 1, pcdata1)
- checkPCData(t, r, name, off, pc, 2, pcdata2)
- }
- }
-}
-
-// findFunc finds the function information in the pclntab of p
-// for the function with the given name.
-// It returns a symbol reader for pclntab, the offset of the function information
-// within that symbol, and the args and frame values read out of the information.
-func findFunc(t *testing.T, p *Prog, name string) (r *SymReader, off, args, frame int, ok bool) {
- tabsym := p.Syms[goobj.SymID{Name: "runtime.pclntab"}]
- if tabsym == nil {
- t.Errorf("pclntab is missing in binary")
- return
- }
-
- r = new(SymReader)
- r.Init(p, tabsym)
-
- // pclntab must with 8-byte header
- if r.Uint32(0) != 0xfffffffb || r.Uint8(4) != 0 || r.Uint8(5) != 0 || r.Uint8(6) != uint8(p.pcquantum) || r.Uint8(7) != uint8(p.ptrsize) {
- t.Errorf("pclntab has incorrect header %.8x", r.data[:8])
- return
- }
-
- sym := p.Syms[goobj.SymID{Name: name}]
- if sym == nil {
- t.Errorf("%s is missing in the binary", name)
- return
- }
-
- // index is nfunc addr0 off0 addr1 off1 ... addr_nfunc (sentinel)
- nfunc := int(r.Addr(8))
- i := sort.Search(nfunc, func(i int) bool {
- return r.Addr(8+p.ptrsize*(1+2*i)) >= sym.Addr
- })
- if entry := r.Addr(8 + p.ptrsize*(1+2*i)); entry != sym.Addr {
- indexTab := make([]Addr, 2*nfunc+1)
- for j := range indexTab {
- indexTab[j] = r.Addr(8 + p.ptrsize*(1+j))
- }
- t.Errorf("pclntab is missing entry for %s (%#x): %#x", name, sym.Addr, indexTab)
- return
- }
-
- off = int(r.Addr(8 + p.ptrsize*(1+2*i+1)))
-
- // func description at off is
- // entry addr
- // nameoff uint32
- // args uint32
- // frame uint32
- // pcspoff uint32
- // pcfileoff uint32
- // pclineoff uint32
- // npcdata uint32
- // nfuncdata uint32
- // pcdata npcdata*uint32
- // funcdata nfuncdata*addr
- //
- if entry := r.Addr(off); entry != sym.Addr {
- t.Errorf("pclntab inconsistent: entry for %s addr=%#x has entry=%#x", name, sym.Addr, entry)
- return
- }
- nameoff := int(r.Uint32(off + p.ptrsize))
- args = int(r.Uint32(off + p.ptrsize + 1*4))
- frame = int(r.Uint32(off + p.ptrsize + 2*4))
-
- fname := r.String(nameoff)
- if fname != name {
- t.Errorf("pclntab inconsistent: entry for %s addr=%#x has name %q", name, sym.Addr, fname)
- }
-
- ok = true // off, args, frame are usable
- return
-}
-
-// loadFuncdata returns the funcdata #fnum value
-// loaded from the function information for name.
-func loadFuncdata(t *testing.T, r *SymReader, name string, off int, fnum int) (Addr, bool) {
- npcdata := int(r.Uint32(off + r.p.ptrsize + 6*4))
- nfuncdata := int(r.Uint32(off + r.p.ptrsize + 7*4))
- if fnum >= nfuncdata {
- t.Errorf("pclntab(%s): no funcdata %d (only < %d)", name, fnum, nfuncdata)
- return 0, false
- }
- fdataoff := off + r.p.ptrsize + (8+npcdata)*4 + fnum*r.p.ptrsize
- fdataoff += fdataoff & 4
- return r.Addr(fdataoff), true
-}
-
-// checkPCSP checks that the PCSP table in the function information at off
-// lists spadj as the sp delta for pc.
-func checkPCSP(t *testing.T, r *SymReader, name string, off, pc, spadj int) {
- pcoff := r.Uint32(off + r.p.ptrsize + 3*4)
- pcval, ok := readPCData(t, r, name, "PCSP", pcoff, pc)
- if !ok {
- return
- }
- if pcval != spadj {
- t.Errorf("pclntab(%s): at pc=+%#x, pcsp=%d, want %d", name, pc, pcval, spadj)
- }
-}
-
-// checkPCSP checks that the PCFile and PCLine tables in the function information at off
-// list file, line as the file name and line number for pc.
-func checkPCFileLine(t *testing.T, r *SymReader, name string, off, pc int, file string, line int) {
- pcfileoff := r.Uint32(off + r.p.ptrsize + 4*4)
- pclineoff := r.Uint32(off + r.p.ptrsize + 5*4)
- pcfilenum, ok1 := readPCData(t, r, name, "PCFile", pcfileoff, pc)
- pcline, ok2 := readPCData(t, r, name, "PCLine", pclineoff, pc)
- if !ok1 || !ok2 {
- return
- }
- nfunc := int(r.Addr(8))
- filetaboff := r.Uint32(8 + r.p.ptrsize*2*(nfunc+1))
- nfile := int(r.Uint32(int(filetaboff)))
- if pcfilenum <= 0 || pcfilenum >= nfile {
- t.Errorf("pclntab(%s): at pc=+%#x, filenum=%d (invalid; nfile=%d)", name, pc, pcfilenum, nfile)
- }
- pcfile := r.String(int(r.Uint32(int(filetaboff) + pcfilenum*4)))
- if !strings.HasSuffix(pcfile, file) {
- t.Errorf("pclntab(%s): at pc=+%#x, file=%q, want %q", name, pc, pcfile, file)
- }
- if pcline != line {
- t.Errorf("pclntab(%s): at pc=+%#x, line=%d, want %d", name, pc, pcline, line)
- }
-}
-
-// checkPCData checks that the PCData#pnum table in the function information at off
-// list val as the value for pc.
-func checkPCData(t *testing.T, r *SymReader, name string, off, pc, pnum, val int) {
- pcoff := r.Uint32(off + r.p.ptrsize + (8+pnum)*4)
- pcval, ok := readPCData(t, r, name, fmt.Sprintf("PCData#%d", pnum), pcoff, pc)
- if !ok {
- return
- }
- if pcval != val {
- t.Errorf("pclntab(%s): at pc=+%#x, pcdata#%d=%d, want %d", name, pc, pnum, pcval, val)
- }
-}
-
-// readPCData reads the PCData table offset off
-// to obtain and return the value associated with pc.
-func readPCData(t *testing.T, r *SymReader, name, pcdataname string, pcoff uint32, pc int) (int, bool) {
- // "If pcsp, pcfile, pcln, or any of the pcdata offsets is zero,
- // that table is considered missing, and all PCs take value -1."
- if pcoff == 0 {
- return -1, true
- }
-
- var it PCIter
- for it.Init(r.p, r.data[pcoff:]); !it.Done; it.Next() {
- if it.PC <= uint32(pc) && uint32(pc) < it.NextPC {
- return int(it.Value), true
- }
- }
- if it.Corrupt {
- t.Errorf("pclntab(%s): %s: corrupt pcdata table", name, pcdataname)
- }
- return 0, false
-}
-
-// A SymReader provides typed access to the data for a symbol.
-type SymReader struct {
- p *Prog
- data []byte
-}
-
-func (r *SymReader) Init(p *Prog, sym *Sym) {
- seg := sym.Section.Segment
- off := sym.Addr - seg.VirtAddr
- data := seg.Data[off : off+Addr(sym.Size)]
- r.p = p
- r.data = data
-}
-
-func (r *SymReader) Uint8(off int) uint8 {
- return r.data[off]
-}
-
-func (r *SymReader) Uint16(off int) uint16 {
- return r.p.byteorder.Uint16(r.data[off:])
-}
-
-func (r *SymReader) Uint32(off int) uint32 {
- return r.p.byteorder.Uint32(r.data[off:])
-}
-
-func (r *SymReader) Uint64(off int) uint64 {
- return r.p.byteorder.Uint64(r.data[off:])
-}
-
-func (r *SymReader) Addr(off int) Addr {
- if r.p.ptrsize == 4 {
- return Addr(r.Uint32(off))
- }
- return Addr(r.Uint64(off))
-}
-
-func (r *SymReader) String(off int) string {
- end := off
- for r.data[end] != '\x00' {
- end++
- }
- return string(r.data[off:end])
-}