Exemple #1
0
// ReadUInt32 reads a uint32 from r.
func ReadUInt32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
	var buf [4]byte
	if _, err := io.ReadFull(r, buf[:]); err != nil {
		return 0, err
	}
	return byteOrder.Uint32(buf[:]), nil
}
Exemple #2
0
func NewNullFrame(data []byte, byteOrder binary.ByteOrder) (*NullFrame, error) {
	if len(data) < NULL_FRAME_HEADER_LENGTH {
		return nil, errors.New(fmt.Sprintf("required at least %d bytes of data.", NULL_FRAME_HEADER_LENGTH))
	}

	return &NullFrame{byteOrder.Uint32(data), data[4:]}, nil
}
Exemple #3
0
func ReadFloat32(buf []byte, format byte, endianness binary.ByteOrder) float32 {
	encoding := format & EncodingMask

	if encoding == EncodingFloatingPoint {
		return math.Float32frombits(endianness.Uint32(buf))
	} else {
		offset := 0
		if endianness == binary.LittleEndian {
			offset = len(buf) - 1
		}
		var neg byte = 0
		if encoding == EncodingSignedInt && buf[offset]&(1<<7) != 0 {
			neg = 0xFF
		}
		tmp := []byte{neg, neg, neg, neg}

		if endianness == binary.BigEndian {
			copy(tmp[4-len(buf):], buf)
		} else {
			copy(tmp, buf)
		}

		sample := endianness.Uint32(tmp)

		div := math.Pow(2, float64(len(buf)*8-1))
		if encoding == EncodingSignedInt {
			return float32(float64(int32(sample)) / div)
		} else {
			return float32(float64(sample)/div - 1.0)
		}
	}
}
Exemple #4
0
func (b *Buffer) ReadUint32(order binary.ByteOrder) (uint32, error) {
	if b.readPos >= len(b.Buf)-4 {
		return 0, io.EOF
	}
	u := order.Uint32(b.Buf[b.readPos:])
	b.readPos += 4
	return u, nil
}
Exemple #5
0
func newQosHistoryFromBytes(bin binary.ByteOrder, b []byte) (qosHistory, error) {
	if len(b) < 4+4 {
		return qosHistory{}, io.EOF
	}
	return qosHistory{
		kind:  bin.Uint32(b[0:]),
		depth: bin.Uint32(b[4:]),
	}, nil
}
Exemple #6
0
func timeFromBytes(order binary.ByteOrder, b []byte) (time.Time, error) {
	if len(b) < 8 {
		return timeInvalid, io.EOF
	}

	sec := int64(order.Uint32(b[0:]))
	frac := int64(order.Uint32(b[4:]))
	return time.Unix(sec, (frac*nanosPerSec)>>32).UTC(), nil
}
Exemple #7
0
func durationFromBytes(order binary.ByteOrder, b []byte) (time.Duration, error) {
	if len(b) < 8 {
		return time.Duration(0), io.EOF
	}

	sec := order.Uint32(b[0:])
	nsec := order.Uint32(b[4:])

	return time.Duration(sec*nanosPerSec + nsec), nil
}
Exemple #8
0
func makeGuid(b []byte, order binary.ByteOrder) Guid {
	g := Guid{
		DataA: order.Uint32(b[:4]),
		DataB: order.Uint16(b[4:6]),
		DataC: order.Uint16(b[6:8]),
		DataD: [8]byte{},
	}
	copy(g.DataD[:], b[8:])
	return g
}
func rvalSRational(in []byte, bo binary.ByteOrder) reflect.Value {
	denom := int64(int32(bo.Uint32(in[4:])))
	if denom == 0 {
		// Prevent panics due to poorly written Rational fields with a
		// denominator of 0.  Their usable value would likely be 0.
		return reflect.New(reflect.TypeOf(big.Rat{}))
	}
	numer := int64(int32(bo.Uint32(in)))
	return reflect.ValueOf(big.NewRat(numer, denom))
}
Exemple #10
0
func newUDPv4LocFromBytes(bin binary.ByteOrder, b []byte) (locator, error) {
	if len(b) < 4+4+16 {
		return locator{}, io.EOF
	}
	return locator{
		kind: int32(bin.Uint32(b[0:])),
		port: bin.Uint32(b[4:]),
		addr: net.IPv4(b[20], b[21], b[22], b[23]), // xxx: ipv6 support
	}, nil
}
Exemple #11
0
// Uint32 reads four bytes from the provided reader using a buffer from the
// free list, converts it to a number using the provided byte order, and returns
// the resulting uint32.
func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
	buf := l.Borrow()[:4]
	if _, err := io.ReadFull(r, buf); err != nil {
		l.Return(buf)
		return 0, err
	}
	rv := byteOrder.Uint32(buf)
	l.Return(buf)
	return rv, nil
}
Exemple #12
0
func (p *paramListItem) valToString(bin binary.ByteOrder) (string, error) {
	if len(p.value) < 4 {
		return "", io.EOF
	}
	sz := int(bin.Uint32(p.value[0:]))
	if len(p.value) < 4+sz {
		return "", io.EOF
	}
	// encoded with null terminator, strip that out
	return string(p.value[4 : 4+sz-1]), nil
}
Exemple #13
0
func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
	var order binary.ByteOrder = binary.BigEndian
	var s sym
	p := data
	for len(p) >= 4 {
		// Symbol type, value.
		if len(p) < ptrsz {
			return &formatError{len(data), "unexpected EOF", nil}
		}
		// fixed-width value
		if ptrsz == 8 {
			s.value = order.Uint64(p[0:8])
			p = p[8:]
		} else {
			s.value = uint64(order.Uint32(p[0:4]))
			p = p[4:]
		}

		var typ byte
		typ = p[0] & 0x7F
		s.typ = typ
		p = p[1:]

		// Name.
		var i int
		var nnul int
		for i = 0; i < len(p); i++ {
			if p[i] == 0 {
				nnul = 1
				break
			}
		}
		switch typ {
		case 'z', 'Z':
			p = p[i+nnul:]
			for i = 0; i+2 <= len(p); i += 2 {
				if p[i] == 0 && p[i+1] == 0 {
					nnul = 2
					break
				}
			}
		}
		if len(p) < i+nnul {
			return &formatError{len(data), "unexpected EOF", nil}
		}
		s.name = p[0:i]
		i += nnul
		p = p[i:]

		fn(s)
	}
	return nil
}
Exemple #14
0
// decodeTag assumes len(buf) >= 8
func decodeTag(buf []byte, bo binary.ByteOrder) tag {
	var t tag
	smallTag := bo.Uint32(buf[:])
	t.dataType = dataType(smallTag)
	t.smallFormat = (smallTag >> 16) != 0
	if t.smallFormat == true {
		t.nBytes = uint32(smallTag >> 16)
	} else {
		t.nBytes = bo.Uint32(buf[4:])
	}
	return t
}
Exemple #15
0
func newQosReliabilityFromBytes(bin binary.ByteOrder, b []byte) (qosReliability, error) {
	if len(b) < 4+4+4 {
		return qosReliability{}, io.EOF
	}
	dur, err := durationFromBytes(bin, b[4:])
	if err != nil {
		return qosReliability{}, err
	}
	return qosReliability{
		kind:            bin.Uint32(b[0:]),
		maxBlockingTime: dur,
	}, nil
}
Exemple #16
0
// Look for the attribute that indicates the object uses the hard-float ABI (a
// file-level attribute with tag Tag_VFP_arch and value 1). Unfortunately the
// format used means that we have to parse all of the file-level attributes to
// find the one we are looking for. This format is slightly documented in "ELF
// for the ARM Architecture" but mostly this is derived from reading the source
// to gold and readelf.
func parseArmAttributes(ctxt *Link, e binary.ByteOrder, data []byte) {
	// We assume the soft-float ABI unless we see a tag indicating otherwise.
	if ehdr.flags == 0x5000002 {
		ehdr.flags = 0x5000202
	}
	if data[0] != 'A' {
		// TODO(dfc) should this be ctxt.Diag ?
		ctxt.Logf(".ARM.attributes has unexpected format %c\n", data[0])
		return
	}
	data = data[1:]
	for len(data) != 0 {
		sectionlength := e.Uint32(data)
		sectiondata := data[4:sectionlength]
		data = data[sectionlength:]

		nulIndex := bytes.IndexByte(sectiondata, 0)
		if nulIndex < 0 {
			// TODO(dfc) should this be ctxt.Diag ?
			ctxt.Logf("corrupt .ARM.attributes (section name not NUL-terminated)\n")
			return
		}
		name := string(sectiondata[:nulIndex])
		sectiondata = sectiondata[nulIndex+1:]

		if name != "aeabi" {
			continue
		}
		for len(sectiondata) != 0 {
			subsectiontag, sz := binary.Uvarint(sectiondata)
			subsectionsize := e.Uint32(sectiondata[sz:])
			subsectiondata := sectiondata[sz+4 : subsectionsize]
			sectiondata = sectiondata[subsectionsize:]

			if subsectiontag == TagFile {
				attrList := elfAttributeList{data: subsectiondata}
				for !attrList.done() {
					attr := attrList.armAttr()
					if attr.tag == TagABIVFPArgs && attr.ival == 1 {
						ehdr.flags = 0x5000402 // has entry point, Version5 EABI, hard-float ABI
					}
				}
				if attrList.err != nil {
					// TODO(dfc) should this be ctxt.Diag ?
					ctxt.Logf("could not parse .ARM.attributes\n")
				}
			}
		}
	}
}
Exemple #17
0
func walksymtab(data []byte, fn func(sym) error) error {
	var order binary.ByteOrder = binary.BigEndian
	if bytes.HasPrefix(data, littleEndianSymtab) {
		data = data[6:]
		order = binary.LittleEndian
	}
	var s sym
	p := data
	for len(p) >= 6 {
		s.value = order.Uint32(p[0:4])
		typ := p[4]
		if typ&0x80 == 0 {
			return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
		}
		typ &^= 0x80
		s.typ = typ
		p = p[5:]
		var i int
		var nnul int
		for i = 0; i < len(p); i++ {
			if p[i] == 0 {
				nnul = 1
				break
			}
		}
		switch typ {
		case 'z', 'Z':
			p = p[i+nnul:]
			for i = 0; i+2 <= len(p); i += 2 {
				if p[i] == 0 && p[i+1] == 0 {
					nnul = 2
					break
				}
			}
		}
		if i+nnul+4 > len(p) {
			return &DecodingError{len(data), "unexpected EOF", nil}
		}
		s.name = p[0:i]
		i += nnul
		s.gotype = order.Uint32(p[i : i+4])
		p = p[i+4:]
		fn(s)
	}
	return nil
}
func newSimpleProtocol(n int, byteOrder binary.ByteOrder) *simpleProtocol {
	protocol := &simpleProtocol{
		n:  n,
		bo: byteOrder,
	}

	switch n {
	case 1:
		protocol.encodeHead = func(buffer []byte) {
			buffer[0] = byte(len(buffer) - n)
		}
		protocol.decodeHead = func(buffer []byte) int {
			return int(buffer[0])
		}
	case 2:
		protocol.encodeHead = func(buffer []byte) {
			byteOrder.PutUint16(buffer, uint16(len(buffer)-n))
		}
		protocol.decodeHead = func(buffer []byte) int {
			return int(byteOrder.Uint16(buffer))
		}
	case 4:
		protocol.encodeHead = func(buffer []byte) {
			byteOrder.PutUint32(buffer, uint32(len(buffer)-n))
		}
		protocol.decodeHead = func(buffer []byte) int {
			return int(byteOrder.Uint32(buffer))
		}
	case 8:
		protocol.encodeHead = func(buffer []byte) {
			byteOrder.PutUint64(buffer, uint64(len(buffer)-n))
		}
		protocol.decodeHead = func(buffer []byte) int {
			return int(byteOrder.Uint64(buffer))
		}
	default:
		panic("unsupported packet head size")
	}

	return protocol
}
Exemple #19
0
func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
	bytesPerPixel := c.PixelFormat.BPP / 8
	pixelBytes := make([]uint8, bytesPerPixel)

	var byteOrder binary.ByteOrder = binary.LittleEndian
	if c.PixelFormat.BigEndian {
		byteOrder = binary.BigEndian
	}

	colors := make([]Color, int(rect.Height)*int(rect.Width))

	for y := uint16(0); y < rect.Height; y++ {
		for x := uint16(0); x < rect.Width; x++ {
			if _, err := io.ReadFull(r, pixelBytes); err != nil {
				return nil, err
			}

			var rawPixel uint32
			if c.PixelFormat.BPP == 8 {
				rawPixel = uint32(pixelBytes[0])
			} else if c.PixelFormat.BPP == 16 {
				rawPixel = uint32(byteOrder.Uint16(pixelBytes))
			} else if c.PixelFormat.BPP == 32 {
				rawPixel = byteOrder.Uint32(pixelBytes)
			}

			color := &colors[int(y)*int(rect.Width)+int(x)]
			if c.PixelFormat.TrueColor {
				color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax))
				color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax))
				color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax))
			} else {
				*color = c.ColorMap[rawPixel]
			}
		}
	}

	return &RawEncoding{colors}, nil
}
Exemple #20
0
// Decode decodes the leading bytes in src as a single instruction using
// byte order ord.
func Decode(src []byte, ord binary.ByteOrder) (inst Inst, err error) {
	if len(src) < 4 {
		return inst, errShort
	}
	if decoderCover == nil {
		decoderCover = make([]bool, len(instFormats))
	}
	inst.Len = 4 // only 4-byte instructions are supported
	ui := ord.Uint32(src[:inst.Len])
	inst.Enc = ui
	for i, iform := range instFormats {
		if ui&iform.Mask != iform.Value {
			continue
		}
		if ui&iform.DontCare != 0 {
			if debugDecode {
				log.Printf("Decode(%#x): unused bit is 1 for Op %s", ui, iform.Op)
			}
			// to match GNU objdump (libopcodes), we ignore don't care bits
		}
		for i, argfield := range iform.Args {
			if argfield == nil {
				break
			}
			inst.Args[i] = argfield.Parse(ui)
		}
		inst.Op = iform.Op
		if debugDecode {
			log.Printf("%#x: search entry %d", ui, i)
			continue
		}
		break
	}
	if inst.Op == 0 {
		return inst, errUnknown
	}
	return inst, nil
}
Exemple #21
0
// buildInputBig creates a byte-slice based on big-endian ordered input
func buildInput(in input, order binary.ByteOrder) []byte {
	data := make([]byte, 0)
	d, _ := hex.DecodeString(in.tgId)
	data = append(data, d...)
	d, _ = hex.DecodeString(in.tpe)
	data = append(data, d...)
	d, _ = hex.DecodeString(in.nVals)
	data = append(data, d...)
	d, _ = hex.DecodeString(in.offset)
	data = append(data, d...)

	if in.val != "" {
		off := order.Uint32(d)
		for i := 0; i < int(off)-12; i++ {
			data = append(data, 0xFF)
		}

		d, _ = hex.DecodeString(in.val)
		data = append(data, d...)
	}

	return data
}
Exemple #22
0
func ldelf(f *Biobuf, pkg string, length int64, pn string) {
	if Debug['v'] != 0 {
		fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
	}

	Ctxt.Version++
	base := int32(Boffset(f))

	var add uint64
	var e binary.ByteOrder
	var elfobj *ElfObj
	var err error
	var flag int
	var hdr *ElfHdrBytes
	var hdrbuf [64]uint8
	var info uint64
	var is64 int
	var j int
	var n int
	var name string
	var p []byte
	var r []Reloc
	var rela int
	var rp *Reloc
	var rsect *ElfSect
	var s *LSym
	var sect *ElfSect
	var sym ElfSym
	var symbols []*LSym
	if Bread(f, hdrbuf[:]) != len(hdrbuf) {
		goto bad
	}
	hdr = new(ElfHdrBytes)
	binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
	if string(hdr.Ident[:4]) != "\x7FELF" {
		goto bad
	}
	switch hdr.Ident[5] {
	case ElfDataLsb:
		e = binary.LittleEndian

	case ElfDataMsb:
		e = binary.BigEndian

	default:
		goto bad
	}

	// read header
	elfobj = new(ElfObj)

	elfobj.e = e
	elfobj.f = f
	elfobj.base = int64(base)
	elfobj.length = length
	elfobj.name = pn

	is64 = 0
	if hdr.Ident[4] == ElfClass64 {
		is64 = 1
		hdr := new(ElfHdrBytes64)
		binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
		elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
		elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
		elfobj.version = e.Uint32(hdr.Version[:])
		elfobj.phoff = e.Uint64(hdr.Phoff[:])
		elfobj.shoff = e.Uint64(hdr.Shoff[:])
		elfobj.flags = e.Uint32(hdr.Flags[:])
		elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
		elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
		elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
		elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
		elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
		elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
	} else {
		elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
		elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
		elfobj.version = e.Uint32(hdr.Version[:])
		elfobj.entry = uint64(e.Uint32(hdr.Entry[:]))
		elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:]))
		elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:]))
		elfobj.flags = e.Uint32(hdr.Flags[:])
		elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
		elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
		elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
		elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
		elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
		elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
	}

	elfobj.is64 = is64

	if uint32(hdr.Ident[6]) != elfobj.version {
		goto bad
	}

	if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
		Diag("%s: elf but not elf relocatable object", pn)
		return
	}

	switch Thearch.Thechar {
	default:
		Diag("%s: elf %s unimplemented", pn, Thestring)
		return

	case '5':
		if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
			Diag("%s: elf object but not arm", pn)
			return
		}

	case '6':
		if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
			Diag("%s: elf object but not amd64", pn)
			return
		}

	case '7':
		if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
			Diag("%s: elf object but not arm64", pn)
			return
		}

	case '8':
		if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
			Diag("%s: elf object but not 386", pn)
			return
		}

	case '9':
		if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
			Diag("%s: elf object but not ppc64", pn)
			return
		}
	}

	// load section list into memory.
	elfobj.sect = make([]ElfSect, elfobj.shnum)

	elfobj.nsect = uint(elfobj.shnum)
	for i := 0; uint(i) < elfobj.nsect; i++ {
		if Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
			goto bad
		}
		sect = &elfobj.sect[i]
		if is64 != 0 {
			var b ElfSectBytes64

			if err = binary.Read(f, e, &b); err != nil {
				goto bad
			}

			sect.nameoff = uint32(e.Uint32(b.Name[:]))
			sect.type_ = e.Uint32(b.Type[:])
			sect.flags = e.Uint64(b.Flags[:])
			sect.addr = e.Uint64(b.Addr[:])
			sect.off = e.Uint64(b.Off[:])
			sect.size = e.Uint64(b.Size[:])
			sect.link = e.Uint32(b.Link[:])
			sect.info = e.Uint32(b.Info[:])
			sect.align = e.Uint64(b.Align[:])
			sect.entsize = e.Uint64(b.Entsize[:])
		} else {
			var b ElfSectBytes

			if err = binary.Read(f, e, &b); err != nil {
				goto bad
			}

			sect.nameoff = uint32(e.Uint32(b.Name[:]))
			sect.type_ = e.Uint32(b.Type[:])
			sect.flags = uint64(e.Uint32(b.Flags[:]))
			sect.addr = uint64(e.Uint32(b.Addr[:]))
			sect.off = uint64(e.Uint32(b.Off[:]))
			sect.size = uint64(e.Uint32(b.Size[:]))
			sect.link = e.Uint32(b.Link[:])
			sect.info = e.Uint32(b.Info[:])
			sect.align = uint64(e.Uint32(b.Align[:]))
			sect.entsize = uint64(e.Uint32(b.Entsize[:]))
		}
	}

	// read section string table and translate names
	if elfobj.shstrndx >= uint32(elfobj.nsect) {
		err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
		goto bad
	}

	sect = &elfobj.sect[elfobj.shstrndx]
	if err = elfmap(elfobj, sect); err != nil {
		goto bad
	}
	for i := 0; uint(i) < elfobj.nsect; i++ {
		if elfobj.sect[i].nameoff != 0 {
			elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:])
		}
	}

	// load string table for symbols into memory.
	elfobj.symtab = section(elfobj, ".symtab")

	if elfobj.symtab == nil {
		// our work is done here - no symbols means nothing can refer to this file
		return
	}

	if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
		Diag("%s: elf object has symbol table with invalid string table link", pn)
		return
	}

	elfobj.symstr = &elfobj.sect[elfobj.symtab.link]
	if is64 != 0 {
		elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE)
	} else {
		elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
	}

	if err = elfmap(elfobj, elfobj.symtab); err != nil {
		goto bad
	}
	if err = elfmap(elfobj, elfobj.symstr); err != nil {
		goto bad
	}

	// load text and data segments into memory.
	// they are not as small as the section lists, but we'll need
	// the memory anyway for the symbol images, so we might
	// as well use one large chunk.

	// create symbols for elfmapped sections
	for i := 0; uint(i) < elfobj.nsect; i++ {
		sect = &elfobj.sect[i]
		if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
			continue
		}
		if sect.type_ != ElfSectNobits {
			if err = elfmap(elfobj, sect); err != nil {
				goto bad
			}
		}

		name = fmt.Sprintf("%s(%s)", pkg, sect.name)
		s = Linklookup(Ctxt, name, Ctxt.Version)

		switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
		default:
			err = fmt.Errorf("unexpected flags for ELF section %s", sect.name)
			goto bad

		case ElfSectFlagAlloc:
			s.Type = SRODATA

		case ElfSectFlagAlloc + ElfSectFlagWrite:
			if sect.type_ == ElfSectNobits {
				s.Type = SNOPTRBSS
			} else {
				s.Type = SNOPTRDATA
			}

		case ElfSectFlagAlloc + ElfSectFlagExec:
			s.Type = STEXT
		}

		if sect.name == ".got" || sect.name == ".toc" {
			s.Type = SELFGOT
		}
		if sect.type_ == ElfSectProgbits {
			s.P = sect.base
			s.P = s.P[:sect.size]
		}

		s.Size = int64(sect.size)
		s.Align = int32(sect.align)
		sect.sym = s
	}

	// enter sub-symbols into symbol table.
	// symbol 0 is the null symbol.
	symbols = make([]*LSym, elfobj.nsymtab)

	if symbols == nil {
		Diag("out of memory")
		Errorexit()
	}

	for i := 1; i < elfobj.nsymtab; i++ {
		if err = readelfsym(elfobj, i, &sym, 1); err != nil {
			goto bad
		}
		symbols[i] = sym.sym
		if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone {
			continue
		}
		if sym.shndx == ElfSymShnCommon {
			s = sym.sym
			if uint64(s.Size) < sym.size {
				s.Size = int64(sym.size)
			}
			if s.Type == 0 || s.Type == SXREF {
				s.Type = SNOPTRBSS
			}
			continue
		}

		if uint(sym.shndx) >= elfobj.nsect || sym.shndx == 0 {
			continue
		}

		// even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
		if sym.sym == nil {
			continue
		}
		sect = &elfobj.sect[sym.shndx:][0]
		if sect.sym == nil {
			if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this
				continue
			}
			Diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type_)
			continue
		}

		s = sym.sym
		if s.Outer != nil {
			if s.Dupok != 0 {
				continue
			}
			Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
			Errorexit()
		}

		s.Sub = sect.sym.Sub
		sect.sym.Sub = s
		s.Type = sect.sym.Type | s.Type&^SMASK | SSUB
		if s.Cgoexport&CgoExportDynamic == 0 {
			s.Dynimplib = "" // satisfy dynimport
		}
		s.Value = int64(sym.value)
		s.Size = int64(sym.size)
		s.Outer = sect.sym
		if sect.sym.Type == STEXT {
			if s.External != 0 && s.Dupok == 0 {
				Diag("%s: duplicate definition of %s", pn, s.Name)
			}
			s.External = 1
		}

		if elfobj.machine == ElfMachPower64 {
			flag = int(sym.other) >> 5
			if 2 <= flag && flag <= 6 {
				s.Localentry = 1 << uint(flag-2)
			} else if flag == 7 {
				Diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s.Name)
			}
		}
	}

	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for i := 0; uint(i) < elfobj.nsect; i++ {
		s = elfobj.sect[i].sym
		if s == nil {
			continue
		}
		if s.Sub != nil {
			s.Sub = listsort(s.Sub, valuecmp, listsubp)
		}
		if s.Type == STEXT {
			if s.Onlist != 0 {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Onlist = 1
			if Ctxt.Etextp != nil {
				Ctxt.Etextp.Next = s
			} else {
				Ctxt.Textp = s
			}
			Ctxt.Etextp = s
			for s = s.Sub; s != nil; s = s.Sub {
				if s.Onlist != 0 {
					log.Fatalf("symbol %s listed multiple times", s.Name)
				}
				s.Onlist = 1
				Ctxt.Etextp.Next = s
				Ctxt.Etextp = s
			}
		}
	}

	// load relocations
	for i := 0; uint(i) < elfobj.nsect; i++ {
		rsect = &elfobj.sect[i]
		if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
			continue
		}
		if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil {
			continue
		}
		sect = &elfobj.sect[rsect.info]
		if err = elfmap(elfobj, rsect); err != nil {
			goto bad
		}
		rela = 0
		if rsect.type_ == ElfSectRela {
			rela = 1
		}
		n = int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
		r = make([]Reloc, n)
		p = rsect.base
		for j = 0; j < n; j++ {
			add = 0
			rp = &r[j]
			if is64 != 0 {
				// 64-bit rel/rela
				rp.Off = int32(e.Uint64(p))

				p = p[8:]
				info = e.Uint64(p)
				p = p[8:]
				if rela != 0 {
					add = e.Uint64(p)
					p = p[8:]
				}
			} else {
				// 32-bit rel/rela
				rp.Off = int32(e.Uint32(p))

				p = p[4:]
				info = uint64(e.Uint32(p))
				info = info>>8<<32 | info&0xff // convert to 64-bit info
				p = p[4:]
				if rela != 0 {
					add = uint64(e.Uint32(p))
					p = p[4:]
				}
			}

			if info&0xffffffff == 0 { // skip R_*_NONE relocation
				j--
				n--
				continue
			}

			if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
				rp.Sym = nil
			} else {
				if err = readelfsym(elfobj, int(info>>32), &sym, 0); err != nil {
					goto bad
				}
				sym.sym = symbols[info>>32]
				if sym.sym == nil {
					err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_)
					goto bad
				}

				rp.Sym = sym.sym
			}

			rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz))
			if rela != 0 {
				rp.Add = int64(add)
			} else {
				// load addend from image
				if rp.Siz == 4 {
					rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
				} else if rp.Siz == 8 {
					rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
				} else {
					Diag("invalid rela size %d", rp.Siz)
				}
			}

			if rp.Siz == 2 {
				rp.Add = int64(int16(rp.Add))
			}
			if rp.Siz == 4 {
				rp.Add = int64(int32(rp.Add))
			}
		}

		//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
		sort.Sort(rbyoff(r[:n]))
		// just in case

		s = sect.sym
		s.R = r
		s.R = s.R[:n]
	}

	return

bad:
	Diag("%s: malformed elf file: %v", pn, err)
}
Exemple #23
0
func (s Custom) Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) {
	*s.A = int(order.Uint32(buf[0:4]))
	return buf[4:], nil
}
Exemple #24
0
func ldelf(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
	if ctxt.Debugvlog != 0 {
		ctxt.Logf("%5.2f ldelf %s\n", obj.Cputime(), pn)
	}

	localSymVersion := ctxt.Syms.IncVersion()
	base := f.Offset()

	var add uint64
	var e binary.ByteOrder
	var elfobj *ElfObj
	var err error
	var flag int
	var hdr *ElfHdrBytes
	var hdrbuf [64]uint8
	var info uint64
	var is64 int
	var j int
	var n int
	var name string
	var p []byte
	var r []Reloc
	var rela int
	var rp *Reloc
	var rsect *ElfSect
	var s *Symbol
	var sect *ElfSect
	var sym ElfSym
	var symbols []*Symbol
	if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
		goto bad
	}
	hdr = new(ElfHdrBytes)
	binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
	if string(hdr.Ident[:4]) != "\x7FELF" {
		goto bad
	}
	switch hdr.Ident[5] {
	case ElfDataLsb:
		e = binary.LittleEndian

	case ElfDataMsb:
		e = binary.BigEndian

	default:
		goto bad
	}

	// read header
	elfobj = new(ElfObj)

	elfobj.e = e
	elfobj.f = f
	elfobj.base = base
	elfobj.length = length
	elfobj.name = pn

	is64 = 0
	if hdr.Ident[4] == ElfClass64 {
		is64 = 1
		hdr := new(ElfHdrBytes64)
		binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
		elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
		elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
		elfobj.version = e.Uint32(hdr.Version[:])
		elfobj.phoff = e.Uint64(hdr.Phoff[:])
		elfobj.shoff = e.Uint64(hdr.Shoff[:])
		elfobj.flags = e.Uint32(hdr.Flags[:])
		elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
		elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
		elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
		elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
		elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
		elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
	} else {
		elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
		elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
		elfobj.version = e.Uint32(hdr.Version[:])
		elfobj.entry = uint64(e.Uint32(hdr.Entry[:]))
		elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:]))
		elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:]))
		elfobj.flags = e.Uint32(hdr.Flags[:])
		elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
		elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
		elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
		elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
		elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
		elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
	}

	elfobj.is64 = is64

	if uint32(hdr.Ident[6]) != elfobj.version {
		goto bad
	}

	if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
		Errorf(nil, "%s: elf but not elf relocatable object", pn)
		return
	}

	switch SysArch.Family {
	default:
		Errorf(nil, "%s: elf %s unimplemented", pn, SysArch.Name)
		return

	case sys.MIPS64:
		if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
			Errorf(nil, "%s: elf object but not mips64", pn)
			return
		}

	case sys.ARM:
		if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
			Errorf(nil, "%s: elf object but not arm", pn)
			return
		}

	case sys.AMD64:
		if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
			Errorf(nil, "%s: elf object but not amd64", pn)
			return
		}

	case sys.ARM64:
		if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
			Errorf(nil, "%s: elf object but not arm64", pn)
			return
		}

	case sys.I386:
		if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
			Errorf(nil, "%s: elf object but not 386", pn)
			return
		}

	case sys.PPC64:
		if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
			Errorf(nil, "%s: elf object but not ppc64", pn)
			return
		}

	case sys.S390X:
		if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
			Errorf(nil, "%s: elf object but not s390x", pn)
			return
		}
	}

	// load section list into memory.
	elfobj.sect = make([]ElfSect, elfobj.shnum)

	elfobj.nsect = uint(elfobj.shnum)
	for i := 0; uint(i) < elfobj.nsect; i++ {
		if f.Seek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
			goto bad
		}
		sect = &elfobj.sect[i]
		if is64 != 0 {
			var b ElfSectBytes64

			if err = binary.Read(f, e, &b); err != nil {
				goto bad
			}

			sect.nameoff = e.Uint32(b.Name[:])
			sect.type_ = e.Uint32(b.Type[:])
			sect.flags = e.Uint64(b.Flags[:])
			sect.addr = e.Uint64(b.Addr[:])
			sect.off = e.Uint64(b.Off[:])
			sect.size = e.Uint64(b.Size[:])
			sect.link = e.Uint32(b.Link[:])
			sect.info = e.Uint32(b.Info[:])
			sect.align = e.Uint64(b.Align[:])
			sect.entsize = e.Uint64(b.Entsize[:])
		} else {
			var b ElfSectBytes

			if err = binary.Read(f, e, &b); err != nil {
				goto bad
			}

			sect.nameoff = e.Uint32(b.Name[:])
			sect.type_ = e.Uint32(b.Type[:])
			sect.flags = uint64(e.Uint32(b.Flags[:]))
			sect.addr = uint64(e.Uint32(b.Addr[:]))
			sect.off = uint64(e.Uint32(b.Off[:]))
			sect.size = uint64(e.Uint32(b.Size[:]))
			sect.link = e.Uint32(b.Link[:])
			sect.info = e.Uint32(b.Info[:])
			sect.align = uint64(e.Uint32(b.Align[:]))
			sect.entsize = uint64(e.Uint32(b.Entsize[:]))
		}
	}

	// read section string table and translate names
	if elfobj.shstrndx >= uint32(elfobj.nsect) {
		err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
		goto bad
	}

	sect = &elfobj.sect[elfobj.shstrndx]
	if err = elfmap(elfobj, sect); err != nil {
		goto bad
	}
	for i := 0; uint(i) < elfobj.nsect; i++ {
		if elfobj.sect[i].nameoff != 0 {
			elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:])
		}
	}

	// load string table for symbols into memory.
	elfobj.symtab = section(elfobj, ".symtab")

	if elfobj.symtab == nil {
		// our work is done here - no symbols means nothing can refer to this file
		return
	}

	if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
		Errorf(nil, "%s: elf object has symbol table with invalid string table link", pn)
		return
	}

	elfobj.symstr = &elfobj.sect[elfobj.symtab.link]
	if is64 != 0 {
		elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE)
	} else {
		elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
	}

	if err = elfmap(elfobj, elfobj.symtab); err != nil {
		goto bad
	}
	if err = elfmap(elfobj, elfobj.symstr); err != nil {
		goto bad
	}

	// load text and data segments into memory.
	// they are not as small as the section lists, but we'll need
	// the memory anyway for the symbol images, so we might
	// as well use one large chunk.

	// create symbols for elfmapped sections
	for i := 0; uint(i) < elfobj.nsect; i++ {
		sect = &elfobj.sect[i]
		if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
			if err = elfmap(elfobj, sect); err != nil {
				goto bad
			}
			parseArmAttributes(ctxt, e, sect.base[:sect.size])
		}
		if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
			continue
		}
		if sect.type_ != ElfSectNobits {
			if err = elfmap(elfobj, sect); err != nil {
				goto bad
			}
		}

		name = fmt.Sprintf("%s(%s)", pkg, sect.name)
		s = ctxt.Syms.Lookup(name, localSymVersion)

		switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
		default:
			err = fmt.Errorf("unexpected flags for ELF section %s", sect.name)
			goto bad

		case ElfSectFlagAlloc:
			s.Type = obj.SRODATA

		case ElfSectFlagAlloc + ElfSectFlagWrite:
			if sect.type_ == ElfSectNobits {
				s.Type = obj.SNOPTRBSS
			} else {
				s.Type = obj.SNOPTRDATA
			}

		case ElfSectFlagAlloc + ElfSectFlagExec:
			s.Type = obj.STEXT
		}

		if sect.name == ".got" || sect.name == ".toc" {
			s.Type = obj.SELFGOT
		}
		if sect.type_ == ElfSectProgbits {
			s.P = sect.base
			s.P = s.P[:sect.size]
		}

		s.Size = int64(sect.size)
		s.Align = int32(sect.align)
		sect.sym = s
	}

	// enter sub-symbols into symbol table.
	// symbol 0 is the null symbol.
	symbols = make([]*Symbol, elfobj.nsymtab)

	for i := 1; i < elfobj.nsymtab; i++ {
		if err = readelfsym(ctxt, elfobj, i, &sym, 1, localSymVersion); err != nil {
			goto bad
		}
		symbols[i] = sym.sym
		if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone {
			continue
		}
		if sym.shndx == ElfSymShnCommon {
			s = sym.sym
			if uint64(s.Size) < sym.size {
				s.Size = int64(sym.size)
			}
			if s.Type == 0 || s.Type == obj.SXREF {
				s.Type = obj.SNOPTRBSS
			}
			continue
		}

		if uint(sym.shndx) >= elfobj.nsect || sym.shndx == 0 {
			continue
		}

		// even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
		if sym.sym == nil {
			continue
		}
		sect = &elfobj.sect[sym.shndx]
		if sect.sym == nil {
			if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this
				continue
			}

			if sym.name == "" && sym.type_ == 0 && sect.name == ".debug_str" {
				// This reportedly happens with clang 3.7 on ARM.
				// See issue 13139.
				continue
			}

			if strings.HasPrefix(sym.name, ".LASF") { // gcc on s390x does this
				continue
			}
			Errorf(sym.sym, "%s: sym#%d: ignoring symbol in section %d (type %d)", pn, i, sym.shndx, sym.type_)
			continue
		}

		s = sym.sym
		if s.Outer != nil {
			if s.Attr.DuplicateOK() {
				continue
			}
			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
		}

		s.Sub = sect.sym.Sub
		sect.sym.Sub = s
		s.Type = sect.sym.Type | s.Type&^obj.SMASK | obj.SSUB
		if !s.Attr.CgoExportDynamic() {
			s.Dynimplib = "" // satisfy dynimport
		}
		s.Value = int64(sym.value)
		s.Size = int64(sym.size)
		s.Outer = sect.sym
		if sect.sym.Type == obj.STEXT {
			if s.Attr.External() && !s.Attr.DuplicateOK() {
				Errorf(s, "%s: duplicate symbol definition", pn)
			}
			s.Attr |= AttrExternal
		}

		if elfobj.machine == ElfMachPower64 {
			flag = int(sym.other) >> 5
			if 2 <= flag && flag <= 6 {
				s.Localentry = 1 << uint(flag-2)
			} else if flag == 7 {
				Errorf(s, "%s: invalid sym.other 0x%x", pn, sym.other)
			}
		}
	}

	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for i := 0; uint(i) < elfobj.nsect; i++ {
		s = elfobj.sect[i].sym
		if s == nil {
			continue
		}
		if s.Sub != nil {
			s.Sub = listsort(s.Sub)
		}
		if s.Type == obj.STEXT {
			if s.Attr.OnList() {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Attr |= AttrOnList
			ctxt.Textp = append(ctxt.Textp, s)
			for s = s.Sub; s != nil; s = s.Sub {
				if s.Attr.OnList() {
					log.Fatalf("symbol %s listed multiple times", s.Name)
				}
				s.Attr |= AttrOnList
				ctxt.Textp = append(ctxt.Textp, s)
			}
		}
	}

	// load relocations
	for i := 0; uint(i) < elfobj.nsect; i++ {
		rsect = &elfobj.sect[i]
		if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
			continue
		}
		if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil {
			continue
		}
		sect = &elfobj.sect[rsect.info]
		if err = elfmap(elfobj, rsect); err != nil {
			goto bad
		}
		rela = 0
		if rsect.type_ == ElfSectRela {
			rela = 1
		}
		n = int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
		r = make([]Reloc, n)
		p = rsect.base
		for j = 0; j < n; j++ {
			add = 0
			rp = &r[j]
			if is64 != 0 {
				// 64-bit rel/rela
				rp.Off = int32(e.Uint64(p))

				p = p[8:]
				info = e.Uint64(p)
				p = p[8:]
				if rela != 0 {
					add = e.Uint64(p)
					p = p[8:]
				}
			} else {
				// 32-bit rel/rela
				rp.Off = int32(e.Uint32(p))

				p = p[4:]
				info = uint64(e.Uint32(p))
				info = info>>8<<32 | info&0xff // convert to 64-bit info
				p = p[4:]
				if rela != 0 {
					add = uint64(e.Uint32(p))
					p = p[4:]
				}
			}

			if info&0xffffffff == 0 { // skip R_*_NONE relocation
				j--
				n--
				continue
			}

			if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
				rp.Sym = nil
			} else {
				if err = readelfsym(ctxt, elfobj, int(info>>32), &sym, 0, 0); err != nil {
					goto bad
				}
				sym.sym = symbols[info>>32]
				if sym.sym == nil {
					err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_)
					goto bad
				}

				rp.Sym = sym.sym
			}

			rp.Type = 256 + obj.RelocType(info)
			rp.Siz = relSize(ctxt, pn, uint32(info))
			if rela != 0 {
				rp.Add = int64(add)
			} else {
				// load addend from image
				if rp.Siz == 4 {
					rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
				} else if rp.Siz == 8 {
					rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
				} else {
					Errorf(nil, "invalid rela size %d", rp.Siz)
				}
			}

			if rp.Siz == 2 {
				rp.Add = int64(int16(rp.Add))
			}
			if rp.Siz == 4 {
				rp.Add = int64(int32(rp.Add))
			}
		}

		//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
		sort.Sort(rbyoff(r[:n]))
		// just in case

		s = sect.sym
		s.R = r
		s.R = s.R[:n]
	}

	return

