1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-30 20:35:38 +02:00

Improve PE64 symbol presentation in Project Explorer

Enhances PE64/COFF symbol presentation for parity with ELF symbol
presentation within Project Explorer.
This commit is contained in:
John Dallaway 2024-01-02 15:42:09 +00:00
parent 0173da5325
commit 0e41dfea40
8 changed files with 283 additions and 79 deletions

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2023 QNX Software Systems and others.
* Copyright (c) 2000, 2024 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -13,32 +13,22 @@
* Anton Leherbauer (Wind River Systems)
* John Dallaway - Adapt for IBinaryFile (#413)
* John Dallaway - Fix object path processing (#630)
* John Dallaway - Use common buildCWD lookup methods (#652)
*******************************************************************************/
package org.eclipse.cdt.internal.core.model;
import java.util.Map;
import java.util.Optional;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.IBinaryParser.IBinaryArchive;
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.IArchive;
import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICOutputEntry;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.extension.CBuildData;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationData;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.internal.core.util.MementoTokenizer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
@ -93,8 +83,8 @@ public class Archive extends Openable implements IArchive {
IPath location = res.getLocation();
if (ar != null && location != null) {
// find the build CWD for the archive file
IPath buildCWD = Optional.ofNullable(findBuildConfiguration(res)).map(Archive::getBuildCWD)
.orElse(location.removeLastSegments(1));
IPath buildCWD = Optional.ofNullable(InternalCoreModelUtil.findBuildConfiguration(res))
.map(InternalCoreModelUtil::getBuildCWD).orElse(location.removeLastSegments(1));
for (IBinaryObject obj : ar.getObjects()) {
// assume object names are paths as specified on the archiver command line ("ar -P")
IPath objPath = new Path(obj.getName());
@ -162,50 +152,4 @@ public class Archive extends Openable implements IArchive {
return 0;
}
private static ICConfigurationDescription findBuildConfiguration(IResource resource) {
IPath location = resource.getLocation();
IProject project = resource.getProject();
ICProjectDescription projectDesc = CoreModel.getDefault().getProjectDescription(project, false);
if (projectDesc == null) {
return null; // not a CDT project
}
// for each build configuration of the project
for (ICConfigurationDescription configDesc : projectDesc.getConfigurations()) {
CConfigurationData configData = configDesc.getConfigurationData();
if (configData == null) {
continue; // no configuration data
}
CBuildData buildData = configData.getBuildData();
if (buildData == null) {
continue; // no build data
}
// for each build output directory of the build configuration
for (ICOutputEntry dir : buildData.getOutputDirectories()) {
IPath dirLocation = CDataUtil.makeAbsolute(project, dir).getLocation();
// if the build output directory is an ancestor of the resource
if ((dirLocation != null) && dirLocation.isPrefixOf(location)) {
return configDesc; // build configuration found
}
}
}
return null;
}
private static IPath getBuildCWD(ICConfigurationDescription configDesc) {
IPath builderCWD = configDesc.getBuildSetting().getBuilderCWD();
if (builderCWD != null) {
ICdtVariableManager manager = CCorePlugin.getDefault().getCdtVariableManager();
try {
String cwd = builderCWD.toString();
cwd = manager.resolveValue(cwd, "", null, configDesc); //$NON-NLS-1$
if (!cwd.isEmpty()) {
return new Path(cwd);
}
} catch (CdtVariableException e) {
CCorePlugin.log(e);
}
}
return null;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2023 QNX Software Systems and others.
* Copyright (c) 2000, 2024 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -13,6 +13,7 @@
* Markus Schorn (Wind River Systems)
* Anton Leherbauer (Wind River Systems)
* John Dallaway - Adapt for IBinaryFile (#413)
* John Dallaway - Support source file lookup from relative path (#652)
*******************************************************************************/
package org.eclipse.cdt.internal.core.model;
@ -22,6 +23,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CCorePreferenceConstants;
@ -282,7 +284,7 @@ public class Binary extends Openable implements IBinary {
// information. If not, fall back on information from the binary parser.
boolean showSourceFiles = Platform.getPreferencesService().getBoolean(CCorePlugin.PLUGIN_ID,
CCorePreferenceConstants.SHOW_SOURCE_FILES_IN_BINARIES, false, null);
if (!showSourceFiles || !addSourceFiles(info, obj, hash)) {
if (!showSourceFiles || !addSourceFiles(info, res, obj, hash)) {
ISymbol[] symbols = obj.getSymbols();
for (ISymbol symbol : symbols) {
switch (symbol.getType()) {
@ -302,7 +304,7 @@ public class Binary extends Openable implements IBinary {
return ok;
}
private boolean addSourceFiles(OpenableInfo info, IBinaryObject obj, Map<IPath, BinaryModule> hash)
private boolean addSourceFiles(OpenableInfo info, IResource res, IBinaryObject obj, Map<IPath, BinaryModule> hash)
throws CModelException {
// Try to get the list of source files used to build the binary from the
// symbol information.
@ -315,7 +317,12 @@ public class Binary extends Openable implements IBinary {
sourceFiles = symbolreader.getSourceFiles();
}
if (sourceFiles != null && sourceFiles.length > 0) {
final IPath location = res.getLocation();
if (location != null && sourceFiles != null && sourceFiles.length > 0) {
// find the build CWD for the archive file
IPath buildCWD = Optional.ofNullable(InternalCoreModelUtil.findBuildConfiguration(res))
.map(InternalCoreModelUtil::getBuildCWD).orElse(location.removeLastSegments(1));
ISourceFinder srcFinder = getAdapter(ISourceFinder.class);
try {
for (String filename : sourceFiles) {
@ -328,11 +335,17 @@ public class Binary extends Openable implements IBinary {
}
}
IPath path = new Path(filename);
if (!path.isAbsolute()) {
// assume path is relative to the build CWD
path = buildCWD.append(path);
}
// Be careful how you use this File object. If filename is a relative path, the resulting File
// object will apply the relative path to the working directory, which is not what we want.
// Stay away from methods that return or use the absolute path of the object. Note that
// File.isAbsolute() returns false when the object was constructed with a relative path.
File file = new File(filename);
File file = path.toFile();
// Create a translation unit for this file and add it as a child of the binary
String id = CoreModel.getRegistedContentTypeId(getCProject().getProject(), file.getName());
@ -345,7 +358,7 @@ public class Binary extends Openable implements IBinary {
// We check this to determine if we should create a TranslationUnit or ExternalTranslationUnit
IFile wkspFile = null;
if (file.isAbsolute()) {
IFile[] filesInWP = ResourceLookup.findFilesForLocation(new Path(filename));
IFile[] filesInWP = ResourceLookup.findFilesForLocation(path);
for (IFile element : filesInWP) {
if (element.isAccessible()) {

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2010, 2015 Google, Inc and others.
* Copyright (c) 2010, 2024 Google, Inc and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -9,7 +9,8 @@
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sergey Prigogin (Google) - initial API and implementation
* Sergey Prigogin (Google) - initial API and implementation
* John Dallaway - Support build CWD lookup (#652)
*******************************************************************************/
package org.eclipse.cdt.internal.core.model;
@ -20,16 +21,23 @@ import java.util.List;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.IPathEntry;
import org.eclipse.cdt.core.model.ISourceEntry;
import org.eclipse.cdt.core.settings.model.CSourceEntry;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICOutputEntry;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICSourceEntry;
import org.eclipse.cdt.core.settings.model.WriteAccessException;
import org.eclipse.cdt.core.settings.model.extension.CBuildData;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationData;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
@ -89,4 +97,51 @@ public class InternalCoreModelUtil {
}
}
}
public static ICConfigurationDescription findBuildConfiguration(IResource resource) {
IPath location = resource.getLocation();
IProject project = resource.getProject();
ICProjectDescription projectDesc = CoreModel.getDefault().getProjectDescription(project, false);
if (projectDesc == null) {
return null; // not a CDT project
}
// for each build configuration of the project
for (ICConfigurationDescription configDesc : projectDesc.getConfigurations()) {
CConfigurationData configData = configDesc.getConfigurationData();
if (configData == null) {
continue; // no configuration data
}
CBuildData buildData = configData.getBuildData();
if (buildData == null) {
continue; // no build data
}
// for each build output directory of the build configuration
for (ICOutputEntry dir : buildData.getOutputDirectories()) {
IPath dirLocation = CDataUtil.makeAbsolute(project, dir).getLocation();
// if the build output directory is an ancestor of the resource
if ((dirLocation != null) && dirLocation.isPrefixOf(location)) {
return configDesc; // build configuration found
}
}
}
return null;
}
public static IPath getBuildCWD(ICConfigurationDescription configDesc) {
IPath builderCWD = configDesc.getBuildSetting().getBuilderCWD();
if (builderCWD != null) {
ICdtVariableManager manager = CCorePlugin.getDefault().getCdtVariableManager();
try {
String cwd = builderCWD.toString();
cwd = manager.resolveValue(cwd, "", null, configDesc); //$NON-NLS-1$
if (!cwd.isEmpty()) {
return new Path(cwd);
}
} catch (CdtVariableException e) {
CCorePlugin.log(e);
}
}
return null;
}
}

View file

@ -12,11 +12,11 @@
* Space Codesign Systems - Initial API and implementation
* QNX Software Systems - initial CygwinPEBinaryArchive class
* John Dallaway - Initial GNUPEBinaryArchive64 class (#361)
* John Dallaway - Update for parity with GNU ELF implementation (#652)
*******************************************************************************/
package org.eclipse.cdt.utils.coff.parser;
import java.io.IOException;
import java.util.ArrayList;
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
import org.eclipse.cdt.utils.AR.ARHeader;
@ -30,11 +30,12 @@ public class GNUPEBinaryArchive64 extends PEBinaryArchive64 {
}
@Override
protected void addArchiveMembers(ARHeader[] headers, ArrayList<IBinaryObject> children2) {
protected IBinaryObject[] createArchiveMembers(ARHeader[] headers) {
IBinaryObject[] result = new IBinaryObject[headers.length];
for (int i = 0; i < headers.length; i++) {
IBinaryObject bin = new GNUPEBinaryObject64(getBinaryParser(), getPath(), headers[i]);
children.add(bin);
result[i] = new GNUPEBinaryObject64(getBinaryParser(), getPath(), headers[i]);
}
return result;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2023 Space Codesign Systems and others.
* Copyright (c) 2000, 2024 Space Codesign Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -12,22 +12,38 @@
* Space Codesign Systems - Initial API and implementation
* QNX Software Systems - Initial CygwinPEBinaryObject class
* John Dallaway - Initial GNUPEBinaryObject64 class (#361)
* John Dallaway - Update for parity with GNU ELF implementation (#652)
*******************************************************************************/
package org.eclipse.cdt.utils.coff.parser;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.IGnuToolFactory;
import org.eclipse.cdt.utils.Objdump;
import org.eclipse.cdt.utils.Symbol;
import org.eclipse.cdt.utils.coff.Coff64;
import org.eclipse.cdt.utils.coff.PE64;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/** @since 8.2 */
public class GNUPEBinaryObject64 extends PEBinaryObject64 {
private Addr2line autoDisposeAddr2line;
private Addr2line symbolLoadingAddr2line;
private CPPFilt symbolLoadingCPPFilt;
long starttime;
public GNUPEBinaryObject64(IBinaryParser parser, IPath path, ARHeader header) {
super(parser, path, header);
}
@ -54,6 +70,60 @@ public class GNUPEBinaryObject64 extends PEBinaryObject64 {
return stream;
}
/** @since 8.4 */
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;
}
private synchronized void stopAddr2Line() {
if (autoDisposeAddr2line != null) {
autoDisposeAddr2line.dispose();
}
autoDisposeAddr2line = null;
}
private Addr2line getAddr2line() {
IGnuToolFactory factory = getBinaryParser().getAdapter(IGnuToolFactory.class);
if (factory != null) {
return factory.getAddr2line(getPath());
}
return null;
}
/** @since 8.4 */
protected CPPFilt getCPPFilt() {
IGnuToolFactory factory = getBinaryParser().getAdapter(IGnuToolFactory.class);
if (factory != null) {
return factory.getCPPFilt();
}
return null;
}
protected Objdump getObjdump() {
IGnuToolFactory factory = getBinaryParser().getAdapter(IGnuToolFactory.class);
if (factory != null) {
@ -62,4 +132,60 @@ public class GNUPEBinaryObject64 extends PEBinaryObject64 {
return null;
}
@Override
protected void loadSymbols(PE64 pe) throws IOException {
symbolLoadingAddr2line = getAddr2line(false);
symbolLoadingCPPFilt = getCPPFilt();
try {
super.loadSymbols(pe);
} finally {
if (symbolLoadingAddr2line != null) {
symbolLoadingAddr2line.dispose();
symbolLoadingAddr2line = null;
}
if (symbolLoadingCPPFilt != null) {
symbolLoadingCPPFilt.dispose();
symbolLoadingCPPFilt = null;
}
}
}
@Override
protected void addSymbols(Coff64.Symbol[] peSyms, byte[] table, List<Symbol> list) {
for (Coff64.Symbol element : peSyms) {
if ((element.n_sclass != Coff64.Symbol.SC_EXTERNAL) || (element.n_scnum <= 0)) {
continue; // ignore non-external symbol
}
String name = element.toString();
if (symbolLoadingCPPFilt != null) {
try {
name = symbolLoadingCPPFilt.getFunction(name);
} catch (IOException e1) {
symbolLoadingCPPFilt.dispose();
symbolLoadingCPPFilt = null;
}
}
IAddress addr = new Addr32(element.n_value);
long size = element.getSize();
int type = element.isFunction() ? ISymbol.FUNCTION : ISymbol.VARIABLE;
if (symbolLoadingAddr2line != null) {
try {
String filename = symbolLoadingAddr2line.getFileName(addr);
// addr2line returns "??" when it can not find the file
IPath file = (filename != null && !filename.equals("??")) ? new Path(filename) : Path.EMPTY; //$NON-NLS-1$
int startLine = symbolLoadingAddr2line.getLineNumber(addr);
int endLine = symbolLoadingAddr2line.getLineNumber(addr.add(size - 1));
list.add(new GNUPESymbol64(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 GNUPESymbol64(this, name, type, addr, size));
}
} else {
list.add(new GNUPESymbol64(this, name, type, addr, size));
}
}
}
}

View file

@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2004, 2024 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 of GNUSymbol
* John Dallaway - Initial GNUPESymbol64 class (#652)
*******************************************************************************/
package org.eclipse.cdt.utils.coff.parser;
import java.io.IOException;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.utils.Addr2line;
import org.eclipse.cdt.utils.Symbol;
import org.eclipse.core.runtime.IPath;
/**
* @since 8.4
*/
public class GNUPESymbol64 extends Symbol {
public GNUPESymbol64(GNUPEBinaryObject64 binary, String name, int type, IAddress addr, long size, IPath sourceFile,
int startLine, int endLine) {
super(binary, name, type, addr, size, sourceFile, startLine, endLine);
}
public GNUPESymbol64(GNUPEBinaryObject64 binary, String name, int type, IAddress addr, long size) {
super(binary, name, type, addr, size);
}
@Override
public int getLineNumber(long offset) {
int line = -1;
Addr2line addr2line = ((GNUPEBinaryObject64) binary).getAddr2line(true);
if (addr2line != null) {
try {
return addr2line.getLineNumber(getAddress().add(offset));
} catch (IOException e) {
// ignore
}
}
return line;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2019 Space Codesign Systems and others.
* Copyright (c) 2000, 2024 Space Codesign Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -11,11 +11,13 @@
* Contributors:
* Space Codesign Systems - Initial API and implementation
* QNX Software Systems - Initial PEBinaryArchive class
* John Dallaway - Update for parity with ELF implementation (#630)
*******************************************************************************/
package org.eclipse.cdt.utils.coff.parser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import org.eclipse.cdt.core.IBinaryParser.IBinaryArchive;
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
@ -51,7 +53,8 @@ public class PEBinaryArchive64 extends BinaryFile implements IBinaryArchive {
try {
ar = new AR(getPath().toOSString());
AR.ARHeader[] headers = ar.getHeaders();
addArchiveMembers(headers, children);
IBinaryObject[] bobjs = createArchiveMembers(headers);
children.addAll(Arrays.asList(bobjs));
} catch (IOException e) {
//e.printStackTrace();
}
@ -63,10 +66,21 @@ public class PEBinaryArchive64 extends BinaryFile implements IBinaryArchive {
return children.toArray(new IBinaryObject[0]);
}
/** @since 8.4 */
protected IBinaryObject[] createArchiveMembers(ARHeader[] headers) {
IBinaryObject[] result = new IBinaryObject[headers.length];
for (int i = 0; i < headers.length; i++) {
result[i] = new PEBinaryObject64(getBinaryParser(), getPath(), headers[i]);
}
return result;
}
/**
* @param headers
* @param children2
* @deprecated use {@link #createArchiveMembers(ARHeader[])}
*/
@Deprecated
protected void addArchiveMembers(ARHeader[] headers, ArrayList<IBinaryObject> children2) {
for (int i = 0; i < headers.length; i++) {
IBinaryObject bin = new PEBinaryObject64(getBinaryParser(), getPath(), headers[i]);

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2023 Space Codesign Systems and others.
* Copyright (c) 2000, 2024 Space Codesign Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -12,7 +12,7 @@
* Space Codesign Systems - Initial API and implementation
* QNX Software Systems - Initial PEBinaryObject class
* John Dallaway - Fix archive header processing (#630)
* John Dallaway - Support sections sizes in binary info (#652)
* John Dallaway - Support sections sizes and all external symbols (#652)
*******************************************************************************/
package org.eclipse.cdt.utils.coff.parser;
@ -170,8 +170,8 @@ public class PEBinaryObject64 extends BinaryObjectAdapter {
}
protected void addSymbols(Coff64.Symbol[] peSyms, byte[] table, List<Symbol> list) {
for (org.eclipse.cdt.utils.coff.Coff64.Symbol peSym : peSyms) {
if (peSym.isFunction() || peSym.isPointer() || peSym.isArray()) {
for (Coff64.Symbol peSym : peSyms) {
if ((peSym.n_sclass == Coff64.Symbol.SC_EXTERNAL) && (peSym.n_scnum > 0)) {
String name = peSym.getName(table);
if (name == null || name.trim().length() == 0 || !Character.isJavaIdentifierStart(name.charAt(0))) {
continue;