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

[248587] Support "Event' Breakpoints

This commit is contained in:
John Cortell 2010-04-06 19:32:14 +00:00
parent cdb45fd02a
commit 57c6ba5fec
21 changed files with 2091 additions and 49 deletions

View file

@ -29,15 +29,15 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension.IBreakpointHitDMEvent;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
@ -50,12 +50,13 @@ import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData;
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints;
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext;
import org.eclipse.cdt.dsf.mi.service.MIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIStack;
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MICatchpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIErrorEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIInferiorExitEvent;
@ -134,7 +135,9 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
}
public StateChangeReason getReason() {
if (getMIEvent() instanceof MIBreakpointHitEvent) {
if (getMIEvent() instanceof MICatchpointHitEvent) { // must precede MIBreakpointHitEvent
return StateChangeReason.EVENT_BREAKPOINT;
} else if (getMIEvent() instanceof MIBreakpointHitEvent) {
return StateChangeReason.BREAKPOINT;
} else if (getMIEvent() instanceof MISteppingRangeEvent) {
return StateChangeReason.STEP;

View file

@ -73,6 +73,8 @@ public class MIBreakpointDMData implements IBreakpointDMData {
fNature = MIBreakpointNature.TRACEPOINT;
} else if (dsfMIBreakpoint.isWatchpoint()) {
fNature = MIBreakpointNature.WATCHPOINT;
} else if (dsfMIBreakpoint.isCatchpoint()) {
fNature = MIBreakpointNature.CATCHPOINT;
} else {
fNature = MIBreakpointNature.BREAKPOINT;
}
@ -82,6 +84,9 @@ public class MIBreakpointDMData implements IBreakpointDMData {
case BREAKPOINT:
{
// Note that this may in fact be a catchpoint. See comment below in
// CATCHPOINT case
// Generic breakpoint attributes
fProperties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT);
fProperties.put(MIBreakpoints.FILE_NAME, dsfMIBreakpoint.getFile());
@ -142,7 +147,27 @@ public class MIBreakpointDMData implements IBreakpointDMData {
fProperties.put(LOCATION, formatLocation());
break;
}
case CATCHPOINT:
{
// Because gdb doesn't support catchpoints in mi, we end up using
// CLI to set the catchpoint. The sort of MIBreakpoint we create
// at that time is minimal as the only information we get back from
// gdb is the breakpoint number and type of the catchpoint we just
// set. See MIBreakpoint(String)
//
// The only type of MIBreakpoint that will be of this CATCHPOINT type
// is the instance we create from the response of the CLI command we
// use to set the catchpoint. If we later query gdb for the breakpoint
// list, we'll unfortunately end up creating an MIBreakpoint of type
// BREAKPOINT. Maybe one day gdb will treats catchpoints like first
// class citizens and this messy situation will go away.
fProperties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.CATCHPOINT);
fProperties.put(MIBreakpoints.CATCHPOINT_TYPE, dsfMIBreakpoint.getCatchpointType());
break;
}
// Not reachable
default:
{

View file

@ -40,6 +40,7 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommand
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointScopeEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
@ -90,6 +91,26 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I
public static final String EXPRESSION = PREFIX + ".expression"; //$NON-NLS-1$
public static final String READ = PREFIX + ".read"; //$NON-NLS-1$
public static final String WRITE = PREFIX + ".write"; //$NON-NLS-1$
// Catchpoint properties
/**
* Property that indicates the kind of catchpoint (.e.g, fork call, C++
* exception throw). Value is the gdb keyword associated with that type, as
* listed in 'help catch'.
*
* @since 3.0
*/
public static final String CATCHPOINT_TYPE = PREFIX + ".catchpoint_type"; //$NON-NLS-1$
/**
* Property that holds arguments for the catchpoint. Value is an array of
* Strings. Never null, but may be empty collection, as most catchpoints are
* argument-less.
*
* @since 3.0
*/
public static final String CATCHPOINT_ARGS = PREFIX + ".catchpoint_args"; //$NON-NLS-1$
// Services
private ICommandControl fConnection;
@ -151,6 +172,8 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I
public final static String TRACEPOINT_INSERTION_FAILURE = "Tracepoint insertion failure"; //$NON-NLS-1$
/** @since 3.0 */
public final static String INVALID_BREAKPOINT_TYPE = "Invalid breakpoint type"; //$NON-NLS-1$
/** @since 3.0 */
public final static String CATCHPOINT_INSERTION_FAILURE = "Catchpoint insertion failure"; //$NON-NLS-1$
///////////////////////////////////////////////////////////////////////////
@ -488,6 +511,9 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I
else if (type.equals(MIBreakpoints.TRACEPOINT)) {
addTracepoint(context, attributes, drm);
}
else if (type.equals(MIBreakpoints.CATCHPOINT)) {
addCatchpoint(context, attributes, drm);
}
else {
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
drm.done();
@ -526,6 +552,9 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I
}
/**
* Creates a gdb location string for a breakpoint/watchpoint/tracepoint
* given its set of properties.
*
* @param attributes
* @return
* @since 3.0
@ -740,6 +769,86 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I
fConnection.queueCommand(fCommandFactory.createMIBreakWatch(context, isRead, isWrite, expression), addWatchpointDRM);
}
/**
* @since 3.0
*/
protected void addCatchpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> finalRm) {
// Select the context breakpoints map
final Map<Integer, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
// Though CDT allows setting a temporary catchpoint, CDT never makes use of it
assert (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false) == false;
// GDB has no support for hardware catchpoints
assert (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false) == false;
final String event = (String) getProperty(attributes, CATCHPOINT_TYPE, NULL_STRING);
final String[] args = (String[]) getProperty(attributes, CATCHPOINT_ARGS, null);
final Step insertBreakpointStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
fConnection.queueCommand(
fCommandFactory.createCLICatch(context, event, args == null ? new String[0] : args),
new DataRequestMonitor<CLICatchInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Sanity check
MIBreakpoint miBkpt = getData().getMIBreakpoint();
if (miBkpt == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, CATCHPOINT_INSERTION_FAILURE, null));
rm.done();
return;
}
// Create a breakpoint object and store it in the map
final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(miBkpt);
int reference = newBreakpoint.getNumber();
if (reference == -1) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, CATCHPOINT_INSERTION_FAILURE, null));
rm.done();
return;
}
contextBreakpoints.put(reference, newBreakpoint);
// Format the return value
MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference);
finalRm.setData(dmc);
// Flag the event
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
// Break/Watch/Catchpoints that are disabled when set are delayed (we
// don't tell gdb about them until the user enables them). So, we shouldn't
// be here if this is a disabled breakpoint
assert ((Boolean)getProperty(attributes, IS_ENABLED, true)) == true;
// Condition, ignore count and cannot be specified at creation time.
// Therefore, we have to update the catchpoint if any of these is present
Map<String,Object> delta = new HashMap<String,Object>();
delta.put(CONDITION, getProperty(attributes, CONDITION, NULL_STRING));
delta.put(IGNORE_COUNT, getProperty(attributes, IGNORE_COUNT, 0 ));
modifyBreakpoint(dmc, delta, rm, false);
}
@Override
protected void handleError() {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, CATCHPOINT_INSERTION_FAILURE, null));
rm.done();
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { insertBreakpointStep }, finalRm);
}
//-------------------------------------------------------------------------
// removeBreakpoint
//-------------------------------------------------------------------------

