// 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 elf implements access to ELF object files.
package elf

import (
	"debug/binary";
	"fmt";
	"io";
	"os";
)

// TODO: error reporting detail

/*
 * Internal ELF representation
 */

// A FileHeader represents an ELF file header.
type FileHeader struct {
	Class Class;
	Data Data;
	Version Version;
	OSABI OSABI;
	ABIVersion uint8;
	ByteOrder binary.ByteOrder;
	Type Type;
	Machine Machine;
}

// A File represents an open ELF file.
type File struct {
	FileHeader;
	Sections []*Section;
	Progs []*Prog;

	closer io.Closer;
}

// A SectionHeader represents a single ELF section header.
type SectionHeader struct {
	Name string;
	Type SectionType;
	Flags SectionFlag;
	Addr uint64;
	Offset uint64;
	Size uint64;
	Link uint32;
	Info uint32;
	Addralign uint64;
	Entsize uint64;
}

// A Section represents a single section in an ELF file.
type Section struct {
	SectionHeader;

	// Embed ReaderAt for ReadAt method.
	// Do not embed SectionReader directly
	// to avoid having Read and Seek.
	// If a client wants Read and Seek it must use
	// Open() to avoid fighting over the seek offset
	// with other clients.
	io.ReaderAt;
	sr *io.SectionReader;
}

// Data reads and returns the contents of the ELF section.
func (s *Section) Data() ([]byte, os.Error) {
	dat := make([]byte, s.sr.Size());
	n, err := s.sr.ReadAt(dat, 0);
	return dat[0:n], err;
}

// Open returns a new ReadSeeker reading the ELF section.
func (s *Section) Open() io.ReadSeeker {
	return io.NewSectionReader(s.sr, 0, 1<<63 - 1);
}

// A ProgHeader represents a single ELF program header.
type ProgHeader struct {
	Type ProgType;
	Flags ProgFlag;
	Vaddr uint64;
	Paddr uint64;
	Filesz uint64;
	Memsz uint64;
	Align uint64;
}

// A Prog represents a single ELF program header in an ELF binary.
type Prog struct {
	ProgHeader;

	// Embed ReaderAt for ReadAt method.
	// Do not embed SectionReader directly
	// to avoid having Read and Seek.
	// If a client wants Read and Seek it must use
	// Open() to avoid fighting over the seek offset
	// with other clients.
	io.ReaderAt;
	sr *io.SectionReader;
}

// Open returns a new ReadSeeker reading the ELF program body.
func (p *Prog) Open() io.ReadSeeker {
	return io.NewSectionReader(p.sr, 0, 1<<63 - 1);
}


