Commit 6ece1b56 authored by Austin Clements's avatar Austin Clements

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
parent 382a19c3
# 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.
include $(GOROOT)/src/Make.$(GOARCH)
TARG=sym
GOFILES=\
binary.go\
elf.go\
elffmt.go\
gosymtab.go\
include $(GOROOT)/src/Make.pkg
// 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)));
}
// 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 (
"fmt";
"io";
"log";
"os";
)
/*
* Internal ELF representation
*/
// Elf represents a decoded ELF binary.
type Elf struct {
class int;
data byteOrder;
Type ElfType;
Machine ElfMachine;
Sections []*Section;
}
// Section represents a single section in an ELF binary.
type Section struct {
r io.ReadSeeker;
Name string;
offset int64;
Size uint64;
Addr uint64;
}
/*
* ELF reader
*/
type FormatError struct {
off int64;
msg string;
val interface{};
}
func (e *FormatError) String() string {
msg := e.msg;
if e.val != nil {
msg += fmt.Sprintf(" '%v' ", e.val);
}
msg += fmt.Sprintf("in record at byte %#x", e.off);
return msg;
}
// NewElf reads and decodes an ELF binary. The ELF binary is expected
// to start where the reader is currently positioned.
func NewElf(r io.ReadSeeker) (*Elf, os.Error) {
// Read ELF identifier
var ident [eiNIdent]uint8;
off, err := r.Seek(0, 0);
if err != nil {
return nil, err;
}
start := off;
n, err := io.ReadFull(r, &ident);
if err != nil {
if err == os.EOF {
err = io.ErrUnexpectedEOF;
}
return nil, err;
}
// Decode identifier
if ident[eiMag0] != '\x7f' || ident[eiMag1] != 'E' || ident[eiMag2] != 'L' || ident[eiMag3] != 'F' {
return nil, &FormatError{off, "bad magic number", string(ident[eiMag0:eiMag3])};
}
e := &Elf{};
switch ident[eiClass] {
case elfClass32:
e.class = 32;
case elfClass64:
e.class = 64;
default:
return nil, &FormatError{off, "unknown ELF class", ident[eiClass]};
}
switch ident[eiData] {
case elfData2LSB:
e.data = lsb;
case elfData2MSB:
e.data = msb;
default:
return nil, &FormatError{off, "unknown ELF data encoding", ident[eiData]};
}
if ident[eiVersion] != evCurrent {
return nil, &FormatError{off, "unknown ELF version", ident[eiVersion]};
}
// TODO(austin) Do something with ABI?
// Read ELF file header
var shoff int64;
var shentsize, shnum, shstrndx int;
br := newBinaryReader(r, e.data);
switch e.class {
case 32:
return nil, &FormatError{off, "ELF32 not implemented", nil};
case 64:
hdr := &elf64Ehdr{};
br.ReadAny(hdr);
if err := br.Error(); err != nil {
return nil, err;
}
if hdr.Type > etCore && hdr.Type < etLoOS {
return nil, &FormatError{off, "unknown ELF file type", hdr.Type};
}
e.Type = ElfType(hdr.Type);
e.Machine = ElfMachine(hdr.Machine);
if hdr.Version != evCurrent {
return nil, &FormatError{off, "unknown second ELF version", hdr.Version};
}
shoff = int64(hdr.Shoff);
shentsize = int(hdr.Shentsize);
shnum = int(hdr.Shnum);
shstrndx = int(hdr.Shstrndx);
}
// Read section headers
e.Sections = make([]*Section, shnum);
secNames := make([]uint32, shnum);
for i := 0; i < shnum; i++ {
off, err = r.Seek(start + shoff + int64(i*shentsize), 0);
if err != nil {
return nil, err;
}
br = newBinaryReader(r, e.data);
switch e.class {
case 32:
panic("not reached");
case 64:
shdr := &elf64Shdr{};
br.ReadAny(shdr);
if err := br.Error(); err != nil {
return nil, err;
}
s := &Section{
r: r,
offset: start + int64(shdr.Off),
Size: shdr.Size,
Addr: uint64(shdr.Addr),
};
secNames[i] = shdr.Name;
e.Sections[i] = s;
}
}
// Resolve section names
off, err = r.Seek(start + e.Sections[shstrndx].offset, 0);
if err != nil {
return nil, err;
}
blob := make([]byte, e.Sections[shstrndx].Size);
n, err = io.ReadFull(r, blob);
strings := make(map[uint32] string);
strStart := uint32(0);
for i, c := range blob {
if c == 0 {
strings[strStart] = string(blob[strStart:i]);
strStart = uint32(i+1);
}
}
for i, s := range e.Sections {
var ok bool;
s.Name, ok = strings[secNames[i]];
if !ok {
return nil, &FormatError{start + shoff + int64(i*shentsize), "bad section name", secNames[i]};
}
}
return e, nil;
}
// Section returns a section with the given name, or nil if no such
// section exists.
func (e *Elf) Section(name string) *Section {
for _, s := range e.Sections {
if s.Name == name {
return s;
}
}
return nil;
}
/*
* Sections
*/
type subReader struct {
r io.Reader;
rem uint64;
}
func (r *subReader) Read(b []byte) (ret int, err os.Error) {
if r.rem == 0 {
return 0, os.EOF;
}
if uint64(len(b)) > r.rem {
b = b[0:r.rem];
}
ret, err = r.r.Read(b);
r.rem -= uint64(ret);
if err == os.EOF {
err = io.ErrUnexpectedEOF;
}
return ret, err;
}
// Open returns a reader backed by the data in this section.
// The original ELF file must still be open for this to work.
// The returned reader assumes there will be no seeks on the
// underlying file or any other opened section between the Open call
// and the last call to Read.
func (s *Section) Open() (io.Reader, os.Error) {
_, err := s.r.Seek(s.offset, 0);
if err != nil {
return nil, err;
}
return &subReader{s.r, s.Size}, nil;
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment