/* * 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. * * Created Sep 5, 2005 */ package com.oracle.max.elf; import java.io.IOException; import java.io.RandomAccessFile; /** * The <code>ELFProgramHeaderTable</code> class represents a program header table * contained in an ELF file. This table contains information about each section * in the program. This class represents a cleaned up view of the table. Since * the size and number of entries in this table are determined from the information * contained in the ELF header, this class requires an instance of the * <code>ELFHeader</code> class to be passed to the constructor. * * </p> * The ELF format states that a program header table is required for executables; this * table contains information for the operating system (or bootloader or programmer * in the case of embedded systems) to create a process image from the binary. This table * is optional for relocatable object files. */ public class ELFProgramHeaderTable { public static final int PT_NULL = 0; public static final int PT_LOAD = 1; public static final int PT_DYNAMIC = 2; public static final int PT_INTERP = 3; public static final int PT_NOTE = 4; public static final int PT_SHLIB = 5; public static final int PT_PHDR = 6; public static final int PT_LOPROC = 0x70000000; public static final int PT_HIPROC = 0x7fffffff; public static final int PF_EXEC = 0x1; public static final int PF_WRITE = 0x2; public static final int PF_READ = 0x4; public static final int ELF32_PHTENT_SIZE = 32; public static final int ELF64_PHTENT_SIZE = 56; public abstract class Entry { public int p_type; public int p_flags; public int getFlags() { return p_flags; } public int getType() { return p_type; } public String getTypeString() { switch (p_type) { case PT_NULL: return "NULL"; case PT_LOAD: return "LOAD"; case PT_DYNAMIC: return "DYNAMIC"; case PT_INTERP: return "INTERP"; case PT_NOTE: return "NOTE"; default: return "UNKNOWN TYPE"; } } public boolean isLoadable() { return getType() == PT_LOAD; } public boolean isExecutable() { return (getFlags() & PF_EXEC) != 0; } public String getFlagString() { final StringBuffer buffer = new StringBuffer(); final int flags = getFlags(); if ((flags & PF_EXEC) != 0) { buffer.append("EXEC "); } if ((flags & PF_WRITE) != 0) { buffer.append("WRITE "); } if ((flags & PF_READ) != 0) { buffer.append("READ "); } return buffer.toString(); } public boolean is32Bit() { return this instanceof Entry32; } public boolean is64Bit() { return this instanceof Entry64; } } public class Entry32 extends Entry { // Checkstyle: stop field name check public int p_offset; public int p_vaddr; public int p_paddr; public int p_filesz; public int p_memsz; public int p_align; // Checkstyle: start field name check } public class Entry64 extends Entry { public long p_offset; public long p_vaddr; public long p_paddr; public long p_filesz; public long p_memsz; public long p_align; } public final ELFHeader header; public final Entry[] entries; /** * The constructor for the <code>ELFProgramHeaderTable</code> class creates a new instance * for the file containing the specified ELF header. The <code>ELFHeader</code> instance * contains information about the ELF file including the machine endianness that is * important for the program header table. * @param elfHeader the initialized ELF header from the file specified. */ public ELFProgramHeaderTable(ELFHeader elfHeader) { this.header = elfHeader; entries = new Entry[elfHeader.e_phnum]; } /** * The <code>read()</code> method reqds the program header table from the specified * input stream. This method assumes that the input stream has been positioned at * the beginning of the program header table. * @param fis the input stream from which to read the program header table * @throws IOException if there is a problem reading the header table from the input */ public void read(RandomAccessFile fis) throws IOException { if (entries.length == 0) { return; } // seek to the beginning of the table fis.seek(header.e_phoff); final ELFDataInputStream is = new ELFDataInputStream(header, fis); // read each entry for (int cntr = 0; cntr < entries.length; cntr++) { entries[cntr] = readEntry(fis, is); } } private Entry readEntry(RandomAccessFile fis, ELFDataInputStream is) throws IOException { if (header.is32Bit()) { return readEntry32(fis, is); } else if (header.is64Bit()) { return readEntry64(fis, is); } throw new Error("unknown bit size for ELF header"); } public Entry32 readEntry32(RandomAccessFile fis, ELFDataInputStream is) throws IOException { final Entry32 e = new Entry32(); e.p_type = is.read_Elf32_Word(); e.p_offset = is.read_Elf32_Off(); e.p_vaddr = is.read_Elf32_Addr(); e.p_paddr = is.read_Elf32_Addr(); e.p_filesz = is.read_Elf32_Word(); e.p_memsz = is.read_Elf32_Word(); e.p_flags = is.read_Elf32_Word(); e.p_align = is.read_Elf32_Word(); readPadding(fis, ELF32_PHTENT_SIZE, header.e_phentsize); return e; } private void readPadding(RandomAccessFile fis, int read, short goal) throws IOException { for (int pad = read; pad < goal; pad++) { fis.read(); } } public Entry64 readEntry64(RandomAccessFile fis, ELFDataInputStream is) throws IOException { final Entry64 e = new Entry64(); // note the order of these fields is different between 32 and 64 bit versions. e.p_type = is.read_Elf64_Word(); e.p_flags = is.read_Elf64_Word(); e.p_offset = is.read_Elf64_Off(); e.p_vaddr = is.read_Elf64_Addr(); e.p_paddr = is.read_Elf64_Addr(); e.p_filesz = is.read_Elf64_XWord(); e.p_memsz = is.read_Elf64_XWord(); e.p_align = is.read_Elf64_XWord(); // read the rest of the entry (padding) readPadding(fis, ELF64_PHTENT_SIZE, header.e_phentsize); return e; } public Entry getEntry(int ind) { return entries[ind]; } public static String getType(Entry e) { switch (e.getType()) { case PT_NULL: return "null"; case PT_LOAD: return "load"; case PT_DYNAMIC: return "dynamic"; case PT_INTERP: return "interp"; case PT_NOTE: return "note"; case PT_SHLIB: return "shlib"; case PT_PHDR: return "phdr"; default: return Integer.toString(e.getType(), 16); } } }