/*
 * 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;
}

// Open opens the named file using os.Open and prepares it for use as an ELF binary.
func Open(name string) (*File, os.Error) {
	f, err := os.Open(name, os.O_RDONLY, 0);
	if err != nil {
		return nil, err;
	}
	ff, err := NewFile(f);
	if err != nil {
		f.Close();
		return nil, err;
	}
	ff.closer = f;
	return ff, nil;
}

// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() os.Error {
	var err os.Error;
	if f.closer != nil {
		err = f.closer.Close();
		f.closer = nil;
	}
	return err;
}

// NewFile creates a new File for acecssing an ELF binary in an underlying reader.
// The ELF binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, os.Error) {
	sr := io.NewSectionReader(r, 0, 1<<63 - 1);
	// Read and decode ELF identifier
	var ident [16]uint8;
	if _, err := r.ReadAt(&ident, 0); err != nil {
		return nil, err;
	}
	if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
		return nil, &FormatError{0, "bad magic number", ident[0:4]};
	}

	f := new(File);
	f.Class = Class(ident[EI_CLASS]);
	switch f.Class {
	case ELFCLASS32:
	case ELFCLASS64:
		// ok
	default:
		return nil, &FormatError{0, "unknown ELF class", f.Class};
	}

	f.Data = Data(ident[EI_DATA]);
	switch f.Data {
	case ELFDATA2LSB:
		f.ByteOrder = binary.LittleEndian;
	case ELFDATA2MSB:
		f.ByteOrder = binary.BigEndian;
	default:
		return nil, &FormatError{0, "unknown ELF data encoding", f.Data};
	}

	f.Version = Version(ident[EI_VERSION]);
	if f.Version != EV_CURRENT {
		return nil, &FormatError{0, "unknown ELF version", f.Version};
	}

	f.OSABI = OSABI(ident[EI_OSABI]);
	f.ABIVersion = ident[EI_ABIVERSION];

	// Read ELF file header
	var shoff int64;
	var shentsize, shnum, shstrndx int;
	shstrndx = -1;
	switch f.Class {
	case ELFCLASS32:
		hdr := new(Header32);
		sr.Seek(0, 0);
		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
			return nil, err;
		}
		f.Type = Type(hdr.Type);
		f.Machine = Machine(hdr.Machine);
		if v := Version(hdr.Version); v != f.Version {
			return nil, &FormatError{0, "mismatched ELF version", v};
		}
		shoff = int64(hdr.Shoff);
		shentsize = int(hdr.Shentsize);
		shnum = int(hdr.Shnum);
		shstrndx = int(hdr.Shstrndx);
	case ELFCLASS64:
		hdr := new(Header64);
		sr.Seek(0, 0);
		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
			return nil, err;
		}
		f.Type = Type(hdr.Type);
		f.Machine = Machine(hdr.Machine);
		if v := Version(hdr.Version); v != f.Version {
			return nil, &FormatError{0, "mismatched ELF version", v};
		}
		shoff = int64(hdr.Shoff);
		shentsize = int(hdr.Shentsize);
		shnum = int(hdr.Shnum);
		shstrndx = int(hdr.Shstrndx);
	}
	if shstrndx < 0 || shstrndx >= shnum {
		return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx};
	}

	// Read program headers
	// TODO

	// Read section headers
	f.Sections = make([]*Section, shnum);
	names := make([]uint32, shnum);
	for i := 0; i < shnum; i++ {
		off := shoff + int64(i)*int64(shentsize);
		sr.Seek(off, 0);
		s := new(Section);
		switch f.Class {
		case ELFCLASS32:
			sh := new(Section32);
			if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
				return nil, err;
			}
			names[i] = sh.Name;
			s.SectionHeader = SectionHeader{
				Type: SectionType(sh.Type),
				Flags: SectionFlag(sh.Flags),
				Addr: uint64(sh.Addr),
				Offset: uint64(sh.Off),
				Size: uint64(sh.Size),
				Link: uint32(sh.Link),
				Info: uint32(sh.Info),
				Addralign: uint64(sh.Addralign),
				Entsize: uint64(sh.Entsize),
			};
		case ELFCLASS64:
			sh := new(Section64);
			if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
				return nil, err;
			}
			names[i] = sh.Name;
			s.SectionHeader = SectionHeader{
				Type: SectionType(sh.Type),
				Flags: SectionFlag(sh.Flags),
				Offset: uint64(sh.Off),
				Size: uint64(sh.Size),
				Addr: uint64(sh.Addr),
				Link: uint32(sh.Link),
				Info: uint32(sh.Info),
				Addralign: uint64(sh.Addralign),
				Entsize: uint64(sh.Entsize),

			};
		}
		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size));
		s.ReaderAt = s.sr;
		f.Sections[i] = s;
	}

	// Load section header string table.
	s := f.Sections[shstrndx];
	shstrtab := make([]byte, s.Size);
	if _, err := r.ReadAt(shstrtab, int64(s.Offset)); err != nil {
		return nil, err;
	}
	for i, s := range f.Sections {
		var ok bool;
		s.Name, ok = getString(shstrtab, int(names[i]));
		if !ok {
			return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]};
		}
	}

	return f, nil;
}

// getString extracts a string from an ELF string table.
func getString(section []byte, start int) (string, bool) {
	if start < 0 || start >= len(section) {
		return "", false;
	}

	for end := start; end < len(section); end++ {
		if section[end] == 0 {
			return string(section[start:end]), true;
		}
	}
	return "", false;
}

// Section returns a section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
	for _, s := range f.Sections {
		if s.Name == name {
			return s;
		}
	}
	return nil;
}
