author | dadubrow |
Thu, 20 May 2010 13:54:19 -0500 | |
changeset 1378 | 9a387b0094c7 |
parent 94 | d74b720418db |
permissions | -rw-r--r-- |
2 | 1 |
/* |
2 |
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 |
* All rights reserved. |
|
4 |
* This component and the accompanying materials are made available |
|
5 |
* under the terms of the License "Eclipse Public License v1.0" |
|
6 |
* which accompanies this distribution, and is available |
|
7 |
* at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 |
* |
|
9 |
* Initial Contributors: |
|
10 |
* Nokia Corporation - initial contribution. |
|
11 |
* |
|
12 |
* Contributors: |
|
13 |
* |
|
14 |
* Description: |
|
15 |
* |
|
16 |
*/ |
|
17 |
package com.nokia.cdt.internal.debug.launch; |
|
18 |
||
19 |
import java.io.BufferedInputStream; |
|
20 |
import java.io.File; |
|
21 |
import java.io.FileNotFoundException; |
|
22 |
import java.io.IOException; |
|
23 |
import java.io.InputStream; |
|
24 |
import java.io.OutputStream; |
|
25 |
import java.io.RandomAccessFile; |
|
26 |
import java.util.ArrayList; |
|
27 |
import java.util.Arrays; |
|
28 |
||
29 |
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; |
|
30 |
import org.eclipse.cdt.core.model.ICProject; |
|
31 |
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; |
|
32 |
import org.eclipse.cdt.debug.core.ICDebugConfiguration; |
|
33 |
import org.eclipse.cdt.debug.core.cdi.ICDISession; |
|
34 |
import org.eclipse.cdt.launch.internal.ui.LaunchMessages; |
|
35 |
import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin; |
|
36 |
import org.eclipse.cdt.utils.pty.PTY; |
|
37 |
import org.eclipse.cdt.utils.spawner.EnvironmentReader; |
|
38 |
import org.eclipse.cdt.utils.spawner.ProcessFactory; |
|
39 |
import org.eclipse.core.runtime.CoreException; |
|
40 |
import org.eclipse.core.runtime.IPath; |
|
41 |
import org.eclipse.core.runtime.IProgressMonitor; |
|
42 |
import org.eclipse.core.runtime.IStatus; |
|
43 |
import org.eclipse.core.runtime.NullProgressMonitor; |
|
44 |
import org.eclipse.core.runtime.Path; |
|
45 |
import org.eclipse.core.runtime.Status; |
|
46 |
import org.eclipse.core.runtime.SubProgressMonitor; |
|
47 |
import org.eclipse.debug.core.DebugPlugin; |
|
48 |
import org.eclipse.debug.core.ILaunch; |
|
49 |
import org.eclipse.debug.core.ILaunchConfiguration; |
|
50 |
import org.eclipse.debug.core.ILaunchManager; |
|
51 |
import org.eclipse.debug.core.IStatusHandler; |
|
52 |
import org.eclipse.debug.core.model.IProcess; |
|
53 |
import org.eclipse.ui.console.ConsolePlugin; |
|
54 |
import org.eclipse.ui.console.IConsole; |
|
55 |
import org.eclipse.ui.console.IOConsoleOutputStream; |
|
56 |
||
57 |
import com.freescale.cdt.debug.cw.DebuggerLog; |
|
58 |
import com.freescale.cdt.debug.cw.core.cdi.ISessionListener; |
|
59 |
import com.freescale.cdt.debug.cw.core.cdi.Session; |
|
94
d74b720418db
Test framework support: Ask debugger to remember DebugTarget so test framework can use it to setup test framework related utility. With this we can use the DebugUI way of launching while keeping test framework functionality
tzelaw
parents:
2
diff
changeset
|
60 |
import com.freescale.cdt.debug.cw.core.cdi.model.Target; |
2 | 61 |
import com.freescale.cdt.debug.cw.core.settings.DebuggerCommonData; |
62 |
import com.freescale.cdt.debug.cw.core.ui.console.LoggingConsole; |
|
63 |
import com.nokia.cdt.debug.cw.symbian.SettingsData; |
|
64 |
import com.nokia.cdt.debug.cw.symbian.SymbianPlugin; |
|
65 |
||
66 |
import cwdbg.PreferenceConstants; |
|
67 |
||
68 |
public class EmulationLaunchDelegate extends NokiaAbstractLaunchDelegate { |
|
69 |
||
70 |
private IPath verifyHostApp(ILaunchConfiguration config) throws CoreException { |
|
71 |
String hostApp = config.getAttribute(DebuggerCommonData.Host_App_Path, (String)null); |
|
72 |
if (hostApp.length() > 0) |
|
73 |
{ |
|
74 |
Path hostAppPath = new Path(hostApp); |
|
75 |
if (hostAppPath == null || hostAppPath.isEmpty()) { |
|
76 |
return null; |
|
77 |
} |
|
78 |
if (!hostAppPath.toFile().exists()) { |
|
79 |
abort( |
|
80 |
"File does not exist", |
|
81 |
new FileNotFoundException( |
|
82 |
LaunchMessages.getFormattedString( |
|
83 |
"AbstractCLaunchDelegate.PROGRAM_PATH_not_found", hostAppPath.toOSString())), //$NON-NLS-1$ |
|
84 |
ICDTLaunchConfigurationConstants.ERR_PROGRAM_NOT_EXIST); |
|
85 |
} |
|
86 |
return hostAppPath; |
|
87 |
} |
|
88 |
return null; |
|
89 |
} |
|
90 |
||
91 |
public void launch( |
|
92 |
ILaunchConfiguration config, |
|
93 |
String mode, |
|
94 |
ILaunch launch, |
|
95 |
IProgressMonitor monitor) throws CoreException |
|
96 |
{ |
|
97 |
// See comment at definition of the "mutex" for why this "synchronized". |
|
98 |
synchronized(Session.sessionStartStopMutex()) { |
|
99 |
||
100 |
if (monitor == null) { |
|
101 |
monitor = new NullProgressMonitor(); |
|
102 |
} |
|
103 |
||
104 |
monitor.beginTask(LaunchMessages.getString("LocalRunLaunchDelegate.Launching_Local_C_Application"), 10); //$NON-NLS-1$ |
|
105 |
// check for cancellation |
|
106 |
if (monitor.isCanceled()) { |
|
107 |
return; |
|
108 |
} |
|
109 |
try { |
|
110 |
addBeingLaunched(config); // indicating the LC is being launched |
|
111 |
||
112 |
monitor.worked(1); |
|
113 |
IPath exePath = verifyProgramPath(config); |
|
114 |
ICProject project = verifyCProject(config); |
|
115 |
IBinaryObject exeFile = verifyBinary(project, exePath); |
|
116 |
String arguments[] = getProgramArgumentsArray(config); |
|
117 |
verifyHostApp(config); |
|
118 |
||
119 |
// See comment for this method for more. |
|
120 |
SettingsData.setInternalPreferences(config, SettingsData.LaunchConfig_Emulator); |
|
121 |
||
122 |
// set the default source locator if required |
|
123 |
setDefaultSourceLocator(launch, config); |
|
124 |
||
125 |
if (mode.equals(ILaunchManager.DEBUG_MODE)) { |
|
126 |
// debug mode |
|
127 |
ICDebugConfiguration debugConfig = getDebugConfig(config); |
|
128 |
ICDISession dsession = null; |
|
129 |
String debugMode = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, |
|
130 |
ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN); |
|
131 |
if (debugMode.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN)) { |
|
132 |
dsession = debugConfig.createDebugger().createDebuggerSession(launch, exeFile, |
|
133 |
new SubProgressMonitor(monitor, 8)); |
|
134 |
||
135 |
assert(dsession instanceof Session); |
|
136 |
Session cwDebugSession = (Session)dsession; |
|
137 |
||
138 |
doAdditionalSessionSetup(cwDebugSession); |
|
139 |
||
140 |
IPath[] otherExecutables = getOtherExecutables(project, exePath, config, monitor); |
|
141 |
{ |
|
142 |
try { |
|
143 |
monitor.worked(1); |
|
144 |
||
145 |
// if enabled in the prefs, show the console view(s) |
|
146 |
if (config.getAttribute(PreferenceConstants.J_PN_ViewSystemMessage, false)) { |
|
147 |
SymbianPlugin.getDefault().openSystemConsole(true); |
|
148 |
} |
|
149 |
||
150 |
if (config.getAttribute(PreferenceConstants.J_PN_ViewProcessOutput, false)) { |
|
151 |
SymbianPlugin.getDefault().openDebugConsole(true); |
|
152 |
} |
|
153 |
||
154 |
if (config.getAttribute(SymbianPlugin.DebugTraceLaunchSetting, false)) { |
|
155 |
openDebugTraceConsole(cwDebugSession); |
|
156 |
} |
|
157 |
||
158 |
config = synchronizeWithProjectAccessPaths(project, config); |
|
159 |
||
160 |
File wd = getWorkingDirectory(config); |
|
161 |
long t = System.currentTimeMillis(); |
|
94
d74b720418db
Test framework support: Ask debugger to remember DebugTarget so test framework can use it to setup test framework related utility. With this we can use the DebugUI way of launching while keeping test framework functionality
tzelaw
parents:
2
diff
changeset
|
162 |
Target target = cwDebugSession.launchExecutable(launch, config, exeFile, otherExecutables, arguments, wd, getEnvironmentAsProperty(config), monitor, project, renderTargetLabel(debugConfig), true); |
d74b720418db
Test framework support: Ask debugger to remember DebugTarget so test framework can use it to setup test framework related utility. With this we can use the DebugUI way of launching while keeping test framework functionality
tzelaw
parents:
2
diff
changeset
|
163 |
ATFLaunchSupport.saveDebugTargetFromLaunchDelegate(target.getCoreModelTarget()); |
2 | 164 |
t = System.currentTimeMillis() - t; |
165 |
// System.out.println("launchExecutable returns in : " + t); |
|
166 |
DebuggerLog.log("launchExecutable returns in : " + t); |
|
167 |
} catch (CoreException e) { |
|
168 |
Session session = (Session)dsession; |
|
169 |
session.cleanupAfterLaunchFailure(); |
|
170 |
throw e; |
|
171 |
} catch (Exception e) { |
|
172 |
Session session = (Session)dsession; |
|
173 |
session.debuggingStopped(null); |
|
174 |
this.abort(e.getLocalizedMessage(), null, 0); |
|
175 |
} |
|
176 |
} |
|
177 |
} |
|
178 |
} else if (mode.equals(ILaunchManager.RUN_MODE)) { |
|
179 |
// run mode |
|
180 |
File wd = getWorkingDirectory(config); |
|
181 |
if (wd == null) { |
|
182 |
wd = new File(System.getProperty("user.home", ".")); //$NON-NLS-1$ //$NON-NLS-2$ |
|
183 |
} |
|
184 |
ArrayList<String> command = new ArrayList<String>(1 + arguments.length); |
|
185 |
||
186 |
// run the host app if specified |
|
187 |
String hostAppPath = config.getAttribute(DebuggerCommonData.Host_App_Path, ""); //$NON-NLS-1$ |
|
188 |
if (hostAppPath.length() > 0) |
|
189 |
command.add(hostAppPath); |
|
190 |
else |
|
191 |
command.add(exePath.toOSString()); |
|
192 |
||
193 |
command.addAll(Arrays.asList(arguments)); |
|
194 |
String[] commandArray = (String[]) command.toArray(new String[command.size()]); |
|
195 |
boolean usePty = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_USE_TERMINAL, |
|
196 |
ICDTLaunchConfigurationConstants.USE_TERMINAL_DEFAULT); |
|
197 |
monitor.worked(5); |
|
198 |
Process process = exec(commandArray, getEnvironment(config), wd, usePty); |
|
199 |
monitor.worked(3); |
|
200 |
IProcess proc = DebugPlugin.newProcess(launch, process, renderProcessLabel(commandArray[0])); |
|
201 |
||
202 |
// set the command line attribute so it shows up in the process |
|
203 |
// information property page |
|
204 |
String cmdLine = ""; //$NON-NLS-1$ |
|
205 |
for (int i=0; i<commandArray.length; i++) { |
|
206 |
cmdLine += commandArray[i]; |
|
207 |
if (i != commandArray.length - 1) { |
|
208 |
cmdLine += " "; //$NON-NLS-1$ |
|
209 |
} |
|
210 |
} |
|
211 |
proc.setAttribute(IProcess.ATTR_CMDLINE, cmdLine); |
|
212 |
} |
|
213 |
} catch (CoreException e) { |
|
214 |
if (! monitor.isCanceled()) // don't throw on user cancellation |
|
215 |
throw e; |
|
216 |
} finally { |
|
217 |
monitor.done(); |
|
218 |
removeBeingLaunched(config); |
|
219 |
} |
|
220 |
} // end of synchronized |
|
221 |
} |
|
222 |
||
223 |
/** |
|
224 |
* Performs a runtime exec on the given command line in the context of the |
|
225 |
* specified working directory, and returns the resulting process. If the |
|
226 |
* current runtime does not support the specification of a working |
|
227 |
* directory, the status handler for error code |
|
228 |
* <code>ERR_WORKING_DIRECTORY_NOT_SUPPORTED</code> is queried to see if |
|
229 |
* the exec should be re-executed without specifying a working directory. |
|
230 |
* |
|
231 |
* @param cmdLine |
|
232 |
* the command line |
|
233 |
* @param workingDirectory |
|
234 |
* the working directory, or <code>null</code> |
|
235 |
* @return the resulting process or <code>null</code> if the exec is |
|
236 |
* cancelled |
|
237 |
* @see Runtime |
|
238 |
*/ |
|
239 |
protected Process exec(String[] cmdLine, String[] environ, File workingDirectory, boolean usePty) |
|
240 |
throws CoreException { |
|
241 |
Process p = null; |
|
242 |
try { |
|
243 |
if (workingDirectory == null) { |
|
244 |
p = ProcessFactory.getFactory().exec(cmdLine, environ); |
|
245 |
} else { |
|
246 |
if (usePty && PTY.isSupported()) { |
|
247 |
p = ProcessFactory.getFactory().exec(cmdLine, environ, workingDirectory, new PTY()); |
|
248 |
} else { |
|
249 |
p = ProcessFactory.getFactory().exec(cmdLine, environ, workingDirectory); |
|
250 |
} |
|
251 |
} |
|
252 |
} catch (IOException e) { |
|
253 |
if (p != null) { |
|
254 |
p.destroy(); |
|
255 |
} |
|
256 |
abort(LaunchMessages.getString("LocalRunLaunchDelegate.Error_starting_process"), e, //$NON-NLS-1$ |
|
257 |
ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); |
|
258 |
} catch (NoSuchMethodError e) { |
|
259 |
//attempting launches on 1.2.* - no ability to set working |
|
260 |
// directory |
|
261 |
||
262 |
IStatus status = new Status(IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), |
|
263 |
ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_NOT_SUPPORTED, LaunchMessages |
|
264 |
.getString("LocalRunLaunchDelegate.Does_not_support_working_dir"), //$NON-NLS-1$ |
|
265 |
e); |
|
266 |
IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler(status); |
|
267 |
||
268 |
if (handler != null) { |
|
269 |
Object result = handler.handleStatus(status, this); |
|
270 |
if (result instanceof Boolean && ((Boolean) result).booleanValue()) { |
|
271 |
p = exec(cmdLine, environ, null, usePty); |
|
272 |
} |
|
273 |
} |
|
274 |
} |
|
275 |
return p; |
|
276 |
} |
|
277 |
||
278 |
@Override |
|
279 |
protected String getCPUString() { |
|
280 |
return "x86"; //$NON-NLS-1$ |
|
281 |
} |
|
282 |
||
283 |
/** |
|
284 |
* Input stream at the tail of a file, used to capture the contents of the epocwind.out file. |
|
285 |
*/ |
|
286 |
public class FileTailInputStream extends InputStream { |
|
287 |
||
288 |
private RandomAccessFile file; |
|
289 |
private long tail; |
|
290 |
||
291 |
public FileTailInputStream(File file) throws IOException { |
|
292 |
super(); |
|
293 |
this.file = new RandomAccessFile(file, "r"); //$NON-NLS-1$ |
|
294 |
||
295 |
// save the original file length when the input stream is created |
|
296 |
tail = file.length(); |
|
297 |
||
298 |
// start at the tail of the file |
|
299 |
this.file.seek(tail); |
|
300 |
} |
|
301 |
||
302 |
public int read() throws IOException { |
|
303 |
checkTail(); |
|
304 |
byte[] b = new byte[1]; |
|
305 |
int len = file.read(b, 0, 1); |
|
306 |
if (len < 0) { |
|
307 |
return len; |
|
308 |
} |
|
309 |
return b[0]; |
|
310 |
} |
|
311 |
||
312 |
public int read(byte[] b) throws IOException { |
|
313 |
checkTail(); |
|
314 |
return file.read(b, 0, b.length); |
|
315 |
} |
|
316 |
||
317 |
public int read(byte[] b, int off, int len) throws IOException { |
|
318 |
checkTail(); |
|
319 |
return file.read(b, off, len); |
|
320 |
} |
|
321 |
||
322 |
public void close() throws IOException { |
|
323 |
file.close(); |
|
324 |
} |
|
325 |
||
326 |
private void checkTail() throws IOException { |
|
327 |
// this checks to see if the file was cleared at |
|
328 |
// some point after we created the input stream. if |
|
329 |
// so we want to start at the beginning of the file. |
|
330 |
if (file.length() < tail) { |
|
331 |
tail = 0; |
|
332 |
file.seek(0); |
|
333 |
} |
|
334 |
} |
|
335 |
} |
|
336 |
||
337 |
// file monitoring thread |
|
338 |
class ReadThread extends Thread implements Runnable, ISessionListener { |
|
339 |
||
340 |
private InputStream in = null; |
|
341 |
private OutputStream out = null; |
|
342 |
private boolean keepListening = true; |
|
343 |
||
344 |
public ReadThread(InputStream in, OutputStream out) { |
|
345 |
this.in = in; |
|
346 |
this.out = out; |
|
347 |
setName("epocwind monitor thread"); //$NON-NLS-1$ |
|
348 |
} |
|
349 |
||
350 |
public void run() { |
|
351 |
||
352 |
byte[] buffer = new byte[1024]; |
|
353 |
||
354 |
try { |
|
355 |
while (keepListening) { |
|
356 |
int bytesRead = in.read(buffer); |
|
357 |
if (bytesRead > 0) { |
|
358 |
out.write(buffer, 0, bytesRead); |
|
359 |
} |
|
360 |
||
361 |
try { |
|
362 |
Thread.sleep(20); |
|
363 |
} catch (InterruptedException e) { |
|
364 |
} |
|
365 |
} |
|
366 |
} catch (IOException e) { |
|
367 |
LaunchUIPlugin.log(e); |
|
368 |
} finally { |
|
369 |
// close the input stream (the file). leave the output stream open |
|
370 |
// for future debug sessions. |
|
371 |
try { |
|
372 |
in.close(); |
|
373 |
} catch (IOException e) { |
|
374 |
} |
|
375 |
} |
|
376 |
} |
|
377 |
||
378 |
public void sessionEnded() { |
|
379 |
keepListening = false; |
|
380 |
} |
|
381 |
} |
|
382 |
||
383 |
public void openDebugTraceConsole(Session session) { |
|
384 |
final String consoleName = SymbianPlugin.DebugTraceMessagesConsoleName; |
|
385 |
||
386 |
// add it if necessary |
|
387 |
LoggingConsole console = null; |
|
388 |
boolean found = false; |
|
389 |
||
390 |
IConsole[] consoles = ConsolePlugin.getDefault().getConsoleManager().getConsoles(); |
|
391 |
for (int i=0; i<consoles.length; i++) { |
|
392 |
if (consoleName.equals(consoles[i].getName())) { |
|
393 |
console = (LoggingConsole)consoles[i]; |
|
394 |
found = true; |
|
395 |
break; |
|
396 |
} |
|
397 |
} |
|
398 |
||
399 |
if (!found) { |
|
400 |
console = new LoggingConsole(consoleName); |
|
401 |
ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[]{console}); |
|
402 |
} |
|
403 |
||
404 |
ConsolePlugin.getDefault().getConsoleManager().showConsoleView(console); |
|
405 |
||
406 |
// clear the console and get an output stream for it |
|
407 |
console.clearConsole(); |
|
408 |
IOConsoleOutputStream consoleOut = console.getLoggingStream(); |
|
409 |
||
410 |
// locate the file |
|
411 |
File traceFile = null; |
|
412 |
String value = EnvironmentReader.getEnvVar("TEMP"); //$NON-NLS-1$ |
|
413 |
if (value != null) { |
|
414 |
try { |
|
415 |
traceFile = new File(value + "\\epocwind.out").getCanonicalFile(); //$NON-NLS-1$ |
|
416 |
} catch (IOException e) { |
|
417 |
e.printStackTrace(); |
|
418 |
} |
|
419 |
} |
|
420 |
||
421 |
if (traceFile != null) { |
|
422 |
// create it if it doesn't already exist. the emulator would create it but |
|
423 |
// hasn't been launched yet and we need to create an input stream from the file now. |
|
424 |
if (!traceFile.exists()) { |
|
425 |
try { |
|
426 |
traceFile.createNewFile(); |
|
427 |
} catch (IOException e) { |
|
428 |
e.printStackTrace(); |
|
429 |
} |
|
430 |
} |
|
431 |
||
432 |
try { |
|
433 |
// create the monitor thread and kick it off |
|
434 |
FileTailInputStream inputStream = new FileTailInputStream(traceFile); |
|
435 |
ReadThread rt = new ReadThread(new BufferedInputStream(inputStream), consoleOut); |
|
436 |
session.addListener(rt); |
|
437 |
rt.start(); |
|
438 |
} catch (IOException e) { |
|
439 |
} |
|
440 |
} else { |
|
441 |
try { |
|
442 |
consoleOut.write("Unable to open %TEMP%\\epocwind.out"); //$NON-NLS-1$ |
|
443 |
consoleOut.close(); |
|
444 |
} catch (IOException e) { |
|
445 |
e.printStackTrace(); |
|
446 |
} |
|
447 |
} |
|
448 |
} |
|
449 |
} |