github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/link/prog_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "io/ioutil" 11 "testing" 12 ) 13 14 // shiftProg adjusts the addresses in p. 15 // It adds vdelta to all virtual addresses and fdelta to all file offsets. 16 func shiftProg(p *Prog, vdelta Addr, fdelta Addr) { 17 p.Entry += vdelta 18 for _, seg := range p.Segments { 19 seg.FileOffset += fdelta 20 seg.VirtAddr += vdelta 21 for _, sect := range seg.Sections { 22 sect.VirtAddr += vdelta 23 for _, sym := range sect.Syms { 24 sym.Addr += vdelta 25 } 26 } 27 } 28 } 29 30 // diffProg returns a list of differences between p and q, 31 // assuming p is being checked and q is the correct answer. 32 func diffProg(p, q *Prog) []string { 33 var errors []string 34 if p.UnmappedSize != q.UnmappedSize { 35 errors = append(errors, fmt.Sprintf("p.UnmappedSize = %#x, want %#x", p.UnmappedSize, q.UnmappedSize)) 36 } 37 if p.HeaderSize != q.HeaderSize { 38 errors = append(errors, fmt.Sprintf("p.HeaderSize = %#x, want %#x", p.HeaderSize, q.HeaderSize)) 39 } 40 if p.Entry != q.Entry { 41 errors = append(errors, fmt.Sprintf("p.Entry = %#x, want %#x", p.Entry, q.Entry)) 42 } 43 for i := 0; i < len(p.Segments) || i < len(q.Segments); i++ { 44 if i >= len(p.Segments) { 45 errors = append(errors, fmt.Sprintf("p missing segment %q", q.Segments[i].Name)) 46 continue 47 } 48 if i >= len(q.Segments) { 49 errors = append(errors, fmt.Sprintf("p has extra segment %q", p.Segments[i].Name)) 50 continue 51 } 52 pseg := p.Segments[i] 53 qseg := q.Segments[i] 54 if pseg.Name != qseg.Name { 55 errors = append(errors, fmt.Sprintf("segment %d Name = %q, want %q", i, pseg.Name, qseg.Name)) 56 continue // probably out of sync 57 } 58 if pseg.VirtAddr != qseg.VirtAddr { 59 errors = append(errors, fmt.Sprintf("segment %q VirtAddr = %#x, want %#x", pseg.Name, pseg.VirtAddr, qseg.VirtAddr)) 60 } 61 if pseg.VirtSize != qseg.VirtSize { 62 errors = append(errors, fmt.Sprintf("segment %q VirtSize = %#x, want %#x", pseg.Name, pseg.VirtSize, qseg.VirtSize)) 63 } 64 if pseg.FileOffset != qseg.FileOffset { 65 errors = append(errors, fmt.Sprintf("segment %q FileOffset = %#x, want %#x", pseg.Name, pseg.FileOffset, qseg.FileOffset)) 66 } 67 if pseg.FileSize != qseg.FileSize { 68 errors = append(errors, fmt.Sprintf("segment %q FileSize = %#x, want %#x", pseg.Name, pseg.FileSize, qseg.FileSize)) 69 } 70 if len(pseg.Data) != len(qseg.Data) { 71 errors = append(errors, fmt.Sprintf("segment %q len(Data) = %d, want %d", pseg.Name, len(pseg.Data), len(qseg.Data))) 72 } else if !bytes.Equal(pseg.Data, qseg.Data) { 73 errors = append(errors, fmt.Sprintf("segment %q Data mismatch:\n\thave %x\n\twant %x", pseg.Name, pseg.Data, qseg.Data)) 74 } 75 76 for j := 0; j < len(pseg.Sections) || j < len(qseg.Sections); j++ { 77 if j >= len(pseg.Sections) { 78 errors = append(errors, fmt.Sprintf("segment %q missing section %q", pseg.Name, qseg.Sections[i].Name)) 79 continue 80 } 81 if j >= len(qseg.Sections) { 82 errors = append(errors, fmt.Sprintf("segment %q has extra section %q", pseg.Name, pseg.Sections[i].Name)) 83 continue 84 } 85 psect := pseg.Sections[j] 86 qsect := qseg.Sections[j] 87 if psect.Name != qsect.Name { 88 errors = append(errors, fmt.Sprintf("segment %q, section %d Name = %q, want %q", pseg.Name, j, psect.Name, qsect.Name)) 89 continue // probably out of sync 90 } 91 92 if psect.VirtAddr != qsect.VirtAddr { 93 errors = append(errors, fmt.Sprintf("segment %q section %q VirtAddr = %#x, want %#x", pseg.Name, psect.Name, psect.VirtAddr, qsect.VirtAddr)) 94 } 95 if psect.Size != qsect.Size { 96 errors = append(errors, fmt.Sprintf("segment %q section %q Size = %#x, want %#x", pseg.Name, psect.Name, psect.Size, qsect.Size)) 97 } 98 if psect.Align != qsect.Align { 99 errors = append(errors, fmt.Sprintf("segment %q section %q Align = %#x, want %#x", pseg.Name, psect.Name, psect.Align, qsect.Align)) 100 } 101 } 102 } 103 104 return errors 105 } 106 107 // cloneProg returns a deep copy of p. 108 func cloneProg(p *Prog) *Prog { 109 q := new(Prog) 110 *q = *p 111 q.Segments = make([]*Segment, len(p.Segments)) 112 for i, seg := range p.Segments { 113 q.Segments[i] = cloneSegment(seg) 114 } 115 return q 116 } 117 118 // cloneSegment returns a deep copy of seg. 119 func cloneSegment(seg *Segment) *Segment { 120 t := new(Segment) 121 *t = *seg 122 t.Sections = make([]*Section, len(seg.Sections)) 123 for i, sect := range seg.Sections { 124 t.Sections[i] = cloneSection(sect) 125 } 126 t.Data = make([]byte, len(seg.Data)) 127 copy(t.Data, seg.Data) 128 return t 129 } 130 131 // cloneSection returns a deep copy of section. 132 func cloneSection(sect *Section) *Section { 133 // At the moment, there's nothing we need to make a deep copy of. 134 t := new(Section) 135 *t = *sect 136 return t 137 } 138 139 const saveMismatch = true 140 141 // checkGolden checks that data matches the named file. 142 // If not, it reports the error to the test. 143 func checkGolden(t *testing.T, data []byte, name string) { 144 golden := mustParseHexdumpFile(t, name) 145 if !bytes.Equal(data, golden) { 146 if saveMismatch { 147 ioutil.WriteFile(name+".raw", data, 0666) 148 ioutil.WriteFile(name+".hex", []byte(hexdump(data)), 0666) 149 } 150 // TODO(rsc): A better diff would be nice, as needed. 151 i := 0 152 for i < len(data) && i < len(golden) && data[i] == golden[i] { 153 i++ 154 } 155 if i >= len(data) { 156 t.Errorf("%s: output file shorter than expected: have %d bytes, want %d", name, len(data), len(golden)) 157 } else if i >= len(golden) { 158 t.Errorf("%s: output file larger than expected: have %d bytes, want %d", name, len(data), len(golden)) 159 } else { 160 t.Errorf("%s: output file differs at byte %d: have %#02x, want %#02x", name, i, data[i], golden[i]) 161 } 162 } 163 }