1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-05 00:36:16 +02:00

[299317] Executables view source remapping does not take into account launch configurations

This commit is contained in:
John Cortell 2010-01-11 20:52:55 +00:00
parent 76547b9958
commit 485b4d73de
13 changed files with 694 additions and 88 deletions

View file

@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2010 Freescale Semiconductor 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:
* Freescale Semiconductor - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core;
import java.io.File;
import org.eclipse.cdt.internal.core.model.Binary;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
/**
* This interface is available for a {@link Binary} via the adapter mechanism. It is used to translate the
* source specification of a source file that was used to produce the executable to its local counterpart. In
* other words, the debug information in the binary tells us what source files where involved in building it.
* Such a file specification may be a simple file name, a relative path, or an absolute path that might be
* invalid on the local machine (the executable may have been built on another machine). In all cases, the
* file is found on the local machine by using source locators (see ISourceLocator). ISourceFinder is a front
* end to that search capability.
*
* <p>
* In CDT, there is/are:
* <ul>
* <li>A global (common) source locator. Its containers are defined via Window > Preferences > C/C++ > Debug >
* Common Source Lookup Path
* <li>Launch configuration source locators. The containers of such a locator are defined via the 'Source' tab
* in a CDT launch configuration.
* <li>Launch source locators. Typically, a launch's locator is the one defined in the launch configuration
* that spawned the launch, but technically, they could be different. The ILaunch API allows any source
* locator to be associated with a launch.
* </ul>
*
* <p>
* So, when trying to translate a source file specification in the debug information to a local file, there
* are a variety of locators that need to be considered. An ISourceFinder shields client code from having to
* worry about those details. A client simply wants to find a file locally.
*
* <p>
* This interface provides two choices for searching. One caters to logic involved in actively debugging a
* binary (e.g., a breakpoint is hit). The other is for use when there is no debug-session context (double
* clicking on a child file element of a Binary object in the Projects view). The former will search using
* only the locator associated with the ILaunch. The latter will use the locator of any relevant launch or
* launch configuration. In all cases, the global locator is consulted if no other locator has converted the
* file.
*
* @since 5.2
* @noimplement This interface is not intended to be implemented by clients.
* @noextend This interface is not intended to be extended by clients.
*/
public interface ISourceFinder {
/**
* Use this method to find a file if you do not have a debug context. The implementation will consult
* locators in the following order:
* <ol>
* <li>If there is an ongoing debug session on that binary, use that's ILaunch's locator. If there are
* multiple such debug sessions going on, the first one encountered is used.
* <li>If there are no ongoing debug sessions on that binary that provide a locator, search for a CDT
* launch configuration that references the binary. Use the locator of the first matching configuration.
* <li>If the above locator did not find the file, use the global locators.
* </ol>
*
* In the first two cases, only the first locator of the first matching launch or launch configuration is
* used, even if that locator doesn't find the file. Potentially, another matching one could find the
* file, but it could easily get very expensive to iterate through numerous matches that way. Searching
* for a file using a single launch/config's locator is expensive enough (it has numerous source
* containers). Searching through multiple ones could make this method unbearably slow. And because
* finding a matching launch/config can itself be a bit expensive, once a match has been found, its
* locator is used from that point on in all subsequent calls to this method. The implementation listens
* for launch and configurations changes, though, so we find a new locator when the active locator is no
* longer relevant. Note that calls to {@link #toLocalPath(IAdaptable, String)} have no effect on the
* active locator we use in this method.
*
* @param compilationPath
* the path of a file as found in the debug information
* @return if we are able to find the file, the location on the host machine, otherwise null. The result
* is in OS specific format, specifically what {@link File#getCanonicalPath()} returns. Note that
* by "on the host machine", we simply mean a specification that is <i>accessible by the host
* machine</i>. The file may be on a network drive, e.g., and thus not really be "local".
*/
public String toLocalPath(String compilationPath);
/**
* Use this method to find a file if you have a debug context. The implementation will consult the source
* locator associated with the given ILaunch. If there is no such locator or it does not find the file,
* the global source locator is consulted.
*
* @param launch
* an IAdaptable that will queried for an ILaunch. Pass in an ILaunch instance or something
* that can be adapted to one. If the object does not adapt to ILaunch, null is returned.
* @param compilationPath
* the path of a file as found in the debug information
* @return if we are able to find the file, the location on the host machine, otherwise null. The result
* is in OS specific format, along the lines of what {@link IPath#toOSString()} would return. Note
* that by "on the host machine", we simply mean a specification that is <i>accessible by the host
* machine</i>. The file may be on a network drive, e.g., and thus not really be "local".
*/
public String toLocalPath(IAdaptable launch, String compilationPath);
}

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<component id="org.eclipse.cdt.debug.core" version="2"> <component id="org.eclipse.cdt.debug.core" version="2">
<resource path="src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java" type="org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants"> <resource path="src/org/eclipse/cdt/debug/core/ICDTLaunchConfigurationConstants.java" type="org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants">
<filter id="403853384"> <filter id="403853384">
@ -7,4 +7,12 @@
</message_arguments> </message_arguments>
</filter> </filter>
</resource> </resource>
<resource path="src/org/eclipse/cdt/debug/internal/core/srcfinder/CSourceFinder.java" type="org.eclipse.cdt.debug.internal.core.srcfinder.CSourceFinder">
<filter id="574619656">
<message_arguments>
<message_argument value="ISourceFinder"/>
<message_argument value="CSourceFinder"/>
</message_arguments>
</filter>
</resource>
</component> </component>