View file

@ -30,6 +30,7 @@ import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager;
import org.eclipse.cdt.debug.core.model.ICAddressBreakpoint;
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
import org.eclipse.cdt.debug.core.model.ICBreakpointExtension;
import org.eclipse.cdt.debug.core.model.ICEventBreakpoint;
import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
import org.eclipse.cdt.debug.core.model.ICTracepoint;
import org.eclipse.cdt.debug.core.model.ICWatchpoint;
@ -42,13 +43,13 @@ import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.IDsfBreakpointExtension;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.IDsfBreakpointExtension;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
@ -91,7 +92,6 @@ import org.osgi.framework.BundleContext;
*
* It relies on MIBreakpoints for the actual back-end interface.
*/
@SuppressWarnings("restriction") // we use an internal platform type (BreakpointProblems)
public class MIBreakpointsManager extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener
{
// Note: Find a way to import this (careful of circular dependencies)
@ -110,6 +110,30 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!)
BreakpointActionManager fBreakpointActionManager;
/**
* A mapping of ICEventBreakpoint event types to their corresponding gdb
* catchpoint keyword (as listed in gdb's 'help catch')
*/
private static final Map<String, String> sEventBkptTypeToGdb = new HashMap<String, String>();
static {
// these Ids are also referenced in mi.ui plugin as contribution
// to event breakpoints selector
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_CATCH, "catch"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_THROW, "throw"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_SIGNAL_CATCH, "signal"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_EXEC, "exec"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_FORK, "fork"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_VFORK, "vfork"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_EXIT, "exit"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_PROCESS_START, "start"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_PROCESS_STOP, "stop"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_THREAD_START, "thread_start"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_THREAD_EXIT, "thread_exit"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_THREAD_JOIN, "thread_join"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_LIBRARY_LOAD, "load"); //$NON-NLS-1$
sEventBkptTypeToGdb.put(ICEventBreakpoint.EVENT_TYPE_LIBRARY_UNLOAD, "unload"); //$NON-NLS-1$
}
///////////////////////////////////////////////////////////////////////////
// Breakpoints tracking
///////////////////////////////////////////////////////////////////////////
@ -1230,6 +1254,7 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
public void eventDispatched(SuspendedEvent e) {
if (e.getMIEvent() instanceof MIBreakpointHitEvent) {
// This covers catchpoints, too
MIBreakpointHitEvent evt = (MIBreakpointHitEvent) e.getMIEvent();
performBreakpointAction(evt.getDMContext(), evt.getNumber());
return;
@ -1673,8 +1698,24 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo
properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.TRACEPOINT);
properties.put(MIBreakpoints.PASS_COUNT, attributes.get(ICTracepoint.PASS_COUNT));
}
} else {
// catchpoint?
}
else if (breakpoint instanceof ICEventBreakpoint) {
properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.CATCHPOINT);
properties.put(MIBreakpoints.CATCHPOINT_TYPE, sEventBkptTypeToGdb.get(attributes.get(ICEventBreakpoint.EVENT_TYPE_ID)));
String arg = (String)attributes.get(ICEventBreakpoint.EVENT_ARG);
String[] args;
if ((arg != null) && (arg.length() != 0)) {
args = new String[1];
args[0] = arg;
}
else {
args = new String[0];
}
properties.put(MIBreakpoints.CATCHPOINT_ARGS, args);
}
else {
assert false : "platform breakpoint is of an unexpected type: " + breakpoint.getClass().getName(); //$NON-NLS-1$
}
// Common fields

