| /******************************************************************************* |
| * Copyright (c) 2000, 2016 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) |
| *******************************************************************************/ |
| package org.eclipse.cdt.utils.elf; |
| |
| import static org.eclipse.cdt.internal.core.ByteUtils.makeInt; |
| import static org.eclipse.cdt.internal.core.ByteUtils.makeLong; |
| import static org.eclipse.cdt.internal.core.ByteUtils.makeShort; |
| |
| 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; |
| import org.eclipse.cdt.utils.ERandomAccessFile; |
| import org.eclipse.cdt.utils.debug.dwarf.DwarfReader; |
| |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.FileChannel.MapMode; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| |
| 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 ERandomAccessFile 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; |
| /** @since 5.5 */ |
| public final static int EM_ESIRISC = 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; |
| |
| /** @since 5.4 */ |
| public final static int EM_RX = 173; /* Renesas RX Microcontroller */ |
| |
| /** @since 5.4 */ |
| public final static int EM_RL78 = 197; /* Renesas RL78 Microcontroller */ |
| /** @since 6.0 */ |
| public final static int EM_AARCH64 = 183; |
| |
| 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; |
| |
| public byte e_ident[] = new byte[EI_NDENT]; |
| public int e_type; /* file type (Elf32_Half) */ |
| public int e_machine; /* machine type (Elf32_Half) */ |
| public long e_version; /* version number (Elf32_Word) */ |
| public IAddress e_entry; /* entry point (Elf32_Addr) */ |
| public long e_phoff; /* Program hdr offset (Elf32_Off) */ |
| public long e_shoff; /* Section hdr offset (Elf32_Off) */ |
| public long e_flags; /* Processor flags (Elf32_Word) */ |
| public short e_ehsize; /* sizeof ehdr (Elf32_Half) */ |
| public short e_phentsize; /* Program header entry size (Elf32_Half) */ |
| public short e_phnum; /* Number of program headers (Elf32_Half) */ |
| public short e_shentsize; /* Section header entry size (Elf32_Half) */ |
| public short e_shnum; /* Number of section headers (Elf32_Half) */ |
| public short e_shstrndx; /* String table index (Elf32_Half) */ |
| |
| 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; |
| } |
| } |
| |
| public class Section { |
| |
| /* sh_type */ |
| public final static int SHT_NULL = 0; |
| public final static int SHT_PROGBITS = 1; |
| public final static int SHT_SYMTAB = 2; |
| public final static int SHT_STRTAB = 3; |
| public final static int SHT_RELA = 4; |
| public final static int SHT_HASH = 5; |
| public final static int SHT_DYNAMIC = 6; |
| public final static int SHT_NOTE = 7; |
| public final static int SHT_NOBITS = 8; |
| public final static int SHT_REL = 9; |
| public final static int SHT_SHLIB = 10; |
| public final static int SHT_DYNSYM = 11; |
| |
| public final static int SHT_LOPROC = 0x70000000; |
| |
| /* sh_flags */ |
| public final static int SHF_WRITE = 1; |
| public final static int SHF_ALLOC = 2; |
| public final static int SHF_EXECINTR = 4; |
| |
| /* note_types */ |
| /** |
| * @since 5.7 |
| */ |
| public final static int NT_GNU_BUILD_ID = 3; |
| |
| public long sh_name; |
| public long sh_type; |
| public long sh_flags; |
| public IAddress sh_addr; |
| public long sh_offset; |
| public long sh_size; |
| public long sh_link; |
| public long sh_info; |
| public long sh_addralign; |
| public long sh_entsize; |
| |
| /** |
| * @since 5.1 |
| */ |
| public ByteBuffer mapSectionData() throws IOException { |
| sections_mapped = true; |
| return efile.getChannel().map(MapMode.READ_ONLY, sh_offset, sh_size).load().asReadOnlyBuffer(); |
| } |
| |
| 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; |
| } |
| |
| StringBuilder str = new StringBuilder(); |
| //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 */ |
| public final static int STB_LOCAL = 0; |
| public final static int STB_GLOBAL = 1; |
| public final static int STB_WEAK = 2; |
| /* Symbol type */ |
| public final static int STT_NOTYPE = 0; |
| public final static int STT_OBJECT = 1; |
| public final static int STT_FUNC = 2; |
| public final static int STT_SECTION = 3; |
| public final static int STT_FILE = 4; |
| /* Special Indexes */ |
| 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; |
| public final static int SHN_ABS = 0xfffffff1; |
| 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 */ |
| public long st_name; |
| public IAddress st_value; |
| public long st_size; |
| public short st_info; |
| public short st_other; |
| 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; |
| } |
| |
| @Override |
| 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; |
| @Override |
| 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); |
| } |
| } |
| |
| public class PHdr { |
| |
| public final static int PT_NULL = 0; |
| public final static int PT_LOAD = 1; |
| public final static int PT_DYNAMIC = 2; |
| public final static int PT_INTERP = 3; |
| public final static int PT_NOTE = 4; |
| public final static int PT_SHLIB = 5; |
| 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 */ |
| public long p_type; |
| public long p_offset; |
| public IAddress p_vaddr; |
| public IAddress p_paddr; |
| public long p_filesz; |
| public long p_memsz; |
| public long p_flags; |
| 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(String file, long offset) throws IOException { |
| try { |
| efile = new ERandomAccessFile(file, "r"); //$NON-NLS-1$ |
| efile.setFileOffset(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(file, offset); |
| } |
| |
| public Elf(String file) throws IOException { |
| commonSetup(file, 0); |
| } |
| |
| 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_AARCH64 : |
| attrib.cpu = "aarch64"; //$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_ESIRISC : |
| attrib.cpu = "esirisc"; //$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_RX: |
| attrib.cpu = "rx"; //$NON-NLS-1$ |
| break; |
| case Elf.ELFhdr.EM_RL78: |
| attrib.cpu = "rl78"; //$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(ERandomAccessFile 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; |
| } |
| |
| 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(); |
| return reader; |
| } |
| |
| /** @since 5.4 */ |
| public static 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; |
| } |
| } |