1
/*******************************************************************************
2
* Copyright (c) 2008, 2010 QNX Software Systems and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* QNX Software Systems - initial API and implementation
10
* Ken Ryall (Nokia) - bug 178731
11
* Ericsson - Support for tracepoint post-mortem debugging
13
*******************************************************************************/
14
package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
16
import org.eclipse.cdt.core.CCorePlugin;
17
import org.eclipse.cdt.core.model.IBinary;
18
import org.eclipse.cdt.core.model.ICElement;
19
import org.eclipse.cdt.core.model.ICProject;
20
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
21
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
22
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
23
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
24
import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages;
25
import org.eclipse.cdt.launch.ui.CAbstractMainTab;
26
import org.eclipse.cdt.ui.CElementLabelProvider;
27
import org.eclipse.core.resources.IProject;
28
import org.eclipse.core.resources.IResource;
29
import org.eclipse.core.resources.ResourcesPlugin;
30
import org.eclipse.core.runtime.CoreException;
31
import org.eclipse.core.runtime.IPath;
32
import org.eclipse.core.runtime.Path;
33
import org.eclipse.debug.core.ILaunchConfiguration;
34
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
35
import org.eclipse.debug.ui.DebugUITools;
36
import org.eclipse.debug.ui.IDebugUIConstants;
37
import org.eclipse.jface.dialogs.MessageDialog;
38
import org.eclipse.jface.viewers.ILabelProvider;
39
import org.eclipse.jface.window.Window;
40
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.events.ModifyEvent;
42
import org.eclipse.swt.events.ModifyListener;
43
import org.eclipse.swt.events.SelectionAdapter;
44
import org.eclipse.swt.events.SelectionEvent;
45
import org.eclipse.swt.events.SelectionListener;
46
import org.eclipse.swt.graphics.Image;
47
import org.eclipse.swt.layout.GridData;
48
import org.eclipse.swt.layout.GridLayout;
49
import org.eclipse.swt.widgets.Button;
50
import org.eclipse.swt.widgets.Combo;
51
import org.eclipse.swt.widgets.Composite;
52
import org.eclipse.swt.widgets.FileDialog;
53
import org.eclipse.swt.widgets.Label;
54
import org.eclipse.swt.widgets.Text;
55
import org.eclipse.ui.dialogs.TwoPaneElementSelector;
58
* A launch configuration tab that displays and edits project and main type name launch
59
* configuration attributes.
61
* This class may be instantiated. This class is not intended to be subclassed.
65
public class CMainTab extends CAbstractMainTab {
68
* Tab identifier used for ordering of tabs added using the
69
* <code>org.eclipse.debug.ui.launchConfigurationTabs</code>
74
public static final String TAB_ID = "org.eclipse.cdt.dsf.gdb.launch.mainTab"; //$NON-NLS-1$
76
private static final String CORE_FILE = LaunchMessages.getString("CMainTab.CoreFile_type"); //$NON-NLS-1$
77
private static final String TRACE_FILE = LaunchMessages.getString("CMainTab.TraceFile_type"); //$NON-NLS-1$
80
* Combo box to select which type of post mortem file should be used.
81
* We currently support core files and trace files.
85
protected Combo fCoreTypeCombo;
87
private final boolean fDontCheckProgram;
88
private final boolean fSpecifyCoreFile;
89
private final boolean fIncludeBuildSettings;
91
public static final int DONT_CHECK_PROGRAM = 2;
92
public static final int SPECIFY_CORE_FILE = 4;
93
public static final int INCLUDE_BUILD_SETTINGS = 8;
96
this(INCLUDE_BUILD_SETTINGS);
99
public CMainTab(int flags) {
100
fDontCheckProgram = (flags & DONT_CHECK_PROGRAM) != 0;
101
fSpecifyCoreFile = (flags & SPECIFY_CORE_FILE) != 0;
102
fIncludeBuildSettings = (flags & INCLUDE_BUILD_SETTINGS) != 0;
108
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite)
110
public void createControl(Composite parent) {
111
Composite comp = new Composite(parent, SWT.NONE);
114
GdbUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(getControl(), ICDTLaunchHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_MAIN_TAB);
116
GridLayout topLayout = new GridLayout();
117
comp.setLayout(topLayout);
119
createVerticalSpacer(comp, 1);
120
createExeFileGroup(comp, 1);
121
createProjectGroup(comp, 1);
122
if (fIncludeBuildSettings){
123
createBuildOptionGroup(comp, 1);
125
createVerticalSpacer(comp, 1);
126
if (fSpecifyCoreFile) {
127
createCoreFileGroup(comp, 1);
130
GdbUIPlugin.setDialogShell(parent.getShell());
133
protected void createExeFileGroup(Composite parent, int colSpan) {
134
Composite mainComp = new Composite(parent, SWT.NONE);
135
GridLayout mainLayout = new GridLayout();
136
mainLayout.numColumns = 3;
137
mainLayout.marginHeight = 0;
138
mainLayout.marginWidth = 0;
139
mainComp.setLayout(mainLayout);
140
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
141
gd.horizontalSpan = colSpan;
142
mainComp.setLayoutData(gd);
143
fProgLabel = new Label(mainComp, SWT.NONE);
144
fProgLabel.setText(LaunchMessages.getString("CMainTab.C/C++_Application")); //$NON-NLS-1$
146
gd.horizontalSpan = 3;
147
fProgLabel.setLayoutData(gd);
148
fProgText = new Text(mainComp, SWT.SINGLE | SWT.BORDER);
149
gd = new GridData(GridData.FILL_HORIZONTAL);
150
fProgText.setLayoutData(gd);
151
fProgText.addModifyListener(new ModifyListener() {
152
public void modifyText(ModifyEvent evt) {
153
updateLaunchConfigurationDialog();
157
fSearchButton = createPushButton(mainComp, LaunchMessages.getString("CMainTab.Search..."), null); //$NON-NLS-1$
158
fSearchButton.addSelectionListener(new SelectionAdapter() {
160
public void widgetSelected(SelectionEvent evt) {
161
handleSearchButtonSelected();
162
updateLaunchConfigurationDialog();
166
Button browseForBinaryButton;
167
browseForBinaryButton = createPushButton(mainComp, LaunchMessages.getString("Launch.common.Browse_2"), null); //$NON-NLS-1$
168
browseForBinaryButton.addSelectionListener(new SelectionAdapter() {
170
public void widgetSelected(SelectionEvent evt) {
171
String text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Application_Selection")); //$NON-NLS-1$
173
fProgText.setText(text);
175
updateLaunchConfigurationDialog();
181
* Overridden to add the possibility to choose a trace file as a post mortem debug file.
185
protected void createCoreFileGroup(Composite parent, int colSpan) {
186
Composite coreComp = new Composite(parent, SWT.NONE);
187
GridLayout coreLayout = new GridLayout();
188
coreLayout.numColumns = 3;
189
coreLayout.marginHeight = 0;
190
coreLayout.marginWidth = 0;
191
coreComp.setLayout(coreLayout);
192
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
193
gd.horizontalSpan = colSpan;
194
coreComp.setLayoutData(gd);
196
Label comboLabel = new Label(coreComp, SWT.NONE);
197
comboLabel.setText(LaunchMessages.getString("CMainTab.Post_mortem_file_type")); //$NON-NLS-1$
198
comboLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
200
fCoreTypeCombo = new Combo(coreComp, SWT.READ_ONLY | SWT.DROP_DOWN);
201
fCoreTypeCombo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1));
202
fCoreTypeCombo.add(CORE_FILE);
203
fCoreTypeCombo.add(TRACE_FILE);
205
fCoreLabel = new Label(coreComp, SWT.NONE);
206
fCoreLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
207
fCoreText = new Text(coreComp, SWT.SINGLE | SWT.BORDER);
208
gd = new GridData(GridData.FILL_HORIZONTAL);
209
fCoreText.setLayoutData(gd);
210
fCoreText.addModifyListener(new ModifyListener() {
211
public void modifyText(ModifyEvent evt) {
212
updateLaunchConfigurationDialog();
216
Button browseForCoreButton;
217
browseForCoreButton = createPushButton(coreComp, LaunchMessages.getString("Launch.common.Browse_3"), null); //$NON-NLS-1$
218
browseForCoreButton.addSelectionListener(new SelectionAdapter() {
220
public void widgetSelected(SelectionEvent evt) {
222
String coreType = getSelectedCoreType();
223
if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) {
224
text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Core_Selection")); //$NON-NLS-1$
225
} else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) {
226
text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Trace_Selection")); //$NON-NLS-1$
228
assert false : "Unknown core file type"; //$NON-NLS-1$
229
text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Core_Selection")); //$NON-NLS-1$
233
fCoreText.setText(text);
235
updateLaunchConfigurationDialog();
239
fCoreTypeCombo.addSelectionListener(new SelectionListener() {
240
public void widgetSelected(SelectionEvent e) {
241
updateCoreFileLabel();
242
updateLaunchConfigurationDialog();
245
public void widgetDefaultSelected(SelectionEvent e) {
248
fCoreTypeCombo.select(0);
252
* Show a dialog that lets the user select a file.
253
* This method allows to set the title of the dialog.
255
* @param title The title the dialog should show.
259
protected String handleBrowseButtonSelected(String title) {
260
FileDialog fileDialog = new FileDialog(getShell(), SWT.NONE);
261
fileDialog.setText(title);
262
fileDialog.setFileName(fProgText.getText());
263
return fileDialog.open();
269
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
271
public void initializeFrom(ILaunchConfiguration config) {
272
filterPlatform = getPlatform(config);
273
updateProjectFromConfig(config);
274
updateProgramFromConfig(config);
275
updateCoreFromConfig(config);
276
updateBuildOptionFromConfig(config);
280
protected void updateCoreFromConfig(ILaunchConfiguration config) {
281
if (fCoreText != null) {
282
String coreName = EMPTY_STRING;
283
String coreType = IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT;
285
coreName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, EMPTY_STRING);
286
coreType = config.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE,
287
IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT);
288
} catch (CoreException ce) {
291
fCoreText.setText(coreName);
292
if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) {
293
fCoreTypeCombo.setText(CORE_FILE);
294
} else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) {
295
fCoreTypeCombo.setText(TRACE_FILE);
297
assert false : "Unknown core file type"; //$NON-NLS-1$
298
fCoreTypeCombo.setText(CORE_FILE);
300
updateCoreFileLabel();
305
protected String getSelectedCoreType() {
306
int selectedIndex = fCoreTypeCombo.getSelectionIndex();
307
if (fCoreTypeCombo.getItem(selectedIndex).equals(CORE_FILE)) {
308
return IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE;
309
} else if (fCoreTypeCombo.getItem(selectedIndex).equals(TRACE_FILE)) {
310
return IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE;
312
assert false : "Unknown post mortem file type"; //$NON-NLS-1$
313
return IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE;
318
protected void updateCoreFileLabel() {
319
String coreType = getSelectedCoreType();
320
if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) {
321
fCoreLabel.setText(LaunchMessages.getString("CMainTab.CoreFile_path")); //$NON-NLS-1$
322
} else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) {
323
fCoreLabel.setText(LaunchMessages.getString("CMainTab.TraceFile_path")); //$NON-NLS-1$
325
assert false : "Unknown post mortem file type"; //$NON-NLS-1$
326
fCoreLabel.setText(LaunchMessages.getString("CMainTab.CoreFile_path")); //$NON-NLS-1$
333
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
336
public void performApply(ILaunchConfigurationWorkingCopy config) {
337
super.performApply(config);
338
ICProject cProject = this.getCProject();
339
if (cProject != null && cProject.exists())
341
config.setMappedResources(new IResource[] { cProject.getProject() });
343
config.setMappedResources(null);
346
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, fProjText.getText());
347
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, fProgText.getText());
348
if (fCoreText != null) {
349
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, fCoreText.getText());
350
config.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE, getSelectedCoreType());
355
* Show a dialog that lists all main types
358
protected void handleSearchButtonSelected() {
359
if (getCProject() == null) {
360
MessageDialog.openInformation(getShell(), LaunchMessages.getString("CMainTab.Project_required"), //$NON-NLS-1$
361
LaunchMessages.getString("CMainTab.Enter_project_before_searching_for_program")); //$NON-NLS-1$
365
ILabelProvider programLabelProvider = new CElementLabelProvider() {
367
public String getText(Object element) {
368
if (element instanceof IBinary) {
369
IBinary bin = (IBinary)element;
370
StringBuffer name = new StringBuffer();
371
name.append(bin.getPath().lastSegment());
372
return name.toString();
374
return super.getText(element);
378
public Image getImage(Object element) {
379
if (! (element instanceof ICElement)) {
380
return super.getImage(element);
382
ICElement celement = (ICElement)element;
384
if (celement.getElementType() == ICElement.C_BINARY) {
385
IBinary belement = (IBinary)celement;
386
if (belement.isExecutable()) {
387
return DebugUITools.getImage(IDebugUIConstants.IMG_ACT_RUN);
391
return super.getImage(element);
395
ILabelProvider qualifierLabelProvider = new CElementLabelProvider() {
397
public String getText(Object element) {
398
if (element instanceof IBinary) {
399
IBinary bin = (IBinary)element;
400
StringBuffer name = new StringBuffer();
401
name.append(bin.getCPU() + (bin.isLittleEndian() ? "le" : "be")); //$NON-NLS-1$ //$NON-NLS-2$
402
name.append(" - "); //$NON-NLS-1$
403
name.append(bin.getPath().toString());
404
return name.toString();
406
return super.getText(element);
410
TwoPaneElementSelector dialog = new TwoPaneElementSelector(getShell(), programLabelProvider, qualifierLabelProvider);
411
dialog.setElements(getBinaryFiles(getCProject()));
412
dialog.setMessage(LaunchMessages.getString("CMainTab.Choose_program_to_run")); //$NON-NLS-1$
413
dialog.setTitle(LaunchMessages.getString("CMainTab.Program_Selection")); //$NON-NLS-1$
414
dialog.setUpperListLabel(LaunchMessages.getString("Launch.common.BinariesColon")); //$NON-NLS-1$
415
dialog.setLowerListLabel(LaunchMessages.getString("Launch.common.QualifierColon")); //$NON-NLS-1$
416
dialog.setMultipleSelection(false);
418
if (dialog.open() == Window.OK) {
419
IBinary binary = (IBinary)dialog.getFirstResult();
420
fProgText.setText(binary.getResource().getProjectRelativePath().toString());
427
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#isValid(org.eclipse.debug.core.ILaunchConfiguration)
430
public boolean isValid(ILaunchConfiguration config) {
431
setErrorMessage(null);
434
if (!fDontCheckProgram) {
435
String programName = fProgText.getText().trim();
436
if (programName.length() == 0) {
437
setErrorMessage(LaunchMessages.getString("CMainTab.Program_not_specified")); //$NON-NLS-1$
440
if (programName.equals(".") || programName.equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$
441
setErrorMessage(LaunchMessages.getString("CMainTab.Program_does_not_exist")); //$NON-NLS-1$
444
IPath exePath = new Path(programName);
445
if (exePath.isAbsolute()) {
446
// For absolute paths, we don't need a project, we can debug the binary directly
447
// as long as it exists
448
if (!exePath.toFile().exists()) {
449
setErrorMessage(LaunchMessages.getString("CMainTab.Program_does_not_exist")); //$NON-NLS-1$
453
// For relative paths, we need a proper project
454
String projectName = fProjText.getText().trim();
455
if (projectName.length() == 0) {
456
setErrorMessage(LaunchMessages.getString("CMainTab.Project_not_specified")); //$NON-NLS-1$
459
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
460
if (!project.exists()) {
461
setErrorMessage(LaunchMessages.getString("Launch.common.Project_does_not_exist")); //$NON-NLS-1$
464
if (!project.isOpen()) {
465
setErrorMessage(LaunchMessages.getString("CMainTab.Project_must_be_opened")); //$NON-NLS-1$
468
if (!project.getFile(programName).exists()) {
469
setErrorMessage(LaunchMessages.getString("CMainTab.Program_does_not_exist")); //$NON-NLS-1$
473
// Notice that we don't check if exePath points to a valid executable since such
474
// check is too expensive to be done on the UI thread.
475
// See "https://bugs.eclipse.org/bugs/show_bug.cgi?id=328012".
478
if (fCoreText != null) {
479
String coreName = fCoreText.getText().trim();
480
// We accept an empty string. This should trigger a prompt to the user
481
// This allows to re-use the launch, with a different core file.
482
if (!coreName.equals(EMPTY_STRING)) {
483
if (coreName.equals(".") || coreName.equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$
484
setErrorMessage(LaunchMessages.getString("CMainTab.File_does_not_exist")); //$NON-NLS-1$
487
IPath corePath = new Path(coreName);
488
if (!corePath.toFile().exists()) {
489
setErrorMessage(LaunchMessages.getString("CMainTab.File_does_not_exist")); //$NON-NLS-1$
501
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
503
public void setDefaults(ILaunchConfigurationWorkingCopy config) {
504
// We set empty attributes for project & program so that when one config is
505
// compared to another, the existence of empty attributes doesn't cause and
506
// incorrect result (the performApply() method can result in empty values
507
// for these attributes being set on a config if there is nothing in the
508
// corresponding text boxes)
509
// plus getContext will use this to base context from if set.
510
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, EMPTY_STRING);
511
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_ID, EMPTY_STRING);
512
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, EMPTY_STRING);
514
// Set the auto choose build configuration to true for new configurations.
515
// Existing configurations created before this setting was introduced will have this disabled.
516
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_BUILD_CONFIG_AUTO, true);
518
ICElement cElement = null;
519
cElement = getContext(config, getPlatform(config));
520
if (cElement != null) {
521
initializeCProject(cElement, config);
522
initializeProgramName(cElement, config);
524
// don't want to remember the interim value from before
525
config.setMappedResources(null);
530
* Set the program name attributes on the working copy based on the ICElement
532
protected void initializeProgramName(ICElement cElement, ILaunchConfigurationWorkingCopy config) {
533
boolean renamed = false;
535
if (!(cElement instanceof IBinary)) {
536
cElement = cElement.getCProject();
539
if (cElement instanceof ICProject) {
540
IProject project = cElement.getCProject().getProject();
541
String name = project.getName();
542
ICProjectDescription projDes = CCorePlugin.getDefault().getProjectDescription(project);
543
if (projDes != null) {
544
String buildConfigName = projDes.getActiveConfiguration().getName();
545
name = name + " " + buildConfigName; //$NON-NLS-1$
547
name = getLaunchConfigurationDialog().generateName(name);
552
IBinary binary = null;
553
if (cElement instanceof ICProject) {
554
IBinary[] bins = getBinaryFiles((ICProject)cElement);
555
if (bins != null && bins.length == 1) {
558
} else if (cElement instanceof IBinary) {
559
binary = (IBinary)cElement;
562
if (binary != null) {
564
path = binary.getResource().getProjectRelativePath().toOSString();
565
config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, path);
568
String name = binary.getElementName();
569
int index = name.lastIndexOf('.');
571
name = name.substring(0, index);
573
name = getLaunchConfigurationDialog().generateName(name);
580
String name = getLaunchConfigurationDialog().generateName(cElement.getCProject().getElementName());
586
public String getId() {
593
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName()
595
public String getName() {
596
return LaunchMessages.getString("CMainTab.Main"); //$NON-NLS-1$
602
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#getImage()
605
public Image getImage() {
606
return LaunchImages.get(LaunchImages.IMG_VIEW_MAIN_TAB);