1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Breakpoint action for DSF

This commit is contained in:
Francois Chouinard 2008-03-07 19:33:00 +00:00
parent e75b2b1a1f
commit 60cb898c86
5 changed files with 247 additions and 193 deletions

View file

@ -1,185 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007 Ericsson 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:
* Ericsson - Initial API and implementation
*******************************************************************************/
package org.eclipse.dd.mi.service;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.breakpointactions.IBreakpointAction;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.model.IBreakpoint;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
public class MIBreakpointsActionManager {
public static final String BREAKPOINT_ACTION_ATTRIBUTE = "BREAKPOINT_ACTIONS"; //$NON-NLS-1$
private static final String BREAKPOINT_ACTION_DATA = "BreakpointActionManager.actionData"; //$NON-NLS-1$
private ArrayList breakpointActions = null;
public MIBreakpointsActionManager() {
}
public void executeActions(final IBreakpoint breakpoint, final IAdaptable context) {
if (breakpoint != null) {
IMarker marker = breakpoint.getMarker();
String actionNames = marker.getAttribute(BREAKPOINT_ACTION_ATTRIBUTE, ""); //$NON-NLS-1$
final String[] actions = actionNames.split(",");
if (actions.length > 0){
Job job = new Job("Execute breakpoint actions") {
public IStatus run(final IProgressMonitor monitor) {
return doExecuteActions(breakpoint, context, actions, monitor);
}
};
job.schedule();
try {
// wait for actions to execute
job.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private IStatus doExecuteActions(final IBreakpoint breakpoint, final IAdaptable context, String[] actions, IProgressMonitor monitor) {
try {
for (int i = 0; i < actions.length && !monitor.isCanceled(); i++) {
String actionName = actions[i];
IBreakpointAction action = findBreakpointAction(actionName);
if (action != null) {
monitor.setTaskName(action.getSummary());
IStatus status = action.execute(breakpoint, context, monitor);
if (status.getCode() != IStatus.OK) {
// do not log status if user canceled.
if (status.getCode() != IStatus.CANCEL)
CDebugCorePlugin.log(status);
return status;
}
}
monitor.worked(1);
}
} catch (Exception e) {
return new Status( IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), CDebugCorePlugin.INTERNAL_ERROR, "Internal Error", e );
}
return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
}
public IBreakpointAction findBreakpointAction(String name) {
for (Iterator iter = getBreakpointActions().iterator(); iter.hasNext();) {
IBreakpointAction action = (IBreakpointAction) iter.next();
if (action.getName().equals(name))
return action;
}
return null;
}
public ArrayList getBreakpointActions() {
if (breakpointActions == null) {
breakpointActions = new ArrayList();
loadActionData();
}
return breakpointActions;
}
private void loadActionData() {
String actionData = CDebugCorePlugin.getDefault().getPluginPreferences().getString(BREAKPOINT_ACTION_DATA);
if (actionData == null || actionData.length() == 0)
return;
Element root = null;
DocumentBuilder parser;
try {
parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
parser.setErrorHandler(new DefaultHandler());
root = parser.parse(new InputSource(new StringReader(actionData))).getDocumentElement();
NodeList nodeList = root.getChildNodes();
int entryCount = nodeList.getLength();
for (int i = 0; i < entryCount; i++) {
Node node = nodeList.item(i);
short type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element subElement = (Element) node;
String nodeName = subElement.getNodeName();
if (nodeName.equalsIgnoreCase("actionEntry")) { //$NON-NLS-1$
String name = subElement.getAttribute("name"); //$NON-NLS-1$
if (name == null)
throw new Exception();
String value = subElement.getAttribute("value"); //$NON-NLS-1$
if (value == null)
throw new Exception();
String className = subElement.getAttribute("class"); //$NON-NLS-1$
if (className == null)
throw new Exception();
IBreakpointAction action = createActionFromClassName(name, className);
action.initializeFromMemento(value);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private IBreakpointAction createActionFromClassName(String name, String className) {
IBreakpointAction action = null;
IExtension[] actionExtensions = CDebugCorePlugin.getDefault().getBreakpointActionManager().getBreakpointActionExtensions();
try {
for (int i = 0; i < actionExtensions.length && action == null; i++) {
IConfigurationElement[] elements = actionExtensions[i].getConfigurationElements();
for (int j = 0; j < elements.length && action == null; j++) {
IConfigurationElement element = elements[j];
if (element.getName().equals(CDebugCorePlugin.ACTION_TYPE_ELEMENT)) {
if (element.getAttribute("class").equals(className)) { //$NON-NLS-1$
action = (IBreakpointAction) element.createExecutableExtension("class"); //$NON-NLS-1$
action.setName(name);
CDebugCorePlugin.getDefault().getBreakpointActionManager().addAction(action);
}
}
}
}
} catch (CoreException e) {
e.printStackTrace();
}
return action;
}
}

View file

@ -9,7 +9,8 @@
* Wind River - Initial API and implementation * Wind River - Initial API and implementation
* Ericsson - High-level breakpoints integration * Ericsson - High-level breakpoints integration
* Ericsson - Added breakpoint filter support * Ericsson - Added breakpoint filter support
* Ericsson - Re-factored the service and put a few comments * Ericsson - Re-factored the service and put a few comments
* Ericsson - Added Action support
*******************************************************************************/ *******************************************************************************/
package org.eclipse.dd.mi.service; package org.eclipse.dd.mi.service;
@ -24,6 +25,8 @@ import java.util.Set;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager;
import org.eclipse.cdt.debug.core.model.ICBreakpoint; import org.eclipse.cdt.debug.core.model.ICBreakpoint;
import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; import org.eclipse.cdt.debug.core.model.ICBreakpointExtension;
import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
@ -65,10 +68,13 @@ import org.eclipse.dd.mi.internal.MIPlugin;
import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointAddedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointAddedEvent;
import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointRemovedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointRemovedEvent;
import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointUpdatedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointUpdatedEvent;
import org.eclipse.dd.mi.service.MIBreakpoints.MIBreakpointDMContext;
import org.eclipse.dd.mi.service.MIRunControl.MIExecutionDMC; import org.eclipse.dd.mi.service.MIRunControl.MIExecutionDMC;
import org.eclipse.dd.mi.service.breakpoint.actions.BreakpointActionAdapter;
import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent; import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent;
import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent;
import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent;
import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointListener; import org.eclipse.debug.core.IBreakpointListener;
import org.eclipse.debug.core.IBreakpointManager; import org.eclipse.debug.core.IBreakpointManager;
@ -98,7 +104,7 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
ISourceLookup fSourceLookup; ISourceLookup fSourceLookup;
IBreakpoints fBreakpoints; IBreakpoints fBreakpoints;
IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!) IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!)
// FIXME: MIBreakpointsActionManager fBreakpointActionManager; BreakpointActionManager fBreakpointActionManager;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Breakpoints tracking // Breakpoints tracking
@ -159,7 +165,6 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// String constants // String constants
// FIXME: Extract to some centralized location
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
private static final String NULL_STRING = ""; //$NON-NLS-1$ private static final String NULL_STRING = ""; //$NON-NLS-1$
@ -230,7 +235,7 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
fSourceLookup = getServicesTracker().getService(ISourceLookup.class); fSourceLookup = getServicesTracker().getService(ISourceLookup.class);
fBreakpoints = getServicesTracker().getService(IBreakpoints.class); fBreakpoints = getServicesTracker().getService(IBreakpoints.class);
fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager();
// FIXME: fBreakpointActionManager = new MIBreakpointsActionManager(); fBreakpointActionManager = CDebugCorePlugin.getDefault().getBreakpointActionManager();
// Register to the useful events // Register to the useful events
getSession().addServiceEventListener(this, null); getSession().addServiceEventListener(this, null);
@ -1134,20 +1139,23 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
// IServiceEventListener // IServiceEventListener
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------
// Breakpoints
//-------------------------------------------------------------------------
@DsfServiceEventHandler @DsfServiceEventHandler
public void eventDispatched(BreakpointAddedEvent e) { public void eventDispatched(BreakpointAddedEvent e) {
// Nothing to do - already handled by breakpointAdded()
} }
@DsfServiceEventHandler @DsfServiceEventHandler
public void eventDispatched(BreakpointUpdatedEvent e) { public void eventDispatched(BreakpointUpdatedEvent e) {
// Nothing to do - already handled by breakpointChanged()
} }
@DsfServiceEventHandler @DsfServiceEventHandler
public void eventDispatched(BreakpointRemovedEvent e) { public void eventDispatched(BreakpointRemovedEvent e) {
} // Nothing to do - already handled by breakpointRemoved()
@DsfServiceEventHandler
public void eventDispatched(MIBreakpointHitEvent e) {
} }
/* /*
@ -1160,6 +1168,67 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
public void eventDispatched(MIWatchpointScopeEvent e) { public void eventDispatched(MIWatchpointScopeEvent e) {
} }
//-------------------------------------------------------------------------
// Breakpoint actions
//-------------------------------------------------------------------------
@DsfServiceEventHandler
public void eventDispatched(MIBreakpointHitEvent e) {
performBreakpointAction(e.getNumber());
}
@DsfServiceEventHandler
public void eventDispatched(MIWatchpointTriggerEvent e) {
performBreakpointAction(e.getNumber());
}
private void performBreakpointAction(int number) {
// Identify the platform breakpoint
final ICBreakpoint breakpoint = findPlatformBreakpoint(number);
// FIXME: Temporary hack to have a context
Object[] contexts = fTargetBPs.keySet().toArray();
final IBreakpointsTargetDMContext context = (IBreakpointsTargetDMContext) contexts[0];
// Perform the actions asynchronously (otherwise we can have a deadlock...)
new Job("Breakpoint action") { //$NON-NLS-1$
{ setSystem(true); }
@Override
protected IStatus run(IProgressMonitor monitor) {
// FIXME: Rename MyAdaptableType to something more relevant
fBreakpointActionManager.executeActions(breakpoint, new BreakpointActionAdapter(getExecutor(), getServicesTracker(), context));
return Status.OK_STATUS;
};
}.schedule();
}
// Helper function to locate the platform breakpoint corresponding
// to the target breakpoint/watchpoint that was just hit
// FIXME: Need a way to identify the correct context where the BP was hit
// because it impacts the action (expression evaluation and resume delay).
// This means that the Breakpoint/WatchpointHitEvent will need to
// provide some extra info...
private ICBreakpoint findPlatformBreakpoint(int targetBreakpointID) {
Set<IBreakpointsTargetDMContext> targets = fTargetBPs.keySet();
for (IBreakpointsTargetDMContext target : targets) {
Map<IBreakpointDMContext, ICBreakpoint> bps = fTargetBPs.get(target);
Set<IBreakpointDMContext> contexts = bps.keySet();
for (IBreakpointDMContext context : contexts) {
if (context instanceof MIBreakpointDMContext) {
MIBreakpointDMContext ctx = (MIBreakpointDMContext) context;
if (ctx.getReference() == targetBreakpointID) {
return bps.get(context);
}
}
}
}
return null;
}
//-------------------------------------------------------------------------
// Session exit
//-------------------------------------------------------------------------
@DsfServiceEventHandler @DsfServiceEventHandler
public void eventDispatched(MIGDBExitEvent e) { public void eventDispatched(MIGDBExitEvent e) {
terminated(); terminated();

View file

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2008 Ericsson 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:
* Ericsson - Initial API and implementation
*******************************************************************************/
package org.eclipse.dd.mi.service.breakpoint.actions;
import org.eclipse.cdt.debug.core.breakpointactions.ILogActionEnabler;
import org.eclipse.cdt.debug.core.breakpointactions.IResumeActionEnabler;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
public class BreakpointActionAdapter implements IAdaptable {
private final DsfExecutor fExecutor;
private final DsfServicesTracker fServiceTracker;
private final IDMContext fContext;
public BreakpointActionAdapter(DsfExecutor executor, DsfServicesTracker serviceTracker, IDMContext context) {
fExecutor = executor;
fServiceTracker = serviceTracker;
fContext = context;
}
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.equals(ILogActionEnabler.class)) {
return new MILogActionEnabler(fExecutor, fServiceTracker, fContext);
}
if (adapter.equals(IResumeActionEnabler.class)) {
return new MIResumeActionEnabler(fExecutor, fServiceTracker, fContext);
}
return null;
}
}

View file

@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2008 Ericsson 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:
* Ericsson - Initial API and implementation
*******************************************************************************/
package org.eclipse.dd.mi.service.breakpoint.actions;
import java.util.concurrent.ExecutionException;
import org.eclipse.cdt.debug.core.breakpointactions.ILogActionEnabler;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.Query;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.debug.service.IExpressions;
import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
public class MILogActionEnabler implements ILogActionEnabler {
private final DsfExecutor fExecutor;
private final DsfServicesTracker fServiceTracker;
private final IBreakpointsTargetDMContext fContext;
public MILogActionEnabler(DsfExecutor executor, DsfServicesTracker serviceTracker, IDMContext context) {
fExecutor = executor;
fServiceTracker = serviceTracker;
// FIXME: Although it looks optimistic, we know it works
// How can we guarantee that it always will?
fContext = (IBreakpointsTargetDMContext) context;
}
public String evaluateExpression(final String expression) throws Exception {
// Use a Query to synchronize the call
Query<String> query = new Query<String>() {
@Override
protected void execute(final DataRequestMonitor<String> drm) {
final IExpressions expressionService = fServiceTracker.getService(IExpressions.class);
if (expressionService != null) {
final IExpressionDMContext expressionDMC = expressionService.createExpression(fContext, expression);
String formatId = IFormattedValues.NATURAL_FORMAT;
FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(expressionDMC, formatId);
expressionService.getFormattedExpressionValue(
valueDmc,
new DataRequestMonitor<FormattedValueDMData>(fExecutor, drm) {
@Override
protected void handleCompleted() {
String result = expression + ": evaluation failed."; //$NON-NLS-1$
if (getStatus().isOK()) {
result = getData().getFormattedValue();
}
drm.setData(result);
drm.done();
}
}
);
}
}
};
fExecutor.execute(query);
try {
// The happy case
return query.get();
} catch (InterruptedException e) {
return "Error evaluating \"" + expression + "\" (InterruptedException)."; //$NON-NLS-1$ //$NON-NLS-2$
} catch (ExecutionException e) {
return "Error evaluating \"" + expression + "\" (ExecutionException)."; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}

View file

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2008 Ericsson 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:
* Ericsson - Initial API and implementation
*******************************************************************************/
package org.eclipse.dd.mi.service.breakpoint.actions;
import org.eclipse.cdt.debug.core.breakpointactions.IResumeActionEnabler;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
public class MIResumeActionEnabler implements IResumeActionEnabler {
@SuppressWarnings("unused")
private final DsfExecutor fExecutor;
private final DsfServicesTracker fServiceTracker;
private final IExecutionDMContext fContext;
public MIResumeActionEnabler(DsfExecutor executor, DsfServicesTracker serviceTracker, IDMContext context) {
fExecutor = executor;
fServiceTracker = serviceTracker;
// FIXME: Although it looks optimistic, we know it works
// How can we guarantee that it always will?
fContext = (IExecutionDMContext) context;
}
public void resume() throws Exception {
final IRunControl runControlService = fServiceTracker.getService(IRunControl.class);
if (runControlService != null) {
runControlService.resume(fContext, new RequestMonitor(fExecutor, null));
}
}
}