OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 namespace NativeClientVSAddIn | 5 namespace NativeClientVSAddIn |
6 { | 6 { |
7 using System; | 7 using System; |
8 using System.Collections.Generic; | 8 using System.Collections.Generic; |
9 using System.IO; | 9 using System.IO; |
10 using System.Linq; | 10 using System.Linq; |
(...skipping 16 matching lines...) Expand all Loading... |
27 /// </summary> | 27 /// </summary> |
28 private const int InitialPluginCheckFrequency = 1000; | 28 private const int InitialPluginCheckFrequency = 1000; |
29 | 29 |
30 /// <summary> | 30 /// <summary> |
31 /// After a plug-in has been found, we slow the frequency of checking | 31 /// After a plug-in has been found, we slow the frequency of checking |
32 /// for new ones. This value is in milliseconds. | 32 /// for new ones. This value is in milliseconds. |
33 /// </summary> | 33 /// </summary> |
34 private const int RelaxedPluginCheckFrequency = 5000; | 34 private const int RelaxedPluginCheckFrequency = 5000; |
35 | 35 |
36 /// <summary> | 36 /// <summary> |
| 37 /// The web server port to default to if the user does not specify one. |
| 38 /// </summary> |
| 39 private const int DefaultWebServerPort = 5103; |
| 40 |
| 41 /// <summary> |
37 /// The main visual studio object through which all Visual Studio functions
are executed. | 42 /// The main visual studio object through which all Visual Studio functions
are executed. |
38 /// </summary> | 43 /// </summary> |
39 private DTE2 dte_; | 44 private DTE2 dte_; |
40 | 45 |
41 /// <summary> | 46 /// <summary> |
42 /// Indicates the PluginDebuggerHelper is configured properly to run. | 47 /// Indicates the PluginDebuggerHelper is configured properly to run. |
43 /// </summary> | 48 /// </summary> |
44 private bool isProperlyInitialized_ = false; | 49 private bool isProperlyInitialized_ = false; |
45 | 50 |
46 /// <summary> | 51 /// <summary> |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 projectPlatformType_ = ProjectPlatformType.NaCl; | 231 projectPlatformType_ = ProjectPlatformType.NaCl; |
227 PluginFoundEvent += new EventHandler<PluginFoundEventArgs>(AttachNaClGDB
); | 232 PluginFoundEvent += new EventHandler<PluginFoundEventArgs>(AttachNaClGDB
); |
228 } | 233 } |
229 else | 234 else |
230 { | 235 { |
231 projectPlatformType_ = ProjectPlatformType.Other; | 236 projectPlatformType_ = ProjectPlatformType.Other; |
232 return false; | 237 return false; |
233 } | 238 } |
234 | 239 |
235 // We only support certain project types (e.g. C/C++ projects). Otherwise
we fail. | 240 // We only support certain project types (e.g. C/C++ projects). Otherwise
we fail. |
236 // If supported, extract necessary information from specific project type. | 241 if (!Utility.IsVisualCProject(startProject)) |
237 if (Utility.IsVisualCProject(startProject)) | |
238 { | |
239 VCConfiguration config = Utility.GetActiveVCConfiguration(startProject); | |
240 IVCRulePropertyStorage general = config.Rules.Item("ConfigurationGeneral
"); | |
241 VCLinkerTool linker = config.Tools.Item("VCLinkerTool"); | |
242 VCProject vcproj = (VCProject)startProject.Object; | |
243 | |
244 sdkRootDirectory_ = general.GetEvaluatedPropertyValue("VSNaClSDKRoot"); | |
245 platformToolset = general.GetEvaluatedPropertyValue("PlatformToolset"); | |
246 pluginOutputDirectory_ = config.Evaluate(config.OutputDirectory); | |
247 pluginAssembly_ = config.Evaluate(linker.OutputFile); | |
248 pluginProjectDirectory_ = vcproj.ProjectDirectory; // Macros not allowe
d here. | |
249 | |
250 if (projectPlatformType_ == ProjectPlatformType.NaCl) | |
251 { | |
252 irtPath_ = general.GetEvaluatedPropertyValue("NaClIrtPath"); | |
253 manifestPath_ = general.GetEvaluatedPropertyValue("NaClManifestPath"); | |
254 } | |
255 } | |
256 else | |
257 { | 242 { |
258 return false; | 243 return false; |
259 } | 244 } |
260 | 245 |
| 246 // Extract necessary information from specific project type. |
| 247 VCConfiguration config = Utility.GetActiveVCConfiguration(startProject); |
| 248 IVCRulePropertyStorage general = config.Rules.Item("ConfigurationGeneral")
; |
| 249 VCLinkerTool linker = config.Tools.Item("VCLinkerTool"); |
| 250 VCProject vcproj = (VCProject)startProject.Object; |
| 251 |
| 252 sdkRootDirectory_ = general.GetEvaluatedPropertyValue("VSNaClSDKRoot"); |
| 253 platformToolset = general.GetEvaluatedPropertyValue("PlatformToolset"); |
| 254 pluginOutputDirectory_ = config.Evaluate(config.OutputDirectory); |
| 255 pluginAssembly_ = config.Evaluate(linker.OutputFile); |
| 256 pluginProjectDirectory_ = vcproj.ProjectDirectory; // Macros not allowed
here. |
| 257 |
| 258 if (projectPlatformType_ == ProjectPlatformType.NaCl) |
| 259 { |
| 260 irtPath_ = general.GetEvaluatedPropertyValue("NaClIrtPath"); |
| 261 manifestPath_ = general.GetEvaluatedPropertyValue("NaClManifestPath"); |
| 262 } |
| 263 |
261 if (string.IsNullOrEmpty(sdkRootDirectory_)) | 264 if (string.IsNullOrEmpty(sdkRootDirectory_)) |
262 { | 265 { |
263 MessageBox.Show( | 266 MessageBox.Show(Strings.SDKPathNotSetError); |
264 string.Format(Strings.SDKPathNotSetFormat, Strings.SDKPathEnvironmen
tVariable)); | |
265 return false; | 267 return false; |
266 } | 268 } |
267 | 269 |
268 sdkRootDirectory_ = sdkRootDirectory_.TrimEnd("/\\".ToArray<char>()); | 270 sdkRootDirectory_ = sdkRootDirectory_.TrimEnd("/\\".ToArray<char>()); |
269 | 271 |
270 // TODO(tysand): Add user option to specify this. | 272 // TODO(tysand): Move this code getting port to where the web server is st
arted. |
271 int webServerPort = 5103; | 273 int webServerPort; |
| 274 if (!int.TryParse(general.GetEvaluatedPropertyValue("NaClWebServerPort"),
out webServerPort)) |
| 275 { |
| 276 webServerPort = DefaultWebServerPort; |
| 277 } |
| 278 |
272 webServerExecutable_ = "python.exe"; | 279 webServerExecutable_ = "python.exe"; |
273 webServerArguments_ = string.Format( | 280 webServerArguments_ = string.Format( |
274 "{0}\\examples\\httpd.py --no_dir_check {1}", | 281 "{0}\\examples\\httpd.py --no_dir_check {1}", sdkRootDirectory_, webSe
rverPort); |
275 sdkRootDirectory_, | |
276 webServerPort); | |
277 | 282 |
278 gdbPath_ = Path.Combine( | 283 gdbPath_ = Path.Combine( |
279 sdkRootDirectory_, "toolchain", platformToolset, @"bin\x86_64-nacl-gdb
.exe"); | 284 sdkRootDirectory_, "toolchain", platformToolset, @"bin\x86_64-nacl-gdb
.exe"); |
280 | 285 |
281 debuggedChromeMainProcess_ = null; | 286 debuggedChromeMainProcess_ = null; |
282 | 287 |
283 isProperlyInitialized_ = true; | 288 isProperlyInitialized_ = true; |
284 return true; | 289 return true; |
285 } | 290 } |
286 | 291 |
(...skipping 23 matching lines...) Expand all Loading... |
310 | 315 |
311 // Remove all event handlers from the plug-in found event. | 316 // Remove all event handlers from the plug-in found event. |
312 if (PluginFoundEvent != null) | 317 if (PluginFoundEvent != null) |
313 { | 318 { |
314 foreach (Delegate del in PluginFoundEvent.GetInvocationList()) | 319 foreach (Delegate del in PluginFoundEvent.GetInvocationList()) |
315 { | 320 { |
316 PluginFoundEvent -= (EventHandler<PluginFoundEventArgs>)del; | 321 PluginFoundEvent -= (EventHandler<PluginFoundEventArgs>)del; |
317 } | 322 } |
318 } | 323 } |
319 | 324 |
320 if (webServer_ != null) | 325 Utility.EnsureProcessKill(ref webServer_); |
321 { | 326 WebServerWriteLine(Strings.WebServerStopMessage); |
322 webServer_.Kill(); | 327 CleanUpGDBProcess(); |
323 webServer_.Dispose(); | |
324 webServer_ = null; | |
325 } | |
326 | |
327 KillGDBProcess(); | |
328 } | 328 } |
329 | 329 |
330 /// <summary> | 330 /// <summary> |
331 /// This function cleans up the started GDB process. | 331 /// This function cleans up the started GDB process. |
332 /// </summary> | 332 /// </summary> |
333 private void KillGDBProcess() | 333 private void CleanUpGDBProcess() |
334 { | 334 { |
335 if (gdbProcess_ != null) | 335 Utility.EnsureProcessKill(ref gdbProcess_); |
| 336 if (!string.IsNullOrEmpty(gdbInitFileName_) && File.Exists(gdbInitFileName
_)) |
336 { | 337 { |
337 if (!gdbProcess_.HasExited) | 338 File.Delete(gdbInitFileName_); |
338 { | 339 gdbInitFileName_ = null; |
339 gdbProcess_.Kill(); | |
340 gdbProcess_.Dispose(); | |
341 } | |
342 | |
343 if (!string.IsNullOrEmpty(gdbInitFileName_) && File.Exists(gdbInitFileNa
me_)) | |
344 { | |
345 File.Delete(gdbInitFileName_); | |
346 } | |
347 | |
348 gdbProcess_ = null; | |
349 } | 340 } |
350 } | 341 } |
351 | 342 |
352 /// <summary> | 343 /// <summary> |
353 /// This is called periodically by the Visual Studio UI thread to look for o
ur plug-in process | 344 /// This is called periodically by the Visual Studio UI thread to look for o
ur plug-in process |
354 /// and attach the debugger to it. The call is triggered by the pluginFinde
rTimer_ object. | 345 /// and attach the debugger to it. The call is triggered by the pluginFinde
rTimer_ object. |
355 /// </summary> | 346 /// </summary> |
356 /// <param name="unused">The parameter is not used.</param> | 347 /// <param name="unused">The parameter is not used.</param> |
357 /// <param name="unused1">The parameter is not used.</param> | 348 /// <param name="unused1">The parameter is not used.</param> |
358 private void FindAndAttachToPlugin(object unused, EventArgs unused1) | 349 private void FindAndAttachToPlugin(object unused, EventArgs unused1) |
(...skipping 13 matching lines...) Expand all Loading... |
372 } | 363 } |
373 } | 364 } |
374 | 365 |
375 return; | 366 return; |
376 } | 367 } |
377 | 368 |
378 // Get the list of all descendants of the main chrome process. | 369 // Get the list of all descendants of the main chrome process. |
379 uint mainChromeProcId = (uint)debuggedChromeMainProcess_.Id; | 370 uint mainChromeProcId = (uint)debuggedChromeMainProcess_.Id; |
380 List<ProcessInfo> chromeDescendants = processSearcher_.GetDescendants(main
ChromeProcId); | 371 List<ProcessInfo> chromeDescendants = processSearcher_.GetDescendants(main
ChromeProcId); |
381 | 372 |
| 373 // If we didn't start with debug flags then we should not attach. |
| 374 string mainChromeFlags = chromeDescendants.Find(p => p.ID == mainChromePro
cId).CommandLine; |
| 375 if (projectPlatformType_ == ProjectPlatformType.NaCl && |
| 376 !mainChromeFlags.Contains(Strings.NaClDebugFlag)) |
| 377 { |
| 378 return; |
| 379 } |
| 380 |
382 // From the list of descendants, find the plug-in by it's command line arg
uments and | 381 // From the list of descendants, find the plug-in by it's command line arg
uments and |
383 // process name as well as not being attached to already. | 382 // process name as well as not being attached to already. |
384 List<ProcessInfo> plugins; | 383 List<ProcessInfo> plugins; |
385 switch (projectPlatformType_) | 384 switch (projectPlatformType_) |
386 { | 385 { |
387 case ProjectPlatformType.Pepper: | 386 case ProjectPlatformType.Pepper: |
388 string identifierFlagTarget = | 387 string identifierFlagTarget = |
389 string.Format(Strings.PepperProcessPluginFlagFormat, pluginAssembl
y_); | 388 string.Format(Strings.PepperProcessPluginFlagFormat, pluginAssembl
y_); |
390 plugins = chromeDescendants.FindAll(p => | 389 plugins = chromeDescendants.FindAll(p => |
391 p.Name.Equals(Strings.ChromeProcessName, ignoreCase) && | 390 p.Name.Equals(Strings.ChromeProcessName, ignoreCase) && |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 /// Attaches the NaCl GDB debugger to the NaCl plug-in process. Handles loa
ding symbols | 436 /// Attaches the NaCl GDB debugger to the NaCl plug-in process. Handles loa
ding symbols |
438 /// and breakpoints from Visual Studio. | 437 /// and breakpoints from Visual Studio. |
439 /// </summary> | 438 /// </summary> |
440 /// <param name="src">The parameter is not used.</param> | 439 /// <param name="src">The parameter is not used.</param> |
441 /// <param name="args"> | 440 /// <param name="args"> |
442 /// Contains the process ID to attach to, unused since debug stub is already
attached. | 441 /// Contains the process ID to attach to, unused since debug stub is already
attached. |
443 /// </param> | 442 /// </param> |
444 private void AttachNaClGDB(object src, PluginFoundEventArgs args) | 443 private void AttachNaClGDB(object src, PluginFoundEventArgs args) |
445 { | 444 { |
446 // Clean up any pre-existing GDB process (can happen if user reloads page)
. | 445 // Clean up any pre-existing GDB process (can happen if user reloads page)
. |
447 KillGDBProcess(); | 446 CleanUpGDBProcess(); |
448 | 447 |
449 gdbInitFileName_ = Path.GetTempFileName(); | 448 gdbInitFileName_ = Path.GetTempFileName(); |
450 string pluginAssemblyEscaped = pluginAssembly_.Replace("\\", "\\\\"); | 449 string pluginAssemblyEscaped = pluginAssembly_.Replace("\\", "\\\\"); |
451 string irtPathEscaped = irtPath_.Replace("\\", "\\\\"); | 450 string irtPathEscaped = irtPath_.Replace("\\", "\\\\"); |
452 | 451 |
453 // Create the initialization file to read in on GDB start. | 452 // Create the initialization file to read in on GDB start. |
454 StringBuilder contents = new StringBuilder(); | 453 StringBuilder contents = new StringBuilder(); |
455 | 454 |
456 if (!string.IsNullOrEmpty(manifestPath_)) | 455 if (!string.IsNullOrEmpty(manifestPath_)) |
457 { | 456 { |
458 string manifestEscaped = manifestPath_.Replace("\\", "\\\\"); | 457 string manifestEscaped = manifestPath_.Replace("\\", "\\\\"); |
459 contents.AppendFormat("nacl-manifest {0}\n", manifestEscaped); | 458 contents.AppendFormat("nacl-manifest {0}\n", manifestEscaped); |
460 } | 459 } |
461 else | 460 else |
462 { | 461 { |
463 contents.AppendFormat("file \"{0}\"\n", pluginAssemblyEscaped); | 462 contents.AppendFormat("file \"{0}\"\n", pluginAssemblyEscaped); |
464 } | 463 } |
465 | 464 |
466 contents.AppendFormat("nacl-irt {0}\n", irtPathEscaped); | 465 contents.AppendFormat("nacl-irt {0}\n", irtPathEscaped); |
467 contents.AppendFormat("target remote localhost:{0}\n", 4014); | 466 contents.AppendFormat("target remote localhost:{0}\n", 4014); |
468 | 467 |
469 // Insert breakpoints from Visual Studio project. | 468 // Insert breakpoints from Visual Studio project. |
470 foreach (Breakpoint bp in dte_.Debugger.Breakpoints) | 469 foreach (Breakpoint bp in dte_.Debugger.Breakpoints) |
471 { | 470 { |
472 if (bp.Enabled && | 471 if (!bp.Enabled) |
473 bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocationTy
peFile) | |
474 { | 472 { |
475 contents.AppendFormat("b {0}:{1}", Path.GetFileName(bp.File), bp.FileL
ine); | 473 continue; |
476 contents.AppendLine(); | |
477 } | 474 } |
478 else if (bp.Enabled && | 475 |
479 bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocationTy
peFunction) | 476 if (bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocationTy
peFile) |
480 { | 477 { |
481 contents.AppendFormat("b {0}", bp.FunctionName); | 478 contents.AppendFormat("b {0}:{1}\n", Path.GetFileName(bp.File), bp.Fil
eLine); |
482 contents.AppendLine(); | |
483 } | 479 } |
484 else if (bp.Enabled) | 480 else if (bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocat
ionTypeFunction) |
| 481 { |
| 482 contents.AppendFormat("b {0}\n", bp.FunctionName); |
| 483 } |
| 484 else |
485 { | 485 { |
486 WebServerWriteLine( | 486 WebServerWriteLine( |
487 string.Format(Strings.UnsupportedBreakpointTypeFormat, bp.LocationTy
pe.ToString())); | 487 string.Format(Strings.UnsupportedBreakpointTypeFormat, bp.LocationTy
pe.ToString())); |
488 } | 488 } |
489 } | 489 } |
490 | 490 |
491 contents.AppendLine("continue"); | 491 contents.AppendLine("continue"); |
492 File.WriteAllText(gdbInitFileName_, contents.ToString()); | 492 File.WriteAllText(gdbInitFileName_, contents.ToString()); |
493 | 493 |
494 // Start NaCl-GDB. | 494 // Start NaCl-GDB. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 { | 556 { |
557 WebServerWriteLine(e.Data); | 557 WebServerWriteLine(e.Data); |
558 } | 558 } |
559 | 559 |
560 /// <summary> | 560 /// <summary> |
561 /// Helper function to write data to the Web Server Output Pane. | 561 /// Helper function to write data to the Web Server Output Pane. |
562 /// </summary> | 562 /// </summary> |
563 /// <param name="message">Message to write.</param> | 563 /// <param name="message">Message to write.</param> |
564 private void WebServerWriteLine(string message) | 564 private void WebServerWriteLine(string message) |
565 { | 565 { |
566 webServerOutputPane_.OutputString(message + "\n"); | 566 if (webServerOutputPane_ != null) |
| 567 { |
| 568 webServerOutputPane_.OutputString(message + "\n"); |
| 569 } |
567 } | 570 } |
568 | 571 |
569 /// <summary> | 572 /// <summary> |
570 /// The event arguments when a plug-in is found. | 573 /// The event arguments when a plug-in is found. |
571 /// </summary> | 574 /// </summary> |
572 public class PluginFoundEventArgs : EventArgs | 575 public class PluginFoundEventArgs : EventArgs |
573 { | 576 { |
574 /// <summary> | 577 /// <summary> |
575 /// Construct the PluginFoundEventArgs. | 578 /// Construct the PluginFoundEventArgs. |
576 /// </summary> | 579 /// </summary> |
577 /// <param name="pid">Process ID of the found plug-in.</param> | 580 /// <param name="pid">Process ID of the found plug-in.</param> |
578 public PluginFoundEventArgs(uint pid) | 581 public PluginFoundEventArgs(uint pid) |
579 { | 582 { |
580 this.ProcessID = pid; | 583 this.ProcessID = pid; |
581 } | 584 } |
582 | 585 |
583 /// <summary> | 586 /// <summary> |
584 /// Gets or sets process ID of the found plug-in. | 587 /// Gets or sets process ID of the found plug-in. |
585 /// </summary> | 588 /// </summary> |
586 public uint ProcessID { get; set; } | 589 public uint ProcessID { get; set; } |
587 } | 590 } |
588 } | 591 } |
589 } | 592 } |
OLD | NEW |