OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 namespace NativeClientVSAddIn |
| 6 { |
| 7 using System; |
| 8 using System.IO; |
| 9 using System.Text; |
| 10 using System.Windows.Forms; |
| 11 |
| 12 using EnvDTE; |
| 13 using EnvDTE80; |
| 14 |
| 15 /// <summary> |
| 16 /// This class handles the details of finding a nexe and attaching to it. |
| 17 /// </summary> |
| 18 public class PluginDebuggerGDB : PluginDebuggerBase |
| 19 { |
| 20 /// <summary> |
| 21 /// Path to the actual plug-in assembly. |
| 22 /// </summary> |
| 23 private string pluginAssembly_; |
| 24 |
| 25 /// <summary> |
| 26 /// Directory of the plug-in project we are debugging. |
| 27 /// </summary> |
| 28 private string pluginProjectDirectory_; |
| 29 |
| 30 /// <summary> |
| 31 /// Path to the NaCl IRT. |
| 32 /// </summary> |
| 33 private string irtPath_; |
| 34 |
| 35 /// <summary> |
| 36 /// Path to the project's nmf file. |
| 37 /// </summary> |
| 38 private string manifestPath_; |
| 39 |
| 40 /// <summary> |
| 41 /// If debugging a .nexe this is the nacl-gdb process object. |
| 42 /// </summary> |
| 43 private System.Diagnostics.Process gdbProcess_; |
| 44 |
| 45 /// <summary> |
| 46 /// Path to NaCl-GDB executable. |
| 47 /// </summary> |
| 48 private string gdbPath_; |
| 49 |
| 50 /// <summary> |
| 51 /// Path to the gdb initialization file that we auto-generate from the VS pr
oject. |
| 52 /// </summary> |
| 53 private string gdbInitFileName_; |
| 54 |
| 55 /// <summary> |
| 56 /// Constructs the PluginDebuggerHelper. |
| 57 /// </summary> |
| 58 /// <param name="dte">Automation object from Visual Studio.</param> |
| 59 /// <param name="properties">PropertyManager pointing to a valid project/pla
tform.</param> |
| 60 public PluginDebuggerGDB(DTE2 dte, PropertyManager properties) |
| 61 : base(dte, properties) |
| 62 { |
| 63 irtPath_ = properties.IrtPath; |
| 64 manifestPath_ = properties.ManifestPath; |
| 65 pluginAssembly_ = properties.PluginAssembly; |
| 66 pluginProjectDirectory_ = properties.ProjectDirectory; |
| 67 gdbPath_ = Path.Combine( |
| 68 properties.SDKRootDirectory, |
| 69 "toolchain", |
| 70 properties.PlatformToolset, |
| 71 @"bin\x86_64-nacl-gdb.exe"); |
| 72 |
| 73 PluginFoundEvent += new EventHandler<PluginFoundEventArgs>(Attach); |
| 74 } |
| 75 |
| 76 /// <summary> |
| 77 /// Disposes the object. If disposing is false then this has been called by
garbage collection, |
| 78 /// and we shouldn't reference managed objects. |
| 79 /// </summary> |
| 80 /// <param name="disposing">True if user call to Dispose, false if garbage c
ollection.</param> |
| 81 protected override void Dispose(bool disposing) |
| 82 { |
| 83 if (!Disposed) |
| 84 { |
| 85 base.Dispose(disposing); |
| 86 |
| 87 if (disposing) |
| 88 { |
| 89 CleanUpGDBProcess(); |
| 90 } |
| 91 |
| 92 // This is repeated functionality from CleanUpGDBProcess but will |
| 93 // only touch unmanaged resources as required by disposing=false. |
| 94 if (!string.IsNullOrEmpty(gdbInitFileName_) && File.Exists(gdbInitFileNa
me_)) |
| 95 { |
| 96 File.Delete(gdbInitFileName_); |
| 97 gdbInitFileName_ = null; |
| 98 } |
| 99 |
| 100 Disposed = true; |
| 101 } |
| 102 } |
| 103 |
| 104 /// <summary> |
| 105 /// Called to check if a process is a valid nacl module to attach to. |
| 106 /// </summary> |
| 107 /// <param name="proc">Contains information about the process in question.</
param> |
| 108 /// <param name="mainChromeFlags">Flags on the main Chrome process.</param> |
| 109 /// <returns>True if we should attach to the process.</returns> |
| 110 protected override bool IsPluginProcess(ProcessInfo proc, string mainChromeF
lags) |
| 111 { |
| 112 // Ensure the main chrome process has the nacl debug flag, otherwise we sh
ouldn't |
| 113 // try to attach to anything. |
| 114 if (!mainChromeFlags.Contains(Strings.NaClDebugFlag)) |
| 115 { |
| 116 return false; |
| 117 } |
| 118 |
| 119 StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase; |
| 120 return proc.Name.Equals(Strings.NaClProcessName, ignoreCase) && |
| 121 proc.CommandLine.Contains(Strings.NaClLoaderFlag, ignoreCase); |
| 122 } |
| 123 |
| 124 /// <summary> |
| 125 /// This function cleans up the started GDB process. |
| 126 /// </summary> |
| 127 private void CleanUpGDBProcess() |
| 128 { |
| 129 Utility.EnsureProcessKill(ref gdbProcess_); |
| 130 if (!string.IsNullOrEmpty(gdbInitFileName_) && File.Exists(gdbInitFileName
_)) |
| 131 { |
| 132 File.Delete(gdbInitFileName_); |
| 133 gdbInitFileName_ = null; |
| 134 } |
| 135 } |
| 136 |
| 137 /// <summary> |
| 138 /// Attaches the NaCl GDB debugger to the NaCl plug-in process. Handles loa
ding symbols |
| 139 /// and breakpoints from Visual Studio. |
| 140 /// </summary> |
| 141 /// <param name="src">The parameter is not used.</param> |
| 142 /// <param name="args"> |
| 143 /// Contains the process ID to attach to, unused since debug stub is already
attached. |
| 144 /// </param> |
| 145 private void Attach(object src, PluginFoundEventArgs args) |
| 146 { |
| 147 // Clean up any pre-existing GDB process (can happen if user reloads page)
. |
| 148 CleanUpGDBProcess(); |
| 149 |
| 150 // Create the initialization file to read in on GDB start. |
| 151 gdbInitFileName_ = Path.GetTempFileName(); |
| 152 StringBuilder contents = new StringBuilder(); |
| 153 |
| 154 if (!string.IsNullOrEmpty(manifestPath_)) |
| 155 { |
| 156 string manifestEscaped = manifestPath_.Replace("\\", "\\\\"); |
| 157 contents.AppendFormat("nacl-manifest {0}\n", manifestEscaped); |
| 158 } |
| 159 else |
| 160 { |
| 161 string pluginAssemblyEscaped = pluginAssembly_.Replace("\\", "\\\\"); |
| 162 contents.AppendFormat("file \"{0}\"\n", pluginAssemblyEscaped); |
| 163 } |
| 164 |
| 165 string irtPathEscaped = irtPath_.Replace("\\", "\\\\"); |
| 166 contents.AppendFormat("nacl-irt {0}\n", irtPathEscaped); |
| 167 contents.AppendFormat("target remote localhost:{0}\n", 4014); |
| 168 |
| 169 // Insert breakpoints from Visual Studio project. |
| 170 if (Dte.Debugger.Breakpoints != null) |
| 171 { |
| 172 foreach (Breakpoint bp in Dte.Debugger.Breakpoints) |
| 173 { |
| 174 if (!bp.Enabled) |
| 175 { |
| 176 continue; |
| 177 } |
| 178 |
| 179 if (bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocation
TypeFile) |
| 180 { |
| 181 contents.AppendFormat("b {0}:{1}\n", Path.GetFileName(bp.File), bp.F
ileLine); |
| 182 } |
| 183 else if (bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLoc
ationTypeFunction) |
| 184 { |
| 185 contents.AppendFormat("b {0}\n", bp.FunctionName); |
| 186 } |
| 187 else |
| 188 { |
| 189 Utility.WebServerWriteLine( |
| 190 Dte, |
| 191 string.Format(Strings.UnsupportedBreakpointTypeFormat, bp.Locati
onType.ToString())); |
| 192 } |
| 193 } |
| 194 } |
| 195 |
| 196 contents.AppendLine("continue"); |
| 197 File.WriteAllText(gdbInitFileName_, contents.ToString()); |
| 198 |
| 199 // Start NaCl-GDB. |
| 200 try |
| 201 { |
| 202 gdbProcess_ = new System.Diagnostics.Process(); |
| 203 gdbProcess_.StartInfo.UseShellExecute = true; |
| 204 gdbProcess_.StartInfo.FileName = gdbPath_; |
| 205 gdbProcess_.StartInfo.Arguments = string.Format("-x {0}", gdbInitFileNam
e_); |
| 206 gdbProcess_.StartInfo.WorkingDirectory = pluginProjectDirectory_; |
| 207 gdbProcess_.Start(); |
| 208 } |
| 209 catch (Exception e) |
| 210 { |
| 211 MessageBox.Show( |
| 212 string.Format("NaCl-GDB Start Failed. {0}. Path: {1}", e.Message, gd
bPath_)); |
| 213 } |
| 214 } |
| 215 } |
| 216 } |
OLD | NEW |