/*******************************************************************************
* Copyright (c) 2004, 2010 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
* Ken Ryall (Nokia) - Support for breakpoint actions (bug 118308)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.debug.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager;
import org.eclipse.cdt.debug.core.command.CCommandAdapterFactory;
import org.eclipse.cdt.debug.core.disassembly.IDisassemblyContextService;
import org.eclipse.cdt.debug.core.model.IRestart;
import org.eclipse.cdt.debug.core.sourcelookup.AbsolutePathSourceContainer;
import org.eclipse.cdt.debug.core.sourcelookup.CProjectSourceContainer;
import org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation;
import org.eclipse.cdt.debug.core.sourcelookup.ProgramRelativePathSourceContainer;
import org.eclipse.cdt.debug.internal.core.DebugConfiguration;
import org.eclipse.cdt.debug.internal.core.ICDebugInternalConstants;
import org.eclipse.cdt.debug.internal.core.ListenerList;
import org.eclipse.cdt.debug.internal.core.SessionManager;
import org.eclipse.cdt.debug.internal.core.Trace;
import org.eclipse.cdt.debug.internal.core.disassembly.DisassemblyContextService;
import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
import org.eclipse.cdt.debug.internal.core.sourcelookup.CommonSourceLookupDirector;
import org.eclipse.cdt.debug.internal.core.sourcelookup.SourceUtils;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchDelegate;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.osgi.framework.BundleContext;
/**
* The plugin class for C/C++ debug core.
*/
public class CDebugCorePlugin extends Plugin {
/**
* The plug-in identifier (value <code>"org.eclipse.cdt.debug.core"</code>).
*/
public static final String PLUGIN_ID = "org.eclipse.cdt.debug.core" ; //$NON-NLS-1$
/**
* Status code indicating an unexpected internal error.
*/
public static final int INTERNAL_ERROR = 1000;
/**
* The shared instance.
*/
private static CDebugCorePlugin plugin;
private HashMap<String, DebugConfiguration> fDebugConfigurations;
private HashSet<String> fActiveDebugConfigurations;
/**
* Breakpoint listener list.
*/
private ListenerList fBreakpointListeners;
/**
* Breakpoint action manager.
*/
private BreakpointActionManager breakpointActionManager;
private DisassemblyContextService fDisassemblyContextService;
public static final String CDEBUGGER_EXTENSION_POINT_ID = "CDebugger"; //$NON-NLS-1$
public static final String DEBUGGER_ELEMENT = "debugger"; //$NON-NLS-1$
public static final String BREAKPOINT_ACTION_EXTENSION_POINT_ID = "BreakpointActionType"; //$NON-NLS-1$
public static final String ACTION_TYPE_ELEMENT = "actionType"; //$NON-NLS-1$
public static final String BREAKPOINT_EXTENSION_EXTENSION_POINT_ID = "BreakpointExtension"; //$NON-NLS-1$
public static final String BREAKPOINT_EXTENSION_ELEMENT = "breakpointExtension"; //$NON-NLS-1$
/**
* Dummy source lookup director needed to manage common source containers.
*/
private CommonSourceLookupDirector fCommonSourceLookupDirector;
private SessionManager fSessionManager = null;
/**
* The constructor.
*/
public CDebugCorePlugin() {
super();
plugin = this;
}
/**
* Returns the shared instance.
*
* @return the shared instance
*/
public static CDebugCorePlugin getDefault() {
return plugin;
}
/**
* Returns the workspace instance.
*
* @return the workspace instance
*/
public static IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* Convenience method which returns the unique identifier of this plugin.
*
* @return the unique identifier of this plugin
*/
public static String getUniqueIdentifier() {
return PLUGIN_ID;
}
/**
* Logs the specified throwable with this plug-in's log.
*
* @param t throwable to log
*/
public static void log(Throwable t) {
Throwable top = t;
if (t instanceof DebugException) {
DebugException de = (DebugException)t;
IStatus status = de.getStatus();
if (status.getException() != null) {
top = status.getException();
}
}
// this message is intentionally not internationalized, as an exception may
// be due to the resource bundle itself
log(new Status(IStatus.ERROR, getUniqueIdentifier(), INTERNAL_ERROR, "Internal error logged from CDI Debug: ", top)); //$NON-NLS-1$
}
/**
* Logs the specified status with this plug-in's log.
*
* @param status status to log
*/
public static void log(IStatus status) {
getDefault().getLog().log(status);
}
/**
* Logs the specified message with this plug-in's log.
*
* @param status status to log
*/
public static void log(String message) {
getDefault().getLog().log(new Status(IStatus.ERROR, CDIDebugModel.getPluginIdentifier(), INTERNAL_ERROR, message, null));
}
private void initializeDebugConfiguration() {
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(getUniqueIdentifier(), CDEBUGGER_EXTENSION_POINT_ID);
IConfigurationElement[] infos = extensionPoint.getConfigurationElements();
fDebugConfigurations = new HashMap<String, DebugConfiguration>(infos.length);
for(int i = 0; i < infos.length; i++) {
IConfigurationElement configurationElement = infos[i];
if (configurationElement.getName().equals(DEBUGGER_ELEMENT)) {
DebugConfiguration configType = new DebugConfiguration(configurationElement);
fDebugConfigurations.put(configType.getID(), configType);
}
}
}
private void initializeActiveDebugConfigurations() {
fActiveDebugConfigurations = new HashSet<String>(getDebugConfigurations().length);
fActiveDebugConfigurations.addAll(fDebugConfigurations.keySet());
String[] filteredTypes = CDebugCorePlugin.getDefault().getPluginPreferences().getString(ICDebugConstants.PREF_FILTERED_DEBUGGERS).split("\\,"); //$NON-NLS-1$
fActiveDebugConfigurations.removeAll(Arrays.asList(filteredTypes));
}
public ICDebugConfiguration[] getDebugConfigurations() {
if (fDebugConfigurations == null) {
initializeDebugConfiguration();
}
return fDebugConfigurations.values().toArray(new ICDebugConfiguration[fDebugConfigurations.size()]);
}
public ICDebugConfiguration[] getActiveDebugConfigurations() {
if (fDebugConfigurations == null) {
initializeDebugConfiguration();
}
if (fActiveDebugConfigurations == null) {
initializeActiveDebugConfigurations();
}
ArrayList<DebugConfiguration> list = new ArrayList<DebugConfiguration>(fActiveDebugConfigurations.size());
for (String id : fActiveDebugConfigurations) {
DebugConfiguration dc = fDebugConfigurations.get(id);
if (dc != null)
list.add(dc);
}
return list.toArray(new ICDebugConfiguration[list.size()]);
}
public ICDebugConfiguration[] getDefaultActiveDebugConfigurations() {
List<String> filtered = Arrays.asList(CDebugCorePlugin.getDefault().getPluginPreferences().getDefaultString(ICDebugConstants.PREF_FILTERED_DEBUGGERS).split("\\,")); //$NON-NLS-1$
HashMap<String, DebugConfiguration> all = new HashMap<String, DebugConfiguration>(fDebugConfigurations);
all.keySet().removeAll(filtered);
return all.values().toArray(new ICDebugConfiguration[all.size()]);
}
public void saveFilteredDebugConfigurations(ICDebugConfiguration[] configurations) {
disposeActiveDebugConfigurations();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < configurations.length; ++i) {
sb.append(configurations[i].getID()).append(',');
}
CDebugCorePlugin.getDefault().getPluginPreferences().setValue(ICDebugConstants.PREF_FILTERED_DEBUGGERS, sb.toString());
CDebugCorePlugin.getDefault().savePluginPreferences();
}
public void saveDefaultDebugConfiguration(String id) {
CDebugCorePlugin.getDefault().getPluginPreferences().setValue(ICDebugConstants.PREF_DEFAULT_DEBUGGER_TYPE, (id != null) ? id : ""); //$NON-NLS-1$
}
public ICDebugConfiguration getDefaultDebugConfiguration() {
ICDebugConfiguration result = null;
try {
result = getDebugConfiguration(CDebugCorePlugin.getDefault().getPluginPreferences().getString(ICDebugConstants.PREF_DEFAULT_DEBUGGER_TYPE));
} catch (CoreException e) {
}
return result;
}
public ICDebugConfiguration getDefaultDefaultDebugConfiguration() {
ICDebugConfiguration result = null;
try {
result = getDebugConfiguration(CDebugCorePlugin.getDefault().getPluginPreferences().getDefaultString(ICDebugConstants.PREF_DEFAULT_DEBUGGER_TYPE));
} catch (CoreException e) {
}
if (result == null) {
}
return result;
}
public boolean isDefaultDebugConfiguration(String id) {
return id.compareTo(CDebugCorePlugin.getDefault().getPluginPreferences().getString(ICDebugConstants.PREF_DEFAULT_DEBUGGER_TYPE)) == 0;
}
public ICDebugConfiguration getDebugConfiguration(String id) throws CoreException {
if (fDebugConfigurations == null) {
initializeDebugConfiguration();
}
ICDebugConfiguration dbgCfg = fDebugConfigurations.get(id);
if (dbgCfg == null) {
IStatus status = new Status(IStatus.ERROR, getUniqueIdentifier(), 100, DebugCoreMessages.getString("CDebugCorePlugin.0"), null); //$NON-NLS-1$
throw new CoreException(status);
}
return dbgCfg;
}
protected SessionManager getSessionManager() {
return fSessionManager;
}
protected void setSessionManager(SessionManager sm) {
if (fSessionManager != null)
fSessionManager.dispose();
fSessionManager = sm;
}
public void saveCommonSourceLocations(ICSourceLocation[] locations) {
CDebugCorePlugin.getDefault().getPluginPreferences().setValue(ICDebugConstants.PREF_SOURCE_LOCATIONS, SourceUtils.getCommonSourceLocationsMemento(locations));
}
public ICSourceLocation[] getCommonSourceLocations() {
return SourceUtils.getCommonSourceLocationsFromMemento(CDebugCorePlugin.getDefault().getPluginPreferences().getString(ICDebugConstants.PREF_SOURCE_LOCATIONS));
}
/**
* Adds the given breakpoint listener to the debug model.
*
* @param listener breakpoint listener
*/
public void addCBreakpointListener(ICBreakpointListener listener) {
fBreakpointListeners.add(listener);
}
/**
* Removes the given breakpoint listener from the debug model.
*
* @param listener breakpoint listener
*/
public void removeCBreakpointListener(ICBreakpointListener listener) {
fBreakpointListeners.remove(listener);
}
/**
* Returns the list of breakpoint listeners registered with this plugin.
*
* @return the list of breakpoint listeners registered with this plugin
*/
public Object[] getCBreakpointListeners() {
if (fBreakpointListeners == null)
return new Object[0];
return fBreakpointListeners.getListeners();
}
private void createBreakpointListenersList() {
fBreakpointListeners = new ListenerList(1);
}
private void disposeBreakpointListenersList() {
fBreakpointListeners.removeAll();
fBreakpointListeners = null;
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
Trace.init();
initializeCommonSourceLookupDirector();
createCommandAdapterFactory();
createBreakpointListenersList();
createDisassemblyContextService();
setSessionManager(new SessionManager());
setDefaultLaunchDelegates();
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
@Override
public void stop(BundleContext context) throws Exception {
setSessionManager(null);
disposeDisassemblyContextService();
disposeBreakpointListenersList();
disposeCommonSourceLookupDirector();
disposeDebugConfigurations();
super.stop(context);
}
private void createCommandAdapterFactory() {
IAdapterManager manager= Platform.getAdapterManager();
CCommandAdapterFactory actionFactory = new CCommandAdapterFactory();
manager.registerAdapters(actionFactory, IRestart.class);
}
private void initializeCommonSourceLookupDirector() {
if (fCommonSourceLookupDirector == null) {
fCommonSourceLookupDirector = new CommonSourceLookupDirector();
boolean convertingFromLegacyFormat = false;
String newMemento = CDebugCorePlugin.getDefault().getPluginPreferences().getString(ICDebugInternalConstants.PREF_DEFAULT_SOURCE_CONTAINERS);
if (newMemento.isEmpty()) {
newMemento = CDebugCorePlugin.getDefault().getPluginPreferences().getString(ICDebugInternalConstants.PREF_COMMON_SOURCE_CONTAINERS);
convertingFromLegacyFormat = true;
}
if (newMemento.isEmpty()) {
// Add the participant(s). This happens as part of
// initializeFromMemento(), but since we're not calling it, we
// need to do this explicitly. See 299583.
fCommonSourceLookupDirector.initializeParticipants();
// Convert source locations to source containers
convertSourceLocations(fCommonSourceLookupDirector);
} else {
try {
fCommonSourceLookupDirector.initializeFromMemento(newMemento);
} catch (CoreException e) {
log(e.getStatus());
}
}
if (convertingFromLegacyFormat) {
// Add three source containers that used to be present implicitly.
ISourceContainer[] oldContainers = fCommonSourceLookupDirector.getSourceContainers();
ISourceContainer[] containers = new ISourceContainer[oldContainers.length + 3];
int i = 0;
containers[i++] = new AbsolutePathSourceContainer();
containers[i++] = new ProgramRelativePathSourceContainer();
containers[i++] = new CProjectSourceContainer(null, true);
System.arraycopy(oldContainers, 0, containers, i, oldContainers.length);
fCommonSourceLookupDirector.setSourceContainers(containers);
}
}
}
private void disposeCommonSourceLookupDirector() {
if (fCommonSourceLookupDirector != null)
fCommonSourceLookupDirector.dispose();
}
public CSourceLookupDirector getCommonSourceLookupDirector() {
return fCommonSourceLookupDirector;
}
private void convertSourceLocations(CommonSourceLookupDirector director) {
director.setSourceContainers(SourceUtils.convertSourceLocations(getCommonSourceLocations()));
}
private void disposeActiveDebugConfigurations() {
if (fActiveDebugConfigurations != null) {
fActiveDebugConfigurations.clear();
fActiveDebugConfigurations = null;
}
}
private void disposeDebugConfigurations() {
disposeActiveDebugConfigurations();
if (fDebugConfigurations != null) {
fDebugConfigurations.clear();
fDebugConfigurations = null;
}
}
public BreakpointActionManager getBreakpointActionManager() {
if (breakpointActionManager == null)
breakpointActionManager = new BreakpointActionManager();
return breakpointActionManager;
}
private void createDisassemblyContextService() {
fDisassemblyContextService = new DisassemblyContextService();
}
public IDisassemblyContextService getDisassemblyContextService() {
return fDisassemblyContextService;
}
private void disposeDisassemblyContextService() {
if (fDisassemblyContextService != null)
fDisassemblyContextService.dispose();
}
private void setDefaultLaunchDelegates() {
// Set the default launch delegates as early as possible, and do it only once (Bug 312997)
ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
HashSet<String> debugSet = new HashSet<String>();
debugSet.add(ILaunchManager.DEBUG_MODE);
ILaunchConfigurationType localCfg = launchMgr.getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_APP);
try {
if (localCfg.getPreferredDelegate(debugSet) == null) {
ILaunchDelegate[] delegates = localCfg.getDelegates(debugSet);
for (ILaunchDelegate delegate : delegates) {
if (ICDTLaunchConfigurationConstants.PREFERRED_DEBUG_LOCAL_LAUNCH_DELEGATE.equals(delegate.getId())) {
localCfg.setPreferredDelegate(debugSet, delegate);
break;
}
}
}
} catch (CoreException e) {
}
ILaunchConfigurationType remoteCfg = launchMgr.getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_REMOTE_APP);
try {
if (remoteCfg.getPreferredDelegate(debugSet) == null) {
ILaunchDelegate[] delegates = remoteCfg.getDelegates(debugSet);
for (ILaunchDelegate delegate : delegates) {
if (ICDTLaunchConfigurationConstants.PREFERRED_DEBUG_REMOTE_LAUNCH_DELEGATE.equals(delegate.getId())) {
remoteCfg.setPreferredDelegate(debugSet, delegate);
break;
}
}
}
} catch (CoreException e) {
}
ILaunchConfigurationType attachCfg = launchMgr.getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_ATTACH);
try {
if (attachCfg.getPreferredDelegate(debugSet) == null) {
ILaunchDelegate[] delegates = attachCfg.getDelegates(debugSet);
for (ILaunchDelegate delegate : delegates) {
if (ICDTLaunchConfigurationConstants.PREFERRED_DEBUG_ATTACH_LAUNCH_DELEGATE.equals(delegate.getId())) {
attachCfg.setPreferredDelegate(debugSet, delegate);
break;
}
}
}
} catch (CoreException e) {
}
ILaunchConfigurationType postMortemCfg = launchMgr.getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_POST_MORTEM);
try {
if (postMortemCfg.getPreferredDelegate(debugSet) == null) {
ILaunchDelegate[] delegates = postMortemCfg.getDelegates(debugSet);
for (ILaunchDelegate delegate : delegates) {
if (ICDTLaunchConfigurationConstants.PREFERRED_DEBUG_POSTMORTEM_LAUNCH_DELEGATE.equals(delegate.getId())) {
postMortemCfg.setPreferredDelegate(debugSet, delegate);
break;
}
}
}
} catch (CoreException e) {
}
HashSet<String> runSet = new HashSet<String>();
runSet.add(ILaunchManager.RUN_MODE);
try {
if (localCfg.getPreferredDelegate(runSet) == null) {
ILaunchDelegate[] delegates = localCfg.getDelegates(runSet);
for (ILaunchDelegate delegate : delegates) {
if (ICDTLaunchConfigurationConstants.PREFERRED_RUN_LAUNCH_DELEGATE.equals(delegate.getId())) {
localCfg.setPreferredDelegate(runSet, delegate);
break;
}
}
}
} catch (CoreException e) {
}
}
}