1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

[258284] This patch allows the user to enable reverse debugging from the launch. I got it all to work except for one case: if the user turns off StopOnMain, but actually has a real breakpoint on main,

then that breakpoint will be ignored when having Reverse on in the launch.
This commit is contained in:
Marc Khouzam 2009-02-09 21:34:16 +00:00
parent 51cf30f09d
commit ea1399cf07
5 changed files with 239 additions and 70 deletions

View file

@ -46,8 +46,10 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
protected Text fGDBCommandText;
protected Text fGDBInitText;
protected Button fNonStopCheckBox;
protected Button fReverseCheckBox;
protected Button fVerboseModeButton;
private IMILaunchConfigurationComponent fSolibBlock;
private boolean fIsInitializing = false;
@ -69,6 +71,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP,
IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE,
IGDBLaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT);
@ -95,6 +99,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
String gdbCommand = IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT;
String gdbInit = IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT;
boolean nonStopMode = IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT;
boolean reverseEnabled = IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT;
boolean verboseMode = IGDBLaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT;
try {
@ -116,6 +122,14 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
}
catch(CoreException e) {
}
try {
reverseEnabled = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
}
catch(CoreException e) {
}
try {
verboseMode = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE,
IGDBLaunchConfigurationConstants.DEBUGGER_VERBOSE_MODE_DEFAULT );
@ -128,6 +142,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
fGDBCommandText.setText(gdbCommand);
fGDBInitText.setText(gdbInit);
fNonStopCheckBox.setSelection(nonStopMode);
fReverseCheckBox.setSelection(reverseEnabled);
fVerboseModeButton.setSelection(verboseMode);
setInitializing(false);
@ -140,6 +155,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
fGDBInitText.getText().trim());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP,
fNonStopCheckBox.getSelection());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
fReverseCheckBox.getSelection());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_VERBOSE_MODE,
fVerboseModeButton.getSelection() );
@ -291,6 +308,16 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
}
});
// TODO: Ideally, this field should be disabled if the back-end doesn't support reverse debugging
// TODO: Find a way to determine if reverse is supported (i.e. find the GDB version) then grey out the check box if necessary
fReverseCheckBox = ControlFactory.createCheckBox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.14")); //$NON-NLS-1$
fReverseCheckBox.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
fVerboseModeButton = ControlFactory.createCheckBox( subComp, LaunchUIMessages.getString( "StandardGDBDebuggerPage.13" ) ); //$NON-NLS-1$
fVerboseModeButton.addSelectionListener(new SelectionAdapter() {
@Override
@ -312,8 +339,10 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
fNonStopCheckBox.setLayoutData(gd);
gd = new GridData();
gd.horizontalSpan = 3;
fVerboseModeButton.setLayoutData(gd);
fReverseCheckBox.setLayoutData(gd);
gd = new GridData();
gd.horizontalSpan = 3;
fVerboseModeButton.setLayoutData(gd);
// Grayed out until bug 249227 is resolved
//
fVerboseModeButton.setVisible(false);

View file

@ -25,6 +25,7 @@ GDBDebuggerPage.10=Shared Libraries
GDBDebuggerPage.11=Protocol:
GDBDebuggerPage.12=Default
GDBDebuggerPage.13=Non-stop mode (Note: Requires non-stop GDB)
GDBDebuggerPage.14=Enable Reverse Debugging at startup (Note: Requires Reverse GDB)
StandardGDBDebuggerPage.0=Debugger executable must be specified.
StandardGDBDebuggerPage.1=GDB Debugger Options
StandardGDBDebuggerPage.2=Main

View file

@ -82,6 +82,12 @@ public class IGDBLaunchConfigurationConstants {
*/
public static final String ATTR_DEBUGGER_VERBOSE_MODE = GdbPlugin.PLUGIN_ID + ".verboseMode"; //$NON-NLS-1$
/**
* Launch configuration attribute key. Boolean value to enable reverse debugging at launch time.
* @since 2.0
*/
public static final String ATTR_DEBUGGER_REVERSE = GdbPlugin.PLUGIN_ID + ".REVERSE"; //$NON-NLS-1$
/**
* Launch configuration attribute value. The key is ATTR_DEBUG_NAME.
*/
@ -114,4 +120,10 @@ public class IGDBLaunchConfigurationConstants {
* @since 1.1
*/
public static final boolean DEBUGGER_VERBOSE_MODE_DEFAULT = false;
/**
* Launch configuration attribute value. The key is ATTR_DEBUGGER_REVERSE.
* @since 2.0
*/
public static final boolean DEBUGGER_REVERSE_DEFAULT = false;
}

View file

@ -184,7 +184,7 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro
public void handleSuccess() {
getConnection().queueCommand(finalcmd, new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
public void handleCompleted() {
getConnection().queueCommand(
new RawCommand(finaldmc, "set exec-direction forward"),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
@ -266,7 +266,7 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro
public void handleSuccess() {
getConnection().queueCommand(finalcmd, new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
public void handleCompleted() {
getConnection().queueCommand(
new RawCommand(finaldmc, "set exec-direction forward"),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));

View file

@ -28,10 +28,12 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
import org.eclipse.cdt.dsf.gdb.service.GDBRunControl_7_0;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.gdb.service.IReverseRunControl;
import org.eclipse.cdt.dsf.gdb.service.SessionType;
import org.eclipse.cdt.dsf.mi.service.IMIBackend;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
@ -51,9 +53,9 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecRun;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBExit;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInferiorTTYSet;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.CoreException;
@ -277,77 +279,202 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
/**
* Insert breakpoint at entry if set, and start or restart the program.
* Note that restart does not apply to remote or attach sessions.
*
* If we want to enable Reverse debugging from the start of the program we do the following:
* attachSession => enable reverse
* else => set temp bp on main, run, enable reverse, continue if bp on main was not requested by user
*/
protected void startOrRestart(final GdbLaunch launch, boolean restart, final RequestMonitor requestMonitor) {
if (fMIBackend.getIsAttachSession()) {
// When attaching to a running process, we do not need to set a breakpoint or
// start the program; it is left up to the user.
requestMonitor.done();
return;
}
DsfServicesTracker servicesTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), getSession().getId());
IMIProcesses procService = servicesTracker.getService(IMIProcesses.class);
servicesTracker.dispose();
IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, MIProcesses.UNIQUE_GROUP_ID);
final IContainerDMContext containerDmc = procService.createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID);
final MICommand<MIInfo> execCommand;
if (fMIBackend.getSessionType() == SessionType.REMOTE) {
// When doing remote debugging, we use -exec-continue instead of -exec-run
execCommand = new MIExecContinue(containerDmc);
} else {
execCommand = new MIExecRun(containerDmc, new String[0]);
}
boolean stopInMain = false;
protected void startOrRestart(final GdbLaunch launch, boolean restart, RequestMonitor requestMonitor) {
boolean tmpReverseEnabled = IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT;
try {
stopInMain = launch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false );
tmpReverseEnabled = launch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve stop at entry point boolean", e)); //$NON-NLS-1$
requestMonitor.done();
return;
}
final boolean reverseEnabled = tmpReverseEnabled;
if (fMIBackend.getIsAttachSession()) {
// Restart does not apply to attach sessions.
//
// When attaching to a running process, we do not need to set a breakpoint or
// start the program; it is left up to the user.
// We only need to turn on Reverse Debugging if requested.
if (reverseEnabled) {
IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class);
if (reverseService != null) {
reverseService.enableReverseMode(fControlDmc, true, requestMonitor);
return;
}
}
requestMonitor.done();
return;
}
final DataRequestMonitor<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor) {
@Override
public void handleSuccess() {
DsfServicesTracker servicesTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), getSession().getId());
GDBRunControl_7_0 reverseService = servicesTracker.getService(GDBRunControl_7_0.class);
servicesTracker.dispose();
// When it is not an attach session, it gets a little more complicated
// so let's use a sequence.
getExecutor().execute(new Sequence(getExecutor(), requestMonitor) {
IContainerDMContext fContainerDmc;
MICommand<MIInfo> fExecCommand;
String fUserStopSymbol = null;
MIBreakpoint fUserBreakpoint = null;
boolean fUserBreakpointIsOnMain = false;
Step[] fSteps = new Step[] {
/*
* Figure out if we should use 'exec-continue' or '-exec-run'.
*/
new Step() {
@Override
public void execute(RequestMonitor rm) {
IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class);
IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, MIProcesses.UNIQUE_GROUP_ID);
fContainerDmc = procService.createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID);
if (reverseService != null) {
// When starting or restarting a program, reverse mode is automatically disabled
reverseService.setReverseModeEnabled(false);
}
requestMonitor.done();
}
};
if (!stopInMain) {
// Just start the program.
queueCommand(execCommand, execMonitor);
} else {
String stopSymbol = null;
try {
stopSymbol = launch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT );
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$
requestMonitor.done();
return;
}
// Insert a breakpoint at the requested stop symbol.
queueCommand(
new MIBreakInsert(fControlDmc, true, false, null, 0, stopSymbol, 0),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleSuccess() {
// After the break-insert is done, execute the -exec-run or -exec-continue command.
queueCommand(execCommand, execMonitor);
}
});
}
if (fMIBackend.getSessionType() == SessionType.REMOTE) {
// Restart does not apply to remote sessions
//
// When doing remote debugging, we use -exec-continue instead of -exec-run
fExecCommand = new MIExecContinue(fContainerDmc);
} else {
fExecCommand = new MIExecRun(fContainerDmc, new String[0]);
}
rm.done();
}},
/*
* If the user requested a 'stopOnMain', let's set the temporary breakpoint
* where the user specified.
*/
new Step() {
@Override
public void execute(final RequestMonitor rm) {
boolean userRequestedStop = false;
try {
userRequestedStop = launch.getLaunchConfiguration().getAttribute(
ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
false);
} catch (CoreException e) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve stop at entry point boolean", e)); //$NON-NLS-1$
rm.done();
return;
}
if (userRequestedStop) {
try {
fUserStopSymbol = launch.getLaunchConfiguration().getAttribute(
ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT);
} catch (CoreException e) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$
rm.done();
return;
}
queueCommand(new MIBreakInsert(fControlDmc, true, false, null, 0, fUserStopSymbol, 0),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
if (getData() != null) {
MIBreakpoint[] breakpoints = getData().getMIBreakpoints();
if (breakpoints.length > 0) {
fUserBreakpoint = breakpoints[0];
}
}
rm.done();
}
});
} else {
rm.done();
}
}},
/*
* If reverse debugging, set a breakpoint on main to be able to enable reverse
* as early as possible.
* If the user has requested a stop at the same point, we could skip this breakpoint
* however, we have to first set it to find out! So, we just leave it.
*/
new Step() {
@Override
public void execute(final RequestMonitor rm) {
if (reverseEnabled) {
queueCommand(new MIBreakInsert(fControlDmc, true, false, null, 0,
ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT, 0),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), rm) {
@Override
public void handleSuccess() {
if (getData() != null) {
MIBreakpoint[] breakpoints = getData().getMIBreakpoints();
if (breakpoints.length > 0 && fUserBreakpoint != null) {
fUserBreakpointIsOnMain = breakpoints[0].getAddress().equals(fUserBreakpoint.getAddress());
}
}
rm.done();
}
});
} else {
rm.done();
}
}},
/*
* Now, run the program.
*/
new Step() {
@Override
public void execute(RequestMonitor rm) {
queueCommand(fExecCommand, new DataRequestMonitor<MIInfo>(getExecutor(), rm));
}},
/*
* In case of a restart, reverse debugging should be marked as off here because
* GDB will have turned it off. We may turn it back on after.
*/
new Step() {
@Override
public void execute(RequestMonitor rm) {
// Although it only makes sense for a restart, it doesn't hurt
// do to it all the time.
GDBRunControl_7_0 reverseService = getServicesTracker().getService(GDBRunControl_7_0.class);
if (reverseService != null) {
reverseService.setReverseModeEnabled(false);
}
rm.done();
}},
/*
* Since we have started the program, we can turn on reverse debugging if needed
*/
new Step() {
@Override
public void execute(RequestMonitor rm) {
if (reverseEnabled) {
IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class);
if (reverseService != null) {
reverseService.enableReverseMode(fControlDmc, true, rm);
return;
}
}
rm.done();
}},
/*
* Finally, if we are enabling reverse, and the userSymbolStop is not on main,
* we should do a continue because we are currently stopped on main but that
* is not what the user requested
*/
new Step() {
@Override
public void execute(RequestMonitor rm) {
if (reverseEnabled && !fUserBreakpointIsOnMain) {
queueCommand(new MIExecContinue(fContainerDmc),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
} else {
rm.done();
}
}},
};
@Override
public Step[] getSteps() {
return fSteps;
}
});
}
/**