1
/*******************************************************************************
2
* Copyright (c) 2011 Ericsson 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
* Ericsson - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.cdt.dsf.gdb.service;
14
import java.util.Properties;
16
import org.eclipse.cdt.debug.core.CDebugUtils;
17
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
18
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
19
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
20
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
21
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
22
import org.eclipse.cdt.dsf.concurrent.ReflectionSequence;
23
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
24
import org.eclipse.cdt.dsf.datamodel.DMContexts;
25
import org.eclipse.cdt.dsf.datamodel.IDMContext;
26
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
27
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
28
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
29
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
30
import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages;
31
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext;
32
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
33
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
34
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
35
import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager;
36
import org.eclipse.cdt.dsf.mi.service.MIProcesses;
37
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
38
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
39
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
40
import org.eclipse.core.runtime.CoreException;
41
import org.eclipse.core.runtime.IProgressMonitor;
42
import org.eclipse.core.runtime.IStatus;
43
import org.eclipse.core.runtime.Status;
44
import org.eclipse.core.runtime.jobs.Job;
45
import org.eclipse.debug.core.DebugPlugin;
46
import org.eclipse.debug.core.IStatusHandler;
49
* This sequence is used to start debugging a new process.
53
public class DebugNewProcessSequence extends ReflectionSequence {
55
private final static String INVALID = "invalid"; //$NON-NLS-1$
57
private IGDBControl fCommandControl;
58
private CommandFactory fCommandFactory;
59
private IGDBBackend fBackend;
60
private IGDBProcesses fProcService;
61
private DsfServicesTracker fTracker;
63
private IDMContext fContext;
64
private String fBinaryName;
65
private Map<String, Object> fAttributes;
66
private IMIContainerDMContext fContainerCtx;
68
// Store the dataRM so that we can fill it with the container context that we will be creating
69
private DataRequestMonitor<IDMContext> fDataRequestMonitor;
72
protected IMIContainerDMContext getContainerContext() {
76
protected void setContainerContext(IMIContainerDMContext ctx) {
80
public DebugNewProcessSequence(DsfExecutor executor, boolean isInitial, IDMContext dmc, String file, Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) {
84
fAttributes = attributes;
85
fDataRequestMonitor = rm;
89
protected String[] getExecutionOrder(String group) {
90
if (GROUP_TOP_LEVEL.equals(group)) {
92
"stepInitializeBaseSequence", //$NON-NLS-1$
93
"stepSetEnvironmentVariables", //$NON-NLS-1$
94
"stepSetExecutable", //$NON-NLS-1$
95
"stepSetArguments", //$NON-NLS-1$
97
// For remote non-attach only
98
"stepRemoteConnection", //$NON-NLS-1$
99
// For post-mortem launch only
100
"stepSpecifyCoreFile", //$NON-NLS-1$
102
"stepStartTrackingBreakpoints", //$NON-NLS-1$
103
"stepStartExecution", //$NON-NLS-1$
104
"stepCleanupBaseSequence", //$NON-NLS-1$
111
* Initialize the members of the DebugNewProcessSequence class.
112
* This step is mandatory for the rest of the sequence to complete.
115
public void stepInitializeBaseSequence(RequestMonitor rm) {
116
fTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fContext.getSessionId());
117
fBackend = fTracker.getService(IGDBBackend.class);
118
fCommandControl = fTracker.getService(IGDBControl.class);
119
fCommandFactory = fTracker.getService(IMICommandControl.class).getCommandFactory();
120
fProcService = fTracker.getService(IGDBProcesses.class);
122
if (fBackend == null || fCommandControl == null || fCommandFactory == null || fProcService == null) {
123
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot obtain service", null)); //$NON-NLS-1$
128
// When we are starting to debug a new process, the container is the default process used by GDB.
129
// We don't have a pid yet, so we can simply create the container with the UNIQUE_GROUP_ID
130
setContainerContext(fProcService.createContainerContextFromGroupId(fCommandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID));
136
* Rollback method for {@link #stepInitializeBaseSequence()}
139
@RollBack("stepInitializeBaseSequence")
140
public void rollBackInitializeBaseSequence(RequestMonitor rm) {
141
if (fTracker != null) fTracker.dispose();
147
* Specify environment variables if needed
150
public void stepSetEnvironmentVariables(RequestMonitor rm) {
151
boolean clear = false;
152
Properties properties = new Properties();
154
// here we need to pass the proper container context
155
clear = fBackend.getClearEnvironment();
156
properties = fBackend.getEnvironmentVariables();
157
} catch (CoreException e) {
158
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Cannot get environment information", e)); //$NON-NLS-1$
163
if (clear == true || properties.size() > 0) {
164
// here we need to pass the proper container context
165
fCommandControl.setEnvironment(properties, clear, rm);
172
* Specify the executable file to be debugged and read the symbol table.
175
public void stepSetExecutable(RequestMonitor rm) {
176
boolean noFileCommand = CDebugUtils.getAttribute(
178
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP,
179
IGDBLaunchConfigurationConstants.DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP_DEFAULT);
181
if (!noFileCommand && fBinaryName != null && fBinaryName.length() > 0) {
182
fCommandControl.queueCommand(
183
fCommandFactory.createMIFileExecAndSymbols(getContainerContext(), fBinaryName),
184
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
191
* Specify the arguments to the program that will be run.
194
public void stepSetArguments(RequestMonitor rm) {
196
String args = fBackend.getProgramArguments();
199
String[] argArray = args.replaceAll("\n", " ").split(" "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
200
fCommandControl.queueCommand(
201
fCommandFactory.createMIGDBSetArgs(getContainerContext(), argArray),
202
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
206
} catch (CoreException e) {
207
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Cannot get inferior arguments", e)); //$NON-NLS-1$
213
* If we are dealing with a remote debugging session, connect to the target.
217
public void stepRemoteConnection(RequestMonitor rm) {
218
// If we are dealing with a non-attach remote session, it is now time to connect
219
// to the remote side. Note that this is the 'target remote' case
220
// and not the 'target extended-remote' case (remote attach session)
221
// This step is actually global for GDB. However, we have to do it after
222
// we have specified the executable, so we have to do it here.
223
// It is safe to do it here because a 'target remote' does not support
224
// multi-process so this step will not be executed more than once.
225
if (fBackend.getSessionType() == SessionType.REMOTE && !fBackend.getIsAttachSession()) {
226
boolean isTcpConnection = CDebugUtils.getAttribute(
228
IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP,
231
if (isTcpConnection) {
232
String remoteTcpHost = CDebugUtils.getAttribute(
234
IGDBLaunchConfigurationConstants.ATTR_HOST, INVALID);
235
String remoteTcpPort = CDebugUtils.getAttribute(
237
IGDBLaunchConfigurationConstants.ATTR_PORT, INVALID);
239
fCommandControl.queueCommand(
240
fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
241
remoteTcpHost, remoteTcpPort, false),
242
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
244
String serialDevice = CDebugUtils.getAttribute(
246
IGDBLaunchConfigurationConstants.ATTR_DEV, INVALID);
247
fCommandControl.queueCommand(
248
fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
249
serialDevice, false),
250
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
258
protected static class PromptForCoreJob extends Job {
259
protected DataRequestMonitor<String> fRequestMonitor;
261
public PromptForCoreJob(String name, DataRequestMonitor<String> rm) {
263
fRequestMonitor = rm;
267
protected IStatus run(IProgressMonitor monitor) {
268
final IStatus promptStatus = new Status(IStatus.INFO, "org.eclipse.debug.ui", 200/*STATUS_HANDLER_PROMPT*/, "", null); //$NON-NLS-1$//$NON-NLS-2$
269
final IStatus filePrompt = new Status(IStatus.INFO, "org.eclipse.cdt.dsf.gdb.ui", 1001, "", null); //$NON-NLS-1$//$NON-NLS-2$
270
// consult a status handler
271
final IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(promptStatus);
273
final Status NO_CORE_STATUS = new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1,
274
LaunchMessages.getString("LocalCDILaunchDelegate.6"), //$NON-NLS-1$
277
if (prompter == null) {
278
fRequestMonitor.setStatus(NO_CORE_STATUS);
279
fRequestMonitor.done();
280
return Status.OK_STATUS;
284
Object result = prompter.handleStatus(filePrompt, null);
285
if (result == null) {
286
fRequestMonitor.cancel();
287
} else if (result instanceof String) {
288
fRequestMonitor.setData((String)result);
290
fRequestMonitor.setStatus(NO_CORE_STATUS);
292
} catch (CoreException e) {
293
fRequestMonitor.setStatus(NO_CORE_STATUS);
295
fRequestMonitor.done();
297
return Status.OK_STATUS;
302
* If we are dealing with a postmortem session, connect to the core/trace file.
306
public void stepSpecifyCoreFile(final RequestMonitor rm) {
307
// If we are dealing with a postmortem session, it is now time to connect
308
// to the core/trace file. We have to do this step after
309
// we have specified the executable, so we have to do it here.
310
// It is safe to do it here because a postmortem session does not support
311
// multi-process so this step will not be executed more than once.
313
if (fBackend.getSessionType() == SessionType.CORE) {
314
String coreFile = CDebugUtils.getAttribute(
316
ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, ""); //$NON-NLS-1$
317
final String coreType = CDebugUtils.getAttribute(
319
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE,
320
IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT);
322
if (coreFile.length() == 0) {
323
new PromptForCoreJob(
324
"Prompt for post mortem file", //$NON-NLS-1$
325
new DataRequestMonitor<String>(getExecutor(), rm) {
327
protected void handleCancel() {
332
protected void handleSuccess() {
333
String newCoreFile = getData();
334
if (newCoreFile == null || newCoreFile.length()== 0) {
335
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get post mortem file path", null)); //$NON-NLS-1$
338
if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) {
339
fCommandControl.queueCommand(
340
fCommandFactory.createMITargetSelectCore(fCommandControl.getContext(), newCoreFile),
341
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
342
} else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) {
343
IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class);
344
if (traceControl != null) {
345
ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(fCommandControl.getContext(), ITraceTargetDMContext.class);
346
traceControl.loadTraceData(targetDmc, newCoreFile, rm);
348
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Tracing not supported", null));
352
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Invalid post-mortem type", null));
359
if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) {
360
fCommandControl.queueCommand(
361
fCommandFactory.createMITargetSelectCore(fCommandControl.getContext(), coreFile),
362
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
363
} else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) {
364
IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class);
365
if (traceControl != null) {
366
ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(fCommandControl.getContext(), ITraceTargetDMContext.class);
367
traceControl.loadTraceData(targetDmc, coreFile, rm);
369
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Tracing not supported", null));
373
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Invalid post-mortem type", null));
383
* Start tracking the breakpoints. Note that for remote debugging
384
* we should first connect to the target.
387
public void stepStartTrackingBreakpoints(RequestMonitor rm) {
388
if (fBackend.getSessionType() != SessionType.CORE) {
389
MIBreakpointsManager bpmService = fTracker.getService(MIBreakpointsManager.class);
390
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(getContainerContext(), IBreakpointsTargetDMContext.class);
391
bpmService.startTrackingBreakpoints(bpTargetDmc, rm);
398
* Start executing the program.
401
public void stepStartExecution(final RequestMonitor rm) {
402
if (fBackend.getSessionType() != SessionType.CORE) {
403
// Overwrite the program name to use the binary name that was specified.
404
// This is important for multi-process
406
fAttributes.put(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, fBinaryName);
408
fProcService.start(getContainerContext(), fAttributes, new DataRequestMonitor<IContainerDMContext>(ImmediateExecutor.getInstance(), rm) {
410
protected void handleSuccess() {
411
assert getData() instanceof IMIContainerDMContext;
413
// Set the container that we created
414
setContainerContext(DMContexts.getAncestorOfType(getData(), IMIContainerDMContext.class));
415
fDataRequestMonitor.setData(getContainerContext());
417
// Don't call fDataRequestMonitor.done(), the sequence will
418
// automatically do that when it completes;
423
fDataRequestMonitor.setData(getContainerContext());
429
* Cleanup now that the sequence has been run.
433
public void stepCleanupBaseSequence(RequestMonitor rm) {
b'\\ No newline at end of file'