From d046afcb844079b7f162061cb0cd6302336d2f8b Mon Sep 17 00:00:00 2001 From: Andrew Gvozdev Date: Wed, 4 Nov 2009 14:33:52 +0000 Subject: [PATCH] bug 270790: Mach-O Parser doesn't recognize x86_64 binaries Initial copy of non-64 MachO BinaryParser files --- .../org/eclipse/cdt/utils/macho/MachO64.java | 1680 +++++++++++++++++ .../cdt/utils/macho/MachOHelper64.java | 319 ++++ .../macho/parser/MachOBinaryArchive64.java | 60 + .../macho/parser/MachOBinaryExecutable64.java | 25 + .../macho/parser/MachOBinaryObject64.java | 416 ++++ .../macho/parser/MachOBinaryShared64.java | 25 + .../cdt/utils/macho/parser/MachOParser64.java | 148 ++ 7 files changed, 2673 insertions(+) create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachO64.java create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachOHelper64.java create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryArchive64.java create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryExecutable64.java create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryObject64.java create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryShared64.java create mode 100644 core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOParser64.java diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachO64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachO64.java new file mode 100644 index 00000000000..b8da4e5e94f --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachO64.java @@ -0,0 +1,1680 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 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 + * Craig Watson. + * Apple Computer - work on performance optimizations + *******************************************************************************/ +package org.eclipse.cdt.utils.macho; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.ISymbolReader; +import org.eclipse.cdt.utils.CPPFilt; +import org.eclipse.cdt.utils.debug.stabs.StabsReader; + +// test checkin +public class MachO { + protected ERandomAccessFile efile; + + protected MachOhdr mhdr; + protected LoadCommand[] loadcommands; + protected boolean cppFiltEnabled = true; + protected CPPFilt cppFilt; + protected String file; + protected boolean debugsym = false; /* contains debugging symbols */ + + private Symbol[] symbols; /* symbols from SymtabCommand */ + private Symbol[] local_symbols; /* local symbols from DySymtabCommand */ + private boolean dynsym = false; /* set if DynSymtabCommand is present */ + Line[] lines; /* line table */ + private ArrayList
sections = new ArrayList
(); /* sections from SegmentCommand */ + SymtabCommand symtab; /* SymtabCommand that contains the symbol table */ + + protected static final String EMPTY_STRING = ""; //$NON-NLS-1$ + + protected static final SymbolComparator symbol_comparator = new SymbolComparator(); + + + public class MachOhdr { + + /* values of magic */ + public final static int MH_MAGIC = 0xfeedface; /* the mach magic number */ + public final static int MH_CIGAM = 0xcefaedfe; + public final static int MH_UNIVERSAL = 0xcafebabe; + + /* values of cputype */ + public final static int CPU_TYPE_ANY = -1; + public final static int CPU_TYPE_VAX = 1; + public final static int CPU_TYPE_MC680x0 = 6; + public final static int CPU_TYPE_I386 = 7; + public final static int CPU_TYPE_MC98000 = 10; + public final static int CPU_TYPE_HPPA = 11; + public final static int CPU_TYPE_MC88000 = 13; + public final static int CPU_TYPE_SPARC = 14; + public final static int CPU_TYPE_I860 = 15; + public final static int CPU_TYPE_POWERPC = 18; + + /* values of cpusubtype */ + public final static int CPU_SUBTYPE_MULTIPLE = -1; + public final static int CPU_SUBTYPE_LITTLE_ENDIAN = 0; + public final static int CPU_SUBTYPE_BIG_ENDIAN = 1; + public final static int CPU_SUBTYPE_VAX_ALL = 0; + public final static int CPU_SUBTYPE_VAX780 = 1; + public final static int CPU_SUBTYPE_VAX785 = 2; + public final static int CPU_SUBTYPE_VAX750 = 3; + public final static int CPU_SUBTYPE_VAX730 = 4; + public final static int CPU_SUBTYPE_UVAXI = 5; + public final static int CPU_SUBTYPE_UVAXII = 6; + public final static int CPU_SUBTYPE_VAX8200 = 7; + public final static int CPU_SUBTYPE_VAX8500 = 8; + public final static int CPU_SUBTYPE_VAX8600 = 9; + public final static int CPU_SUBTYPE_VAX8650 = 10; + public final static int CPU_SUBTYPE_VAX8800 = 11; + public final static int CPU_SUBTYPE_UVAXIII = 12; + public final static int CPU_SUBTYPE_MC680x0_ALL = 1; + public final static int CPU_SUBTYPE_MC68030 = 1; + public final static int CPU_SUBTYPE_MC68040 = 2; + public final static int CPU_SUBTYPE_MC68030_ONLY = 3; + public final static int CPU_SUBTYPE_I386_ALL = 3; + public final static int CPU_SUBTYPE_386 = 3; + public final static int CPU_SUBTYPE_486 = 4; + public final static int CPU_SUBTYPE_486SX = 132; + public final static int CPU_SUBTYPE_586 = 5; + public final static int CPU_SUBTYPE_PENT = 5; + public final static int CPU_SUBTYPE_PENTPRO = 32; + public final static int CPU_SUBTYPE_PENTII_M3 = 54; + public final static int CPU_SUBTYPE_PENTII_M5 = 86; + public final static int CPU_SUBTYPE_MIPS_ALL = 0; + public final static int CPU_SUBTYPE_MIPS_R2300 = 1; + public final static int CPU_SUBTYPE_MIPS_R2600 = 2; + public final static int CPU_SUBTYPE_MIPS_R2800 = 3; + public final static int CPU_SUBTYPE_MIPS_R2000a = 4; + public final static int CPU_SUBTYPE_MIPS_R2000 = 5; + public final static int CPU_SUBTYPE_MIPS_R3000a = 6; + public final static int CPU_SUBTYPE_MIPS_R3000 = 7; + public final static int CPU_SUBTYPE_MC98000_ALL = 0; + public final static int CPU_SUBTYPE_MC98601 = 1; + public final static int CPU_SUBTYPE_HPPA_ALL = 0; + public final static int CPU_SUBTYPE_HPPA_7100 = 0; + public final static int CPU_SUBTYPE_HPPA_7100LC = 1; + public final static int CPU_SUBTYPE_MC88000_ALL = 0; + public final static int CPU_SUBTYPE_MC88100 = 1; + public final static int CPU_SUBTYPE_MC88110 = 2; + public final static int CPU_SUBTYPE_SPARC_ALL = 0; + public final static int CPU_SUBTYPE_I860_ALL = 0; + public final static int CPU_SUBTYPE_I860_860 = 1; + public final static int CPU_SUBTYPE_POWERPC_ALL = 0; + public final static int CPU_SUBTYPE_POWERPC_601 = 1; + public final static int CPU_SUBTYPE_POWERPC_602 = 2; + public final static int CPU_SUBTYPE_POWERPC_603 = 3; + public final static int CPU_SUBTYPE_POWERPC_603e = 4; + public final static int CPU_SUBTYPE_POWERPC_603ev = 5; + public final static int CPU_SUBTYPE_POWERPC_604 = 6; + public final static int CPU_SUBTYPE_POWERPC_604e = 7; + public final static int CPU_SUBTYPE_POWERPC_620 = 8; + public final static int CPU_SUBTYPE_POWERPC_750 = 9; + public final static int CPU_SUBTYPE_POWERPC_7400 = 10; + public final static int CPU_SUBTYPE_POWERPC_7450 = 11; + public final static int CPU_SUBTYPE_POWERPC_970 = 100; + + /* values of filetype */ + public final static int MH_OBJECT = 0x1; /* relocatable object file */ + public final static int MH_EXECUTE = 0x2; /* demand paged executable file */ + public final static int MH_FVMLIB = 0x3; /* fixed VM shared library file */ + public final static int MH_CORE = 0x4; /* core file */ + public final static int MH_PRELOAD = 0x5; /* preloaded executable file */ + public final static int MH_DYLIB = 0x6; /* dynamically bound shared library */ + public final static int MH_DYLINKER = 0x7; /* dynamic link editor */ + public final static int MH_BUNDLE = 0x8; /* dynamically bound bundle file */ + public final static int MH_DYLIB_STUB = 0x9; /* shared library stub for static linking only, no section contents */ + + /* values of flags */ + public final static int MH_NOUNDEFS = 0x1; /* the object file has no undefined references */ + public final static int MH_INCRLINK = 0x2; /* the object file is the output of an incremental link against a base file and can't be link edited again */ + public final static int MH_DYLDLINK = 0x4; /* the object file is input for the dynamic linker and can't be staticly link edited again */ + public final static int MH_BINDATLOAD = 0x8; /* the object file's undefined references are bound by the dynamic linker when loaded. */ + public final static int MH_PREBOUND = 0x10; /* the file has its dynamic undefined references prebound. */ + public final static int MH_SPLIT_SEGS = 0x20; /* the file has its read-only and read-write segments split */ + public final static int MH_LAZY_INIT = 0x40; /* the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete) */ + public final static int MH_TWOLEVEL = 0x80; /* the image is using two-level name space bindings */ + public final static int MH_FORCE_FLAT = 0x100; /* the executable is forcing all images to use flat name space bindings */ + public final static int MH_NOMULTIDEFS = 0x200; /* this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used. */ + public final static int MH_NOFIXPREBINDING = 0x400; /* do not have dyld notify the prebinding agent about this executable */ + + public int magic; /* mach magic number identifier */ + public int cputype; /* cpu specifier */ + public int cpusubtype; /* machine specifier */ + public int filetype; /* type of file */ + public int ncmds; /* number of load commands */ + public int sizeofcmds; /* the size of all the load commands */ + public int flags; /* flags */ + + protected MachOhdr() throws IOException { + efile.seek(0); + efile.setEndian(false); + magic = efile.readIntE(); + if ( magic == MH_CIGAM ) + efile.setEndian(true); + else + if ( magic == MH_UNIVERSAL) + { + String arch = System.getProperty("os.arch"); //$NON-NLS-1$ + int numArchives = efile.readIntE(); + while (numArchives-- > 0) + { + int cpuType = efile.readIntE(); // cpuType + efile.readIntE(); // cpuSubType + int archiveOffset = efile.readIntE(); // archiveOffset + efile.readIntE(); // archiveSize + efile.readIntE(); // archiveAlignment + if ((cpuType == MachO.MachOhdr.CPU_TYPE_I386 && arch.equalsIgnoreCase("i386")) || //$NON-NLS-1$ + (cpuType == MachO.MachOhdr.CPU_TYPE_POWERPC && arch.equalsIgnoreCase("ppc"))) //$NON-NLS-1$ + { + efile.seek(archiveOffset); + magic = efile.readIntE(); + if ( magic == MH_CIGAM ) + efile.setEndian(true); + else if ( magic != MH_MAGIC ) + throw new IOException(CCorePlugin.getResourceString("Util.exception.notMACHO")); //$NON-NLS-1$ + break; + } + } + } + else if ( magic != MH_MAGIC ) + throw new IOException(CCorePlugin.getResourceString("Util.exception.notMACHO")); //$NON-NLS-1$ + cputype = efile.readIntE(); + cpusubtype = efile.readIntE(); + filetype = efile.readIntE(); + ncmds = efile.readIntE(); + sizeofcmds = efile.readIntE(); + flags = efile.readIntE(); + } + + protected MachOhdr(byte [] bytes) throws IOException { + boolean isle = false; + int offset = 0; + magic = makeInt(bytes, offset, isle); offset += 4; + if ( magic == MH_CIGAM ) + isle = true; + else + if ( magic == MH_UNIVERSAL) + { + String arch = System.getProperty("os.arch"); //$NON-NLS-1$ + int numArchives = makeInt(bytes, offset, isle); offset += 4; + while (numArchives-- > 0) + { + int cpuType = makeInt(bytes, offset, isle); offset += 4; + offset += 4; // cpuSubType + int archiveOffset = makeInt(bytes, offset, isle); offset += 4; + offset += 4; // archiveSize + offset += 4; // archiveAlignment + if ((cpuType == MachO.MachOhdr.CPU_TYPE_I386 && arch.equalsIgnoreCase("i386")) || //$NON-NLS-1$ + (cpuType == MachO.MachOhdr.CPU_TYPE_POWERPC && arch.equalsIgnoreCase("ppc"))) //$NON-NLS-1$ + { + offset = archiveOffset; + magic = makeInt(bytes, offset, isle); offset += 4; + if ( magic == MH_CIGAM ) + isle = true; + else if ( magic != MH_MAGIC ) + throw new IOException(CCorePlugin.getResourceString("Util.exception.notMACHO")); //$NON-NLS-1$ + break; + } + } + } + else if ( magic != MH_MAGIC ) + throw new IOException(CCorePlugin.getResourceString("Util.exception.notMACHO")); //$NON-NLS-1$ + cputype = makeInt(bytes, offset, isle); offset += 4; + cpusubtype = makeInt(bytes, offset, isle); offset += 4; + filetype = makeInt(bytes, offset, isle); offset += 4; + ncmds = makeInt(bytes, offset, isle); offset += 4; + sizeofcmds = makeInt(bytes, offset, isle); offset += 4; + flags = makeInt(bytes, offset, isle); offset += 4; + } + } + + private static final int makeInt(byte [] val, int offset, boolean isle) throws IOException + { + if (val.length < offset + 4) + throw new IOException(); + if ( isle ) { + return (((val[offset + 3] & 0xff) << 24) | + ((val[offset + 2] & 0xff) << 16) | + ((val[offset + 1] & 0xff) << 8) | + (val[offset + 0] & 0xff)); + } else { + return (((val[offset + 0] & 0xff) << 24) | + ((val[offset + 1] & 0xff) << 16) | + ((val[offset + 2] & 0xff) << 8) | + (val[offset + 3] & 0xff)); + } + } + + public class LoadCommand { + public final static int LC_REQ_DYLD = 0x80000000; + + /* values of cmd */ + public final static int LC_SEGMENT = 0x1; /* segment of this file to be mapped */ + public final static int LC_SYMTAB = 0x2; /* link-edit stab symbol table info */ + public final static int LC_SYMSEG = 0x3; /* link-edit gdb symbol table info (obsolete) */ + public final static int LC_THREAD = 0x4; /* thread */ + public final static int LC_UNIXTHREAD = 0x5; /* unix thread (includes a stack) */ + public final static int LC_LOADFVMLIB = 0x6; /* load a specified fixed VM shared library */ + public final static int LC_IDFVMLIB = 0x7; /* fixed VM shared library identification */ + public final static int LC_IDENT = 0x8; /* object identification info (obsolete) */ + public final static int LC_FVMFILE = 0x9; /* fixed VM file inclusion (internal use) */ + public final static int LC_PREPAGE = 0xa; /* prepage command (internal use) */ + public final static int LC_DYSYMTAB = 0xb; /* dynamic link-edit symbol table info */ + public final static int LC_LOAD_DYLIB = 0xc; /* load a dynamically linked shared library */ + public final static int LC_ID_DYLIB = 0xd; /* dynamically linked shared lib ident */ + public final static int LC_LOAD_DYLINKER = 0xe; /* load a dynamic linker */ + public final static int LC_ID_DYLINKER = 0xf; /* dynamic linker identification */ + public final static int LC_PREBOUND_DYLIB = 0x10; /* modules prebound for a dynamically linked shared library */ + public final static int LC_ROUTINES = 0x11; /* image routines */ + public final static int LC_SUB_FRAMEWORK = 0x12; /* sub framework */ + public final static int LC_SUB_UMBRELLA = 0x13; /* sub umbrella */ + public final static int LC_SUB_CLIENT = 0x14; /* sub client */ + public final static int LC_SUB_LIBRARY = 0x15; /* sub library */ + public final static int LC_TWOLEVEL_HINTS = 0x16; /* two-level namespace lookup hints */ + public final static int LC_PREBIND_CKSUM = 0x17; /* prebind checksum */ + /* + * load a dynamically linked shared library that is allowed to be missing + * (all symbols are weak imported). + */ + public final static int LC_LOAD_WEAK_DYLIB = (0x18 | LC_REQ_DYLD); + + public int cmd; + public int cmdsize; + } + + public class UnknownCommand extends LoadCommand { + } + + public class LCStr { + public long offset; + public long ptr; + } + + public class SegmentCommand extends LoadCommand { + /* values of flags */ + public final static long SG_HIGHVM = 0x1; + public final static long SG_FVMLIB = 0x2; + public final static long SG_NORELOC = 0x4; + + /* VM protection values */ + public final static int VM_PROT_NONE = 0x00; + public final static int VM_PROT_READ = 0x01; /* read permission */ + public final static int VM_PROT_WRITE = 0x02; /* write permission */ + public final static int VM_PROT_EXECUTE = 0x04; /* execute permission */ + public final static int VM_PROT_DEFAULT = (VM_PROT_READ|VM_PROT_WRITE); + public final static int VM_PROT_ALL = (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); + public final static int VM_PROT_NO_CHANGE = 0x08; + public final static int VM_PROT_COPY = 0x10; + public final static int VM_PROT_WANTS_COPY = 0x10; + + public String segname; /* segment name */ + public int vmaddr; /* memory address of this segment */ + public int vmsize; /* memory size of this segment */ + public int fileoff; /* file offset of this segment */ + public int filesize; /* amount to map from the file */ + public int maxprot; /* maximum VM protection */ + public int initprot; /* initial VM protection */ + public int nsects; /* number of sections in segment */ + public int flags; /* flags */ + + public boolean prot(int val) { + return (initprot & val) == val; + } + } + + public class Section { + + public final static int SECTION_TYP = 0x000000ff; /* 256 section types */ + public final static int SECTION_ATTRIBUTES = 0xffffff00; /* 24 section attributes */ + public final static int SECTION_ATTRIBUTES_USR =0xff000000; /* User setable attributes */ + + /* values of flags */ + public final static int S_REGULAR = 0x0; /* regular section */ + public final static int S_ZEROFILL = 0x1; /* zero fill on demand section */ + public final static int S_CSTRING_LITERALS = 0x2; /* section with only literal C strings*/ + public final static int S_4BYTE_LITERALS = 0x3; /* section with only 4 byte literals */ + public final static int S_8BYTE_LITERALS = 0x4; /* section with only 8 byte literals */ + public final static int S_LITERAL_POINTERS = 0x5; /* section with only pointers to literals */ + public final static int S_NON_LAZY_SYMBOL_POINTERS = 0x6; /* section with only non-lazy symbol pointers */ + public final static int S_LAZY_SYMBOL_POINTERS = 0x7; /* section with only lazy symbol pointers */ + public final static int S_SYMBOL_STUBS = 0x8; /* section with only symbol stubs, byte size of stub in the reserved2 field */ + public final static int S_MOD_INIT_FUNC_POINTERS = 0x9; /* section with only function pointers for initialization*/ + public final static int S_MOD_TERM_FUNC_POINTERS = 0xa; /* section with only function pointers for termination */ + public final static int S_COALESCED = 0xb; /* section contains symbols that are to be coalesced */ + public final static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000; /* section contains only true machine instructions */ + public final static int S_ATTR_NO_TOC = 0x40000000; /* section contains coalesced symbols that are not to be in a ranlib table of contents */ + public final static int S_ATTR_STRIP_STATIC_SYMS = 0x20000000; /* ok to strip static symbols in this section in files with the MH_DYLDLINK flag */ + public final static int SECTION_ATTRIBUTES_SYS = 0x00ffff00; /* system setable attributes */ + public final static int S_ATTR_SOME_INSTRUCTIONS = 0x00000400; /* section contains some machine instructions */ + public final static int S_ATTR_EXT_RELOC = 0x00000200; /* section has external relocation entries */ + public final static int S_ATTR_LOC_RELOC = 0x00000100; /* section has local relocation entries */ + + public String sectname; /* name of this section */ + public String segname; /* name segment this section goes in */ + public SegmentCommand segment; /* segment this section goes in */ + public int addr; /* memory address of this section */ + public int size; /* size in bytes of this section */ + public int offset; /* file offset of this section */ + public int align; /* section alignment (power of 2) */ + public int reloff; /* file offset of relocation entries */ + public int nreloc; /* number of relocation entries */ + public int flags; /* flags (section type and attributes)*/ + public int reserved1; /* reserved */ + public int reserved2; /* reserved */ + + public int flags(int mask) { + return flags & mask; + } + } + + public class FVMLib { + public int name; /* library's target pathname */ + public int minor_version; /* library's minor version number */ + public int header_addr; /* library's header address */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class FVMLibCommand extends LoadCommand { + public FVMLib fvmlib; /* the library identification */ + } + + public class DyLib { + public int name; /* library's path name */ + public int timestamp; /* library's build time stamp */ + public int current_version; /* library's current version number */ + public int compatibility_version; /* library's compatibility vers number*/ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class DyLibCommand extends LoadCommand { + public DyLib dylib; /* the library identification */ + } + + public class SubFrameworkCommand extends LoadCommand { + public int umbrella; /* the umbrella framework name */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class SubClientCommand extends LoadCommand { + public int client; /* the client name */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class SubUmbrellaCommand extends LoadCommand { + public int sub_umbrella; /* the sub_umbrella framework name */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class SubLibraryCommand extends LoadCommand { + public int sub_library; /* the sub_library name */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class PreboundDyLibCommand extends LoadCommand { + public int name; /* library's path name */ + public int nmodules; /* number of modules in library */ + public int linked_modules; /* bit vector of linked modules */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class DyLinkerCommand extends LoadCommand { + public int name; /* dynamic linker's path name */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + public class ThreadCommand extends LoadCommand { + } + + public class RoutinesCommand extends LoadCommand { + public int init_address; /* address of initialization routine */ + public int init_module; /* index into the module table that the init routine is defined in */ + public int reserved1; + public int reserved2; + public int reserved3; + public int reserved4; + public int reserved5; + public int reserved6; + } + + public class SymtabCommand extends LoadCommand { + public int symoff; /* symbol table offset */ + public int nsyms; /* number of symbol table entries */ + public int stroff; /* string table offset */ + public int strsize; /* string table size in bytes */ + } + + public class DySymtabCommand extends LoadCommand { + public int ilocalsym; /* index to local symbols */ + public int nlocalsym; /* number of local symbols */ + public int iextdefsym; /* index to externally defined symbols */ + public int nextdefsym; /* number of externally defined symbols */ + public int iundefsym; /* index to undefined symbols */ + public int nundefsym; /* number of undefined symbols */ + public int tocoff; /* file offset to table of contents */ + public int ntoc; /* number of entries in table of contents */ + public int modtaboff; /* file offset to module table */ + public int nmodtab; /* number of module table entries */ + public int extrefsymoff; /* offset to referenced symbol table */ + public int nextrefsyms; /* number of referenced symbol table entries */ + public int indirectsymoff; /* file offset to the indirect symbol table */ + public int nindirectsyms; /* number of indirect symbol table entries */ + public int extreloff; /* offset to external relocation entries */ + public int nextrel; /* number of external relocation entries */ + public int locreloff; /* offset to local relocation entries */ + public int nlocrel; /* number of local relocation entries */ + } + + public class DyLibTableOfContents { + public final static int INDIRECT_SYMBOL_LOCAL = 0x80000000; + public final static int INDIRECT_SYMBOL_ABS = 0x40000000; + public int symbol_index; /* the defined external symbol (index into the symbol table) */ + public int module_index; /* index into the module table this symbol is defined in */ + } + + public class DyLibModule { + public int module_name; /* the module name (index into string table) */ + public int iextdefsym; /* index into externally defined symbols */ + public int nextdefsym; /* number of externally defined symbols */ + public int irefsym; /* index into reference symbol table */ + public int nrefsym; /* number of reference symbol table entries */ + public int ilocalsym; /* index into symbols for local symbols */ + public int nlocalsym; /* number of local symbols */ + public int iextrel; /* index into external relocation entries */ + public int nextrel; /* number of external relocation entries */ + public int iinit_iterm; /* low 16 bits are the index into the init section, high 16 bits are the index into the term section */ + public int ninit_nterm; /* low 16 bits are the number of init section entries, high 16 bits are the number of term section entries */ + public int objc_module_info_addr; /* for this module address of the start of the (__OBJC,__module_info) section */ + public int objc_module_info_size; /* for this module size of the (__OBJC,__module_info) section */ + } + + public class DyLibReference { + public int isym; /* index into the symbol table */ + public int flags; /* flags to indicate the type of reference */ + } + + public class TwoLevelHintsCommand extends LoadCommand { + public int offset; /* offset to the hint table */ + public int nhints; /* number of hints in the hint table */ + public TwoLevelHint[] hints; + } + + public class TwoLevelHint { + public int isub_image; /* index into the sub images */ + public int itoc; /* index into the table of contents */ + } + + public class PrebindCksumCommand extends LoadCommand { + public int cksum; /* the check sum or zero */ + } + + public class SymSegCommand extends LoadCommand { + public int offset; /* symbol segment offset */ + public int size; /* symbol segment size in bytes */ + } + + public class IdentCommand extends LoadCommand { + } + + public class FVMFileCommand extends LoadCommand { + public int name; /* files pathname */ + public int header_addr; /* files virtual address */ + public String lc_str_name = null; + + @Override + public String toString() { + if ( lc_str_name == null ) { + return EMPTY_STRING; + } + return lc_str_name; + } + } + + private void commonSetup( String file, long offset, boolean filton ) + throws IOException + { + this.cppFiltEnabled = filton; + + try { + efile = new ERandomAccessFile(file, "r"); //$NON-NLS-1$ + efile.setFileOffset( offset ); + mhdr = new MachOhdr(); + this.file = file; + } finally { + if ( mhdr == null ) { + dispose(); + } + } + } + + protected String string_from_macho_symtab(MachO.SymtabCommand symtab, int index) throws IOException { + if ( index > symtab.strsize ) { + return EMPTY_STRING; + } + efile.seek(symtab.stroff + index); + return getCStr(); + } + + public class Symbol implements Comparable { + /* n_type bit masks */ + public final static int N_STAB = 0xe0; + public final static int N_PEXT = 0x10; + public final static int N_EXT = 0x01; + public final static int N_TYPE = 0x0e; /* type mask */ + /* Values of N_TYPE bits */ + public final static int N_UNDF = 0x0; + public final static int N_ABS = 0x2; + public final static int N_SECT = 0xe; + public final static int N_PBUD = 0xc; + public final static int N_INDR = 0xa; + /* Values of n_type if N_STAB bits are set (stabs) */ + public final static int N_GSYM = 0x20; /* global symbol: name,,NO_SECT,type,0 */ + public final static int N_FNAME = 0x22; /* procedure name (f77 kludge): name,,NO_SECT,0,0 */ + public final static int N_FUN = 0x24; /* procedure: name,,n_sect,linenumber,address */ + public final static int N_STSYM = 0x26; /* static symbol: name,,n_sect,type,address */ + public final static int N_LCSYM = 0x28; /* .lcomm symbol: name,,n_sect,type,address */ + public final static int N_BNSYM = 0x2e; /* begin nsect sym: 0,,n_sect,0,address */ + public final static int N_OPT = 0x3c; /* emitted with gcc2_compiled and in gcc source */ + public final static int N_RSYM = 0x40; /* register sym: name,,NO_SECT,type,register */ + public final static int N_SLINE = 0x44; /* src line: 0,,n_sect,linenumber,address */ + public final static int N_ENSYM = 0x4e; /* end nsect sym: 0,,n_sect,0,address */ + public final static int N_SSYM = 0x60; /* structure elt: name,,NO_SECT,type,struct_offset */ + public final static int N_SO = 0x64; /* source file name: name,,n_sect,0,address */ + public final static int N_LSYM = 0x80; /* local sym: name,,NO_SECT,type,offset */ + public final static int N_BINCL = 0x82; /* include file beginning: name,,NO_SECT,0,sum */ + public final static int N_SOL = 0x84; /* #included file name: name,,n_sect,0,address */ + public final static int N_PARAMS = 0x86; /* compiler parameters: name,,NO_SECT,0,0 */ + public final static int N_VERSION = 0x88; /* compiler version: name,,NO_SECT,0,0 */ + public final static int N_OLEVEL = 0x8A; /* compiler -O level: name,,NO_SECT,0,0 */ + public final static int N_PSYM = 0xa0; /* parameter: name,,NO_SECT,type,offset */ + public final static int N_EINCL = 0xa2; /* include file end: name,,NO_SECT,0,0 */ + public final static int N_ENTRY = 0xa4; /* alternate entry: name,,n_sect,linenumber,address */ + public final static int N_LBRAC = 0xc0; /* left bracket: 0,,NO_SECT,nesting level,address */ + public final static int N_EXCL = 0xc2; /* deleted include file: name,,NO_SECT,0,sum */ + public final static int N_RBRAC = 0xe0; /* right bracket: 0,,NO_SECT,nesting level,address */ + public final static int N_BCOMM = 0xe2; /* begin common: name,,NO_SECT,0,0 */ + public final static int N_ECOMM = 0xe4; /* end common: name,,n_sect,0,0 */ + public final static int N_ECOML = 0xe8; /* end common (local name): 0,,n_sect,0,address */ + public final static int N_LENG = 0xfe; /* second stab entry with length information */ + /* Values of n_sect */ + public final static int NO_SECT = 0; + public final static int MAX_SECT = 255; + /* Values of n_desc */ + public final static int REFERENCE_TYPE = 0xf; /* reference type mask */ + public final static int REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0x0; + public final static int REFERENCE_FLAG_UNDEFINED_LAZY = 0x1; + public final static int REFERENCE_FLAG_DEFINED = 0x2; + public final static int REFERENCE_FLAG_PRIVATE_DEFINED = 0x3; + public final static int REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 0x4; + public final static int REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 0x5; + public final static int REFERENCED_DYNAMICALLY = 0x10; + public final static int N_DESC_DISCARDED = 0x20; + public final static int N_WEAK_REF = 0x40; + public final static int N_WEAK_DEF = 0x80; + + public long n_strx; + public long n_value; + public short n_desc; + public byte n_type; + public byte n_sect; + + private String name = null; /* symbol name */ + private Line line = null; /* symbol line information */ + + private String cppFilt(String in) { + if (cppFiltEnabled) { + try { + if (in.indexOf("__") != -1 || in.indexOf("_._") != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + if (cppFilt == null) { + cppFilt = new CPPFilt(); + } + return cppFilt.getFunction(in); + } + } catch (IOException e) { + return in; + } + } + return in; + } + + public Symbol() { + } + + public boolean n_type_mask(int mask) { + return (n_type & mask) != 0; + } + + public boolean n_type(int val) { + return (n_type & N_TYPE) == val; + } + + public boolean n_desc(int val) { + return (n_type & REFERENCE_TYPE) == val; + } + + public int compareTo(Object obj) { + long thisVal = 0; + long anotherVal = 0; + if ( obj instanceof Symbol ) { + Symbol sym = (Symbol)obj; + thisVal = this.n_value; + anotherVal = sym.n_value; + } else if ( obj instanceof Long ) { + Long val = (Long)obj; + anotherVal = val.longValue(); + thisVal = this.n_value; + } + return (thisVal= 0 ) + return lines[ndx]; + if ( ndx == -1 ) { + return null; + } + ndx = -ndx - 1; + for (int l = ndx - 1; l < lines.length; l++) { + Line line = lines[l]; + if (value <= line.address) + return line; + } + return null; + } + + /** + * 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. + */ + public static class SymbolComparator implements Comparator { + long val1, val2; + public int compare(Object o1, Object o2) { + + if(o1 instanceof Long) { + val1 = ((Long)o1).longValue(); + } else if(o1 instanceof Symbol) { + val1 = ((Symbol)o1).n_value; + } else { + return -1; + } + + if(o2 instanceof Long) { + val2 = ((Long)o2).longValue(); + } else if(o2 instanceof Symbol) { + val2 = ((Symbol)o2).n_value; + } else { + return -1; + } + return (val1 == val2) ? 0 + : ((val1 < val2) ? -1 : 1); + } + } + + /** + * Simple class to implement a line table + */ + public static class Line implements Comparable { + public long address; + public int lineno; + public String file; + public String function; + + public int compareTo(Object obj) { + long thisVal = 0; + long anotherVal = 0; + if ( obj instanceof Line ) { + Line l = (Line)obj; + thisVal = this.address; + anotherVal = l.address; + } else if ( obj instanceof Long ) { + Long val = (Long)obj; + anotherVal = val.longValue(); + thisVal = this.address; + } + return (thisVal symList = new ArrayList(symtab.nsyms); + for (int s = 0; s < symtab.nsyms; s++) { + Symbol symbol = new Symbol(); + symbol.n_strx = efile.readIntE(); + symbol.n_type = (byte)efile.readUnsignedByte(); + symbol.n_sect = (byte)efile.readUnsignedByte(); + symbol.n_desc = efile.readShortE(); + symbol.n_value = efile.readIntE(); + symList.add(symbol); + if ((symbol.n_type & Symbol.N_STAB) != 0) { + debugsym = true; + } + } + symbols = symList.toArray(new Symbol[0]); + break; + + case LoadCommand.LC_DYSYMTAB: + dysymtab = (DySymtabCommand)loadcommand; + break; + } + } + if (dysymtab != null) { + ArrayList symList = new ArrayList(dysymtab.nlocalsym); + for (int s = dysymtab.ilocalsym; s < dysymtab.nlocalsym; s++) { + symList.add(symbols[s]); + } + local_symbols = symList.toArray(new Symbol[0]); + } + } + + private void loadLineTable() { + if (symbols == null) { + return; + } + /* count number of source line entries */ + int nlines = 0; + for (Symbol symbol : symbols) { + if (symbol.n_type == Symbol.N_SLINE || symbol.n_type == Symbol.N_FUN) { + nlines++; + } + } + if (nlines == 0) { + return; + } + + /* now create line table, sorted on address */ + Map lineList = new HashMap(nlines); + for (Symbol sym : symbols) { + if (sym.n_type == Symbol.N_SLINE || sym.n_type == Symbol.N_FUN) { + Line lentry = new Line(); + lentry.address = sym.n_value; + lentry.lineno = sym.n_desc; + + Line lookup = lineList.get(lentry); + if (lookup != null) { + lentry = lookup; + } else { + lineList.put(lentry, lentry); + } + + if (lentry.function == null && sym.n_type == Symbol.N_FUN) { + String func = sym.toString(); + if (func != null && func.length() > 0) { + int colon = func.indexOf(':'); + if (colon > 0) + lentry.function = func.substring(0, colon); + else + lentry.function = func; + } else { + lentry.function = EMPTY_STRING; + } + } + } + } + Set k = lineList.keySet(); + lines = k.toArray(new Line[k.size()]); + Arrays.sort(lines); + + /* now check for file names */ + for (Symbol sym : symbols) { + if (sym.n_type == Symbol.N_SO) { + Line line = getLine(sym.n_value); + if (line != null) { + line.file = sym.toString(); + } + } + } + + } + + private ArrayList
getSections(SegmentCommand seg) throws IOException { + if ( seg.nsects == 0 ) { + return new ArrayList
(); + } + ArrayList
sections = new ArrayList
(); + for ( int i = 0; i < seg.nsects; i++ ) { + Section section = new Section(); + byte[] sectname = new byte[16]; + byte[] segname = new byte[16]; + efile.readFully(sectname); + section.sectname = new String(sectname, 0, 16); + efile.readFully(segname); + section.segment = seg; + section.segname = new String(segname, 0, 16); + section.addr = efile.readIntE(); + section.size = efile.readIntE(); + section.offset = efile.readIntE(); + section.align = efile.readIntE(); + section.reloff = efile.readIntE(); + section.nreloc = efile.readIntE(); + section.flags = efile.readIntE(); + section.reserved1 = efile.readIntE(); + section.reserved2 = efile.readIntE(); + sections.add(section); + } + return sections; + } + +// private TwoLevelHint[] getTwoLevelHints(int nhints) throws IOException { +// if ( nhints == 0 ) { +// return new TwoLevelHint[0]; +// } +// TwoLevelHint[] tlhints = new TwoLevelHint[nhints]; +// for ( int i = 0; i < nhints; i++ ) { +// int field = efile.readIntE(); +// tlhints[i] = new TwoLevelHint(); +// tlhints[i].isub_image = (field & 0xff000000) >> 24; +// tlhints[i].itoc = field & 0x00ffffff; +// } +// return tlhints; +// } + + private String getCStr() throws IOException { + StringBuffer str = new StringBuffer(); + while( true ) { + byte tmp = efile.readByte(); + if (tmp == 0) + break; + str.append((char)tmp); + } + return str.toString(); + } + + private String getLCStr(int len) throws IOException { + if (len == 0) + return EMPTY_STRING; + StringBuffer str = new StringBuffer(); + for (; len > 0; len--) { + byte tmp = efile.readByte(); + if (tmp == 0) + break; + str.append((char)tmp); + } + return str.toString(); + } + + private void loadLoadCommands() throws IOException { + if ( loadcommands == null ) { + if ( mhdr.ncmds == 0 ) { + loadcommands = new LoadCommand[0]; + return; + } + loadcommands = new LoadCommand[mhdr.ncmds]; + for ( int i = 0; i < mhdr.ncmds; i++ ) { + int cmd = efile.readIntE(); + int len; + switch (cmd) { + case LoadCommand.LC_SEGMENT: + SegmentCommand seg = new SegmentCommand(); + byte[] segname = new byte[16]; + seg.cmd = cmd; + seg.cmdsize = efile.readIntE(); + efile.readFully(segname); + seg.segname = new String(segname, 0, 16); + seg.vmaddr = efile.readIntE(); + seg.vmsize = efile.readIntE(); + seg.fileoff = efile.readIntE(); + seg.filesize = efile.readIntE(); + seg.maxprot = efile.readIntE(); + seg.initprot = efile.readIntE(); + seg.nsects = efile.readIntE(); + seg.flags = efile.readIntE(); + sections.addAll(getSections(seg)); + loadcommands[i] = seg; + break; + + case LoadCommand.LC_SYMTAB: + SymtabCommand stcmd = new SymtabCommand(); + stcmd.cmd = cmd; + stcmd.cmdsize = efile.readIntE(); + stcmd.symoff = efile.readIntE(); + stcmd.nsyms = efile.readIntE(); + stcmd.stroff = efile.readIntE(); + stcmd.strsize = efile.readIntE(); + loadcommands[i] = stcmd; + break; + + case LoadCommand.LC_SYMSEG: + SymSegCommand sscmd = new SymSegCommand(); + sscmd.cmd = cmd; + sscmd.cmdsize = efile.readIntE(); + sscmd.offset = efile.readIntE(); + sscmd.size = efile.readIntE(); + loadcommands[i] = sscmd; + break; + + case LoadCommand.LC_THREAD: + case LoadCommand.LC_UNIXTHREAD: + ThreadCommand thcmd = new ThreadCommand(); + thcmd.cmd = cmd; + thcmd.cmdsize = efile.readIntE(); + efile.skipBytes(thcmd.cmdsize - 8 /* sizeof(ThreadCommand) */); + loadcommands[i] = thcmd; + break; + + case LoadCommand.LC_LOADFVMLIB: + case LoadCommand.LC_IDFVMLIB: + FVMLibCommand fvmcmd = new FVMLibCommand(); + fvmcmd.cmd = cmd; + fvmcmd.cmdsize = efile.readIntE(); + fvmcmd.fvmlib = new FVMLib(); + fvmcmd.fvmlib.name = efile.readIntE(); + fvmcmd.fvmlib.minor_version = efile.readIntE(); + fvmcmd.fvmlib.header_addr = efile.readIntE(); + len = fvmcmd.cmdsize - 20 /* sizeof FVMLibCommand */; + fvmcmd.fvmlib.lc_str_name = getLCStr(len); + len -= fvmcmd.fvmlib.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = fvmcmd; + break; + + case LoadCommand.LC_IDENT: + IdentCommand icmd = new IdentCommand(); + icmd.cmd = cmd; + icmd.cmdsize = efile.readIntE(); + loadcommands[i] = icmd; + break; + + case LoadCommand.LC_FVMFILE: + FVMFileCommand fcmd = new FVMFileCommand(); + fcmd.cmd = cmd; + fcmd.cmdsize = efile.readIntE(); + fcmd.name = efile.readIntE(); + fcmd.header_addr = efile.readIntE(); + len = fcmd.cmdsize - 16 /* sizeof FVMFileCommand */; + fcmd.lc_str_name = getLCStr(len); + len -= fcmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = fcmd; + break; + + case LoadCommand.LC_DYSYMTAB: + DySymtabCommand dscmd = new DySymtabCommand(); + dscmd.cmd = cmd; + dscmd.cmdsize = efile.readIntE(); + dscmd.ilocalsym = efile.readIntE(); + dscmd.nlocalsym = efile.readIntE(); + dscmd.iextdefsym = efile.readIntE(); + dscmd.nextdefsym = efile.readIntE(); + dscmd.iundefsym = efile.readIntE(); + dscmd.nundefsym = efile.readIntE(); + dscmd.tocoff = efile.readIntE(); + dscmd.ntoc = efile.readIntE(); + dscmd.modtaboff = efile.readIntE(); + dscmd.nmodtab = efile.readIntE(); + dscmd.extrefsymoff = efile.readIntE(); + dscmd.nextrefsyms = efile.readIntE(); + dscmd.indirectsymoff = efile.readIntE(); + dscmd.nindirectsyms = efile.readIntE(); + dscmd.extreloff = efile.readIntE(); + dscmd.nextrel = efile.readIntE(); + dscmd.locreloff = efile.readIntE(); + dscmd.nlocrel = efile.readIntE(); + loadcommands[i] = dscmd; + dynsym = true; + break; + + case LoadCommand.LC_LOAD_DYLIB: + case LoadCommand.LC_ID_DYLIB: + case LoadCommand.LC_LOAD_WEAK_DYLIB: + DyLibCommand dylcmd = new DyLibCommand(); + dylcmd.cmd = cmd; + dylcmd.cmdsize = efile.readIntE(); + dylcmd.dylib = new DyLib(); + dylcmd.dylib.name = efile.readIntE(); + dylcmd.dylib.timestamp = efile.readIntE(); + dylcmd.dylib.current_version = efile.readIntE(); + dylcmd.dylib.compatibility_version = efile.readIntE(); + len = dylcmd.cmdsize - 24 /* sizeof DyLibCommand */; + dylcmd.dylib.lc_str_name = getLCStr(len); + len -= dylcmd.dylib.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = dylcmd; + break; + + case LoadCommand.LC_LOAD_DYLINKER: + case LoadCommand.LC_ID_DYLINKER: + DyLinkerCommand dylkcmd = new DyLinkerCommand(); + dylkcmd.cmd = cmd; + dylkcmd.cmdsize = efile.readIntE(); + dylkcmd.name = efile.readIntE(); + len = dylkcmd.cmdsize - 12 /* sizeof(DyLinkerCommand) */; + dylkcmd.lc_str_name = getLCStr(len); + len -= dylkcmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = dylkcmd; + break; + + case LoadCommand.LC_PREBOUND_DYLIB: + PreboundDyLibCommand pbcmd = new PreboundDyLibCommand(); + pbcmd.cmd = cmd; + pbcmd.cmdsize = efile.readIntE(); + pbcmd.name = efile.readIntE(); + pbcmd.nmodules = efile.readIntE(); + pbcmd.linked_modules = efile.readIntE(); + len = pbcmd.cmdsize - 20 /* sizeof(PreboundDyLibCommand) */; + pbcmd.lc_str_name = getLCStr(len); + len -= pbcmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = pbcmd; + break; + + case LoadCommand.LC_ROUTINES: + RoutinesCommand rcmd = new RoutinesCommand(); + rcmd.cmd = cmd; + rcmd.cmdsize = efile.readIntE(); + rcmd.init_address = efile.readIntE(); + rcmd.init_module = efile.readIntE(); + rcmd.reserved1 = efile.readIntE(); + rcmd.reserved2 = efile.readIntE(); + rcmd.reserved3 = efile.readIntE(); + rcmd.reserved4 = efile.readIntE(); + rcmd.reserved5 = efile.readIntE(); + rcmd.reserved6 = efile.readIntE(); + loadcommands[i] = rcmd; + break; + + case LoadCommand.LC_SUB_FRAMEWORK: + SubFrameworkCommand subfcmd = new SubFrameworkCommand(); + subfcmd.cmd = cmd; + subfcmd.cmdsize = efile.readIntE(); + subfcmd.umbrella = efile.readIntE(); + len = subfcmd.cmdsize - 12 /* sizeof(SubFrameworkCommand) */ ; + subfcmd.lc_str_name = getLCStr(len); + len -= subfcmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = subfcmd; + break; + + case LoadCommand.LC_SUB_UMBRELLA: + SubUmbrellaCommand subucmd = new SubUmbrellaCommand(); + subucmd.cmd = cmd; + subucmd.cmdsize = efile.readIntE(); + subucmd.sub_umbrella = efile.readIntE(); + len = subucmd.cmdsize - 12 /* sizeof(SubUmbrellaCommand) */; + subucmd.lc_str_name = getLCStr(len); + len -= subucmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = subucmd; + break; + + case LoadCommand.LC_SUB_CLIENT: + SubClientCommand subccmd = new SubClientCommand(); + subccmd.cmd = cmd; + subccmd.cmdsize = efile.readIntE(); + subccmd.client = efile.readIntE(); + len = subccmd.cmdsize - 12 /* sizeof(SubClientCommand) */; + subccmd.lc_str_name = getLCStr(len); + len -= subccmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = subccmd; + break; + + case LoadCommand.LC_SUB_LIBRARY: + SubLibraryCommand sublcmd = new SubLibraryCommand(); + sublcmd.cmd = cmd; + sublcmd.cmdsize = efile.readIntE(); + sublcmd.sub_library = efile.readIntE(); + len = sublcmd.cmdsize - 12 /* sizeof(SubLibraryCommand) */; + sublcmd.lc_str_name = getLCStr(len); + len -= sublcmd.lc_str_name.length() + 1; + efile.skipBytes(len); + loadcommands[i] = sublcmd; + break; + + case LoadCommand.LC_TWOLEVEL_HINTS: + TwoLevelHintsCommand tlhcmd = new TwoLevelHintsCommand(); + tlhcmd.cmd = cmd; + tlhcmd.cmdsize = efile.readIntE(); + tlhcmd.offset = efile.readIntE(); + tlhcmd.nhints = efile.readIntE(); + loadcommands[i] = tlhcmd; + break; + + case LoadCommand.LC_PREBIND_CKSUM: + PrebindCksumCommand pbccmd = new PrebindCksumCommand(); + pbccmd.cmd = cmd; + pbccmd.cmdsize = efile.readIntE(); + pbccmd.cksum = efile.readIntE(); + loadcommands[i] = pbccmd; + break; + + default: + // fallback, just in case we don't recognize the command + UnknownCommand unknowncmd = new UnknownCommand(); + unknowncmd.cmd = cmd; + unknowncmd.cmdsize = 0; + loadcommands[i] = unknowncmd; + break; + } + } + } + } + + public void loadBinary() throws IOException { + if ( loadcommands == null ) { + loadLoadCommands(); + loadSymbolTable(); + loadLineTable(); + } + } + + public Symbol[] getSymbols() { + return symbols; + } + + public Symbol[] getDynamicSymbols() { + if (dynsym) { + return symbols; + } + return null; + } + + public Symbol[] getSymtabSymbols() { + return symbols; + } + + public Symbol[] getLocalSymbols() { + if (local_symbols == null) { + return symbols; + } + return local_symbols; + } + + public Line[] getLineTable() { + return lines; + } + + public Section[] getSections() { + return sections.toArray(new Section[sections.size()]); + } + + public DyLib[] getDyLibs(int type) { + ArrayList v = new ArrayList(); + for (LoadCommand loadcommand : loadcommands) { + if (loadcommand.cmd == type) { + DyLibCommand dl = (DyLibCommand)loadcommand; + v.add(dl.dylib); + } + } + return v.toArray(new DyLib[v.size()]); + } + + /* return the address of the function that address is in */ + public Symbol getSymbol( long vma ) { + if ( symbols == null ) { + return null; + } + + int ndx = Arrays.binarySearch(symbols, new Long(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 ( mhdr.magic == MachOhdr.MH_CIGAM ) { + 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 ( mhdr.magic == MachOhdr.MH_CIGAM ) { + 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; + } + + private ISymbolReader createStabsReader() { + ISymbolReader symReader = null; + + try { + if ( loadcommands == null ) { + loadLoadCommands(); + } + } catch (IOException e) { } + + + for (LoadCommand loadcommand : loadcommands) { + if (loadcommand.cmd == LoadCommand.LC_SYMTAB) + { + symtab = (SymtabCommand)loadcommand; + try { + int symSize = symtab.nsyms * 12; + byte[] data = new byte[symSize]; + efile.seek(symtab.symoff); + efile.readFully(data); + byte[] stabstr = new byte[symtab.strsize]; + efile.seek(symtab.stroff); + efile.readFully(stabstr); + symReader = new StabsReader(data, stabstr, getAttributes().isLittleEndian()); + } catch (IOException e) {} + + } + } + return symReader; + } + + public Object getSymbolReader() { + ISymbolReader reader = null; + reader = createStabsReader(); + return reader; + } +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachOHelper64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachOHelper64.java new file mode 100644 index 00000000000..895a88e22f5 --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/MachOHelper64.java @@ -0,0 +1,319 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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 + * Craig Watson + * Apple Computer - work on performance optimizations + *******************************************************************************/ +package org.eclipse.cdt.utils.macho; + +import java.io.IOException; +import java.util.Vector; + +import org.eclipse.cdt.utils.macho.MachO.DyLib; +import org.eclipse.cdt.utils.macho.MachO.Section; +import org.eclipse.cdt.utils.macho.MachO.Symbol; + +/** + * MachOHelper is a wrapper class for the MachO class + * to provide higher level API for sorting/searching the MachO data. + * + * @see MachO + */ +public class MachOHelper { + + private MachO macho; + private MachO.Symbol[] dynsyms; + private MachO.Symbol[] symbols; + private MachO.Section[] sections; + private MachO.DyLib[] needed; + private MachO.DyLib[] sonames; + + public void dispose() { + if (macho != null) { + macho.dispose(); + macho = null; + } + } + + public class Sizes { + public long text; + public long data; + public long bss; + public long total; + public Sizes(long t, long d, long b) { + text = t; + data = d; + bss = b; + total = text + data + bss; + } + } + + private void loadBinary() throws IOException { + if (symbols == null) { + macho.loadBinary(); + symbols = macho.getSymtabSymbols(); + dynsyms = macho.getDynamicSymbols(); + sections = macho.getSections(); + needed = macho.getDyLibs(MachO.LoadCommand.LC_LOAD_DYLIB); + sonames = macho.getDyLibs(MachO.LoadCommand.LC_ID_DYLIB); + + if (dynsyms == null) + dynsyms = symbols; + } + } + + + /** + * Create a new MachOHelper using an existing MachO + * object. + * @param macho An existing MachO object to wrap. + * @throws IOException Error processing the MachO file. + */ + public MachOHelper(MachO macho) throws IOException { + this.macho = macho; + } + + /** + * Create a new MachOHelper based on the given filename. + * + * @param filename The file to use for creating a new MachO object. + * @throws IOException Error processing the MachO file. + * @see MachO#MachO( String ) + */ + public MachOHelper(String filename) throws IOException { + macho = new MachO(filename); + } + + /** + * Create a new MachOHelper based on the given filename. + * + * @param filename The file to use for creating a new MachO object. + * @throws IOException Error processing the MachO file. + * @see MachO#MachO( String ) + */ + public MachOHelper(String filename, long offset) throws IOException { + macho = new MachO(filename, offset); + } + + + public MachOHelper(String filename, boolean filton) throws IOException { + macho = new MachO(filename, filton); + } + + /** Give back the MachO object that this helper is wrapping */ + public MachO getMachO() { + return macho; + } + + public MachO.Symbol[] getExternalFunctions() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (Symbol sym : dynsyms) { + if ((sym.n_type_mask(MachO.Symbol.N_PEXT) + || sym.n_type_mask(MachO.Symbol.N_EXT)) + && sym.n_desc(MachO.Symbol.REFERENCE_FLAG_UNDEFINED_LAZY)) { + String name = sym.toString(); + if (name != null && name.trim().length() > 0) + v.add(sym); + } + } + + MachO.Symbol[] ret = v.toArray(new MachO.Symbol[0]); + return ret; + } + + public MachO.Symbol[] getExternalObjects() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (Symbol sym : dynsyms) { + if ((sym.n_type_mask(MachO.Symbol.N_PEXT) + || sym.n_type_mask(MachO.Symbol.N_EXT)) + && sym.n_desc(MachO.Symbol.REFERENCE_FLAG_UNDEFINED_NON_LAZY)) { + String name = sym.toString(); + if (name != null && name.trim().length() > 0) + v.add(sym); + } + } + + MachO.Symbol[] ret = v.toArray(new MachO.Symbol[0]); + return ret; + } + + public MachO.Symbol[] getUndefined() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (Symbol dynsym : dynsyms) { + if (dynsym.n_type(MachO.Symbol.N_UNDF)) + v.add(dynsym); + } + + MachO.Symbol[] ret = v.toArray(new MachO.Symbol[0]); + return ret; + } + + /* + * TODO: I'm not sure if this are correct. Need to check + */ + public MachO.Symbol[] getLocalFunctions() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (Symbol sym : dynsyms) { + if ((!sym.n_type_mask(MachO.Symbol.N_PEXT) + && !sym.n_type_mask(MachO.Symbol.N_EXT)) + && sym.n_desc(MachO.Symbol.REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)) { + String name = sym.toString(); + if (name != null && name.trim().length() > 0) + v.add(sym); + } + } + + MachO.Symbol[] ret = v.toArray(new MachO.Symbol[0]); + return ret; + } + + /* + * TODO: I'm not sure if this are correct. Need to check + */ + public MachO.Symbol[] getLocalObjects() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (Symbol sym : dynsyms) { + if ((!sym.n_type_mask(MachO.Symbol.N_PEXT) + && !sym.n_type_mask(MachO.Symbol.N_EXT)) + && sym.n_desc(MachO.Symbol.REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)) { + String name = sym.toString(); + if (name != null && name.trim().length() > 0) + v.add(sym); + } + } + + MachO.Symbol[] ret = v.toArray(new MachO.Symbol[0]); + return ret; + } + + public MachO.Symbol[] getCommonObjects() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (int i = 0; i < dynsyms.length; i++) { + MachO.Symbol sym = dynsyms[i]; + if (sym.n_type_mask(MachO.Symbol.N_EXT) + && sym.n_type(MachO.Symbol.N_UNDF) + && sym.n_value != 0) { + v.add(symbols[i]); + } + } + + MachO.Symbol[] ret = v.toArray(new MachO.Symbol[0]); + return ret; + } + + public String[] getNeeded() throws IOException { + Vector v = new Vector(); + + loadBinary(); + + for (DyLib element : needed) { + v.add(element.toString()); + } + return v.toArray(new String[0]); + } + + public String getSoname() throws IOException { + String soname = ""; //$NON-NLS-1$ + + loadBinary(); + + for (DyLib soname2 : sonames) { + soname = soname2.toString(); + } + return soname; + } + +// private String getSubUsage(String full, String name) { +// int start, end; +// //boolean has_names = false; +// //boolean has_languages = false; +// start = 0; +// end = 0; +// +// for (int i = 0; i < full.length(); i++) { +// if (full.charAt(i) == '%') { +// if (full.charAt(i + 1) == '-') { +// if (start == 0) { +// int eol = full.indexOf('\n', i + 2); +// String temp = full.substring(i + 2, eol); +// if (temp.compareTo(name) == 0) +// start = eol; +// +// //has_names = true; +// } else if (end == 0) { +// end = i - 1; +// } +// } +// +// //if( full.charAt( i+1 ) == '=' ) +// //has_languages = true; +// } +// } +// +// if (end == 0) +// end = full.length(); +// +// if (start == 0) +// return full; +// +// return full.substring(start, end); +// } + + public String getQnxUsage() throws IOException { + return new String(""); //$NON-NLS-1$ + } + + public Sizes getSizes() throws IOException { + long text, data, bss; + + text = 0; + data = 0; + bss = 0; + + // TODO further optimization + // TODO we only need to load the sections, not the whole shebang + loadBinary(); + + for (Section section : sections) { + MachO.SegmentCommand seg = section.segment; + if (section.flags(MachO.Section.SECTION_TYP) != MachO.Section.S_ZEROFILL) { + if (seg.prot(MachO.SegmentCommand.VM_PROT_EXECUTE)) { + text += section.size; + } else if (!seg.prot(MachO.SegmentCommand.VM_PROT_WRITE)) { + data += section.size; + } + } else { + if (seg.prot(MachO.SegmentCommand.VM_PROT_WRITE)) { + bss += section.size; + } + } + } + + return new Sizes(text, data, bss); + } + +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryArchive64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryArchive64.java new file mode 100644 index 00000000000..51f08a7b0ae --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryArchive64.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2002, 2008 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 + *******************************************************************************/ +package org.eclipse.cdt.utils.macho.parser; + +import java.io.IOException; +import java.util.ArrayList; + +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.IBinaryParser.IBinaryArchive; +import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; +import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; +import org.eclipse.cdt.utils.BinaryFile; +import org.eclipse.cdt.utils.macho.AR; +import org.eclipse.core.runtime.IPath; + +/** + */ +public class MachOBinaryArchive extends BinaryFile implements IBinaryArchive { + + ArrayList children; + + public MachOBinaryArchive(IBinaryParser parser, IPath p) throws IOException { + super(parser, p, IBinaryFile.ARCHIVE); + new AR(p.toOSString()).dispose(); // check file type + children = new ArrayList(5); + } + + /** + * @see org.eclipse.cdt.core.IBinaryParser.IBinaryArchive#getObjects() + */ + public IBinaryObject[] getObjects() { + if (hasChanged()) { + children.clear(); + AR ar = null; + try { + ar = new AR(getPath().toOSString()); + AR.ARHeader[] headers = ar.getHeaders(); + for (int i = 0; i < headers.length; i++) { + IBinaryObject bin = new MachOBinaryObject(getBinaryParser(), getPath(), headers[i]); + children.add(bin); + } + } catch (IOException e) { + //e.printStackTrace(); + } + if (ar != null) { + ar.dispose(); + } + children.trimToSize(); + } + return children.toArray(new IBinaryObject[0]); + } +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryExecutable64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryExecutable64.java new file mode 100644 index 00000000000..0972171070d --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryExecutable64.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2004, 2006 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 + *******************************************************************************/ +package org.eclipse.cdt.utils.macho.parser; + +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.IBinaryParser.IBinaryExecutable; +import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; +import org.eclipse.core.runtime.IPath; + + +public class MachOBinaryExecutable extends MachOBinaryObject implements IBinaryExecutable { + + public MachOBinaryExecutable(IBinaryParser parser, IPath path) { + super(parser, path, IBinaryFile.EXECUTABLE); + } + +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryObject64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryObject64.java new file mode 100644 index 00000000000..dcb9671912c --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryObject64.java @@ -0,0 +1,416 @@ +/******************************************************************************* + * Copyright (c) 2002, 2007 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 + * Apple Computer - work on performance optimizations + *******************************************************************************/ +package org.eclipse.cdt.utils.macho.parser; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.core.IAddressFactory; +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.ISymbolReader; +import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; +import org.eclipse.cdt.core.IBinaryParser.ISymbol; +import org.eclipse.cdt.utils.Addr32; +import org.eclipse.cdt.utils.Addr32Factory; +import org.eclipse.cdt.utils.BinaryObjectAdapter; +import org.eclipse.cdt.utils.CPPFilt; +import org.eclipse.cdt.utils.Symbol; +import org.eclipse.cdt.utils.macho.AR; +import org.eclipse.cdt.utils.macho.MachO; +import org.eclipse.cdt.utils.macho.MachOHelper; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +/* + * MachOBinaryObject + */ +public class MachOBinaryObject extends BinaryObjectAdapter { + + protected AR.ARHeader header; + protected IAddressFactory addressFactory; + protected MachO.Attribute attributes; + protected MachOHelper.Sizes sizes; + protected ISymbol[] symbols; + protected String soname; + protected String[] needed; + protected long timeStamp; + private static final String[] NO_NEEDED = new String[0]; + + + /** + * @param parser + * @param path + * @param header + */ + public MachOBinaryObject(IBinaryParser parser, IPath path, AR.ARHeader header) { + super(parser, path, IBinaryFile.OBJECT); + this.header = header; + } + + /** + * @param parser + * @param path + * @param type + */ + public MachOBinaryObject(IBinaryParser parser, IPath path, int type) { + super(parser, path, type); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.utils.BinaryObjectAdapter#getBinaryObjectInfo() + */ + @Override + protected BinaryObjectInfo getBinaryObjectInfo() { + // we don't use this method + // overload to do nothing + return new BinaryObjectInfo(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser.IBinaryFile#getContents() + */ + @Override + public InputStream getContents() throws IOException { + if (getPath() != null && header != null) { + return new ByteArrayInputStream(header.getObjectData()); + } + return super.getContents(); + } + + protected MachOHelper getMachOHelper() throws IOException { + IPath path = getPath(); + if (path != null) { + if (header != null) { + return new MachOHelper(path.toOSString(), header.getObjectDataOffset()); + } else { + return new MachOHelper(path.toOSString()); + } + } + return null; + } + + /** + * @see org.eclipse.cdt.core.IBinaryParser.IBinaryObject#getName() + */ + @Override + public String getName() { + if (header != null) { + return header.getObjectName(); + } + return super.getName(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.utils.BinaryObjectAdapter#getAddressFactory() + */ + @Override + public IAddressFactory getAddressFactory() { + if (addressFactory == null) { + addressFactory = new Addr32Factory(); + } + return addressFactory; + } + + protected void clearCachedValues() { + attributes = null; + sizes = null; + symbols = null; + soname = null; + needed = null; + } + + protected MachO.Attribute internalGetAttributes() { + if (hasChanged()) { + clearCachedValues(); + } + if (attributes == null) { + MachOHelper helper = null; + try { + helper = getMachOHelper(); + if (helper != null) { + attributes = helper.getMachO().getAttributes(); + } + } catch (IOException e) { + } finally { + if (helper != null) { + helper.dispose(); + } + } + } + return attributes; + } + + protected MachOHelper.Sizes internalGetSizes() { + if (hasChanged()) { + clearCachedValues(); + } + if (sizes == null) { + MachOHelper helper = null; + try { + helper = getMachOHelper(); + if (helper != null) { + sizes = helper.getSizes(); + // since we're invoking the helper we might as well update + // the attributes since it's a pretty lightweight operation + if (attributes == null) { + attributes = helper.getMachO().getAttributes(); + } + } + } catch (IOException e) { + } finally { + if (helper != null) { + helper.dispose(); + } + } + } + return sizes; + } + + protected ISymbol[] internalGetSymbols() { + if (hasChanged()) { + clearCachedValues(); + } + if (symbols == null) { + loadBinaryInfo(); + } + return symbols; + } + + protected String internalGetSoName() { + if (hasChanged()) { + clearCachedValues(); + } + if (soname == null) { + loadBinaryInfo(); + } + return soname; + } + + protected String[] internalGetNeeded() { + if (hasChanged()) { + clearCachedValues(); + } + if (needed == null) { + loadBinaryInfo(); + } + return needed; + } + + protected void loadBinaryInfo() { + MachOHelper helper = null; + try { + helper = getMachOHelper(); + if (helper != null) { + //TODO we can probably optimize this further in MachOHelper + + symbols = loadSymbols(helper); + //TODO is the sort necessary? + Arrays.sort(symbols); + + soname = helper.getSoname(); + needed = helper.getNeeded(); + + // since we're invoking the helper we might as well update the + // sizes since it's a pretty lightweight operation by comparison + if (sizes == null) { + sizes = helper.getSizes(); + } + // since we're invoking the helper we might as well update the + // attributes since it's a pretty lightweight operation by comparison + if (attributes == null) { + attributes = helper.getMachO().getAttributes(); + } + } + } catch (IOException e) { + symbols = NO_SYMBOLS; + } finally { + if (helper != null) { + helper.dispose(); + } + } + } + + protected ISymbol[] loadSymbols(MachOHelper helper) throws IOException { + CPPFilt cppfilt = null; + try { + ArrayList list = new ArrayList(); + // Hack should be remove when Elf is clean + helper.getMachO().setCppFilter(false); + cppfilt = getCPPFilt(); + //TODO we can probably optimize this further in MachOHelper + addSymbols(helper.getExternalFunctions(), ISymbol.FUNCTION, cppfilt, list); + addSymbols(helper.getLocalFunctions(), ISymbol.FUNCTION, cppfilt, list); + addSymbols(helper.getExternalObjects(), ISymbol.VARIABLE, cppfilt, list); + addSymbols(helper.getLocalObjects(), ISymbol.VARIABLE, cppfilt, list); + return list.toArray(new ISymbol[list.size()]); + } finally { + if (cppfilt != null) { + cppfilt.dispose(); + } + } + } + + protected CPPFilt getCPPFilt() { + MachOParser parser = (MachOParser) getBinaryParser(); + return parser.getCPPFilt(); + } + + private void addSymbols(MachO.Symbol[] array, int type, CPPFilt cppfilt, List list) { + for (org.eclipse.cdt.utils.macho.MachO.Symbol element : array) { + String name = element.toString(); + if (cppfilt != null) { + try { + name = cppfilt.getFunction(name); + } catch (IOException e1) { + cppfilt = null; + } + } + long addr = element.n_value; + int size = 0; + String filename = element.getFilename(); + IPath filePath = (filename != null) ? new Path(filename) : null; + list.add(new Symbol(this, name, type, new Addr32(element.n_value), size, filePath, element.getLineNumber(addr), element.getLineNumber(addr + size - 1))); + } + } + + @Override + public String getCPU() { + MachO.Attribute attribute = internalGetAttributes(); + if (attribute != null) { + return attribute.getCPU(); + } + return ""; //$NON-NLS-1$ + } + + @Override + public boolean hasDebug() { + MachO.Attribute attribute = internalGetAttributes(); + if (attribute != null) { + return attribute.hasDebug(); + } + return false; + } + + @Override + public boolean isLittleEndian() { + MachO.Attribute attribute = internalGetAttributes(); + if (attribute != null) { + return attribute.isLittleEndian(); + } + return false; + } + + @Override + public long getBSS() { + MachOHelper.Sizes size = internalGetSizes(); + if (size != null) { + return size.bss; + } + return 0; + } + + @Override + public long getData() { + MachOHelper.Sizes size = internalGetSizes(); + if (size != null) { + return size.data; + } + return 0; + } + + @Override + public long getText() { + MachOHelper.Sizes size = internalGetSizes(); + if (size != null) { + return size.text; + } + return 0; + } + + @Override + public ISymbol[] getSymbols() { + ISymbol[] syms = internalGetSymbols(); + if (syms != null) { + return syms; + } + return NO_SYMBOLS; + } + + @Override + public ISymbol getSymbol(IAddress addr) { + //TODO should this be cached? + // fall back to super implementation for now + return super.getSymbol(addr); + } + + @Override + public String[] getNeededSharedLibs() { + String[] libs = internalGetNeeded(); + if (libs != null) { + return libs; + } + return NO_NEEDED; + } + + @Override + public String getSoName() { + String name = internalGetSoName(); + if (name != null) { + return name; + } + return ""; //$NON-NLS-1$ + } + + @Override + protected boolean hasChanged() { + IPath path = getPath(); + if (path != null) { + File file = path.toFile(); + if (file != null) { + long modification = file.lastModified(); + if (modification != timeStamp) { + timeStamp = modification; + return true; + } + } + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @SuppressWarnings("unchecked") + @Override + public Object getAdapter(Class adapter) { + if (adapter.equals(MachO.class)) { + try { + return new MachO(getPath().toOSString()); + } catch (IOException e) { + } + } + if (adapter.equals(ISymbolReader.class)) { + MachO macho = (MachO)getAdapter(MachO.class); + if (macho != null) { + return macho.getSymbolReader(); + } + } + return super.getAdapter(adapter); + } + +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryShared64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryShared64.java new file mode 100644 index 00000000000..96dcbe9df7b --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOBinaryShared64.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2004, 2006 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 + *******************************************************************************/ +package org.eclipse.cdt.utils.macho.parser; + +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; +import org.eclipse.cdt.core.IBinaryParser.IBinaryShared; +import org.eclipse.core.runtime.IPath; + + +public class MachOBinaryShared extends MachOBinaryObject implements IBinaryShared { + + protected MachOBinaryShared(IBinaryParser parser, IPath path) { + super(parser, path, IBinaryFile.SHARED); + } + +} diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOParser64.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOParser64.java new file mode 100644 index 00000000000..f99d86cc9e9 --- /dev/null +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/macho/parser/MachOParser64.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2002, 2007 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 + *******************************************************************************/ +package org.eclipse.cdt.utils.macho.parser; + +import java.io.IOException; + +import org.eclipse.cdt.core.AbstractCExtension; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.ICExtensionReference; +import org.eclipse.cdt.utils.CPPFilt; +import org.eclipse.cdt.utils.macho.AR; +import org.eclipse.cdt.utils.macho.MachO; +import org.eclipse.cdt.utils.macho.MachO.Attribute; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +/** + */ +public class MachOParser extends AbstractCExtension implements IBinaryParser { + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser#getBinary(org.eclipse.core.runtime.IPath) + */ + public IBinaryFile getBinary(IPath path) throws IOException { + return getBinary(null, path); + } + + + public IBinaryFile getBinary(byte[] hints, IPath path) throws IOException { + if (path == null) { + throw new IOException(CCorePlugin.getResourceString("Util.exception.nullPath")); //$NON-NLS-1$ + } + + IBinaryFile binary = null; + try { + MachO.Attribute attribute = null; + if (hints != null && hints.length > 0) { + try { + attribute = MachO.getAttributes(hints); + } catch (IOException eof) { + // continue, the array was to small. + } + } + + //Take a second run at it if the data array failed. + if(attribute == null) { + attribute = MachO.getAttributes(path.toOSString()); + } + + if (attribute != null) { + switch (attribute.getType()) { + case Attribute.MACHO_TYPE_EXE : + binary = createBinaryExecutable(path); + break; + + case Attribute.MACHO_TYPE_SHLIB : + binary = createBinaryShared(path); + break; + + case Attribute.MACHO_TYPE_OBJ : + binary = createBinaryObject(path); + break; + + case Attribute.MACHO_TYPE_CORE : + binary = createBinaryCore(path); + break; + } + } + } catch (IOException e) { + binary = createBinaryArchive(path); + } + return binary; + } + + /** + * @see org.eclipse.cdt.core.IBinaryParser#getFormat() + */ + public String getFormat() { + return "MACHO"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser#isBinary(byte[], org.eclipse.core.runtime.IPath) + */ + public boolean isBinary(byte[] array, IPath path) { + return MachO.isMachOHeader(array) || AR.isARHeader(array); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser#getBufferSize() + */ + public int getHintBufferSize() { + return 128; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.utils.IGnuToolProvider#getCPPFilt() + */ + public CPPFilt getCPPFilt() { + IPath cppFiltPath = getCPPFiltPath(); + CPPFilt cppfilt = null; + if (cppFiltPath != null && ! cppFiltPath.isEmpty()) { + try { + cppfilt = new CPPFilt(cppFiltPath.toOSString()); + } catch (IOException e2) { + } + } + return cppfilt; + } + + protected IPath getCPPFiltPath() { + ICExtensionReference ref = getExtensionReference(); + String value = ref.getExtensionData("c++filt"); //$NON-NLS-1$ + if (value == null || value.length() == 0) { + value = "c++filt"; //$NON-NLS-1$ + } + return new Path(value); + } + + protected IBinaryArchive createBinaryArchive(IPath path) throws IOException { + return new MachOBinaryArchive(this, path); + } + + protected IBinaryObject createBinaryObject(IPath path) throws IOException { + return new MachOBinaryObject(this, path, IBinaryFile.OBJECT); + } + + protected IBinaryExecutable createBinaryExecutable(IPath path) throws IOException { + return new MachOBinaryExecutable(this, path); + } + + protected IBinaryShared createBinaryShared(IPath path) throws IOException { + return new MachOBinaryShared(this, path); + } + + protected IBinaryObject createBinaryCore(IPath path) throws IOException { + return new MachOBinaryObject(this, path, IBinaryFile.CORE); + } +}