View file

@ -28,11 +28,11 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension.IBreakpointHitDMEvent;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
@ -44,6 +44,7 @@ import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MICatchpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIErrorEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIRunningEvent;
@ -171,7 +172,9 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
}
public StateChangeReason getReason() {
if (getMIEvent() instanceof MIBreakpointHitEvent) {
if (getMIEvent() instanceof MICatchpointHitEvent) { // must precede MIBreakpointHitEvent
return StateChangeReason.EVENT_BREAKPOINT;
} else if (getMIEvent() instanceof MIBreakpointHitEvent) {
return StateChangeReason.BREAKPOINT;
} else if (getMIEvent() instanceof MISteppingRangeEvent) {
return StateChangeReason.STEP;

View file

@ -20,6 +20,7 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
@ -50,6 +51,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIParser;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStreamRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
import org.eclipse.cdt.dsf.service.AbstractDsfService;
import org.eclipse.cdt.dsf.service.DsfSession;
@ -604,12 +606,20 @@ public abstract class AbstractMIControl extends AbstractDsfService
private final InputStream fInputStream;
private final MIParser fMiParser = new MIParser();
/**
* List of out of band records since the last result record. Out of band records are
* required for processing the results of CLI commands.
*/
private final List<MIOOBRecord> fAccumulatedOOBRecords = new ArrayList<MIOOBRecord>();
/**
* List of out of band records since the last result record. Out of band
* records are required for processing the results of CLI commands.
*/
private final List<MIOOBRecord> fAccumulatedOOBRecords = new LinkedList<MIOOBRecord>();
/**
* List of stream records since the last result record, not including
* the record currently being processed (if it's a stream one). This is
* a subset of {@link #fAccumulatedOOBRecords}, as a stream record is a
* particular type of OOB record.
*/
private final List<MIStreamRecord> fAccumulatedStreamRecords = new LinkedList<MIStreamRecord>();
public RxThread(InputStream inputStream) {
super("MI RX Thread"); //$NON-NLS-1$
fInputStream = inputStream;
@ -784,6 +794,7 @@ public abstract class AbstractMIControl extends AbstractDsfService
final MIOutput response = new MIOutput(
rr, fAccumulatedOOBRecords.toArray(new MIOOBRecord[fAccumulatedOOBRecords.size()]) );
fAccumulatedOOBRecords.clear();
fAccumulatedStreamRecords.clear();
MIInfo result = commandHandle.getCommand().getResult(response);
DataRequestMonitor<MIInfo> rm = commandHandle.getRequestMonitor();
@ -870,12 +881,28 @@ public abstract class AbstractMIControl extends AbstractDsfService
} else if (recordType == MIParser.RecordType.OOBRecord) {
// Process OOBs
final MIOOBRecord oob = fMiParser.parseMIOOBRecord(line);
if (!fRxCommands.isEmpty()) {
// This is for CLI commands, so only store if we are actually
// waiting for a command reply
fAccumulatedOOBRecords.add(oob);
fAccumulatedOOBRecords.add(oob);
if (fAccumulatedOOBRecords.size() > 20) { // limit growth; see bug 302927
fAccumulatedOOBRecords.remove(0);
}
final MIOutput response = new MIOutput(oob);
// The handling of this OOB record may need the stream records
// that preceded it. One such case is a stopped event caused by a
// catchpoint in gdb < 7.0. The stopped event provides no
// reason, but we can determine it was caused by a catchpoint by
// looking at the target stream.
final MIOutput response = new MIOutput(oob, fAccumulatedStreamRecords.toArray(new MIStreamRecord[fAccumulatedStreamRecords.size()]));
// If this is a stream record, add it to the accumulated bucket
// for possible use in handling a future OOB (see comment above)
if (oob instanceof MIStreamRecord) {
fAccumulatedStreamRecords.add((MIStreamRecord)oob);
if (fAccumulatedStreamRecords.size() > 20) { // limit growth; see bug 302927
fAccumulatedStreamRecords.remove(0);
}
}
/*
* OOBS are events. So we pass them to any event listeners who want to see them. Again this must

View file

@ -27,6 +27,7 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommand
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIAttach;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLICatch;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIDetach;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIExecAbort;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoSharedLibrary;
@ -122,6 +123,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarSetFormat;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowAttributes;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowFormat;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarUpdate;
import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoThreadsInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIThreadInfo;
@ -176,6 +178,10 @@ public class CommandFactory {
return new CLIAttach(ctx, pid);
}
public ICommand<CLICatchInfo> createCLICatch(IBreakpointsTargetDMContext ctx, String event, String[] args) {
return new CLICatch(ctx, event, args);
}
public ICommand<MIInfo> createCLIDetach(IDMContext ctx) {
return new CLIDetach(ctx);
}

View file

@ -14,17 +14,17 @@ package org.eclipse.cdt.dsf.mi.service.command;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandListener;
import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
import org.eclipse.cdt.dsf.debug.service.command.ICommandToken;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
@ -40,6 +40,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecStep;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecStepInstruction;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecUntil;
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MICatchpointHitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIFunctionFinishedEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIInferiorExitEvent;
@ -58,6 +59,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStreamRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
@ -136,6 +138,21 @@ public class MIRunControlEventProcessor
}
}
}
// GDB < 7.0 does not provide a reason when stopping on a
// catchpoint. However, the reason is contained in the
// stream records that precede the exec async output one.
// This is ugly, but we don't really have an alternative.
if (events.isEmpty()) {
MIStreamRecord[] streamRecords = ((MIOutput)output).getStreamRecords();
for (MIStreamRecord streamRecord : streamRecords) {
String log = streamRecord.getString();
if (log.startsWith("Catchpoint ")) { //$NON-NLS-1$
events.add(MICatchpointHitEvent.parse(getExecutionContext(exec), exec.getToken(), results, streamRecord));
}
}
}
// We were stopped for some unknown reason, for example
// GDB for temporary breakpoints will not send the
// "reason" ??? still fire a stopped event.
@ -153,8 +170,13 @@ public class MIRunControlEventProcessor
}
}
}
protected MIEvent<?> createEvent(String reason, MIExecAsyncOutput exec) {
/**
* Create an execution context given an exec-async-output OOB record
*
* @since 3.0
*/
protected IExecutionDMContext getExecutionContext(MIExecAsyncOutput exec) {
String threadId = null;
MIResult[] results = exec.getMIResults();
@ -185,6 +207,11 @@ public class MIRunControlEventProcessor
execDmc = procService.createExecutionContext(processContainerDmc, threadDmc, threadId);
}
return execDmc;
}
protected MIEvent<?> createEvent(String reason, MIExecAsyncOutput exec) {
IExecutionDMContext execDmc = getExecutionContext(exec);
MIEvent<?> event = null;
if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$
event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults());

View file

@ -60,6 +60,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStreamRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
@ -132,7 +133,7 @@ public class MIRunControlEventProcessor_7_0
if (var.equals("reason")) { //$NON-NLS-1$
if (val instanceof MIConst) {
String reason = ((MIConst) val).getString();
MIEvent<?> e = createEvent(reason, exec);
MIEvent<?> e = createEvent(reason, exec, ((MIOutput)output).getStreamRecords());
if (e != null) {
events.add(e);
continue;
@ -144,7 +145,7 @@ public class MIRunControlEventProcessor_7_0
// GDB for temporary breakpoints will not send the
// "reason" ??? still fire a stopped event.
if (events.isEmpty()) {
MIEvent<?> e = createEvent(STOPPED_REASON, exec);
MIEvent<?> e = createEvent(STOPPED_REASON, exec, ((MIOutput)output).getStreamRecords());
if (e != null) {
events.add(e);
}
@ -155,7 +156,7 @@ public class MIRunControlEventProcessor_7_0
}
}
else if (RUNNING_REASON.equals(state)) {
MIEvent<?> event = createEvent(RUNNING_REASON, exec);
MIEvent<?> event = createEvent(RUNNING_REASON, exec, ((MIOutput)output).getStreamRecords());
if (event != null) {
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
}
@ -240,8 +241,18 @@ public class MIRunControlEventProcessor_7_0
}
}
}
protected MIEvent<?> createEvent(String reason, MIExecAsyncOutput exec) {
/**
* @since 3.0
* @param miStreamRecords
* the stream records that preceded 'exec'. Determining which
* type of event to create may require additional insight
* available in those records. One example is catchpoint hits.
* They are reported by gdb (>= 7.0)as a simple breakpoint hit.
* However, gdb also sends a stream record that reveals that it's
* a catchpoint hit.
*/
protected MIEvent<?> createEvent(String reason, MIExecAsyncOutput exec, MIStreamRecord[] miStreamRecords) {
MIEvent<?> event = null;
if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$
@ -300,7 +311,7 @@ public class MIRunControlEventProcessor_7_0
}
if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$
event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults(), miStreamRecords);
} else if (
"watchpoint-trigger".equals(reason) //$NON-NLS-1$
|| "read-watchpoint-trigger".equals(reason) //$NON-NLS-1$

View file

@ -0,0 +1,52 @@
/*******************************************************************************
* 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.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
/**
* gdb 'catch' command. Even though the command has been around since gdb 6.6,
* it's still not supported in gdb 7.0 MI.
*
* @since 3.0
*/
public class CLICatch extends CLICommand<CLICatchInfo> {
private static String formOperation(String event, String[] args) {
StringBuilder oper = new StringBuilder("catch " + event); //$NON-NLS-1$
for (String arg : args) {
oper.append(" " + arg); //$NON-NLS-1$
}
return oper.toString();
}
/**
* Constructor
* @param ctx the context for the command
* @param event the type of event to be caught; one of the keywords documented in 'help catch'
* @param args zero or more arguments particular to the 'event'
*/
public CLICatch(IBreakpointsTargetDMContext ctx, String event, String[] args) {
super(ctx, formOperation(event, args));
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.mi.service.command.commands.MICommand#getResult(org.eclipse.cdt.dsf.mi.service.command.output.MIOutput)
*/
@Override
public MIInfo getResult(MIOutput MIresult) {
return new CLICatchInfo(MIresult);
}
}

View file

@ -17,11 +17,17 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStreamRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
/**
* ^stopped,reason="breakpoint-hit",bkptno="1",thread-id="0",frame={addr="0x08048468",func="main",args=[{name="argc",value="1"},{name="argv",value="0xbffff18c"}],file="hello.c",line="4"}
*
* Conveys that gdb reported the target stopped because of a breakpoint. This
* includes catchpoints, as gdb reports them as a breakpoint-hit. The
* async-exec-output record looks like this:
*
* <code>
* ^stopped,reason="breakpoint-hit",bkptno="1",thread-id="0",frame={addr="0x08048468",func="main",args=[{name="argc",value="1"},{name="argv",value="0xbffff18c"}],file="hello.c",line="4"}
* </code>
*/
@Immutable
public class MIBreakpointHitEvent extends MIStoppedEvent {
@ -38,9 +44,10 @@ public class MIBreakpointHitEvent extends MIStoppedEvent {
}
/**
* @since 1.1
* @param miStreamRecords
* @since 3.0
*/
public static MIBreakpointHitEvent parse(IExecutionDMContext dmc, int token, MIResult[] results)
public static MIBreakpointHitEvent parse(IExecutionDMContext dmc, int token, MIResult[] results, MIStreamRecord[] miStreamRecords)
{
int bkptno = -1;
@ -60,6 +67,14 @@ public class MIBreakpointHitEvent extends MIStoppedEvent {
}
}
MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(dmc, token, results);
for (MIStreamRecord streamRecord : miStreamRecords) {
String log = streamRecord.getString();
if (log.startsWith("Catchpoint ")) { //$NON-NLS-1$
return new MICatchpointHitEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), bkptno);
}
}
return new MIBreakpointHitEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), bkptno);
}
}

