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

[280631] Thread list in Debug view not updated with non-Linux target

This commit is contained in:
John Cortell 2010-04-22 23:03:58 +00:00
parent e26d82f4d5
commit a2f1be9eff
8 changed files with 132 additions and 59 deletions

View file

@ -15,6 +15,9 @@
<description>Control the behavior of the C/C++ debugger when debugging with GDB, specifically when using a GDB (DSF) launcher.</description>
<topic href="reference/cdt_u_dsfgdb.htm" label="GDB Preferences"/>
</context>
<context id="update_threadlist_button_context" title="About this checkbox">
<description>This checkbox controls whether the CDT debugger will ask gdb for the target program&apos;s thread list on each suspend event (breakpoint-hit, step, etc). Normally, this isn&apos;t necessary, as GDB sends notifications in realtime when a thread is created or destroyed. However, some lightweight GDB remote stubs won&apos;t send these notifications. As such, the CDT debugger doesn&apos;t find out about new or destroyed threads unless it polls gdb. Turn on this option if you are debugging such a target (typically an embedded one).</description>
</context>
</contexts>

View file

@ -17,6 +17,7 @@ import java.util.Observer;
import org.eclipse.cdt.debug.ui.AbstractCDebuggerPage;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
import org.eclipse.cdt.utils.ui.controls.ControlFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
@ -36,6 +37,7 @@ import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
/**
* The dynamic tab for gdb-based debugger implementations.
@ -47,6 +49,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
protected Text fGDBInitText;
protected Button fNonStopCheckBox;
protected Button fReverseCheckBox;
protected Button fUpdateThreadlistOnSuspend;
private IMILaunchConfigurationComponent fSolibBlock;
private boolean fIsInitializing = false;
@ -71,6 +74,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
if (fSolibBlock != null)
fSolibBlock.setDefaults(configuration);
@ -90,46 +95,45 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
return valid;
}
/** utility method to cut down on clutter */
private String getStringAttr(ILaunchConfiguration config, String attributeName, String defaultValue) {
try {
return config.getAttribute(attributeName, defaultValue);
}
catch (CoreException exc) {
return defaultValue;
}
}
/** utility method to cut down on clutter */
private boolean getBooleanAttr(ILaunchConfiguration config, String attributeName, boolean defaultValue) {
try {
return config.getAttribute(attributeName, defaultValue);
}
catch (CoreException exc) {
return defaultValue;
}
}
public void initializeFrom(ILaunchConfiguration configuration) {
setInitializing(true);
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;
try {
gdbCommand = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME,
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT);
}
catch(CoreException e) {
}
try {
gdbInit = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT,
IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT);
}
catch(CoreException e) {
}
try {
nonStopMode = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP,
IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT);
}
catch(CoreException e) {
}
String gdbCommand = getStringAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME,
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT);
String gdbInit = getStringAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_GDB_INIT,
IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT);
boolean nonStopMode = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP,
IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT);
boolean reverseEnabled = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
boolean updateThreadsOnSuspend = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
try {
reverseEnabled = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
}
catch(CoreException e) {
}
if (fSolibBlock != null)
fSolibBlock.initializeFrom(configuration);
fGDBCommandText.setText(gdbCommand);
fGDBInitText.setText(gdbInit);
fNonStopCheckBox.setSelection(nonStopMode);
fReverseCheckBox.setSelection(reverseEnabled);
fUpdateThreadlistOnSuspend.setSelection(updateThreadsOnSuspend);
setInitializing(false);
}
@ -143,6 +147,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
fNonStopCheckBox.getSelection());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
fReverseCheckBox.getSelection());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
fUpdateThreadlistOnSuspend.getSelection());
if (fSolibBlock != null)
fSolibBlock.performApply(configuration);
@ -284,32 +290,15 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
// TODO: Ideally, this field should be disabled if the back-end doesn't support non-stop debugging
// TODO: Find a way to determine if non-stop is supported (i.e. find the GDB version) then grey out the check box if necessary
fNonStopCheckBox = ControlFactory.createCheckBox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.nonstop_mode")); //$NON-NLS-1$
fNonStopCheckBox.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
fNonStopCheckBox = addCheckbox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.nonstop_mode")); //$NON-NLS-1$
// 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.reverse_Debugging")); //$NON-NLS-1$
fReverseCheckBox.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
fReverseCheckBox = addCheckbox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.reverse_Debugging")); //$NON-NLS-1$
// fit options one per line
gd = new GridData();
gd.horizontalSpan = 3;
fNonStopCheckBox.setLayoutData(gd);
gd = new GridData();
gd.horizontalSpan = 3;
fReverseCheckBox.setLayoutData(gd);
fUpdateThreadlistOnSuspend = addCheckbox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.update_thread_list_on_suspend")); //$NON-NLS-1$
// This checkbox needs an explanation. Attach context help to it.
PlatformUI.getWorkbench().getHelpSystem().setHelp(fUpdateThreadlistOnSuspend, GdbUIPlugin.PLUGIN_ID + ".update_threadlist_button_context"); //$NON-NLS-1$
}
public void createSolibTab(TabFolder tabFolder) {
@ -323,6 +312,22 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
((Observable)fSolibBlock).addObserver(this);
}
/** Used to add a checkbox to the tab. Each checkbox has its own line. */
private Button addCheckbox(Composite parent, String label) {
Button button = ControlFactory.createCheckBox(parent, label);
button .addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateLaunchConfigurationDialog();
}
});
GridData gd = new GridData();
gd.horizontalSpan = 3;
button.setLayoutData(gd);
return button;
}
/*
* (non-Javadoc)
*

View file

@ -23,6 +23,7 @@ GDBDebuggerPage.cmdfile_warning=(Warning: Some commands in this file may interfe
GDBDebuggerPage.shared_libraries=Shared Libraries
GDBDebuggerPage.nonstop_mode=Non-stop mode (Note: Requires non-stop GDB)
GDBDebuggerPage.reverse_Debugging=Enable Reverse Debugging at startup (Note: Requires Reverse GDB)
GDBDebuggerPage.update_thread_list_on_suspend=Force thread list update on suspend
StandardGDBDebuggerPage.0=Debugger executable must be specified.
StandardGDBDebuggerPage.1=GDB Debugger Options
StandardGDBDebuggerPage.2=Main

View file

@ -81,6 +81,14 @@ public class IGDBLaunchConfigurationConstants {
* @since 2.0
*/
public static final String ATTR_DEBUGGER_REVERSE = GdbPlugin.PLUGIN_ID + ".REVERSE"; //$NON-NLS-1$
/**
* Launch configuration attribute key. Boolean value. See
* IGDBBackend.getUpdateThreadListOnSuspend()
*
* @since 3.0
*/
public static final String ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND = GdbPlugin.PLUGIN_ID + ".UPDATE_THREADLIST_ON_SUSPEND"; //$NON-NLS-1$
/**
* Launch configuration attribute value. The key is ATTR_DEBUG_NAME.
@ -114,4 +122,13 @@ public class IGDBLaunchConfigurationConstants {
* @since 2.0
*/
public static final boolean DEBUGGER_REVERSE_DEFAULT = false;
/**
* Launch configuration attribute value. The key is
* ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND
*
* @since 3.0
*/
public static final boolean DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT = false;
}

