mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
bug 270790: Mach-O Parser doesn't recognize x86_64 binaries
Initial copy of non-64 MachO BinaryParser files
This commit is contained in:
parent
4d329afecd
commit
d046afcb84
7 changed files with 2673 additions and 0 deletions
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>MachOHelper</code> is a wrapper class for the <code>MachO</code> 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 <code>MachOHelper</code> using an existing <code>MachO</code>
|
||||||
|
* 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 <code>MachOHelper</code> 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 <code>MachOHelper</code> 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<Symbol> v = new Vector<Symbol>();
|
||||||
|
|
||||||
|
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<Symbol> v = new Vector<Symbol>();
|
||||||
|
|
||||||
|
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<Symbol> v = new Vector<Symbol>();
|
||||||
|
|
||||||
|
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<Symbol> v = new Vector<Symbol>();
|
||||||
|
|
||||||
|
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<Symbol> v = new Vector<Symbol>();
|
||||||
|
|
||||||
|
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<Symbol> v = new Vector<Symbol>();
|
||||||
|
|
||||||
|
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<String> v = new Vector<String>();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<IBinaryObject> 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<IBinaryObject>(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]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Symbol> list = new ArrayList<Symbol>();
|
||||||
|
// 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<Symbol> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue