diff options
author | Lluis Sanchez Gual <lluis@xamarin.com> | 2014-06-04 20:47:32 +0400 |
---|---|---|
committer | Lluis Sanchez Gual <lluis@xamarin.com> | 2014-06-04 21:14:46 +0400 |
commit | d60a13af675e68705083ec78861ea7ec0d9a9a7b (patch) | |
tree | afeba355cd4fbb1ee134595d9ea136237e5d6fb0 /main | |
parent | f6ee1d2cf8d4e8656bc8199c8620eef4e3dc6f7c (diff) |
Move the gdb debugger to the main solution
Diffstat (limited to 'main')
-rw-r--r-- | main/Main.sln | 15 | ||||
-rw-r--r-- | main/configure.in | 3 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/AddinInfo.cs | 16 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/AssemblyInfo.cs | 9 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/ChangeLog | 365 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/CommandStatus.cs | 38 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/GdbBacktrace.cs | 400 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/GdbCommandResult.cs | 53 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/GdbEvent.cs | 49 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/GdbSession.cs | 730 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/GdbSessionFactory.cs | 151 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/Makefile.am | 1 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/Manifest.addin.xml | 8 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/MonoDevelop.Debugger.Gdb.csproj | 100 | ||||
-rw-r--r-- | main/src/addins/MonoDevelop.Debugger.Gdb/ResultData.cs | 229 |
15 files changed, 2166 insertions, 1 deletions
diff --git a/main/Main.sln b/main/Main.sln index bf3350c84c..5f16bcac0f 100644 --- a/main/Main.sln +++ b/main/Main.sln @@ -162,6 +162,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.Debugger.Tests" EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.Debugger.Tests.TestApp", "src\addins\MonoDevelop.Debugger\MonoDevelop.Debugger.Tests.TestApp\MonoDevelop.Debugger.Tests.TestApp.csproj", "{05EDFE55-C8D1-47E4-BB61-0BC809CD82E2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.Debugger.Gdb", "src\addins\MonoDevelop.Debugger.Gdb\MonoDevelop.Debugger.Gdb.csproj", "{FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}"
+EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MonoDevelop.Debugger.Win32", "MonoDevelop.Debugger.Win32", "{8F47F5EC-2F57-4030-B658-7B1002DA90C2}"
ProjectSection(SolutionItems) = preProject
src\addins\MonoDevelop.Debugger.Win32\eula.rtf = src\addins\MonoDevelop.Debugger.Win32\eula.rtf
@@ -1900,6 +1902,18 @@ Global {F8F92AA4-A376-4679-A9D4-60E7B7FBF477}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
{F8F92AA4-A376-4679-A9D4-60E7B7FBF477}.ReleaseWin32|Any CPU.ActiveCfg = Release|Any CPU
{F8F92AA4-A376-4679-A9D4-60E7B7FBF477}.ReleaseWin32|Any CPU.Build.0 = Release|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.DebugGnome|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.DebugGnome|Any CPU.Build.0 = Debug|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.DebugWin32|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.ReleaseGnome|Any CPU.ActiveCfg = Release|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.ReleaseGnome|Any CPU.Build.0 = Release|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}.ReleaseWin32|Any CPU.ActiveCfg = Release|Any CPU
{FEC19BDA-4904-4005-8C09-68E82E8BEF6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEC19BDA-4904-4005-8C09-68E82E8BEF6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEC19BDA-4904-4005-8C09-68E82E8BEF6A}.DebugGnome|Any CPU.ActiveCfg = Debug|Any CPU
@@ -1995,6 +2009,7 @@ Global {2357AABD-08C7-4808-A495-8FF2D3CDFDB0} = {776872D9-76FA-407B-BA69-08E25A24E5CE}
{174E6044-DD3A-49AB-9A5C-2A1F341B7B4F} = {776872D9-76FA-407B-BA69-08E25A24E5CE}
{05EDFE55-C8D1-47E4-BB61-0BC809CD82E2} = {776872D9-76FA-407B-BA69-08E25A24E5CE}
+ {FA15FC26-A7E7-4932-93B7-65FAE6D5DD33} = {776872D9-76FA-407B-BA69-08E25A24E5CE}
{9FBCC262-10DC-4E84-A5C4-17230BBF8862} = {8F47F5EC-2F57-4030-B658-7B1002DA90C2}
{69136056-BFD3-4CEC-BB41-D9991C79593C} = {8F47F5EC-2F57-4030-B658-7B1002DA90C2}
{7E4B15FB-E8C4-419A-A31C-9310FD9062BD} = {8F47F5EC-2F57-4030-B658-7B1002DA90C2}
diff --git a/main/configure.in b/main/configure.in index bb761c1b03..94e9d58d08 100644 --- a/main/configure.in +++ b/main/configure.in @@ -215,7 +215,7 @@ fi AM_CONDITIONAL(ENABLE_MACPLATFORM, [test x$enable_macplatform = xyes]) -# Mac bundle +# Mac bundle AC_ARG_ENABLE(macbundle, AC_HELP_STRING([--enable-macbundle], [enable Mac bundle packaging [default=no]]), @@ -335,6 +335,7 @@ src/addins/MonoDevelop.SourceEditor2/Makefile src/addins/MonoDevelop.XmlEditor/Makefile src/addins/MonoDevelop.Refactoring/Makefile src/addins/MonoDevelop.Debugger/Makefile +src/addins/MonoDevelop.Debugger.Gdb/Makefile src/addins/MonoDevelop.Debugger.Soft/Makefile src/addins/MonoDevelop.Debugger.Soft/MonoDevelop.Debugger.Soft/Makefile src/addins/MonoDevelop.Debugger.Soft/MonoDevelop.Debugger.Soft.AspNet/Makefile diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/AddinInfo.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/AddinInfo.cs new file mode 100644 index 0000000000..3cd8505305 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/AddinInfo.cs @@ -0,0 +1,16 @@ + +using System; +using Mono.Addins; +using Mono.Addins.Description; + +[assembly:Addin ("Debugger.Gdb", + Namespace = "MonoDevelop", + Version = MonoDevelop.BuildInfo.Version, + Category = "Debugging")] + +[assembly:AddinName ("GDB Debugger Support")] +[assembly:AddinDescription ("Support for debugging native applications using the GDB debugger")] + +[assembly:AddinDependency ("Core", MonoDevelop.BuildInfo.Version)] +[assembly:AddinDependency ("Ide", MonoDevelop.BuildInfo.Version)] +[assembly:AddinDependency ("Debugger", MonoDevelop.BuildInfo.Version)] diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/AssemblyInfo.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/AssemblyInfo.cs new file mode 100644 index 0000000000..ad3b28e1a8 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/AssemblyInfo.cs @@ -0,0 +1,9 @@ +// Autogenerated from Manifest.addin.xml + +using System.Reflection; + +[assembly: AssemblyProduct ("MonoDevelop")] +[assembly: AssemblyTitle ("GDB support for Mono.Debugging")] +[assembly: AssemblyDescription ("GNU Debugger support for Mono.Debugging")] +[assembly: AssemblyVersion ("2.6")] +[assembly: AssemblyCopyright ("MIT X11")] diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/ChangeLog b/main/src/addins/MonoDevelop.Debugger.Gdb/ChangeLog new file mode 100644 index 0000000000..ce5286dfe1 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/ChangeLog @@ -0,0 +1,365 @@ +2010-06-14 Lluis Sanchez Gual <lluis@novell.com> + + * configure: Bump MD version. + +2010-05-20 Lluis Sanchez Gual <lluis@novell.com> + + * configure: Bump MD version. + +2010-05-20 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2010-05-07 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2010-05-03 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Increased console creation timeout. + +2010-04-28 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Track api changes. + +2010-04-19 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + + * MonoDevelop.Debugger.csproj: Flush. + +2010-03-22 Lluis Sanchez Gual <lluis@novell.com> + + * configure: + * AssemblyInfo.cs: + * Manifest.addin.xml: Bumped MD version. + +2010-03-17 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.csproj: Flush. + +2010-03-17 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.csproj: Merged MD.Projects into + MD.Core, and MD.Projects.Gui, MD.Core.Gui and MD.Components + into MD.Ide. + +2010-03-15 David Makovský <yakeen@sannyas-on.net> + + * GdbBacktrace.cs: fixes for C++ structures (thx Martin Vejnár + <avakar@ratatanek.cz>) + +2010-03-08 Jonathan Pryor <jpryor@novell.com> + + * configure: Create a $(CSC) make variable. + * MonoDevelop.Debugger.Gdb.make: Set $(ASSEMBLY_COMPILER_COMMAND) to + $(CSC). This allows a top-level CSC override to be used within this + module (e.g. top-level `make CSC=dmcs` for a v4 build). + +2010-03-03 Michael Hutchinson <mhutchinson@novell.com> + + * GdbSession.cs: Name the reader thread. + +2010-03-01 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.Gdb.sln: The invariant policy can't be + used anymore as base policy set. + +2010-02-22 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2010-02-20 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Add missing method. + +2010-02-19 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2010-02-16 Lluis Sanchez Gual <lluis@novell.com> + + * Manifest.addin.xml: + * GdbSessionFactory.cs: Track api changes. Some engine info is + now taken from extension node metadata. + + * MonoDevelop.Debugger.csproj: + * MonoDevelop.Debugger.Gdb.sln: Flush. + + * GdbSession.cs: Expressions are now printed by the debugging + service. + +2009-12-11 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2009-11-20 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSessionFactory.cs: Implement Id property. + +2009-11-18 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2009-11-12 Lluis Sanchez Gual <lluis@novell.com> + + * GdbEvent.cs: Reason can be an array. Handle this case. + + * MonoDevelop.Debugger.csproj: Flush. + + * GdbSession.cs: If there is an error while initializing, + report that the process has exited. + +2009-10-30 Lluis Sanchez Gual <lluis@novell.com> + + * configure: + * AssemblyInfo.cs: + * Manifest.addin.xml: Bump MD version. + +2009-10-18 Michael Hutchinson <mhutchinson@novell.com> + + * GdbSession.cs: Fix Pocess/Process spelling. + +2009-10-16 Michael Hutchinson <mhutchinson@novell.com> + + * GdbSessionFactory.cs: Fix spelling of GetAttachableProcesses + API. + +2009-10-07 Lluis Sanchez Gual <lluis@novell.com> + + * configure: + * AssemblyInfo.cs: + * Manifest.addin.xml: Bump MD version. + +2009-10-05 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: + * GdbBacktrace.cs: Use long for thread and process id. + +2009-10-01 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.Gdb.sln: + + * GdbSession.cs: Don't crash if a breakpoint can't be set. + +2009-08-20 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.csproj: + * MonoDevelop.Debugger.Gdb.sln: Updated. + + * GdbSession.cs: Quote file names when needed. + +2009-05-19 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.csproj: Flush. + +2009-04-27 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSessionFactory.cs: + * MonoDevelop.Debugger.csproj: + * MonoDevelop.Debugger.Gdb.make: Track api changes. + +2009-04-15 Lluis Sanchez Gual <lluis@novell.com> + + * configure: + * AssemblyInfo.cs: + * Manifest.addin.xml: Bump MD version. + +2009-03-04 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSessionFactory.cs: Removed unused CanDebugPlatform and + rename CanDebugFile to CanDebugCommand. + +2009-03-04 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSessionFactory.cs: Changed the way execution handlers + work. We are not using platform ids anymore. Instead, we use + command strings when looking for execution handlers. + IExecutionHandlerFactory has been removed and now everything + is handled by IExecutionHandler, which has a new CanExecute + method. This model is more simple and more generic. + +2009-02-26 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.Gdb.sln: Flush. + +2009-02-25 Michael Hutchinson <mhutchinson@novell.com> + + * MonoDevelop.Debugger.Gdb.sln: Set policies. Remove unused + name attribute. + +2009-02-20 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.csproj: Updated references. + +2009/02/06 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.mdp: + * MonoDevelop.Debugger.mds: + * MonoDevelop.Debugger.csproj: + * MonoDevelop.Debugger.Gdb.mds: + * MonoDevelop.Debugger.Gdb.sln: Migrated to MSBuild file format. + +2009/02/03 Lluis Sanchez Gual <lluis@novell.com> + + * configure: + * AssemblyInfo.cs: + * Manifest.addin.xml: Bump MD version. + +2009-01-26 Michael Hutchinson <mhutchinson@novell.com> + + * MonoDevelop.Debugger.mdp: Flush project format changes. + +2008-12-19 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.mdp: Updated. + + * GdbBacktrace.cs: Track api changes. + +2008-12-09 Levi Bard <taktaktaktaktaktaktaktaktaktak@gmail.com> + + * GdbSession.cs: Fallback to relative source file path. + +2008-12-04 Lluis Sanchez Gual <lluis@novell.com> + + * Manifest.addin.xml: Set correct add-in category. + + * GdbSession.cs: + * GdbSessionFactory.cs: + * MonoDevelop.Debugger.mdp: Track api changes. + +2008-12-02 Michael Hutchinson <mhutchinson@novell.com> + + * Manifest.addin.xml: Change addin version number to match + configure/tarball version number. + +2008-12-02 Michael Hutchinson <mhutchinson@novell.com> + + * AssemblyInfo.cs: Add AssemblyInfo.cs files that are autogenerated from + the addin manifests. + +2008-12-02 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.mdp: + * MonoDevelop.Debugger.Gdb.make: Remove .pc file. It's not required. + +2008-11-25 Lluis Sanchez Gual <lluis@novell.com> + + * Manifest.addin.xml: Track api changes. + +2008-11-05 Lluis Sanchez Gual <lluis@novell.com> + + * configure: + * Manifest.addin.xml: Bump MD version. + +2008-10-16 Michael Hutchinson <mhutchinson@novell.com> + + * configure: Fix tarball name. + +2008-09-26 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs, GdbSession.cs: When debugging a mono process, try to + get managed method names for unknown stack frames. + +2008-09-17 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.mdp: Updated projects. + +2008-09-03 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Track api changes. + +2008-08-22 Lluis Sanchez Gual <lluis@novell.com> + + * Manifest.addin.xml, MonoDevelop.Debugger.mdp: Extension point + location has changed. + +2008-08-18 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.mdp: Fix reference to Mono.TextEditor. The + incorrect add-in version number causes problems in the makefile + synchronization. + +2008-08-07 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Implemented support for conditions, trace expressions + and hit counts. + +2008-08-05 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Track api changes. + +2008-07-25 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Implement GetAllLocals. + +2008-07-16 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Track api changes. + +2008-07-11 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSessionFactory.cs: Fix construction process command line string. + * GdbSession.cs: Track api changes. + +2008-07-09 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.Gdb.make: Install the assemblies to the correct + directory. + +2008-07-09 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Track api changes. + +2008-07-09 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Added support for code completion. + +2008-07-09 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + * GdbSession.cs: Clean temporary variables. + +2008-07-07 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Track api changes. + +2008-07-02 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs: Support modifying variable values. + * GdbSession.cs: Implemented support for disassembling files. + +2008-07-01 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Track api changes. + +2008-06-26 Lluis Sanchez Gual <lluis@novell.com> + + * GdbBacktrace.cs, GdbSession.cs: Allow setting the active thread. + Implemented GetThreads and GetProcesses. + * ResultData.cs: Handle weird case where a tuple can have several + values for a property. + +2008-06-20 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSession.cs: Implemented detach. + +2008-06-20 Lluis Sanchez Gual <lluis@novell.com> + + * GdbSessionFactory.cs, GdbBacktrace.cs, GdbSession.cs, ResultData.cs: + Implemented process attaching, variable query, disassemble. + +2008-06-17 Lluis Sanchez Gual <lluis@novell.com> + + * MonoDevelop.Debugger.Gdb.make, configure, MonoDevelop.Debugger.mdp, + MonoDevelop.Debugger.mds, Makefile.include, rules.make, + monodevelop.debugger.gdb.pc.in, Makefile: Added missing build + files. + +2008-06-17 Lluis Sanchez Gual <lluis@novell.com> + + * AssemblyInfo.cs, GdbBacktrace.cs, GdbEvent.cs, GdbSession.cs, + CommandStatus.cs, GdbSessionFactory.cs, ResultData.cs, + GdbCommandResult.cs, Manifest.addin.xml: Initial support for gdb + integration. + diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/CommandStatus.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/CommandStatus.cs new file mode 100644 index 0000000000..683c304cbe --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/CommandStatus.cs @@ -0,0 +1,38 @@ +// CommandStatus.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; + +namespace MonoDevelop.Debugger.Gdb +{ + enum CommandStatus + { + Done, + Running, + Error + } +} diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/GdbBacktrace.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbBacktrace.cs new file mode 100644 index 0000000000..7aec2df3d0 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbBacktrace.cs @@ -0,0 +1,400 @@ +// GdbBacktrace.cs +// +// Authors: Lluis Sanchez Gual <lluis@novell.com> +// Jeffrey Stedfast <jeff@xamarin.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; +using System.Collections.Generic; +using System.Globalization; +using Mono.Debugging.Client; +using Mono.Debugging.Backend; + +namespace MonoDevelop.Debugger.Gdb +{ + class GdbBacktrace: IBacktrace, IObjectValueSource + { + int fcount; + StackFrame firstFrame; + GdbSession session; + DissassemblyBuffer[] disBuffers; + int currentFrame = -1; + long threadId; + + public GdbBacktrace (GdbSession session, long threadId, int count, ResultData firstFrame) + { + fcount = count; + this.threadId = threadId; + if (firstFrame != null) + this.firstFrame = CreateFrame (firstFrame); + this.session = session; + } + + public int FrameCount { + get { + return fcount; + } + } + + public StackFrame[] GetStackFrames (int firstIndex, int lastIndex) + { + List<StackFrame> frames = new List<StackFrame> (); + if (firstIndex == 0 && firstFrame != null) { + frames.Add (firstFrame); + firstIndex++; + } + + if (lastIndex >= fcount) + lastIndex = fcount - 1; + + if (firstIndex > lastIndex) + return frames.ToArray (); + + session.SelectThread (threadId); + GdbCommandResult res = session.RunCommand ("-stack-list-frames", firstIndex.ToString (), lastIndex.ToString ()); + ResultData stack = res.GetObject ("stack"); + for (int n=0; n<stack.Count; n++) { + ResultData frd = stack.GetObject (n); + frames.Add (CreateFrame (frd.GetObject ("frame"))); + } + return frames.ToArray (); + } + + public ObjectValue[] GetLocalVariables (int frameIndex, EvaluationOptions options) + { + List<ObjectValue> values = new List<ObjectValue> (); + SelectFrame (frameIndex); + + GdbCommandResult res = session.RunCommand ("-stack-list-locals", "0"); + foreach (ResultData data in res.GetObject ("locals")) + values.Add (CreateVarObject (data.GetValue ("name"))); + + return values.ToArray (); + } + + public ObjectValue[] GetParameters (int frameIndex, EvaluationOptions options) + { + List<ObjectValue> values = new List<ObjectValue> (); + SelectFrame (frameIndex); + GdbCommandResult res = session.RunCommand ("-stack-list-arguments", "0", frameIndex.ToString (), frameIndex.ToString ()); + foreach (ResultData data in res.GetObject ("stack-args").GetObject (0).GetObject ("frame").GetObject ("args")) + values.Add (CreateVarObject (data.GetValue ("name"))); + + return values.ToArray (); + } + + public ObjectValue GetThisReference (int frameIndex, EvaluationOptions options) + { + return null; + } + + public ObjectValue[] GetAllLocals (int frameIndex, EvaluationOptions options) + { + List<ObjectValue> locals = new List<ObjectValue> (); + locals.AddRange (GetParameters (frameIndex, options)); + locals.AddRange (GetLocalVariables (frameIndex, options)); + return locals.ToArray (); + } + + public ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, EvaluationOptions options) + { + List<ObjectValue> values = new List<ObjectValue> (); + SelectFrame (frameIndex); + foreach (string exp in expressions) + values.Add (CreateVarObject (exp)); + return values.ToArray (); + } + + public ExceptionInfo GetException (int frameIndex, EvaluationOptions options) + { + return null; + } + + public ValidationResult ValidateExpression (int frameIndex, string expression, EvaluationOptions options) + { + return new ValidationResult (true, null); + } + + public CompletionData GetExpressionCompletionData (int frameIndex, string exp) + { + SelectFrame (frameIndex); + + bool pointer = exp.EndsWith ("->"); + int i; + + if (pointer || exp.EndsWith (".")) { + exp = exp.Substring (0, exp.Length - (pointer ? 2 : 1)); + i = 0; + while (i < exp.Length) { + ObjectValue val = CreateVarObject (exp); + if (!val.IsUnknown && !val.IsError) { + CompletionData data = new CompletionData (); + foreach (ObjectValue cv in val.GetAllChildren ()) + data.Items.Add (new CompletionItem (cv.Name, cv.Flags)); + data.ExpressionLength = 0; + return data; + } + i++; + } + return null; + } + + i = exp.Length - 1; + bool lastWastLetter = false; + while (i >= 0) { + char c = exp [i--]; + if (!char.IsLetterOrDigit (c) && c != '_') + break; + lastWastLetter = !char.IsDigit (c); + } + + if (lastWastLetter) { + string partialWord = exp.Substring (i+1); + + CompletionData cdata = new CompletionData (); + cdata.ExpressionLength = partialWord.Length; + + // Local variables + + GdbCommandResult res = session.RunCommand ("-stack-list-locals", "0"); + foreach (ResultData data in res.GetObject ("locals")) { + string name = data.GetValue ("name"); + if (name.StartsWith (partialWord)) + cdata.Items.Add (new CompletionItem (name, ObjectValueFlags.Variable)); + } + + // Parameters + + res = session.RunCommand ("-stack-list-arguments", "0", frameIndex.ToString (), frameIndex.ToString ()); + foreach (ResultData data in res.GetObject ("stack-args").GetObject (0).GetObject ("frame").GetObject ("args")) { + string name = data.GetValue ("name"); + if (name.StartsWith (partialWord)) + cdata.Items.Add (new CompletionItem (name, ObjectValueFlags.Parameter)); + } + + if (cdata.Items.Count > 0) + return cdata; + } + return null; + } + + + ObjectValue CreateVarObject (string exp) + { + try { + session.SelectThread (threadId); + exp = exp.Replace ("\"", "\\\""); + GdbCommandResult res = session.RunCommand ("-var-create", "-", "*", "\"" + exp + "\""); + string vname = res.GetValue ("name"); + session.RegisterTempVariableObject (vname); + return CreateObjectValue (exp, res); + } catch { + return ObjectValue.CreateUnknown (exp); + } + } + + ObjectValue CreateObjectValue (string name, ResultData data) + { + string vname = data.GetValue ("name"); + string typeName = data.GetValue ("type"); + string value = data.GetValue ("value"); + int nchild = data.GetInt ("numchild"); + + ObjectValue val; + ObjectValueFlags flags = ObjectValueFlags.Variable; + + // There can be 'public' et al children for C++ structures + if (typeName == null) + typeName = "none"; + + if (typeName.EndsWith ("]")) { + val = ObjectValue.CreateArray (this, new ObjectPath (vname), typeName, nchild, flags, null); + } else if (value == "{...}" || typeName.EndsWith ("*") || nchild > 0) { + val = ObjectValue.CreateObject (this, new ObjectPath (vname), typeName, value, flags, null); + } else { + val = ObjectValue.CreatePrimitive (this, new ObjectPath (vname), typeName, new EvaluationResult (value), flags); + } + val.Name = name; + return val; + } + + public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options) + { + List<ObjectValue> children = new List<ObjectValue> (); + session.SelectThread (threadId); + GdbCommandResult res = session.RunCommand ("-var-list-children", "2", path.Join (".")); + ResultData cdata = res.GetObject ("children"); + + // The response may not contain the "children" list at all. + if (cdata == null) + return children.ToArray (); + + if (index == -1) { + index = 0; + count = cdata.Count; + } + + for (int n=index; n<cdata.Count && n<index+count; n++) { + ResultData data = cdata.GetObject (n); + ResultData child = data.GetObject ("child"); + + string name = child.GetValue ("exp"); + if (name.Length > 0 && char.IsNumber (name [0])) + name = "[" + name + "]"; + + // C++ structures may contain typeless children named + // "public", "private" and "protected". + if (child.GetValue("type") == null) { + ObjectPath childPath = new ObjectPath (child.GetValue ("name").Split ('.')); + ObjectValue[] subchildren = GetChildren (childPath, -1, -1, options); + children.AddRange(subchildren); + } else { + ObjectValue val = CreateObjectValue (name, child); + children.Add (val); + } + } + return children.ToArray (); + } + + public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options) + { + session.SelectThread (threadId); + session.RunCommand ("-var-assign", path.Join ("."), value); + return new EvaluationResult (value); + } + + public ObjectValue GetValue (ObjectPath path, EvaluationOptions options) + { + throw new NotSupportedException (); + } + + void SelectFrame (int frame) + { + session.SelectThread (threadId); + if (frame != currentFrame) { + session.RunCommand ("-stack-select-frame", frame.ToString ()); + currentFrame = frame; + } + } + + StackFrame CreateFrame (ResultData frameData) + { + string lang = "Native"; + string func = frameData.GetValue ("func"); + string sadr = frameData.GetValue ("addr"); + + if (func == "??" && session.IsMonoProcess) { + // Try to get the managed func name + try { + ResultData data = session.RunCommand ("-data-evaluate-expression", "mono_pmip(" + sadr + ")"); + string val = data.GetValue ("value"); + if (val != null) { + int i = val.IndexOf ('"'); + if (i != -1) { + func = val.Substring (i).Trim ('"',' '); + lang = "Mono"; + } + } + } catch { + } + } + + int line = -1; + string sline = frameData.GetValue ("line"); + if (sline != null) + line = int.Parse (sline); + + string sfile = frameData.GetValue ("fullname"); + if (sfile == null) + sfile = frameData.GetValue ("file"); + if (sfile == null) + sfile = frameData.GetValue ("from"); + SourceLocation loc = new SourceLocation (func ?? "?", sfile, line); + + long addr; + if (!string.IsNullOrEmpty (sadr)) + addr = long.Parse (sadr.Substring (2), NumberStyles.HexNumber); + else + addr = 0; + + return new StackFrame (addr, loc, lang); + } + + public AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count) + { + SelectFrame (frameIndex); + if (disBuffers == null) + disBuffers = new DissassemblyBuffer [fcount]; + + DissassemblyBuffer buffer = disBuffers [frameIndex]; + if (buffer == null) { + ResultData data = session.RunCommand ("-stack-info-frame"); + long addr = long.Parse (data.GetObject ("frame").GetValue ("addr").Substring (2), NumberStyles.HexNumber); + buffer = new GdbDissassemblyBuffer (session, addr); + disBuffers [frameIndex] = buffer; + } + + return buffer.GetLines (firstLine, firstLine + count - 1); + } + + public object GetRawValue (ObjectPath path, EvaluationOptions options) + { + return null; + } + + public void SetRawValue (ObjectPath path, object value, EvaluationOptions options) + { + } + } + + class GdbDissassemblyBuffer: DissassemblyBuffer + { + GdbSession session; + + public GdbDissassemblyBuffer (GdbSession session, long addr): base (addr) + { + this.session = session; + } + + public override AssemblyLine[] GetLines (long startAddr, long endAddr) + { + try { + ResultData data = session.RunCommand ("-data-disassemble", "-s", startAddr.ToString (), "-e", endAddr.ToString (), "--", "0"); + ResultData ins = data.GetObject ("asm_insns"); + + AssemblyLine[] alines = new AssemblyLine [ins.Count]; + for (int n=0; n<ins.Count; n++) { + ResultData aline = ins.GetObject (n); + long addr = long.Parse (aline.GetValue ("address").Substring (2), NumberStyles.HexNumber); + AssemblyLine line = new AssemblyLine (addr, aline.GetValue ("inst")); + alines [n] = line; + } + return alines; + } catch { + return new AssemblyLine [0]; + } + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/GdbCommandResult.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbCommandResult.cs new file mode 100644 index 0000000000..a8790d74ad --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbCommandResult.cs @@ -0,0 +1,53 @@ +// GdbCommandResult.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; + +namespace MonoDevelop.Debugger.Gdb +{ + class GdbCommandResult: ResultData + { + public CommandStatus Status; + public string ErrorMessage; + + public GdbCommandResult (string line) + { + if (line.StartsWith ("^done")) { + Status = CommandStatus.Done; + ReadResults (line, 6); + } else if (line.StartsWith ("^error")) { + Status = CommandStatus.Error; + if (line.Length > 7) { + ReadResults (line, 7); + ErrorMessage = GetValue ("msg"); + } + } else if (line.StartsWith ("^running")) { + Status = CommandStatus.Running; + } + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/GdbEvent.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbEvent.cs new file mode 100644 index 0000000000..cf631cfb70 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbEvent.cs @@ -0,0 +1,49 @@ +// GdbEvent.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; + +namespace MonoDevelop.Debugger.Gdb +{ + class GdbEvent: ResultData + { + public string Name; + public string Reason; + + public GdbEvent (string line) + { + int i = line.IndexOf (','); + if (i == -1) + i = line.Length; + Name = line.Substring (1, i - 1); + ReadResults (line, i+1); + object[] reasons = GetAllValues ("reason"); + if (reasons.Length > 0) + Reason = (string) reasons [0]; + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/GdbSession.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbSession.cs new file mode 100644 index 0000000000..c585ab86b5 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbSession.cs @@ -0,0 +1,730 @@ +// GdbSession.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; +using System.Globalization; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using Mono.Debugging.Client; +using MonoDevelop.Core; +using MonoDevelop.Core.Execution; +using Mono.Unix.Native; + +namespace MonoDevelop.Debugger.Gdb +{ + class GdbSession: DebuggerSession + { + Process proc; + StreamReader sout; + StreamWriter sin; + IProcessAsyncOperation console; + GdbCommandResult lastResult; + bool running; + Thread thread; + long currentThread = -1; + long activeThread = -1; + bool isMonoProcess; + string currentProcessName; + List<string> tempVariableObjects = new List<string> (); + Dictionary<int,BreakEventInfo> breakpoints = new Dictionary<int,BreakEventInfo> (); + List<BreakEventInfo> breakpointsWithHitCount = new List<BreakEventInfo> (); + + DateTime lastBreakEventUpdate = DateTime.Now; + Dictionary<int, WaitCallback> breakUpdates = new Dictionary<int,WaitCallback> (); + bool breakUpdateEventsQueued; + const int BreakEventUpdateNotifyDelay = 500; + + bool internalStop; + bool logGdb; + + object syncLock = new object (); + object eventLock = new object (); + object gdbLock = new object (); + + public GdbSession () + { + logGdb = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONODEVELOP_GDB_LOG")); + } + + protected override void OnRun (DebuggerStartInfo startInfo) + { + lock (gdbLock) { + // Create a script to be run in a terminal + string script = Path.GetTempFileName (); + string ttyfile = Path.GetTempFileName (); + string ttyfileDone = ttyfile + "_done"; + string tty; + + try { + File.WriteAllText (script, "tty > " + ttyfile + "\ntouch " + ttyfileDone + "\nsleep 10000d"); + Mono.Unix.Native.Syscall.chmod (script, FilePermissions.ALLPERMS); + + console = Runtime.ProcessService.StartConsoleProcess (script, "", ".", ExternalConsoleFactory.Instance.CreateConsole (true), null); + DateTime tim = DateTime.Now; + while (!File.Exists (ttyfileDone)) { + System.Threading.Thread.Sleep (100); + if ((DateTime.Now - tim).TotalSeconds > 10) + throw new InvalidOperationException ("Console could not be created."); + } + tty = File.ReadAllText (ttyfile).Trim (' ','\n'); + } finally { + try { + if (File.Exists (script)) + File.Delete (script); + if (File.Exists (ttyfile)) + File.Delete (ttyfile); + if (File.Exists (ttyfileDone)) + File.Delete (ttyfileDone); + } catch { + // Ignore + } + } + + StartGdb (); + + // Initialize the terminal + RunCommand ("-inferior-tty-set", Escape (tty)); + + try { + RunCommand ("-file-exec-and-symbols", Escape (startInfo.Command)); + } catch { + FireTargetEvent (TargetEventType.TargetExited, null); + throw; + } + + RunCommand ("-environment-cd", Escape (startInfo.WorkingDirectory)); + + // Set inferior arguments + if (!string.IsNullOrEmpty (startInfo.Arguments)) + RunCommand ("-exec-arguments", startInfo.Arguments); + + currentProcessName = startInfo.Command + " " + startInfo.Arguments; + + CheckIsMonoProcess (); + OnStarted (); + + RunCommand ("-exec-run"); + } + } + + protected override void OnAttachToProcess (long processId) + { + lock (gdbLock) { + StartGdb (); + currentProcessName = "PID " + processId.ToString (); + RunCommand ("attach", processId.ToString ()); + currentThread = activeThread = 1; + CheckIsMonoProcess (); + OnStarted (); + FireTargetEvent (TargetEventType.TargetStopped, null); + } + } + + public bool IsMonoProcess { + get { return isMonoProcess; } + } + + void CheckIsMonoProcess () + { + try { + RunCommand ("-data-evaluate-expression", "mono_pmip"); + isMonoProcess = true; + } catch { + isMonoProcess = false; + // Ignore + } + } + + void StartGdb () + { + proc = new Process (); + proc.StartInfo.FileName = "gdb"; + proc.StartInfo.Arguments = "-quiet -fullname -i=mi2"; + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.RedirectStandardInput = true; + proc.StartInfo.RedirectStandardOutput = true; + proc.StartInfo.RedirectStandardError = true; + proc.Start (); + + sout = proc.StandardOutput; + sin = proc.StandardInput; + + thread = new Thread (OutputInterpreter); + thread.Name = "GDB output interpeter"; + thread.IsBackground = true; + thread.Start (); + } + + public override void Dispose () + { + if (console != null && !console.IsCompleted) { + console.Cancel (); + console = null; + } + + if (thread != null) + thread.Abort (); + } + + protected override void OnSetActiveThread (long processId, long threadId) + { + activeThread = threadId; + } + + protected override void OnStop () + { + Syscall.kill (proc.Id, Signum.SIGINT); + } + + protected override void OnDetach () + { + lock (gdbLock) { + InternalStop (); + RunCommand ("detach"); + FireTargetEvent (TargetEventType.TargetExited, null); + } + } + + protected override void OnExit () + { + lock (gdbLock) { + InternalStop (); + RunCommand ("kill"); + TargetEventArgs args = new TargetEventArgs (TargetEventType.TargetExited); + OnTargetEvent (args); +/* proc.Kill (); + TargetEventArgs args = new TargetEventArgs (TargetEventType.TargetExited); + OnTargetEvent (args); +*/ } + } + + protected override void OnStepLine () + { + SelectThread (activeThread); + RunCommand ("-exec-step"); + } + + protected override void OnNextLine () + { + SelectThread (activeThread); + RunCommand ("-exec-next"); + } + + protected override void OnStepInstruction () + { + SelectThread (activeThread); + RunCommand ("-exec-step-instruction"); + } + + protected override void OnNextInstruction () + { + SelectThread (activeThread); + RunCommand ("-exec-next-instruction"); + } + + protected override void OnFinish () + { + SelectThread (activeThread); + GdbCommandResult res = RunCommand ("-stack-info-depth", "2"); + if (res.GetValue ("depth") == "1") { + RunCommand ("-exec-continue"); + } else { + RunCommand ("-stack-select-frame", "0"); + RunCommand ("-exec-finish"); + } + } + + protected override BreakEventInfo OnInsertBreakEvent (BreakEvent be) + { + Breakpoint bp = be as Breakpoint; + if (bp == null) + throw new NotSupportedException (); + + BreakEventInfo bi = new BreakEventInfo (); + + lock (gdbLock) { + bool dres = InternalStop (); + try { + string extraCmd = string.Empty; + if (bp.HitCount > 0) { + extraCmd += "-i " + bp.HitCount; + breakpointsWithHitCount.Add (bi); + } + if (!string.IsNullOrEmpty (bp.ConditionExpression)) { + if (!bp.BreakIfConditionChanges) + extraCmd += " -c " + bp.ConditionExpression; + } + + GdbCommandResult res = null; + string errorMsg = null; + + if (bp is FunctionBreakpoint) { + try { + res = RunCommand ("-break-insert", extraCmd.Trim (), ((FunctionBreakpoint) bp).FunctionName); + } catch (Exception ex) { + errorMsg = ex.Message; + } + } else { + // Breakpoint locations must be double-quoted if files contain spaces. + // For example: -break-insert "\"C:/Documents and Settings/foo.c\":17" + RunCommand ("-environment-directory", Escape (Path.GetDirectoryName (bp.FileName))); + + try { + res = RunCommand ("-break-insert", extraCmd.Trim (), Escape (Escape (bp.FileName) + ":" + bp.Line)); + } catch (Exception ex) { + errorMsg = ex.Message; + } + + if (res == null) { + try { + res = RunCommand ("-break-insert", extraCmd.Trim (), Escape (Escape (Path.GetFileName (bp.FileName)) + ":" + bp.Line)); + } + catch { + // Ignore + } + } + } + + if (res == null) { + bi.SetStatus (BreakEventStatus.Invalid, errorMsg); + return bi; + } + int bh = res.GetObject ("bkpt").GetInt ("number"); + if (!be.Enabled) + RunCommand ("-break-disable", bh.ToString ()); + breakpoints [bh] = bi; + bi.Handle = bh; + bi.SetStatus (BreakEventStatus.Bound, null); + return bi; + } finally { + InternalResume (dres); + } + } + } + + bool CheckBreakpoint (int handle) + { + BreakEventInfo binfo; + if (!breakpoints.TryGetValue (handle, out binfo)) + return true; + + Breakpoint bp = (Breakpoint) binfo.BreakEvent; + + if (!string.IsNullOrEmpty (bp.ConditionExpression) && bp.BreakIfConditionChanges) { + // Update the condition expression + GdbCommandResult res = RunCommand ("-data-evaluate-expression", Escape (bp.ConditionExpression)); + string val = res.GetValue ("value"); + RunCommand ("-break-condition", handle.ToString (), "(" + bp.ConditionExpression + ") != " + val); + } + + if (!string.IsNullOrEmpty (bp.TraceExpression) && bp.HitAction == HitAction.PrintExpression) { + GdbCommandResult res = RunCommand ("-data-evaluate-expression", Escape (bp.TraceExpression)); + string val = res.GetValue ("value"); + NotifyBreakEventUpdate (binfo, 0, val); + return false; + } + return true; + } + + void NotifyBreakEventUpdate (BreakEventInfo binfo, int hitCount, string lastTrace) + { + bool notify = false; + + WaitCallback nc = delegate { + if (hitCount != -1) + binfo.IncrementHitCount (); + if (lastTrace != null) + binfo.UpdateLastTraceValue (lastTrace); + }; + + lock (breakUpdates) + { + int span = (int) (DateTime.Now - lastBreakEventUpdate).TotalMilliseconds; + if (span >= BreakEventUpdateNotifyDelay && !breakUpdateEventsQueued) { + // Last update was more than 0.5s ago. The update can be sent. + lastBreakEventUpdate = DateTime.Now; + notify = true; + } else { + // Queue the event notifications to avoid wasting too much time + breakUpdates [(int)binfo.Handle] = nc; + if (!breakUpdateEventsQueued) { + breakUpdateEventsQueued = true; + + ThreadPool.QueueUserWorkItem (delegate { + Thread.Sleep (BreakEventUpdateNotifyDelay - span); + List<WaitCallback> copy; + lock (breakUpdates) { + copy = new List<WaitCallback> (breakUpdates.Values); + breakUpdates.Clear (); + breakUpdateEventsQueued = false; + lastBreakEventUpdate = DateTime.Now; + } + foreach (WaitCallback wc in copy) + wc (null); + }); + } + } + } + if (notify) + nc (null); + } + + void UpdateHitCountData () + { + foreach (BreakEventInfo bp in breakpointsWithHitCount) { + GdbCommandResult res = RunCommand ("-break-info", bp.Handle.ToString ()); + string val = res.GetObject ("BreakpointTable").GetObject ("body").GetObject (0).GetObject ("bkpt").GetValue ("ignore"); + if (val != null) + NotifyBreakEventUpdate (bp, int.Parse (val), null); + else + NotifyBreakEventUpdate (bp, 0, null); + } + breakpointsWithHitCount.Clear (); + } + + protected override void OnRemoveBreakEvent (BreakEventInfo binfo) + { + lock (gdbLock) { + if (binfo.Handle == null) + return; + bool dres = InternalStop (); + breakpointsWithHitCount.Remove (binfo); + breakpoints.Remove ((int)binfo.Handle); + try { + RunCommand ("-break-delete", binfo.Handle.ToString ()); + } finally { + InternalResume (dres); + } + } + } + + protected override void OnEnableBreakEvent (BreakEventInfo binfo, bool enable) + { + lock (gdbLock) { + if (binfo.Handle == null) + return; + bool dres = InternalStop (); + try { + if (enable) + RunCommand ("-break-enable", binfo.Handle.ToString ()); + else + RunCommand ("-break-disable", binfo.Handle.ToString ()); + } finally { + InternalResume (dres); + } + } + } + + protected override void OnUpdateBreakEvent (BreakEventInfo binfo) + { + Breakpoint bp = binfo.BreakEvent as Breakpoint; + if (bp == null) + throw new NotSupportedException (); + + if (binfo.Handle == null) + return; + + bool ss = InternalStop (); + + try { + if (bp.HitCount > 0) { + RunCommand ("-break-after", binfo.Handle.ToString (), bp.HitCount.ToString ()); + breakpointsWithHitCount.Add (binfo); + } else + breakpointsWithHitCount.Remove (binfo); + + if (!string.IsNullOrEmpty (bp.ConditionExpression) && !bp.BreakIfConditionChanges) + RunCommand ("-break-condition", binfo.Handle.ToString (), bp.ConditionExpression); + else + RunCommand ("-break-condition", binfo.Handle.ToString ()); + } finally { + InternalResume (ss); + } + } + + protected override void OnContinue () + { + SelectThread (activeThread); + RunCommand ("-exec-continue"); + } + + protected override ThreadInfo[] OnGetThreads (long processId) + { + List<ThreadInfo> list = new List<ThreadInfo> (); + ResultData data = RunCommand ("-thread-list-ids").GetObject ("thread-ids"); + foreach (string id in data.GetAllValues ("thread-id")) + list.Add (GetThread (long.Parse (id))); + return list.ToArray (); + } + + protected override ProcessInfo[] OnGetProcesses () + { + ProcessInfo p = new ProcessInfo (0, currentProcessName); + return new ProcessInfo [] { p }; + } + + ThreadInfo GetThread (long id) + { + return new ThreadInfo (0, id, "Thread #" + id, null); + } + + protected override Backtrace OnGetThreadBacktrace (long processId, long threadId) + { + ResultData data = SelectThread (threadId); + GdbCommandResult res = RunCommand ("-stack-info-depth"); + int fcount = int.Parse (res.GetValue ("depth")); + GdbBacktrace bt = new GdbBacktrace (this, threadId, fcount, data != null ? data.GetObject ("frame") : null); + return new Backtrace (bt); + } + + protected override AssemblyLine[] OnDisassembleFile (string file) + { + List<AssemblyLine> lines = new List<AssemblyLine> (); + int cline = 1; + do { + ResultData data = null; + try { + data = RunCommand ("-data-disassemble", "-f", file, "-l", cline.ToString (), "--", "1"); + } catch { + break; + } + ResultData asm_insns = data.GetObject ("asm_insns"); + int newLine = cline; + for (int n=0; n<asm_insns.Count; n++) { + ResultData src_and_asm_line = asm_insns.GetObject (n).GetObject ("src_and_asm_line"); + newLine = src_and_asm_line.GetInt ("line"); + ResultData line_asm_insn = src_and_asm_line.GetObject ("line_asm_insn"); + for (int i=0; i<line_asm_insn.Count; i++) { + ResultData asm = line_asm_insn.GetObject (i); + long addr = long.Parse (asm.GetValue ("address").Substring (2), NumberStyles.HexNumber); + string code = asm.GetValue ("inst"); + lines.Add (new AssemblyLine (addr, code, newLine)); + } + } + if (newLine <= cline) + break; + cline = newLine + 1; + + } while (true); + + return lines.ToArray (); + } + + public ResultData SelectThread (long id) + { + if (id == currentThread) + return null; + currentThread = id; + return RunCommand ("-thread-select", id.ToString ()); + } + + string Escape (string str) + { + if (str == null) + return null; + else if (str.IndexOf (' ') != -1 || str.IndexOf ('"') != -1) { + str = str.Replace ("\"", "\\\""); + return "\"" + str + "\""; + } + else + return str; + } + + public GdbCommandResult RunCommand (string command, params string[] args) + { + lock (gdbLock) { + lock (syncLock) { + lastResult = null; + + lock (eventLock) { + running = true; + } + + if (logGdb) + Console.WriteLine ("gdb<: " + command + " " + string.Join (" ", args)); + + sin.WriteLine (command + " " + string.Join (" ", args)); + + if (!Monitor.Wait (syncLock, 4000)) + throw new InvalidOperationException ("Command execution timeout."); + if (lastResult.Status == CommandStatus.Error) + throw new InvalidOperationException (lastResult.ErrorMessage); + return lastResult; + } + } + } + + bool InternalStop () + { + lock (eventLock) { + if (!running) + return false; + internalStop = true; + Syscall.kill (proc.Id, Signum.SIGINT); + if (!Monitor.Wait (eventLock, 4000)) + throw new InvalidOperationException ("Target could not be interrupted."); + } + return true; + } + + void InternalResume (bool resume) + { + if (resume) + RunCommand ("-exec-continue"); + } + + void OutputInterpreter () + { + string line; + while ((line = sout.ReadLine ()) != null) { + try { + ProcessOutput (line); + } catch (Exception ex) { + Console.WriteLine (ex); + } + } + } + + void ProcessOutput (string line) + { + if (logGdb) + Console.WriteLine ("dbg>: '" + line + "'"); + switch (line [0]) { + case '^': + lock (syncLock) { + lastResult = new GdbCommandResult (line); + running = (lastResult.Status == CommandStatus.Running); + Monitor.PulseAll (syncLock); + } + break; + + case '~': + case '&': + if (line.Length > 1 && line[1] == '"') + line = line.Substring (2, line.Length - 5); + ThreadPool.QueueUserWorkItem (delegate { + OnTargetOutput (false, line + "\n"); + }); + break; + + case '*': + GdbEvent ev; + lock (eventLock) { + running = false; + ev = new GdbEvent (line); + string ti = ev.GetValue ("thread-id"); + if (ti != null && ti != "all") + currentThread = activeThread = int.Parse (ti); + Monitor.PulseAll (eventLock); + if (internalStop) { + internalStop = false; + return; + } + } + ThreadPool.QueueUserWorkItem (delegate { + try { + HandleEvent (ev); + } catch (Exception ex) { + Console.WriteLine (ex); + } + }); + break; + } + } + + void HandleEvent (GdbEvent ev) + { + if (ev.Name != "stopped") { + Console.WriteLine ("Unknown event: " + ev.Name); + return; + } + + CleanTempVariableObjects (); + + TargetEventType type; + switch (ev.Reason) { + case "breakpoint-hit": + type = TargetEventType.TargetHitBreakpoint; + if (!CheckBreakpoint (ev.GetInt ("bkptno"))) { + RunCommand ("-exec-continue"); + return; + } + break; + case "signal-received": + if (ev.GetValue ("signal-name") == "SIGINT") + type = TargetEventType.TargetInterrupted; + else + type = TargetEventType.TargetSignaled; + break; + case "exited": + case "exited-signalled": + case "exited-normally": + type = TargetEventType.TargetExited; + break; + default: + type = TargetEventType.TargetStopped; + break; + } + + ResultData curFrame = ev.GetObject ("frame"); + FireTargetEvent (type, curFrame); + } + + void FireTargetEvent (TargetEventType type, ResultData curFrame) + { + UpdateHitCountData (); + + TargetEventArgs args = new TargetEventArgs (type); + + if (type != TargetEventType.TargetExited) { + GdbCommandResult res = RunCommand ("-stack-info-depth"); + int fcount = int.Parse (res.GetValue ("depth")); + + GdbBacktrace bt = new GdbBacktrace (this, activeThread, fcount, curFrame); + args.Backtrace = new Backtrace (bt); + args.Thread = GetThread (activeThread); + } + OnTargetEvent (args); + } + + internal void RegisterTempVariableObject (string var) + { + tempVariableObjects.Add (var); + } + + void CleanTempVariableObjects () + { + foreach (string s in tempVariableObjects) + RunCommand ("-var-delete", s); + tempVariableObjects.Clear (); + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/GdbSessionFactory.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbSessionFactory.cs new file mode 100644 index 0000000000..a4e11b6877 --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/GdbSessionFactory.cs @@ -0,0 +1,151 @@ +// GdbSessionFactory.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; +using System.Collections.Generic; +using System.IO; +using Mono.Debugging.Client; +using Mono.Debugging.Backend; +using MonoDevelop.Core.Execution; + +namespace MonoDevelop.Debugger.Gdb +{ + public class GdbSessionFactory: IDebuggerEngine + { + struct FileData { + public DateTime LastCheck; + public bool IsExe; + } + + Dictionary<string,FileData> fileCheckCache = new Dictionary<string, FileData> (); + + public bool CanDebugCommand (ExecutionCommand command) + { + NativeExecutionCommand cmd = command as NativeExecutionCommand; + if (cmd == null) + return false; + + string file = FindFile (cmd.Command); + if (!File.Exists (file)) { + // The provided file is not guaranteed to exist. If it doesn't + // we assume we can execute it because otherwise the run command + // in the IDE will be disabled, and that's not good because that + // command will build the project if the exec doesn't yet exist. + return true; + } + + file = Path.GetFullPath (file); + DateTime currentTime = File.GetLastWriteTime (file); + + FileData data; + if (fileCheckCache.TryGetValue (file, out data)) { + if (data.LastCheck == currentTime) + return data.IsExe; + } + data.LastCheck = currentTime; + try { + data.IsExe = IsExecutable (file); + } catch { + data.IsExe = false; + } + fileCheckCache [file] = data; + return data.IsExe; + } + + public DebuggerStartInfo CreateDebuggerStartInfo (ExecutionCommand command) + { + NativeExecutionCommand pec = (NativeExecutionCommand) command; + DebuggerStartInfo startInfo = new DebuggerStartInfo (); + startInfo.Command = pec.Command; + startInfo.Arguments = pec.Arguments; + startInfo.WorkingDirectory = pec.WorkingDirectory; + if (pec.EnvironmentVariables.Count > 0) { + foreach (KeyValuePair<string,string> val in pec.EnvironmentVariables) + startInfo.EnvironmentVariables [val.Key] = val.Value; + } + return startInfo; + } + + public bool IsExecutable (string file) + { + // HACK: this is a quick but not very reliable way of checking if a file + // is a native executable. Actually, we are interested in checking that + // the file is not a script. + using (StreamReader sr = new StreamReader (file)) { + char[] chars = new char[3]; + int n = 0, nr = 0; + while (n < chars.Length && (nr = sr.ReadBlock (chars, n, chars.Length - n)) != 0) + n += nr; + if (nr != chars.Length) + return true; + if (chars [0] == '#' && chars [1] == '!') + return false; + } + return true; + } + + public DebuggerSession CreateSession () + { + GdbSession ds = new GdbSession (); + return ds; + } + + public ProcessInfo[] GetAttachableProcesses () + { + List<ProcessInfo> procs = new List<ProcessInfo> (); + foreach (string dir in Directory.GetDirectories ("/proc")) { + int id; + if (!int.TryParse (Path.GetFileName (dir), out id)) + continue; + try { + File.ReadAllText (Path.Combine (dir, "sessionid")); + } catch { + continue; + } + string cmdline = File.ReadAllText (Path.Combine (dir, "cmdline")); + cmdline = cmdline.Replace ('\0',' '); + ProcessInfo pi = new ProcessInfo (id, cmdline); + procs.Add (pi); + } + return procs.ToArray (); + } + + string FindFile (string cmd) + { + if (Path.IsPathRooted (cmd)) + return cmd; + string pathVar = Environment.GetEnvironmentVariable ("PATH"); + string[] paths = pathVar.Split (Path.PathSeparator); + foreach (string path in paths) { + string file = Path.Combine (path, cmd); + if (File.Exists (file)) + return file; + } + return cmd; + } + } +} diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/Makefile.am b/main/src/addins/MonoDevelop.Debugger.Gdb/Makefile.am new file mode 100644 index 0000000000..c9cc87438f --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/Makefile.am @@ -0,0 +1 @@ +include $(top_srcdir)/xbuild.include diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/Manifest.addin.xml b/main/src/addins/MonoDevelop.Debugger.Gdb/Manifest.addin.xml new file mode 100644 index 0000000000..238f37937e --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/Manifest.addin.xml @@ -0,0 +1,8 @@ +<ExtensionModel> + <Extension path="/MonoDevelop/Debugging/DebuggerEngines"> + <DebuggerEngine id="Mono.Debugger.Gdb" + name="GNU Debugger (GDB)" + features="ConditionalBreakpoints, Tracepoints, Catchpoints, Attaching, DebugFile, Stepping, Pause, Breakpoints, Disassembly" + type="MonoDevelop.Debugger.Gdb.GdbSessionFactory" /> + </Extension> +</ExtensionModel>
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/MonoDevelop.Debugger.Gdb.csproj b/main/src/addins/MonoDevelop.Debugger.Gdb/MonoDevelop.Debugger.Gdb.csproj new file mode 100644 index 0000000000..d555a666ea --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/MonoDevelop.Debugger.Gdb.csproj @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{FA15FC26-A7E7-4932-93B7-65FAE6D5DD33}</ProjectGuid> + <OutputType>Library</OutputType> + <AssemblyName>MonoDevelop.Debugger.Gdb</AssemblyName> + <RootNamespace>MonoDevelop.Debugger</RootNamespace> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\..\..\build\AddIns\MonoDevelop.Debugger.Gdb</OutputPath> + <DefineConstants>DEBUG</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + <Execution> + <Execution clr-version="Net_2_0" /> + </Execution> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>none</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\..\..\build\AddIns\MonoDevelop.Debugger.Gdb</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + <Execution> + <Execution clr-version="Net_2_0" /> + </Execution> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="Mono.TextEditor, Version=1.0.0.0, Culture=neutral"> + <Package>monodevelop</Package> + </Reference> + <Reference Include="Mono.Posix" /> + <Reference Include="Mono.Debugging, Version=0.0.0.0, Culture=neutral, PublicKeyToken=5e9ce85b0923c84f"> + <Package>monodevelop</Package> + </Reference> + <Reference Include="Mono.Debugging.Soft, Version=0.0.0.0, Culture=neutral, PublicKeyToken=5e9ce85b0923c84f"> + <Package>monodevelop-core-addins</Package> + </Reference> + <Reference Include="Mono.Debugger.Soft, Version=0.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756"> + <Package>monodevelop-core-addins</Package> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="AssemblyInfo.cs" /> + <Compile Include="GdbSession.cs" /> + <Compile Include="GdbSessionFactory.cs" /> + <Compile Include="GdbBacktrace.cs" /> + <Compile Include="CommandStatus.cs" /> + <Compile Include="ResultData.cs" /> + <Compile Include="GdbEvent.cs" /> + <Compile Include="GdbCommandResult.cs" /> + <Compile Include="AddinInfo.cs" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Manifest.addin.xml"> + <LogicalName>Manifest.addin.xml</LogicalName> + </EmbeddedResource> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <ProjectExtensions> + <MonoDevelop> + <Properties> + <Deployment.LinuxDeployData generatePcFile="False" /> + </Properties> + </MonoDevelop> + </ProjectExtensions> + <ItemGroup> + <ProjectReference Include="..\MonoDevelop.Debugger\MonoDevelop.Debugger.csproj"> + <Project>{2357AABD-08C7-4808-A495-8FF2D3CDFDB0}</Project> + <Name>MonoDevelop.Debugger</Name> + <Private>False</Private> + </ProjectReference> + <ProjectReference Include="..\..\core\MonoDevelop.Core\MonoDevelop.Core.csproj"> + <Project>{7525BB88-6142-4A26-93B9-A30C6983390A}</Project> + <Name>MonoDevelop.Core</Name> + <Private>False</Private> + </ProjectReference> + <ProjectReference Include="..\..\core\MonoDevelop.Ide\MonoDevelop.Ide.csproj"> + <Project>{27096E7F-C91C-4AC6-B289-6897A701DF21}</Project> + <Name>MonoDevelop.Ide</Name> + <Private>False</Private> + </ProjectReference> + <ProjectReference Include="..\..\..\external\mono-addins\Mono.Addins\Mono.Addins.csproj"> + <Project>{91DD5A2D-9FE3-4C3C-9253-876141874DAD}</Project> + <Name>Mono.Addins</Name> + <Private>False</Private> + </ProjectReference> + </ItemGroup> +</Project> diff --git a/main/src/addins/MonoDevelop.Debugger.Gdb/ResultData.cs b/main/src/addins/MonoDevelop.Debugger.Gdb/ResultData.cs new file mode 100644 index 0000000000..73c5612a6c --- /dev/null +++ b/main/src/addins/MonoDevelop.Debugger.Gdb/ResultData.cs @@ -0,0 +1,229 @@ +// ResultData.cs +// +// Author: +// Lluis Sanchez Gual <lluis@novell.com> +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Mono.Debugging.Client; +using Mono.Debugging.Backend; + +namespace MonoDevelop.Debugger.Gdb +{ + class ResultData: IEnumerable + { + Hashtable props; + object[] array; + bool isArrayProperty; + + public int Count { + get { + if (array != null) + return array.Length; + else if (props != null) + return props.Count; + else + return 0; + } + } + + public string GetValue (string name) + { + return (string) props [name]; + } + + public int GetInt (string name) + { + return int.Parse (GetValue (name)); + } + + public string GetValue (int index) + { + return (string) array [index]; + } + + public ResultData GetObject (string name) + { + return (ResultData) props [name]; + } + + public ResultData GetObject (int index) + { + return (ResultData) array [index]; + } + + public object[] GetAllValues (string name) + { + object ob = props [name]; + if (ob == null) + return new object [0]; + ResultData rd = ob as ResultData; + if (rd != null && rd.isArrayProperty) + return rd.array; + else + return new object[] { ob }; + } + + protected void ReadResults (string str, int pos) + { + ReadTuple (str, ref pos, this); + } + + void ReadResult (string str, ref int pos, out string name, out object value) + { + name = null; + value = null; + + name = ReadString (str, '=', ref pos); + ReadChar (str, ref pos, '='); + value = ReadValue (str, ref pos); + } + + string ReadString (string str, char term, ref int pos) + { + StringBuilder sb = new StringBuilder (); + while (pos < str.Length && str [pos] != term) { + if (str [pos] == '\\') { + pos++; + if (pos >= str.Length) + break; + } + sb.Append (str [pos]); + pos++; + } + return sb.ToString (); + } + + object ReadValue (string str, ref int pos) + { + if (str [pos] == '"') { + pos++; + string ret = ReadString (str, '"', ref pos); + pos++; + return ret; + } + if (str [pos] == '{') { + pos++; + ResultData data = new ResultData (); + ReadTuple (str, ref pos, data); + return data; + } + if (str [pos] == '[') { + pos++; + return ReadArray (str, ref pos); + } + + // Single value tuple + string name; + object val; + ReadResult (str, ref pos, out name, out val); + ResultData sdata = new ResultData (); + sdata.props = new Hashtable (); + sdata.props [name] = val; + return sdata; + } + + void ReadTuple (string str, ref int pos, ResultData data) + { + if (data.props == null) + data.props = new Hashtable (); + + while (pos < str.Length && str [pos] != '}') { + string name; + object val; + ReadResult (str, ref pos, out name, out val); + if (data.props.ContainsKey (name)) { + object ob = data.props [name]; + ResultData rd = ob as ResultData; + if (rd != null && rd.isArrayProperty) { + object[] newArr = new object [rd.array.Length + 1]; + Array.Copy (rd.array, newArr, rd.array.Length); + newArr [rd.array.Length] = val; + rd.array = newArr; + } else { + rd = new ResultData (); + rd.isArrayProperty = true; + rd.array = new object [2]; + rd.array [0] = ob; + rd.array [1] = val; + data.props [name] = rd; + } + } else { + data.props [name] = val; + } + TryReadChar (str, ref pos, ','); + } + TryReadChar (str, ref pos, '}'); + } + + ResultData ReadArray (string str, ref int pos) + { + ArrayList list = new ArrayList (); + while (pos < str.Length && str [pos] != ']') { + object val = ReadValue (str, ref pos); + list.Add (val); + TryReadChar (str, ref pos, ','); + } + TryReadChar (str, ref pos, ']'); + ResultData arr = new ResultData (); + arr.array = list.ToArray (); + return arr; + } + + void ReadChar (string str, ref int pos, char c) + { + if (!TryReadChar (str, ref pos, c)) + ThrownParseError (str, pos); + } + + bool TryReadChar (string str, ref int pos, char c) + { + if (pos >= str.Length || str [pos] != c) + return false; + pos++; + return true; + } + + void ThrownParseError (string str, int pos) + { + if (pos > str.Length) + pos = str.Length; + str = str.Insert (pos, "[!]"); + throw new InvalidOperationException ("Error parsing result: " + str); + } + + public IEnumerator GetEnumerator () + { + if (props != null) + return props.Values.GetEnumerator (); + else if (array != null) + return array.GetEnumerator (); + else + return new object[0].GetEnumerator (); + } + } +} |