/*******************************************************************************
* Copyright (c) 2013, 2015 Red Hat, Inc.
* 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:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.debug.application;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
import org.eclipse.cdt.core.ICompileOptionsFinder;
import org.eclipse.cdt.core.ISymbolReader;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
import org.eclipse.cdt.core.language.settings.providers.IWorkingDirectoryTracker;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager;
import org.eclipse.cdt.debug.application.GCCCompileOptionsParser;
import org.eclipse.cdt.debug.application.Messages;
import org.eclipse.cdt.utils.coff.parser.PEParser;
import org.eclipse.cdt.utils.elf.parser.GNUElfParser;
import org.eclipse.cdt.utils.macho.parser.MachOParser64;
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.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
public class CompilerOptionParser implements IWorkspaceRunnable {
private static final String GCC_COMPILE_OPTIONS_PROVIDER_ID = "org.eclipse.cdt.debug.application.DwarfLanguageSettingsProvider"; //$NON-NLS-1$
private final IProject project;
private final String executable;
public CompilerOptionParser (IProject project, String executable) {
this.project = project;
this.executable = executable;
}
private class CWDTracker implements IWorkingDirectoryTracker {
@Override
public URI getWorkingDirectoryURI() {
return null;
}
}
@Override
public void run(IProgressMonitor monitor) {
try {
// Calculate how many source files we have to process and use that as a basis
// for our work estimate.
IBinaryFile bf = null;
try {
bf = new GNUElfParser().getBinary(new Path(executable));
} catch (IOException e) {
// Will try other parsers
}
// Try Portable Executable (Windows)
if (bf == null) {
try {
bf = new PEParser().getBinary(new Path(executable));
} catch (IOException e) {
// Will try other parsers
}
}
// Try Mach-O (Mac OS X)
if (bf == null) {
bf = new MachOParser64().getBinary(new Path(executable));
try {
bf = new PEParser().getBinary(new Path(executable));
} catch (IOException e) {
// ignored, see below early return
}
}
if (bf == null) {
// Doesn't look like a known binary but we can let the debugger try to
// debug it. This means that the project will likely be
// incomplete and this will affect code navigation.
return;
}
ISymbolReader reader = bf.getAdapter(ISymbolReader.class);
String[] sourceFiles = reader
.getSourceFiles();
monitor.beginTask(Messages.GetCompilerOptions, sourceFiles.length * 2 + 1);
for (String sourceFile : sourceFiles) {
IPath sourceFilePath = new Path(
sourceFile);
String sourceName = sourceFilePath
.lastSegment();
IContainer c = createFromRoot(project,
new Path(sourceFile));
Path sourceNamePath = new Path(
sourceName);
IFile source = c
.getFile(sourceNamePath);
if (!source.isLinked()) {
try {
source.createLink(sourceFilePath, 0,
null);
} catch (Exception e) {
// ignore file not found errors since certain headers might not be found
// or are a different version from that used to compile the source (e.g. std headers)
}
}
monitor.worked(1);
}
// Find the GCCCompileOptions LanguageSettingsProvider for the configuration.
IWorkingDirectoryTracker cwdTracker = new CWDTracker();
ICProjectDescriptionManager projDescManager = CCorePlugin
.getDefault().getProjectDescriptionManager();
ICProjectDescription projDesc = projDescManager
.getProjectDescription(project,
false);
ICConfigurationDescription ccdesc = projDesc
.getActiveConfiguration();
GCCCompileOptionsParser parser = null;
if (ccdesc instanceof ILanguageSettingsProvidersKeeper) {
ILanguageSettingsProvidersKeeper keeper = (ILanguageSettingsProvidersKeeper)ccdesc;
List<ILanguageSettingsProvider> list = keeper.getLanguageSettingProviders();
for (ILanguageSettingsProvider p : list) {
// System.out.println("language settings provider " + p.getId());
if (p.getId().equals(GCC_COMPILE_OPTIONS_PROVIDER_ID)) {
parser = (GCCCompileOptionsParser)p;
}
}
}
// Start up the parser and process lines generated from the .debug_macro section.
parser.startup(ccdesc, cwdTracker);
// Get compile options for each source file and process via the parser
// to generate LanguageSettingsEntries.
if (reader instanceof
ICompileOptionsFinder) {
ICompileOptionsFinder f =
(ICompileOptionsFinder) reader;
for (String fileName : sourceFiles) {
parser.setCurrentResourceName(fileName);
parser.processLine(f
.getCompileOptions(fileName));
monitor.worked(1);
}
parser.shutdown(); // this will serialize the data to an xml file and create an event.
monitor.worked(1);
}
} catch (CoreException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
monitor.done();
}
private IContainer createFromRoot(IProject exeProject, IPath path)
throws CoreException {
int segmentCount = path.segmentCount() - 1;
IContainer currentFolder = exeProject;
for (int i = 0; i < segmentCount; i++) {
currentFolder = currentFolder.getFolder(new Path(path.segment(i)));
if (!currentFolder.exists()) {
((IFolder) currentFolder).create(IResource.VIRTUAL
| IResource.DERIVED, true, new NullProgressMonitor());
}
}
return currentFolder;
}
};