blob: 695bffeb5feca0af0a7c7a9dcb1f5a31e9b917c4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* QNX Software Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.utils.coff.parser;
import java.io.ByteArrayInputStream;
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.CConventions;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.core.IBinaryParser;
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
import org.eclipse.cdt.utils.AR.ARHeader;
import org.eclipse.cdt.utils.Addr2line;
import org.eclipse.cdt.utils.Addr32;
import org.eclipse.cdt.utils.CPPFilt;
import org.eclipse.cdt.utils.CygPath;
import org.eclipse.cdt.utils.ICygwinToolsFactroy;
import org.eclipse.cdt.utils.NM;
import org.eclipse.cdt.utils.Objdump;
import org.eclipse.cdt.utils.Symbol;
import org.eclipse.cdt.utils.coff.Coff;
import org.eclipse.cdt.utils.coff.PE;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/*
* CygwinPEBinaryObject
*/
/**
* @deprecated. Deprecated as of CDT 6.9. Use 64 bit version {@link CygwinPEBinaryObject64}.
* This class is planned for removal in next major release.
*/
@Deprecated
public class CygwinPEBinaryObject extends PEBinaryObject {
private Addr2line autoDisposeAddr2line;
private Addr2line symbolLoadingAddr2line;
private CygPath symbolLoadingCygPath;
private CPPFilt symbolLoadingCPPFilt;
long starttime;
/**
* @param parser
* @param path
* @param header
*/
public CygwinPEBinaryObject(IBinaryParser parser, IPath path, ARHeader header) {
super(parser, path, header);
}
public CygwinPEBinaryObject(IBinaryParser parser, IPath path, int type) {
super(parser, path, type);
}
public Addr2line getAddr2line(boolean autodisposing) {
if (!autodisposing) {
return getAddr2line();
}
if (autoDisposeAddr2line == null) {
autoDisposeAddr2line = getAddr2line();
if (autoDisposeAddr2line != null) {
starttime = System.currentTimeMillis();
Runnable worker = () -> {
long diff = System.currentTimeMillis() - starttime;
while (diff < 10000) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
break;
}
diff = System.currentTimeMillis() - starttime;
}
stopAddr2Line();
};
new Thread(worker, "Addr2line Reaper").start(); //$NON-NLS-1$
}
} else {
starttime = System.currentTimeMillis(); // reset autodispose timeout
}
return autoDisposeAddr2line;
}
synchronized void stopAddr2Line() {
if (autoDisposeAddr2line != null) {
autoDisposeAddr2line.dispose();
}
autoDisposeAddr2line = null;
}
private Addr2line getAddr2line() {
ICygwinToolsFactroy factory = getBinaryParser().getAdapter(ICygwinToolsFactroy.class);
if (factory != null) {
return factory.getAddr2line(getPath());
}
return null;
}
protected CPPFilt getCPPFilt() {
ICygwinToolsFactroy factory = getBinaryParser().getAdapter(ICygwinToolsFactroy.class);
if (factory != null) {
return factory.getCPPFilt();
}
return null;
}
protected Objdump getObjdump() {
ICygwinToolsFactroy factory = getBinaryParser().getAdapter(ICygwinToolsFactroy.class);
if (factory != null) {
return factory.getObjdump(getPath());
}
return null;
}
protected CygPath getCygPath() {
ICygwinToolsFactroy factory = getBinaryParser().getAdapter(ICygwinToolsFactroy.class);
if (factory != null) {
return factory.getCygPath();
}
return null;
}
/**
*/
protected NM getNM() {
ICygwinToolsFactroy factory = getBinaryParser().getAdapter(ICygwinToolsFactroy.class);
if (factory != null) {
return factory.getNM(getPath());
}
return null;
}
/**
* @throws IOException
* @see org.eclipse.cdt.core.IBinaryParser.IBinaryFile#getContents()
*/
@Override
public InputStream getContents() throws IOException {
InputStream stream = null;
Objdump objdump = getObjdump();
if (objdump != null) {
try {
byte[] contents = objdump.getOutput();
stream = new ByteArrayInputStream(contents);
} catch (IOException e) {
// Nothing
}
}
if (stream == null) {
stream = super.getContents();
}
return stream;
}
@Override
protected void loadSymbols(PE pe) throws IOException {
symbolLoadingAddr2line = getAddr2line(false);
symbolLoadingCPPFilt = getCPPFilt();
symbolLoadingCygPath = getCygPath();
ArrayList<Symbol> list = new ArrayList<>();
super.loadSymbols(pe, list);
// Add any global symbols
NM nm = getNM();
if (nm != null) {
NM.AddressNamePair[] pairs = nm.getBSSSymbols();
for (int i = 0; i < pairs.length; ++i) {
addSymbol(pairs[i], list, ISymbol.VARIABLE);
}
pairs = nm.getDataSymbols();
for (int i = 0; i < pairs.length; ++i) {
addSymbol(pairs[i], list, ISymbol.VARIABLE);
}
}
// pairs = nm.getTextSymbols();
// for (int i = 0; i < pairs.length; ++i) {
// addSymbol(pairs[i], list, ISymbol.FUNCTION);
// }
symbols = list.toArray(NO_SYMBOLS);
Arrays.sort(symbols);
list.clear();
if (symbolLoadingAddr2line != null) {
symbolLoadingAddr2line.dispose();
symbolLoadingAddr2line = null;
}
if (symbolLoadingCPPFilt != null) {
symbolLoadingCPPFilt.dispose();
symbolLoadingCPPFilt = null;
}
if (symbolLoadingCygPath != null) {
symbolLoadingCygPath.dispose();
symbolLoadingCygPath = null;
}
}
private void addSymbol(NM.AddressNamePair p, List<Symbol> list, int type) {
String name = p.name;
if (name != null && name.length() > 0 && CConventions.isValidIdentifier(name)) {
IAddress addr = new Addr32(p.address);
int size = 4;
if (symbolLoadingCPPFilt != null) {
try {
name = symbolLoadingCPPFilt.getFunction(name);
} catch (IOException e1) {
symbolLoadingCPPFilt.dispose();
symbolLoadingCPPFilt = null;
}
}
if (symbolLoadingAddr2line != null) {
try {
String filename = symbolLoadingAddr2line.getFileName(addr);
// Addr2line returns the funny "??" when it can not find
// the file.
if (filename != null && filename.equals("??")) { //$NON-NLS-1$
filename = null;
}
if (filename != null) {
try {
if (symbolLoadingCygPath != null) {
filename = symbolLoadingCygPath.getFileName(filename);
}
} catch (IOException e) {
symbolLoadingCygPath.dispose();
symbolLoadingCygPath = null;
}
}
IPath file = filename != null ? new Path(filename) : Path.EMPTY;
int startLine = symbolLoadingAddr2line.getLineNumber(addr);
int endLine = symbolLoadingAddr2line.getLineNumber(addr.add(size - 1));
list.add(new CygwinSymbol(this, name, type, addr, size, file, startLine, endLine));
} catch (IOException e) {
symbolLoadingAddr2line.dispose();
symbolLoadingAddr2line = null;
}
}
}
}
@Override
protected void addSymbols(Coff.Symbol[] peSyms, byte[] table, List<Symbol> list) {
for (Coff.Symbol peSym : peSyms) {
if (peSym.isFunction() || peSym.isPointer() || peSym.isArray()) {
String name = peSym.getName(table);
if (name == null || name.trim().length() == 0 || !Character.isJavaIdentifierStart(name.charAt(0))) {
continue;
}
int type = peSym.isFunction() ? ISymbol.FUNCTION : ISymbol.VARIABLE;
IAddress addr = new Addr32(peSym.n_value);
int size = 4;
if (symbolLoadingCPPFilt != null) {
try {
name = symbolLoadingCPPFilt.getFunction(name);
} catch (IOException e1) {
symbolLoadingCPPFilt.dispose();
symbolLoadingCPPFilt = null;
}
}
if (symbolLoadingAddr2line != null) {
try {
String filename = symbolLoadingAddr2line.getFileName(addr);
// Addr2line returns the funny "??" when it can not find
// the file.
if (filename != null && filename.equals("??")) { //$NON-NLS-1$
filename = null;
}
if (filename != null) {
try {
if (symbolLoadingCygPath != null) {
filename = symbolLoadingCygPath.getFileName(filename);
}
} catch (IOException e) {
symbolLoadingCygPath.dispose();
symbolLoadingCygPath = null;
}
}
IPath file = filename != null ? new Path(filename) : Path.EMPTY;
int startLine = symbolLoadingAddr2line.getLineNumber(addr);
int endLine = symbolLoadingAddr2line.getLineNumber(addr.add(size - 1));
list.add(new CygwinSymbol(this, name, type, addr, size, file, startLine, endLine));
} catch (IOException e) {
symbolLoadingAddr2line.dispose();
symbolLoadingAddr2line = null;
// the symbol still needs to be added
list.add(new CygwinSymbol(this, name, type, addr, size));
}
} else {
list.add(new CygwinSymbol(this, name, type, addr, size));
}
}
}
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
if (adapter == Addr2line.class) {
return (T) getAddr2line(false);
} else if (adapter == CPPFilt.class) {
return (T) getCPPFilt();
} else if (adapter == CygPath.class) {
return (T) getCygPath();
}
return super.getAdapter(adapter);
}
}