bad:
	Errorf(nil, "%s: malformed elf file: %v", pn, err)
}
Exemple #25
0
// decodeNumeric decodes a simple stream of numeric or character data
func decodeNumeric(de dataElement, bo binary.ByteOrder) (interface{}, error) {
	var b [8]byte
	var bs []byte
	if int(de.nBytes) > len(b) {
		bs = make([]byte, de.nBytes)
	} else {
		bs = b[:de.nBytes]
	}
	_, err := de.r.ReadAt(bs, 0)
	if err != nil {
		return nil, err
	}
	switch de.dataType {
	case miINT8:
		val := make([]int8, de.nBytes)
		for i, x := range bs {
			val[i] = int8(x)
		}
		return val, nil
	case miUINT8:
		val := make([]uint8, de.nBytes)
		copy(val, bs)
		return val, nil
	case miINT16:
		val := make([]int16, de.nBytes/2)
		for i := range bs {
			val[i] = int16(bo.Uint16(bs[2*i:]))
		}
		return val, nil
	case miUINT16:
		val := make([]uint16, de.nBytes/2)
		for i := range bs {
			val[i] = bo.Uint16(bs[2*i:])
		}
		return val, nil
	case miINT32:
		val := make([]int32, de.nBytes/4)
		for i := range bs {
			val[i] = int32(bo.Uint32(bs[4*i:]))
		}
		return val, nil
	case miUINT32:
		val := make([]uint32, de.nBytes/4)
		for i := range bs {
			val[i] = bo.Uint32(bs[4*i:])
		}
		return val, nil
	case miINT64:
		val := make([]int64, de.nBytes/8)
		for i := range bs {
			val[i] = int64(bo.Uint64(bs[8*i:]))
		}
		return val, nil
	case miUINT64:
		val := make([]uint64, de.nBytes/8)
		for i := range bs {
			val[i] = bo.Uint64(bs[8*i:])
		}
		return val, nil
	case miSINGLE:
		val := make([]float32, de.nBytes/4)
		for i := range bs {
			val[i] = math.Float32frombits(bo.Uint32(bs[4*i:]))
		}
		return val, nil
	case miDOUBLE:
		val := make([]float64, de.nBytes/8)
		for i := range bs {
			val[i] = math.Float64frombits(bo.Uint64(bs[8*i:]))
		}
		return val, nil
	case miUTF8:
		return string(bs), nil
	case miUTF16:
		x := make([]uint16, de.nBytes/2)
		for i := range bs {
			x[i] = bo.Uint16(bs[2*i:])
		}
		return string(utf16.Decode(x)), nil
	case miUTF32:
		runes := make([]rune, de.nBytes/4)
		for i := range runes {
			runes[i] = rune(bo.Uint32(bs[4*i:]))
		}
		return string(runes), nil
	}
	return nil, nil
}
Exemple #26
0
func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
	var err error
	var j int
	var is64 bool
	var secaddr uint64
	var hdr [7 * 4]uint8
	var cmdp []byte
	var dat []byte
	var ncmd uint32
	var cmdsz uint32
	var ty uint32
	var sz uint32
	var off uint32
	var m *LdMachoObj
	var e binary.ByteOrder
	var sect *LdMachoSect
	var rel *LdMachoRel
	var rpi int
	var s *LSym
	var s1 *LSym
	var outer *LSym
	var c *LdMachoCmd
	var symtab *LdMachoSymtab
	var dsymtab *LdMachoDysymtab
	var sym *LdMachoSym
	var r []Reloc
	var rp *Reloc
	var name string

	Ctxt.IncVersion()
	base := f.Offset()
	if _, err := io.ReadFull(f, hdr[:]); err != nil {
		goto bad
	}

	if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
		e = binary.BigEndian
	} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
		e = binary.LittleEndian
	} else {
		err = fmt.Errorf("bad magic - not mach-o file")
		goto bad
	}

	is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
	ncmd = e.Uint32(hdr[4*4:])
	cmdsz = e.Uint32(hdr[5*4:])
	if ncmd > 0x10000 || cmdsz >= 0x01000000 {
		err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
		goto bad
	}

	if is64 {
		f.Seek(4, 1) // skip reserved word in header
	}

	m = new(LdMachoObj)

	m.f = f
	m.e = e
	m.cputype = uint(e.Uint32(hdr[1*4:]))
	m.subcputype = uint(e.Uint32(hdr[2*4:]))
	m.filetype = e.Uint32(hdr[3*4:])
	m.ncmd = uint(ncmd)
	m.flags = e.Uint32(hdr[6*4:])
	m.is64 = is64
	m.base = base
	m.length = length
	m.name = pn

	switch SysArch.Family {
	default:
		Diag("%s: mach-o %s unimplemented", pn, SysArch.Name)
		return

	case sys.AMD64:
		if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
			Diag("%s: mach-o object but not amd64", pn)
			return
		}

	case sys.I386:
		if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
			Diag("%s: mach-o object but not 386", pn)
			return
		}
	}

	m.cmd = make([]LdMachoCmd, ncmd)
	off = uint32(len(hdr))
	cmdp = make([]byte, cmdsz)
	if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
		err = fmt.Errorf("reading cmds: %v", err)
		goto bad
	}

	// read and parse load commands
	c = nil

	symtab = nil
	dsymtab = nil

	for i := 0; uint32(i) < ncmd; i++ {
		ty = e.Uint32(cmdp)
		sz = e.Uint32(cmdp[4:])
		m.cmd[i].off = off
		unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
		cmdp = cmdp[sz:]
		off += sz
		if ty == LdMachoCmdSymtab {
			if symtab != nil {
				err = fmt.Errorf("multiple symbol tables")
				goto bad
			}

			symtab = &m.cmd[i].sym
			macholoadsym(m, symtab)
		}

		if ty == LdMachoCmdDysymtab {
			dsymtab = &m.cmd[i].dsym
			macholoaddsym(m, dsymtab)
		}

		if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
			if c != nil {
				err = fmt.Errorf("multiple load commands")
				goto bad
			}

			c = &m.cmd[i]
		}
	}

	// load text and data segments into memory.
	// they are not as small as the load commands, but we'll need
	// the memory anyway for the symbol images, so we might
	// as well use one large chunk.
	if c == nil {
		err = fmt.Errorf("no load command")
		goto bad
	}

	if symtab == nil {
		// our work is done here - no symbols means nothing can refer to this file
		return
	}

	if int64(c.seg.fileoff+c.seg.filesz) >= length {
		err = fmt.Errorf("load segment out of range")
		goto bad
	}

	dat = make([]byte, c.seg.filesz)
	if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 {
		err = fmt.Errorf("cannot load object data: %v", err)
		goto bad
	}
	if _, err2 := io.ReadFull(f, dat); err2 != nil {
		err = fmt.Errorf("cannot load object data: %v", err)
		goto bad
	}

	for i := 0; uint32(i) < c.seg.nsect; i++ {
		sect = &c.seg.sect[i]
		if sect.segname != "__TEXT" && sect.segname != "__DATA" {
			continue
		}
		if sect.name == "__eh_frame" {
			continue
		}
		name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
		s = Linklookup(Ctxt, name, Ctxt.Version)
		if s.Type != 0 {
			err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
			goto bad
		}

		if sect.flags&0xff == 1 { // S_ZEROFILL
			s.P = make([]byte, sect.size)
		} else {
			s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
		}
		s.Size = int64(len(s.P))

		if sect.segname == "__TEXT" {
			if sect.name == "__text" {
				s.Type = obj.STEXT
			} else {
				s.Type = obj.SRODATA
			}
		} else {
			if sect.name == "__bss" {
				s.Type = obj.SNOPTRBSS
				s.P = s.P[:0]
			} else {
				s.Type = obj.SNOPTRDATA
			}
		}

		sect.sym = s
	}

	// enter sub-symbols into symbol table.
	// have to guess sizes from next symbol.
	for i := 0; uint32(i) < symtab.nsym; i++ {
		sym = &symtab.sym[i]
		if sym.type_&N_STAB != 0 {
			continue
		}

		// TODO: check sym->type against outer->type.
		name = sym.name

		if name[0] == '_' && name[1] != '\x00' {
			name = name[1:]
		}
		v := 0
		if sym.type_&N_EXT == 0 {
			v = Ctxt.Version
		}
		s = Linklookup(Ctxt, name, v)
		if sym.type_&N_EXT == 0 {
			s.Attr |= AttrDuplicateOK
		}
		sym.sym = s
		if sym.sectnum == 0 { // undefined
			continue
		}
		if uint32(sym.sectnum) > c.seg.nsect {
			err = fmt.Errorf("reference to invalid section %d", sym.sectnum)
			goto bad
		}

		sect = &c.seg.sect[sym.sectnum-1]
		outer = sect.sym
		if outer == nil {
			err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
			continue
		}

		if s.Outer != nil {
			if s.Attr.DuplicateOK() {
				continue
			}
			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
		}

		s.Type = outer.Type | obj.SSUB
		s.Sub = outer.Sub
		outer.Sub = s
		s.Outer = outer
		s.Value = int64(sym.value - sect.addr)
		if !s.Attr.CgoExportDynamic() {
			s.Dynimplib = "" // satisfy dynimport
		}
		if outer.Type == obj.STEXT {
			if s.Attr.External() && !s.Attr.DuplicateOK() {
				Diag("%s: duplicate definition of %s", pn, s.Name)
			}
			s.Attr |= AttrExternal
		}

		sym.sym = s
	}

	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for i := 0; uint32(i) < c.seg.nsect; i++ {
		sect = &c.seg.sect[i]
		s = sect.sym
		if s == nil {
			continue
		}
		if s.Sub != nil {
			s.Sub = listsort(s.Sub, valuecmp, listsubp)

			// assign sizes, now that we know symbols in sorted order.
			for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
				if s1.Sub != nil {
					s1.Size = s1.Sub.Value - s1.Value
				} else {
					s1.Size = s.Value + s.Size - s1.Value
				}
			}
		}

		if s.Type == obj.STEXT {
			if s.Attr.OnList() {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Attr |= AttrOnList
			Ctxt.Textp = append(Ctxt.Textp, s)
			for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
				if s1.Attr.OnList() {
					log.Fatalf("symbol %s listed multiple times", s1.Name)
				}
				s1.Attr |= AttrOnList
				Ctxt.Textp = append(Ctxt.Textp, s1)
			}
		}
	}

	// load relocations
	for i := 0; uint32(i) < c.seg.nsect; i++ {
		sect = &c.seg.sect[i]
		s = sect.sym
		if s == nil {
			continue
		}
		macholoadrel(m, sect)
		if sect.rel == nil {
			continue
		}
		r = make([]Reloc, sect.nreloc)
		rpi = 0
	Reloc:
		for j = 0; uint32(j) < sect.nreloc; j++ {
			rp = &r[rpi]
			rel = &sect.rel[j]
			if rel.scattered != 0 {
				if SysArch.Family != sys.I386 {
					// mach-o only uses scattered relocation on 32-bit platforms
					Diag("unexpected scattered relocation")
					continue
				}

				// on 386, rewrite scattered 4/1 relocation and some
				// scattered 2/1 relocation into the pseudo-pc-relative
				// reference that it is.
				// assume that the second in the pair is in this section
				// and use that as the pc-relative base.
				if uint32(j+1) >= sect.nreloc {
					err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
					goto bad
				}

				if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
					err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
					goto bad
				}

				rp.Siz = rel.length
				rp.Off = int32(rel.addr)

				// NOTE(rsc): I haven't worked out why (really when)
				// we should ignore the addend on a
				// scattered relocation, but it seems that the
				// common case is we ignore it.
				// It's likely that this is not strictly correct
				// and that the math should look something
				// like the non-scattered case below.
				rp.Add = 0

				// want to make it pc-relative aka relative to rp->off+4
				// but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
				// adjust rp->add accordingly.
				rp.Type = obj.R_PCREL

				rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))

				// now consider the desired symbol.
				// find the section where it lives.
				var ks *LdMachoSect
				for k := 0; uint32(k) < c.seg.nsect; k++ {
					ks = &c.seg.sect[k]
					if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
						if ks.sym != nil {
							rp.Sym = ks.sym
							rp.Add += int64(uint64(rel.value) - ks.addr)
						} else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
							// handle reference to __IMPORT/__pointers.
							// how much worse can this get?
							// why are we supporting 386 on the mac anyway?
							rp.Type = 512 + MACHO_FAKE_GOTPCREL

							// figure out which pointer this is a reference to.
							k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4)

							// load indirect table for __pointers
							// fetch symbol number
							if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
								err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
								goto bad
							}

							k = int(dsymtab.indir[k])
							if k < 0 || uint32(k) >= symtab.nsym {
								err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
								goto bad
							}

							rp.Sym = symtab.sym[k].sym
						} else {
							err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
							goto bad
						}

						rpi++

						// skip #1 of 2 rel; continue skips #2 of 2.
						j++

						continue Reloc
					}
				}

				err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
				goto bad

			}

			rp.Siz = rel.length
			rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel)
			rp.Off = int32(rel.addr)

			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
			if SysArch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == 1 {
				// Calculate the addend as the offset into the section.
				//
				// The rip-relative offset stored in the object file is encoded
				// as follows:
				//
				//    movsd	0x00000360(%rip),%xmm0
				//
				// To get the absolute address of the value this rip-relative address is pointing
				// to, we must add the address of the next instruction to it. This is done by
				// taking the address of the relocation and adding 4 to it (since the rip-relative
				// offset can at most be 32 bits long).  To calculate the offset into the section the
				// relocation is referencing, we subtract the vaddr of the start of the referenced
				// section found in the original object file.
				//
				// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
				secaddr = c.seg.sect[rel.symnum-1].addr

				rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
			} else {
				rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
			}

			// For i386 Mach-O PC-relative, the addend is written such that
			// it *is* the PC being subtracted. Use that to make
			// it match our version of PC-relative.
			if rel.pcrel != 0 && SysArch.Family == sys.I386 {
				rp.Add += int64(rp.Off) + int64(rp.Siz)
			}
			if rel.extrn == 0 {
				if rel.symnum < 1 || rel.symnum > c.seg.nsect {
					err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
					goto bad
				}

				rp.Sym = c.seg.sect[rel.symnum-1].sym
				if rp.Sym == nil {
					err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
					goto bad
				}

				// References to symbols in other sections
				// include that information in the addend.
				// We only care about the delta from the
				// section base.
				if SysArch.Family == sys.I386 {
					rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
				}
			} else {
				if rel.symnum >= symtab.nsym {
					err = fmt.Errorf("invalid relocation: symbol reference out of range")
					goto bad
				}

				rp.Sym = symtab.sym[rel.symnum].sym
			}

			rpi++
		}

		sort.Sort(rbyoff(r[:rpi]))
		s.R = r
		s.R = s.R[:rpi]
	}

	return

