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