diff options
Diffstat (limited to 'src/cmd/newlink/pclntab_test.go')
-rw-r--r-- | src/cmd/newlink/pclntab_test.go | 340 |
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]) -} |