View file

@ -337,5 +337,14 @@
<sourceContainer <sourceContainer
id="org.eclipse.debug.core.containerType.project"/> id="org.eclipse.debug.core.containerType.project"/>
</extension> </extension>
<extension
point="org.eclipse.core.runtime.adapters">
<factory
adaptableType="org.eclipse.cdt.core.model.IBinary"
class="org.eclipse.cdt.debug.internal.core.srcfinder.CSourceFinderFactory">
<adapter
type="org.eclipse.cdt.core.ISourceFinder">
</adapter>
</factory>
</extension>
</plugin> </plugin>

View file

@ -2,9 +2,9 @@
<!-- Schema file written by PDE --> <!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.cdt.debug.core" xmlns="http://www.w3.org/2001/XMLSchema"> <schema targetNamespace="org.eclipse.cdt.debug.core" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation> <annotation>
<appinfo> <appInfo>
<meta.schema plugin="org.eclipse.cdt.debug.core" id="SourceRemappingProvider" name="Source Remapping Provider"/> <meta.schema plugin="org.eclipse.cdt.debug.core" id="SourceRemappingProvider" name="Source Remapping Provider"/>
</appinfo> </appInfo>
<documentation> <documentation>
This extension points allows you to extened the executables manager in CDT by providing your own source remapping provider. This extension points allows you to extened the executables manager in CDT by providing your own source remapping provider.
</documentation> </documentation>
@ -12,9 +12,9 @@
<element name="extension"> <element name="extension">
<annotation> <annotation>
<appinfo> <appInfo>
<meta.element /> <meta.element />
</appinfo> </appInfo>
</annotation> </annotation>
<complexType> <complexType>
<sequence> <sequence>
@ -39,9 +39,9 @@
<documentation> <documentation>
</documentation> </documentation>
<appinfo> <appInfo>
<meta.attribute translatable="true"/> <meta.attribute translatable="true"/>
</appinfo> </appInfo>
</annotation> </annotation>
</attribute> </attribute>
</complexType> </complexType>
@ -54,27 +54,27 @@
<documentation> <documentation>
</documentation> </documentation>
<appinfo> <appInfo>
<meta.attribute kind="java" basedOn="org.eclipse.cdt.debug.core.executables.ISourceFileRemapping"/> <meta.attribute kind="java" basedOn=":org.eclipse.cdt.debug.core.executables.ISourceFileRemappingFactory"/>
</appinfo> </appInfo>
</annotation> </annotation>
</attribute> </attribute>
</complexType> </complexType>
</element> </element>
<annotation> <annotation>
<appinfo> <appInfo>
<meta.section type="since"/> <meta.section type="since"/>
</appinfo> </appInfo>
<documentation> <documentation>
CDT 7.0 CDT 7.0
</documentation> </documentation>
</annotation> </annotation>
<annotation> <annotation>
<appinfo> <appInfo>
<meta.section type="examples"/> <meta.section type="examples"/>
</appinfo> </appInfo>
<documentation> <documentation>
&lt;extension &lt;extension
point=&quot;org.eclipse.cdt.debug.core.SourceRemappingProvider&quot;&gt; point=&quot;org.eclipse.cdt.debug.core.SourceRemappingProvider&quot;&gt;
@ -83,4 +83,7 @@
</documentation> </documentation>
</annotation> </annotation>
</schema> </schema>

