diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java index c03a5e11221..5df9ac5fae3 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/Executable.java @@ -12,21 +12,15 @@ package org.eclipse.cdt.debug.core.executables; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.IBinaryParser; -import org.eclipse.cdt.core.ISymbolReader; -import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ITranslationUnit; -import org.eclipse.cdt.internal.core.model.BinaryParserConfig; import org.eclipse.cdt.internal.core.model.CModelManager; import org.eclipse.cdt.internal.core.model.ExternalTranslationUnit; import org.eclipse.cdt.internal.core.model.TranslationUnit; @@ -35,7 +29,6 @@ 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.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; @@ -46,6 +39,38 @@ import org.eclipse.core.runtime.content.IContentTypeManager; public class Executable extends PlatformObject { + static public boolean isExecutableFile(IPath path) { + // ignore directories + if (path.toFile().isDirectory()) { + return false; + } + // Only if file has no extension, has an extension that is an integer + // or is a binary file content type + String ext = path.getFileExtension(); + if (ext != null) { + // shared libraries often have a version number + boolean isNumber = true; + for (int i = 0; i < ext.length(); ++i) + if (!Character.isDigit(ext.charAt(i))) { + isNumber = false; + break; + } + if (!isNumber) { + boolean isBinary = false; + final IContentTypeManager ctm = Platform.getContentTypeManager(); + final IContentType ctbin = ctm.getContentType(CCorePlugin.CONTENT_TYPE_BINARYFILE); + final IContentType[] cts = ctm.findContentTypesFor(path.toFile().getName()); + for (int i = 0; !isBinary && i < cts.length; i++) { + isBinary = cts[i].isKindOf(ctbin); + } + if (!isBinary) { + return false; + } + } + } + return true; + } + private IPath path; private IProject project; private String name; @@ -96,116 +121,6 @@ public class Executable extends PlatformObject { return super.getAdapter(adapter); } - static public boolean isExecutableFile(IPath path) { - // ignore directories - if (path.toFile().isDirectory()) { - return false; - } - // Only if file has no extension, has an extension that is an integer - // or is a binary file content type - String ext = path.getFileExtension(); - if (ext != null) { - // shared libraries often have a version number - boolean isNumber = true; - for (int i = 0; i < ext.length(); ++i) - if (!Character.isDigit(ext.charAt(i))) { - isNumber = false; - break; - } - if (!isNumber) { - boolean isBinary = false; - final IContentTypeManager ctm = Platform.getContentTypeManager(); - final IContentType ctbin = ctm.getContentType(CCorePlugin.CONTENT_TYPE_BINARYFILE); - final IContentType[] cts = ctm.findContentTypesFor(path.toFile().getName()); - for (int i = 0; !isBinary && i < cts.length; i++) { - isBinary = cts[i].isKindOf(ctbin); - } - if (!isBinary) { - return false; - } - } - } - return true; - } - - public IBinaryFile createBinaryFile() { - CModelManager factory = CModelManager.getDefault(); - - if (resource != null && resource instanceof IFile) - return factory.createBinaryFile((IFile) resource); - - BinaryParserConfig[] parsers = factory.getBinaryParser(getProject()); - if (parsers.length == 0) { - return null; - } - - if (!isExecutableFile(path)) - return null; - - File f = new File(path.toOSString()); - if (f.length() == 0) { - return null; - } - - int hints = 0; - - for (int i = 0; i < parsers.length; i++) { - IBinaryParser parser = null; - try { - parser = parsers[i].getBinaryParser(); - if (parser.getHintBufferSize() > hints) { - hints = parser.getHintBufferSize(); - } - } catch (CoreException e) { - } - } - byte[] bytes = new byte[hints]; - if (hints > 0) { - InputStream is = null; - try { - is = new FileInputStream(path.toFile()); - int count = 0; - // Make sure we read up to 'hints' bytes if we possibly can - while (count < hints) { - int bytesRead = is.read(bytes, count, hints - count); - if (bytesRead < 0) - break; - count += bytesRead; - } - if (count > 0 && count < bytes.length) { - byte[] array = new byte[count]; - System.arraycopy(bytes, 0, array, 0, count); - bytes = array; - } - } catch (IOException e) { - return null; - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - // ignore - } - } - } - } - - for (int i = 0; i < parsers.length; i++) { - try { - IBinaryParser parser = parsers[i].getBinaryParser(); - if (parser.isBinary(bytes, path)) { - IBinaryFile binFile = parser.getBinary(bytes, path); - if (binFile != null) { - return binFile; - } - } - } catch (IOException e) { - } catch (CoreException e) { - } - } - return null; - } - public TranslationUnit[] getSourceFiles(IProgressMonitor monitor) { if (!refreshSourceFiles) @@ -219,90 +134,83 @@ public class Executable extends PlatformObject { sourceFiles.clear(); CModelManager factory = CModelManager.getDefault(); - IBinaryFile bin = createBinaryFile(); - if (bin != null) { - ICProject cproject = factory.create(project); + ICProject cproject = factory.create(project); - ISymbolReader symbolreader = (ISymbolReader) bin.getAdapter(ISymbolReader.class); - if (symbolreader != null) { - String[] symReaderSources = symbolreader.getSourceFiles(); - if (symReaderSources != null && symReaderSources.length > 0) { - for (int i = 0; i < symReaderSources.length; i++) { - String filename = symReaderSources[i]; - String orgPath = filename; + String[] symReaderSources = ExecutablesManager.getExecutablesManager().getSourceFiles(this, monitor); + if (symReaderSources != null && symReaderSources.length > 0) { + for (int i = 0; i < symReaderSources.length; i++) { + String filename = symReaderSources[i]; + String orgPath = filename; - filename = ExecutablesManager.getExecutablesManager().remapSourceFile(filename); + filename = ExecutablesManager.getExecutablesManager().remapSourceFile(filename); - // Sometimes the path in the symbolics will have a - // different - // case than the actual file system path. Even if the - // file - // system is not case sensitive this will confuse the - // Path - // class. - // So make sure the path is canonical, otherwise - // breakpoints - // won't be resolved, etc.. - // Also check for relative path names and attempt to - // resolve - // them relative to the executable. + // Sometimes the path in the symbolics will have a + // different + // case than the actual file system path. Even if the + // file + // system is not case sensitive this will confuse the + // Path + // class. + // So make sure the path is canonical, otherwise + // breakpoints + // won't be resolved, etc.. + // Also check for relative path names and attempt to + // resolve + // them relative to the executable. - try { - File file = new File(filename); - if (file.exists()) { - filename = file.getCanonicalPath(); - } else if (filename.startsWith(".")) { //$NON-NLS-1$ - file = new File(bin.getPath().removeLastSegments(1).toOSString(), filename); - filename = file.getCanonicalPath(); - } - } catch (IOException e) { // Do nothing. - } + try { + File file = new File(filename); + if (file.exists()) { + filename = file.getCanonicalPath(); + } else if (filename.startsWith(".")) { //$NON-NLS-1$ + file = new File(path.removeLastSegments(1).toOSString(), filename); + filename = file.getCanonicalPath(); + } + } catch (IOException e) { // Do nothing. + } - // See if this source file is already in the project. - // We check this to determine if we should create a - // TranslationUnit or ExternalTranslationUnit - IFile sourceFile = getProject().getFile(filename); - IPath path = new Path(filename); + // See if this source file is already in the project. + // We check this to determine if we should create a + // TranslationUnit or ExternalTranslationUnit + IFile sourceFile = getProject().getFile(filename); + IPath path = new Path(filename); - IFile wkspFile = null; - if (sourceFile.exists()) - wkspFile = sourceFile; - else { - IFile[] filesInWP = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(path); + IFile wkspFile = null; + if (sourceFile.exists()) + wkspFile = sourceFile; + else { + IFile[] filesInWP = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(path); - for (int j = 0; j < filesInWP.length; j++) { - if (filesInWP[j].isAccessible()) { - wkspFile = filesInWP[j]; - break; - } - } - } - - // Create a translation unit for this file and add it as - // a child of the binary - String id = CoreModel.getRegistedContentTypeId(sourceFile.getProject(), sourceFile.getName()); - - if (id != null) { // Don't add files we can't get an - // ID for. - TranslationUnit tu; - if (wkspFile != null) - tu = new TranslationUnit(cproject, wkspFile, id); - else - tu = new ExternalTranslationUnit(cproject, URIUtil.toURI(path), id); - - sourceFiles.add(tu); - - if (!orgPath.equals(filename)) { - remappedPaths.put(tu, orgPath); - } + for (int j = 0; j < filesInWP.length; j++) { + if (filesInWP[j].isAccessible()) { + wkspFile = filesInWP[j]; + break; } } } + + // Create a translation unit for this file and add it as + // a child of the binary + String id = CoreModel.getRegistedContentTypeId(sourceFile.getProject(), sourceFile.getName()); + + if (id != null) { // Don't add files we can't get an + // ID for. + TranslationUnit tu; + if (wkspFile != null) + tu = new TranslationUnit(cproject, wkspFile, id); + else + tu = new ExternalTranslationUnit(cproject, URIUtil.toURI(path), id); + + sourceFiles.add(tu); + + if (!orgPath.equals(filename)) { + remappedPaths.put(tu, orgPath); + } + } } - } - + refreshSourceFiles = false; return sourceFiles.toArray(new TranslationUnit[sourceFiles.size()]) ; } diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java index bccdd61886e..f846f1f753b 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ExecutablesManager.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.debug.core.executables; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import org.eclipse.core.runtime.IPath; @@ -37,6 +38,7 @@ public class ExecutablesManager extends PlatformObject { private List changeListeners = Collections.synchronizedList(new ArrayList()); private List sourceFileRemappings = Collections.synchronizedList(new ArrayList()); private List executableProviders = Collections.synchronizedList(new ArrayList()); + private List sourceFileProviders = Collections.synchronizedList(new ArrayList()); private List executableImporters = Collections.synchronizedList(new ArrayList()); private boolean refreshNeeded = true; private boolean tempDisableRefresh = false; @@ -62,6 +64,7 @@ public class ExecutablesManager extends PlatformObject { addSourceFileRemapping(new StandardSourceFileRemapping()); addExecutableImporter(new StandardExecutableImporter()); addExecutablesProvider(new StandardExecutableProvider()); + addSourceFilesProvider(new StandardSourceFilesProvider()); } public void addExecutablesChangeListener(IExecutablesChangeListener listener) { @@ -92,6 +95,14 @@ public class ExecutablesManager extends PlatformObject { executableProviders.add(provider); } + public void addSourceFilesProvider(ISourceFilesProvider provider) { + sourceFileProviders.add(provider); + } + + public void removeSourceFilesProvider(ISourceFilesProvider provider) { + sourceFileProviders.remove(provider); + } + public void removeExecutablesProvider(IExecutableProvider provider) { executableProviders.remove(provider); } @@ -177,6 +188,10 @@ public class ExecutablesManager extends PlatformObject { return executableProviders.toArray(new IExecutableProvider[executableProviders.size()]); } + public ISourceFilesProvider[] getSourceFileProviders() { + return sourceFileProviders.toArray(new ISourceFilesProvider[sourceFileProviders.size()]); + } + public IExecutableImporter[] getExecutableImporters() { return executableImporters.toArray(new IExecutableImporter[executableImporters.size()]); } @@ -198,4 +213,34 @@ public class ExecutablesManager extends PlatformObject { return false; } + public String[] getSourceFiles(final Executable executable, + IProgressMonitor monitor) { + String[] result = new String[0]; + synchronized (sourceFileProviders) { + Collections.sort(sourceFileProviders, new Comparator() { + + public int compare(ISourceFilesProvider arg0, ISourceFilesProvider arg1) { + int p0 = arg0.getPriority(executable); + int p1 = arg1.getPriority(executable); + if (p0 < p1) + return 1; + if (p0 > p1) + return -1; + return 0; + }}); + + monitor.beginTask("Finding source files in " + executable.getName(), sourceFileProviders.size()); + for (ISourceFilesProvider provider : sourceFileProviders) { + String[] sourceFiles = provider.getSourceFiles(executable, new SubProgressMonitor(monitor, 1)); + if (sourceFiles.length > 0) + { + result = sourceFiles; + break; + } + } + monitor.done(); + } + return result; + } + } \ No newline at end of file diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFilesProvider.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFilesProvider.java new file mode 100644 index 00000000000..f6171005db4 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/ISourceFilesProvider.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2008 Nokia 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: + * Nokia - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.core.executables; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * ISourceFileProvider supplies a list of source files used by a given Executable. + * + * @author Ken Ryall + * + */ + +public interface ISourceFilesProvider { + + static int LOW_PRIORITY = 25; + static int NORMAL_PRIORITY = 50; + static int HIGH_PRIORITY = 75; + + /** + * Gets the priority to be used for this executable. + * The priority is used by the Executables Manager when multiple ISourceFilesProviders are available. + * ISourceFilesProvider.getSourceFiles will be called for each one in priority order and will use the + * first one that returns a non empty result. + * + * @param executable + * @return the priority level to be used for this ISourceFilesProvider + */ + int getPriority(Executable executable); + + /** + * Returns a list of source files used by an executable. + * @param executable + * @param monitor + * @return The list of source files for the executable. These may be file name, full or partial paths. + */ + String[] getSourceFiles(Executable executable, IProgressMonitor monitor); + +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableImporter.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableImporter.java index be2b8fda4ad..6bae84ad5b7 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableImporter.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardExecutableImporter.java @@ -22,7 +22,9 @@ import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IWorkspace; @@ -114,18 +116,32 @@ public class StandardExecutableImporter implements IExecutableImporter { monitor.done(); } - private void importExecutable(IProject exeProject, String path) { + private IContainer createFromRoot(IProject exeProject, IPath path) throws CoreException { + int segmentCount = path.segmentCount() - 1; + IContainer currentFolder = exeProject; - IPath location = Path.fromOSString(path); - String executableName = location.toFile().getName(); - IFile exeFile = exeProject.getProject().getFile(executableName); - if (!exeFile.exists() && validateBinaryParsers(exeProject, new File(path))) { - try { - exeFile.createLink(location, 0, null); - } catch (Exception e) { + for (int i = 0; i < segmentCount; i++) { + currentFolder = currentFolder.getFolder(new Path(path.segment(i))); + if (!currentFolder.exists()) { + ((IFolder) currentFolder).create(false, true, new NullProgressMonitor()); } } + return currentFolder; + } + + private void importExecutable(IProject exeProject, String path) { + IPath location = Path.fromOSString(path); + String executableName = location.toFile().getName(); + try { + IContainer fileContainer = createFromRoot(exeProject, location); + IFile exeFile = fileContainer.getFile(new Path(executableName)); + if (!exeFile.exists() && validateBinaryParsers(exeProject, new File(path))) { + exeFile.createLink(location, 0, null); + } + } catch (CoreException e) { + CDebugCorePlugin.log(e); + } } private boolean isExtensionVisible(IExtension ext) { diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardSourceFilesProvider.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardSourceFilesProvider.java new file mode 100644 index 00000000000..d8cf3f17474 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/executables/StandardSourceFilesProvider.java @@ -0,0 +1,120 @@ +package org.eclipse.cdt.debug.core.executables; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.cdt.core.IBinaryParser; +import org.eclipse.cdt.core.ISymbolReader; +import org.eclipse.cdt.core.IBinaryParser.IBinaryFile; +import org.eclipse.cdt.internal.core.model.BinaryParserConfig; +import org.eclipse.cdt.internal.core.model.CModelManager; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.PlatformObject; + +public class StandardSourceFilesProvider extends PlatformObject implements ISourceFilesProvider { + + public IBinaryFile createBinaryFile(Executable executable) { + CModelManager factory = CModelManager.getDefault(); + + IResource resource = executable.getResource(); + IPath path = executable.getPath(); + + if (resource != null && resource instanceof IFile) + return factory.createBinaryFile((IFile) resource); + + BinaryParserConfig[] parsers = factory.getBinaryParser(executable.getProject()); + if (parsers.length == 0) { + return null; + } + + if (!Executable.isExecutableFile(executable.getPath())) + return null; + + File f = new File(path.toOSString()); + if (f.length() == 0) { + return null; + } + + int hints = 0; + + for (int i = 0; i < parsers.length; i++) { + IBinaryParser parser = null; + try { + parser = parsers[i].getBinaryParser(); + if (parser.getHintBufferSize() > hints) { + hints = parser.getHintBufferSize(); + } + } catch (CoreException e) { + } + } + byte[] bytes = new byte[hints]; + if (hints > 0) { + InputStream is = null; + try { + is = new FileInputStream(path.toFile()); + int count = 0; + // Make sure we read up to 'hints' bytes if we possibly can + while (count < hints) { + int bytesRead = is.read(bytes, count, hints - count); + if (bytesRead < 0) + break; + count += bytesRead; + } + if (count > 0 && count < bytes.length) { + byte[] array = new byte[count]; + System.arraycopy(bytes, 0, array, 0, count); + bytes = array; + } + } catch (IOException e) { + return null; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + } + } + + for (int i = 0; i < parsers.length; i++) { + try { + IBinaryParser parser = parsers[i].getBinaryParser(); + if (parser.isBinary(bytes, path)) { + IBinaryFile binFile = parser.getBinary(bytes, path); + if (binFile != null) { + return binFile; + } + } + } catch (IOException e) { + } catch (CoreException e) { + } + } + return null; + } + + public String[] getSourceFiles(Executable executable, IProgressMonitor monitor) { + + IBinaryFile bin = createBinaryFile(executable); + if (bin != null) { + ISymbolReader symbolreader = (ISymbolReader) bin.getAdapter(ISymbolReader.class); + if (symbolreader != null) { + return symbolreader.getSourceFiles(); + } + + } + return new String[0]; + } + + public int getPriority(Executable executable) { + return ISourceFilesProvider.NORMAL_PRIORITY; + } + +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/BaseViewer.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/BaseViewer.java index 14ffe305506..535a241e931 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/BaseViewer.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/BaseViewer.java @@ -148,7 +148,7 @@ abstract class BaseViewer extends TreeViewer { } String[] columns = visibleColumns.split(","); //$NON-NLS-1$ for (int i=0; i