/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Copyright (c) 2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.max.elf;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* The <code>ELFHeader</code> class represents the header of an ELF file.
* It can load the header from a file and check the identification, identify
* the version, endianness, and detect which architecture the file
* has been created for.
*/
public class ELFHeader {
protected static final int ELFCLASSNONE = 0;
protected static final int ELFCLASS32 = 1;
protected static final int ELFCLASS64 = 2;
protected static final int ELFCLASSNUM = 3;
protected static final int EI_NIDENT = 16;
// constants for information within e_ident section
protected static final int EI_CLASS = 4;
protected static final int EI_DATA = 5;
protected static final int EI_VERSION = 6;
protected static final int EI_PAD = 7;
// constants for data format
protected static final int ELFDATA2LSB = 1;
protected static final int ELFDATA2MSB = 2;
/*******************************************/
// constants for the e_type field
protected static final int ET_NONE = 0;
protected static final int ET_REL = 1;
protected static final int ET_EXEC = 2;
protected static final int ET_DYN = 3;
protected static final int ET_CORE = 4;
// constants for the version field.
protected static final int EV_NONE = 0;
protected static final int EV_CURRENT = 1;
// constants for the e_ident[] member
protected static final int EI_ELFMAG0 = 0;
protected static final int EI_ELFMAG1 = 1;
protected static final int EI_ELFMAG2 = 2;
protected static final int EI_ELFMAG3 = 3;
protected static final int EI_OSABI = 7;
protected static final int EI_ABIVERSION = 8;
protected static final int EI_PADJG = 9;
/*******************************************/
// Checkstyle: stop field name check
public final byte[] e_ident;
public short e_type;
public short e_machine;
public int e_version;
public long e_entry;
public long e_phoff;
public long e_shoff;
public int e_flags;
public short e_ehsize;
public short e_phentsize;
public short e_phnum;
public short e_shentsize;
public short e_shnum;
public short e_shstrndx;
boolean bigEndian;
// Checkstyle: resume field name check
public class FormatError extends Exception {
static final long serialVersionUID = 89236748768763L;
}
/**
* The default constructor for the <code>ELFHeader</code> class simply creates a new, unitialized
* instance of this class that is ready to load.
*/
public ELFHeader() {
e_ident = new byte[EI_NIDENT];
}
/**
* The <code>read()</code> method reads the header from the specified input stream.
* It loads the identification section and checks that the header is present by testing against
* the magic ELF values, and reads the rests of the data section, initializes the ELF section.
* @param fs the input stream from which to read the ELF header
* @throws IOException if there is a problem reading from the input stream
*/
public void read(RandomAccessFile fs) throws IOException, FormatError {
// read the indentification string
if (fs.length() < EI_NIDENT) {
throw new FormatError();
}
int index = 0;
//String abc = fs.readLine();
//System.out.println(abc);
while (index < EI_NIDENT) {
index += fs.read(e_ident, index, EI_NIDENT - index);
}
checkIdent();
final ELFDataInputStream is = new ELFDataInputStream(this, fs);
if (is32Bit()) {
// read a 32-bit header.
readHeader32(is);
} else if (is64Bit()) {
// read a 64-bit header.
readHeader64(is);
}
}
private void readHeader32(ELFDataInputStream is) throws IOException {
e_type = is.read_Elf32_Half();
e_machine = is.read_Elf32_Half();
e_version = is.read_Elf32_Word();
e_entry = is.read_Elf32_Addr();
e_phoff = is.read_Elf32_Off();
e_shoff = is.read_Elf32_Off();
e_flags = is.read_Elf32_Word();
e_ehsize = is.read_Elf32_Half();
e_phentsize = is.read_Elf32_Half();
e_phnum = is.read_Elf32_Half();
e_shentsize = is.read_Elf32_Half();
e_shnum = is.read_Elf32_Half();
e_shstrndx = is.read_Elf32_Half();
}
private void readHeader64(ELFDataInputStream is) throws IOException {
e_type = is.read_Elf64_Half();
e_machine = is.read_Elf64_Half();
e_version = is.read_Elf64_Word();
e_entry = is.read_Elf64_Addr();
e_phoff = is.read_Elf64_Off();
e_shoff = is.read_Elf64_Off();
e_flags = is.read_Elf64_Word();
e_ehsize = is.read_Elf64_Half();
e_phentsize = is.read_Elf64_Half();
e_phnum = is.read_Elf64_Half();
e_shentsize = is.read_Elf64_Half();
e_shnum = is.read_Elf64_Half();
e_shstrndx = is.read_Elf64_Half();
}
private void checkIdent() throws FormatError {
checkIndentByte(0, 0x7f);
checkIndentByte(1, 'E');
checkIndentByte(2, 'L');
checkIndentByte(3, 'F');
bigEndian = isBigEndian();
}
private void checkIndentByte(int ind, int val) throws FormatError {
if (e_ident[ind] != val) {
throw new FormatError();
}
}
/**
* The <code>getVersion()</code> method returns the version of this ELF file. The version
* number is stored in the identification section of the ELF file at the beginning.
* @return the version of this ELF file as an integer
*/
public int getVersion() {
return e_ident[EI_VERSION];
}
/**
* The <code>getArchitecture()</code> method resolves the name of the architecture
* from the <code>e_machine</code> file of the structure, using an internal map for
* well-known architectures.
* @return a String representation of the architecture name
*/
public String getArchitecture() {
return ELFIdentifier.getArchitecture(e_machine);
}
/**
* The <code>isLittleEndian()</code> method checks whether this ELF file is encoded
* in the little endian format (i.e. least signficant byte first). This information is
* present in the identification section of the ELF file
* @return true if this file has the little endian data format; false otherwise
*/
public boolean isLittleEndian() {
return e_ident[EI_DATA] == ELFDATA2LSB;
}
/**
* The <code>isBigEndian()</code> method checks whether this ELF file is encoded
* in big endian format (i.e. most signficant byte first). This information is present
* in the identification section of the ELF file.
* @return true if this file has the big endian data format; false otherwise
*/
public boolean isBigEndian() {
return e_ident[EI_DATA] == ELFDATA2MSB;
}
/**
* The <code>is32Bit()</code> method checks whether this ELF file is encoded
* as 32 or 64 bits. This information is contained in the header in the EI_CLASS
* byte.
* @return true if this ELF file is 32 bit
*/
public boolean is32Bit() {
return e_ident[EI_CLASS] == ELFCLASS32;
}
/**
* The <code>is64Bit()</code> method checks whether this ELF file is encoded
* as 32 or 64 bits. This information is contained in the header in the EI_CLASS
* byte.
* @return true if this ELF file is 64 bit
*/
public boolean is64Bit() {
return e_ident[EI_CLASS] == ELFCLASS64;
}
// The following code is to write a 64 bit ELF header for creating a ELF file
public void writeHeader64(long size) throws IOException {
// To fill the e_ident[] data member.
// The following are the magic numbers that tell that the file is a ELF file.
e_ident[EI_ELFMAG0] = 0x7f;
e_ident[EI_ELFMAG1] = 'E';
e_ident[EI_ELFMAG2] = 'L';
e_ident[EI_ELFMAG3] = 'F';
e_ident[EI_CLASS] = ELFCLASS64;
e_ident[EI_DATA] = ELFDATA2LSB;
e_ident[EI_VERSION] = EV_CURRENT;
// Shd find out what the following fields have to be populated as.
e_ident[EI_OSABI] = 0;
e_ident[EI_ABIVERSION] = 0;
// The below field is for EI_PAD, and is not used.
e_ident[9] = 0;
e_type = ET_REL;
e_machine = 62; //EM_AMD64 or EM_X86_64
e_version = EV_CURRENT;
e_entry = 0;
e_phoff = 0; // No program table, hence the offset to the program header table is 0.
e_shoff = 0; // section header offset, this will be filled later.
e_flags = 0; // No Processor specific flag.
e_ehsize = 64; // The size of the header is 64 bytes for 64 bit architecture.
e_phentsize = 0; // The size of the file's program header table, here it is 0 since there is no program header table.
e_phnum = 0;
e_shentsize = 64; // size of the entry64 members in ELFSecti0n HearderTable - These are the total bytes in each header.
e_shnum = 5; // The total number of sections in the file. (intial null section, Maxvm_image, section string table, symbol table, string table )
e_shstrndx = 2; // This is the index in the section header table of the section that contains the section string table, 0 if there is no section string table.
}
public void writeELFHeader64ToFile(ELFDataOutputStream os, RandomAccessFile fis) throws IOException {
// 64 byte header is written.
// Write the e_ident[16] byte array into the object file.
fis.write(e_ident);
os.write_Elf64_Half(e_type);
os.write_Elf64_Half(e_machine);
os.write_Elf64_Word(e_version);
os.write_Elf64_Addr(e_entry);
os.write_Elf64_Off(e_phoff);
os.write_Elf64_Off(e_shoff);
os.write_Elf64_Word(e_flags);
os.write_Elf64_Half(e_ehsize);
os.write_Elf64_Half(e_phentsize);
os.write_Elf64_Half(e_phnum);
os.write_Elf64_Half(e_shentsize);
os.write_Elf64_Half(e_shnum);
os.write_Elf64_Half(e_shstrndx);
}
public void setShOff(long offset) {
this.e_shoff = offset;
}
}