View file

@ -89,6 +89,7 @@ public class Executable extends PlatformObject {
private final Map<ITranslationUnit, String> remappedPaths; private final Map<ITranslationUnit, String> remappedPaths;
private final ArrayList<ITranslationUnit> sourceFiles; private final ArrayList<ITranslationUnit> sourceFiles;
private boolean refreshSourceFiles; private boolean refreshSourceFiles;
private ISourceFileRemapping[] remappers;
public IPath getPath() { public IPath getPath() {
return executablePath; return executablePath;
@ -98,11 +99,15 @@ public class Executable extends PlatformObject {
return project; return project;
} }
public Executable(IPath path, IProject project, IResource resource) { /**
* @since 7.0
*/
public Executable(IPath path, IProject project, IResource resource, ISourceFileRemapping[] sourceFileRemappings) {
this.executablePath = path; this.executablePath = path;
this.project = project; this.project = project;
this.name = new File(path.toOSString()).getName(); this.name = new File(path.toOSString()).getName();
this.resource = resource; this.resource = resource;
this.remappers = sourceFileRemappings;
remappedPaths = new HashMap<ITranslationUnit, String>(); remappedPaths = new HashMap<ITranslationUnit, String>();
sourceFiles = new ArrayList<ITranslationUnit>(); sourceFiles = new ArrayList<ITranslationUnit>();
refreshSourceFiles = true; refreshSourceFiles = true;
@ -121,7 +126,7 @@ public class Executable extends PlatformObject {
return name; return name;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("rawtypes")
@Override @Override
public Object getAdapter(Class adapter) { public Object getAdapter(Class adapter) {
if (adapter.equals(IResource.class)) if (adapter.equals(IResource.class))
@ -132,6 +137,17 @@ public class Executable extends PlatformObject {
return super.getAdapter(adapter); return super.getAdapter(adapter);
} }
private String remapSourceFile(String filename) {
for (ISourceFileRemapping remapper : remappers) {
String remapped = remapper.remapSourceFile(this.getPath(), filename);
if (!remapped.equals(filename)) {
return remapped;
}
}
return filename;
}
/** /**
* @noreference This method is not intended to be referenced by clients. * @noreference This method is not intended to be referenced by clients.
* @since 6.0 * @since 6.0
@ -157,7 +173,7 @@ public class Executable extends PlatformObject {
for (String filename : symReaderSources) { for (String filename : symReaderSources) {
String orgPath = filename; String orgPath = filename;
filename = ExecutablesManager.getExecutablesManager().remapSourceFile(this, filename); filename = remapSourceFile(filename);
// Sometimes the path in the symbolics will have a different // Sometimes the path in the symbolics will have a different
// case than the actual file system path. Even if the file // case than the actual file system path. Even if the file

View file

@ -27,7 +27,7 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener;
import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.internal.core.executables.StandardExecutableImporter; import org.eclipse.cdt.debug.internal.core.executables.StandardExecutableImporter;
import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFileRemapping; import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFileRemappingFactory;
import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFilesProvider; import org.eclipse.cdt.debug.internal.core.executables.StandardSourceFilesProvider;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IProjectDescription;
@ -73,7 +73,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
private List<IExecutablesChangeListener> changeListeners = Collections.synchronizedList(new ArrayList<IExecutablesChangeListener>()); private List<IExecutablesChangeListener> changeListeners = Collections.synchronizedList(new ArrayList<IExecutablesChangeListener>());
private List<IProjectExecutablesProvider> executableProviders; private List<IProjectExecutablesProvider> executableProviders;
private List<ISourceFilesProvider> sourceFileProviders; private List<ISourceFilesProvider> sourceFileProviders;
private List<ISourceFileRemapping> sourceFileRemappings; private List<ISourceFileRemappingFactory> sourceFileRemappingFactories;
private List<IExecutableImporter> executableImporters; private List<IExecutableImporter> executableImporters;
private boolean DEBUG; private boolean DEBUG;
@ -164,7 +164,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
// add the standard providers // add the standard providers
executableProviders.add(0, new StandardExecutableProvider()); executableProviders.add(0, new StandardExecutableProvider());
sourceFileProviders.add(0, new StandardSourceFilesProvider()); sourceFileProviders.add(0, new StandardSourceFilesProvider());
sourceFileRemappings.add(0, new StandardSourceFileRemapping()); sourceFileRemappingFactories.add(0, new StandardSourceFileRemappingFactory());
executableImporters.add(0, new StandardExecutableImporter()); executableImporters.add(0, new StandardExecutableImporter());
// listen for events we're interested in // listen for events we're interested in
@ -266,26 +266,6 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
return executables; return executables;
} }
/**
* Attempt to remap the path to the given source file in the given executable using
* source file mapping extensions
* @param executable the executable
* @param filePath the absolute path to the source file
* @return the new path to the source file, which was remapped if possible
*
* @since 6.0
*/
public String remapSourceFile(Executable executable, String filePath) {
synchronized (sourceFileRemappings) {
for (ISourceFileRemapping remapping : sourceFileRemappings) {
String remappedPath = remapping.remapSourceFile(executable.getPath(), filePath);
if (!remappedPath.equals(filePath))
return remappedPath;
}
}
return filePath;
}
/** /**
* Import the given executables into the manager * Import the given executables into the manager
* @param fileNames the absolute paths of the executables to import * @param fileNames the absolute paths of the executables to import
@ -651,6 +631,10 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
return provider; return provider;
} }
ISourceFileRemappingFactory[] getSourceFileRemappingFactories() {
return sourceFileRemappingFactories.toArray(new ISourceFileRemappingFactory[sourceFileRemappingFactories.size()]);
}
private void loadExecutableProviderExtensions() { private void loadExecutableProviderExtensions() {
executableProviders = Collections.synchronizedList(new ArrayList<IProjectExecutablesProvider>()); executableProviders = Collections.synchronizedList(new ArrayList<IProjectExecutablesProvider>());
@ -714,7 +698,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
} }
private void loadSoureRemappingExtensions() { private void loadSoureRemappingExtensions() {
sourceFileRemappings = Collections.synchronizedList(new ArrayList<ISourceFileRemapping>()); sourceFileRemappingFactories = Collections.synchronizedList(new ArrayList<ISourceFileRemappingFactory>());
IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(CDebugCorePlugin.PLUGIN_ID + ".SourceRemappingProvider"); //$NON-NLS-1$ IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(CDebugCorePlugin.PLUGIN_ID + ".SourceRemappingProvider"); //$NON-NLS-1$
@ -729,7 +713,7 @@ public class ExecutablesManager extends PlatformObject implements IResourceChang
try { try {
Object extObject = element.createExecutableExtension("class"); //$NON-NLS-1$ Object extObject = element.createExecutableExtension("class"); //$NON-NLS-1$
if (extObject instanceof ISourceFileRemapping) { if (extObject instanceof ISourceFileRemapping) {
sourceFileRemappings.add((ISourceFileRemapping)extObject); sourceFileRemappingFactories.add((ISourceFileRemappingFactory)extObject);
} else { } else {
failed = true; failed = true;
} }

View file

@ -0,0 +1,23 @@
/*******************************************************************************
* Copyright (c) 2010 Freescale Semiconductor 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:
* Freescale Semiconductor - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.core.executables;
import org.eclipse.cdt.core.model.IBinary;
/**
* Factory that creates an ISourceFileRemapping instance for a particular binary
* object
*
* @since 7.0
*/
public interface ISourceFileRemappingFactory {
public ISourceFileRemapping createRemapper(IBinary binary);
}

View file

@ -65,7 +65,15 @@ public class StandardExecutableProvider implements IProjectExecutablesProvider {
IPath exePath = binary.getResource().getLocation(); IPath exePath = binary.getResource().getLocation();
if (exePath == null) if (exePath == null)
exePath = binary.getPath(); exePath = binary.getPath();
executables.add(new Executable(exePath, project, binary.getResource())); List<ISourceFileRemapping> srcRemappers = new ArrayList<ISourceFileRemapping>(2);
ISourceFileRemappingFactory[] factories = ExecutablesManager.getExecutablesManager().getSourceFileRemappingFactories();
for (ISourceFileRemappingFactory factory : factories) {
ISourceFileRemapping remapper = factory.createRemapper(binary);
if (remapper != null) {
srcRemappers.add(remapper);
}
}
executables.add(new Executable(exePath, project, binary.getResource(), srcRemappers.toArray(new ISourceFileRemapping[srcRemappers.size()])));
} }
progress.worked(1); progress.worked(1);

View file

@ -11,49 +11,26 @@
package org.eclipse.cdt.debug.internal.core.executables; package org.eclipse.cdt.debug.internal.core.executables;
import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.core.ISourceFinder;
import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.cdt.debug.core.executables.ISourceFileRemapping; import org.eclipse.cdt.debug.core.executables.ISourceFileRemapping;
import org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocator;
import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
public class StandardSourceFileRemapping implements ISourceFileRemapping { public class StandardSourceFileRemapping implements ISourceFileRemapping {
ISourceFinder srcFinder;
public StandardSourceFileRemapping(IBinary binary) {
srcFinder = (ISourceFinder) binary.getAdapter(ISourceFinder.class);
}
public String remapSourceFile(IPath executable, String filePath) { public String remapSourceFile(IPath executable, String filePath) {
if (srcFinder != null) {
try { String mappedPath = srcFinder.toLocalPath(filePath);
Object[] foundElements = CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().findSourceElements(filePath); if (mappedPath != null) {
return mappedPath;
if (foundElements.length == 0) {
Object foundElement = null;
ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
ILaunch[] launches = launchMgr.getLaunches();
for (ILaunch launch : launches) {
ISourceLocator locator = launch.getSourceLocator();
if (locator instanceof ICSourceLocator || locator instanceof CSourceLookupDirector) {
if (locator instanceof ICSourceLocator)
foundElement = ((ICSourceLocator) locator).findSourceElement(filePath);
else
foundElement = ((CSourceLookupDirector) locator).getSourceElement(filePath);
} }
} }
if (foundElement != null)
foundElements = new Object[] { foundElement };
}
if (foundElements.length == 1 && foundElements[0] instanceof LocalFileStorage) {
LocalFileStorage newLocation = (LocalFileStorage) foundElements[0];
filePath = newLocation.getFullPath().toOSString();
}
} catch (CoreException e) {
}
return filePath; return filePath;
} }

View file

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2010 Freescale Semiconductor 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:
* Freescale Semiconductor - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.core.executables;
import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.cdt.debug.core.executables.ISourceFileRemapping;
import org.eclipse.cdt.debug.core.executables.ISourceFileRemappingFactory;
public class StandardSourceFileRemappingFactory implements ISourceFileRemappingFactory{
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.executables.ISourceFileRemappingFactory#createRemapper(org.eclipse.cdt.core.model.IBinary)
*/
public ISourceFileRemapping createRemapper(IBinary binary) {
return new StandardSourceFileRemapping(binary);
}
}

View file

@ -0,0 +1,363 @@
/*******************************************************************************
* Copyright (c) 2010 Freescale Semiconductor 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:
* Freescale Semiconductor - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.core.srcfinder;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.cdt.core.ISourceFinder;
import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
import org.eclipse.cdt.internal.core.model.ExternalTranslationUnit;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationListener;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.ILaunchesListener;
import org.eclipse.debug.core.model.IPersistableSourceLocator;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
public class CSourceFinder implements ISourceFinder, ILaunchConfigurationListener, ILaunchesListener {
/**
* The binary we are searching files for. We need this reference to find a
* matching ILaunch or ILaunchConfiguration if the caller needs to search
* for files when it doesn't have a debug context.
*/
private IBinary fBinary;
/**
* The locator tied to an ILaunch or an ILaunchConfiguration that is
* associated with the binary. Used for searching when the caller has no
* debug context. See {@link ISourceFinder#toLocalPath(String)} for
* performance considerations that dictate how the locator is chosen. Access
* this only from synchronized blocks as the field is subject to be changed
* by listener invocations.
*/
private ISourceLookupDirector fLaunchLocator;
/**
* A launch configuration doesn't have a source locator instance tied to it.
* Instead, one is created on the fly as needed from attributes in the
* launch config. This is a heavy operation. As an optimization, we cache
* the locators we create and discard when the launch config changes or is
* disposed. Collection is subject to be changed by listener invocations.
*
* @see CSourceFinder#getLocator(ILaunchConfiguration)
*/
private Map<ILaunchConfiguration, ISourceLocator> fConfigLocators = Collections.synchronizedMap(new HashMap<ILaunchConfiguration, ISourceLocator>());
/**
* Constructor.
*
* @param binary
* the executable whose source files we will be asked to find
* locally
*/
public CSourceFinder(IBinary binary) {
assert(binary != null);
fBinary = binary;
ILaunchManager lmgr = DebugPlugin.getDefault().getLaunchManager();
lmgr.addLaunchConfigurationListener(this);
lmgr.addLaunchListener(this);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.ISourceFinder#toLocalPath(java.lang.String)
*/
synchronized public String toLocalPath(String compilationPath) {
try {
Object foundElement = null;
// Find a suitable launch/config locator if we haven't found one yet
if (fLaunchLocator == null) {
ILaunchManager lmgr = DebugPlugin.getDefault().getLaunchManager();
// See if there are any active debug sessions (running, or
// terminated but still in the Debug view) that are targeting
// our executable. If there are then use the first one to
// provide a locator
ILaunch[] launches = lmgr.getLaunches();
for (ILaunch launch : launches) {
ILaunchConfiguration config = launch.getLaunchConfiguration();
if (isMatch(config)) {
ISourceLocator launchLocator = launch.getSourceLocator();
// in practice, a launch locator is always an ISourceLookupDirector
if (launchLocator instanceof ISourceLookupDirector) {
fLaunchLocator = (ISourceLookupDirector)launchLocator;
break;
}
}
}
// If there were no matching launches or none of them
// provided a locator, search the launch configurations
if (fLaunchLocator == null) {
for (ILaunchConfiguration config : lmgr.getLaunchConfigurations()) {
if (isMatch(config)) {
// Search our cache of locators that we
// instantiate for configurations. Create one if
// not found
ISourceLocator configLocator = fConfigLocators.get(config);
if (configLocator == null) {
configLocator = getLocator(config); // heavy operation
fConfigLocators.put(config, configLocator); // cache to avoid next time
}
// In practice, a config's locator is always an ISourceLookupDirector
if (configLocator instanceof ISourceLookupDirector) {
fLaunchLocator = (ISourceLookupDirector)configLocator;
break;
}
}
}
}
}
// Search for the file using the launch/config locator
if (fLaunchLocator != null) {
foundElement = fLaunchLocator.getSourceElement(compilationPath);
}
// If not found, look in the global (common) locator
if (foundElement == null) {
CSourceLookupDirector locator = CDebugCorePlugin.getDefault().getCommonSourceLookupDirector();
foundElement = locator.getSourceElement(compilationPath);
}
return foundElementToPath(foundElement);
}
catch (CoreException exc) {
CDebugCorePlugin.log(exc);
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.ISourceFinder#toLocalPath(org.eclipse.core.runtime.IAdaptable, java.lang.String)
*/
public String toLocalPath(IAdaptable _launch, String compilationPath) {
Object foundElement = null;
ILaunch launch = (ILaunch)_launch.getAdapter(ILaunch.class);
if (launch != null) {
ISourceLocator locator = launch.getSourceLocator();
// in practice, a launch locator is always an ISourceLookupDirector
if (locator instanceof ISourceLookupDirector) {
foundElement = ((ISourceLookupDirector)locator).getSourceElement(compilationPath);
}
}
// If not found, look in the global (common) locator
if (foundElement == null) {
CSourceLookupDirector locator = CDebugCorePlugin.getDefault().getCommonSourceLookupDirector();
foundElement = locator.getSourceElement(compilationPath);
}
return foundElementToPath(foundElement);
}
/**
* Utility method to convert the element found by the source locators to a
* canonical file path
*
* @param foundElement
* the element found by the source locator, or null if not found
* @return the canonical file path of the element
*/
private static String foundElementToPath(Object foundElement) {
if (foundElement != null) {
try {
if (foundElement instanceof IFile) {
IPath path = ((IFile)foundElement).getLocation();
if (path != null) {
File file = path.toFile();
if (file != null) {
return file.getCanonicalPath();
}
}
}
else if (foundElement instanceof LocalFileStorage) {
File file = ((LocalFileStorage)foundElement).getFile();
if (file != null) {
return file.getCanonicalPath();
}
}
else if (foundElement instanceof ExternalTranslationUnit) {
URI uri = ((ExternalTranslationUnit)foundElement).getLocationURI();
if (uri != null) {
IPath path = URIUtil.toPath(uri);
if (path != null) {
File file = path.toFile();
if (file != null) {
return file.getCanonicalPath();
}
}
}
}
} catch (IOException e) {
CDebugCorePlugin.log(e);
}
}
return null;
}
/**
* Utility method to determine if the given launch configuration targets the Binary we are associated with
* @param config
* @return true if the launch config targets our binary, false otherwise
*/
private boolean isMatch(ILaunchConfiguration config) {
IResource resource = (IResource)fBinary.getAdapter(IResource.class);
if (resource != null) {
String binaryPath = resource.getFullPath().toString();
try {
String projectNameConfig = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
String programNameConfig = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$
IProject project = resource.getProject();
if (project != null && project.getName().equals(projectNameConfig)) {
Path path = new Path(programNameConfig);
if (!path.isEmpty()) {
IFile file = project.getFile(path);
if (file != null) {
String fullPath = file.getFullPath().toString();
return fullPath.equals(binaryPath);
}
}
}
} catch (CoreException e) {
// Problem getting attribute from launch config? Not expecting that.
CDebugCorePlugin.log(e);
}
}
return false;
}
/**
* Utility method to instantiate a source locator for a launch
* configuration. A launch configuration doesn't have a source locator
* instance tied to it. Transient instances are created as needed. from
* attributes in the launch config. This is a heavy operation.
*
* @param config
* the launch configuration to create the locator for
* @return the source locator
* @throws CoreException
*/
static private ISourceLocator getLocator(ILaunchConfiguration config) throws CoreException {
String type = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String)null);
if (type == null) {
type = config.getType().getSourceLocatorId();
}
if (type != null) {
IPersistableSourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type);
String memento = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String)null);
if (memento == null) {
locator.initializeDefaults(config);
} else {
if(locator instanceof IPersistableSourceLocator2)
((IPersistableSourceLocator2)locator).initializeFromMemento(memento, config);
else
locator.initializeFromMemento(memento);
}
return locator;
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationAdded(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void launchConfigurationAdded(ILaunchConfiguration config) {
// Don't care.
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void launchConfigurationChanged(ILaunchConfiguration config) {
// We don't care if it's a working copy.
if (config.isWorkingCopy()) {
return;
}
// the source locator attribute may have changed
fConfigLocators.remove(config);
if ((fLaunchLocator != null) && (fLaunchLocator.getLaunchConfiguration() == config)) {
fLaunchLocator = null;
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationRemoved(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void launchConfigurationRemoved(ILaunchConfiguration config) {
fConfigLocators.remove(config);
if ((fLaunchLocator != null) && (fLaunchLocator.getLaunchConfiguration() == config)) {
fLaunchLocator = null;
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchesListener#launchesRemoved(org.eclipse.debug.core.ILaunch[])
*/
synchronized public void launchesRemoved(ILaunch[] launches) {
for (ILaunch launch : launches) {
if (launch.getSourceLocator() == fLaunchLocator) {
fLaunchLocator = null;
return;
}
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchesListener#launchesAdded(org.eclipse.debug.core.ILaunch[])
*/
synchronized public void launchesAdded(ILaunch[] launches) {
// If there's a new launch in town, we need to take it into
// consideration. E.g., if it targets our binary, and we're currently
// searching using an inactive launch configuration's locator, then the
// new launch's locator should take precedence
for (ILaunch launch : launches) {
if (isMatch(launch.getLaunchConfiguration())) {
fLaunchLocator = null;
}
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchesListener#launchesChanged(org.eclipse.debug.core.ILaunch[])
*/
public void launchesChanged(ILaunch[] launches) {
// don't care. I don't think setting a new locator in a launch would result in us getting notified
}
}

View file

@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright (c) 2010 Freescale Semiconductor 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:
* Freescale Semiconductor - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.core.srcfinder;
import org.eclipse.cdt.core.ISourceFinder;
import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.core.runtime.IAdapterFactory;
/**
* Adapter factory that adapts an IBinary object to an ISourceFinder
*/
public class CSourceFinderFactory implements IAdapterFactory {
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class)
*/
@SuppressWarnings("rawtypes")
public Object getAdapter(Object adaptableObject, Class adapterType) {
if (adaptableObject instanceof IBinary) {
if (adapterType.equals(ISourceFinder.class)) {
return new CSourceFinder((IBinary)adaptableObject);
}
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
*/
@SuppressWarnings("rawtypes")
public Class[] getAdapterList() {
return new Class[] { ISourceFinder.class };
}
}

View file

@ -24,6 +24,9 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationListener;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant; import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.IOpenListener;
@ -46,7 +49,7 @@ import org.eclipse.ui.progress.UIJob;
* Displays the list of source files for the executable selected in the * Displays the list of source files for the executable selected in the
* ExecutablesViewer. * ExecutablesViewer.
*/ */
public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant { public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant, ILaunchConfigurationListener {
private static final String P_COLUMN_ORDER_KEY_SF = "columnOrderKeySF"; //$NON-NLS-1$ private static final String P_COLUMN_ORDER_KEY_SF = "columnOrderKeySF"; //$NON-NLS-1$
private static final String P_SORTED_COLUMN_INDEX_KEY_SF = "sortedColumnIndexKeySF"; //$NON-NLS-1$ private static final String P_SORTED_COLUMN_INDEX_KEY_SF = "sortedColumnIndexKeySF"; //$NON-NLS-1$
@ -79,6 +82,11 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
// source lookup as this viewer shows both original and remapped // source lookup as this viewer shows both original and remapped
// locations // locations
CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().addParticipants(new ISourceLookupParticipant[] { this }); CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().addParticipants(new ISourceLookupParticipant[] { this });
// We also look for launch configuration changes, since their source
// locators are involved in source path remapping, too
DebugPlugin.getDefault().getLaunchManager().addLaunchConfigurationListener(this);
sourceFilesTree.addDisposeListener(new DisposeListener() { sourceFilesTree.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) { public void widgetDisposed(DisposeEvent e) {
@ -169,7 +177,7 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
if (sortType == ExecutablesView.ORG_LOCATION) { if (sortType == ExecutablesView.ORG_LOCATION) {
return new ExecutablesViewerComparator(sortType, column_sort_order[ExecutablesView.ORG_LOCATION]) { return new ExecutablesViewerComparator(sortType, column_sort_order[ExecutablesView.ORG_LOCATION]) {
@SuppressWarnings("unchecked") //$NON-NLS-1$ @SuppressWarnings("unchecked")
public int compare(Viewer viewer, Object e1, Object e2) { public int compare(Viewer viewer, Object e1, Object e2) {
if (e1 instanceof ITranslationUnit && e2 instanceof ITranslationUnit) { if (e1 instanceof ITranslationUnit && e2 instanceof ITranslationUnit) {
ITranslationUnit entry1 = (ITranslationUnit) e1; ITranslationUnit entry1 = (ITranslationUnit) e1;
@ -201,6 +209,10 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
} }
public void sourceContainersChanged(ISourceLookupDirector director) { public void sourceContainersChanged(ISourceLookupDirector director) {
refreshContent();
}
private void refreshContent() {
UIJob refreshJob = new UIJob(Messages.SourceFilesViewer_RefreshSourceFiles) { UIJob refreshJob = new UIJob(Messages.SourceFilesViewer_RefreshSourceFiles) {
@Override @Override
@ -241,4 +253,32 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
// default visible columns // default visible columns
return "1,1,0,0,0,0"; //$NON-NLS-1$ return "1,1,0,0,0,0"; //$NON-NLS-1$
} }
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationAdded(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void launchConfigurationAdded(ILaunchConfiguration configuration) {
if (!configuration.isWorkingCopy()) {
refreshContent();
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void launchConfigurationChanged(ILaunchConfiguration configuration) {
if (!configuration.isWorkingCopy()) {
refreshContent();
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationRemoved(org.eclipse.debug.core.ILaunchConfiguration)
*/
public void launchConfigurationRemoved(ILaunchConfiguration configuration) {
if (!configuration.isWorkingCopy()) {
refreshContent();
}
}
} }