| Index: visual_studio/NativeClientVSAddIn/NativeClientVSAddIn/PluginDebuggerGDB.cs | 
| diff --git a/visual_studio/NativeClientVSAddIn/NativeClientVSAddIn/PluginDebuggerGDB.cs b/visual_studio/NativeClientVSAddIn/NativeClientVSAddIn/PluginDebuggerGDB.cs | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..2dbf6bbfabc4c9d270202018413cdd2aec6b8217 | 
| --- /dev/null | 
| +++ b/visual_studio/NativeClientVSAddIn/NativeClientVSAddIn/PluginDebuggerGDB.cs | 
| @@ -0,0 +1,216 @@ | 
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +namespace NativeClientVSAddIn | 
| +{ | 
| +  using System; | 
| +  using System.IO; | 
| +  using System.Text; | 
| +  using System.Windows.Forms; | 
| + | 
| +  using EnvDTE; | 
| +  using EnvDTE80; | 
| + | 
| +  /// <summary> | 
| +  /// This class handles the details of finding a nexe and attaching to it. | 
| +  /// </summary> | 
| +  public class PluginDebuggerGDB : PluginDebuggerBase | 
| +  { | 
| +    /// <summary> | 
| +    /// Path to the actual plug-in assembly. | 
| +    /// </summary> | 
| +    private string pluginAssembly_; | 
| + | 
| +    /// <summary> | 
| +    /// Directory of the plug-in project we are debugging. | 
| +    /// </summary> | 
| +    private string pluginProjectDirectory_; | 
| + | 
| +    /// <summary> | 
| +    /// Path to the NaCl IRT. | 
| +    /// </summary> | 
| +    private string irtPath_; | 
| + | 
| +    /// <summary> | 
| +    /// Path to the project's nmf file. | 
| +    /// </summary> | 
| +    private string manifestPath_; | 
| + | 
| +    /// <summary> | 
| +    /// If debugging a .nexe this is the nacl-gdb process object. | 
| +    /// </summary> | 
| +    private System.Diagnostics.Process gdbProcess_; | 
| + | 
| +    /// <summary> | 
| +    /// Path to NaCl-GDB executable. | 
| +    /// </summary> | 
| +    private string gdbPath_; | 
| + | 
| +    /// <summary> | 
| +    /// Path to the gdb initialization file that we auto-generate from the VS project. | 
| +    /// </summary> | 
| +    private string gdbInitFileName_; | 
| + | 
| +    /// <summary> | 
| +    /// Constructs the PluginDebuggerHelper. | 
| +    /// </summary> | 
| +    /// <param name="dte">Automation object from Visual Studio.</param> | 
| +    /// <param name="properties">PropertyManager pointing to a valid project/platform.</param> | 
| +    public PluginDebuggerGDB(DTE2 dte, PropertyManager properties) | 
| +        : base(dte, properties) | 
| +    { | 
| +      irtPath_ = properties.IrtPath; | 
| +      manifestPath_ = properties.ManifestPath; | 
| +      pluginAssembly_ = properties.PluginAssembly; | 
| +      pluginProjectDirectory_ = properties.ProjectDirectory; | 
| +      gdbPath_ = Path.Combine( | 
| +          properties.SDKRootDirectory, | 
| +          "toolchain", | 
| +          properties.PlatformToolset, | 
| +          @"bin\x86_64-nacl-gdb.exe"); | 
| + | 
| +      PluginFoundEvent += new EventHandler<PluginFoundEventArgs>(Attach); | 
| +    } | 
| + | 
| +    /// <summary> | 
| +    /// Disposes the object. If disposing is false then this has been called by garbage collection, | 
| +    /// and we shouldn't reference managed objects. | 
| +    /// </summary> | 
| +    /// <param name="disposing">True if user call to Dispose, false if garbage collection.</param> | 
| +    protected override void Dispose(bool disposing) | 
| +    { | 
| +      if (!Disposed) | 
| +      { | 
| +        base.Dispose(disposing); | 
| + | 
| +        if (disposing) | 
| +        { | 
| +          CleanUpGDBProcess(); | 
| +        } | 
| + | 
| +        // This is repeated functionality from CleanUpGDBProcess but will | 
| +        // only touch unmanaged resources as required by disposing=false. | 
| +        if (!string.IsNullOrEmpty(gdbInitFileName_) && File.Exists(gdbInitFileName_)) | 
| +        { | 
| +          File.Delete(gdbInitFileName_); | 
| +          gdbInitFileName_ = null; | 
| +        } | 
| + | 
| +        Disposed = true; | 
| +      } | 
| +    } | 
| + | 
| +    /// <summary> | 
| +    /// Called to check if a process is a valid nacl module to attach to. | 
| +    /// </summary> | 
| +    /// <param name="proc">Contains information about the process in question.</param> | 
| +    /// <param name="mainChromeFlags">Flags on the main Chrome process.</param> | 
| +    /// <returns>True if we should attach to the process.</returns> | 
| +    protected override bool IsPluginProcess(ProcessInfo proc, string mainChromeFlags) | 
| +    { | 
| +      // Ensure the main chrome process has the nacl debug flag, otherwise we shouldn't | 
| +      // try to attach to anything. | 
| +      if (!mainChromeFlags.Contains(Strings.NaClDebugFlag)) | 
| +      { | 
| +        return false; | 
| +      } | 
| + | 
| +      StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase; | 
| +      return proc.Name.Equals(Strings.NaClProcessName, ignoreCase) && | 
| +             proc.CommandLine.Contains(Strings.NaClLoaderFlag, ignoreCase); | 
| +    } | 
| + | 
| +    /// <summary> | 
| +    /// This function cleans up the started GDB process. | 
| +    /// </summary> | 
| +    private void CleanUpGDBProcess() | 
| +    { | 
| +      Utility.EnsureProcessKill(ref gdbProcess_); | 
| +      if (!string.IsNullOrEmpty(gdbInitFileName_) && File.Exists(gdbInitFileName_)) | 
| +      { | 
| +        File.Delete(gdbInitFileName_); | 
| +        gdbInitFileName_ = null; | 
| +      } | 
| +    } | 
| + | 
| +    /// <summary> | 
| +    /// Attaches the NaCl GDB debugger to the NaCl plug-in process.  Handles loading symbols | 
| +    /// and breakpoints from Visual Studio. | 
| +    /// </summary> | 
| +    /// <param name="src">The parameter is not used.</param> | 
| +    /// <param name="args"> | 
| +    /// Contains the process ID to attach to, unused since debug stub is already attached. | 
| +    /// </param> | 
| +    private void Attach(object src, PluginFoundEventArgs args) | 
| +    { | 
| +      // Clean up any pre-existing GDB process (can happen if user reloads page). | 
| +      CleanUpGDBProcess(); | 
| + | 
| +      // Create the initialization file to read in on GDB start. | 
| +      gdbInitFileName_ = Path.GetTempFileName(); | 
| +      StringBuilder contents = new StringBuilder(); | 
| + | 
| +      if (!string.IsNullOrEmpty(manifestPath_)) | 
| +      { | 
| +        string manifestEscaped = manifestPath_.Replace("\\", "\\\\"); | 
| +        contents.AppendFormat("nacl-manifest {0}\n", manifestEscaped); | 
| +      } | 
| +      else | 
| +      { | 
| +        string pluginAssemblyEscaped = pluginAssembly_.Replace("\\", "\\\\"); | 
| +        contents.AppendFormat("file \"{0}\"\n", pluginAssemblyEscaped); | 
| +      } | 
| + | 
| +      string irtPathEscaped = irtPath_.Replace("\\", "\\\\"); | 
| +      contents.AppendFormat("nacl-irt {0}\n", irtPathEscaped); | 
| +      contents.AppendFormat("target remote localhost:{0}\n", 4014); | 
| + | 
| +      // Insert breakpoints from Visual Studio project. | 
| +      if (Dte.Debugger.Breakpoints != null) | 
| +      { | 
| +        foreach (Breakpoint bp in Dte.Debugger.Breakpoints) | 
| +        { | 
| +          if (!bp.Enabled) | 
| +          { | 
| +            continue; | 
| +          } | 
| + | 
| +          if (bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocationTypeFile) | 
| +          { | 
| +            contents.AppendFormat("b {0}:{1}\n", Path.GetFileName(bp.File), bp.FileLine); | 
| +          } | 
| +          else if (bp.LocationType == dbgBreakpointLocationType.dbgBreakpointLocationTypeFunction) | 
| +          { | 
| +            contents.AppendFormat("b {0}\n", bp.FunctionName); | 
| +          } | 
| +          else | 
| +          { | 
| +            Utility.WebServerWriteLine( | 
| +                Dte, | 
| +                string.Format(Strings.UnsupportedBreakpointTypeFormat, bp.LocationType.ToString())); | 
| +          } | 
| +        } | 
| +      } | 
| + | 
| +      contents.AppendLine("continue"); | 
| +      File.WriteAllText(gdbInitFileName_, contents.ToString()); | 
| + | 
| +      // Start NaCl-GDB. | 
| +      try | 
| +      { | 
| +        gdbProcess_ = new System.Diagnostics.Process(); | 
| +        gdbProcess_.StartInfo.UseShellExecute = true; | 
| +        gdbProcess_.StartInfo.FileName = gdbPath_; | 
| +        gdbProcess_.StartInfo.Arguments = string.Format("-x {0}", gdbInitFileName_); | 
| +        gdbProcess_.StartInfo.WorkingDirectory = pluginProjectDirectory_; | 
| +        gdbProcess_.Start(); | 
| +      } | 
| +      catch (Exception e) | 
| +      { | 
| +        MessageBox.Show( | 
| +            string.Format("NaCl-GDB Start Failed. {0}. Path: {1}", e.Message, gdbPath_)); | 
| +      } | 
| +    } | 
| +  } | 
| +} | 
|  |