View file

@ -0,0 +1,43 @@
package org.eclipse.cdt.dsf.mi.service.command.events;
import java.util.StringTokenizer;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIStreamRecord;
/**
* @since 3.0
*/
public class MICatchpointHitEvent extends MIBreakpointHitEvent {
protected MICatchpointHitEvent(IExecutionDMContext ctx, int token,
MIResult[] results, MIFrame frame, int bkptno) {
super(ctx, token, results, frame, bkptno);
}
/**
* This variant is for catchpoint-hit in gdb < 7.0. For those versions, gdb
* sends us a stopped event, but it doesn't include a reason in it.
* Fortunately, it does output a stream record that tells us not only that a
* catchpoint was hit, but what its breakpoint number is.
*
* @param streamRecord
* the stream record that reveals that a catchpoint was hit
*/
public static MIBreakpointHitEvent parse(IExecutionDMContext dmc, int token, MIResult[] results, MIStreamRecord streamRecord) {
// stream record example: "Catchpoint 1 (exception caught)"
StringTokenizer tokenizer = new StringTokenizer(streamRecord.getString());
tokenizer.nextToken(); // "Catchpoint"
try {
int bkptNumber = Integer.parseInt(tokenizer.nextToken()); // "1" (e.g.,)
MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(dmc, token, results);
return new MICatchpointHitEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), bkptNumber);
}
catch (NumberFormatException exc) {
assert false : "unexpected catchpoint stream record format: " + streamRecord.getString(); //$NON-NLS-1$
return null;
}
}
}

View file

@ -0,0 +1,67 @@
/*******************************************************************************
* 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.dsf.mi.service.command.output;
/**
* Processes the result of a gdb 'catch' command. Even though the command has
* been around since gdb 6.6, it's still not supported in gdb 7.0 MI.
*
* @since 3.0
*/
public class CLICatchInfo extends MIInfo {
private MIBreakpoint fMiBreakpoint;
/**
* Constructor
* @param record the result object for the command
*/
public CLICatchInfo(MIOutput record) {
super(record);
assert record != null;
parse();
}
/**
* sample output: Catchpoint 3 (catch)
*/
protected void parse() {
if (isDone()) {
MIOutput out = getMIOutput();
for (MIOOBRecord oob : out.getMIOOBRecords()) {
if (oob instanceof MIConsoleStreamOutput) {
// We are interested in the catchpoint info
fMiBreakpoint = parseCatchpoint(((MIConsoleStreamOutput)oob).getString().trim());
if (fMiBreakpoint != null) {
return;
}
}
}
}
}
private MIBreakpoint parseCatchpoint(String str) {
if (str.startsWith("Catchpoint ")) { //$NON-NLS-1$
return new MIBreakpoint(str);
}
assert false : "CLI catch command had an unexpected result: " + str; //$NON-NLS-1$
return null;
}
/**
* Return an MIBreakpoint object for the catchpoint that was created.
*
* @return an MIBreakpoint object or null if the command result had
* unexpected data
*/
public MIBreakpoint getMIBreakpoint() {
return fMiBreakpoint;
}
}

