diff options
author | Austin Clements <aclements@csail.mit.edu> | 2009-08-19 10:05:11 -0700 |
---|---|---|
committer | Austin Clements <aclements@csail.mit.edu> | 2009-08-19 10:05:11 -0700 |
commit | 68c5968a7dc814a3f0ddd0af4235a47857981983 (patch) | |
tree | 213b3794503aab8d5e52cf0799fb309d995470c8 /usr/austin/sym/binary.go | |
parent | c96a8d488643318109f2e6f418cbc6d7d29b67e1 (diff) | |
download | golang-68c5968a7dc814a3f0ddd0af4235a47857981983.tar.gz |
ELF reader and Go symbol table and PC/line table decoder.
R=rsc
APPROVED=rsc
DELTA=1425 (1425 added, 0 deleted, 0 changed)
OCL=33432
CL=33517
Diffstat (limited to 'usr/austin/sym/binary.go')
-rw-r--r-- | usr/austin/sym/binary.go | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/usr/austin/sym/binary.go b/usr/austin/sym/binary.go new file mode 100644 index 000000000..d06179cec --- /dev/null +++ b/usr/austin/sym/binary.go @@ -0,0 +1,190 @@ +// Copyright 2009 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 sym + +import ( + "bufio"; + "io"; + "log"; + "os"; + "reflect"; +) + +type byteOrder interface { + Uint16(b []byte) uint16; + Uint32(b []byte) uint32; + Uint64(b []byte) uint64; + String() string; +} + +type olsb struct {} + +func (olsb) Uint16(b []byte) uint16 { + return uint16(b[0]) | uint16(b[1]) << 8; +} + +func (olsb) Uint32(b []byte) uint32 { + return uint32(b[0]) | uint32(b[1]) << 8 | uint32(b[2]) << 16 | uint32(b[3]) << 24; +} + +func (olsb) Uint64(b []byte) uint64 { + return uint64(b[0]) | uint64(b[1]) << 8 | uint64(b[2]) << 16 | uint64(b[3]) << 24 | uint64(b[4]) << 32 | uint64(b[5]) << 40 | uint64(b[6]) << 48 | uint64(b[7]) << 56; +} + +func (olsb) String() string { + return "LSB"; +} + +type omsb struct {} + +func (omsb) Uint16(b []byte) uint16 { + return uint16(b[1]) | uint16(b[0]) << 8; +} + +func (omsb) Uint32(b []byte) uint32 { + return uint32(b[3]) | uint32(b[2]) << 8 | uint32(b[1]) << 16 | uint32(b[0]) << 24; +} + +func (omsb) Uint64(b []byte) uint64 { + return uint64(b[7]) | uint64(b[6]) << 8 | uint64(b[5]) << 16 | uint64(b[4]) << 24 | uint64(b[3]) << 32 | uint64(b[2]) << 40 | uint64(b[1]) << 48 | uint64(b[0]) << 56; +} + +func (omsb) String() string { + return "MSB"; +} + +var ( + lsb = olsb{}; + msb = omsb{}; +) + +// A binaryReader decodes binary data from another reader. On an +// error, the Read methods simply return 0 and record the error, to +// make it more convenient to decode long sequences of binary data. +// The caller should use the Error method when convenient to check +// for errors. +type binaryReader struct { + *bufio.Reader; + err os.Error; + order byteOrder; +} + +// newBinaryReader creates a new binary data reader backed by the +// given reader and using the given byte order for decoding. +func newBinaryReader(r io.Reader, o byteOrder) *binaryReader { + return &binaryReader{bufio.NewReader(r), nil, o}; +} + +// Error returns the recorded error, or nil if no error has occurred. +func (r *binaryReader) Error() os.Error { + return r.err; +} + +func (r *binaryReader) ReadUint8() uint8 { + var buf [1]byte; + n, err := io.ReadFull(r.Reader, &buf); + if r.err == nil && err != nil { + r.err = err; + } + return buf[0]; +} + +func (r *binaryReader) ReadUint16() uint16 { + var buf [2]byte; + n, err := io.ReadFull(r.Reader, &buf); + if r.err == nil && err != nil { + r.err = err; + } + return r.order.Uint16(&buf); +} + +func (r *binaryReader) ReadUint32() uint32 { + var buf [4]byte; + n, err := io.ReadFull(r.Reader, &buf); + if r.err == nil && err != nil { + r.err = err; + } + return r.order.Uint32(&buf); +} + +func (r *binaryReader) ReadUint64() uint64 { + var buf [8]byte; + n, err := io.ReadFull(r.Reader, &buf); + if r.err == nil && err != nil { + r.err = err; + } + return r.order.Uint64(&buf); +} + +func (r *binaryReader) ReadInt8() int8 { + return int8(r.ReadUint8()); +} + +func (r *binaryReader) ReadInt16() int16 { + return int16(r.ReadUint16()); +} + +func (r *binaryReader) ReadInt32() int32 { + return int32(r.ReadUint32()); +} + +func (r *binaryReader) ReadInt64() int64 { + return int64(r.ReadUint64()); +} + +// ReadCString reads a NULL-terminated string. +func (r *binaryReader) ReadCString() string { + str, err := r.Reader.ReadLineString('\x00', false); + if r.err == nil && err != nil { + r.err = err; + } + return str; +} + +// ReadValue reads a value according to its reflected type. This can +// read any of the types for which there is a regular Read method, +// plus structs and arrays. It assumes structs contain no padding. +func (r *binaryReader) ReadValue(v reflect.Value) { + switch v := v.(type) { + case *reflect.ArrayValue: + l := v.Len(); + for i := 0; i < l; i++ { + r.ReadValue(v.Elem(i)); + } + case *reflect.StructValue: + l := v.NumField(); + for i := 0; i < l; i++ { + r.ReadValue(v.Field(i)); + } + + case *reflect.Uint8Value: + v.Set(r.ReadUint8()); + case *reflect.Uint16Value: + v.Set(r.ReadUint16()); + case *reflect.Uint32Value: + v.Set(r.ReadUint32()); + case *reflect.Uint64Value: + v.Set(r.ReadUint64()); + case *reflect.Int8Value: + v.Set(r.ReadInt8()); + case *reflect.Int16Value: + v.Set(r.ReadInt16()); + case *reflect.Int32Value: + v.Set(r.ReadInt32()); + case *reflect.Int64Value: + v.Set(r.ReadInt64()); + case *reflect.StringValue: + v.Set(r.ReadCString()); + + default: + log.Crashf("Value of unexpected type %T", v); + } +} + +// ReadAny is a convenience wrapper for ReadValue. It can be passed a +// pointer any type that can be decoded by ReadValue. +func (r *binaryReader) ReadAny(out interface {}) { + r.ReadValue(reflect.Indirect(reflect.NewValue(out))); +} |