github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/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  }