View file

@ -14,6 +14,8 @@
package org.eclipse.cdt.dsf.mi.service.command.output;
import java.util.StringTokenizer;
/**
* Contain info about the GDB/MI breakpoint.
*
@ -78,7 +80,13 @@ public class MIBreakpoint {
// Indicate if we are dealing with a tracepoint.
// (if its a fast or slow tracepoint can be known through the 'type' field)
boolean isTpt = false;
/** See {@link #isCatchpoint()} */
boolean isCatchpoint;
/** See {@link #getCatchpointType()} */
private String catchpointType;
public MIBreakpoint() {
}
@ -105,12 +113,80 @@ public class MIBreakpoint {
isWWpt = other.isWWpt;
isHdw = other.isHdw;
isTpt = other.isTpt;
isCatchpoint = other.isCatchpoint;
catchpointType = other.catchpointType;
}
public MIBreakpoint(MITuple tuple) {
parse(tuple);
}
/**
* This constructor is used for catchpoints. Catchpoints are not yet
* supported in MI, so we end up using CLI.
*
* <p>
* Note that this poses at least one challenge for us. Normally, upon
* creating a breakpoint/watchpoint/tracepoint via mi, we get back a command
* result from gdb that contains all the details of the newly created
* object, and we use that detailed information to create the MIBreakpoint.
* This is the same data we'll get back if we later ask gdb for the
* breakpoint list. However, because we're using CLI for cathpoints, we
* don't get that detailed information from gdb at creation time, but the
* detail will be there if we later ask for the breakpoint list. What this
* all means is that we can't compare the two MIBreakponts (the one we
* construct at creation time, and the one we get by asking gdb for the
* breakpoint list). The most we can do is compare the breakpoint number.
* That for sure should be the same.
*
* <p>
* The detail we get from querying the breakpoint list, BTW, won't even
* reveal that it's a catchpoint. gdb simply reports it as a breakpoint,
* probably because that's what it really sets under the cover--an address
* breakpoint. This is another thing we need to keep in mind and creatively
* deal with. When we set the catchpoint, this constructor is used. When the
* breakpoint list is queried, {@link #MIBreakpoint(MITuple)} is used for
* that same breakpoint number, and a consumer of that MIBreakpoint won't be
* able to tell it's a catchpoint. Quite the mess. Wish gdb would treat
* catchpoints like first class citizens.
*
* @param cliResult
* the output from the CLI command. Example:
* "Catchpoint 1 (catch)"
* @since 3.0
*/
public MIBreakpoint(String cliResult) {
if (cliResult.startsWith("Catchpoint ")) { //$NON-NLS-1$
int bkptNumber = 0;
StringTokenizer tokenizer = new StringTokenizer(cliResult);
for (int i = 0; tokenizer.hasMoreTokens(); i++) {
String sub = tokenizer.nextToken();
switch (i) {
case 0: // first token is "Catchpoint"
break;
case 1: // second token is the breakpoint number
bkptNumber = Integer.parseInt(sub);
break;
case 2: // third token is the event type; drop the parenthesis
if (sub.startsWith("(")) { //$NON-NLS-1$
sub = sub.substring(1, sub.length()-1);
}
catchpointType = sub;
break;
}
}
number = bkptNumber;
isCatchpoint = true;
enabled = true;
}
else {
assert false : "unexpected CLI output: " + cliResult; //$NON-NLS-1$
}
}
///////////////////////////////////////////////////////////////////////////
// Properties getters
///////////////////////////////////////////////////////////////////////////
@ -183,6 +259,17 @@ public class MIBreakpoint {
return exp;
}
/**
* If isCatchpoint is true, then this indicates the type of catchpoint
* (event), as reported by gdb in its response to the CLI catch command.
* E.g., 'catch' or 'fork'
*
* @since 3.0
*/
public String getCatchpointType() {
return catchpointType;
}
public boolean isTemporary() {
return getDisposition().equals("del"); //$NON-NLS-1$
}
@ -247,6 +334,15 @@ public class MIBreakpoint {
public boolean isTracepoint() {
return isTpt;
}
/**
* Indicates if we are dealing with a catchpoint.
*
* @since 3.0
*/
public boolean isCatchpoint() {
return isCatchpoint;
}
/**
* Returns the passcount of a tracepoint. Will return 0 if this
@ -303,6 +399,11 @@ public class MIBreakpoint {
} catch (NumberFormatException e) {
}
} else if (var.equals("type")) { //$NON-NLS-1$
// Note that catchpoints are reported by gdb as address
// breakpoints; there's really nothing we can go on to determine
// that it's actually a catchpoint (short of using a really ugly
// and fragile hack--looking at the 'what' field for specific values)
type = str;
//type="hw watchpoint"
if (type.startsWith("hw")) { //$NON-NLS-1$
@ -370,5 +471,4 @@ public class MIBreakpoint {
}
}
}
}

View file

@ -20,17 +20,54 @@ public class MIOutput {
private final MIResultRecord rr;
private final MIOOBRecord[] oobs;
private MIStreamRecord[] streamRecords;
public MIOutput() {
this(null, null);
this(null, (MIOOBRecord[])null);
}
public MIOutput(MIOOBRecord oob) {
/**
* @param oob
* @deprecated Use {@link #MIOutput(MIOOBRecord, MIStreamRecord[])}
*/
@Deprecated
public MIOutput(MIOOBRecord oob) {
this(null, new MIOOBRecord[] { oob });
}
/**
* Constructor used when handling a single out-of-band record
*
* @param the
* out-of-bound record
* @param streamRecords
* any stream records that preceded the out-of-bound record,
* since the last command result. This need not contain *all*
* such records if it's been a while since the last command (for
* practical reasons, there is a cap on the number of stream
* records that are remembered). This will have the most recent
* records. Must not be null; may be empty
* @since 3.0
*/
public MIOutput(MIOOBRecord oob, MIStreamRecord[] streamRecords) {
this(null, new MIOOBRecord[] { oob });
this.streamRecords = streamRecords;
assert streamRecords != null;
}
/**
* Constructor used when handling a command result.
*
* @param rr
* the result record
* @param oobs
* any out-of-band records that preceded this particular command
* result. This need not contain *all* such records if it's been
* a while since the last command (for practical reasons, there
* is a cap on the number of OOB records that are remembered).
* This will have the most recent records.
*
*/
public MIOutput(MIResultRecord rr, MIOOBRecord[] oobs) {
this.rr = rr;
this.oobs = oobs;
@ -44,6 +81,20 @@ public class MIOutput {
return oobs;
}
/**
* See param in {@link #MIOutput(MIOOBRecord, MIStreamRecord[])}
*
* @return Only instances created for an OOB record will have stream
* records; may be an empty collection in that case, but not null.
* Instances created for a command result will return null from this
* method. Stream records can be retrieved from
* {@link #getMIOOBRecords()} in that case.
* @since 3.0
*/
public MIStreamRecord[] getStreamRecords() {
return streamRecords;
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();

View file

@ -0,0 +1,28 @@
#include <iostream>
#include <unistd.h>
int g_i = 0;
int main() {
for (; g_i < 8; g_i++) {
try {
std::cout << "Throwing exception" << std::endl;
throw 1;
}
catch (int exc) {
std::cout << "Exception caught" << std::endl;
}
}
// For setting a catchpoint while target is running
std::cout << "Sleeping..." << std::endl;
sleep(2);
std::cout << "...awake!" << std::endl;
try {
std::cout << "Throwing exception" << std::endl;
throw 1;
}
catch (int exc) {
std::cout << "Exception caught" << std::endl;
}
return 0;
}

View file

@ -72,7 +72,12 @@ public class ExecutionContextLabelText extends LabelText {
reasonLabel = MessagesForLaunchVM.State_change_reason__User_request__label;
} else if (StateChangeReason.WATCHPOINT.name().equals(reason)) {
reasonLabel = MessagesForLaunchVM.State_change_reason__Watchpoint__label;
} else if (StateChangeReason.EVENT_BREAKPOINT.name().equals(reason)) {
reasonLabel = MessagesForLaunchVM.State_change_reason__EventBreakpoint__label;
} else {
assert false : "unexpected state change reason: " + reason; //$NON-NLS-1$
}
return reasonLabel;
} else if ( ILaunchVMConstants.PROP_STATE_CHANGE_DETAILS.equals(propertyName) ) {
return properties.get(propertyName);

View file

@ -51,4 +51,5 @@ public class MessagesForLaunchVM extends NLS {
public static String State_change_reason__Shared_lib__label;
public static String State_change_reason__Error__label;
public static String State_change_reason__Evaluation__label;
public static String State_change_reason__EventBreakpoint__label;
}

View file

@ -66,4 +66,5 @@ State_change_reason__Watchpoint__label = Watchpoint
State_change_reason__Signal__label = Signal
State_change_reason__Shared_lib__label = Shared Library
State_change_reason__Error__label = Error
State_change_reason__Evaluation__label = Evaluation
State_change_reason__Evaluation__label = Evaluation
State_change_reason__EventBreakpoint__label = Event Breakpoint

View file

@ -46,7 +46,11 @@ public interface IRunControl extends IDsfService
public interface IContainerDMContext extends IExecutionDMContext {}
/** Flag indicating reason context state change. */
public enum StateChangeReason { UNKNOWN, USER_REQUEST, STEP, BREAKPOINT, EXCEPTION, CONTAINER, WATCHPOINT, SIGNAL, SHAREDLIB, ERROR, EVALUATION };
public enum StateChangeReason {
UNKNOWN, USER_REQUEST, STEP, BREAKPOINT, EXCEPTION, CONTAINER, WATCHPOINT, SIGNAL, SHAREDLIB, ERROR, EVALUATION,
/** @since 2.1 */
EVENT_BREAKPOINT };
/**
* Indicates that the given thread has suspended.