blob: 9eb12f76abe3cc3fb4e040a2e3e614b65795586f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010, 2011 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - initial API and implementation
* Markus Schorn (Wind River Systems)
* Ed Swartz (Nokia) - temporary fork into EDC to adapt to IRandomReadAccessFile
* Broadcom - additional JavaDoc
* TODO: merge this fork.
*******************************************************************************/
package org.eclipse.cdt.debug.edc.internal.symbols.elf;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.core.IAddressFactory;
import org.eclipse.cdt.core.ISymbolReader;
import org.eclipse.cdt.utils.Addr32;
import org.eclipse.cdt.utils.Addr32Factory;
import org.eclipse.cdt.utils.Addr64;
import org.eclipse.cdt.utils.Addr64Factory;
public class Elf {
public final static int ELF32_ADDR_SIZE = 4;
public final static int ELF32_OFF_SIZE = 4;
public final static int ELF64_ADDR_SIZE = 8;
public final static int ELF64_OFF_SIZE = 8;
protected IRandomReadAccessFile efile;
protected ELFhdr ehdr;
protected Section[] sections;
protected String file;
protected byte[] section_strtab;
private int syms = 0;
private Symbol[] symbols;
private Symbol[] symtab_symbols;
private Section symtab_sym;
private Symbol[] dynsym_symbols;
private Section dynsym_sym;
private boolean sections_mapped; // Have sections been mapped? Used to clean up properly in Elf.Dispose.
protected String EMPTY_STRING = ""; //$NON-NLS-1$
public class ELFhdr {
/* e_ident offsets */
public final static int EI_MAG0 = 0;
public final static int EI_MAG1 = 1;
public final static int EI_MAG2 = 2;
public final static int EI_MAG3 = 3;
public final static int EI_CLASS = 4;
public final static int EI_DATA = 5;
public final static int EI_VERSION = 6;
public final static int EI_PAD = 7;
public final static int EI_NDENT = 16;
/* e_ident[EI_CLASS] */
public final static int ELFCLASSNONE = 0;
public final static int ELFCLASS32 = 1;
public final static int ELFCLASS64 = 2;
/* e_ident[EI_DATA] */
public final static int ELFDATANONE = 0;
public final static int ELFDATA2LSB = 1;
public final static int ELFDATA2MSB = 2;
/* values of e_type */
public final static int ET_NONE = 0;
public final static int ET_REL = 1;
public final static int ET_EXEC = 2;
public final static int ET_DYN = 3;
public final static int ET_CORE = 4;
public final static int ET_LOPROC = 0xff00;
public final static int ET_HIPROC = 0xffff;
/* values of e_machine */
public final static int EM_NONE = 0;
public final static int EM_M32 = 1;
public final static int EM_SPARC = 2;
public final static int EM_386 = 3;
public final static int EM_68K = 4;
public final static int EM_88K = 5;
public final static int EM_486 = 6;
public final static int EM_860 = 7;
public final static int EM_MIPS = 8;
public final static int EM_MIPS_RS3_LE = 10;
public final static int EM_RS6000 = 11;
public final static int EM_PARISC = 15;
public final static int EM_nCUBE = 16;
public final static int EM_VPP550 = 17;
public final static int EM_SPARC32PLUS = 18;
public final static int EM_PPC = 20;
public final static int EM_PPC64 = 21;
public final static int EM_ARM = 40;
public final static int EM_SH = 42;
public final static int EM_SPARCV9 = 43;
public final static int EM_TRICORE = 44;
public final static int EM_H8_300 = 46;
public final static int EM_H8_300H = 47;
public final static int EM_IA_64 = 50;
public final static int EM_COLDFIRE = 52;
public final static int EM_STARCORE = 58;
public final static int EM_X86_64 = 62;
public final static int EM_ST100 = 60;
/** @since 5.2 */
public final static int EM_68HC08 = 71; /* Freescale MC68HC08 Microcontroller */
public final static int EM_AVR = 83;
public final static int EM_FR30 = 84; /* Fujitsu FR30 */
public final static int EM_V850 = 87;
public final static int EM_M32R = 88;
public final static int EM_MN10300 = 89;
public final static int EM_MN10200 = 90;
public final static int EM_XTENSA = 94;
public final static int EM_MSP430 = 105;
public final static int EM_BLACKFIN = 106;
public final static int EM_EXCESS = 111;
public final static int EM_NIOSII = 113;
public final static int EM_C166 = 116;
public final static int EM_M16C = 117;
/** @since 5.2 */
public final static int EM_RS08 = 132; /* Freescale RS08 embedded processor */
public final static int EM_MMDSP = 160;
public final static int EM_NIOS = 0xFEBB;
public final static int EM_CYGNUS_POWERPC = 0x9025;
public final static int EM_CYGNUS_M32R = 0x9041;
public final static int EM_CYGNUS_V850 = 0x9080;
public final static int EM_CYGNUS_MN10200 = 0xdead;
public final static int EM_CYGNUS_MN10300 = 0xbeef;
public final static int EM_CYGNUS_FR30 = 0x3330;
public final static int EM_XSTORMY16 = 0xad45;
public final static int EM_CYGNUS_FRV = 0x5441;
public final static int EM_IQ2000 = 0xFEBA;
public static final int EM_XILINX_MICROBLAZE = 0xbaab;
public static final int EM_SDMA = 0xcafe;
public static final int EM_CRADLE = 0x4d55;
/** Machine-independent data for decoding the file's contents */
public byte e_ident[] = new byte[EI_NDENT];
/** file type (Elf32_Half) */
public int e_type;
/** machine type (Elf32_Half) */
public int e_machine;
/** version number (Elf32_Word) */
public long e_version;
/** entry point (Elf32_Addr) virtual address where system transfers control*/
public IAddress e_entry;
/** Program hdr offset (Elf32_Off) (zero if no table)*/
public long e_phoff;
/** Section hdr offset (Elf32_Off) (zero if no table)*/
public long e_shoff;
/** Processor flags (Elf32_Word) */
public long e_flags;
/** sizeof ehdr (Elf32_Half) */
public short e_ehsize;
/** Program header entry size (Elf32_Half) */
public short e_phentsize;
/** Number of program headers (Elf32_Half) */
public short e_phnum;
/** Section header entry size (Elf32_Half) */
public short e_shentsize;
/** Number of section headers (Elf32_Half) */
public short e_shnum;
/**
* String table index (Elf32_Half) index into the section header table
* associated with section name string table or {@link Symbol#SHN_UNDEF}
* if none.
*/
public short e_shstrndx;
protected ELFhdr() throws IOException {
efile.seek(0);
efile.readFully(e_ident);
if (e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' || e_ident[ELFhdr.EI_MAG2] != 'L'
|| e_ident[ELFhdr.EI_MAG3] != 'F')
throw new IOException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
efile.setEndian(e_ident[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB);
e_type = efile.readShortE();
e_machine = efile.readShortE();
e_version = efile.readIntE();
switch (e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
byte[] addrArray = new byte[ELF32_ADDR_SIZE];
efile.readFullyE(addrArray);
e_entry = new Addr32(addrArray);
e_phoff = efile.readIntE();
e_shoff = efile.readIntE();
}
break;
case ELFhdr.ELFCLASS64 : {
byte[] addrArray = new byte[ELF64_ADDR_SIZE];
efile.readFullyE(addrArray);
e_entry = new Addr64(addrArray);
e_phoff = readUnsignedLong(efile);
e_shoff = readUnsignedLong(efile);
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
e_flags = efile.readIntE();
e_ehsize = efile.readShortE();
e_phentsize = efile.readShortE();
e_phnum = efile.readShortE();
e_shentsize = efile.readShortE();
e_shnum = efile.readShortE();
e_shstrndx = efile.readShortE();
}
protected ELFhdr(byte[] bytes) throws IOException {
if (bytes.length <= e_ident.length) {
throw new EOFException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
}
System.arraycopy(bytes, 0, e_ident, 0, e_ident.length);
if (e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' || e_ident[ELFhdr.EI_MAG2] != 'L'
|| e_ident[ELFhdr.EI_MAG3] != 'F')
throw new IOException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
boolean isle = (e_ident[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB);
int offset = e_ident.length;
e_type = makeShort(bytes, offset, isle);
offset += 2;
e_machine = makeShort(bytes, offset, isle);
offset += 2;
e_version = makeInt(bytes, offset, isle);
offset += 4;
switch (e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
byte[] addrArray = new byte[ELF32_ADDR_SIZE];
System.arraycopy(bytes, offset, addrArray, 0, ELF32_ADDR_SIZE);
offset += ELF32_ADDR_SIZE;
e_entry = new Addr32(addrArray);
e_phoff = makeInt(bytes, offset, isle);
offset += ELF32_OFF_SIZE;
e_shoff = makeInt(bytes, offset, isle);
offset += ELF32_OFF_SIZE;
}
break;
case ELFhdr.ELFCLASS64 : {
byte[] addrArray = new byte[ELF64_ADDR_SIZE];
System.arraycopy(bytes, offset, addrArray, 0, ELF64_ADDR_SIZE);
offset += ELF64_ADDR_SIZE;
e_entry = new Addr64(addrArray);
e_phoff = makeUnsignedLong(bytes, offset, isle);
offset += ELF64_OFF_SIZE;
e_shoff = makeUnsignedLong(bytes, offset, isle);
offset += ELF64_OFF_SIZE;
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
e_flags = makeInt(bytes, offset, isle);
offset += 4;
e_ehsize = makeShort(bytes, offset, isle);
offset += 2;
e_phentsize = makeShort(bytes, offset, isle);
offset += 2;
e_phnum = makeShort(bytes, offset, isle);
offset += 2;
e_shentsize = makeShort(bytes, offset, isle);
offset += 2;
e_shnum = makeShort(bytes, offset, isle);
offset += 2;
e_shstrndx = makeShort(bytes, offset, isle);
offset += 2;
}
private final short makeShort(byte[] val, int offset, boolean isle) throws IOException {
if (val.length < offset + 2)
throw new IOException();
if (isle) {
return (short) ( (val[offset + 1] << 8) + val[offset + 0]);
}
return (short) ( (val[offset + 0] << 8) + val[offset + 1]);
}
private final long makeInt(byte[] val, int offset, boolean isle) throws IOException {
if (val.length < offset + 4)
throw new IOException();
if (isle) {
return ( (val[offset + 3] << 24) + (val[offset + 2] << 16) + (val[offset + 1] << 8) + val[offset + 0]);
}
return ( (val[offset + 0] << 24) + (val[offset + 1] << 16) + (val[offset + 2] << 8) + val[offset + 3]);
}
private final long makeLong(byte[] val, int offset, boolean isle) throws IOException {
long result = 0;
int shift = 0;
if (isle)
for (int i = 7; i >= 0; i--) {
shift = i * 8;
result += ( ((long)val[offset + i]) << shift) & (0xffL << shift);
}
else
for (int i = 0; i <= 7; i++) {
shift = (7 - i) * 8;
result += ( ((long)val[offset + i]) << shift) & (0xffL << shift);
}
return result;
}
private final long makeUnsignedLong(byte[] val, int offset, boolean isle) throws IOException {
long result = makeLong(val, offset, isle);
if (result < 0) {
throw new IOException("Maximal file offset is " + Long.toHexString(Long.MAX_VALUE) + //$NON-NLS-1$
" given offset is " + Long.toHexString(result)); //$NON-NLS-1$
}
return result;
}
}
public class Section {
/* sh_type */
/** section header inactive, other members undefined*/
public final static int SHT_NULL = 0;
/** information defined by program */
public final static int SHT_PROGBITS = 1;
/** holds a symbol table */
public final static int SHT_SYMTAB = 2;
/** holds a string table */
public final static int SHT_STRTAB = 3;
/** holds relocation entries with explicit addends */
public final static int SHT_RELA = 4;
/** holds symbol hash table */
public final static int SHT_HASH = 5;
/** holds information for dynamic linking */
public final static int SHT_DYNAMIC = 6;
/** marks the file in some way */
public final static int SHT_NOTE = 7;
/** occupies no space in file but resembles {@link #SHT_PROGBITS} */
public final static int SHT_NOBITS = 8;
/** holds relocation entries without explicit addends */
public final static int SHT_REL = 9;
/** reserved */
public final static int SHT_SHLIB = 10;
/** holds a symbol table */
public final static int SHT_DYNSYM = 11;
/* reserved section types */
/** Reserved for processor specific semantics to {@link #SHT_HIPROC} */
public final static int SHT_LOPROC = 0x70000000;
public final static int SHT_HIPROC = 0x7fffffff;
/** Reserved for use by the application programs to {@link #SHT_HIUSER} */
public final static int SHT_LOUSER = 0x80000000;
public final static int SHT_HIUSER = 0xffffffff;
/* sh_flags */
/** Section should be writable during program execution */
public final static int SHF_WRITE = 1;
/** Section occupies memory during execution */
public final static int SHF_ALLOC = 2;
/** Section contains executable machine instructions */
public final static int SHF_EXECINTR = 4;
/** All bits in this mask reserved for processor-specific semantics */
public final static int SHF_MASKPROC = 0xf0000000;
/** name of string as index into section header string table
* @see #SHT_STRTAB
* @see ELFhdr#e_shstrndx */
public long sh_name;
/** Categorizes sections content and semantics see SHT_* */
public long sh_type;
/** 1-bit flags that describe attributes */
public long sh_flags;
/** First byte of section in memory image of process or 0 if not in memory image */
public IAddress sh_addr;
/** Offset from beginning of file to first byte in section */
public long sh_offset;
/** Section's size in bytes */
public long sh_size;
/** section header table index link */
public long sh_link;
/** extra information. Semantics depends on section type */
public long sh_info;
/** address alignment constraints of section */
public long sh_addralign;
/** If section contains fixed size entries then the size of an entry else 0 */
public long sh_entsize;
/**
* @since 5.1
*/
public ByteBuffer mapSectionData() throws IOException {
sections_mapped = true;
return efile.createReadByteBuffer(sh_offset, sh_size);
}
public byte[] loadSectionData() throws IOException {
byte[] data = new byte[(int)sh_size];
efile.seek(sh_offset);
efile.read(data);
return data;
}
@Override
public String toString() {
try {
if (section_strtab == null) {
final int shstrndx= ehdr.e_shstrndx & 0xffff; // unsigned short
if (shstrndx > sections.length || shstrndx < 0)
return EMPTY_STRING;
int size = (int)sections[shstrndx].sh_size;
if (size <= 0 || size > efile.length())
return EMPTY_STRING;
section_strtab = new byte[size];
efile.seek(sections[shstrndx].sh_offset);
efile.read(section_strtab);
}
int str_size = 0;
if (sh_name > section_strtab.length) {
return EMPTY_STRING;
}
while (section_strtab[(int)sh_name + str_size] != 0)
str_size++;
return new String(section_strtab, (int)sh_name, str_size);
} catch (IOException e) {
return EMPTY_STRING;
}
}
}
protected String string_from_elf_section(Elf.Section section, int index) throws IOException {
if (index > section.sh_size) {
return EMPTY_STRING;
}
StringBuffer str = new StringBuffer();
//Most string symbols will be less than 50 bytes in size
byte [] tmp = new byte[50];
efile.seek(section.sh_offset + index);
while(true) {
int len = efile.read(tmp);
for(int i = 0; i < len; i++) {
if(tmp[i] == 0) {
len = 0;
break;
}
str.append((char)tmp[i]);
}
if(len <= 0) {
break;
}
}
return str.toString();
}
public class Symbol implements Comparable<Object> {
/* Symbol bindings */
/**
* Not visible outside the object containing their definition
*/
public final static int STB_LOCAL = 0;
/**
* Visible to all object files
*/
public final static int STB_GLOBAL = 1;
/**
* As {@link #STB_GLOBAL} but at lower precedence
*/
public final static int STB_WEAK = 2;
/* Symbol type */
/**
* Type not specified
*/
public final static int STT_NOTYPE = 0;
/**
* Associated with data object
*/
public final static int STT_OBJECT = 1;
/**
* Associated with function or other code
*/
public final static int STT_FUNC = 2;
/**
* Associated with a section @see #STB_LOCAL
*/
public final static int STT_SECTION = 3;
/**
* Associated with a file, is {@link #STB_LOCAL}
*/
public final static int STT_FILE = 4;
/* Special Indexes */
/**
* Symbol is undefined
*/
public final static int SHN_UNDEF = 0;
public final static int SHN_LORESERVE = 0xffffff00;
public final static int SHN_LOPROC = 0xffffff00;
public final static int SHN_HIPROC = 0xffffff1f;
public final static int SHN_LOOS = 0xffffff20;
public final static int SHN_HIOS = 0xffffff3f;
/**
* Absolute - will not change because of relocation
*/
public final static int SHN_ABS = 0xfffffff1;
/**
* Common block not yet allocated
*/
public final static int SHN_COMMON = 0xfffffff2;
public final static int SHN_XINDEX = 0xffffffff;
public final static int SHN_HIRESERVE = 0xffffffff;
/* NOTE: 64 bit and 32 bit ELF sections has different order */
/**
* Index into symbol string table holding name
*/
public long st_name;
/**
* May be absolute value or address
*/
public IAddress st_value;
/**
* Number of bytes of object or 0 if no size or unknown
*/
public long st_size;
/**
* Type and binding attributes
*/
public short st_info;
/**
* Holds 0 and has no meaning
*/
public short st_other;
/**
* Index into section header table for he section this symbol is defined in.
*/
public short st_shndx;
private String name = null;
private final Section sym_section;
public Symbol(Section section) {
sym_section = section;
}
public int st_type() {
return st_info & 0xf;
}
public int st_bind() {
return (st_info >> 4) & 0xf;
}
public int compareTo(Object obj) {
/*
* long thisVal = 0; long anotherVal = 0; if ( obj instanceof Symbol ) {
* Symbol sym = (Symbol)obj; thisVal = this.st_value; anotherVal =
* sym.st_value; } else if ( obj instanceof Long ) { Long val =
* (Long)obj; anotherVal = val.longValue(); thisVal = this.st_value; }
* return (thisVal <anotherVal ? -1 : (thisVal==anotherVal ? 0 :
* 1));
*/
return this.st_value.compareTo( ((Symbol)obj).st_value);
}
@Override
public String toString() {
if (name == null) {
try {
Section sections[] = getSections();
Section symstr = sections[(int)sym_section.sh_link];
name = string_from_elf_section(symstr, (int)st_name);
} catch (IOException e) {
return EMPTY_STRING;
}
}
return name;
}
}
/**
* We have to implement a separate compararator since when we do the binary
* search down below we are using a Long and a Symbol object and the Long
* doesn't know how to compare against a Symbol so if we compare Symbol vs
* Long it is ok, but not if we do Long vs Symbol.
*/
class SymbolComparator implements Comparator<Object> {
IAddress val1, val2;
public int compare(Object o1, Object o2) {
if (o1 instanceof IAddress) {
val1 = (IAddress)o1;
} else if (o1 instanceof Symbol) {
val1 = ((Symbol)o1).st_value;
} else {
return -1;
}
if (o2 instanceof IAddress) {
val2 = (IAddress)o2;
} else if (o2 instanceof Symbol) {
val2 = ((Symbol)o2).st_value;
} else {
return -1;
}
return val1.compareTo(val2);
}
}
/** Program header describing a segment or other information needed to prepare the program for execution */
public class PHdr {
/** element unused, other members undefined */
public final static int PT_NULL = 0;
/** Specifies loadable segment */
public final static int PT_LOAD = 1;
/** dynamic linking information */
public final static int PT_DYNAMIC = 2;
/** element specifies null terminated path name to invoke an interpreter */
public final static int PT_INTERP = 3;
/** location and size of auxiliary information */
public final static int PT_NOTE = 4;
/** reserved */
public final static int PT_SHLIB = 5;
/** specifies location and size of program header table */
public final static int PT_PHDR = 6;
public final static int PF_X = 1;
public final static int PF_W = 2;
public final static int PF_R = 4;
/* NOTE: 64 bit and 32 bit ELF have different order and size of elements */
/** what kind of segment */
public long p_type;
/** offset in the file of the first byte */
public long p_offset;
/** virtual address of first byte in memory */
public IAddress p_vaddr;
/** reserved for physical address in memory */
public IAddress p_paddr;
/** number of bytes of file image of segment */
public long p_filesz;
/** number of bytes of memory image of segment */
public long p_memsz;
/** flags relevant to the segment */
public long p_flags;
/** Alignment constraints of segment both in file and in memory */
public long p_align;
}
public PHdr[] getPHdrs() throws IOException {
if (ehdr.e_phnum == 0) {
return new PHdr[0];
}
efile.seek(ehdr.e_phoff);
final int length= ehdr.e_phnum & 0xffff; // interpret as unsigned short
PHdr phdrs[] = new PHdr[length];
for (int i = 0; i < length; i++) {
phdrs[i] = new PHdr();
switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
byte[] addrArray = new byte[ELF32_ADDR_SIZE];
phdrs[i].p_type = efile.readIntE();
phdrs[i].p_offset = efile.readIntE();
efile.readFullyE(addrArray);
phdrs[i].p_vaddr = new Addr32(addrArray);
efile.readFullyE(addrArray);
phdrs[i].p_paddr = new Addr32(addrArray);
phdrs[i].p_filesz = efile.readIntE();
phdrs[i].p_memsz = efile.readIntE();
phdrs[i].p_flags = efile.readIntE();
phdrs[i].p_align = efile.readIntE();
}
break;
case ELFhdr.ELFCLASS64 : {
byte[] addrArray = new byte[ELF64_ADDR_SIZE];
phdrs[i].p_type = efile.readIntE();
phdrs[i].p_flags = efile.readIntE();
phdrs[i].p_offset = readUnsignedLong(efile);
efile.readFullyE(addrArray);
phdrs[i].p_vaddr = new Addr64(addrArray);
efile.readFullyE(addrArray);
phdrs[i].p_paddr = new Addr64(addrArray);
phdrs[i].p_filesz = readUnsignedLong(efile);
phdrs[i].p_memsz = readUnsignedLong(efile);
phdrs[i].p_align = readUnsignedLong(efile);
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
}
return phdrs;
}
public class Dynamic {
public final static int DYN_ENT_SIZE_32 = 8;
public final static int DYN_ENT_SIZE_64 = 16;
public final static int DT_NULL = 0;
public final static int DT_NEEDED = 1;
public final static int DT_PLTRELSZ = 2;
public final static int DT_PLTGOT = 3;
public final static int DT_HASH = 4;
public final static int DT_STRTAB = 5;
public final static int DT_SYMTAB = 6;
public final static int DT_RELA = 7;
public final static int DT_RELASZ = 8;
public final static int DT_RELAENT = 9;
public final static int DT_STRSZ = 10;
public final static int DT_SYMENT = 11;
public final static int DT_INIT = 12;
public final static int DT_FINI = 13;
public final static int DT_SONAME = 14;
public final static int DT_RPATH = 15;
public long d_tag;
public long d_val;
private final Section section;
private String name;
protected Dynamic(Section section) {
this.section = section;
}
@Override
public String toString() {
if (name == null) {
switch ((int)d_tag) {
case DT_NEEDED :
case DT_SONAME :
case DT_RPATH :
try {
Section symstr = sections[(int)section.sh_link];
name = string_from_elf_section(symstr, (int)d_val);
} catch (IOException e) {
name = EMPTY_STRING;
}
break;
default :
name = EMPTY_STRING;
}
}
return name;
}
}
public Dynamic[] getDynamicSections(Section section) throws IOException {
if (section.sh_type != Section.SHT_DYNAMIC) {
return new Dynamic[0];
}
ArrayList<Dynamic> dynList = new ArrayList<Dynamic>();
efile.seek(section.sh_offset);
int off = 0;
// We must assume the section is a table ignoring the sh_entsize as it
// is not
// set for MIPS.
while (off < section.sh_size) {
Dynamic dynEnt = new Dynamic(section);
switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
dynEnt.d_tag = efile.readIntE();
dynEnt.d_val = efile.readIntE();
off += Dynamic.DYN_ENT_SIZE_32;
}
break;
case ELFhdr.ELFCLASS64 : {
dynEnt.d_tag = efile.readLongE();
dynEnt.d_val = efile.readLongE();
off += Dynamic.DYN_ENT_SIZE_64;
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
if (dynEnt.d_tag != Dynamic.DT_NULL)
dynList.add(dynEnt);
}
return dynList.toArray(new Dynamic[0]);
}
private void commonSetup(IRandomReadAccessFile rraFile, String file, long offset) throws IOException {
try {
efile = rraFile;
efile.seek(offset);
ehdr = new ELFhdr();
this.file = file;
} finally {
if (ehdr == null) {
dispose();
}
}
}
//A hollow entry, to be used with caution in controlled situations
protected Elf() {
}
public Elf(String file, long offset) throws IOException {
commonSetup(new ERandomAccessFile(file, "r"), file, offset); //$NON-NLS-1$
}
public Elf(String file) throws IOException {
commonSetup(new ERandomAccessFile(file, "r"), file, 0); //$NON-NLS-1$
}
public Elf(IRandomReadAccessFile rraFile, String file, long offset) throws IOException {
commonSetup(rraFile, file, offset);
}
public ELFhdr getELFhdr() throws IOException {
return ehdr;
}
public class Attribute {
public static final int ELF_TYPE_EXE = 1;
public static final int ELF_TYPE_SHLIB = 2;
public static final int ELF_TYPE_OBJ = 3;
public static final int ELF_TYPE_CORE = 4;
public static final int DEBUG_TYPE_NONE = 0;
public static final int DEBUG_TYPE_STABS = 1;
public static final int DEBUG_TYPE_DWARF = 2;
String cpu;
int type;
int debugType;
boolean bDebug;
boolean isle;
IAddressFactory addressFactory;
public String getCPU() {
return cpu;
}
public int getType() {
return type;
}
public boolean hasDebug() {
return debugType != DEBUG_TYPE_NONE;
}
public int getDebugType() {
return debugType;
}
public boolean isLittleEndian() {
return isle;
}
public IAddressFactory getAddressFactory() {
return addressFactory;
}
}
public Attribute getAttributes() throws IOException {
Attribute attrib = new Attribute();
switch (ehdr.e_type) {
case Elf.ELFhdr.ET_CORE :
attrib.type = Attribute.ELF_TYPE_CORE;
break;
case Elf.ELFhdr.ET_EXEC :
attrib.type = Attribute.ELF_TYPE_EXE;
break;
case Elf.ELFhdr.ET_REL :
attrib.type = Attribute.ELF_TYPE_OBJ;
break;
case Elf.ELFhdr.ET_DYN :
attrib.type = Attribute.ELF_TYPE_SHLIB;
break;
}
switch (ehdr.e_machine & 0xFFFF) {
case Elf.ELFhdr.EM_386 :
case Elf.ELFhdr.EM_486 :
attrib.cpu = "x86"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_68K :
attrib.cpu = "m68k"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_PPC :
case Elf.ELFhdr.EM_CYGNUS_POWERPC :
case Elf.ELFhdr.EM_RS6000 :
attrib.cpu = "ppc"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_PPC64 :
attrib.cpu = "ppc64"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_SH :
attrib.cpu = "sh"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_ARM :
attrib.cpu = "arm"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_MIPS_RS3_LE :
case Elf.ELFhdr.EM_MIPS :
attrib.cpu = "mips"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_SPARC32PLUS :
case Elf.ELFhdr.EM_SPARC :
case Elf.ELFhdr.EM_SPARCV9 :
attrib.cpu = "sparc"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_H8_300 :
case Elf.ELFhdr.EM_H8_300H :
attrib.cpu = "h8300"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_V850 :
case Elf.ELFhdr.EM_CYGNUS_V850 :
attrib.cpu = "v850"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_MN10300 :
case Elf.ELFhdr.EM_CYGNUS_MN10300 :
attrib.cpu = "mn10300"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_MN10200 :
case Elf.ELFhdr.EM_CYGNUS_MN10200 :
attrib.cpu = "mn10200"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_M32R :
attrib.cpu = "m32r"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_FR30 :
case Elf.ELFhdr.EM_CYGNUS_FR30 :
attrib.cpu = "fr30"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_XSTORMY16 :
attrib.cpu = "xstormy16"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_CYGNUS_FRV :
attrib.cpu = "frv"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_IQ2000 :
attrib.cpu = "iq2000"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_EXCESS :
attrib.cpu = "excess"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_NIOSII :
attrib.cpu = "alteranios2"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_NIOS :
attrib.cpu = "alteranios"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_IA_64 :
attrib.cpu = "ia64"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_COLDFIRE:
attrib.cpu = "coldfire"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_AVR :
attrib.cpu = "avr"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_MSP430 :
attrib.cpu = "msp430"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_XTENSA:
attrib.cpu = "xtensa"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_ST100:
attrib.cpu = "st100"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_X86_64:
attrib.cpu = "x86_64"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_XILINX_MICROBLAZE:
attrib.cpu = "microblaze"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_C166:
attrib.cpu = "c166"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_TRICORE:
attrib.cpu = "TriCore"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_M16C:
attrib.cpu = "M16C"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_STARCORE:
attrib.cpu = "StarCore"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_BLACKFIN :
attrib.cpu = "bfin"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_SDMA:
attrib.cpu = "sdma"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_CRADLE:
attrib.cpu = "cradle"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_MMDSP:
attrib.cpu = "mmdsp"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_68HC08:
attrib.cpu = "hc08"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_RS08:
attrib.cpu = "rs08"; //$NON-NLS-1$
break;
case Elf.ELFhdr.EM_NONE :
default :
attrib.cpu = "none"; //$NON-NLS-1$
}
switch (ehdr.e_ident[Elf.ELFhdr.EI_DATA]) {
case Elf.ELFhdr.ELFDATA2LSB :
attrib.isle = true;
break;
case Elf.ELFhdr.ELFDATA2MSB :
attrib.isle = false;
break;
}
switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 :
attrib.addressFactory = new Addr32Factory();
break;
case ELFhdr.ELFCLASS64 :
attrib.addressFactory = new Addr64Factory();
break;
case ELFhdr.ELFCLASSNONE :
default :
attrib.addressFactory = null;
}
// getSections
// find .debug using toString
Section[] sec = getSections();
if (sec != null) {
for (int i = 0; i < sec.length; i++) {
String s = sec[i].toString();
if (s.startsWith(".debug")) { //$NON-NLS-1$
attrib.debugType = Attribute.DEBUG_TYPE_DWARF;
break;
} else if (s.equals(".stab")) { //$NON-NLS-1$
attrib.debugType = Attribute.DEBUG_TYPE_STABS;
break;
}
}
}
return attrib;
}
public static Attribute getAttributes(String file) throws IOException {
Elf elf = new Elf(file);
Attribute attrib = elf.getAttributes();
elf.dispose();
return attrib;
}
public static Attribute getAttributes(byte[] array) throws IOException {
Elf emptyElf = new Elf();
emptyElf.ehdr = emptyElf.new ELFhdr(array);
emptyElf.sections = new Elf.Section[0];
Attribute attrib = emptyElf.getAttributes();
emptyElf.dispose();
return attrib;
}
public static boolean isElfHeader(byte[] e_ident) {
if (e_ident.length < 4 || e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E'
|| e_ident[ELFhdr.EI_MAG2] != 'L' || e_ident[ELFhdr.EI_MAG3] != 'F')
return false;
return true;
}
public void dispose() {
try {
if (efile != null) {
efile.close();
efile = null;
// ensure the mappings get cleaned up
if (sections_mapped)
System.gc();
}
} catch (IOException e) {
}
}
/**
* Make sure we do not leak the fds.
*/
@Override
protected void finalize() throws Throwable {
try {
dispose();
} finally {
super.finalize();
}
}
public Section getSectionByName(String name) throws IOException {
if (sections == null)
getSections();
for (int i = 0; i < sections.length; i++) {
if (sections[i].toString().equals(name)) {
return sections[i];
}
}
return null;
}
public Section[] getSections(int type) throws IOException {
if (sections == null)
getSections();
ArrayList<Section> slist = new ArrayList<Section>();
for (int i = 0; i < sections.length; i++) {
if (sections[i].sh_type == type)
slist.add(sections[i]);
}
return slist.toArray(new Section[0]);
}
public Section[] getSections() throws IOException {
if (sections == null) {
if (ehdr.e_shoff == 0) {
sections = new Section[0];
return sections;
}
final int length= ehdr.e_shnum & 0xffff; // unsigned short
sections = new Section[length];
for (int i = 0; i < length; i++) {
efile.seek(ehdr.e_shoff + i * (ehdr.e_shentsize & 0xffff)); // unsigned short
sections[i] = new Section();
sections[i].sh_name = efile.readIntE();
sections[i].sh_type = efile.readIntE();
switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
byte[] addrArray = new byte[ELF32_ADDR_SIZE];
sections[i].sh_flags = efile.readIntE();
efile.readFullyE(addrArray);
sections[i].sh_addr = new Addr32(addrArray);
sections[i].sh_offset = efile.readIntE();
sections[i].sh_size = efile.readIntE();
}
break;
case ELFhdr.ELFCLASS64 : {
byte[] addrArray = new byte[ELF64_ADDR_SIZE];
sections[i].sh_flags = efile.readLongE();
efile.readFullyE(addrArray);
sections[i].sh_addr = new Addr64(addrArray);
sections[i].sh_offset = readUnsignedLong(efile);
sections[i].sh_size = readUnsignedLong(efile);
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
sections[i].sh_link = efile.readIntE();
sections[i].sh_info = efile.readIntE();
switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
sections[i].sh_addralign = efile.readIntE();
sections[i].sh_entsize = efile.readIntE();
}
break;
case ELFhdr.ELFCLASS64 : {
sections[i].sh_addralign = efile.readLongE();
sections[i].sh_entsize = readUnsignedLong(efile);
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
if (sections[i].sh_type == Section.SHT_SYMTAB)
syms = i;
if (syms == 0 && sections[i].sh_type == Section.SHT_DYNSYM)
syms = i;
}
}
return sections;
}
private Symbol[] loadSymbolsBySection(Section section) throws IOException {
int numSyms = 1;
if (section.sh_entsize != 0) {
numSyms = (int)section.sh_size / (int)section.sh_entsize;
}
ArrayList<Symbol> symList = new ArrayList<Symbol>(numSyms);
long offset = section.sh_offset;
for (int c = 0; c < numSyms; offset += section.sh_entsize, c++) {
efile.seek(offset);
Symbol symbol = new Symbol(section);
switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
case ELFhdr.ELFCLASS32 : {
byte[] addrArray = new byte[ELF32_ADDR_SIZE];
symbol.st_name = efile.readIntE();
efile.readFullyE(addrArray);
symbol.st_value = new Addr32(addrArray);
symbol.st_size = efile.readIntE();
symbol.st_info = efile.readByte();
symbol.st_other = efile.readByte();
symbol.st_shndx = efile.readShortE();
}
break;
case ELFhdr.ELFCLASS64 : {
byte[] addrArray = new byte[ELF64_ADDR_SIZE];
symbol.st_name = efile.readIntE();
symbol.st_info = efile.readByte();
symbol.st_other = efile.readByte();
symbol.st_shndx = efile.readShortE();
efile.readFullyE(addrArray);
symbol.st_value = new Addr64(addrArray);
symbol.st_size = readUnsignedLong(efile);
}
break;
case ELFhdr.ELFCLASSNONE :
default :
throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
}
if (symbol.st_info == 0)
continue;
symList.add(symbol);
}
Symbol[] results = symList.toArray(new Symbol[0]);
Arrays.sort(results);
return results;
}
public void loadSymbols() throws IOException {
if (symbols == null) {
Section section[] = getSections(Section.SHT_SYMTAB);
if (section.length > 0) {
symtab_sym = section[0];
symtab_symbols = loadSymbolsBySection(section[0]);
} else {
symtab_sym = null;
symtab_symbols = new Symbol[0];
}
section = getSections(Section.SHT_DYNSYM);
if (section.length > 0) {
dynsym_sym = section[0];
dynsym_symbols = loadSymbolsBySection(section[0]);
} else {
dynsym_sym = null;
dynsym_symbols = new Symbol[0];
}
if (symtab_sym != null) {
// sym = symtab_sym;
symbols = symtab_symbols;
} else if (dynsym_sym != null) {
// sym = dynsym_sym;
symbols = dynsym_symbols;
}
}
}
public Symbol[] getSymbols() {
return symbols;
}
public Symbol[] getDynamicSymbols() {
return dynsym_symbols;
}
public Symbol[] getSymtabSymbols() {
return symtab_symbols;
}
/* return the address of the function that address is in */
public Symbol getSymbol(IAddress vma) {
if (symbols == null) {
return null;
}
//@@@ If this works, move it to a single instance in this class.
SymbolComparator symbol_comparator = new SymbolComparator();
int ndx = Arrays.binarySearch(symbols, vma, symbol_comparator);
if (ndx > 0)
return symbols[ndx];
if (ndx == -1) {
return null;
}
ndx = -ndx - 1;
return symbols[ndx - 1];
}
/*
* public long swapInt( long val ) { if ( ehdr.e_ident[ELFhdr.EI_DATA] ==
* ELFhdr.ELFDATA2LSB ) { short tmp[] = new short[4]; tmp[0] = (short)(val &
* 0x00ff); tmp[1] = (short)((val >> 8) & 0x00ff); tmp[2] = (short)((val >>
* 16) & 0x00ff); tmp[3] = (short)((val >> 24) & 0x00ff); return ((tmp[0] < <
* 24) + (tmp[1] < < 16) + (tmp[2] < < 8) + tmp[3]); } return val; }
*
* public int swapShort( short val ) { if ( ehdr.e_ident[ELFhdr.EI_DATA] ==
* ELFhdr.ELFDATA2LSB ) { short tmp[] = new short[2]; tmp[0] = (short)(val &
* 0x00ff); tmp[1] = (short)((val >> 8) & 0x00ff); return (short)((tmp[0] < <
* 8) + tmp[1]); } return val; }
*/
public String getFilename() {
return file;
}
protected long readUnsignedLong(IRandomReadAccessFile file) throws IOException {
long result = file.readLongE();
if (result < 0) {
throw new IOException("Maximal file offset is " + Long.toHexString(Long.MAX_VALUE) + //$NON-NLS-1$
" given offset is " + Long.toHexString(result)); //$NON-NLS-1$
}
return result;
}
/* TODO: not used in EDC
private ISymbolReader createDwarfReader() {
DwarfReader reader = null;
// Check if Dwarf data exists
try {
reader = new DwarfReader(this);
} catch (IOException e) {
// No Dwarf data in the Elf.
}
return reader;
}
*/
public ISymbolReader getSymbolReader() {
ISymbolReader reader = null;
//reader = createDwarfReader(); // TODO: not used in EDC
return reader;
}
}