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