bad:
	Diag("%s: malformed mach-o file: %v", pn, err)
}
Exemple #27
0
// Convert raw image data into a 2d array of 64-bit labels
func (d *Data) convertTo64bit(geom dvid.Geometry, data []uint8, bytesPerVoxel, stride int) ([]byte, error) {
	nx := int(geom.Size().Value(0))
	ny := int(geom.Size().Value(1))
	numBytes := nx * ny * 8
	data64 := make([]byte, numBytes, numBytes)

	var byteOrder binary.ByteOrder
	if geom.DataShape().ShapeDimensions() == 2 {
		byteOrder = binary.BigEndian // This is the default for PNG
	} else {
		byteOrder = binary.LittleEndian
	}

	switch bytesPerVoxel {
	case 1:
		dstI := 0
		for y := 0; y < ny; y++ {
			srcI := y * stride
			for x := 0; x < nx; x++ {
				binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(data[srcI]))
				srcI++
				dstI += 8
			}
		}
	case 2:
		dstI := 0
		for y := 0; y < ny; y++ {
			srcI := y * stride
			for x := 0; x < nx; x++ {
				value := byteOrder.Uint16(data[srcI : srcI+2])
				binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(value))
				srcI += 2
				dstI += 8
			}
		}
	case 4:
		dstI := 0
		for y := 0; y < ny; y++ {
			srcI := y * stride
			for x := 0; x < nx; x++ {
				value := byteOrder.Uint32(data[srcI : srcI+4])
				binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(value))
				srcI += 4
				dstI += 8
			}
		}
	case 8:
		dstI := 0
		for y := 0; y < ny; y++ {
			srcI := y * stride
			for x := 0; x < nx; x++ {
				value := byteOrder.Uint64(data[srcI : srcI+8])
				binary.LittleEndian.PutUint64(data64[dstI:dstI+8], uint64(value))
				srcI += 8
				dstI += 8
			}
		}
	default:
		return nil, fmt.Errorf("could not convert to 64-bit label given %d bytes/voxel", bytesPerVoxel)
	}
	return data64, nil
}
Exemple #28
0
// parseNotes returns the notes from a SHT_NOTE section or PT_NOTE segment.
func parseNotes(reader io.Reader, alignment int, order binary.ByteOrder) ([]elfNote, error) {
	r := bufio.NewReader(reader)

	// padding returns the number of bytes required to pad the given size to an
	// alignment boundary.
	padding := func(size int) int {
		return ((size + (alignment - 1)) &^ (alignment - 1)) - size
	}

	var notes []elfNote
	for {
		noteHeader := make([]byte, 12) // 3 4-byte words
		if _, err := io.ReadFull(r, noteHeader); err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		namesz := order.Uint32(noteHeader[0:4])
		descsz := order.Uint32(noteHeader[4:8])
		typ := order.Uint32(noteHeader[8:12])

		if uint64(namesz) > uint64(maxNoteSize) {
			return nil, fmt.Errorf("note name too long (%d bytes)", namesz)
		}
		var name string
		if namesz > 0 {
			// Documentation differs as to whether namesz is meant to include the
			// trailing zero, but everyone agrees that name is null-terminated.
			// So we'll just determine the actual length after the fact.
			var err error
			name, err = r.ReadString('\x00')
			if err == io.EOF {
				return nil, fmt.Errorf("missing note name (want %d bytes)", namesz)
			} else if err != nil {
				return nil, err
			}
			namesz = uint32(len(name))
			name = name[:len(name)-1]
		}

		// Drop padding bytes until the desc field.
		for n := padding(len(noteHeader) + int(namesz)); n > 0; n-- {
			if _, err := r.ReadByte(); err == io.EOF {
				return nil, fmt.Errorf(
					"missing %d bytes of padding after note name", n)
			} else if err != nil {
				return nil, err
			}
		}

		if uint64(descsz) > uint64(maxNoteSize) {
			return nil, fmt.Errorf("note desc too long (%d bytes)", descsz)
		}
		desc := make([]byte, int(descsz))
		if _, err := io.ReadFull(r, desc); err == io.EOF {
			return nil, fmt.Errorf("missing desc (want %d bytes)", len(desc))
		} else if err != nil {
			return nil, err
		}

		notes = append(notes, elfNote{Name: name, Desc: desc, Type: typ})

		// Drop padding bytes until the next note or the end of the section,
		// whichever comes first.
		for n := padding(len(desc)); n > 0; n-- {
			if _, err := r.ReadByte(); err == io.EOF {
				// We hit the end of the section before an alignment boundary.
				// This can happen if this section is at the end of the file or the next
				// section has a smaller alignment requirement.
				break
			} else if err != nil {
				return nil, err
			}
		}
	}
	return notes, nil
}
Exemple #29
0
func walksymtab(data []byte, fn func(sym) error) error {
	if len(data) == 0 { // missing symtab is okay
		return nil
	}
	var order binary.ByteOrder = binary.BigEndian
	newTable := false
	switch {
	case bytes.HasPrefix(data, oldLittleEndianSymtab):
		// Same as Go 1.0, but little endian.
		// Format was used during interim development between Go 1.0 and Go 1.1.
		// Should not be widespread, but easy to support.
		data = data[6:]
		order = binary.LittleEndian
	case bytes.HasPrefix(data, bigEndianSymtab):
		newTable = true
	case bytes.HasPrefix(data, littleEndianSymtab):
		newTable = true
		order = binary.LittleEndian
	}
	var ptrsz int
	if newTable {
		if len(data) < 8 {
			return &DecodingError{len(data), "unexpected EOF", nil}
		}
		ptrsz = int(data[7])
		if ptrsz != 4 && ptrsz != 8 {
			return &DecodingError{7, "invalid pointer size", ptrsz}
		}
		data = data[8:]
	}
	var s sym
	p := data
	for len(p) >= 4 {
		var typ byte
		if newTable {
			// Symbol type, value, Go type.
			typ = p[0] & 0x3F
			wideValue := p[0]&0x40 != 0
			goType := p[0]&0x80 != 0
			if typ < 26 {
				typ += 'A'
			} else {
				typ += 'a' - 26
			}
			s.typ = typ
			p = p[1:]
			if wideValue {
				if len(p) < ptrsz {
					return &DecodingError{len(data), "unexpected EOF", nil}
				}
				// fixed-width value
				if ptrsz == 8 {
					s.value = order.Uint64(p[0:8])
					p = p[8:]
				} else {
					s.value = uint64(order.Uint32(p[0:4]))
					p = p[4:]
				}
			} else {
				// varint value
				s.value = 0
				shift := uint(0)
				for len(p) > 0 && p[0]&0x80 != 0 {
					s.value |= uint64(p[0]&0x7F) << shift
					shift += 7
					p = p[1:]
				}
				if len(p) == 0 {
					return &DecodingError{len(data), "unexpected EOF", nil}
				}
				s.value |= uint64(p[0]) << shift
				p = p[1:]
			}
			if goType {
				if len(p) < ptrsz {
					return &DecodingError{len(data), "unexpected EOF", nil}
				}
				// fixed-width go type
				if ptrsz == 8 {
					s.gotype = order.Uint64(p[0:8])
					p = p[8:]
				} else {
					s.gotype = uint64(order.Uint32(p[0:4]))
					p = p[4:]
				}
			}
		} else {
			// Value, symbol type.
			s.value = uint64(order.Uint32(p[0:4]))
			if len(p) < 5 {
				return &DecodingError{len(data), "unexpected EOF", nil}
			}
			typ = p[4]
			if typ&0x80 == 0 {
				return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
			}
			typ &^= 0x80
			s.typ = typ
			p = p[5:]
		}

		// Name.
		var i int
		var nnul int
		for i = 0; i < len(p); i++ {
			if p[i] == 0 {
				nnul = 1
				break
			}
		}
		switch typ {
		case 'z', 'Z':
			p = p[i+nnul:]
			for i = 0; i+2 <= len(p); i += 2 {
				if p[i] == 0 && p[i+1] == 0 {
					nnul = 2
					break
				}
			}
		}
		if len(p) < i+nnul {
			return &DecodingError{len(data), "unexpected EOF", nil}
		}
		s.name = p[0:i]
		i += nnul
		p = p[i:]

		if !newTable {
			if len(p) < 4 {
				return &DecodingError{len(data), "unexpected EOF", nil}
			}
			// Go type.
			s.gotype = uint64(order.Uint32(p[:4]))
			p = p[4:]
		}
		fn(s)
	}
	return nil
}
Exemple #30
0
func (s *Stream) readSectionHeaderBlockBody(headerData []byte) (header *SectionHeaderBlock, err error) {
	//
	// read byte-order magic, version and section length
	//
	bodyData, err := s.read(16)
	if err != nil {
		return nil, err
	}

	//
	// read byte-order magic
	//
	var byteOrder binary.ByteOrder

	if bodyData[0] == 0x1A && bodyData[1] == 0x2B && bodyData[2] == 0x3C && bodyData[3] == 0x4D {
		byteOrder = binary.BigEndian
	} else if bodyData[3] == 0x1A && bodyData[2] == 0x2B && bodyData[1] == 0x3C && bodyData[0] == 0x4D {
		byteOrder = binary.LittleEndian
	} else {
		return nil, errors.New("invalid byte order mark")
	}

	//
	// read other fields
	//
	versionMajor := byteOrder.Uint16(bodyData[4:6])
	versionMinor := byteOrder.Uint16(bodyData[6:8])
	sectionLength := int64(byteOrder.Uint64(bodyData[8:16]))

	//
	// Read options
	//
	totalLength := byteOrder.Uint32(headerData[4:8])
	optsLen := totalLength - 28
	rawOpts, err := s.readOptions(optsLen, byteOrder)
	if err != nil {
		return nil, err
	}

	opts, err := parseSectionHeaderOptions(rawOpts)
	if err != nil {
		return nil, err
	}

	//
	// Read last block total length
	//
	_, err = s.readExactly(4)
	if err != nil {
		return nil, err
	}

	retval := &SectionHeaderBlock{
		totalLength:   totalLength,
		ByteOrder:     byteOrder,
		VersionMajor:  versionMajor,
		VersionMinor:  versionMinor,
		SectionLength: sectionLength,
		RawOptions:    rawOpts,
		Options:       opts,
	}

	s.sectionHeader = retval
	return retval, nil
}