...

Source file src/go/internal/gcimporter/exportdata.go

     1	// Copyright 2011 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	// This file implements FindExportData.
     6	
     7	package gcimporter
     8	
     9	import (
    10		"bufio"
    11		"fmt"
    12		"io"
    13		"strconv"
    14		"strings"
    15	)
    16	
    17	func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
    18		// See $GOROOT/include/ar.h.
    19		hdr := make([]byte, 16+12+6+6+8+10+2)
    20		_, err = io.ReadFull(r, hdr)
    21		if err != nil {
    22			return
    23		}
    24		// leave for debugging
    25		if false {
    26			fmt.Printf("header: %s", hdr)
    27		}
    28		s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
    29		size, err = strconv.Atoi(s)
    30		if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
    31			err = fmt.Errorf("invalid archive header")
    32			return
    33		}
    34		name = strings.TrimSpace(string(hdr[:16]))
    35		return
    36	}
    37	
    38	// FindExportData positions the reader r at the beginning of the
    39	// export data section of an underlying GC-created object/archive
    40	// file by reading from it. The reader must be positioned at the
    41	// start of the file before calling this function. The hdr result
    42	// is the string before the export data, either "$$" or "$$B".
    43	//
    44	func FindExportData(r *bufio.Reader) (hdr string, err error) {
    45		// Read first line to make sure this is an object file.
    46		line, err := r.ReadSlice('\n')
    47		if err != nil {
    48			err = fmt.Errorf("can't find export data (%v)", err)
    49			return
    50		}
    51	
    52		if string(line) == "!<arch>\n" {
    53			// Archive file. Scan to __.PKGDEF.
    54			var name string
    55			if name, _, err = readGopackHeader(r); err != nil {
    56				return
    57			}
    58	
    59			// First entry should be __.PKGDEF.
    60			if name != "__.PKGDEF" {
    61				err = fmt.Errorf("go archive is missing __.PKGDEF")
    62				return
    63			}
    64	
    65			// Read first line of __.PKGDEF data, so that line
    66			// is once again the first line of the input.
    67			if line, err = r.ReadSlice('\n'); err != nil {
    68				err = fmt.Errorf("can't find export data (%v)", err)
    69				return
    70			}
    71		}
    72	
    73		// Now at __.PKGDEF in archive or still at beginning of file.
    74		// Either way, line should begin with "go object ".
    75		if !strings.HasPrefix(string(line), "go object ") {
    76			err = fmt.Errorf("not a Go object file")
    77			return
    78		}
    79	
    80		// Skip over object header to export data.
    81		// Begins after first line starting with $$.
    82		for line[0] != '$' {
    83			if line, err = r.ReadSlice('\n'); err != nil {
    84				err = fmt.Errorf("can't find export data (%v)", err)
    85				return
    86			}
    87		}
    88		hdr = string(line)
    89	
    90		return
    91	}
    92	

View as plain text