/* * 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>ELFSymbolTable</code> class represents a symbol table within * an ELF file. The symbol table is used to locate functions and variables * for relocation and debugging purposes. * */ public class ELFSymbolTable { public static final int STT_NOTYPE = 0; public static final int STT_OBJECT = 1; public static final int STT_FUNC = 2; public static final int STT_SECTION = 3; public static final int STT_FILE = 4; public static final int STT_LOPROC = 13; public static final int STT_HIPROC = 15; public static final int STB_LOCAL = 0; public static final int STB_GLOBAL = 1; public static final int STB_WEAK = 2; public static final int STB_LOPROC = 13; public static final int STB_HIPROC = 15; private static final int ELF32_STENT_SIZE = 16; private static final int ELF64_STENT_SIZE = 24; public abstract class Entry { public abstract int getInfo(); public String getBinding() { switch ((getInfo() >> 4) & 0xf) { case STB_LOCAL: return "LOCAL"; case STB_GLOBAL: return "GLOBAL"; case STB_WEAK: return "WEAK"; default: return "unknown"; } } public String getType() { switch (getInfo() & 0xf) { case STT_NOTYPE: return "n"; case STT_OBJECT: return "object"; case STT_FUNC: return "func"; case STT_SECTION: return "section"; case STT_FILE: return "file"; default: return "unknown"; } } public boolean isFunction() { return (getInfo() & 0xf) == STT_FUNC; } public boolean isObject() { return (getInfo() & 0xf) == STT_OBJECT; } public abstract int getNameIndex(); public boolean is32Bit() { return this instanceof Entry32; } public boolean is64Bit() { return this instanceof Entry64; } public String getName() { if (strtab != null) { return strtab.getString(getNameIndex()); } return ""; } public abstract short getSectionHeaderIndex(); } public class Entry32 extends Entry { public int st_name; public int st_value; public int st_size; public int st_info; public int st_other; public short st_shndx; @Override public int getInfo() { return st_info; } @Override public int getNameIndex() { return st_name; } @Override public short getSectionHeaderIndex() { return st_shndx; } } public class Entry64 extends Entry { public int st_name; public int st_info; // Should be a byte public int st_other; // Should be a byte public short st_shndx; public long st_value; public long st_size; @Override public int getInfo() { return st_info; } @Override public int getNameIndex() { return st_name; } @Override public short getSectionHeaderIndex() { return st_shndx; } } public final ELFHeader header; public final ELFSectionHeaderTable.Entry entry; public final Entry[] entries; protected ELFStringTable strtab; /** * The constructor for the <code>ELFSymbolTable</code> class creates a new * symbol table with the specified ELF header from the specified ELF section * header table entry. * @param elfHeader the header of the ELF file * @param sectionEntry the entry in the section header table corresponding to this * symbol table */ public ELFSymbolTable(ELFHeader elfHeader, ELFSectionHeaderTable.Entry sectionEntry) { this.header = elfHeader; this.entry = sectionEntry; entries = new Entry[(int) (sectionEntry.getSize() / sectionEntry.getEntrySize())]; } /** * The <code>read()</code> method reads this symbol table from the specified random * access file. The file is first advanced to the appropriate position with the * <code>seek()</code> method and then the entries are loaded. * @param f the random access file from which to read the symbol table * @throws IOException if there is a problem reading from the file */ public void read(RandomAccessFile f) throws IOException { // seek to the beginning of the section f.seek(entry.getOffset()); // create the elf data input stream final ELFDataInputStream is = new ELFDataInputStream(header, f); // read each of the entries for (int cntr = 0; cntr < entries.length; cntr++) { entries[cntr] = readEntry(f, is); } } private String getSymbolTableName(int cntr) { switch(cntr) { case 0: return ""; case 1: return "maxvm_image"; case 2: return "maxvm_image_start"; case 3: return "maxvm_image_end"; default: return "Error"; } } public void setSymbolTableEntries(int index, long size) { for (int cntr = 0; cntr < entries.length; cntr++) { entries[cntr] = setEntries(getSymbolTableName(cntr), index, size); } } /* * This Function sets the entries for the symbol table. */ public Entry64 setEntries(String sectionName, int index, long size) { Entry64 e = new Entry64(); e.st_other = 0; e.st_size = 0; e.st_value = 0; e.st_name = 0; if (sectionName.equalsIgnoreCase("")) { e.st_shndx = 0; e.st_info = 0; return e; } else if (sectionName.equalsIgnoreCase("maxvm_image")) { // The below value of 3 will equate to STB_LOCAL for the bind value. // and section for the type section as per the bind and type value extraction // from the value field. e.st_info = 3; } else { // This is for the globals in the maxvm image that is stored in the maxvm_image section. e.st_name = strtab.getIndex(sectionName); // the value of 16 will equate to STB_GLOBAL for the bind value. e.st_info = 16; if (sectionName.equalsIgnoreCase("maxvm_image_end")) { // This entry will contain the size of the entire file. e.st_value = size; } } e.st_shndx = (short) index; return e; } private ELFSymbolTable.Entry readEntry(RandomAccessFile f, ELFDataInputStream is) throws IOException { if (header.is32Bit()) { return readEntry32(f, is); } else if (header.is64Bit()) { return readEntry64(f, is); } throw new Error("unknown bit size"); } private Entry32 readEntry32(RandomAccessFile f, ELFDataInputStream is) throws IOException { final Entry32 e = new Entry32(); e.st_name = is.read_Elf32_Word(); e.st_value = is.read_Elf32_Addr(); e.st_size = is.read_Elf32_Word(); e.st_info = is.read_Elf32_uchar(); e.st_other = is.read_Elf32_uchar(); e.st_shndx = is.read_Elf32_Half(); for (int pad = ELF32_STENT_SIZE; pad < entry.getEntrySize(); pad++) { f.read(); } return e; } private Entry64 readEntry64(RandomAccessFile f, ELFDataInputStream is) throws IOException { final Entry64 e = new Entry64(); // note the order of fields is different in the 64 bit version. e.st_name = is.read_Elf64_Word(); e.st_info = is.read_Elf64_uchar(); e.st_other = is.read_Elf64_uchar(); e.st_shndx = is.read_Elf64_Half(); e.st_value = is.read_Elf64_Addr(); e.st_size = is.read_Elf64_XWord(); for (int pad = ELF64_STENT_SIZE; pad < entry.getEntrySize(); pad++) { f.read(); } return e; } public void setStringTable(ELFStringTable str) { strtab = str; } public ELFStringTable getStringTable() { return strtab; } public void write64ToFile(ELFDataOutputStream os, RandomAccessFile fis) throws IOException { for (int cntr = 0; cntr < entries.length; cntr++) { final Entry e = entries[cntr]; final Entry64 e64 = (Entry64) e; os.write_Elf64_Word(e64.getNameIndex()); // 4 bytes; byte info = (byte) e64.getInfo(); os.write_1(info); // Only one byte byte other = (byte) e64.st_other; os.write_1(other); // Only one byte os.write_Elf64_Half(e64.st_shndx); // 2 bytes; os.write_Elf64_Addr(e64.st_value); // 8 bytes; os.write_Elf64_XWord(e64.st_size); // 8 bytes; } } }