View file

@ -335,6 +335,14 @@ public class GDBBackend extends AbstractDsfService implements IGDBBackend {
return !fLaunchConfiguration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
}
/** @since 3.0 */
public boolean getUpdateThreadListOnSuspend() throws CoreException {
return fLaunchConfiguration
.getAttribute(
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
}
/*
* Launch GDB process.
* Allow subclass to override.

View file

@ -65,6 +65,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo.IThr
import org.eclipse.cdt.dsf.service.AbstractDsfService;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.BundleContext;
@ -882,6 +883,16 @@ public class GDBProcesses_7_0 extends AbstractDsfService
} else {
// This will happen in non-stop mode
}
// If user is debugging a gdb target that doesn't send thread
// creation events, make sure we don't use cached thread
// information. Reset the cache after every suspend. See bugzilla
// 280631
try {
if (fBackend.getUpdateThreadListOnSuspend()) {
fThreadCommandCache.reset(e.getDMContext());
}
} catch (CoreException exc) {}
}
// Event handler when a thread or threadGroup starts

View file

@ -133,4 +133,18 @@ public interface IGDBBackend extends IMIBackend {
* @return true if the ongoing session is attaching to a remote target.
*/
public boolean getIsAttachSession();
/**
* Indicates whether the CDT debugger should ask gdb for the target
* program's thread list on each suspend event (breakpoint-hit, step, etc).
* Normally, this isn't necessary, as GDB sends notifications in realtime
* when a thread is created or destroyed. However, some lightweight GDB
* remote stubs won't send these notifications. As such, the CDT debugger
* doesn't find out about new or destroyed threads unless it polls gdb. The
* user will enable this behavior if he is debugging such a target
* (typically an embedded one)
*
* @since 3.0
*/
public boolean getUpdateThreadListOnSuspend() throws CoreException;
}

View file

@ -33,6 +33,7 @@ import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
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.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoThreadsInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
@ -40,6 +41,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadListIdsInfo;
import org.eclipse.cdt.dsf.service.AbstractDsfService;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.BundleContext;
@ -305,6 +307,7 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
private ICommandControlService fCommandControl;
private CommandCache fContainerCommandCache;
private CommandFactory fCommandFactory;
private IGDBBackend fGdbBackend;
private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$
// The unique id should be an empty string so that the views know not to display the fake id
@ -350,6 +353,8 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
fGdbBackend = getServicesTracker().getService(IGDBBackend.class);
// This cache stores the result of a command when received; also, this cache
// is manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
@ -638,12 +643,21 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
*/
@DsfServiceEventHandler
public void eventDispatched(ISuspendedDMEvent e) {
if (e instanceof IContainerSuspendedDMEvent) {
// This will happen in all-stop mode
fContainerCommandCache.setContextAvailable(e.getDMContext(), true);
} else {
// This will happen in non-stop mode
}
// This assert may turn out to be overzealous. Refer to
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=280631#c26
assert e instanceof IContainerSuspendedDMEvent : "Unexpected type of suspended event: " + e.getClass().toString(); //$NON-NLS-1$
fContainerCommandCache.setContextAvailable(e.getDMContext(), true);
// If user is debugging a gdb target that doesn't send thread
// creation events, make sure we don't use cached thread
// information. Reset the cache after every suspend. See bugzilla
// 280631
try {
if (fGdbBackend.getUpdateThreadListOnSuspend()) {
fContainerCommandCache.reset(e.getDMContext());
}
} catch (CoreException exc) {}
}
/**