[Pkg-cli-libs-commits] [mono-debugger-libs] 01/02: Imported Upstream version 0+20131201.3459502
Jo Shields
directhex at moszumanska.debian.org
Sun Dec 1 12:42:02 UTC 2013
This is an automated email from the git hooks/post-receive script.
directhex pushed a commit to annotated tag debian/0+20131201.3459502-1
in repository mono-debugger-libs.
commit 25200ecf4209472a409063d972d4b18627aab46c
Author: Jo Shields <directhex at apebox.org>
Date: Sun Dec 1 10:58:12 2013 +0000
Imported Upstream version 0+20131201.3459502
---
.gitignore | 13 +
Mono.Debugger.Soft/Locale.cs | 51 +
Mono.Debugger.Soft/Makefile.am | 3 +
Mono.Debugger.Soft/Mono.Debugger.Soft.csproj | 127 +
.../AbsentInformationException.cs | 10 +
.../Mono.Debugger.Soft/AppDomainCreateEvent.cs | 20 +
.../Mono.Debugger.Soft/AppDomainMirror.cs | 96 +
.../Mono.Debugger.Soft/AppDomainUnloadEvent.cs | 20 +
.../Mono.Debugger.Soft/ArrayMirror.cs | 143 ++
.../Mono.Debugger.Soft/AssemblyLoadEvent.cs | 20 +
.../Mono.Debugger.Soft/AssemblyLoadEventRequest.cs | 11 +
.../Mono.Debugger.Soft/AssemblyMirror.cs | 100 +
.../Mono.Debugger.Soft/AssemblyUnloadEvent.cs | 20 +
.../Mono.Debugger.Soft/BreakpointEvent.cs | 20 +
.../Mono.Debugger.Soft/BreakpointEventRequest.cs | 28 +
Mono.Debugger.Soft/Mono.Debugger.Soft/ChangeLog | 210 ++
.../Mono.Debugger.Soft/Connection.cs | 2393 ++++++++++++++++++
.../CustomAttributeDataMirror.cs | 147 ++
.../CustomAttributeNamedArgumentMirror.cs | 37 +
.../CustomAttributeTypedArgumentMirror.cs | 59 +
.../Mono.Debugger.Soft/DataConverter.cs | 1836 ++++++++++++++
.../Mono.Debugger.Soft/EnumMirror.cs | 48 +
Mono.Debugger.Soft/Mono.Debugger.Soft/Event.cs | 50 +
.../Mono.Debugger.Soft/EventQueueImpl.cs | 133 +
.../Mono.Debugger.Soft/EventRequest.cs | 142 ++
Mono.Debugger.Soft/Mono.Debugger.Soft/EventSet.cs | 34 +
Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs | 32 +
.../Mono.Debugger.Soft/ExceptionEvent.cs | 20 +
.../Mono.Debugger.Soft/ExceptionEventRequest.cs | 48 +
.../Mono.Debugger.Soft/FieldInfoMirror.cs | 181 ++
.../Mono.Debugger.Soft/IInvokeAsyncResult.cs | 10 +
.../Mono.Debugger.Soft/ILExceptionHandler.cs | 33 +
.../Mono.Debugger.Soft/ILInstruction.cs | 67 +
Mono.Debugger.Soft/Mono.Debugger.Soft/IMirror.cs | 20 +
.../Mono.Debugger.Soft/ITargetProcess.cs | 74 +
.../Mono.Debugger.Soft/InterfaceMappingMirror.cs | 26 +
.../InvalidStackFrameException.cs | 10 +
.../Mono.Debugger.Soft/InvocationException.cs | 20 +
.../Mono.Debugger.Soft/InvokeOptions.cs | 18 +
.../Mono.Debugger.Soft/LocalVariable.cs | 79 +
Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs | 68 +
.../Mono.Debugger.Soft/MethodBodyMirror.cs | 216 ++
.../Mono.Debugger.Soft/MethodEntryEvent.cs | 20 +
.../Mono.Debugger.Soft/MethodEntryEventRequest.cs | 10 +
.../Mono.Debugger.Soft/MethodExitEvent.cs | 20 +
.../Mono.Debugger.Soft/MethodExitEventRequest.cs | 10 +
.../Mono.Debugger.Soft/MethodMirror.cs | 411 +++
Mono.Debugger.Soft/Mono.Debugger.Soft/Mirror.cs | 39 +
.../Mono.Debugger.Soft/ModuleMirror.cs | 66 +
.../Mono.Debugger.Soft/ObjectCollectedException.cs | 10 +
.../Mono.Debugger.Soft/ObjectMirror.cs | 380 +++
.../Mono.Debugger.Soft/ParameterInfoMirror.cs | 64 +
.../Mono.Debugger.Soft/PointerValue.cs | 65 +
.../Mono.Debugger.Soft/PrimitiveValue.cs | 56 +
.../Mono.Debugger.Soft/PropertyInfoMirror.cs | 139 ++
.../Mono.Debugger.Soft/StackFrame.cs | 208 ++
Mono.Debugger.Soft/Mono.Debugger.Soft/StepEvent.cs | 27 +
.../Mono.Debugger.Soft/StepEventRequest.cs | 91 +
.../Mono.Debugger.Soft/StringMirror.cs | 43 +
.../Mono.Debugger.Soft/StructMirror.cs | 71 +
.../Mono.Debugger.Soft/SuspendPolicy.cs | 10 +
.../Mono.Debugger.Soft/ThreadDeathEvent.cs | 8 +
.../Mono.Debugger.Soft/ThreadMirror.cs | 95 +
.../Mono.Debugger.Soft/ThreadStartEvent.cs | 8 +
.../Mono.Debugger.Soft/TypeLoadEvent.cs | 20 +
.../Mono.Debugger.Soft/TypeLoadEventRequest.cs | 43 +
.../Mono.Debugger.Soft/TypeMirror.cs | 868 +++++++
.../Mono.Debugger.Soft/UserBreakEvent.cs | 8 +
.../Mono.Debugger.Soft/UserLogEvent.cs | 33 +
.../Mono.Debugger.Soft/VMDeathEvent.cs | 10 +
.../Mono.Debugger.Soft/VMDisconnectEvent.cs | 10 +
.../Mono.Debugger.Soft/VMDisconnectedException.cs | 10 +
.../Mono.Debugger.Soft/VMMismatchException.cs | 10 +
.../Mono.Debugger.Soft/VMStartEvent.cs | 10 +
Mono.Debugger.Soft/Mono.Debugger.Soft/Value.cs | 14 +
.../Mono.Debugger.Soft/VirtualMachine.cs | 701 ++++++
.../Mono.Debugger.Soft/VirtualMachineManager.cs | 339 +++
Mono.Debugger.Soft/mono-git-revision | 1 +
Mono.Debugger.Soft/mono.snk | Bin 0 -> 596 bytes
Mono.Debugging.Soft/ArrayAdaptor.cs | 89 +
Mono.Debugging.Soft/AssemblyInfo.cs | 29 +
Mono.Debugging.Soft/ChangeLog | 264 ++
Mono.Debugging.Soft/FieldValueReference.cs | 170 ++
Mono.Debugging.Soft/Makefile.am | 1 +
Mono.Debugging.Soft/Mono.Debugging.Soft.csproj | 79 +
Mono.Debugging.Soft/PropertyValueReference.cs | 128 +
Mono.Debugging.Soft/SoftDebuggerAdaptor.cs | 1825 ++++++++++++++
Mono.Debugging.Soft/SoftDebuggerBacktrace.cs | 215 ++
Mono.Debugging.Soft/SoftDebuggerSession.cs | 2638 ++++++++++++++++++++
Mono.Debugging.Soft/SoftDebuggerStartInfo.cs | 203 ++
Mono.Debugging.Soft/SoftEvaluationContext.cs | 186 ++
Mono.Debugging.Soft/StringAdaptor.cs | 76 +
Mono.Debugging.Soft/VariableValueReference.cs | 88 +
Mono.Debugging/ChangeLog | 1032 ++++++++
Mono.Debugging/Makefile.am | 1 +
.../Mono.Debugging.Backend/DissassemblyBuffer.cs | 154 ++
.../Mono.Debugging.Backend/EvaluationResult.cs | 55 +
.../Mono.Debugging.Backend/IBacktrace.cs | 20 +
.../IDebuggerBackendObject.cs | 34 +
.../IDebuggerSessionFrontend.cs | 44 +
.../Mono.Debugging.Backend/IObjectValueSource.cs | 43 +
.../IObjectValueUpdateCallback.cs | 37 +
.../Mono.Debugging.Backend/IObjectValueUpdater.cs | 37 +
Mono.Debugging/Mono.Debugging.Backend/IRawValue.cs | 40 +
.../Mono.Debugging.Backend/IRawValueArray.cs | 40 +
.../Mono.Debugging.Backend/IRawValueString.cs | 39 +
.../Mono.Debugging.Backend/UpdateCallback.cs | 68 +
.../Mono.Debugging.Client/AssemblyLine.cs | 90 +
Mono.Debugging/Mono.Debugging.Client/Backtrace.cs | 67 +
Mono.Debugging/Mono.Debugging.Client/BreakEvent.cs | 338 +++
.../Mono.Debugging.Client/BreakEventArgs.cs | 45 +
.../Mono.Debugging.Client/BreakEventInfo.cs | 164 ++
.../Mono.Debugging.Client/BreakEventStatus.cs | 57 +
Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs | 237 ++
.../Mono.Debugging.Client/BreakpointEventArgs.cs | 45 +
.../Mono.Debugging.Client/BreakpointStore.cs | 583 +++++
Mono.Debugging/Mono.Debugging.Client/Catchpoint.cs | 81 +
.../Mono.Debugging.Client/CatchpointEventArgs.cs | 45 +
.../Mono.Debugging.Client/CompletionData.cs | 77 +
.../Mono.Debugging.Client/DebuggerException.cs | 47 +
.../Mono.Debugging.Client/DebuggerFeatures.cs | 47 +
.../DebuggerLoggingService.cs | 71 +
.../Mono.Debugging.Client/DebuggerSession.cs | 1538 ++++++++++++
.../DebuggerSessionOptions.cs | 38 +
.../Mono.Debugging.Client/DebuggerStartInfo.cs | 80 +
.../Mono.Debugging.Client/EvaluationOptions.cs | 117 +
.../Mono.Debugging.Client/ExceptionInfo.cs | 254 ++
.../Mono.Debugging.Client/FunctionBreakpoint.cs | 189 ++
.../Mono.Debugging.Client/IExpressionEvaluator.cs | 38 +
Mono.Debugging/Mono.Debugging.Client/ObjectPath.cs | 101 +
.../Mono.Debugging.Client/ObjectValue.cs | 787 ++++++
.../Mono.Debugging.Client/ObjectValueFlags.cs | 71 +
.../Mono.Debugging.Client/ProcessEventArgs.cs | 47 +
.../Mono.Debugging.Client/ProcessInfo.cs | 78 +
Mono.Debugging/Mono.Debugging.Client/RawValue.cs | 280 +++
.../Mono.Debugging.Client/SourceLocation.cs | 32 +
Mono.Debugging/Mono.Debugging.Client/StackFrame.cs | 313 +++
.../Mono.Debugging.Client/TargetEventArgs.cs | 57 +
.../Mono.Debugging.Client/TargetEventType.cs | 19 +
.../Mono.Debugging.Client/ThreadEventArgs.cs | 47 +
Mono.Debugging/Mono.Debugging.Client/ThreadInfo.cs | 135 +
.../Mono.Debugging.Evaluation/ArrayElementGroup.cs | 359 +++
.../ArrayValueReference.cs | 79 +
.../AsyncEvaluationTracker.cs | 147 ++
.../AsyncOperationManager.cs | 241 ++
.../Mono.Debugging.Evaluation/BaseBacktrace.cs | 245 ++
.../BaseTypeViewSource.cs | 89 +
.../Mono.Debugging.Evaluation/EvaluationContext.cs | 145 ++
.../ExceptionInfoSource.cs | 160 ++
.../ExpressionEvaluator.cs | 232 ++
.../FilteredMembersSource.cs | 123 +
.../ICollectionAdaptor.cs | 41 +
.../Mono.Debugging.Evaluation/IObjectSource.cs | 35 +
.../Mono.Debugging.Evaluation/IStringAdaptor.cs | 37 +
.../LiteralValueReference.cs | 181 ++
.../NRefactoryExpressionEvaluator.cs | 242 ++
.../NRefactoryExpressionEvaluatorVisitor.cs | 1375 ++++++++++
.../NRefactoryExpressionResolverVisitor.cs | 131 +
.../NRefactoryExtensions.cs | 182 ++
.../NamespaceValueReference.cs | 150 ++
.../NullValueReference.cs | 97 +
.../ObjectValueAdaptor.cs | 1380 ++++++++++
.../Mono.Debugging.Evaluation/RawViewSource.cs | 83 +
.../Mono.Debugging.Evaluation/RemoteFrameObject.cs | 76 +
.../Mono.Debugging.Evaluation/RemoteRawValue.cs | 214 ++
.../Mono.Debugging.Evaluation/TimeOutException.cs | 38 +
.../Mono.Debugging.Evaluation/TimedEvaluator.cs | 254 ++
.../TypeValueReference.cs | 207 ++
.../UserVariableReference.cs | 73 +
.../Mono.Debugging.Evaluation/ValueReference.cs | 266 ++
Mono.Debugging/Mono.Debugging.csproj | 140 ++
Mono.Debugging/mono.debugging.snk | Bin 0 -> 596 bytes
README.md | 15 +
UnitTests/UnitTests/DebugTests.cs | 110 +
UnitTests/UnitTests/EvaluationTests.cs | 695 ++++++
UnitTests/UnitTests/SdbEvaluationTests.cs | 48 +
UnitTests/UnitTests/SdbStackFrameTests.cs | 49 +
UnitTests/UnitTests/StackFrameTests.cs | 122 +
UnitTests/UnitTests/UnitTests.TestApp/Main.cs | 179 ++
.../UnitTests.TestApp/Properties/AssemblyInfo.cs | 27 +
.../UnitTests.TestApp/UnitTests.TestApp.csproj | 39 +
UnitTests/UnitTests/UnitTests.csproj | 63 +
debugger-libs.sln | 302 +++
183 files changed, 33142 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3ab4775
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+bin
+obj
+*~
+*.sln.cache
+*.suo
+*.user
+*.dotCover
+*.pidb
+*.userprefs
+*.usertasks
+*.mdb
+.DS_Store
+Makefile.in
diff --git a/Mono.Debugger.Soft/Locale.cs b/Mono.Debugger.Soft/Locale.cs
new file mode 100644
index 0000000..7293ab2
--- /dev/null
+++ b/Mono.Debugger.Soft/Locale.cs
@@ -0,0 +1,51 @@
+//
+// Locale.cs
+//
+// Author:
+// Miguel de Icaza (miguel at ximian.com)
+// Andreas Nahr (ClassDevelopment at A-SoftTech.com)
+//
+// (C) 2001 - 2003 Ximian, Inc (http://www.ximian.com)
+//
+
+//
+// Copyright (C) 2004 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;
+
+internal sealed class Locale {
+
+ private Locale ()
+ {
+ }
+
+ public static string GetText (string msg)
+ {
+ return msg;
+ }
+
+ public static string GetText (string fmt, params object [] args)
+ {
+ return String.Format (fmt, args);
+ }
+}
diff --git a/Mono.Debugger.Soft/Makefile.am b/Mono.Debugger.Soft/Makefile.am
new file mode 100644
index 0000000..c5d0ed3
--- /dev/null
+++ b/Mono.Debugger.Soft/Makefile.am
@@ -0,0 +1,3 @@
+include $(top_srcdir)/xbuild.include
+
+XBUILD_OUTPUT=$(XBUILD_OUTPUT_BIN)/MonoDevelop.Debugger.Soft
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj b/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj
new file mode 100644
index 0000000..7278c3f
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{372E8E3E-29D5-4B4D-88A2-4711CD628C4E}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Mono.Debugger.Soft</RootNamespace>
+ <AssemblyName>Mono.Debugger.Soft</AssemblyName>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>mono.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>True</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>False</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>MONO_DATACONVERTER_STATIC_METHODS</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>False</ConsolePause>
+ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>none</DebugType>
+ <Optimize>False</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>False</ConsolePause>
+ <DefineConstants>MONO_DATACONVERTER_STATIC_METHODS</DefineConstants>
+ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Compile Include="Mono.Debugger.Soft\AbsentInformationException.cs" />
+ <Compile Include="Mono.Debugger.Soft\AppDomainCreateEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\AppDomainMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\AppDomainUnloadEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\ArrayMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\AssemblyLoadEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\AssemblyMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\AssemblyUnloadEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\BreakpointEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\BreakpointEventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\Connection.cs" />
+ <Compile Include="Mono.Debugger.Soft\CustomAttributeDataMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\CustomAttributeNamedArgumentMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\CustomAttributeTypedArgumentMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\DataConverter.cs" />
+ <Compile Include="Mono.Debugger.Soft\EnumMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\Event.cs" />
+ <Compile Include="Mono.Debugger.Soft\EventQueueImpl.cs" />
+ <Compile Include="Mono.Debugger.Soft\EventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\EventSet.cs" />
+ <Compile Include="Mono.Debugger.Soft\EventType.cs" />
+ <Compile Include="Mono.Debugger.Soft\ExceptionEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\ExceptionEventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\FieldInfoMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\IInvokeAsyncResult.cs" />
+ <Compile Include="Mono.Debugger.Soft\ILExceptionHandler.cs" />
+ <Compile Include="Mono.Debugger.Soft\ILInstruction.cs" />
+ <Compile Include="Mono.Debugger.Soft\IMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\InterfaceMappingMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\InvalidStackFrameException.cs" />
+ <Compile Include="Mono.Debugger.Soft\InvocationException.cs" />
+ <Compile Include="Mono.Debugger.Soft\InvokeOptions.cs" />
+ <Compile Include="Mono.Debugger.Soft\ITargetProcess.cs" />
+ <Compile Include="Mono.Debugger.Soft\LocalVariable.cs" />
+ <Compile Include="Mono.Debugger.Soft\Location.cs" />
+ <Compile Include="Mono.Debugger.Soft\MethodBodyMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\MethodEntryEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\MethodEntryEventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\MethodExitEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\MethodExitEventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\MethodMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\Mirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\ModuleMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\ObjectCollectedException.cs" />
+ <Compile Include="Mono.Debugger.Soft\ObjectMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\ParameterInfoMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\PrimitiveValue.cs" />
+ <Compile Include="Mono.Debugger.Soft\PropertyInfoMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\StackFrame.cs" />
+ <Compile Include="Mono.Debugger.Soft\StepEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\StepEventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\StringMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\StructMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\SuspendPolicy.cs" />
+ <Compile Include="Mono.Debugger.Soft\ThreadDeathEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\ThreadMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\ThreadStartEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\TypeLoadEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\TypeLoadEventRequest.cs" />
+ <Compile Include="Mono.Debugger.Soft\TypeMirror.cs" />
+ <Compile Include="Mono.Debugger.Soft\UserBreakEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\UserLogEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\Value.cs" />
+ <Compile Include="Mono.Debugger.Soft\VirtualMachine.cs" />
+ <Compile Include="Mono.Debugger.Soft\VirtualMachineManager.cs" />
+ <Compile Include="Mono.Debugger.Soft\VMDeathEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\VMDisconnectedException.cs" />
+ <Compile Include="Mono.Debugger.Soft\VMDisconnectEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\VMMismatchException.cs" />
+ <Compile Include="Mono.Debugger.Soft\VMStartEvent.cs" />
+ <Compile Include="Mono.Debugger.Soft\AssemblyLoadEventRequest.cs" />
+ <Compile Include="Locale.cs" />
+ <Compile Include="Mono.Debugger.Soft\PointerValue.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Makefile.am" />
+ <None Include="mono-git-revision" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="System.Core" />
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\cecil\Mono.Cecil.csproj">
+ <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
+ <Name>Mono.Cecil</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+</Project>
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AbsentInformationException.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AbsentInformationException.cs
new file mode 100644
index 0000000..5ce9ee2
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AbsentInformationException.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class AbsentInformationException : Exception {
+
+ public AbsentInformationException () : base ("Debug information is not available for this frame.") {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainCreateEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainCreateEvent.cs
new file mode 100644
index 0000000..ae2a3e9
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainCreateEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class AppDomainCreateEvent : Event {
+ AppDomainMirror domain;
+ long id;
+
+ internal AppDomainCreateEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.AppDomainCreate, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public AppDomainMirror Domain {
+ get {
+ if (domain == null)
+ domain = vm.GetDomain (id);
+ return domain;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainMirror.cs
new file mode 100644
index 0000000..0b934c1
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainMirror.cs
@@ -0,0 +1,96 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class AppDomainMirror : Mirror
+ {
+ string friendly_name;
+ AssemblyMirror entry_assembly, corlib;
+
+ internal AppDomainMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ public string FriendlyName {
+ get {
+ /* The name can't be empty during domain creation */
+ if (friendly_name == null || friendly_name == String.Empty)
+ friendly_name = vm.conn.Domain_GetName (id);
+ return friendly_name;
+ }
+ }
+
+ // Not cached
+ public AssemblyMirror[] GetAssemblies () {
+ long[] ids = vm.conn.Domain_GetAssemblies (id);
+ AssemblyMirror[] assemblies = new AssemblyMirror [ids.Length];
+ // FIXME: Uniqueness
+ for (int i = 0; i < ids.Length; ++i)
+ assemblies [i] = vm.GetAssembly (ids [i]);
+ return assemblies;
+ }
+
+ // This returns null when called before the first AssemblyLoad event
+ public AssemblyMirror GetEntryAssembly () {
+ if (entry_assembly == null) {
+ long ass_id = vm.conn.Domain_GetEntryAssembly (id);
+
+ entry_assembly = vm.GetAssembly (ass_id);
+ }
+ return entry_assembly;
+ }
+
+ public AssemblyMirror Corlib {
+ get {
+ if (corlib == null) {
+ long ass_id = vm.conn.Domain_GetCorlib (id);
+
+ corlib = vm.GetAssembly (ass_id);
+ }
+ return corlib;
+ }
+ }
+
+ public StringMirror CreateString (string s) {
+ if (s == null)
+ throw new ArgumentNullException ("s");
+
+ return vm.GetObject<StringMirror> (vm.conn.Domain_CreateString (id, s));
+ }
+
+ public ObjectMirror CreateBoxedValue (Value value) {
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ if (!(value is PrimitiveValue) && !(value is StructMirror))
+ throw new ArgumentException ("Value must be a PrimitiveValue or a StructMirror", "value");
+ if ((value is PrimitiveValue) && (value as PrimitiveValue).Value == null)
+ return null;
+
+ TypeMirror t = null;
+ if (value is PrimitiveValue)
+ t = GetCorrespondingType ((value as PrimitiveValue).Value.GetType ());
+ else
+ t = (value as StructMirror).Type;
+
+ return vm.GetObject<ObjectMirror> (vm.conn.Domain_CreateBoxedValue (id, t.Id, vm.EncodeValue (value)));
+ }
+
+ TypeMirror[] primitiveTypes = new TypeMirror [32];
+
+ public TypeMirror GetCorrespondingType (Type t) {
+ if (t == null)
+ throw new ArgumentNullException ("t");
+ TypeCode tc = Type.GetTypeCode (t);
+
+ if (tc == TypeCode.Empty || tc == TypeCode.Object)
+ throw new ArgumentException ("t must be a primitive type", "t");
+
+ int tc_index = (int)tc;
+ if (primitiveTypes [tc_index] == null) {
+ primitiveTypes [tc_index] = Corlib.GetType ("System." + t.Name, false, false);
+ if (primitiveTypes [tc_index] == null)
+ throw new NotImplementedException ();
+ }
+ return primitiveTypes [tc_index];
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainUnloadEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainUnloadEvent.cs
new file mode 100644
index 0000000..e2ad5a9
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AppDomainUnloadEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class AppDomainUnloadEvent : Event {
+ AppDomainMirror domain;
+ long id;
+
+ internal AppDomainUnloadEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.AppDomainUnload, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public AppDomainMirror Domain {
+ get {
+ if (domain == null)
+ domain = vm.GetDomain (id);
+ return domain;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ArrayMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ArrayMirror.cs
new file mode 100644
index 0000000..57a7951
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ArrayMirror.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public class ArrayMirror : ObjectMirror, IEnumerable {
+
+ public int[] lengths;
+ public int[] lower_bounds;
+ public int rank;
+
+ internal ArrayMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ internal ArrayMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id, type, domain) {
+ }
+
+ public int Length {
+ get {
+ GetLengths ();
+
+ int length = lengths [0];
+
+ for (int i = 1; i < Rank; i++) {
+ length *= lengths [i];
+ }
+
+ return length;
+ }
+ }
+
+ public int Rank {
+ get {
+ GetLengths ();
+
+ return rank;
+ }
+ }
+
+ public int GetLength (int dimension) {
+ GetLengths ();
+
+ if (dimension < 0 || dimension >= Rank)
+ throw new ArgumentOutOfRangeException ("dimension");
+
+ return lengths [dimension];
+ }
+
+ public int GetLowerBound (int dimension) {
+ GetLengths ();
+
+ if (dimension < 0 || dimension >= Rank)
+ throw new ArgumentOutOfRangeException ("dimension");
+
+ return lower_bounds [dimension];
+ }
+
+ void GetLengths () {
+ if (lengths == null)
+ lengths = vm.conn.Array_GetLength (id, out this.rank, out this.lower_bounds);
+ }
+
+ public Value this [int index] {
+ get {
+ // FIXME: Multiple dimensions
+ if (index < 0 || index > Length - 1)
+ throw new IndexOutOfRangeException ();
+ return vm.DecodeValue (vm.conn.Array_GetValues (id, index, 1) [0]);
+ }
+ set {
+ // FIXME: Multiple dimensions
+ if (index < 0 || index > Length - 1)
+ throw new IndexOutOfRangeException ();
+ vm.conn.Array_SetValues (id, index, new ValueImpl [] { vm.EncodeValue (value) });
+ }
+ }
+
+ public IList<Value> GetValues (int index, int length) {
+ // FIXME: Multiple dimensions
+ if (index < 0 || index > Length - length)
+ throw new IndexOutOfRangeException ();
+ return vm.DecodeValues (vm.conn.Array_GetValues (id, index, length));
+ }
+
+ public void SetValues (int index, Value[] values) {
+ if (values == null)
+ throw new ArgumentNullException ("values");
+ // FIXME: Multiple dimensions
+ if (index < 0 || index > Length - values.Length)
+ throw new IndexOutOfRangeException ();
+ vm.conn.Array_SetValues (id, index, vm.EncodeValues (values));
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return new SimpleEnumerator (this);
+ }
+
+ internal class SimpleEnumerator : IEnumerator, ICloneable
+ {
+ ArrayMirror arr;
+ int pos, length;
+
+ public SimpleEnumerator (ArrayMirror arr)
+ {
+ this.arr = arr;
+ this.pos = -1;
+ this.length = arr.Length;
+ }
+
+ public object Current {
+ get {
+ if (pos < 0 )
+ throw new InvalidOperationException ("Enumeration has not started.");
+ if (pos >= length)
+ throw new InvalidOperationException ("Enumeration has already ended");
+ return arr [pos];
+ }
+ }
+
+ public bool MoveNext()
+ {
+ if (pos < length)
+ pos++;
+ if(pos < length)
+ return true;
+ else
+ return false;
+ }
+
+ public void Reset()
+ {
+ pos = -1;
+ }
+
+ public object Clone ()
+ {
+ return MemberwiseClone ();
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyLoadEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyLoadEvent.cs
new file mode 100644
index 0000000..df9c691
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyLoadEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class AssemblyLoadEvent : Event {
+ AssemblyMirror assembly;
+ long id;
+
+ internal AssemblyLoadEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.AssemblyLoad, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public AssemblyMirror Assembly {
+ get {
+ if (assembly == null)
+ assembly = vm.GetAssembly (id);
+ return assembly;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyLoadEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyLoadEventRequest.cs
new file mode 100644
index 0000000..0ecc1b1
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyLoadEventRequest.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mono.Debugger.Soft
+{
+ public sealed class AssemblyLoadEventRequest : EventRequest {
+ internal AssemblyLoadEventRequest (VirtualMachine vm) : base (vm, EventType.AssemblyLoad) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs
new file mode 100644
index 0000000..475b28a
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Reflection;
+using Mono.Debugger;
+using Mono.Cecil;
+
+namespace Mono.Debugger.Soft
+{
+ public class AssemblyMirror : Mirror
+ {
+ string location;
+ MethodMirror entry_point;
+ bool entry_point_set;
+ ModuleMirror main_module;
+ AssemblyName aname;
+ AssemblyDefinition meta;
+
+ internal AssemblyMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ public string Location {
+ get {
+ if (location == null)
+ location = vm.conn.Assembly_GetLocation (id);
+ return location;
+ }
+ }
+
+ public MethodMirror EntryPoint {
+ get {
+ if (!entry_point_set) {
+ long mid = vm.conn.Assembly_GetEntryPoint (id);
+
+ if (mid != 0)
+ entry_point = vm.GetMethod (mid);
+ entry_point_set = true;
+ }
+ return entry_point;
+ }
+ }
+
+ public ModuleMirror ManifestModule {
+ get {
+ if (main_module == null) {
+ main_module = vm.GetModule (vm.conn.Assembly_GetManifestModule (id));
+ }
+ return main_module;
+ }
+ }
+
+ public virtual AssemblyName GetName () {
+ if (aname == null) {
+ string name = vm.conn.Assembly_GetName (id);
+ aname = new AssemblyName (name);
+ }
+ return aname;
+ }
+
+ public ObjectMirror GetAssemblyObject () {
+ return vm.GetObject (vm.conn.Assembly_GetObject (id));
+ }
+
+ public TypeMirror GetType (string name, bool throwOnError, bool ignoreCase)
+ {
+ if (name == null)
+ throw new ArgumentNullException (name);
+ if (name.Length == 0)
+ throw new ArgumentException ("name", "Name cannot be empty");
+
+ if (throwOnError)
+ throw new NotImplementedException ();
+ return vm.GetType (vm.conn.Assembly_GetType (id, name, ignoreCase));
+ }
+
+ public TypeMirror GetType (String name, Boolean throwOnError)
+ {
+ return GetType (name, throwOnError, false);
+ }
+
+ public TypeMirror GetType (String name) {
+ return GetType (name, false, false);
+ }
+
+ /*
+ * An optional Cecil assembly which could be used to access metadata instead
+ * of reading it from the debuggee.
+ */
+ public AssemblyDefinition Metadata {
+ get {
+ return meta;
+ }
+ set {
+ if (value.MainModule.Name != ManifestModule.Name)
+ throw new ArgumentException ("The supplied assembly is named '" + value.MainModule.Name + "', while the assembly in the debuggee is named '" + ManifestModule.Name + "'.");
+ if (value.MainModule.Mvid != ManifestModule.ModuleVersionId)
+ throw new ArgumentException ("The supplied assembly's main module has guid '" + value.MainModule.Mvid + ", while the assembly in the debuggee has guid '" + ManifestModule.ModuleVersionId + "'.", "value");
+ meta = value;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyUnloadEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyUnloadEvent.cs
new file mode 100644
index 0000000..cc34f8e
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyUnloadEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class AssemblyUnloadEvent : Event {
+ AssemblyMirror assembly;
+ long id;
+
+ internal AssemblyUnloadEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.AssemblyUnload, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public AssemblyMirror Assembly {
+ get {
+ if (assembly == null)
+ assembly = vm.GetAssembly (id);
+ return assembly;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/BreakpointEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/BreakpointEvent.cs
new file mode 100644
index 0000000..cd52f7e
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/BreakpointEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class BreakpointEvent : Event {
+ MethodMirror method;
+ long id;
+
+ internal BreakpointEvent (VirtualMachine vm, int req_id, long thread_id, long id, long loc) : base (EventType.Breakpoint, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public MethodMirror Method {
+ get {
+ if (method == null)
+ method = vm.GetMethod (id);
+ return method;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/BreakpointEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/BreakpointEventRequest.cs
new file mode 100644
index 0000000..cb94851
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/BreakpointEventRequest.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mono.Debugger.Soft
+{
+ public sealed class BreakpointEventRequest : EventRequest {
+
+ MethodMirror method;
+ long location;
+
+ internal BreakpointEventRequest (VirtualMachine vm, MethodMirror method, long location) : base (vm, EventType.Breakpoint) {
+ if (method == null)
+ throw new ArgumentNullException ("method");
+ CheckMirror (vm, method);
+ if (method.Locations.Count > 0 && !method.Locations.Any (l => l.ILOffset == location))
+ throw new ArgumentException ("A breakpoint can only be set at an IL offset which is equal to the ILOffset property of one of the locations in method.Locations", "location");
+ this.method = method;
+ this.location = location;
+ }
+
+ public override void Enable () {
+ var mods = new List <Modifier> ();
+ mods.Add (new LocationModifier () { Method = method.Id, Location = location });
+ SendReq (mods);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ChangeLog b/Mono.Debugger.Soft/Mono.Debugger.Soft/ChangeLog
new file mode 100644
index 0000000..47f2476
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ChangeLog
@@ -0,0 +1,210 @@
+2010-06-17 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachine.cs Connection.cs: Group events received together into an EventSet,
+ like it is done in JDI. Add a GetNextEventSet () method.
+
+2010-06-04 Zoltan Varga <vargaz at gmail.com>
+
+ * StackFrame.cs (GetVisibleVariables): New method to return the set of variables
+ visible at the current stack frame.
+
+2010-05-24 Martin Baulig <martin at ximian.com>
+
+ * Connection.cs (VersionInfo): Make this public.
+
+ * VirtualMachine.cs (Version): New public property.
+
+2010-05-07 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachine.cs (ErrorHandler): Convert ABSENT_INFORMATION to
+ AbsentInformationException.
+
+ * AbsentInformationException.cs: New file.
+
+2010-04-30 Zoltan Varga <vargaz at gmail.com>
+
+ * TypeMirror.cs: Add new overload for GetSourceFiles () which returns full paths.
+
+2010-04-27 Lluis Sanchez <lluis at novell.com>
+
+ * ITargetProcess.cs:
+ * VirtualMachine.cs:
+ * VirtualMachineManager.cs:
+ Restored old API. Renamed IProcess to ITargetProcess everywhere
+ to avoid naming conflicts.
+
+2010-04-26 Lluis Sanchez <lluis at novell.com>
+
+ * IProcess.cs:
+ * VirtualMachine.cs:
+ * VirtualMachineManager.cs:
+ Added new IProcess interface which wraps the debugged process.
+ This abstraction makes it easier to support debugging processes
+ for which we don't have a direct Process reference (for example,
+ if the process is remote).
+
+2010-04-10 Zoltan Varga <vargaz at gmail.com>
+
+ * ThreadMirror.cs: Add a ThreadId property.
+
+2010-03-05 Martin Baulig <martin at ximian.com>
+
+ Add support for aborting invocations.
+
+ * IInvokeAsyncResult.cs: New file.
+ (IInvokeAsyncResult): New public interface; derives from
+ `IAsyncResult' and contains an Abort() method.
+
+ * Connection.cs
+ (Connection.VM_BeginInvokeMethod): Return the `id'.
+ (Connection.VM_AbortInvoke): New method.
+
+ * ObjectMirror.cs
+ (ObjectMirror.AbortInvoke): New internal static method.
+
+2010-03-01 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachine.cs: Allow working with runtimes implementing a different
+ minor version of the debugger protocol.
+
+2010-03-01 Zoltan Varga <vargaz at gmail.com>
+
+ * Connection.cs: Send the protocol version used by the client to the debuggee
+ after the handshake.
+
+2010-03-01 Zoltan Varga <vargaz at gmail.com>
+
+ * Location.cs: Implement ToString ().
+
+ * AppDomainMirror.cs (CreateBoxedValue): New method to create a boxed value from
+ a primitive value or struct.
+
+2010-02-26 Zoltan Varga <vargaz at gmail.com>
+
+ * Connection.cs: Throw a NotSupportedException if the protocol version doesn't
+ support the caught/uncaught flags in an exception modifier.
+
+2010-02-20 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachine.cs (CreateExceptionRequest): Add an overload taking two
+ booleans which specify whenever to report caught/uncaught exceptions.
+
+ * ExceptionRequest.cs: Add public properties for them.
+
+ * Connections.cs: Pass the caught/uncaught flags to the debuggee. Bump protocol
+ minor version.
+
+2010-02-11 Zoltan Varga <vargaz at gmail.com>
+
+ * AssemblyMirror.cs: Add missing GetType () overloads.
+
+2010-02-04 Zoltan Varga <vargaz at gmail.com>
+
+ * TypeMirror.cs (EnumUnderlyingType): New property.
+
+ * EnumMirror.cs: Use it.
+
+ * VirtualMachine.cs (CreateEnumMirror): New method to create an EnumMirror.
+
+ * AppDomainMirror.cs (GetCorrespondingType): New method to return a TypeMirror
+ corresponding to a primitive type.
+
+ * TypeMirror.cs (IsEnum): Implement.
+
+ * EnumMirror.cs (.ctor): New internal constructor called from CreateEnumMirror
+ which does lots of error checking.
+
+2010-01-28 Zoltan Varga <vargaz at gmail.com>
+
+ * AssemblyUnloadEvent: New file.
+
+ * VirtualMachine.cs Connection.cs: Add support for assembly unload events.
+
+2009-12-05 Lluis Sanchez <lluis at novell.com>
+
+ * StructMirror.cs: Fix field indexer for structs with static fields.
+ * VirtualMachineManager.cs: Added an option to LaunchOptions which
+ allows providing a custom method for launching the process. This
+ allows launching mono in a wrapper process.
+
+2009-12-03 Zoltan Varga <vargaz at gmail.com>
+
+ * StructMirror.cs (this): Ignore static fields.
+
+2009-12-02 Geoff Norton <gnorton at novell.com>
+
+ * VirtualMachineManager.cs: We might get a SocketException (interrupted)
+ here, so lets just handle all Exceptions to our Accept pattern the same
+ way
+
+2009-12-01 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachine.cs (ErrorHandler): Handle NOT_SUSPENDED error code too.
+
+2009-11-24 Zoltan Varga <vargaz at gmail.com>
+
+ * ObjectMirror.cs TypeMirror.cs StructMirror.cs: Make the BeginInvokeMethod
+ which takes a 'vm' argument obsolete, it was added by mistake, add a version
+ without that argument instead.
+
+2009-11-19 Zoltan Varga <vargaz at gmail.com>
+
+ * AssemblyMirror.cs: Add a GetName () method.
+
+2009-11-17 Zoltan Varga <vargaz at gmail.com>
+
+ * Connection.cs ObjectMirror.cs: Implement invokes in a real asynchronous way,
+ without waiting.
+
+2009-11-14 Zoltan Varga <vargaz at gmail.com>
+
+ * InvokeOptions.cs: Add SingleThreaded option, not yet works.
+
+ * VirtualMachineManager.cs (Launch): Pass options to BeginLaunch.
+
+ * ObjectMirror.cs TypeMirror.cs StructMirror.cs: Implement an async version of
+ InvokeMethod ().
+
+2009-11-13 Zoltan Varga <vargaz at gmail.com>
+
+ * InvokeOptions.cs: New file.
+
+ * ObjectMirror.cs TypeMirror.cs StructMirror.cs: Add support for passing flags
+ to InvokeMethod ().
+
+ * Connection.cs: Bump protocol version.
+
+2009-11-12 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachineManager.cs: Put back the old Launch (string[], LaunchOptions)
+ overload.
+
+2009-11-11 Geoff Norton <gnorton at novell.com>
+
+ * VirtualMachineManager.cs: Refactor the APIs to have async methods.
+ Remove a bunch of Listen overloads that are pointless. Refactor
+ Launch to take a ProcessStartInfo instead of string arguments.
+
+2009-11-10 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachineManager.cs (Launch): Close the listening socket instead of
+ shutting it down since Shutdown throws on exception on non-connected sockets
+ in ms.net.
+
+2009-11-05 Zoltan Varga <vargaz at gmail.com>
+
+ * VirtualMachineManager.cs (Listen): Resurrect the old listen method.
+
+ * VirtualMachineManager.cs (Connect): New method to connect to a runtime
+ listening at the provided address.
+
+2009-11-04 Lluis Sanchez <lluis at novell.com>
+
+ * VirtualMachineManager.cs: Properly redirect standard output.
+
+2009-11-03 Zoltan Varga <vargaz at gmail.com>
+
+ * EventRequest.cs (AssemblyFilter): New property to filter
+ events based on a list of assemblies.
+
+ * Connection.cs: Add assembly filters to the protocol implementation.
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
new file mode 100644
index 0000000..28ddb0f
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
@@ -0,0 +1,2393 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ public class VersionInfo {
+ public string VMVersion {
+ get; set;
+ }
+
+ public int MajorVersion {
+ get; set;
+ }
+
+ public int MinorVersion {
+ get; set;
+ }
+
+ /*
+ * Check that this version is at least major:minor
+ */
+ public bool AtLeast (int major, int minor) {
+ if ((MajorVersion > major) || ((MajorVersion == major && MinorVersion >= minor)))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ struct SourceInfo {
+ public string source_file;
+ public byte[] guid, hash;
+ }
+
+ class DebugInfo {
+ public int max_il_offset;
+ public int[] il_offsets;
+ public int[] line_numbers;
+ public int[] column_numbers;
+ public SourceInfo[] source_files;
+ }
+
+ struct FrameInfo {
+ public long id;
+ public long method;
+ public int il_offset;
+ public StackFrameFlags flags;
+ }
+
+ class TypeInfo {
+ public string ns, name, full_name;
+ public long assembly, module, base_type, element_type;
+ public int token, rank, attributes;
+ public bool is_byref, is_pointer, is_primitive, is_valuetype, is_enum;
+ public bool is_gtd, is_generic_type;
+ public long[] nested;
+ public long gtd;
+ public long[] type_args;
+ }
+
+ struct IfaceMapInfo {
+ public long iface_id;
+ public long[] iface_methods;
+ public long[] target_methods;
+ }
+
+ class MethodInfo {
+ public int attributes, iattributes, token;
+ public bool is_gmd, is_generic_method;
+ public long gmd;
+ public long[] type_args;
+ }
+
+ class MethodBodyInfo {
+ public byte[] il;
+ public ExceptionClauseInfo[] clauses;
+ }
+
+ struct ExceptionClauseInfo {
+ public ExceptionClauseFlags flags;
+ public int try_offset;
+ public int try_length;
+ public int handler_offset;
+ public int handler_length;
+ public int filter_offset;
+ public long catch_type_id;
+ }
+
+ [Flags]
+ enum ExceptionClauseFlags {
+ None = 0x0,
+ Filter = 0x1,
+ Finally = 0x2,
+ Fault = 0x4,
+ }
+
+ struct ParamInfo {
+ public int call_conv;
+ public int param_count;
+ public int generic_param_count;
+ public long ret_type;
+ public long[] param_types;
+ public string[] param_names;
+ }
+
+ struct LocalsInfo {
+ public long[] types;
+ public string[] names;
+ public int[] live_range_start;
+ public int[] live_range_end;
+ }
+
+ struct PropInfo {
+ public long id;
+ public string name;
+ public long get_method, set_method;
+ public int attrs;
+ }
+
+ class CattrNamedArgInfo {
+ public bool is_property;
+ public long id;
+ public ValueImpl value;
+ }
+
+ class CattrInfo {
+ public long ctor_id;
+ public ValueImpl[] ctor_args;
+ public CattrNamedArgInfo[] named_args;
+ }
+
+ class ThreadInfo {
+ public bool is_thread_pool;
+ }
+
+ struct ObjectRefInfo {
+ public long type_id;
+ public long domain_id;
+ }
+
+ enum ValueTypeId {
+ VALUE_TYPE_ID_NULL = 0xf0,
+ VALUE_TYPE_ID_TYPE = 0xf1
+ }
+
+ [Flags]
+ enum InvokeFlags {
+ NONE = 0x0,
+ DISABLE_BREAKPOINTS = 0x1,
+ SINGLE_THREADED = 0x2
+ }
+
+ enum ElementType {
+ End = 0x00,
+ Void = 0x01,
+ Boolean = 0x02,
+ Char = 0x03,
+ I1 = 0x04,
+ U1 = 0x05,
+ I2 = 0x06,
+ U2 = 0x07,
+ I4 = 0x08,
+ U4 = 0x09,
+ I8 = 0x0a,
+ U8 = 0x0b,
+ R4 = 0x0c,
+ R8 = 0x0d,
+ String = 0x0e,
+ Ptr = 0x0f,
+ ByRef = 0x10,
+ ValueType = 0x11,
+ Class = 0x12,
+ Var = 0x13,
+ Array = 0x14,
+ GenericInst = 0x15,
+ TypedByRef = 0x16,
+ I = 0x18,
+ U = 0x19,
+ FnPtr = 0x1b,
+ Object = 0x1c,
+ SzArray = 0x1d,
+ MVar = 0x1e,
+ CModReqD = 0x1f,
+ CModOpt = 0x20,
+ Internal = 0x21,
+ Modifier = 0x40,
+ Sentinel = 0x41,
+ Pinned = 0x45,
+
+ Type = 0x50,
+ Boxed = 0x51,
+ Enum = 0x55
+ }
+
+ class ValueImpl {
+ public ElementType Type; /* or one of the VALUE_TYPE_ID constants */
+ public long Objid;
+ public object Value;
+ public long Klass; // For ElementType.ValueType
+ public ValueImpl[] Fields; // for ElementType.ValueType
+ public bool IsEnum; // For ElementType.ValueType
+ public long Id; /* For VALUE_TYPE_ID_TYPE */
+ }
+
+ class ModuleInfo {
+ public string Name, ScopeName, FQName, Guid;
+ public long Assembly;
+ }
+
+ enum TokenType {
+ STRING = 0,
+ TYPE = 1,
+ FIELD = 2,
+ METHOD = 3,
+ UNKNOWN = 4
+ }
+
+ [Flags]
+ enum StackFrameFlags {
+ NONE = 0,
+ DEBUGGER_INVOKE = 1,
+ NATIVE_TRANSITION = 2
+ }
+
+ class ResolvedToken {
+ public TokenType Type;
+ public string Str;
+ public long Id;
+ }
+
+ class Modifier {
+ }
+
+ class CountModifier : Modifier {
+ public int Count {
+ get; set;
+ }
+ }
+
+ class LocationModifier : Modifier {
+ public long Method {
+ get; set;
+ }
+
+ public long Location {
+ get; set;
+ }
+ }
+
+ class StepModifier : Modifier {
+ public long Thread {
+ get; set;
+ }
+
+ public int Depth {
+ get; set;
+ }
+
+ public int Size {
+ get; set;
+ }
+
+ public int Filter {
+ get; set;
+ }
+ }
+
+ class ThreadModifier : Modifier {
+ public long Thread {
+ get; set;
+ }
+ }
+
+ class ExceptionModifier : Modifier {
+ public long Type {
+ get; set;
+ }
+ public bool Caught {
+ get; set;
+ }
+ public bool Uncaught {
+ get; set;
+ }
+ public bool Subclasses {
+ get; set;
+ }
+ }
+
+ class AssemblyModifier : Modifier {
+ public long[] Assemblies {
+ get; set;
+ }
+ }
+
+ class SourceFileModifier : Modifier {
+ public string[] SourceFiles {
+ get; set;
+ }
+ }
+
+ class TypeNameModifier : Modifier {
+ public string[] TypeNames {
+ get; set;
+ }
+ }
+
+ class EventInfo {
+ public EventType EventType {
+ get; set;
+ }
+
+ public int ReqId {
+ get; set;
+ }
+
+ public SuspendPolicy SuspendPolicy {
+ get; set;
+ }
+
+ public long ThreadId {
+ get; set;
+ }
+
+ public long Id {
+ get; set;
+ }
+
+ public long Location {
+ get; set;
+ }
+
+ public int Level {
+ get; set;
+ }
+
+ public string Category {
+ get; set;
+ }
+
+ public string Message {
+ get; set;
+ }
+
+ public EventInfo (EventType type, int req_id) {
+ EventType = type;
+ ReqId = req_id;
+ }
+ }
+
+ public enum ErrorCode {
+ NONE = 0,
+ INVALID_OBJECT = 20,
+ INVALID_FIELDID = 25,
+ INVALID_FRAMEID = 30,
+ NOT_IMPLEMENTED = 100,
+ NOT_SUSPENDED = 101,
+ INVALID_ARGUMENT = 102,
+ ERR_UNLOADED = 103,
+ ERR_NO_INVOCATION = 104,
+ ABSENT_INFORMATION = 105,
+ NO_SEQ_POINT_AT_IL_OFFSET = 106
+ }
+
+ public class ErrorHandlerEventArgs : EventArgs {
+
+ public ErrorCode ErrorCode {
+ get; set;
+ }
+ }
+
+ /*
+ * Represents the connection to the debuggee
+ */
+ public abstract class Connection
+ {
+ /*
+ * The protocol and the packet format is based on JDWP, the differences
+ * are in the set of supported events, and the commands.
+ */
+ internal const string HANDSHAKE_STRING = "DWP-Handshake";
+
+ internal const int HEADER_LENGTH = 11;
+
+ static readonly bool EnableConnectionLogging = !String.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONO_SDB_LOG"));
+ static int ConnectionId;
+ readonly StreamWriter LoggingStream = EnableConnectionLogging ?
+ new StreamWriter (string.Format ("/tmp/sdb_conn_log_{0}", ConnectionId++), false) : null;
+
+ /*
+ * Th version of the wire-protocol implemented by the library. The library
+ * and the debuggee can communicate if they implement the same major version.
+ * If they implement a different minor version, they can communicate, but some
+ * features might not be available. This allows older clients to communicate
+ * with newer runtimes, and vice versa.
+ */
+ internal const int MAJOR_VERSION = 2;
+ internal const int MINOR_VERSION = 26;
+
+ enum WPSuspendPolicy {
+ NONE = 0,
+ EVENT_THREAD = 1,
+ ALL = 2
+ }
+
+ enum CommandSet {
+ VM = 1,
+ OBJECT_REF = 9,
+ STRING_REF = 10,
+ THREAD = 11,
+ ARRAY_REF = 13,
+ EVENT_REQUEST = 15,
+ STACK_FRAME = 16,
+ APPDOMAIN = 20,
+ ASSEMBLY = 21,
+ METHOD = 22,
+ TYPE = 23,
+ MODULE = 24,
+ EVENT = 64
+ }
+
+ enum EventKind {
+ VM_START = 0,
+ VM_DEATH = 1,
+ THREAD_START = 2,
+ THREAD_DEATH = 3,
+ APPDOMAIN_CREATE = 4, // Not in JDI
+ APPDOMAIN_UNLOAD = 5, // Not in JDI
+ METHOD_ENTRY = 6,
+ METHOD_EXIT = 7,
+ ASSEMBLY_LOAD = 8,
+ ASSEMBLY_UNLOAD = 9,
+ BREAKPOINT = 10,
+ STEP = 11,
+ TYPE_LOAD = 12,
+ EXCEPTION = 13,
+ KEEPALIVE = 14,
+ USER_BREAK = 15,
+ USER_LOG = 16
+ }
+
+ enum ModifierKind {
+ COUNT = 1,
+ THREAD_ONLY = 3,
+ LOCATION_ONLY = 7,
+ EXCEPTION_ONLY = 8,
+ STEP = 10,
+ ASSEMBLY_ONLY = 11,
+ SOURCE_FILE_ONLY = 12,
+ TYPE_NAME_ONLY = 13
+ }
+
+ enum CmdVM {
+ VERSION = 1,
+ ALL_THREADS = 2,
+ SUSPEND = 3,
+ RESUME = 4,
+ EXIT = 5,
+ DISPOSE = 6,
+ INVOKE_METHOD = 7,
+ SET_PROTOCOL_VERSION = 8,
+ ABORT_INVOKE = 9,
+ SET_KEEPALIVE = 10,
+ GET_TYPES_FOR_SOURCE_FILE = 11,
+ GET_TYPES = 12,
+ INVOKE_METHODS = 13
+ }
+
+ enum CmdEvent {
+ COMPOSITE = 100
+ }
+
+ enum CmdThread {
+ GET_FRAME_INFO = 1,
+ GET_NAME = 2,
+ GET_STATE = 3,
+ GET_INFO = 4,
+ /* FIXME: Merge into GET_INFO when the major protocol version is increased */
+ GET_ID = 5,
+ /* Ditto */
+ GET_TID = 6
+ }
+
+ enum CmdEventRequest {
+ SET = 1,
+ CLEAR = 2,
+ CLEAR_ALL_BREAKPOINTS = 3
+ }
+
+ enum CmdAppDomain {
+ GET_ROOT_DOMAIN = 1,
+ GET_FRIENDLY_NAME = 2,
+ GET_ASSEMBLIES = 3,
+ GET_ENTRY_ASSEMBLY = 4,
+ CREATE_STRING = 5,
+ GET_CORLIB = 6,
+ CREATE_BOXED_VALUE = 7
+ }
+
+ enum CmdAssembly {
+ GET_LOCATION = 1,
+ GET_ENTRY_POINT = 2,
+ GET_MANIFEST_MODULE = 3,
+ GET_OBJECT = 4,
+ GET_TYPE = 5,
+ GET_NAME = 6
+ }
+
+ enum CmdModule {
+ GET_INFO = 1,
+ }
+
+ enum CmdMethod {
+ GET_NAME = 1,
+ GET_DECLARING_TYPE = 2,
+ GET_DEBUG_INFO = 3,
+ GET_PARAM_INFO = 4,
+ GET_LOCALS_INFO = 5,
+ GET_INFO = 6,
+ GET_BODY = 7,
+ RESOLVE_TOKEN = 8,
+ GET_CATTRS = 9,
+ MAKE_GENERIC_METHOD = 10
+ }
+
+ enum CmdType {
+ GET_INFO = 1,
+ GET_METHODS = 2,
+ GET_FIELDS = 3,
+ GET_VALUES = 4,
+ GET_OBJECT = 5,
+ GET_SOURCE_FILES = 6,
+ SET_VALUES = 7,
+ IS_ASSIGNABLE_FROM = 8,
+ GET_PROPERTIES = 9,
+ GET_CATTRS = 10,
+ GET_FIELD_CATTRS = 11,
+ GET_PROPERTY_CATTRS = 12,
+ /* FIXME: Merge into GET_SOURCE_FILES when the major protocol version is increased */
+ GET_SOURCE_FILES_2 = 13,
+ /* FIXME: Merge into GET_VALUES when the major protocol version is increased */
+ GET_VALUES_2 = 14,
+ CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15,
+ GET_INTERFACES = 16,
+ GET_INTERFACE_MAP = 17,
+ IS_INITIALIZED = 18
+ }
+
+ [Flags]
+ enum BindingFlagsExtensions {
+ BINDING_FLAGS_IGNORE_CASE = 0x70000000,
+ }
+
+ enum CmdStackFrame {
+ GET_VALUES = 1,
+ GET_THIS = 2,
+ SET_VALUES = 3
+ }
+
+ enum CmdArrayRef {
+ GET_LENGTH = 1,
+ GET_VALUES = 2,
+ SET_VALUES = 3
+ }
+
+ enum CmdStringRef {
+ GET_VALUE = 1,
+ GET_LENGTH = 2,
+ GET_CHARS = 3
+ }
+
+ enum CmdObjectRef {
+ GET_TYPE = 1,
+ GET_VALUES = 2,
+ IS_COLLECTED = 3,
+ GET_ADDRESS = 4,
+ GET_DOMAIN = 5,
+ SET_VALUES = 6,
+ GET_INFO = 7,
+ }
+
+ class Header {
+ public int id;
+ public int command_set;
+ public int command;
+ public int flags;
+ }
+
+ internal static int GetPacketLength (byte[] header) {
+ int offset = 0;
+ return decode_int (header, ref offset);
+ }
+
+ internal static bool IsReplyPacket (byte[] packet) {
+ int offset = 8;
+ return decode_byte (packet, ref offset) == 0x80;
+ }
+
+ internal static int GetPacketId (byte[] packet) {
+ int offset = 4;
+ return decode_int (packet, ref offset);
+ }
+
+ static int decode_byte (byte[] packet, ref int offset) {
+ return packet [offset++];
+ }
+
+ static int decode_short (byte[] packet, ref int offset) {
+ int res = ((int)packet [offset] << 8) | (int)packet [offset + 1];
+ offset += 2;
+ return res;
+ }
+
+ static int decode_int (byte[] packet, ref int offset) {
+ int res = ((int)packet [offset] << 24) | ((int)packet [offset + 1] << 16) | ((int)packet [offset + 2] << 8) | (int)packet [offset + 3];
+ offset += 4;
+ return res;
+ }
+
+ static long decode_id (byte[] packet, ref int offset) {
+ return decode_int (packet, ref offset);
+ }
+
+ static long decode_long (byte[] packet, ref int offset) {
+ uint high = (uint)decode_int (packet, ref offset);
+ uint low = (uint)decode_int (packet, ref offset);
+
+ return (long)(((ulong)high << 32) | (ulong)low);
+ }
+
+ internal static SuspendPolicy decode_suspend_policy (int suspend_policy) {
+ switch ((WPSuspendPolicy)suspend_policy) {
+ case WPSuspendPolicy.NONE:
+ return SuspendPolicy.None;
+ case WPSuspendPolicy.EVENT_THREAD:
+ return SuspendPolicy.EventThread;
+ case WPSuspendPolicy.ALL:
+ return SuspendPolicy.All;
+ default:
+ throw new NotImplementedException ();
+ }
+ }
+
+ static Header decode_command_header (byte[] packet) {
+ int offset = 0;
+ Header res = new Header ();
+
+ decode_int (packet, ref offset);
+ res.id = decode_int (packet, ref offset);
+ res.flags = decode_byte (packet, ref offset);
+ res.command_set = decode_byte (packet, ref offset);
+ res.command = decode_byte (packet, ref offset);
+
+ return res;
+ }
+
+ static void encode_byte (byte[] buf, int b, ref int offset) {
+ buf [offset] = (byte)b;
+ offset ++;
+ }
+
+ static void encode_int (byte[] buf, int i, ref int offset) {
+ buf [offset] = (byte)((i >> 24) & 0xff);
+ buf [offset + 1] = (byte)((i >> 16) & 0xff);
+ buf [offset + 2] = (byte)((i >> 8) & 0xff);
+ buf [offset + 3] = (byte)((i >> 0) & 0xff);
+ offset += 4;
+ }
+
+ static void encode_id (byte[] buf, long id, ref int offset) {
+ encode_int (buf, (int)id, ref offset);
+ }
+
+ static void encode_long (byte[] buf, long l, ref int offset) {
+ encode_int (buf, (int)((l >> 32) & 0xffffffff), ref offset);
+ encode_int (buf, (int)(l & 0xffffffff), ref offset);
+ }
+
+ internal static byte[] EncodePacket (int id, int commandSet, int command, byte[] data, int dataLen) {
+ byte[] buf = new byte [dataLen + 11];
+ int offset = 0;
+
+ encode_int (buf, buf.Length, ref offset);
+ encode_int (buf, id, ref offset);
+ encode_byte (buf, 0, ref offset);
+ encode_byte (buf, commandSet, ref offset);
+ encode_byte (buf, command, ref offset);
+
+ for (int i = 0; i < dataLen; ++i)
+ buf [offset + i] = data [i];
+
+ return buf;
+ }
+
+ class PacketReader {
+ byte[] packet;
+ int offset;
+
+ public PacketReader (byte[] packet) {
+ this.packet = packet;
+
+ // For event packets
+ Header header = decode_command_header (packet);
+ CommandSet = (CommandSet)header.command_set;
+ Command = header.command;
+
+ // For reply packets
+ offset = 0;
+ ReadInt (); // length
+ ReadInt (); // id
+ ReadByte (); // flags
+ ErrorCode = ReadShort ();
+ }
+
+ public CommandSet CommandSet {
+ get; set;
+ }
+
+ public int Command {
+ get; set;
+ }
+
+ public int ErrorCode {
+ get; set;
+ }
+
+ public int Offset {
+ get {
+ return offset;
+ }
+ }
+
+ public int ReadByte () {
+ return decode_byte (packet, ref offset);
+ }
+
+ public int ReadShort () {
+ return decode_short (packet, ref offset);
+ }
+
+ public int ReadInt () {
+ return decode_int (packet, ref offset);
+ }
+
+ public long ReadId () {
+ return decode_id (packet, ref offset);
+ }
+
+ public long ReadLong () {
+ return decode_long (packet, ref offset);
+ }
+
+ public float ReadFloat () {
+ float f = DataConverter.FloatFromBE (packet, offset);
+ offset += 4;
+ return f;
+ }
+
+ public double ReadDouble () {
+ double d = DataConverter.DoubleFromBE (packet, offset);
+ offset += 8;
+ return d;
+ }
+
+ public string ReadString () {
+ int len = decode_int (packet, ref offset);
+ string res = new String (Encoding.UTF8.GetChars (packet, offset, len));
+ offset += len;
+ return res;
+ }
+
+ public ValueImpl ReadValue () {
+ ElementType etype = (ElementType)ReadByte ();
+
+ switch (etype) {
+ case ElementType.Void:
+ return new ValueImpl { Type = etype };
+ case ElementType.I1:
+ return new ValueImpl { Type = etype, Value = (sbyte)ReadInt () };
+ case ElementType.U1:
+ return new ValueImpl { Type = etype, Value = (byte)ReadInt () };
+ case ElementType.Boolean:
+ return new ValueImpl { Type = etype, Value = ReadInt () != 0 };
+ case ElementType.I2:
+ return new ValueImpl { Type = etype, Value = (short)ReadInt () };
+ case ElementType.U2:
+ return new ValueImpl { Type = etype, Value = (ushort)ReadInt () };
+ case ElementType.Char:
+ return new ValueImpl { Type = etype, Value = (char)ReadInt () };
+ case ElementType.I4:
+ return new ValueImpl { Type = etype, Value = ReadInt () };
+ case ElementType.U4:
+ return new ValueImpl { Type = etype, Value = (uint)ReadInt () };
+ case ElementType.I8:
+ return new ValueImpl { Type = etype, Value = ReadLong () };
+ case ElementType.U8:
+ return new ValueImpl { Type = etype, Value = (ulong)ReadLong () };
+ case ElementType.R4:
+ return new ValueImpl { Type = etype, Value = ReadFloat () };
+ case ElementType.R8:
+ return new ValueImpl { Type = etype, Value = ReadDouble () };
+ case ElementType.I:
+ case ElementType.U:
+ case ElementType.Ptr:
+ // FIXME: The client and the debuggee might have different word sizes
+ return new ValueImpl { Type = etype, Value = ReadLong () };
+ case ElementType.String:
+ case ElementType.SzArray:
+ case ElementType.Class:
+ case ElementType.Array:
+ case ElementType.Object:
+ long objid = ReadId ();
+ return new ValueImpl () { Type = etype, Objid = objid };
+ case ElementType.ValueType:
+ bool is_enum = ReadByte () == 1;
+ long klass = ReadId ();
+ long nfields = ReadInt ();
+ ValueImpl[] fields = new ValueImpl [nfields];
+ for (int i = 0; i < nfields; ++i)
+ fields [i] = ReadValue ();
+ return new ValueImpl () { Type = etype, Klass = klass, Fields = fields, IsEnum = is_enum };
+ case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
+ return new ValueImpl { Type = etype };
+ case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE:
+ return new ValueImpl () { Type = etype, Id = ReadId () };
+ default:
+ throw new NotImplementedException ("Unable to handle type " + etype);
+ }
+ }
+
+ public long[] ReadIds (int n) {
+ long[] res = new long [n];
+ for (int i = 0; i < n; ++i)
+ res [i] = ReadId ();
+ return res;
+ }
+ }
+
+ class PacketWriter {
+
+ byte[] data;
+ int offset;
+
+ public PacketWriter () {
+ data = new byte [1024];
+ offset = 0;
+ }
+
+ void MakeRoom (int size) {
+ if (offset + size >= data.Length) {
+ int new_len = data.Length * 2;
+ while (new_len < offset + size) {
+ new_len *= 2;
+ }
+ byte[] new_data = new byte [new_len];
+ Array.Copy (data, new_data, data.Length);
+ data = new_data;
+ }
+ }
+
+ public PacketWriter WriteByte (byte val) {
+ MakeRoom (1);
+ encode_byte (data, val, ref offset);
+ return this;
+ }
+
+ public PacketWriter WriteInt (int val) {
+ MakeRoom (4);
+ encode_int (data, val, ref offset);
+ return this;
+ }
+
+ public PacketWriter WriteId (long id) {
+ MakeRoom (8);
+ encode_id (data, id, ref offset);
+ return this;
+ }
+
+ public PacketWriter WriteLong (long val) {
+ MakeRoom (8);
+ encode_long (data, val, ref offset);
+ return this;
+ }
+
+ public PacketWriter WriteFloat (float f) {
+ MakeRoom (8);
+ byte[] b = DataConverter.GetBytesBE (f);
+ for (int i = 0; i < 4; ++i)
+ data [offset + i] = b [i];
+ offset += 4;
+ return this;
+ }
+
+ public PacketWriter WriteDouble (double d) {
+ MakeRoom (8);
+ byte[] b = DataConverter.GetBytesBE (d);
+ for (int i = 0; i < 8; ++i)
+ data [offset + i] = b [i];
+ offset += 8;
+ return this;
+ }
+
+ public PacketWriter WriteInts (int[] ids) {
+ for (int i = 0; i < ids.Length; ++i)
+ WriteInt (ids [i]);
+ return this;
+ }
+
+ public PacketWriter WriteIds (long[] ids) {
+ for (int i = 0; i < ids.Length; ++i)
+ WriteId (ids [i]);
+ return this;
+ }
+
+ public PacketWriter WriteString (string s) {
+ if (s == null)
+ return WriteInt (-1);
+
+ byte[] b = Encoding.UTF8.GetBytes (s);
+ MakeRoom (4);
+ encode_int (data, b.Length, ref offset);
+ MakeRoom (b.Length);
+ Buffer.BlockCopy (b, 0, data, offset, b.Length);
+ offset += b.Length;
+ return this;
+ }
+
+ public PacketWriter WriteBool (bool val) {
+ WriteByte (val ? (byte)1 : (byte)0);
+ return this;
+ }
+
+ public PacketWriter WriteValue (ValueImpl v) {
+ ElementType t;
+
+ if (v.Value != null)
+ t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ()));
+ else
+ t = v.Type;
+ WriteByte ((byte)t);
+ switch (t) {
+ case ElementType.Boolean:
+ WriteInt ((bool)v.Value ? 1 : 0);
+ break;
+ case ElementType.Char:
+ WriteInt ((int)(char)v.Value);
+ break;
+ case ElementType.I1:
+ WriteInt ((int)(sbyte)v.Value);
+ break;
+ case ElementType.U1:
+ WriteInt ((int)(byte)v.Value);
+ break;
+ case ElementType.I2:
+ WriteInt ((int)(short)v.Value);
+ break;
+ case ElementType.U2:
+ WriteInt ((int)(ushort)v.Value);
+ break;
+ case ElementType.I4:
+ WriteInt ((int)(int)v.Value);
+ break;
+ case ElementType.U4:
+ WriteInt ((int)(uint)v.Value);
+ break;
+ case ElementType.I8:
+ WriteLong ((long)(long)v.Value);
+ break;
+ case ElementType.U8:
+ WriteLong ((long)(ulong)v.Value);
+ break;
+ case ElementType.R4:
+ WriteFloat ((float)v.Value);
+ break;
+ case ElementType.R8:
+ WriteDouble ((double)v.Value);
+ break;
+ case ElementType.String:
+ case ElementType.SzArray:
+ case ElementType.Class:
+ case ElementType.Array:
+ case ElementType.Object:
+ WriteId (v.Objid);
+ break;
+ case ElementType.ValueType:
+ // FIXME:
+ if (v.IsEnum)
+ throw new NotImplementedException ();
+ WriteByte (0);
+ WriteId (v.Klass);
+ WriteInt (v.Fields.Length);
+ for (int i = 0; i < v.Fields.Length; ++i)
+ WriteValue (v.Fields [i]);
+ break;
+ case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
+ break;
+ default:
+ throw new NotImplementedException ();
+ }
+
+ return this;
+ }
+
+ public PacketWriter WriteValues (ValueImpl[] values) {
+ for (int i = 0; i < values.Length; ++i)
+ WriteValue (values [i]);
+ return this;
+ }
+
+ public byte[] Data {
+ get {
+ return data;
+ }
+ }
+
+ public int Offset {
+ get {
+ return offset;
+ }
+ }
+ }
+
+ delegate void ReplyCallback (int packet_id, byte[] packet);
+
+ bool closed;
+ Thread receiver_thread;
+ Dictionary<int, byte[]> reply_packets;
+ Dictionary<int, ReplyCallback> reply_cbs;
+ Dictionary<int, int> reply_cb_counts;
+ object reply_packets_monitor;
+
+ internal event EventHandler<ErrorHandlerEventArgs> ErrorHandler;
+
+ protected Connection () {
+ closed = false;
+ reply_packets = new Dictionary<int, byte[]> ();
+ reply_cbs = new Dictionary<int, ReplyCallback> ();
+ reply_cb_counts = new Dictionary<int, int> ();
+ reply_packets_monitor = new Object ();
+ }
+
+ protected abstract int TransportReceive (byte[] buf, int buf_offset, int len);
+ protected abstract int TransportSend (byte[] buf, int buf_offset, int len);
+ protected abstract void TransportSetTimeouts (int send_timeout, int receive_timeout);
+ protected abstract void TransportClose ();
+
+ internal VersionInfo Version;
+
+ int Receive (byte[] buf, int buf_offset, int len) {
+ int offset = 0;
+
+ while (offset < len) {
+ int n = TransportReceive (buf, buf_offset + offset, len - offset);
+
+ if (n == 0)
+ return offset;
+ offset += n;
+ }
+
+ return offset;
+ }
+
+ // Do the wire protocol handshake
+ internal void Connect () {
+ byte[] buf = new byte [HANDSHAKE_STRING.Length];
+ char[] cbuf = new char [buf.Length];
+
+ // FIXME: Add a timeout
+ int n = Receive (buf, 0, buf.Length);
+ if (n == 0)
+ throw new IOException ("DWP Handshake failed.");
+ for (int i = 0; i < buf.Length; ++i)
+ cbuf [i] = (char)buf [i];
+
+ if (new String (cbuf) != HANDSHAKE_STRING)
+ throw new IOException ("DWP Handshake failed.");
+
+ TransportSend (buf, 0, buf.Length);
+
+ receiver_thread = new Thread (new ThreadStart (receiver_thread_main));
+ receiver_thread.Name = "SDB Receiver";
+ receiver_thread.IsBackground = true;
+ receiver_thread.Start ();
+
+ Version = VM_GetVersion ();
+
+ //
+ // Tell the debuggee our protocol version, so newer debuggees can work
+ // with older clients
+ //
+
+ //
+ // Older debuggees might not support this request
+ EventHandler<ErrorHandlerEventArgs> OrigErrorHandler = ErrorHandler;
+ ErrorHandler = null;
+ ErrorHandler += delegate (object sender, ErrorHandlerEventArgs args) {
+ throw new NotSupportedException ();
+ };
+ try {
+ VM_SetProtocolVersion (MAJOR_VERSION, MINOR_VERSION);
+ } catch (NotSupportedException) {
+ }
+ ErrorHandler = OrigErrorHandler;
+ }
+
+ internal byte[] ReadPacket () {
+ // FIXME: Throw ClosedConnectionException () if the connection is closed
+ // FIXME: Throw ClosedConnectionException () if another thread closes the connection
+ // FIXME: Locking
+ byte[] header = new byte [HEADER_LENGTH];
+
+ int len = Receive (header, 0, header.Length);
+ if (len == 0)
+ return new byte [0];
+ if (len != HEADER_LENGTH) {
+ // FIXME:
+ throw new IOException ("Packet of length " + len + " is read.");
+ }
+
+ int packetLength = GetPacketLength (header);
+ if (packetLength < 11)
+ throw new IOException ("Invalid packet length.");
+
+ if (packetLength == 11) {
+ return header;
+ } else {
+ byte[] buf = new byte [packetLength];
+ for (int i = 0; i < header.Length; ++i)
+ buf [i] = header [i];
+ len = Receive (buf, header.Length, packetLength - header.Length);
+ if (len != packetLength - header.Length)
+ throw new IOException ();
+ return buf;
+ }
+ }
+
+ internal void WritePacket (byte[] packet) {
+ // FIXME: Throw ClosedConnectionException () if the connection is closed
+ // FIXME: Throw ClosedConnectionException () if another thread closes the connection
+ // FIXME: Locking
+ TransportSend (packet, 0, packet.Length);
+ }
+
+ internal void Close () {
+ closed = true;
+ }
+
+ internal bool IsClosed {
+ get {
+ return closed;
+ }
+ }
+
+ bool disconnected;
+
+ void receiver_thread_main () {
+ while (!closed) {
+ try {
+ bool res = ReceivePacket ();
+ if (!res)
+ break;
+ } catch (Exception ex) {
+ if (!closed) {
+ Console.WriteLine (ex);
+ }
+ break;
+ }
+ }
+
+ lock (reply_packets_monitor) {
+ disconnected = true;
+ Monitor.PulseAll (reply_packets_monitor);
+ TransportClose ();
+ }
+ EventHandler.VMDisconnect (0, 0, null);
+ }
+
+ bool ReceivePacket () {
+ byte[] packet = ReadPacket ();
+
+ if (packet.Length == 0) {
+ return false;
+ }
+
+ if (IsReplyPacket (packet)) {
+ int id = GetPacketId (packet);
+ ReplyCallback cb = null;
+ lock (reply_packets_monitor) {
+ reply_cbs.TryGetValue (id, out cb);
+ if (cb == null) {
+ reply_packets [id] = packet;
+ Monitor.PulseAll (reply_packets_monitor);
+ } else {
+ int c = reply_cb_counts [id];
+ c --;
+ if (c == 0) {
+ reply_cbs.Remove (id);
+ reply_cb_counts.Remove (id);
+ }
+ }
+ }
+
+ if (cb != null)
+ cb.Invoke (id, packet);
+ } else {
+ PacketReader r = new PacketReader (packet);
+
+ if (r.CommandSet == CommandSet.EVENT && r.Command == (int)CmdEvent.COMPOSITE) {
+ int spolicy = r.ReadByte ();
+ int nevents = r.ReadInt ();
+
+ SuspendPolicy suspend_policy = decode_suspend_policy (spolicy);
+
+ EventInfo[] events = new EventInfo [nevents];
+
+ for (int i = 0; i < nevents; ++i) {
+ EventKind kind = (EventKind)r.ReadByte ();
+ int req_id = r.ReadInt ();
+
+ EventType etype = (EventType)kind;
+
+ if (kind == EventKind.VM_START) {
+ long thread_id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id };
+ //EventHandler.VMStart (req_id, thread_id, null);
+ } else if (kind == EventKind.VM_DEATH) {
+ //EventHandler.VMDeath (req_id, 0, null);
+ events [i] = new EventInfo (etype, req_id) { };
+ } else if (kind == EventKind.THREAD_START) {
+ long thread_id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = thread_id };
+ //EventHandler.ThreadStart (req_id, thread_id, thread_id);
+ } else if (kind == EventKind.THREAD_DEATH) {
+ long thread_id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = thread_id };
+ //EventHandler.ThreadDeath (req_id, thread_id, thread_id);
+ } else if (kind == EventKind.ASSEMBLY_LOAD) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.AssemblyLoad (req_id, thread_id, id);
+ } else if (kind == EventKind.ASSEMBLY_UNLOAD) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.AssemblyUnload (req_id, thread_id, id);
+ } else if (kind == EventKind.TYPE_LOAD) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.TypeLoad (req_id, thread_id, id);
+ } else if (kind == EventKind.METHOD_ENTRY) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.MethodEntry (req_id, thread_id, id);
+ } else if (kind == EventKind.METHOD_EXIT) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.MethodExit (req_id, thread_id, id);
+ } else if (kind == EventKind.BREAKPOINT) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ long loc = r.ReadLong ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
+ //EventHandler.Breakpoint (req_id, thread_id, id, loc);
+ } else if (kind == EventKind.STEP) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ long loc = r.ReadLong ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
+ //EventHandler.Step (req_id, thread_id, id, loc);
+ } else if (kind == EventKind.EXCEPTION) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ long loc = 0; // FIXME
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
+ //EventHandler.Exception (req_id, thread_id, id, loc);
+ } else if (kind == EventKind.APPDOMAIN_CREATE) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.AppDomainCreate (req_id, thread_id, id);
+ } else if (kind == EventKind.APPDOMAIN_UNLOAD) {
+ long thread_id = r.ReadId ();
+ long id = r.ReadId ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
+ //EventHandler.AppDomainUnload (req_id, thread_id, id);
+ } else if (kind == EventKind.USER_BREAK) {
+ long thread_id = r.ReadId ();
+ long id = 0;
+ long loc = 0;
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
+ //EventHandler.Exception (req_id, thread_id, id, loc);
+ } else if (kind == EventKind.USER_LOG) {
+ long thread_id = r.ReadId ();
+ int level = r.ReadInt ();
+ string category = r.ReadString ();
+ string message = r.ReadString ();
+ events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Level = level, Category = category, Message = message };
+ //EventHandler.Exception (req_id, thread_id, id, loc);
+ } else if (kind == EventKind.KEEPALIVE) {
+ events [i] = new EventInfo (etype, req_id) { };
+ } else {
+ throw new NotImplementedException ("Unknown event kind: " + kind);
+ }
+ }
+
+ EventHandler.Events (suspend_policy, events);
+ }
+ }
+
+ return true;
+ }
+
+ internal IEventHandler EventHandler {
+ get; set;
+ }
+
+ static String CommandString (CommandSet command_set, int command)
+ {
+ string cmd;
+ switch (command_set) {
+ case CommandSet.VM:
+ cmd = ((CmdVM)command).ToString ();
+ break;
+ case CommandSet.OBJECT_REF:
+ cmd = ((CmdObjectRef)command).ToString ();
+ break;
+ case CommandSet.STRING_REF:
+ cmd = ((CmdStringRef)command).ToString ();
+ break;
+ case CommandSet.THREAD:
+ cmd = ((CmdThread)command).ToString ();
+ break;
+ case CommandSet.ARRAY_REF:
+ cmd = ((CmdArrayRef)command).ToString ();
+ break;
+ case CommandSet.EVENT_REQUEST:
+ cmd = ((CmdEventRequest)command).ToString ();
+ break;
+ case CommandSet.STACK_FRAME:
+ cmd = ((CmdStackFrame)command).ToString ();
+ break;
+ case CommandSet.APPDOMAIN:
+ cmd = ((CmdAppDomain)command).ToString ();
+ break;
+ case CommandSet.ASSEMBLY:
+ cmd = ((CmdAssembly)command).ToString ();
+ break;
+ case CommandSet.METHOD:
+ cmd = ((CmdMethod)command).ToString ();
+ break;
+ case CommandSet.TYPE:
+ cmd = ((CmdType)command).ToString ();
+ break;
+ case CommandSet.MODULE:
+ cmd = ((CmdModule)command).ToString ();
+ break;
+ case CommandSet.EVENT:
+ cmd = ((CmdEvent)command).ToString ();
+ break;
+ default:
+ cmd = command.ToString ();
+ break;
+ }
+ return string.Format ("[{0} {1}]", command_set, cmd);
+ }
+
+ long total_protocol_ticks;
+
+ void LogPacket (int packet_id, byte[] encoded_packet, byte[] reply_packet, CommandSet command_set, int command, Stopwatch watch) {
+ watch.Stop ();
+ total_protocol_ticks += watch.ElapsedTicks;
+ var ts = TimeSpan.FromTicks (total_protocol_ticks);
+ string msg = string.Format ("Packet: {0} sent: {1} received: {2} ms: {3} total ms: {4} {5}",
+ packet_id, encoded_packet.Length, reply_packet.Length, watch.ElapsedMilliseconds,
+ (ts.Seconds * 1000) + ts.Milliseconds,
+ CommandString (command_set, command));
+
+ LoggingStream.WriteLine (msg);
+ LoggingStream.Flush ();
+ }
+
+ /* Send a request and call cb when a result is received */
+ int Send (CommandSet command_set, int command, PacketWriter packet, Action<PacketReader> cb, int count) {
+ int id = IdGenerator;
+
+ Stopwatch watch = null;
+ if (EnableConnectionLogging)
+ watch = Stopwatch.StartNew ();
+
+ byte[] encoded_packet;
+ if (packet == null)
+ encoded_packet = EncodePacket (id, (int)command_set, command, null, 0);
+ else
+ encoded_packet = EncodePacket (id, (int)command_set, command, packet.Data, packet.Offset);
+
+ lock (reply_packets_monitor) {
+ reply_cbs [id] = delegate (int packet_id, byte[] p) {
+ if (EnableConnectionLogging)
+ LogPacket (packet_id, encoded_packet, p, command_set, command, watch);
+ /* Run the callback on a tp thread to avoid blocking the receive thread */
+ PacketReader r = new PacketReader (p);
+ cb.BeginInvoke (r, null, null);
+ };
+ reply_cb_counts [id] = count;
+ }
+
+ WritePacket (encoded_packet);
+
+ return id;
+ }
+
+ PacketReader SendReceive (CommandSet command_set, int command, PacketWriter packet) {
+ int id = IdGenerator;
+ Stopwatch watch = null;
+
+ if (disconnected)
+ throw new VMDisconnectedException ();
+
+ if (EnableConnectionLogging)
+ watch = Stopwatch.StartNew ();
+
+ byte[] encoded_packet;
+
+ if (packet == null)
+ encoded_packet = EncodePacket (id, (int)command_set, command, null, 0);
+ else
+ encoded_packet = EncodePacket (id, (int)command_set, command, packet.Data, packet.Offset);
+
+ WritePacket (encoded_packet);
+
+ int packetId = id;
+
+ /* Wait for the reply packet */
+ while (true) {
+ lock (reply_packets_monitor) {
+ if (reply_packets.ContainsKey (packetId)) {
+ byte[] reply = reply_packets [packetId];
+ reply_packets.Remove (packetId);
+ PacketReader r = new PacketReader (reply);
+
+ if (EnableConnectionLogging)
+ LogPacket (packetId, encoded_packet, reply, command_set, command, watch);
+ if (r.ErrorCode != 0) {
+ if (ErrorHandler != null)
+ ErrorHandler (this, new ErrorHandlerEventArgs () { ErrorCode = (ErrorCode)r.ErrorCode });
+ throw new NotImplementedException ("No error handler set.");
+ } else {
+ return r;
+ }
+ } else {
+ if (disconnected)
+ throw new VMDisconnectedException ();
+ Monitor.Wait (reply_packets_monitor);
+ }
+ }
+ }
+ }
+
+ PacketReader SendReceive (CommandSet command_set, int command) {
+ return SendReceive (command_set, command, null);
+ }
+
+ int packet_id_generator;
+
+ int IdGenerator {
+ get {
+ return Interlocked.Increment (ref packet_id_generator);
+ }
+ }
+
+ CattrInfo[] ReadCattrs (PacketReader r) {
+ CattrInfo[] res = new CattrInfo [r.ReadInt ()];
+ for (int i = 0; i < res.Length; ++i) {
+ CattrInfo info = new CattrInfo ();
+ info.ctor_id = r.ReadId ();
+ info.ctor_args = new ValueImpl [r.ReadInt ()];
+ for (int j = 0; j < info.ctor_args.Length; ++j) {
+ info.ctor_args [j] = r.ReadValue ();
+ }
+ info.named_args = new CattrNamedArgInfo [r.ReadInt ()];
+ for (int j = 0; j < info.named_args.Length; ++j) {
+ CattrNamedArgInfo arg = new CattrNamedArgInfo ();
+ int arg_type = r.ReadByte ();
+ arg.is_property = arg_type == 0x54;
+ arg.id = r.ReadId ();
+ arg.value = r.ReadValue ();
+ info.named_args [j] = arg;
+ }
+ res [i] = info;
+ }
+ return res;
+ }
+
+ static ElementType TypeCodeToElementType (TypeCode c) {
+ switch (c) {
+ case TypeCode.Boolean:
+ return ElementType.Boolean;
+ case TypeCode.Char:
+ return ElementType.Char;
+ case TypeCode.SByte:
+ return ElementType.I1;
+ case TypeCode.Byte:
+ return ElementType.U1;
+ case TypeCode.Int16:
+ return ElementType.I2;
+ case TypeCode.UInt16:
+ return ElementType.U2;
+ case TypeCode.Int32:
+ return ElementType.I4;
+ case TypeCode.UInt32:
+ return ElementType.U4;
+ case TypeCode.Int64:
+ return ElementType.I8;
+ case TypeCode.UInt64:
+ return ElementType.U8;
+ case TypeCode.Single:
+ return ElementType.R4;
+ case TypeCode.Double:
+ return ElementType.R8;
+ default:
+ throw new NotImplementedException ();
+ }
+ }
+
+ /*
+ * Implementation of debugger commands
+ */
+
+ internal VersionInfo VM_GetVersion () {
+ var res = SendReceive (CommandSet.VM, (int)CmdVM.VERSION, null);
+ VersionInfo info = new VersionInfo ();
+ info.VMVersion = res.ReadString ();
+ info.MajorVersion = res.ReadInt ();
+ info.MinorVersion = res.ReadInt ();
+ return info;
+ }
+
+ internal void VM_SetProtocolVersion (int major, int minor) {
+ SendReceive (CommandSet.VM, (int)CmdVM.SET_PROTOCOL_VERSION, new PacketWriter ().WriteInt (major).WriteInt (minor));
+ }
+
+ internal long[] VM_GetThreads () {
+ var res = SendReceive (CommandSet.VM, (int)CmdVM.ALL_THREADS, null);
+ int len = res.ReadInt ();
+ long[] arr = new long [len];
+ for (int i = 0; i < len; ++i)
+ arr [i] = res.ReadId ();
+ return arr;
+ }
+
+ internal void VM_Suspend () {
+ SendReceive (CommandSet.VM, (int)CmdVM.SUSPEND);
+ }
+
+ internal void VM_Resume () {
+ SendReceive (CommandSet.VM, (int)CmdVM.RESUME);
+ }
+
+ internal void VM_Exit (int exitCode) {
+ SendReceive (CommandSet.VM, (int)CmdVM.EXIT, new PacketWriter ().WriteInt (exitCode));
+ }
+
+ internal void VM_Dispose () {
+ SendReceive (CommandSet.VM, (int)CmdVM.DISPOSE);
+ }
+
+ internal ValueImpl VM_InvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, out ValueImpl exc) {
+ exc = null;
+ PacketReader r = SendReceive (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments));
+ if (r.ReadByte () == 0) {
+ exc = r.ReadValue ();
+ return null;
+ } else {
+ return r.ReadValue ();
+ }
+ }
+
+ internal delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, ErrorCode error, object state);
+
+ internal int VM_BeginInvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, InvokeMethodCallback callback, object state) {
+ return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments), delegate (PacketReader r) {
+ ValueImpl v, exc;
+
+ if (r.ErrorCode != 0) {
+ callback (null, null, (ErrorCode)r.ErrorCode, state);
+ } else {
+ if (r.ReadByte () == 0) {
+ exc = r.ReadValue ();
+ v = null;
+ } else {
+ v = r.ReadValue ();
+ exc = null;
+ }
+
+ callback (v, exc, 0, state);
+ }
+ }, 1);
+ }
+
+ internal int VM_BeginInvokeMethods (long thread, long[] methods, ValueImpl this_arg, List<ValueImpl[]> arguments, InvokeFlags flags, InvokeMethodCallback callback, object state) {
+ // FIXME: Merge this with INVOKE_METHOD
+ var w = new PacketWriter ();
+ w.WriteId (thread);
+ w.WriteInt ((int)flags);
+ w.WriteInt (methods.Length);
+ for (int i = 0; i < methods.Length; ++i) {
+ w.WriteId (methods [i]);
+ w.WriteValue (this_arg);
+ w.WriteInt (arguments [i].Length);
+ w.WriteValues (arguments [i]);
+ }
+ return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHODS, w, delegate (PacketReader r) {
+ ValueImpl v, exc;
+
+ if (r.ErrorCode != 0) {
+ callback (null, null, (ErrorCode)r.ErrorCode, state);
+ } else {
+ if (r.ReadByte () == 0) {
+ exc = r.ReadValue ();
+ v = null;
+ } else {
+ v = r.ReadValue ();
+ exc = null;
+ }
+
+ callback (v, exc, 0, state);
+ }
+ }, methods.Length);
+ }
+
+ internal void VM_AbortInvoke (long thread, int id)
+ {
+ SendReceive (CommandSet.VM, (int)CmdVM.ABORT_INVOKE, new PacketWriter ().WriteId (thread).WriteInt (id));
+ }
+
+ internal void SetSocketTimeouts (int send_timeout, int receive_timeout, int keepalive_interval)
+ {
+ TransportSetTimeouts (send_timeout, receive_timeout);
+ SendReceive (CommandSet.VM, (int)CmdVM.SET_KEEPALIVE, new PacketWriter ().WriteId (keepalive_interval));
+ }
+
+ internal long[] VM_GetTypesForSourceFile (string fname, bool ignoreCase) {
+ var res = SendReceive (CommandSet.VM, (int)CmdVM.GET_TYPES_FOR_SOURCE_FILE, new PacketWriter ().WriteString (fname).WriteBool (ignoreCase));
+ int count = res.ReadInt ();
+ long[] types = new long [count];
+ for (int i = 0; i < count; ++i)
+ types [i] = res.ReadId ();
+ return types;
+ }
+
+ internal long[] VM_GetTypes (string name, bool ignoreCase) {
+ var res = SendReceive (CommandSet.VM, (int)CmdVM.GET_TYPES, new PacketWriter ().WriteString (name).WriteBool (ignoreCase));
+ int count = res.ReadInt ();
+ long[] types = new long [count];
+ for (int i = 0; i < count; ++i)
+ types [i] = res.ReadId ();
+ return types;
+ }
+
+ /*
+ * DOMAIN
+ */
+
+ internal long RootDomain {
+ get {
+ return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ROOT_DOMAIN, null).ReadId ();
+ }
+ }
+
+ internal string Domain_GetName (long id) {
+ return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_FRIENDLY_NAME, new PacketWriter ().WriteId (id)).ReadString ();
+ }
+
+ internal long[] Domain_GetAssemblies (long id) {
+ var res = SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ASSEMBLIES, new PacketWriter ().WriteId (id));
+ int count = res.ReadInt ();
+ long[] assemblies = new long [count];
+ for (int i = 0; i < count; ++i)
+ assemblies [i] = res.ReadId ();
+ return assemblies;
+ }
+
+ internal long Domain_GetEntryAssembly (long id) {
+ return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ENTRY_ASSEMBLY, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal long Domain_GetCorlib (long id) {
+ return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_CORLIB, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal long Domain_CreateString (long id, string s) {
+ return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_STRING, new PacketWriter ().WriteId (id).WriteString (s)).ReadId ();
+ }
+
+ internal long Domain_CreateBoxedValue (long id, long type_id, ValueImpl v) {
+ return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_BOXED_VALUE, new PacketWriter ().WriteId (id).WriteId (type_id).WriteValue (v)).ReadId ();
+ }
+
+ /*
+ * METHOD
+ */
+
+ internal string Method_GetName (long id) {
+ return SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
+ }
+
+ internal long Method_GetDeclaringType (long id) {
+ return SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_DECLARING_TYPE, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal DebugInfo Method_GetDebugInfo (long id) {
+ var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_DEBUG_INFO, new PacketWriter ().WriteId (id));
+
+ DebugInfo info = new DebugInfo ();
+ info.max_il_offset = res.ReadInt ();
+
+ SourceInfo[] sources = null;
+ if (Version.AtLeast (2, 13)) {
+ int n = res.ReadInt ();
+ sources = new SourceInfo [n];
+ for (int i = 0; i < n; ++i) {
+ sources [i].source_file = res.ReadString ();
+ if (Version.AtLeast (2, 14)) {
+ sources [i].hash = new byte [16];
+ for (int j = 0; j < 16; ++j)
+ sources [i].hash [j] = (byte)res.ReadByte ();
+ }
+ }
+ } else {
+ sources = new SourceInfo [1];
+ sources [0].source_file = res.ReadString ();
+ }
+
+ int n_il_offsets = res.ReadInt ();
+ info.il_offsets = new int [n_il_offsets];
+ info.line_numbers = new int [n_il_offsets];
+ info.source_files = new SourceInfo [n_il_offsets];
+ info.column_numbers = new int [n_il_offsets];
+ for (int i = 0; i < n_il_offsets; ++i) {
+ info.il_offsets [i] = res.ReadInt ();
+ info.line_numbers [i] = res.ReadInt ();
+ if (Version.AtLeast (2, 12)) {
+ int idx = res.ReadInt ();
+ info.source_files [i] = idx >= 0 ? sources [idx] : default (SourceInfo);
+ } else {
+ info.source_files [i] = sources [0];
+ }
+ if (Version.AtLeast (2, 19))
+ info.column_numbers [i] = res.ReadInt ();
+ else
+ info.column_numbers [i] = 0;
+ }
+
+ return info;
+ }
+
+ internal ParamInfo Method_GetParamInfo (long id) {
+ var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_PARAM_INFO, new PacketWriter ().WriteId (id));
+
+ ParamInfo info = new ParamInfo ();
+ info.call_conv = res.ReadInt ();
+ info.param_count = res.ReadInt ();
+ info.generic_param_count = res.ReadInt ();
+ info.ret_type = res.ReadId ();
+ info.param_types = new long [info.param_count];
+ for (int i = 0; i < info.param_count; ++i)
+ info.param_types [i] = res.ReadId ();
+ info.param_names = new string [info.param_count];
+ for (int i = 0; i < info.param_count; ++i)
+ info.param_names [i] = res.ReadString ();
+
+ return info;
+ }
+
+ internal LocalsInfo Method_GetLocalsInfo (long id) {
+ var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_LOCALS_INFO, new PacketWriter ().WriteId (id));
+
+ LocalsInfo info = new LocalsInfo ();
+ int nlocals = res.ReadInt ();
+ info.types = new long [nlocals];
+ for (int i = 0; i < nlocals; ++i)
+ info.types [i] = res.ReadId ();
+ info.names = new string [nlocals];
+ for (int i = 0; i < nlocals; ++i)
+ info.names [i] = res.ReadString ();
+ info.live_range_start = new int [nlocals];
+ info.live_range_end = new int [nlocals];
+ for (int i = 0; i < nlocals; ++i) {
+ info.live_range_start [i] = res.ReadInt ();
+ info.live_range_end [i] = res.ReadInt ();
+ }
+
+ return info;
+ }
+
+ internal MethodInfo Method_GetInfo (long id) {
+ var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_INFO, new PacketWriter ().WriteId (id));
+
+ MethodInfo info = new MethodInfo ();
+ info.attributes = res.ReadInt ();
+ info.iattributes = res.ReadInt ();
+ info.token = res.ReadInt ();
+ if (Version.AtLeast (2, 12)) {
+ int attrs = res.ReadByte ();
+ if ((attrs & (1 << 0)) != 0)
+ info.is_gmd = true;
+ if ((attrs & (1 << 1)) != 0)
+ info.is_generic_method = true;
+ info.gmd = res.ReadId ();
+ if (Version.AtLeast (2, 15)) {
+ if (info.is_generic_method) {
+ int n = res.ReadInt ();
+ info.type_args = res.ReadIds (n);
+ }
+ }
+ }
+ return info;
+ }
+
+ internal MethodBodyInfo Method_GetBody (long id) {
+ var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_BODY, new PacketWriter ().WriteId (id));
+
+ MethodBodyInfo info = new MethodBodyInfo ();
+ info.il = new byte [res.ReadInt ()];
+ for (int i = 0; i < info.il.Length; ++i)
+ info.il [i] = (byte)res.ReadByte ();
+
+ if (Version.AtLeast (2, 18)) {
+ info.clauses = new ExceptionClauseInfo [res.ReadInt ()];
+
+ for (int i = 0; i < info.clauses.Length; ++i) {
+ var clause = new ExceptionClauseInfo {
+ flags = (ExceptionClauseFlags) res.ReadInt (),
+ try_offset = res.ReadInt (),
+ try_length = res.ReadInt (),
+ handler_offset = res.ReadInt (),
+ handler_length = res.ReadInt (),
+ };
+
+ if (clause.flags == ExceptionClauseFlags.None)
+ clause.catch_type_id = res.ReadId ();
+ else if (clause.flags == ExceptionClauseFlags.Filter)
+ clause.filter_offset = res.ReadInt ();
+
+ info.clauses [i] = clause;
+ }
+ } else
+ info.clauses = new ExceptionClauseInfo [0];
+
+ return info;
+ }
+
+ internal ResolvedToken Method_ResolveToken (long id, int token) {
+ var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.RESOLVE_TOKEN, new PacketWriter ().WriteId (id).WriteInt (token));
+
+ TokenType type = (TokenType)res.ReadByte ();
+ switch (type) {
+ case TokenType.STRING:
+ return new ResolvedToken () { Type = type, Str = res.ReadString () };
+ case TokenType.TYPE:
+ case TokenType.METHOD:
+ case TokenType.FIELD:
+ return new ResolvedToken () { Type = type, Id = res.ReadId () };
+ case TokenType.UNKNOWN:
+ return new ResolvedToken () { Type = type };
+ default:
+ throw new NotImplementedException ();
+ }
+ }
+
+ internal CattrInfo[] Method_GetCustomAttributes (long id, long attr_type_id, bool inherit) {
+ PacketReader r = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_CATTRS, new PacketWriter ().WriteId (id).WriteId (attr_type_id));
+ return ReadCattrs (r);
+ }
+
+ internal long Method_MakeGenericMethod (long id, long[] args) {
+ PacketReader r = SendReceive (CommandSet.METHOD, (int)CmdMethod.MAKE_GENERIC_METHOD, new PacketWriter ().WriteId (id).WriteInt (args.Length).WriteIds (args));
+ return r.ReadId ();
+ }
+
+ /*
+ * THREAD
+ */
+
+ internal string Thread_GetName (long id) {
+ return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
+ }
+
+ internal FrameInfo[] Thread_GetFrameInfo (long id, int start_frame, int length) {
+ var res = SendReceive (CommandSet.THREAD, (int)CmdThread.GET_FRAME_INFO, new PacketWriter ().WriteId (id).WriteInt (start_frame).WriteInt (length));
+ int count = res.ReadInt ();
+
+ var frames = new FrameInfo [count];
+ for (int i = 0; i < count; ++i) {
+ var f = new FrameInfo ();
+ f.id = res.ReadInt ();
+ f.method = res.ReadId ();
+ f.il_offset = res.ReadInt ();
+ f.flags = (StackFrameFlags)res.ReadByte ();
+ frames [i] = f;
+ }
+
+ return frames;
+ }
+
+ internal int Thread_GetState (long id) {
+ return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_STATE, new PacketWriter ().WriteId (id)).ReadInt ();
+ }
+
+ internal ThreadInfo Thread_GetInfo (long id) {
+ PacketReader r = SendReceive (CommandSet.THREAD, (int)CmdThread.GET_INFO, new PacketWriter ().WriteId (id));
+
+ ThreadInfo res = new ThreadInfo () { is_thread_pool = r.ReadByte () > 0 ? true : false };
+
+ return res;
+ }
+
+ internal long Thread_GetId (long id) {
+ return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_ID, new PacketWriter ().WriteId (id)).ReadLong ();
+ }
+
+ internal long Thread_GetTID (long id) {
+ return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_TID, new PacketWriter ().WriteId (id)).ReadLong ();
+ }
+
+ /*
+ * MODULE
+ */
+
+ internal ModuleInfo Module_GetInfo (long id) {
+ PacketReader r = SendReceive (CommandSet.MODULE, (int)CmdModule.GET_INFO, new PacketWriter ().WriteId (id));
+ ModuleInfo info = new ModuleInfo { Name = r.ReadString (), ScopeName = r.ReadString (), FQName = r.ReadString (), Guid = r.ReadString (), Assembly = r.ReadId () };
+ return info;
+ }
+
+ /*
+ * ASSEMBLY
+ */
+
+ internal string Assembly_GetLocation (long id) {
+ return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_LOCATION, new PacketWriter ().WriteId (id)).ReadString ();
+ }
+
+ internal long Assembly_GetEntryPoint (long id) {
+ return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_ENTRY_POINT, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal long Assembly_GetManifestModule (long id) {
+ return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_MANIFEST_MODULE, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal long Assembly_GetObject (long id) {
+ return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_OBJECT, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal long Assembly_GetType (long id, string name, bool ignoreCase) {
+ return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_TYPE, new PacketWriter ().WriteId (id).WriteString (name).WriteBool (ignoreCase)).ReadId ();
+ }
+
+ internal string Assembly_GetName (long id) {
+ return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
+ }
+
+ /*
+ * TYPE
+ */
+
+ internal TypeInfo Type_GetInfo (long id) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INFO, new PacketWriter ().WriteId (id));
+ TypeInfo res = new TypeInfo ();
+
+ res.ns = r.ReadString ();
+ res.name = r.ReadString ();
+ res.full_name = r.ReadString ();
+ res.assembly = r.ReadId ();
+ res.module = r.ReadId ();
+ res.base_type = r.ReadId ();
+ res.element_type = r.ReadId ();
+ res.token = r.ReadInt ();
+ res.rank = r.ReadByte ();
+ res.attributes = r.ReadInt ();
+ int b = r.ReadByte ();
+ res.is_byref = (b & 1) != 0;
+ res.is_pointer = (b & 2) != 0;
+ res.is_primitive = (b & 4) != 0;
+ res.is_valuetype = (b & 8) != 0;
+ res.is_enum = (b & 16) != 0;
+ res.is_gtd = (b & 32) != 0;
+ res.is_generic_type = (b & 64) != 0;
+
+ int nested_len = r.ReadInt ();
+ res.nested = new long [nested_len];
+ for (int i = 0; i < nested_len; ++i)
+ res.nested [i] = r.ReadId ();
+
+ if (Version.AtLeast (2, 12))
+ res.gtd = r.ReadId ();
+ if (Version.AtLeast (2, 15) && res.is_generic_type) {
+ int n = r.ReadInt ();
+ res.type_args = r.ReadIds (n);
+ }
+
+ return res;
+ }
+
+ internal long[] Type_GetMethods (long id) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_METHODS, new PacketWriter ().WriteId (id));
+
+ int n = r.ReadInt ();
+ long[] res = new long [n];
+ for (int i = 0; i < n; ++i)
+ res [i] = r.ReadId ();
+ return res;
+ }
+
+ internal long[] Type_GetFields (long id, out string[] names, out long[] types, out int[] attrs) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_FIELDS, new PacketWriter ().WriteId (id));
+
+ int n = r.ReadInt ();
+ long[] res = new long [n];
+ names = new string [n];
+ types = new long [n];
+ attrs = new int [n];
+ for (int i = 0; i < n; ++i) {
+ res [i] = r.ReadId ();
+ names [i] = r.ReadString ();
+ types [i] = r.ReadId ();
+ attrs [i] = r.ReadInt ();
+ }
+ return res;
+ }
+
+ internal PropInfo[] Type_GetProperties (long id) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_PROPERTIES, new PacketWriter ().WriteId (id));
+
+ int n = r.ReadInt ();
+ PropInfo[] res = new PropInfo [n];
+ for (int i = 0; i < n; ++i) {
+ res [i] = new PropInfo ();
+ res [i].id = r.ReadId ();
+ res [i].name = r.ReadString ();
+ res [i].get_method = r.ReadId ();
+ res [i].set_method = r.ReadId ();
+ res [i].attrs = r.ReadInt ();
+ }
+
+ return res;
+ }
+
+ internal long Type_GetObject (long id) {
+ return SendReceive (CommandSet.TYPE, (int)CmdType.GET_OBJECT, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal ValueImpl[] Type_GetValues (long id, long[] fields, long thread_id) {
+ int len = fields.Length;
+ PacketReader r;
+ if (thread_id != 0)
+ r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUES_2, new PacketWriter ().WriteId (id).WriteId (thread_id).WriteInt (len).WriteIds (fields));
+ else
+ r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (len).WriteIds (fields));
+
+ ValueImpl[] res = new ValueImpl [len];
+ for (int i = 0; i < len; ++i)
+ res [i] = r.ReadValue ();
+ return res;
+ }
+
+ internal void Type_SetValues (long id, long[] fields, ValueImpl[] values) {
+ SendReceive (CommandSet.TYPE, (int)CmdType.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (fields.Length).WriteIds (fields).WriteValues (values));
+ }
+
+ internal string[] Type_GetSourceFiles (long id, bool return_full_paths) {
+ var r = SendReceive (CommandSet.TYPE, return_full_paths ? (int)CmdType.GET_SOURCE_FILES_2 : (int)CmdType.GET_SOURCE_FILES, new PacketWriter ().WriteId (id));
+ int len = r.ReadInt ();
+ string[] res = new string [len];
+ for (int i = 0; i < len; ++i)
+ res [i] = r.ReadString ();
+ return res;
+ }
+
+ internal bool Type_IsAssignableFrom (long id, long c_id) {
+ return SendReceive (CommandSet.TYPE, (int)CmdType.IS_ASSIGNABLE_FROM, new PacketWriter ().WriteId (id).WriteId (c_id)).ReadByte () > 0;
+ }
+
+ internal CattrInfo[] Type_GetCustomAttributes (long id, long attr_type_id, bool inherit) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_CATTRS, new PacketWriter ().WriteId (id).WriteId (attr_type_id));
+ return ReadCattrs (r);
+ }
+
+ internal CattrInfo[] Type_GetFieldCustomAttributes (long id, long field_id, long attr_type_id, bool inherit) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_FIELD_CATTRS, new PacketWriter ().WriteId (id).WriteId (field_id).WriteId (attr_type_id));
+ return ReadCattrs (r);
+ }
+
+ internal CattrInfo[] Type_GetPropertyCustomAttributes (long id, long field_id, long attr_type_id, bool inherit) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_PROPERTY_CATTRS, new PacketWriter ().WriteId (id).WriteId (field_id).WriteId (attr_type_id));
+ return ReadCattrs (r);
+ }
+
+ public long[] Type_GetMethodsByNameFlags (long id, string name, int flags, bool ignoreCase) {
+ flags |= ignoreCase ? (int)BindingFlagsExtensions.BINDING_FLAGS_IGNORE_CASE : 0;
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.CMD_TYPE_GET_METHODS_BY_NAME_FLAGS, new PacketWriter ().WriteId (id).WriteString (name).WriteInt (flags));
+ int len = r.ReadInt ();
+ long[] res = new long [len];
+ for (int i = 0; i < len; ++i)
+ res [i] = r.ReadId ();
+ return res;
+ }
+
+ internal long[] Type_GetInterfaces (long id) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INTERFACES, new PacketWriter ().WriteId (id));
+ int len = r.ReadInt ();
+ return r.ReadIds (len);
+ }
+
+ internal IfaceMapInfo[] Type_GetInterfaceMap (long id, long[] ids) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INTERFACE_MAP, new PacketWriter ().WriteId (id).WriteInt (ids.Length).WriteIds (ids));
+ var res = new IfaceMapInfo [ids.Length];
+ for (int i = 0; i < ids.Length; ++i) {
+ int n = r.ReadInt ();
+
+ res [i].iface_id = ids [i];
+ res [i].iface_methods = r.ReadIds (n);
+ res [i].target_methods = r.ReadIds (n);
+ }
+
+ return res;
+ }
+
+ internal bool Type_IsInitialized (long id) {
+ PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.IS_INITIALIZED, new PacketWriter ().WriteId (id));
+ return r.ReadInt () == 1;
+ }
+
+ /*
+ * EVENTS
+ */
+
+ internal int EnableEvent (EventType etype, SuspendPolicy suspend_policy, List<Modifier> mods) {
+ var w = new PacketWriter ().WriteByte ((byte)etype).WriteByte ((byte)suspend_policy);
+ if (mods != null) {
+ if (mods.Count > 255)
+ throw new NotImplementedException ();
+ w.WriteByte ((byte)mods.Count);
+ foreach (Modifier mod in mods) {
+ if (mod is CountModifier) {
+ w.WriteByte ((byte)ModifierKind.COUNT);
+ w.WriteInt ((mod as CountModifier).Count);
+ } else if (mod is LocationModifier) {
+ w.WriteByte ((byte)ModifierKind.LOCATION_ONLY);
+ w.WriteId ((mod as LocationModifier).Method);
+ w.WriteLong ((mod as LocationModifier).Location);
+ } else if (mod is StepModifier) {
+ w.WriteByte ((byte)ModifierKind.STEP);
+ w.WriteId ((mod as StepModifier).Thread);
+ w.WriteInt ((mod as StepModifier).Size);
+ w.WriteInt ((mod as StepModifier).Depth);
+ if (Version.AtLeast (2, 16))
+ w.WriteInt ((mod as StepModifier).Filter);
+ } else if (mod is ThreadModifier) {
+ w.WriteByte ((byte)ModifierKind.THREAD_ONLY);
+ w.WriteId ((mod as ThreadModifier).Thread);
+ } else if (mod is ExceptionModifier) {
+ var em = mod as ExceptionModifier;
+ w.WriteByte ((byte)ModifierKind.EXCEPTION_ONLY);
+ w.WriteId (em.Type);
+ if (Version.MajorVersion > 2 || Version.MinorVersion > 0) {
+ /* This is only supported in protocol version 2.1 */
+ w.WriteBool (em.Caught);
+ w.WriteBool (em.Uncaught);
+ } else if (!em.Caught || !em.Uncaught) {
+ throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
+ }
+ if (Version.MajorVersion > 2 || Version.MinorVersion > 24) {
+ w.WriteBool (em.Subclasses);
+ } else if (!em.Subclasses) {
+ throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
+ }
+ } else if (mod is AssemblyModifier) {
+ w.WriteByte ((byte)ModifierKind.ASSEMBLY_ONLY);
+ var amod = (mod as AssemblyModifier);
+ w.WriteInt (amod.Assemblies.Length);
+ foreach (var id in amod.Assemblies)
+ w.WriteId (id);
+ } else if (mod is SourceFileModifier) {
+ w.WriteByte ((byte)ModifierKind.SOURCE_FILE_ONLY);
+ var smod = (mod as SourceFileModifier);
+ w.WriteInt (smod.SourceFiles.Length);
+ foreach (var s in smod.SourceFiles)
+ w.WriteString (s);
+ } else if (mod is TypeNameModifier) {
+ w.WriteByte ((byte)ModifierKind.TYPE_NAME_ONLY);
+ var tmod = (mod as TypeNameModifier);
+ w.WriteInt (tmod.TypeNames.Length);
+ foreach (var s in tmod.TypeNames)
+ w.WriteString (s);
+ } else {
+ throw new NotImplementedException ();
+ }
+ }
+ } else {
+ w.WriteByte (0);
+ }
+ return SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.SET, w).ReadInt ();
+ }
+
+ internal void ClearEventRequest (EventType etype, int req_id) {
+ SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.CLEAR, new PacketWriter ().WriteByte ((byte)etype).WriteInt (req_id));
+ }
+
+ internal void ClearAllBreakpoints () {
+ SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.CLEAR_ALL_BREAKPOINTS, new PacketWriter ());
+ }
+
+ /*
+ * STACK FRAME
+ */
+ internal ValueImpl StackFrame_GetThis (long thread_id, long id) {
+ PacketReader r = SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_THIS, new PacketWriter ().WriteId (thread_id).WriteId (id));
+ return r.ReadValue ();
+ }
+
+ internal ValueImpl[] StackFrame_GetValues (long thread_id, long id, int[] pos) {
+ /* pos < 0 -> argument at pos (-pos) - 1 */
+ /* pos >= 0 -> local at pos */
+ int len = pos.Length;
+ PacketReader r = SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_VALUES, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteInt (len).WriteInts (pos));
+
+ ValueImpl[] res = new ValueImpl [len];
+ for (int i = 0; i < len; ++i)
+ res [i] = r.ReadValue ();
+ return res;
+ }
+
+ internal void StackFrame_SetValues (long thread_id, long id, int[] pos, ValueImpl[] values) {
+ /* pos < 0 -> argument at pos (-pos) - 1 */
+ /* pos >= 0 -> local at pos */
+ int len = pos.Length;
+ SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.SET_VALUES, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteInt (len).WriteInts (pos).WriteValues (values));
+ }
+
+ /*
+ * ARRAYS
+ */
+ internal int[] Array_GetLength (long id, out int rank, out int[] lower_bounds) {
+ var r = SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.GET_LENGTH, new PacketWriter ().WriteId (id));
+ rank = r.ReadInt ();
+ int[] res = new int [rank];
+ lower_bounds = new int [rank];
+ for (int i = 0; i < rank; ++i) {
+ res [i] = r.ReadInt ();
+ lower_bounds [i] = r.ReadInt ();
+ }
+ return res;
+ }
+
+ internal ValueImpl[] Array_GetValues (long id, int index, int len) {
+ var r = SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (index).WriteInt (len));
+ ValueImpl[] res = new ValueImpl [len];
+ for (int i = 0; i < len; ++i)
+ res [i] = r.ReadValue ();
+ return res;
+ }
+
+ internal void Array_SetValues (long id, int index, ValueImpl[] values) {
+ SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (index).WriteInt (values.Length).WriteValues (values));
+ }
+
+ /*
+ * STRINGS
+ */
+ internal string String_GetValue (long id) {
+ return SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_VALUE, new PacketWriter ().WriteId (id)).ReadString ();
+ }
+
+ internal int String_GetLength (long id) {
+ return (int)SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_LENGTH, new PacketWriter ().WriteId (id)).ReadLong ();
+ }
+
+ internal char[] String_GetChars (long id, int index, int length) {
+ var r = SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_CHARS, new PacketWriter ().WriteId (id).WriteLong (index).WriteLong (length));
+ var res = new char [length];
+ for (int i = 0; i < length; ++i)
+ res [i] = (char)r.ReadShort ();
+ return res;
+ }
+
+ /*
+ * OBJECTS
+ */
+ internal long Object_GetType (long id) {
+ return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_TYPE, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal long Object_GetDomain (long id) {
+ return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_DOMAIN, new PacketWriter ().WriteId (id)).ReadId ();
+ }
+
+ internal ValueImpl[] Object_GetValues (long id, long[] fields) {
+ int len = fields.Length;
+ PacketReader r = SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (len).WriteIds (fields));
+
+ ValueImpl[] res = new ValueImpl [len];
+ for (int i = 0; i < len; ++i)
+ res [i] = r.ReadValue ();
+ return res;
+ }
+
+ internal void Object_SetValues (long id, long[] fields, ValueImpl[] values) {
+ SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (fields.Length).WriteIds (fields).WriteValues (values));
+ }
+
+ internal bool Object_IsCollected (long id) {
+ return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.IS_COLLECTED, new PacketWriter ().WriteId (id)).ReadInt () == 1;
+ }
+
+ internal long Object_GetAddress (long id) {
+ return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_ADDRESS, new PacketWriter ().WriteId (id)).ReadLong ();
+ }
+
+ internal ObjectRefInfo Object_GetInfo (long id) {
+ ObjectRefInfo res = new ObjectRefInfo ();
+ PacketReader r = SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_INFO, new PacketWriter ().WriteId (id));
+
+ res.type_id = r.ReadId ();
+ res.domain_id = r.ReadId ();
+ return res;
+ }
+
+ public void ForceDisconnect ()
+ {
+ closed = true;
+ disconnected = true;
+ TransportClose ();
+ }
+ }
+
+ class TcpConnection : Connection
+ {
+ Socket socket;
+
+ internal TcpConnection (Socket socket)
+ {
+ this.socket = socket;
+ //socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.NoDelay, 1);
+ }
+
+ internal EndPoint EndPoint {
+ get {
+ return socket.RemoteEndPoint;
+ }
+ }
+
+ protected override int TransportSend (byte[] buf, int buf_offset, int len)
+ {
+ return socket.Send (buf, buf_offset, len, SocketFlags.None);
+ }
+
+ protected override int TransportReceive (byte[] buf, int buf_offset, int len)
+ {
+ return socket.Receive (buf, buf_offset, len, SocketFlags.None);
+ }
+
+ protected override void TransportSetTimeouts (int send_timeout, int receive_timeout)
+ {
+ socket.SendTimeout = send_timeout;
+ socket.ReceiveTimeout = receive_timeout;
+ }
+
+ protected override void TransportClose ()
+ {
+ socket.Close ();
+ }
+ }
+
+ /* This is the interface exposed by the debugger towards the debugger agent */
+ interface IEventHandler
+ {
+ void Events (SuspendPolicy suspend_policy, EventInfo[] events);
+
+ void VMDisconnect (int req_id, long thread_id, string vm_uri);
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeDataMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeDataMirror.cs
new file mode 100644
index 0000000..8003473
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeDataMirror.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft {
+
+ public sealed class CustomAttributeDataMirror {
+ MethodMirror ctorInfo;
+ IList<CustomAttributeTypedArgumentMirror> ctorArgs;
+ IList<CustomAttributeNamedArgumentMirror> namedArgs;
+
+ internal CustomAttributeDataMirror (MethodMirror ctorInfo, object [] ctorArgs, object [] namedArgs)
+ {
+ this.ctorInfo = ctorInfo;
+
+ this.ctorArgs = Array.AsReadOnly<CustomAttributeTypedArgumentMirror>
+ (ctorArgs != null ? UnboxValues<CustomAttributeTypedArgumentMirror> (ctorArgs) : new CustomAttributeTypedArgumentMirror [0]);
+
+ this.namedArgs = Array.AsReadOnly<CustomAttributeNamedArgumentMirror>
+ (namedArgs != null ? UnboxValues<CustomAttributeNamedArgumentMirror> (namedArgs) : new CustomAttributeNamedArgumentMirror [0]);
+ }
+
+ [ComVisible (true)]
+ public MethodMirror Constructor {
+ get {
+ return ctorInfo;
+ }
+ }
+
+ [ComVisible (true)]
+ public IList<CustomAttributeTypedArgumentMirror> ConstructorArguments {
+ get {
+ return ctorArgs;
+ }
+ }
+
+ public IList<CustomAttributeNamedArgumentMirror> NamedArguments {
+ get {
+ return namedArgs;
+ }
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ sb.Append ("[" + ctorInfo.DeclaringType.FullName + "(");
+ if (ctorArgs != null) {
+ for (int i = 0; i < ctorArgs.Count; i++) {
+ sb.Append (ctorArgs [i].ToString ());
+ if (i + 1 < ctorArgs.Count)
+ sb.Append (", ");
+ }
+ }
+
+ if (namedArgs != null) {
+ if (namedArgs.Count > 0)
+ sb.Append (", ");
+
+ for (int j = 0; j < namedArgs.Count; j++) {
+ sb.Append (namedArgs [j].ToString ());
+ if (j + 1 < namedArgs.Count)
+ sb.Append (", ");
+ }
+ }
+ sb.AppendFormat (")]");
+
+ return sb.ToString ();
+ }
+
+ static T [] UnboxValues<T> (object [] values)
+ {
+ T [] retval = new T [values.Length];
+ for (int i = 0; i < values.Length; i++)
+ retval [i] = (T) values [i];
+
+ return retval;
+ }
+
+ /*
+ * Construct a normal object from the value, so accessing the cattr doesn't
+ * require remoting calls.
+ */
+ static CustomAttributeTypedArgumentMirror CreateArg (VirtualMachine vm, ValueImpl vi) {
+ object val;
+
+ /* Instead of receiving a mirror of the Type object, we receive the id of the type */
+ if (vi.Type == (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE)
+ val = vm.GetType (vi.Id);
+ else {
+ Value v = vm.DecodeValue (vi);
+ if (v is PrimitiveValue)
+ val = (v as PrimitiveValue).Value;
+ else if (v is StringMirror)
+ val = (v as StringMirror).Value;
+ else
+ // FIXME:
+ val = v;
+ }
+ return new CustomAttributeTypedArgumentMirror (null, val);
+ }
+
+ internal static CustomAttributeDataMirror[] Create (VirtualMachine vm, CattrInfo[] info) {
+ var res = new CustomAttributeDataMirror [info.Length];
+ for (int i = 0; i < info.Length; ++i) {
+ CattrInfo attr = info [i];
+ MethodMirror ctor = vm.GetMethod (attr.ctor_id);
+ var ctor_args = new object [attr.ctor_args.Length];
+ for (int j = 0; j < ctor_args.Length; ++j)
+ ctor_args [j] = CreateArg (vm, attr.ctor_args [j]);
+ var named_args = new object [attr.named_args.Length];
+ for (int j = 0; j < named_args.Length; ++j) {
+ CattrNamedArgInfo arg = attr.named_args [j];
+ CustomAttributeTypedArgumentMirror val;
+
+ val = CreateArg (vm, arg.value);
+
+ TypeMirror t = ctor.DeclaringType;
+ while (named_args [j] == null && t != null) {
+ if (arg.is_property) {
+ foreach (var prop in t.GetProperties ()) {
+ if (prop.Id == arg.id)
+ named_args [j] = new CustomAttributeNamedArgumentMirror (prop, null, val);
+ }
+ } else {
+ foreach (var field in t.GetFields ()) {
+ if (field.Id == arg.id)
+ named_args [j] = new CustomAttributeNamedArgumentMirror (null, field, val);
+ }
+ }
+ t = t.BaseType;
+ }
+ if (named_args [j] == null)
+ throw new NotImplementedException ();
+ }
+ res [i] = new CustomAttributeDataMirror (ctor, ctor_args, named_args);
+ }
+
+ return res;
+ }
+ }
+
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeNamedArgumentMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeNamedArgumentMirror.cs
new file mode 100644
index 0000000..0f90449
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeNamedArgumentMirror.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+namespace Mono.Debugger.Soft {
+
+ public struct CustomAttributeNamedArgumentMirror {
+ CustomAttributeTypedArgumentMirror arg;
+ PropertyInfoMirror prop;
+ FieldInfoMirror field;
+
+ internal CustomAttributeNamedArgumentMirror (PropertyInfoMirror prop, FieldInfoMirror field, CustomAttributeTypedArgumentMirror arg)
+ {
+ this.arg = arg;
+ this.prop = prop;
+ this.field = field;
+ }
+
+ public PropertyInfoMirror Property {
+ get {
+ return prop;
+ }
+ }
+
+ public FieldInfoMirror Field {
+ get {
+ return field;
+ }
+ }
+
+ public CustomAttributeTypedArgumentMirror TypedValue {
+ get {
+ return arg;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeTypedArgumentMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeTypedArgumentMirror.cs
new file mode 100644
index 0000000..8096d20
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/CustomAttributeTypedArgumentMirror.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.ObjectModel;
+using System.Reflection;
+
+namespace Mono.Debugger.Soft {
+
+ public struct CustomAttributeTypedArgumentMirror {
+ Type type;
+ object value;
+
+ internal CustomAttributeTypedArgumentMirror (Type type, object value)
+ {
+ this.type = type;
+ this.value = value;
+
+ if (value != null)
+ this.type = value.GetType ();
+ else
+ this.type = typeof (void);
+
+ // MS seems to convert arrays into a ReadOnlyCollection
+ if (value is Array) {
+ Array a = (Array)value;
+
+ Type etype = a.GetType ().GetElementType ();
+ CustomAttributeTypedArgumentMirror[] new_value = new CustomAttributeTypedArgumentMirror [a.GetLength (0)];
+ for (int i = 0; i < new_value.Length; ++i)
+ new_value [i] = new CustomAttributeTypedArgumentMirror (etype, a.GetValue (i));
+ this.value = new ReadOnlyCollection <CustomAttributeTypedArgumentMirror> (new_value);
+ }
+ }
+
+ public Type ArgumentType {
+ get {
+ return type;
+ }
+ }
+
+ public object Value {
+ get {
+ return value;
+ }
+ }
+
+ public override string ToString ()
+ {
+ string val = value != null ? value.ToString () : String.Empty;
+ if (ArgumentType == typeof (string))
+ return "\"" + val + "\"";
+ if (ArgumentType == typeof (Type))
+ return "typeof (" + val + ")";
+ if (ArgumentType.IsEnum)
+ return "(" + ArgumentType.Name + ")" + val;
+
+ return val;
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/DataConverter.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/DataConverter.cs
new file mode 100644
index 0000000..d0bf047
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/DataConverter.cs
@@ -0,0 +1,1836 @@
+//
+// Authors:
+// Miguel de Icaza (miguel at novell.com)
+//
+// See the following url for documentation:
+// http://www.mono-project.com/Mono_DataConvert
+//
+// Compilation Options:
+// MONO_DATACONVERTER_PUBLIC:
+// Makes the class public instead of the default internal.
+//
+// MONO_DATACONVERTER_STATIC_METHODS:
+// Exposes the public static methods.
+//
+// TODO:
+// Support for "DoubleWordsAreSwapped" for ARM devices
+//
+// Copyright (C) 2006 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.Text;
+
+#pragma warning disable 3021
+
+namespace Mono {
+
+#if MONO_DATACONVERTER_PUBLIC
+ unsafe public abstract class DataConverter {
+#else
+ unsafe internal abstract class DataConverter {
+
+// Disables the warning: CLS compliance checking will not be performed on
+// `XXXX' because it is not visible from outside this assembly
+#pragma warning disable 3019
+#endif
+ static DataConverter SwapConv = new SwapConverter ();
+ static DataConverter CopyConv = new CopyConverter ();
+
+ public static readonly bool IsLittleEndian = BitConverter.IsLittleEndian;
+
+ public abstract double GetDouble (byte [] data, int index);
+ public abstract float GetFloat (byte [] data, int index);
+ public abstract long GetInt64 (byte [] data, int index);
+ public abstract int GetInt32 (byte [] data, int index);
+
+ public abstract short GetInt16 (byte [] data, int index);
+
+ [CLSCompliant (false)]
+ public abstract uint GetUInt32 (byte [] data, int index);
+ [CLSCompliant (false)]
+ public abstract ushort GetUInt16 (byte [] data, int index);
+ [CLSCompliant (false)]
+ public abstract ulong GetUInt64 (byte [] data, int index);
+
+ public abstract void PutBytes (byte [] dest, int destIdx, double value);
+ public abstract void PutBytes (byte [] dest, int destIdx, float value);
+ public abstract void PutBytes (byte [] dest, int destIdx, int value);
+ public abstract void PutBytes (byte [] dest, int destIdx, long value);
+ public abstract void PutBytes (byte [] dest, int destIdx, short value);
+
+ [CLSCompliant (false)]
+ public abstract void PutBytes (byte [] dest, int destIdx, ushort value);
+ [CLSCompliant (false)]
+ public abstract void PutBytes (byte [] dest, int destIdx, uint value);
+ [CLSCompliant (false)]
+ public abstract void PutBytes (byte [] dest, int destIdx, ulong value);
+
+ public byte[] GetBytes (double value)
+ {
+ byte [] ret = new byte [8];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ public byte[] GetBytes (float value)
+ {
+ byte [] ret = new byte [4];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ public byte[] GetBytes (int value)
+ {
+ byte [] ret = new byte [4];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ public byte[] GetBytes (long value)
+ {
+ byte [] ret = new byte [8];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ public byte[] GetBytes (short value)
+ {
+ byte [] ret = new byte [2];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ [CLSCompliant (false)]
+ public byte[] GetBytes (ushort value)
+ {
+ byte [] ret = new byte [2];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ [CLSCompliant (false)]
+ public byte[] GetBytes (uint value)
+ {
+ byte [] ret = new byte [4];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ [CLSCompliant (false)]
+ public byte[] GetBytes (ulong value)
+ {
+ byte [] ret = new byte [8];
+ PutBytes (ret, 0, value);
+ return ret;
+ }
+
+ static public DataConverter LittleEndian {
+ get {
+ return BitConverter.IsLittleEndian ? CopyConv : SwapConv;
+ }
+ }
+
+ static public DataConverter BigEndian {
+ get {
+ return BitConverter.IsLittleEndian ? SwapConv : CopyConv;
+ }
+ }
+
+ static public DataConverter Native {
+ get {
+ return CopyConv;
+ }
+ }
+
+ static int Align (int current, int align)
+ {
+ return ((current + align - 1) / align) * align;
+ }
+
+ class PackContext {
+ // Buffer
+ public byte [] buffer;
+ int next;
+
+ public string description;
+ public int i; // position in the description
+ public DataConverter conv;
+ public int repeat;
+
+ //
+ // if align == -1, auto align to the size of the byte array
+ // if align == 0, do not do alignment
+ // Any other values aligns to that particular size
+ //
+ public int align;
+
+ public void Add (byte [] group)
+ {
+ //Console.WriteLine ("Adding {0} bytes to {1} (next={2}", group.Length,
+ // buffer == null ? "null" : buffer.Length.ToString (), next);
+
+ if (buffer == null){
+ buffer = group;
+ next = group.Length;
+ return;
+ }
+ if (align != 0){
+ if (align == -1)
+ next = Align (next, group.Length);
+ else
+ next = Align (next, align);
+ align = 0;
+ }
+
+ if (next + group.Length > buffer.Length){
+ byte [] nb = new byte [System.Math.Max (next, 16) * 2 + group.Length];
+ Array.Copy (buffer, nb, buffer.Length);
+ Array.Copy (group, 0, nb, next, group.Length);
+ next = next + group.Length;
+ buffer = nb;
+ } else {
+ Array.Copy (group, 0, buffer, next, group.Length);
+ next += group.Length;
+ }
+ }
+
+ public byte [] Get ()
+ {
+ if (buffer == null)
+ return new byte [0];
+
+ if (buffer.Length != next){
+ byte [] b = new byte [next];
+ Array.Copy (buffer, b, next);
+ return b;
+ }
+ return buffer;
+ }
+ }
+
+ //
+ // Format includes:
+ // Control:
+ // ^ Switch to big endian encoding
+ // _ Switch to little endian encoding
+ // % Switch to host (native) encoding
+ // ! aligns the next data type to its natural boundary (for strings this is 4).
+ //
+ // Types:
+ // s Int16
+ // S UInt16
+ // i Int32
+ // I UInt32
+ // l Int64
+ // L UInt64
+ // f float
+ // d double
+ // b byte
+ // c 1-byte signed character
+ // C 1-byte unsigned character
+ // z8 string encoded as UTF8 with 1-byte null terminator
+ // z6 string encoded as UTF16 with 2-byte null terminator
+ // z7 string encoded as UTF7 with 1-byte null terminator
+ // zb string encoded as BigEndianUnicode with 2-byte null terminator
+ // z3 string encoded as UTF32 with 4-byte null terminator
+ // z4 string encoded as UTF32 big endian with 4-byte null terminator
+ // $8 string encoded as UTF8
+ // $6 string encoded as UTF16
+ // $7 string encoded as UTF7
+ // $b string encoded as BigEndianUnicode
+ // $3 string encoded as UTF32
+ // $4 string encoded as UTF-32 big endian encoding
+ // x null byte
+ //
+ // Repeats, these are prefixes:
+ // N a number between 1 and 9, indicates a repeat count (process N items
+ // with the following datatype
+ // [N] For numbers larger than 9, use brackets, for example [20]
+ // * Repeat the next data type until the arguments are exhausted
+ //
+ static public byte [] Pack (string description, params object [] args)
+ {
+ int argn = 0;
+ PackContext b = new PackContext ();
+ b.conv = CopyConv;
+ b.description = description;
+
+ for (b.i = 0; b.i < description.Length; ){
+ object oarg;
+
+ if (argn < args.Length)
+ oarg = args [argn];
+ else {
+ if (b.repeat != 0)
+ break;
+
+ oarg = null;
+ }
+
+ int save = b.i;
+
+ if (PackOne (b, oarg)){
+ argn++;
+ if (b.repeat > 0){
+ if (--b.repeat > 0)
+ b.i = save;
+ else
+ b.i++;
+ } else
+ b.i++;
+ } else
+ b.i++;
+ }
+ return b.Get ();
+ }
+
+ static public byte [] PackEnumerable (string description, IEnumerable args)
+ {
+ PackContext b = new PackContext ();
+ b.conv = CopyConv;
+ b.description = description;
+
+ IEnumerator enumerator = args.GetEnumerator ();
+ bool ok = enumerator.MoveNext ();
+
+ for (b.i = 0; b.i < description.Length; ){
+ object oarg;
+
+ if (ok)
+ oarg = enumerator.Current;
+ else {
+ if (b.repeat != 0)
+ break;
+ oarg = null;
+ }
+
+ int save = b.i;
+
+ if (PackOne (b, oarg)){
+ ok = enumerator.MoveNext ();
+ if (b.repeat > 0){
+ if (--b.repeat > 0)
+ b.i = save;
+ else
+ b.i++;
+ } else
+ b.i++;
+ } else
+ b.i++;
+ }
+ return b.Get ();
+ }
+
+ //
+ // Packs one datum `oarg' into the buffer `b', using the string format
+ // in `description' at position `i'
+ //
+ // Returns: true if we must pick the next object from the list
+ //
+ static bool PackOne (PackContext b, object oarg)
+ {
+ int n;
+
+ switch (b.description [b.i]){
+ case '^':
+ b.conv = BigEndian;
+ return false;
+ case '_':
+ b.conv = LittleEndian;
+ return false;
+ case '%':
+ b.conv = Native;
+ return false;
+
+ case '!':
+ b.align = -1;
+ return false;
+
+ case 'x':
+ b.Add (new byte [] { 0 });
+ return false;
+
+ // Type Conversions
+ case 'i':
+ b.Add (b.conv.GetBytes (Convert.ToInt32 (oarg)));
+ break;
+
+ case 'I':
+ b.Add (b.conv.GetBytes (Convert.ToUInt32 (oarg)));
+ break;
+
+ case 's':
+ b.Add (b.conv.GetBytes (Convert.ToInt16 (oarg)));
+ break;
+
+ case 'S':
+ b.Add (b.conv.GetBytes (Convert.ToUInt16 (oarg)));
+ break;
+
+ case 'l':
+ b.Add (b.conv.GetBytes (Convert.ToInt64 (oarg)));
+ break;
+
+ case 'L':
+ b.Add (b.conv.GetBytes (Convert.ToUInt64 (oarg)));
+ break;
+
+ case 'f':
+ b.Add (b.conv.GetBytes (Convert.ToSingle (oarg)));
+ break;
+
+ case 'd':
+ b.Add (b.conv.GetBytes (Convert.ToDouble (oarg)));
+ break;
+
+ case 'b':
+ b.Add (new byte [] { Convert.ToByte (oarg) });
+ break;
+
+ case 'c':
+ b.Add (new byte [] { (byte) (Convert.ToSByte (oarg)) });
+ break;
+
+ case 'C':
+ b.Add (new byte [] { Convert.ToByte (oarg) });
+ break;
+
+ // Repeat acount;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ b.repeat = ((short) b.description [b.i]) - ((short) '0');
+ return false;
+
+ case '*':
+ b.repeat = Int32.MaxValue;
+ return false;
+
+ case '[':
+ int count = -1, j;
+
+ for (j = b.i+1; j < b.description.Length; j++){
+ if (b.description [j] == ']')
+ break;
+ n = ((short) b.description [j]) - ((short) '0');
+ if (n >= 0 && n <= 9){
+ if (count == -1)
+ count = n;
+ else
+ count = count * 10 + n;
+ }
+ }
+ if (count == -1)
+ throw new ArgumentException ("invalid size specification");
+ b.i = j;
+ b.repeat = count;
+ return false;
+
+ case '$': case 'z':
+ bool add_null = b.description [b.i] == 'z';
+ b.i++;
+ if (b.i >= b.description.Length)
+ throw new ArgumentException ("$ description needs a type specified", "description");
+ char d = b.description [b.i];
+ Encoding e;
+
+ switch (d){
+ case '8':
+ e = Encoding.UTF8;
+ n = 1;
+ break;
+ case '6':
+ e = Encoding.Unicode;
+ n = 2;
+ break;
+ case '7':
+ e = Encoding.UTF7;
+ n = 1;
+ break;
+ case 'b':
+ e = Encoding.BigEndianUnicode;
+ n = 2;
+ break;
+ case '3':
+ e = Encoding.GetEncoding (12000);
+ n = 4;
+ break;
+ case '4':
+ e = Encoding.GetEncoding (12001);
+ n = 4;
+ break;
+
+ default:
+ throw new ArgumentException ("Invalid format for $ specifier", "description");
+ }
+ if (b.align == -1)
+ b.align = 4;
+ b.Add (e.GetBytes (Convert.ToString (oarg)));
+ if (add_null)
+ b.Add (new byte [n]);
+ break;
+ default:
+ throw new ArgumentException (String.Format ("invalid format specified `{0}'",
+ b.description [b.i]));
+ }
+ return true;
+ }
+
+ static bool Prepare (byte [] buffer, ref int idx, int size, ref bool align)
+ {
+ if (align){
+ idx = Align (idx, size);
+ align = false;
+ }
+ if (idx + size > buffer.Length){
+ idx = buffer.Length;
+ return false;
+ }
+ return true;
+ }
+
+ static public IList Unpack (string description, byte [] buffer, int startIndex)
+ {
+ DataConverter conv = CopyConv;
+ ArrayList result = new ArrayList ();
+ int idx = startIndex;
+ bool align = false;
+ int repeat = 0, n;
+
+ for (int i = 0; i < description.Length && idx < buffer.Length; ){
+ int save = i;
+
+ switch (description [i]){
+ case '^':
+ conv = BigEndian;
+ break;
+ case '_':
+ conv = LittleEndian;
+ break;
+ case '%':
+ conv = Native;
+ break;
+ case 'x':
+ idx++;
+ break;
+
+ case '!':
+ align = true;
+ break;
+
+ // Type Conversions
+ case 'i':
+ if (Prepare (buffer, ref idx, 4, ref align)){
+ result.Add (conv.GetInt32 (buffer, idx));
+ idx += 4;
+ }
+ break;
+
+ case 'I':
+ if (Prepare (buffer, ref idx, 4, ref align)){
+ result.Add (conv.GetUInt32 (buffer, idx));
+ idx += 4;
+ }
+ break;
+
+ case 's':
+ if (Prepare (buffer, ref idx, 2, ref align)){
+ result.Add (conv.GetInt16 (buffer, idx));
+ idx += 2;
+ }
+ break;
+
+ case 'S':
+ if (Prepare (buffer, ref idx, 2, ref align)){
+ result.Add (conv.GetUInt16 (buffer, idx));
+ idx += 2;
+ }
+ break;
+
+ case 'l':
+ if (Prepare (buffer, ref idx, 8, ref align)){
+ result.Add (conv.GetInt64 (buffer, idx));
+ idx += 8;
+ }
+ break;
+
+ case 'L':
+ if (Prepare (buffer, ref idx, 8, ref align)){
+ result.Add (conv.GetUInt64 (buffer, idx));
+ idx += 8;
+ }
+ break;
+
+ case 'f':
+ if (Prepare (buffer, ref idx, 4, ref align)){
+ result.Add (conv.GetDouble (buffer, idx));
+ idx += 4;
+ }
+ break;
+
+ case 'd':
+ if (Prepare (buffer, ref idx, 8, ref align)){
+ result.Add (conv.GetDouble (buffer, idx));
+ idx += 8;
+ }
+ break;
+
+ case 'b':
+ if (Prepare (buffer, ref idx, 1, ref align)){
+ result.Add (buffer [idx]);
+ idx++;
+ }
+ break;
+
+ case 'c': case 'C':
+ if (Prepare (buffer, ref idx, 1, ref align)){
+ char c;
+
+ if (description [i] == 'c')
+ c = ((char) ((sbyte)buffer [idx]));
+ else
+ c = ((char) ((byte)buffer [idx]));
+
+ result.Add (c);
+ idx++;
+ }
+ break;
+
+ // Repeat acount;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ repeat = ((short) description [i]) - ((short) '0');
+ save = i + 1;
+ break;
+
+ case '*':
+ repeat = Int32.MaxValue;
+ break;
+
+ case '[':
+ int count = -1, j;
+
+ for (j = i+1; j < description.Length; j++){
+ if (description [j] == ']')
+ break;
+ n = ((short) description [j]) - ((short) '0');
+ if (n >= 0 && n <= 9){
+ if (count == -1)
+ count = n;
+ else
+ count = count * 10 + n;
+ }
+ }
+ if (count == -1)
+ throw new ArgumentException ("invalid size specification");
+ i = j;
+ repeat = count;
+ break;
+
+ case '$': case 'z':
+ // bool with_null = description [i] == 'z';
+ i++;
+ if (i >= description.Length)
+ throw new ArgumentException ("$ description needs a type specified", "description");
+ char d = description [i];
+ Encoding e;
+ if (align){
+ idx = Align (idx, 4);
+ align = false;
+ }
+ if (idx >= buffer.Length)
+ break;
+
+ switch (d){
+ case '8':
+ e = Encoding.UTF8;
+ n = 1;
+ break;
+ case '6':
+ e = Encoding.Unicode;
+ n = 2;
+ break;
+ case '7':
+ e = Encoding.UTF7;
+ n = 1;
+ break;
+ case 'b':
+ e = Encoding.BigEndianUnicode;
+ n = 2;
+ break;
+ case '3':
+ e = Encoding.GetEncoding (12000);
+ n = 4;
+ break;
+ case '4':
+ e = Encoding.GetEncoding (12001);
+ n = 4;
+ break;
+
+ default:
+ throw new ArgumentException ("Invalid format for $ specifier", "description");
+ }
+ int k = idx;
+ switch (n){
+ case 1:
+ for (; k < buffer.Length && buffer [k] != 0; k++)
+ ;
+ result.Add (e.GetChars (buffer, idx, k-idx));
+ if (k == buffer.Length)
+ idx = k;
+ else
+ idx = k+1;
+ break;
+
+ case 2:
+ for (; k < buffer.Length; k++){
+ if (k+1 == buffer.Length){
+ k++;
+ break;
+ }
+ if (buffer [k] == 0 && buffer [k+1] == 0)
+ break;
+ }
+ result.Add (e.GetChars (buffer, idx, k-idx));
+ if (k == buffer.Length)
+ idx = k;
+ else
+ idx = k+2;
+ break;
+
+ case 4:
+ for (; k < buffer.Length; k++){
+ if (k+3 >= buffer.Length){
+ k = buffer.Length;
+ break;
+ }
+ if (buffer[k]==0 && buffer[k+1] == 0 && buffer[k+2] == 0 && buffer[k+3]== 0)
+ break;
+ }
+ result.Add (e.GetChars (buffer, idx, k-idx));
+ if (k == buffer.Length)
+ idx = k;
+ else
+ idx = k+4;
+ break;
+ }
+ break;
+ default:
+ throw new ArgumentException (String.Format ("invalid format specified `{0}'",
+ description [i]));
+ }
+
+ if (repeat > 0){
+ if (--repeat > 0)
+ i = save;
+ } else
+ i++;
+ }
+ return result;
+ }
+
+ internal void Check (byte [] dest, int destIdx, int size)
+ {
+ if (dest == null)
+ throw new ArgumentNullException ("dest");
+ if (destIdx < 0 || destIdx > dest.Length - size)
+ throw new ArgumentException ("destIdx");
+ }
+
+ class CopyConverter : DataConverter {
+ public override double GetDouble (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+ double ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 8; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override ulong GetUInt64 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ulong ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 8; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override long GetInt64 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ long ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 8; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override float GetFloat (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ float ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 4; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override int GetInt32 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ int ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 4; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override uint GetUInt32 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ uint ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 4; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override short GetInt16 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ short ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 2; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override ushort GetUInt16 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ushort ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 2; i++)
+ b [i] = data [index+i];
+
+ return ret;
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, double value)
+ {
+ Check (dest, destIdx, 8);
+ fixed (byte *target = &dest [destIdx]){
+ long *source = (long *) &value;
+
+ *((long *)target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, float value)
+ {
+ Check (dest, destIdx, 4);
+ fixed (byte *target = &dest [destIdx]){
+ uint *source = (uint *) &value;
+
+ *((uint *)target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, int value)
+ {
+ Check (dest, destIdx, 4);
+ fixed (byte *target = &dest [destIdx]){
+ uint *source = (uint *) &value;
+
+ *((uint *)target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, uint value)
+ {
+ Check (dest, destIdx, 4);
+ fixed (byte *target = &dest [destIdx]){
+ uint *source = (uint *) &value;
+
+ *((uint *)target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, long value)
+ {
+ Check (dest, destIdx, 8);
+ fixed (byte *target = &dest [destIdx]){
+ long *source = (long *) &value;
+
+ *((long*)target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, ulong value)
+ {
+ Check (dest, destIdx, 8);
+ fixed (byte *target = &dest [destIdx]){
+ ulong *source = (ulong *) &value;
+
+ *((ulong *) target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, short value)
+ {
+ Check (dest, destIdx, 2);
+ fixed (byte *target = &dest [destIdx]){
+ ushort *source = (ushort *) &value;
+
+ *((ushort *)target) = *source;
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, ushort value)
+ {
+ Check (dest, destIdx, 2);
+ fixed (byte *target = &dest [destIdx]){
+ ushort *source = (ushort *) &value;
+
+ *((ushort *)target) = *source;
+ }
+ }
+ }
+
+ class SwapConverter : DataConverter {
+ public override double GetDouble (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ double ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 8; i++)
+ b [7-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override ulong GetUInt64 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ulong ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 8; i++)
+ b [7-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override long GetInt64 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ long ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 8; i++)
+ b [7-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override float GetFloat (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ float ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 4; i++)
+ b [3-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override int GetInt32 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ int ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 4; i++)
+ b [3-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override uint GetUInt32 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ uint ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 4; i++)
+ b [3-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override short GetInt16 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ short ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 2; i++)
+ b [1-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override ushort GetUInt16 (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ushort ret;
+ byte *b = (byte *)&ret;
+
+ for (int i = 0; i < 2; i++)
+ b [1-i] = data [index+i];
+
+ return ret;
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, double value)
+ {
+ Check (dest, destIdx, 8);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 8; i++)
+ target [i] = source [7-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, float value)
+ {
+ Check (dest, destIdx, 4);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 4; i++)
+ target [i] = source [3-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, int value)
+ {
+ Check (dest, destIdx, 4);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 4; i++)
+ target [i] = source [3-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, uint value)
+ {
+ Check (dest, destIdx, 4);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 4; i++)
+ target [i] = source [3-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, long value)
+ {
+ Check (dest, destIdx, 8);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 8; i++)
+ target [i] = source [7-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, ulong value)
+ {
+ Check (dest, destIdx, 8);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 4; i++)
+ target [i] = source [7-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, short value)
+ {
+ Check (dest, destIdx, 2);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 2; i++)
+ target [i] = source [1-i];
+ }
+ }
+
+ public override void PutBytes (byte [] dest, int destIdx, ushort value)
+ {
+ Check (dest, destIdx, 2);
+
+ fixed (byte *target = &dest [destIdx]){
+ byte *source = (byte *) &value;
+
+ for (int i = 0; i < 2; i++)
+ target [i] = source [1-i];
+ }
+ }
+ }
+
+#if MONO_DATACONVERTER_STATIC_METHODS
+ static unsafe void PutBytesLE (byte *dest, byte *src, int count)
+ {
+ int i = 0;
+
+ if (BitConverter.IsLittleEndian){
+ for (; i < count; i++)
+ *dest++ = *src++;
+ } else {
+ dest += count;
+ for (; i < count; i++)
+ *(--dest) = *src++;
+ }
+ }
+
+ static unsafe void PutBytesBE (byte *dest, byte *src, int count)
+ {
+ int i = 0;
+
+ if (BitConverter.IsLittleEndian){
+ dest += count;
+ for (; i < count; i++)
+ *(--dest) = *src++;
+ } else {
+ for (; i < count; i++)
+ *dest++ = *src++;
+ }
+ }
+
+ static unsafe void PutBytesNative (byte *dest, byte *src, int count)
+ {
+ int i = 0;
+
+ for (; i < count; i++)
+ dest [i-count] = *src++;
+ }
+
+ static public unsafe double DoubleFromLE (byte[] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ double ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe float FloatFromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ float ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe long Int64FromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ long ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe ulong UInt64FromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ulong ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe int Int32FromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ int ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe uint UInt32FromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ uint ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe short Int16FromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ short ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 2);
+ }
+ return ret;
+ }
+
+ static public unsafe ushort UInt16FromLE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ushort ret;
+ fixed (byte *src = &data[index]){
+ PutBytesLE ((byte *) &ret, src, 2);
+ }
+ return ret;
+ }
+
+ static public unsafe double DoubleFromBE (byte[] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ double ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe float FloatFromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ float ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe long Int64FromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ long ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe ulong UInt64FromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ulong ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe int Int32FromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ int ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe uint UInt32FromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ uint ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe short Int16FromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ short ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 2);
+ }
+ return ret;
+ }
+
+ static public unsafe ushort UInt16FromBE (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ushort ret;
+ fixed (byte *src = &data[index]){
+ PutBytesBE ((byte *) &ret, src, 2);
+ }
+ return ret;
+ }
+
+ static public unsafe double DoubleFromNative (byte[] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ double ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe float FloatFromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ float ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe long Int64FromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ long ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe ulong UInt64FromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 8)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ulong ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 8);
+ }
+ return ret;
+ }
+
+ static public unsafe int Int32FromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ int ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe uint UInt32FromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 4)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ uint ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 4);
+ }
+ return ret;
+ }
+
+ static public unsafe short Int16FromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ short ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 2);
+ }
+ return ret;
+ }
+
+ static public unsafe ushort UInt16FromNative (byte [] data, int index)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+ if (data.Length - index < 2)
+ throw new ArgumentException ("index");
+ if (index < 0)
+ throw new ArgumentException ("index");
+
+ ushort ret;
+ fixed (byte *src = &data[index]){
+ PutBytesNative ((byte *) &ret, src, 2);
+ }
+ return ret;
+ }
+
+ unsafe static byte[] GetBytesPtr (byte *ptr, int count)
+ {
+ byte [] ret = new byte [count];
+
+ for (int i = 0; i < count; i++) {
+ ret [i] = ptr [i];
+ }
+
+ return ret;
+ }
+
+ unsafe static byte[] GetBytesSwap (bool swap, byte *ptr, int count)
+ {
+ byte [] ret = new byte [count];
+
+ if (swap){
+ int t = count-1;
+ for (int i = 0; i < count; i++) {
+ ret [t-i] = ptr [i];
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ ret [i] = ptr [i];
+ }
+ }
+ return ret;
+ }
+
+ unsafe public static byte[] GetBytesNative (bool value)
+ {
+ return GetBytesPtr ((byte *) &value, 1);
+ }
+
+ unsafe public static byte[] GetBytesNative (char value)
+ {
+ return GetBytesPtr ((byte *) &value, 2);
+ }
+
+ unsafe public static byte[] GetBytesNative (short value)
+ {
+ return GetBytesPtr ((byte *) &value, 2);
+ }
+
+ unsafe public static byte[] GetBytesNative (int value)
+ {
+ return GetBytesPtr ((byte *) &value, 4);
+ }
+
+ unsafe public static byte[] GetBytesNative (long value)
+ {
+ return GetBytesPtr ((byte *) &value, 8);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesNative (ushort value)
+ {
+ return GetBytesPtr ((byte *) &value, 2);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesNative (uint value)
+ {
+ return GetBytesPtr ((byte *) &value, 4);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesNative (ulong value)
+ {
+ return GetBytesPtr ((byte *) &value, 8);
+ }
+
+ unsafe public static byte[] GetBytesNative (float value)
+ {
+ return GetBytesPtr ((byte *) &value, 4);
+ }
+
+ unsafe public static byte[] GetBytesNative (double value)
+ {
+ return GetBytesPtr ((byte *) &value, 8);
+ }
+
+ unsafe public static byte[] GetBytesLE (bool value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 1);
+ }
+
+ unsafe public static byte[] GetBytesLE (char value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
+ }
+
+ unsafe public static byte[] GetBytesLE (short value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
+ }
+
+ unsafe public static byte[] GetBytesLE (int value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
+ }
+
+ unsafe public static byte[] GetBytesLE (long value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesLE (ushort value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesLE (uint value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesLE (ulong value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
+ }
+
+ unsafe public static byte[] GetBytesLE (float value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
+ }
+
+ unsafe public static byte[] GetBytesLE (double value)
+ {
+ return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
+ }
+
+ unsafe public static byte[] GetBytesBE (bool value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 1);
+ }
+
+ unsafe public static byte[] GetBytesBE (char value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
+ }
+
+ unsafe public static byte[] GetBytesBE (short value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
+ }
+
+ unsafe public static byte[] GetBytesBE (int value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
+ }
+
+ unsafe public static byte[] GetBytesBE (long value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesBE (ushort value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesBE (uint value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
+ }
+
+ [CLSCompliant (false)]
+ unsafe public static byte[] GetBytesBE (ulong value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
+ }
+
+ unsafe public static byte[] GetBytesBE (float value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
+ }
+
+ unsafe public static byte[] GetBytesBE (double value)
+ {
+ return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
+ }
+#endif
+
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/EnumMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/EnumMirror.cs
new file mode 100644
index 0000000..5131b2a
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/EnumMirror.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * Represents an enum value in the debuggee
+ */
+ public class EnumMirror : StructMirror {
+
+ internal EnumMirror (VirtualMachine vm, TypeMirror type, Value[] fields) : base (vm, type, fields) {
+ }
+
+ internal EnumMirror (VirtualMachine vm, TypeMirror type, PrimitiveValue value) : base (vm, type, new Value[] { value }) {
+ if (type == null)
+ throw new ArgumentNullException ("type");
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ if (!type.IsEnum)
+ throw new ArgumentException ("type must be an enum type", "type");
+ TypeMirror t = type.EnumUnderlyingType;
+ if (value.Value == null || !value.Value.GetType ().IsPrimitive || t != vm.RootDomain.GetCorrespondingType (value.Value.GetType ()))
+ throw new ArgumentException ("Value '" + value.Value + "' does not match the type of the enum.");
+ }
+
+ public object Value {
+ get {
+ return ((PrimitiveValue)Fields [0]).Value;
+ }
+ set {
+ SetField (0, vm.CreateValue (value));
+ }
+ }
+
+ public string StringValue {
+ get {
+ foreach (FieldInfoMirror f in Type.GetFields ()) {
+ if (f.IsStatic) {
+ object v = (Type.GetValue (f) as EnumMirror).Value;
+ if (f.IsStatic && v.Equals (Value))
+ return f.Name;
+ }
+ }
+ return Value.ToString ();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Event.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Event.cs
new file mode 100644
index 0000000..6a09dea
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Event.cs
@@ -0,0 +1,50 @@
+
+namespace Mono.Debugger.Soft
+{
+ public abstract class Event {
+ protected VirtualMachine vm;
+ EventType evtype;
+ ThreadMirror thread;
+ int req_id;
+ long thread_id;
+
+ internal Event (EventType evtype, VirtualMachine vm, int req_id, long thread_id) {
+ this.evtype = evtype;
+ this.vm = vm;
+ this.req_id = req_id;
+ this.thread_id = thread_id;
+ }
+
+ internal Event (EventType evtype, VirtualMachine vm) {
+ this.evtype = evtype;
+ this.vm = vm;
+ this.thread_id = -1;
+ }
+
+ public EventType EventType {
+ get {
+ return evtype;
+ }
+ }
+
+ public override string ToString () {
+ return evtype.ToString ();
+ }
+
+ public ThreadMirror Thread {
+ get {
+ if (thread_id == -1)
+ return null;
+ if (thread == null)
+ thread = vm.GetThread (thread_id);
+ return thread;
+ }
+ }
+
+ public EventRequest Request {
+ get {
+ return vm.GetRequest (req_id);
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/EventQueueImpl.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventQueueImpl.cs
new file mode 100644
index 0000000..08826fe
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventQueueImpl.cs
@@ -0,0 +1,133 @@
+#if FALSE
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using Mono.Debugger;
+using Mono.Debugger.Requests;
+using Mono.Debugger.Events;
+
+namespace Mono.Debugger.Soft
+{
+ class EventQueueImpl : MirrorImpl, EventQueue
+ {
+ bool disconnected;
+ Dictionary<int, byte[]> reply_packets;
+ Thread receiver_thread;
+ Queue queue;
+ object queue_monitor;
+ object reply_packets_monitor;
+
+ public EventQueueImpl (VirtualMachineImpl vm) : base (vm) {
+ reply_packets = new Dictionary<int, byte[]> ();
+ reply_packets_monitor = new Object ();
+
+ queue = new Queue ();
+ queue_monitor = new Object ();
+ receiver_thread = new Thread (new ThreadStart (receiver_thread_main));
+ receiver_thread.Start ();
+ }
+
+ public EventSet Remove () {
+ if (disconnected)
+ // FIXME: VMDisconnectedException
+ throw new IOException ();
+
+ lock (queue_monitor) {
+ if (queue.Count == 0)
+ Monitor.Wait (queue_monitor);
+ return (EventSet)queue.Dequeue ();
+ }
+ }
+
+ public EventSet Remove (int timeout) {
+ throw new NotImplementedException ();
+ }
+
+ Event DecodeEventInfo (WireProtocol.EventInfo info) {
+ EventRequest req = FindRequest (info.requestId);
+ if (info.eventKind == WireProtocol.EVENT_VM_START) {
+ WireProtocol.VMStartEventInfo einfo = (WireProtocol.VMStartEventInfo)info;
+ return new VMStartEventImpl (vm, req, new ThreadReferenceImpl (vm, einfo.thread), new AppDomainMirrorImpl (vm, einfo.domain));
+ } else if (info.eventKind == WireProtocol.EVENT_VM_DEATH) {
+ return new VMDeathEventImpl (vm, req);
+ } else if (info.eventKind == WireProtocol.EVENT_THREAD_START) {
+ WireProtocol.ThreadStartEventInfo einfo = (WireProtocol.ThreadStartEventInfo)info;
+ return new ThreadStartEventImpl (vm, req, new ThreadReferenceImpl (vm, einfo.thread));
+ } else if (info.eventKind == WireProtocol.EVENT_THREAD_DEATH) {
+ WireProtocol.ThreadDeathEventInfo einfo = (WireProtocol.ThreadDeathEventInfo)info;
+ return new ThreadDeathEventImpl (vm, req, new ThreadReferenceImpl (vm, einfo.thread));
+ } else {
+ throw new NotImplementedException ();
+ }
+ }
+
+ EventRequest FindRequest (int requestId) {
+ if (requestId == 0)
+ return null;
+ else
+ return ((EventRequestManagerImpl)vm.EventRequestManager).FindRequest (requestId);
+ }
+
+ // Wait for the reply for a command packet
+ public byte[] WaitForReply (int packetId) {
+ while (true) {
+ lock (reply_packets_monitor) {
+ if (reply_packets.ContainsKey (packetId)) {
+ byte[] reply = reply_packets [packetId];
+ reply_packets.Remove (packetId);
+ return reply;
+ } else {
+ Monitor.Wait (reply_packets_monitor);
+ }
+ }
+ }
+ }
+
+ void add_event_set (EventSet set) {
+ lock (queue_monitor) {
+ queue.Enqueue (set);
+ Monitor.Pulse (queue_monitor);
+ }
+ }
+
+ void receiver_thread_main () {
+
+ Connection conn = vm.Connection;
+
+ while (true) {
+ byte[] packet = conn.ReadPacket ();
+
+ if (packet.Length == 0) {
+ disconnected = true;
+
+ VMDisconnectEventImpl ev = new VMDisconnectEventImpl (vm, null);
+ add_event_set (new EventSetImpl (vm, new Event [] { ev }, SuspendPolicy.SuspendNone));
+ break;
+ }
+
+ if (WireProtocol.IsReplyPacket (packet)) {
+ /* Reply packet */
+ int id = WireProtocol.GetPacketId (packet);
+ lock (reply_packets_monitor) {
+ reply_packets [id] = packet;
+ Monitor.PulseAll (reply_packets_monitor);
+ }
+ } else {
+ WireProtocol.Packet decoded = WireProtocol.DecodePacket (packet);
+ if (decoded is WireProtocol.Event.CompositePacket) {
+ WireProtocol.Event.CompositePacket p = (WireProtocol.Event.CompositePacket)decoded;
+ Event[] events = new Event [p.events.Length];
+ for (int i = 0; i < p.events.Length; ++i) {
+ events [i] = DecodeEventInfo (p.events [i]);
+ }
+
+ add_event_set (new EventSetImpl (vm, events, p.suspendPolicy));
+ }
+ }
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/EventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventRequest.cs
new file mode 100644
index 0000000..69f35f4
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventRequest.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mono.Debugger.Soft
+{
+ public abstract class EventRequest {
+ protected int id;
+ protected EventType etype;
+ protected bool enabled;
+ protected VirtualMachine vm;
+ protected SuspendPolicy suspend;
+ protected int count;
+ protected ThreadMirror thread;
+ protected IList<AssemblyMirror> assembly_filter;
+
+ internal EventRequest (VirtualMachine vm, EventType etype) {
+ this.vm = vm;
+ this.etype = etype;
+ this.suspend = SuspendPolicy.All;
+ }
+
+ internal EventRequest (EventType etype, int id) {
+ this.id = id;
+ this.etype = etype;
+ }
+
+ internal int Id {
+ get {
+ return id;
+ }
+ set {
+ id = value;
+ }
+ }
+
+ public EventType EventType {
+ get {
+ return etype;
+ }
+ }
+
+ public bool Enabled {
+ get {
+ return enabled;
+ }
+ set {
+ if (value != enabled) {
+ if (value)
+ Enable ();
+ else
+ Disable ();
+ }
+ }
+ }
+
+ public int Count {
+ get {
+ return count;
+ }
+ set {
+ CheckDisabled ();
+ count = value;
+ }
+ }
+
+ public ThreadMirror Thread {
+ get {
+ return thread;
+ }
+ set {
+ CheckDisabled ();
+ if (value != null && value.VirtualMachine != vm)
+ throw new VMMismatchException ();
+ thread = value;
+ }
+ }
+
+ public IList<AssemblyMirror> AssemblyFilter {
+ get {
+ return assembly_filter;
+ }
+ set {
+ CheckDisabled ();
+ if (value != null) {
+ foreach (var ass in value)
+ if (ass == null)
+ throw new ArgumentException ("one of the elements of the array is null.");
+ }
+ assembly_filter = value;
+ }
+ }
+
+ /*
+ * Every time an EventRequest object is enabled, a new JDWP event request
+ * is created, and the event request's id changes.
+ */
+ internal void SendReq (List<Modifier> mods) {
+ if (!enabled) {
+ if (Count > 0)
+ mods.Add (new CountModifier () { Count = Count });
+ if (Thread != null)
+ mods.Add (new ThreadModifier () { Thread = Thread.Id });
+ if (AssemblyFilter != null)
+ mods.Add (new AssemblyModifier () { Assemblies = AssemblyFilter.Select (x => x.Id ).ToArray () });
+ id = vm.conn.EnableEvent (EventType, suspend, mods);
+ SetEnabled (id);
+ }
+ }
+
+ public virtual void Enable () {
+ SendReq (new List<Modifier> ());
+ }
+
+ public void Disable () {
+ if (enabled) {
+ vm.conn.ClearEventRequest (etype, id);
+ enabled = false;
+ // FIXME: This causes problems because Events can still reference
+ // the old id
+ //vm.RemoveRequest (this, id);
+ id = -1;
+ }
+ }
+
+ protected void SetEnabled (int id) {
+ this.id = id;
+ enabled = true;
+ vm.AddRequest (this, id);
+ }
+
+ protected void CheckDisabled () {
+ if (Enabled)
+ throw new InvalidOperationException ("Request objects can only be modified while they are disabled.");
+ }
+
+ protected void CheckMirror (VirtualMachine vm, Mirror m) {
+ if (vm != m.VirtualMachine)
+ throw new VMMismatchException ();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/EventSet.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventSet.cs
new file mode 100644
index 0000000..cc83be5
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventSet.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class EventSet {
+ protected VirtualMachine vm;
+ SuspendPolicy suspend_policy;
+ Event[] events;
+
+ internal EventSet (VirtualMachine vm, SuspendPolicy suspend_policy, Event[] events) {
+ this.vm = vm;
+ this.suspend_policy = suspend_policy;
+ this.events = events;
+ }
+
+ public SuspendPolicy SuspendPolicy {
+ get {
+ return suspend_policy;
+ }
+ }
+
+ public Event[] Events {
+ get {
+ return events;
+ }
+ }
+
+ public Event this [int index] {
+ get {
+ return Events [index];
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs
new file mode 100644
index 0000000..802a4ad
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/EventType.cs
@@ -0,0 +1,32 @@
+
+namespace Mono.Debugger.Soft
+{
+ // Keep it in sync with debugger-agent.h
+ public enum EventType {
+ VMStart = 0,
+ VMDeath = 1,
+ ThreadStart = 2,
+ ThreadDeath = 3,
+ AppDomainCreate = 4,
+ AppDomainUnload = 5,
+ MethodEntry = 6,
+ MethodExit = 7,
+ AssemblyLoad = 8,
+ AssemblyUnload = 9,
+ Breakpoint = 10,
+ Step = 11,
+ TypeLoad = 12,
+ Exception = 13,
+ KeepAlive = 14,
+ //
+ // System.Diagnostics.Debugger.Break ()
+ //
+ UserBreak = 15,
+ //
+ // System.Diagnostics.Debugger.Log ()
+ //
+ UserLog = 16,
+ // Not part of the wire protocol
+ VMDisconnect = 99
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ExceptionEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ExceptionEvent.cs
new file mode 100644
index 0000000..4b2c606
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ExceptionEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class ExceptionEvent : Event {
+ ObjectMirror exc;
+ long exc_id;
+
+ internal ExceptionEvent (VirtualMachine vm, int req_id, long thread_id, long exc_id, long loc) : base (EventType.Exception, vm, req_id, thread_id) {
+ this.exc_id = exc_id;
+ }
+
+ public ObjectMirror Exception {
+ get {
+ if (exc == null)
+ exc = vm.GetObject (exc_id);
+ return exc;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ExceptionEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ExceptionEventRequest.cs
new file mode 100644
index 0000000..906b43f
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ExceptionEventRequest.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public sealed class ExceptionEventRequest : EventRequest {
+
+ TypeMirror exc_type;
+ bool caught, uncaught, subclasses;
+
+ internal ExceptionEventRequest (VirtualMachine vm, TypeMirror exc_type, bool caught, bool uncaught) : base (vm, EventType.Exception) {
+ if (exc_type != null) {
+ CheckMirror (vm, exc_type);
+ TypeMirror exception_type = vm.RootDomain.Corlib.GetType ("System.Exception", false, false);
+ if (!exception_type.IsAssignableFrom (exc_type))
+ throw new ArgumentException ("The exception type does not inherit from System.Exception", "exc_type");
+ }
+ this.exc_type = exc_type;
+ this.caught = caught;
+ this.uncaught = uncaught;
+ this.subclasses = true;
+ }
+
+ public TypeMirror ExceptionType {
+ get {
+ return exc_type;
+ }
+ }
+
+ // Defaults to true
+ // Supported since protocol version 2.25
+ public bool IncludeSubclasses {
+ get {
+ return subclasses;
+ }
+ set {
+ vm.CheckProtocolVersion (2, 25);
+ subclasses = value;
+ }
+ }
+
+ public override void Enable () {
+ var mods = new List <Modifier> ();
+ mods.Add (new ExceptionModifier () { Type = exc_type != null ? exc_type.Id : 0, Caught = caught, Uncaught = uncaught, Subclasses = subclasses });
+ SendReq (mods);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs
new file mode 100644
index 0000000..bb71ee3
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using C = Mono.Cecil;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ public class FieldInfoMirror : Mirror {
+
+ TypeMirror parent;
+ string name;
+ TypeMirror type;
+ FieldAttributes attrs;
+ CustomAttributeDataMirror[] cattrs;
+ C.FieldDefinition meta;
+
+ public FieldInfoMirror (TypeMirror parent, long id, string name, TypeMirror type, FieldAttributes attrs) : base (parent.VirtualMachine, id) {
+ this.parent = parent;
+ this.name = name;
+ this.type = type;
+ this.attrs = attrs;
+ }
+
+ public TypeMirror DeclaringType {
+ get {
+ return parent;
+ }
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public TypeMirror FieldType {
+ get {
+ return type;
+ }
+ }
+
+ public FieldAttributes Attributes {
+ get {
+ return attrs;
+ }
+ }
+
+ public bool IsLiteral
+ {
+ get {return (Attributes & FieldAttributes.Literal) != 0;}
+ }
+
+ public bool IsStatic
+ {
+ get {return (Attributes & FieldAttributes.Static) != 0;}
+ }
+
+ public bool IsInitOnly
+ {
+ get {return (Attributes & FieldAttributes.InitOnly) != 0;}
+ }
+
+ public Boolean IsPublic
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public;
+ }
+ }
+
+ public Boolean IsPrivate
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Private;
+ }
+ }
+
+ public Boolean IsFamily
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Family;
+ }
+ }
+
+ public Boolean IsAssembly
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Assembly;
+ }
+ }
+
+ public Boolean IsFamilyAndAssembly
+ {
+ get {
+ return (Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamANDAssem;
+ }
+ }
+
+ public Boolean IsFamilyOrAssembly
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamORAssem;
+ }
+ }
+
+ public Boolean IsPinvokeImpl
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.PinvokeImpl) == FieldAttributes.PinvokeImpl;
+ }
+ }
+
+ public Boolean IsSpecialName
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.SpecialName) == FieldAttributes.SpecialName;
+ }
+ }
+
+ public Boolean IsNotSerialized
+ {
+ get
+ {
+ return (Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized;
+ }
+ }
+
+ public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
+ return GetCAttrs (null, inherit);
+ }
+
+ public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
+ if (attributeType == null)
+ throw new ArgumentNullException ("attributeType");
+ return GetCAttrs (attributeType, inherit);
+ }
+
+ public C.FieldDefinition Metadata {
+ get {
+ if (parent.Metadata == null)
+ return null;
+ // FIXME: Speed this up
+ foreach (var fd in parent.Metadata.Fields) {
+ if (fd.Name == Name) {
+ meta = fd;
+ break;
+ }
+ }
+ if (meta == null)
+ /* Shouldn't happen */
+ throw new NotImplementedException ();
+ return meta;
+ }
+ }
+
+ CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
+ if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
+ cattrs = new CustomAttributeDataMirror [0];
+
+ // FIXME: Handle inherit
+ if (cattrs == null) {
+ CattrInfo[] info = vm.conn.Type_GetFieldCustomAttributes (DeclaringType.Id, id, 0, false);
+ cattrs = CustomAttributeDataMirror.Create (vm, info);
+ }
+ var res = new List<CustomAttributeDataMirror> ();
+ foreach (var attr in cattrs)
+ if (type == null || attr.Constructor.DeclaringType == type)
+ res.Add (attr);
+ return res.ToArray ();
+ }
+ }
+}
+
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/IInvokeAsyncResult.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/IInvokeAsyncResult.cs
new file mode 100644
index 0000000..19b0ae7
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/IInvokeAsyncResult.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public interface IInvokeAsyncResult : IAsyncResult
+ {
+ void Abort ();
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ILExceptionHandler.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ILExceptionHandler.cs
new file mode 100644
index 0000000..927949d
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ILExceptionHandler.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+
+namespace Mono.Debugger.Soft
+{
+ public enum ILExceptionHandlerType
+ {
+ Catch = ExceptionClauseFlags.None,
+ Filter = ExceptionClauseFlags.Filter,
+ Finally = ExceptionClauseFlags.Finally,
+ Fault = ExceptionClauseFlags.Fault,
+ }
+
+ public class ILExceptionHandler
+ {
+ public int TryOffset { get; internal set; }
+ public int TryLength { get; internal set; }
+ public ILExceptionHandlerType HandlerType { get; internal set; }
+ public int HandlerOffset { get; internal set; }
+ public int HandlerLength { get; internal set;}
+ public int FilterOffset { get; internal set; }
+ public TypeMirror CatchType { get; internal set; }
+
+ internal ILExceptionHandler (int try_offset, int try_length, ILExceptionHandlerType handler_type, int handler_offset, int handler_length)
+ {
+ TryOffset = try_offset;
+ TryLength = try_length;
+ HandlerType = handler_type;
+ HandlerOffset = handler_offset;
+ HandlerLength = handler_length;
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ILInstruction.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ILInstruction.cs
new file mode 100644
index 0000000..6c2c7d1
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ILInstruction.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+using System.IO;
+using System.Reflection;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * This is similar to the Instruction class in Cecil, we can't use that
+ * as its constructor is internal.
+ */
+ public class ILInstruction
+ {
+ int offset;
+ OpCode opcode;
+ object operand;
+ ILInstruction prev, next;
+
+ internal ILInstruction (int offset, OpCode opcode, object operand) {
+ this.offset = offset;
+ this.opcode = opcode;
+ this.operand = operand;
+ }
+
+ public int Offset {
+ get {
+ return offset;
+ }
+ }
+
+ public OpCode OpCode {
+ get {
+ return opcode;
+ }
+ }
+
+ public Object Operand {
+ get {
+ return operand;
+ }
+ set {
+ operand = value;
+ }
+ }
+
+ public ILInstruction Next {
+ get {
+ return next;
+ }
+ set {
+ next = value;
+ }
+ }
+
+ public ILInstruction Previous {
+ get {
+ return prev;
+ }
+ set {
+ prev = value;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/IMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/IMirror.cs
new file mode 100644
index 0000000..61c364e
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/IMirror.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * A Mirror represents a runtime object in the remote virtual machine. Calling
+ * methods/properties of mirror objects potentially involves a remoting call,
+ * which
+ * has some overhead, and may also fail. Values of properties which are
+ * constant (like Type.Name) are cached locally, so only the first call is
+ * affected.
+ * FIXME: Thread safety in the api ?
+ */
+ public interface IMirror
+ {
+ VirtualMachine VirtualMachine {
+ get;
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ITargetProcess.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ITargetProcess.cs
new file mode 100644
index 0000000..3a29e35
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ITargetProcess.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Mono.Debugger.Soft
+{
+ public interface ITargetProcess
+ {
+ event System.EventHandler Exited;
+ StreamReader StandardOutput { get; }
+ StreamReader StandardError { get; }
+ bool HasExited { get; }
+ void Kill ();
+ int Id { get; }
+ string ProcessName { get; }
+ }
+
+ internal class ProcessWrapper: ITargetProcess
+ {
+ Process process;
+
+ public ProcessWrapper (Process process)
+ {
+ this.process = process;
+ }
+
+ public Process Process {
+ get { return process; }
+ }
+
+ public event System.EventHandler Exited {
+ add { process.Exited += value; }
+ remove { process.Exited -= value; }
+ }
+
+ public StreamReader StandardOutput {
+ get {
+ return process.StandardOutput;
+ }
+ }
+
+ public StreamReader StandardError {
+ get {
+ return process.StandardError;
+ }
+ }
+
+ public bool HasExited {
+ get {
+ return process.HasExited;
+ }
+ }
+
+ public void Kill ()
+ {
+ process.Kill ();
+ }
+
+ public int Id {
+ get {
+ return process.Id;
+ }
+ }
+
+ public string ProcessName {
+ get {
+ return process.ProcessName;
+ }
+ }
+
+
+
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/InterfaceMappingMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/InterfaceMappingMirror.cs
new file mode 100644
index 0000000..a4ccfbb
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/InterfaceMappingMirror.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using C = Mono.Cecil;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ public class InterfaceMappingMirror : Mirror {
+
+ internal InterfaceMappingMirror (VirtualMachine vm, TypeMirror target, TypeMirror iface, MethodMirror[] iface_methods, MethodMirror[] target_methods) : base (vm, 0) {
+ TargetType = target;
+ InterfaceType = iface;
+ InterfaceMethods = iface_methods;
+ TargetMethods = target_methods;
+ }
+
+ public MethodMirror[] InterfaceMethods;
+
+ public TypeMirror InterfaceType;
+
+ public MethodMirror[] TargetMethods;
+
+ public TypeMirror TargetType;
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/InvalidStackFrameException.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/InvalidStackFrameException.cs
new file mode 100644
index 0000000..751df40
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/InvalidStackFrameException.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class InvalidStackFrameException : Exception {
+
+ public InvalidStackFrameException () : base ("The requested operation cannot be completed because the specified stack frame is no longer valid.") {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/InvocationException.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/InvocationException.cs
new file mode 100644
index 0000000..d8ae2e6
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/InvocationException.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public class InvocationException : Exception {
+
+ ObjectMirror exception;
+
+ public InvocationException (ObjectMirror exception) {
+ this.exception = exception;
+ }
+
+ public ObjectMirror Exception {
+ get {
+ return exception;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs
new file mode 100644
index 0000000..bc06479
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/InvokeOptions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ [Flags]
+ public enum InvokeOptions {
+ None = 0,
+ /*
+ * Disable breakpoints on the thread doing the invoke
+ */
+ DisableBreakpoints = 1,
+ /*
+ * Only resume the target thread during the invoke
+ */
+ SingleThreaded = 2
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/LocalVariable.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/LocalVariable.cs
new file mode 100644
index 0000000..6003ae2
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/LocalVariable.cs
@@ -0,0 +1,79 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class LocalVariable : Mirror {
+
+ MethodMirror method;
+ string name;
+ int index;
+ long type_id;
+ TypeMirror t;
+ bool is_arg;
+ int live_range_start, live_range_end;
+
+ internal LocalVariable (VirtualMachine vm, MethodMirror method, int index, long type_id, string name, int live_range_start, int live_range_end, bool is_arg) : base (vm, 0) {
+ this.method = method;
+ this.index = index;
+ this.name = name;
+ this.type_id = type_id;
+ this.is_arg = is_arg;
+ this.live_range_start = live_range_start;
+ this.live_range_end = live_range_end;
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public int Index {
+ get {
+ return index;
+ }
+ }
+
+ public TypeMirror Type {
+ get {
+ if (t == null)
+ t = vm.GetType (type_id);
+ return t;
+ }
+ }
+
+ public bool IsArg {
+ get {
+ return is_arg;
+ }
+ }
+
+ public MethodMirror Method {
+ get {
+ return method;
+ }
+ }
+
+ internal int LiveRangeStart {
+ get {
+ return live_range_start;
+ }
+ }
+
+ internal int LiveRangeEnd {
+ get {
+ return live_range_end;
+ }
+ }
+
+ internal int GetValueIndex {
+ get {
+ if (IsArg)
+ return (-Index) - 1;
+ else
+ return Index;
+ }
+ }
+ }
+}
+
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs
new file mode 100644
index 0000000..0624095
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs
@@ -0,0 +1,68 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class Location : Mirror
+ {
+ MethodMirror method;
+ //long native_addr;
+ int il_offset;
+ string source_file;
+ int line_number;
+ byte[] hash;
+ int column_number;
+
+ internal Location (VirtualMachine vm, MethodMirror method, long native_addr, int il_offset, string source_file, int line_number, int column_number, byte[] hash) : base (vm, 0) {
+ this.method = method;
+ //this.native_addr = native_addr;
+ this.il_offset = il_offset;
+ this.source_file = source_file;
+ this.line_number = line_number;
+ this.hash = hash;
+ this.column_number = column_number;
+ }
+
+ public MethodMirror Method {
+ get {
+ return method;
+ }
+ }
+
+ public int ILOffset {
+ get {
+ return il_offset;
+ }
+ }
+
+ public string SourceFile {
+ get {
+ return source_file;
+ }
+ }
+
+ public int LineNumber {
+ get {
+ return line_number;
+ }
+ }
+
+ // Since protocol version 2.19, 0 in earlier protocol versions
+ public int ColumnNumber {
+ get {
+ return column_number;
+ }
+ }
+
+ // MD5 hash of source file
+ // Since protocol version 2.14, null in earlier protocol versions
+ public byte[] SourceFileHash {
+ get {
+ return hash;
+ }
+ }
+
+ public override string ToString () {
+ return String.Format ("{0}+0x{1:x} at {2}:{3}", Method.FullName, ILOffset, SourceFile, LineNumber);
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodBodyMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodBodyMirror.cs
new file mode 100644
index 0000000..481bf9a
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodBodyMirror.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Globalization;
+using System.Collections.Generic;
+using System.Text;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+
+namespace Mono.Debugger.Soft
+{
+ public class MethodBodyMirror : Mirror
+ {
+ MethodMirror method;
+ MethodBodyInfo info;
+
+ internal MethodBodyMirror (VirtualMachine vm, MethodMirror method, MethodBodyInfo info) : base (vm, 0) {
+ this.method = method;
+ this.info = info;
+ }
+
+ public MethodMirror Method {
+ get {
+ return method;
+ }
+ }
+
+ public List<ILExceptionHandler> ExceptionHandlers {
+ get {
+ vm.CheckProtocolVersion (2, 18);
+ return info.clauses.Select (c =>
+ {
+ var handler = new ILExceptionHandler (c.try_offset, c.try_length, (ILExceptionHandlerType) c.flags, c.handler_offset, c.handler_length);
+ if (c.flags == ExceptionClauseFlags.None)
+ handler.CatchType = vm.GetType (c.catch_type_id);
+ else if (c.flags == ExceptionClauseFlags.Filter)
+ handler.FilterOffset = c.filter_offset;
+
+ return handler;
+ }).ToList ();
+ }
+ }
+
+ public byte[] GetILAsByteArray () {
+ return info.il;
+ }
+
+ public List<ILInstruction> Instructions {
+ get {
+ return ReadCilBody (new BinaryReader (new MemoryStream (info.il)), info.il.Length);
+ }
+ }
+
+ static bool opcodes_inited;
+
+ static OpCode [] OneByteOpCode = new OpCode [0xe0 + 1];
+ static OpCode [] TwoBytesOpCode = new OpCode [0x1e + 1];
+
+ // Adapted from Cecil
+ List<ILInstruction> ReadCilBody (BinaryReader br, int code_size)
+ {
+ long start = br.BaseStream.Position;
+ ILInstruction last = null;
+ //GenericContext context = new GenericContext (body.Method);
+ List<ILInstruction> code = new List<ILInstruction> ();
+
+ var by_offset = new Dictionary<int, ILInstruction> ();
+
+ if (!opcodes_inited) {
+ foreach (FieldInfo fi in typeof (OpCodes).GetFields (BindingFlags.Static|BindingFlags.Public)) {
+ var val = (OpCode)fi.GetValue (null);
+
+ if (val.Op1 == 0xff)
+ OneByteOpCode [val.Op2] = val;
+ else
+ TwoBytesOpCode [val.Op2] = val;
+ }
+ opcodes_inited = true;
+ }
+
+ while (br.BaseStream.Position < start + code_size) {
+ OpCode op;
+ long offset = br.BaseStream.Position - start;
+ int cursor = br.ReadByte ();
+ int token;
+ ResolvedToken t;
+
+ if (cursor == 0xfe)
+ op = TwoBytesOpCode [br.ReadByte ()];
+ else
+ op = OneByteOpCode [cursor];
+
+ ILInstruction instr = new ILInstruction ((int)offset, op, null);
+
+ by_offset [instr.Offset] = instr;
+
+ switch (op.OperandType) {
+ case OperandType.InlineNone :
+ break;
+ case OperandType.InlineSwitch :
+ uint length = br.ReadUInt32 ();
+ int [] branches = new int [length];
+ int [] buf = new int [length];
+ for (int i = 0; i < length; i++)
+ buf [i] = br.ReadInt32 ();
+ for (int i = 0; i < length; i++)
+ branches [i] = Convert.ToInt32 (br.BaseStream.Position - start + buf [i]);
+ instr.Operand = branches;
+ break;
+ case OperandType.ShortInlineBrTarget :
+ sbyte sbrtgt = br.ReadSByte ();
+ instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + sbrtgt);
+ break;
+ case OperandType.InlineBrTarget :
+ int brtgt = br.ReadInt32 ();
+ instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + brtgt);
+ break;
+ case OperandType.ShortInlineI :
+ if (op == OpCodes.Ldc_I4_S)
+ instr.Operand = br.ReadSByte ();
+ else
+ instr.Operand = br.ReadByte ();
+ break;
+ case OperandType.ShortInlineVar :
+ instr.Operand = br.ReadByte ();
+ break;
+ case OperandType.ShortInlineArg :
+ instr.Operand = br.ReadByte ();
+ break;
+ case OperandType.InlineSig :
+ br.ReadInt32 ();
+ //instr.Operand = GetCallSiteAt (br.ReadInt32 (), context);
+ break;
+ case OperandType.InlineI :
+ instr.Operand = br.ReadInt32 ();
+ break;
+ case OperandType.InlineVar :
+ instr.Operand = br.ReadInt16 ();
+ break;
+ case OperandType.InlineArg :
+ instr.Operand = br.ReadInt16 ();
+ break;
+ case OperandType.InlineI8 :
+ instr.Operand = br.ReadInt64 ();
+ break;
+ case OperandType.ShortInlineR :
+ instr.Operand = br.ReadSingle ();
+ break;
+ case OperandType.InlineR :
+ instr.Operand = br.ReadDouble ();
+ break;
+ case OperandType.InlineString :
+ token = br.ReadInt32 ();
+ t = vm.conn.Method_ResolveToken (Method.Id, token);
+ if (t.Type == TokenType.STRING)
+ instr.Operand = t.Str;
+ break;
+ case OperandType.InlineField :
+ case OperandType.InlineMethod :
+ case OperandType.InlineType :
+ case OperandType.InlineTok :
+ token = br.ReadInt32 ();
+
+ t = vm.conn.Method_ResolveToken (Method.Id, token);
+
+ switch (t.Type) {
+ case TokenType.TYPE:
+ instr.Operand = vm.GetType (t.Id);
+ break;
+ case TokenType.FIELD:
+ // FIXME: No vm.GetField ()
+ //instr.Operand = vm.GetField (t.Id);
+ break;
+ case TokenType.METHOD:
+ instr.Operand = vm.GetMethod (t.Id);
+ break;
+ case TokenType.UNKNOWN:
+ break;
+ default:
+ throw new NotImplementedException ("Unknown token type: " + t.Type);
+ }
+ break;
+ }
+
+ if (last != null) {
+ last.Next = instr;
+ instr.Previous = last;
+ }
+
+ last = instr;
+
+ code.Add (instr);
+ }
+
+ // resolve branches
+ foreach (ILInstruction i in code) {
+ switch (i.OpCode.OperandType) {
+ case OperandType.ShortInlineBrTarget:
+ case OperandType.InlineBrTarget:
+ i.Operand = by_offset [(int)i.Operand];
+ break;
+ case OperandType.InlineSwitch:
+ int [] lbls = (int []) i.Operand;
+ ILInstruction [] instrs = new ILInstruction [lbls.Length];
+ for (int j = 0; j < lbls.Length; j++)
+ instrs [j] = by_offset [lbls [j]];
+ i.Operand = instrs;
+ break;
+ }
+ }
+
+ return code;
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodEntryEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodEntryEvent.cs
new file mode 100644
index 0000000..d21f60c
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodEntryEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class MethodEntryEvent : Event {
+ MethodMirror method;
+ long id;
+
+ internal MethodEntryEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.MethodEntry, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public MethodMirror Method {
+ get {
+ if (method == null)
+ method = vm.GetMethod (id);
+ return method;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodEntryEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodEntryEventRequest.cs
new file mode 100644
index 0000000..e54cb73
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodEntryEventRequest.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public sealed class MethodEntryEventRequest : EventRequest {
+
+ internal MethodEntryEventRequest (VirtualMachine vm) : base (vm, EventType.MethodEntry) {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodExitEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodExitEvent.cs
new file mode 100644
index 0000000..55cd4b7
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodExitEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class MethodExitEvent : Event {
+ MethodMirror method;
+ long id;
+
+ internal MethodExitEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.MethodExit, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public MethodMirror Method {
+ get {
+ if (method == null)
+ method = vm.GetMethod (id);
+ return method;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodExitEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodExitEventRequest.cs
new file mode 100644
index 0000000..be89dcd
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodExitEventRequest.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public sealed class MethodExitEventRequest : EventRequest {
+
+ internal MethodExitEventRequest (VirtualMachine vm) : base (vm, EventType.MethodExit) {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs
new file mode 100644
index 0000000..04717c6
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs
@@ -0,0 +1,411 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using C = Mono.Cecil;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ public class MethodMirror : Mirror
+ {
+ string name;
+ MethodInfo info;
+ TypeMirror declaring_type;
+ DebugInfo debug_info;
+ C.MethodDefinition meta;
+ CustomAttributeDataMirror[] cattrs;
+ ParameterInfoMirror[] param_info;
+ ParameterInfoMirror ret_param;
+ LocalVariable[] locals;
+ IList<Location> locations;
+ MethodBodyMirror body;
+ MethodMirror gmd;
+ TypeMirror[] type_args;
+
+ internal MethodMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ public string Name {
+ get {
+ if (name == null)
+ name = vm.conn.Method_GetName (id);
+ return name;
+ }
+ }
+
+ public TypeMirror DeclaringType {
+ get {
+ if (declaring_type == null)
+ declaring_type = vm.GetType (vm.conn.Method_GetDeclaringType (id));
+ return declaring_type;
+ }
+ }
+
+ public TypeMirror ReturnType {
+ get {
+ return ReturnParameter.ParameterType;
+ }
+ }
+
+ // FIXME:
+ public string FullName {
+ get {
+ string type_namespace = DeclaringType.Namespace;
+ string type_name = DeclaringType.Name;
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (ReturnType.Name);
+ sb.Append (' ');
+ if (type_namespace != String.Empty)
+ sb.Append (type_namespace + ".");
+ sb.Append(type_name);
+ sb.Append(":");
+ sb.Append(Name);
+ sb.Append(" ");
+ sb.Append("(");
+ for (var i = 0; i < param_info.Length; i++) {
+ sb.Append(param_info[i].ParameterType.Name);
+ if (i != param_info.Length - 1)
+ sb.Append(", ");
+ }
+ sb.Append(")");
+ return sb.ToString ();
+ }
+ }
+
+ /*
+ * Creating the custom attributes themselves could modify the behavior of the
+ * debuggee, so we return objects similar to the CustomAttributeData objects
+ * used by the reflection-only functionality on .net.
+ * Since protocol version 2.21
+ */
+ public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
+ return GetCAttrs (null, inherit);
+ }
+
+ /* Since protocol version 2.21 */
+ public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
+ if (attributeType == null)
+ throw new ArgumentNullException ("attributeType");
+ return GetCAttrs (attributeType, inherit);
+ }
+
+ CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
+ if (cattrs == null && meta != null && !Metadata.HasCustomAttributes)
+ cattrs = new CustomAttributeDataMirror [0];
+
+ // FIXME: Handle inherit
+ if (cattrs == null) {
+ CattrInfo[] info = vm.conn.Method_GetCustomAttributes (id, 0, false);
+ cattrs = CustomAttributeDataMirror.Create (vm, info);
+ }
+ var res = new List<CustomAttributeDataMirror> ();
+ foreach (var attr in cattrs)
+ if (type == null || attr.Constructor.DeclaringType == type)
+ res.Add (attr);
+ return res.ToArray ();
+ }
+
+ MethodInfo GetInfo () {
+ if (info == null)
+ info = vm.conn.Method_GetInfo (id);
+
+ return info;
+ }
+
+ public int MetadataToken {
+ get {
+ return GetInfo ().token;
+ }
+ }
+
+ public MethodAttributes Attributes {
+ get {
+ return (MethodAttributes) GetInfo ().attributes;
+ }
+ }
+
+ public bool IsPublic {
+ get {
+ return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
+ }
+ }
+ public bool IsPrivate {
+ get {
+ return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
+ }
+ }
+ public bool IsFamily {
+ get {
+ return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
+ }
+ }
+ public bool IsAssembly {
+ get {
+ return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
+ }
+ }
+ public bool IsFamilyAndAssembly {
+ get {
+ return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
+ }
+ }
+ public bool IsFamilyOrAssembly {
+ get {
+ return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
+ }
+ }
+ public bool IsStatic {
+ get {
+ return (Attributes & MethodAttributes.Static) != 0;
+ }
+ }
+ public bool IsFinal {
+ get {
+ return (Attributes & MethodAttributes.Final) != 0;
+ }
+ }
+ public bool IsVirtual {
+ get {
+ return (Attributes & MethodAttributes.Virtual) != 0;
+ }
+ }
+ public bool IsHideBySig {
+ get {
+ return (Attributes & MethodAttributes.HideBySig) != 0;
+ }
+ }
+ public bool IsAbstract {
+ get {
+ return (Attributes & MethodAttributes.Abstract) != 0;
+ }
+ }
+ public bool IsSpecialName {
+ get {
+ return (Attributes & MethodAttributes.SpecialName) != 0;
+ }
+ }
+
+ public bool IsConstructor {
+ get {
+ int attr = (int)Attributes;
+ return ((attr & (int)MethodAttributes.RTSpecialName) != 0
+ && (Name == ".ctor"));
+ }
+ }
+
+ // Since protocol version 2.12
+ public bool IsGenericMethodDefinition {
+ get {
+ vm.CheckProtocolVersion (2, 12);
+ return GetInfo ().is_gmd;
+ }
+ }
+
+ // Since protocol version 2.12
+ public bool IsGenericMethod {
+ get {
+ vm.CheckProtocolVersion (2, 12);
+ return GetInfo ().is_generic_method;
+ }
+ }
+
+ public MethodImplAttributes GetMethodImplementationFlags() {
+ return (MethodImplAttributes)GetInfo ().iattributes;
+ }
+
+ public ParameterInfoMirror[] GetParameters () {
+ if (param_info == null) {
+ var pi = vm.conn.Method_GetParamInfo (id);
+ param_info = new ParameterInfoMirror [pi.param_count];
+ // Return
+ ret_param = new ParameterInfoMirror (this, -1, vm.GetType (pi.ret_type), null, ParameterAttributes.Retval);
+ // FIXME: this
+ // FIXME: Attributes
+ for (int i = 0; i < pi.param_count; ++i) {
+ param_info [i] = new ParameterInfoMirror (this, i, vm.GetType (pi.param_types [i]), pi.param_names [i], 0);
+ }
+ }
+
+ return param_info;
+ }
+
+ public ParameterInfoMirror ReturnParameter {
+ get {
+ if (ret_param == null)
+ GetParameters ();
+ return ret_param;
+ }
+ }
+
+ public LocalVariable[] GetLocals () {
+ if (locals == null) {
+ LocalsInfo li = new LocalsInfo ();
+ try {
+ li = vm.conn.Method_GetLocalsInfo (id);
+ } catch (CommandException) {
+ throw new AbsentInformationException ();
+ }
+
+ // Add the arguments as well
+ var pi = vm.conn.Method_GetParamInfo (id);
+
+ locals = new LocalVariable [pi.param_count + li.names.Length];
+
+ for (int i = 0; i < pi.param_count; ++i)
+ locals [i] = new LocalVariable (vm, this, i, pi.param_types [i], pi.param_names [i], -1, -1, true);
+
+ for (int i = 0; i < li.names.Length; ++i)
+ locals [i + pi.param_count] = new LocalVariable (vm, this, i, li.types [i], li.names [i], li.live_range_start [i], li.live_range_end [i], false);
+ }
+ return locals;
+ }
+
+ public LocalVariable GetLocal (string name) {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ GetLocals ();
+
+ LocalVariable res = null;
+ for (int i = 0; i < locals.Length; ++i) {
+ if (locals [i].Name == name) {
+ if (res != null)
+ throw new AmbiguousMatchException ("More that one local has the name '" + name + "'.");
+ res = locals [i];
+ }
+ }
+
+ return res;
+ }
+
+ public MethodBodyMirror GetMethodBody () {
+ if (body == null) {
+ MethodBodyInfo info = vm.conn.Method_GetBody (id);
+
+ body = new MethodBodyMirror (vm, this, info);
+ }
+ return body;
+ }
+
+ public MethodMirror GetGenericMethodDefinition () {
+ vm.CheckProtocolVersion (2, 12);
+ if (gmd == null) {
+ if (info.gmd == 0)
+ throw new InvalidOperationException ();
+ gmd = vm.GetMethod (info.gmd);
+ }
+ return gmd;
+ }
+
+ // Since protocol version 2.15
+ public TypeMirror[] GetGenericArguments () {
+ vm.CheckProtocolVersion (2, 15);
+ if (type_args == null)
+ type_args = vm.GetTypes (GetInfo ().type_args);
+ return type_args;
+ }
+
+ // Since protocol version 2.24
+ public MethodMirror MakeGenericMethod (TypeMirror[] args) {
+ if (args == null)
+ throw new ArgumentNullException ("args");
+ foreach (var a in args)
+ if (a == null)
+ throw new ArgumentNullException ("args");
+
+ if (!IsGenericMethodDefinition)
+ throw new InvalidOperationException ("not a generic method definition");
+
+ if (GetGenericArguments ().Length != args.Length)
+ throw new ArgumentException ("Incorrect length");
+
+ vm.CheckProtocolVersion (2, 24);
+ long id = -1;
+ try {
+ id = vm.conn.Method_MakeGenericMethod (Id, args.Select (t => t.Id).ToArray ());
+ } catch (CommandException) {
+ throw new InvalidOperationException ();
+ }
+ return vm.GetMethod (id);
+ }
+
+ public IList<int> ILOffsets {
+ get {
+ if (debug_info == null)
+ debug_info = vm.conn.Method_GetDebugInfo (id);
+ return Array.AsReadOnly (debug_info.il_offsets);
+ }
+ }
+
+ public IList<int> LineNumbers {
+ get {
+ if (debug_info == null)
+ debug_info = vm.conn.Method_GetDebugInfo (id);
+ return Array.AsReadOnly (debug_info.line_numbers);
+ }
+ }
+
+ public string SourceFile {
+ get {
+ if (debug_info == null)
+ debug_info = vm.conn.Method_GetDebugInfo (id);
+ return debug_info.source_files.Length > 0 ? debug_info.source_files [0].source_file : null;
+ }
+ }
+
+ public IList<Location> Locations {
+ get {
+ if (locations == null) {
+ var il_offsets = ILOffsets;
+ var line_numbers = LineNumbers;
+ IList<Location> res = new Location [ILOffsets.Count];
+ for (int i = 0; i < il_offsets.Count; ++i)
+ res [i] = new Location (vm, this, -1, il_offsets [i], debug_info.source_files [i].source_file, line_numbers [i], debug_info.column_numbers [i], debug_info.source_files [i].hash);
+ locations = res;
+ }
+ return locations;
+ }
+ }
+
+ internal int il_offset_to_line_number (int il_offset, out string src_file, out byte[] src_hash, out int column_number) {
+ if (debug_info == null)
+ debug_info = vm.conn.Method_GetDebugInfo (id);
+
+ // FIXME: Optimize this
+ src_file = null;
+ src_hash = null;
+ column_number = 0;
+ for (int i = debug_info.il_offsets.Length - 1; i >= 0; --i) {
+ if (debug_info.il_offsets [i] <= il_offset) {
+ src_file = debug_info.source_files [i].source_file;
+ src_hash = debug_info.source_files [i].hash;
+ column_number = debug_info.column_numbers [i];
+ return debug_info.line_numbers [i];
+ }
+ }
+ return -1;
+ }
+
+ public Location LocationAtILOffset (int il_offset) {
+ IList<Location> locs = Locations;
+
+ // FIXME: Optimize this
+ for (int i = locs.Count - 1; i >= 0; --i) {
+ if (locs [i].ILOffset <= il_offset)
+ return locs [i];
+ }
+
+ return null;
+ }
+
+ public C.MethodDefinition Metadata {
+ get {
+ if (meta == null)
+ meta = (C.MethodDefinition)DeclaringType.Assembly.Metadata.MainModule.LookupToken (MetadataToken);
+ return meta;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Mirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Mirror.cs
new file mode 100644
index 0000000..699706c
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Mirror.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public abstract class Mirror : IMirror
+ {
+ protected VirtualMachine vm;
+ protected long id; // The id used in the protocol
+
+ internal Mirror (VirtualMachine vm, long id) {
+ this.vm = vm;
+ this.id = id;
+ }
+
+ internal Mirror () {
+ }
+
+ public VirtualMachine VirtualMachine {
+ get {
+ return vm;
+ }
+ }
+
+ internal long Id {
+ get {
+ return id;
+ }
+ }
+
+ protected void SetVirtualMachine (VirtualMachine vm) {
+ this.vm = vm;
+ }
+
+ protected void CheckMirror (Mirror m) {
+ if (vm != m.VirtualMachine)
+ throw new VMMismatchException ();
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ModuleMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ModuleMirror.cs
new file mode 100644
index 0000000..fb94436
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ModuleMirror.cs
@@ -0,0 +1,66 @@
+using System;
+using Mono.Debugger;
+using Mono.Cecil;
+
+namespace Mono.Debugger.Soft
+{
+ public class ModuleMirror : Mirror
+ {
+ ModuleInfo info;
+ Guid guid;
+ AssemblyMirror assembly;
+
+ internal ModuleMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ void ReadInfo () {
+ if (info == null)
+ info = vm.conn.Module_GetInfo (id);
+ }
+
+ public string Name {
+ get {
+ ReadInfo ();
+ return info.Name;
+ }
+ }
+
+ public string ScopeName {
+ get {
+ ReadInfo ();
+ return info.ScopeName;
+ }
+ }
+
+ public string FullyQualifiedName {
+ get {
+ ReadInfo ();
+ return info.FQName;
+ }
+ }
+
+ public Guid ModuleVersionId {
+ get {
+ if (guid == Guid.Empty) {
+ ReadInfo ();
+ guid = new Guid (info.Guid);
+ }
+ return guid;
+ }
+ }
+
+ public AssemblyMirror Assembly {
+ get {
+ if (assembly == null) {
+ ReadInfo ();
+ if (info.Assembly == 0)
+ return null;
+ assembly = vm.GetAssembly (info.Assembly);
+ }
+ return assembly;
+ }
+ }
+
+ // FIXME: Add function to query the guid, check in Metadata
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectCollectedException.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectCollectedException.cs
new file mode 100644
index 0000000..f89177c
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectCollectedException.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class ObjectCollectedException : Exception {
+
+ public ObjectCollectedException () : base ("The requested operation cannot be completed because the object has been garbage collected.") {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs
new file mode 100644
index 0000000..18611ba
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ObjectMirror.cs
@@ -0,0 +1,380 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Remoting.Messaging;
+using System.Threading;
+
+namespace Mono.Debugger.Soft
+{
+ public class ObjectMirror : Value {
+ TypeMirror type;
+ AppDomainMirror domain;
+
+ internal ObjectMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ internal ObjectMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id) {
+ this.type = type;
+ this.domain = domain;
+ }
+
+ void GetInfo () {
+ var info = vm.conn.Object_GetInfo (id);
+ type = vm.GetType (info.type_id);
+ domain = vm.GetDomain (info.domain_id);
+ }
+
+ public TypeMirror Type {
+ get {
+ if (type == null) {
+ if (vm.conn.Version.AtLeast (2, 5))
+ GetInfo ();
+ else
+ type = vm.GetType (vm.conn.Object_GetType (id));
+ }
+ return type;
+ }
+ }
+
+ public AppDomainMirror Domain {
+ get {
+ if (domain == null) {
+ if (vm.conn.Version.AtLeast (2, 5))
+ GetInfo ();
+ else
+ domain = vm.GetDomain (vm.conn.Object_GetDomain (id));
+ }
+ return domain;
+ }
+ }
+
+ public bool IsCollected {
+ get {
+ return vm.conn.Object_IsCollected (id);
+ }
+ }
+
+ public Value GetValue (FieldInfoMirror field) {
+ return GetValues (new FieldInfoMirror [] { field }) [0];
+ }
+
+ public Value[] GetValues (IList<FieldInfoMirror> fields) {
+ if (fields == null)
+ throw new ArgumentNullException ("fields");
+ foreach (FieldInfoMirror f in fields) {
+ if (f == null)
+ throw new ArgumentNullException ("field");
+ CheckMirror (f);
+ }
+ long[] ids = new long [fields.Count];
+ for (int i = 0; i < fields.Count; ++i)
+ ids [i] = fields [i].Id;
+ try {
+ return vm.DecodeValues (vm.conn.Object_GetValues (id, ids));
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
+ throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
+ else
+ throw;
+ }
+ }
+
+ public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
+ if (fields == null)
+ throw new ArgumentNullException ("fields");
+ if (values == null)
+ throw new ArgumentNullException ("values");
+ foreach (FieldInfoMirror f in fields) {
+ if (f == null)
+ throw new ArgumentNullException ("field");
+ CheckMirror (f);
+ }
+ foreach (Value v in values) {
+ if (v == null)
+ throw new ArgumentNullException ("values");
+ CheckMirror (v);
+ }
+ long[] ids = new long [fields.Count];
+ for (int i = 0; i < fields.Count; ++i)
+ ids [i] = fields [i].Id;
+ try {
+ vm.conn.Object_SetValues (id, ids, vm.EncodeValues (values));
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
+ throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
+ else if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
+ throw new ArgumentException ("One of the values is not valid for its field.", "values");
+ else
+ throw;
+ }
+ }
+
+ public void SetValue (FieldInfoMirror field, Value value) {
+ SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
+ }
+
+ /*
+ * The current address of the object. It can change during garbage
+ * collections. Use a long since the debuggee might have a different
+ * pointer size.
+ */
+ public long Address {
+ get {
+ return vm.conn.Object_GetAddress (id);
+ }
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
+ return InvokeMethod (vm, thread, method, this, arguments, InvokeOptions.None);
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
+ return InvokeMethod (vm, thread, method, this, arguments, options);
+ }
+
+ [Obsolete ("Use the overload without the 'vm' argument")]
+ public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
+ }
+
+ public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
+ }
+
+ public Value EndInvokeMethod (IAsyncResult asyncResult) {
+ return EndInvokeMethodInternal (asyncResult);
+ }
+
+ //
+ // Invoke the members of METHODS one-by-one, calling CALLBACK after each invoke was finished. The IAsyncResult will be marked as completed after all invokes have
+ // finished. The callback will be called with a different IAsyncResult that represents one method invocation.
+ // From protocol version 2.22.
+ //
+ public IAsyncResult BeginInvokeMultiple (ThreadMirror thread, MethodMirror[] methods, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return BeginInvokeMultiple (vm, thread, methods, this, arguments, options, callback, state);
+ }
+
+ public void EndInvokeMultiple (IAsyncResult asyncResult) {
+ EndInvokeMultipleInternal (asyncResult);
+ }
+
+ /*
+ * Common implementation for invokes
+ */
+
+ class InvokeAsyncResult : IInvokeAsyncResult {
+
+ public object AsyncState {
+ get; set;
+ }
+
+ public WaitHandle AsyncWaitHandle {
+ get; set;
+ }
+
+ public bool CompletedSynchronously {
+ get {
+ return false;
+ }
+ }
+
+ public bool IsCompleted {
+ get; set;
+ }
+
+ public AsyncCallback Callback {
+ get; set;
+ }
+
+ public ErrorCode ErrorCode {
+ get; set;
+ }
+
+ public VirtualMachine VM {
+ get; set;
+ }
+
+ public ThreadMirror Thread {
+ get; set;
+ }
+
+ public ValueImpl Value {
+ get; set;
+ }
+
+ public ValueImpl Exception {
+ get; set;
+ }
+
+ public int ID {
+ get; set;
+ }
+
+ public bool IsMultiple {
+ get; set;
+ }
+
+ public int NumPending;
+
+ public void Abort ()
+ {
+ if (ID == 0) // Ooops
+ return;
+
+ ObjectMirror.AbortInvoke (VM, Thread, ID);
+ }
+ }
+
+ internal static IInvokeAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ if (thread == null)
+ throw new ArgumentNullException ("thread");
+ if (method == null)
+ throw new ArgumentNullException ("method");
+ if (arguments == null)
+ arguments = new Value [0];
+
+ InvokeFlags f = InvokeFlags.NONE;
+
+ if ((options & InvokeOptions.DisableBreakpoints) != 0)
+ f |= InvokeFlags.DISABLE_BREAKPOINTS;
+ if ((options & InvokeOptions.SingleThreaded) != 0)
+ f |= InvokeFlags.SINGLE_THREADED;
+
+ InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback };
+
+ r.ID = vm.conn.VM_BeginInvokeMethod (thread.Id, method.Id, this_obj != null ? vm.EncodeValue (this_obj) : vm.EncodeValue (vm.CreateValue (null)), vm.EncodeValues (arguments), f, InvokeCB, r);
+
+ return r;
+ }
+
+ // This is called when the result of an invoke is received
+ static void InvokeCB (ValueImpl v, ValueImpl exc, ErrorCode error, object state) {
+ InvokeAsyncResult r = (InvokeAsyncResult)state;
+
+ if (error != 0) {
+ r.ErrorCode = error;
+ } else {
+ r.Value = v;
+ r.Exception = exc;
+ }
+
+ r.IsCompleted = true;
+ ((ManualResetEvent)r.AsyncWaitHandle).Set ();
+
+ if (r.Callback != null)
+ r.Callback.BeginInvoke (r, null, null);
+ }
+
+ internal static Value EndInvokeMethodInternal (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
+
+ if (!r.IsCompleted)
+ r.AsyncWaitHandle.WaitOne ();
+
+ if (r.ErrorCode != 0) {
+ try {
+ r.VM.ErrorHandler (null, new ErrorHandlerEventArgs () { ErrorCode = r.ErrorCode });
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
+ throw new ArgumentException ("Incorrect number or types of arguments", "arguments");
+ else
+ throw;
+ }
+ throw new NotImplementedException ();
+ } else {
+ if (r.Exception != null)
+ throw new InvocationException ((ObjectMirror)r.VM.DecodeValue (r.Exception));
+ else
+ return r.VM.DecodeValue (r.Value);
+ }
+ }
+
+ internal static void EndInvokeMultipleInternal (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
+
+ if (!r.IsCompleted)
+ r.AsyncWaitHandle.WaitOne ();
+ }
+
+ internal static Value InvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options) {
+ return EndInvokeMethodInternal (BeginInvokeMethod (vm, thread, method, this_obj, arguments, options, null, null));
+ }
+
+ internal static void AbortInvoke (VirtualMachine vm, ThreadMirror thread, int id)
+ {
+ vm.conn.VM_AbortInvoke (thread.Id, id);
+ }
+
+ //
+ // Implementation of InvokeMultiple
+ //
+
+ internal static IInvokeAsyncResult BeginInvokeMultiple (VirtualMachine vm, ThreadMirror thread, MethodMirror[] methods, Value this_obj, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ if (thread == null)
+ throw new ArgumentNullException ("thread");
+ if (methods == null)
+ throw new ArgumentNullException ("methods");
+ foreach (var m in methods)
+ if (m == null)
+ throw new ArgumentNullException ("method");
+ if (arguments == null) {
+ arguments = new List<IList<Value>> ();
+ for (int i = 0; i < methods.Length; ++i)
+ arguments.Add (new Value [0]);
+ } else {
+ // FIXME: Not needed for property evaluation
+ throw new NotImplementedException ();
+ }
+ if (callback == null)
+ throw new ArgumentException ("A callback argument is required for this method.", "callback");
+
+ InvokeFlags f = InvokeFlags.NONE;
+
+ if ((options & InvokeOptions.DisableBreakpoints) != 0)
+ f |= InvokeFlags.DISABLE_BREAKPOINTS;
+ if ((options & InvokeOptions.SingleThreaded) != 0)
+ f |= InvokeFlags.SINGLE_THREADED;
+
+ InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback, NumPending = methods.Length, IsMultiple = true };
+
+ var mids = new long [methods.Length];
+ for (int i = 0; i < methods.Length; ++i)
+ mids [i] = methods [i].Id;
+ var args = new List<ValueImpl[]> ();
+ for (int i = 0; i < methods.Length; ++i)
+ args.Add (vm.EncodeValues (arguments [i]));
+ r.ID = vm.conn.VM_BeginInvokeMethods (thread.Id, mids, this_obj != null ? vm.EncodeValue (this_obj) : vm.EncodeValue (vm.CreateValue (null)), args, f, InvokeMultipleCB, r);
+
+ return r;
+ }
+
+ // This is called when the result of an invoke is received
+ static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, ErrorCode error, object state) {
+ var r = (InvokeAsyncResult)state;
+
+ Interlocked.Decrement (ref r.NumPending);
+
+ if (r.NumPending == 0) {
+ r.IsCompleted = true;
+ ((ManualResetEvent)r.AsyncWaitHandle).Set ();
+ }
+
+ // Have to pass another asyncresult to the callback since multiple threads can execute it concurrently with results of multiple invocations
+ var r2 = new InvokeAsyncResult { AsyncState = r.AsyncState, AsyncWaitHandle = null, VM = r.VM, Thread = r.Thread, Callback = r.Callback, IsCompleted = true };
+
+ if (error != 0) {
+ r2.ErrorCode = error;
+ } else {
+ r2.Value = v;
+ r2.Exception = exc;
+ }
+
+ r.Callback.BeginInvoke (r2, null, null);
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ParameterInfoMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ParameterInfoMirror.cs
new file mode 100644
index 0000000..32fb621
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ParameterInfoMirror.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+
+namespace Mono.Debugger.Soft
+{
+ public class ParameterInfoMirror : Mirror {
+
+ MethodMirror method;
+ TypeMirror type;
+ string name;
+ int pos;
+ ParameterAttributes attrs;
+
+ internal ParameterInfoMirror (MethodMirror method, int pos, TypeMirror type, string name, ParameterAttributes attrs) : base (method.VirtualMachine, 0) {
+ this.method = method;
+ this.pos = pos;
+ this.type = type;
+ this.name = name;
+ this.attrs = attrs;
+ }
+
+ public TypeMirror ParameterType {
+ get {
+ return type;
+ }
+ }
+
+ public MethodMirror Method {
+ get {
+ return method;
+ }
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public int Position {
+ get {
+ return pos;
+ }
+ }
+
+ public ParameterAttributes Attributes {
+ get {
+ return attrs;
+ }
+ }
+
+ public bool IsRetval {
+ get {
+ return (Attributes & ParameterAttributes.Retval) != 0;
+ }
+ }
+
+ public override string ToString () {
+ return String.Format ("ParameterInfo ({0})", Name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs
new file mode 100644
index 0000000..3fa359f
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs
@@ -0,0 +1,65 @@
+//
+// PointerValue.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2012 Xamarin Inc.
+//
+// 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;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * Represents a value of a pointer type in the debuggee
+ */
+ public class PointerValue : Value {
+ TypeMirror type;
+ long addr;
+
+ public PointerValue (VirtualMachine vm, TypeMirror type, long addr) : base (vm, 0) {
+ this.type = type;
+ this.addr = addr;
+ }
+
+ public long Address {
+ get { return addr; }
+ }
+
+ public TypeMirror Type {
+ get { return type; }
+ }
+
+ public override bool Equals (object obj) {
+ if (obj != null && obj is PointerValue)
+ return addr == (obj as PointerValue).addr;
+ return base.Equals (obj);
+ }
+
+ public override int GetHashCode () {
+ return base.GetHashCode ();
+ }
+
+ public override string ToString () {
+ return string.Format ("PointerValue<({0}) 0x{1:x}>", type.CSharpName, addr);
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/PrimitiveValue.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/PrimitiveValue.cs
new file mode 100644
index 0000000..696f649
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/PrimitiveValue.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * Represents a value of a primitive type in the debuggee
+ */
+ public class PrimitiveValue : Value {
+ object value;
+
+ public PrimitiveValue (VirtualMachine vm, object value) : base (vm, 0) {
+ this.value = value;
+ }
+
+ public object Value {
+ get {
+ return value;
+ }
+ }
+
+ public override bool Equals (object obj) {
+ if (value == obj)
+ return true;
+ if (obj != null && obj is PrimitiveValue)
+ return value == (obj as PrimitiveValue).Value;
+ return base.Equals (obj);
+ }
+
+ public override int GetHashCode () {
+ return base.GetHashCode ();
+ }
+
+ public override string ToString () {
+ object v = Value;
+
+ return "PrimitiveValue<" + (v != null ? v.ToString () : "(null)") + ">";
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, this, arguments, InvokeOptions.None);
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, this, arguments, options);
+ }
+
+ public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return ObjectMirror.BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
+ }
+
+ public Value EndInvokeMethod (IAsyncResult asyncResult) {
+ return ObjectMirror.EndInvokeMethodInternal (asyncResult);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/PropertyInfoMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/PropertyInfoMirror.cs
new file mode 100644
index 0000000..32f87d1
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/PropertyInfoMirror.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using C = Mono.Cecil;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ public class PropertyInfoMirror : Mirror {
+
+ TypeMirror parent;
+ string name;
+ PropertyAttributes attrs;
+ MethodMirror get_method, set_method;
+ CustomAttributeDataMirror[] cattrs;
+ C.PropertyDefinition meta;
+
+ public PropertyInfoMirror (TypeMirror parent, long id, string name, MethodMirror get_method, MethodMirror set_method, PropertyAttributes attrs) : base (parent.VirtualMachine, id) {
+ this.parent = parent;
+ this.name = name;
+ this.attrs = attrs;
+ this.get_method = get_method;
+ this.set_method = set_method;
+ }
+
+ public TypeMirror DeclaringType {
+ get {
+ return parent;
+ }
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public TypeMirror PropertyType {
+ get {
+ if (get_method != null)
+ return get_method.ReturnType;
+ else {
+ ParameterInfoMirror[] parameters = set_method.GetParameters ();
+
+ return parameters [parameters.Length - 1].ParameterType;
+ }
+ }
+ }
+
+ public PropertyAttributes Attributes {
+ get {
+ return attrs;
+ }
+ }
+
+ public bool IsSpecialName {
+ get {return (Attributes & PropertyAttributes.SpecialName) != 0;}
+ }
+
+ public MethodMirror GetGetMethod ()
+ {
+ return GetGetMethod (false);
+ }
+
+ public MethodMirror GetGetMethod (bool nonPublic)
+ {
+ if (get_method != null && (nonPublic || get_method.IsPublic))
+ return get_method;
+ else
+ return null;
+ }
+
+ public MethodMirror GetSetMethod ()
+ {
+ return GetSetMethod (false);
+ }
+
+ public MethodMirror GetSetMethod (bool nonPublic)
+ {
+ if (set_method != null && (nonPublic || set_method.IsPublic))
+ return set_method;
+ else
+ return null;
+ }
+
+ public ParameterInfoMirror[] GetIndexParameters()
+ {
+ if (get_method != null)
+ return get_method.GetParameters ();
+ return new ParameterInfoMirror [0];
+ }
+
+ public C.PropertyDefinition Metadata {
+ get {
+ if (parent.Metadata == null)
+ return null;
+ // FIXME: Speed this up
+ foreach (var def in parent.Metadata.Properties) {
+ if (def.Name == Name) {
+ meta = def;
+ break;
+ }
+ }
+ if (meta == null)
+ /* Shouldn't happen */
+ throw new NotImplementedException ();
+ return meta;
+ }
+ }
+
+ public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
+ return GetCAttrs (null, inherit);
+ }
+
+ public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
+ if (attributeType == null)
+ throw new ArgumentNullException ("attributeType");
+ return GetCAttrs (attributeType, inherit);
+ }
+
+ CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
+ if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
+ cattrs = new CustomAttributeDataMirror [0];
+
+ // FIXME: Handle inherit
+ if (cattrs == null) {
+ CattrInfo[] info = vm.conn.Type_GetPropertyCustomAttributes (DeclaringType.Id, id, 0, false);
+ cattrs = CustomAttributeDataMirror.Create (vm, info);
+ }
+ var res = new List<CustomAttributeDataMirror> ();
+ foreach (var attr in cattrs)
+ if (type == null || attr.Constructor.DeclaringType == type)
+ res.Add (attr);
+ return res.ToArray ();
+ }
+ }
+}
+
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/StackFrame.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/StackFrame.cs
new file mode 100644
index 0000000..c0b4c7b
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/StackFrame.cs
@@ -0,0 +1,208 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mono.Debugger.Soft
+{
+ public class StackFrame : Mirror
+ {
+ ThreadMirror thread;
+ MethodMirror method;
+ int il_offset;
+ Location location;
+ StackFrameFlags flags;
+
+ /*
+ * FIXME: Decide on the way to request/handle debugging information:
+ * - request the info in bulk for all frames/on demand for individual frames
+ * - request the info from the runtime/request only the il offset, and compute
+ * everything else based on this info using the method debug info.
+ */
+
+ internal StackFrame (VirtualMachine vm, long id, ThreadMirror thread, MethodMirror method, int il_offset, StackFrameFlags flags) : base (vm, id) {
+ this.thread = thread;
+ this.method = method;
+ this.il_offset = il_offset;
+ this.flags = flags;
+ }
+
+ public ThreadMirror Thread {
+ get {
+ return thread;
+ }
+ }
+
+ public MethodMirror Method {
+ get {
+ return method;
+ }
+ }
+
+ public Location Location {
+ get {
+ if (location == null) {
+ int line_number;
+ string src_file = null;
+ byte[] hash = null;
+ int column_number = 0;
+
+ if (il_offset == -1)
+ line_number = -1;
+ else
+ line_number = method.il_offset_to_line_number (il_offset, out src_file, out hash, out column_number);
+
+ location = new Location (vm, Method, 0, il_offset, src_file != null ? src_file : method.SourceFile, line_number, column_number, hash);
+ }
+ return location;
+ }
+ }
+
+ public string FileName {
+ get {
+ return Location.SourceFile;
+ }
+ }
+
+ public int ILOffset {
+ get {
+ return Location.ILOffset;
+ }
+ }
+
+ public int LineNumber {
+ get {
+ return Location.LineNumber;
+ }
+ }
+
+ public int ColumnNumber {
+ get {
+ return Location.ColumnNumber;
+ }
+ }
+
+ public bool IsDebuggerInvoke {
+ get {
+ return (flags & StackFrameFlags.DEBUGGER_INVOKE) != 0;
+ }
+ }
+
+ /*
+ * Whenever this frame transitions to native code. The method associated
+ * with the frame is either an InternalCall or a pinvoke method.
+ */
+ public bool IsNativeTransition {
+ get {
+ return (flags & StackFrameFlags.NATIVE_TRANSITION) != 0;
+ }
+ }
+
+ public Value GetValue (ParameterInfoMirror param) {
+ if (param == null)
+ throw new ArgumentNullException ("param");
+ if (param.Method != Method)
+ throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
+ if (param.IsRetval)
+ throw new ArgumentException ("Parameter represents the method return value.");
+
+ // FIXME: Liveness
+ // FIXME: Allow returning the frame return value if possible
+ return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { (- param.Position) - 1 })[0]);
+ }
+
+ public Value GetValue (LocalVariable var) {
+ if (var == null)
+ throw new ArgumentNullException ("var");
+ if (var.Method != Method)
+ throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
+
+ // FIXME: Liveness
+ // FIXME: Check for return value
+ // FIXME: Allow returning the frame return value if possible
+ return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { var.GetValueIndex } )[0]);
+ }
+
+ public Value[] GetValues (LocalVariable[] vars) {
+ if (vars == null)
+ throw new ArgumentNullException ("vars");
+ for (int i = 0; i < vars.Length; ++i) {
+ if (vars [i] == null)
+ throw new ArgumentNullException ("vars");
+ if (vars [i].Method != Method)
+ throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
+ }
+ int[] pos = new int [vars.Length];
+ for (int i = 0; i < vars.Length; ++i)
+ pos [i] = vars [i].GetValueIndex;
+ return vm.DecodeValues (vm.conn.StackFrame_GetValues (thread.Id, Id, pos));
+ }
+
+ public Value GetArgument (int pos) {
+ return GetValue (Method.GetParameters () [pos]);
+ }
+
+ public Value GetThis () {
+ return vm.DecodeValue (vm.conn.StackFrame_GetThis (thread.Id, Id));
+ }
+
+ public void SetValue (LocalVariable var, Value value) {
+ if (var == null)
+ throw new ArgumentNullException ("var");
+ if (var.Method != Method)
+ throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ CheckMirror (value);
+ // FIXME: Liveness
+ // FIXME: Check for return value
+ try {
+ vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { var.GetValueIndex }, new ValueImpl [] { vm.EncodeValue (value) });
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
+ throw new ArgumentException ("Value does not match the type of the local variable.");
+ else
+ throw;
+ }
+ }
+
+ public void SetValue (ParameterInfoMirror param, Value value) {
+ if (param == null)
+ throw new ArgumentNullException ("param");
+ if (param.Method != Method)
+ throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
+ if (param.IsRetval)
+ throw new ArgumentException ("Parameter represents the method return value.");
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ CheckMirror (value);
+
+ // FIXME: Liveness
+ // FIXME: Allow setting the frame return value if possible
+ try {
+ vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { (- param.Position) - 1 }, new ValueImpl [] { vm.EncodeValue (value) });
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
+ throw new ArgumentException ("Value does not match the type of the variable.");
+ else
+ throw;
+ }
+ }
+
+ public IList<LocalVariable> GetVisibleVariables () {
+ if (Location.ILOffset == -1)
+ throw new AbsentInformationException ();
+
+ return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset).ToList ();
+ }
+
+ public LocalVariable GetVisibleVariableByName (string name) {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ if (Location.ILOffset == -1)
+ throw new AbsentInformationException ();
+
+ return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset && l.Name == name).FirstOrDefault ();
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/StepEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/StepEvent.cs
new file mode 100644
index 0000000..5fe3c8b
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/StepEvent.cs
@@ -0,0 +1,27 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class StepEvent : Event {
+ MethodMirror method;
+ long id, loc;
+
+ internal StepEvent (VirtualMachine vm, int req_id, long thread_id, long id, long loc) : base (EventType.Step, vm, req_id, thread_id) {
+ this.id = id;
+ this.loc = loc;
+ }
+
+ public MethodMirror Method {
+ get {
+ if (method == null)
+ method = vm.GetMethod (id);
+ return method;
+ }
+ }
+
+ public long Location {
+ get {
+ return loc;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/StepEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/StepEventRequest.cs
new file mode 100644
index 0000000..035fbce
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/StepEventRequest.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public enum StepDepth {
+ Into = 0,
+ Over = 1,
+ Out = 2
+ }
+
+ public enum StepSize {
+ Min = 0,
+ Line = 1
+ }
+
+ /*
+ * Filter which kinds of methods to skip during single stepping
+ */
+ [Flags]
+ public enum StepFilter {
+ None = 0,
+ StaticCtor = 1,
+ /* Since protocol version 2.20 */
+ /* Methods which have the [DebuggerHidden] attribute */
+ /* Before protocol version 2.26, this includes [DebuggerStepThrough] as well */
+ DebuggerHidden = 2,
+ /* Since protocol version 2.26 */
+ /* Methods which have the [DebuggerStepThrough] attribute */
+ DebuggerStepThrough = 4,
+ }
+
+ public sealed class StepEventRequest : EventRequest {
+
+ ThreadMirror step_thread;
+ StepDepth depth;
+ StepSize size;
+ StepFilter filter;
+
+ internal StepEventRequest (VirtualMachine vm, ThreadMirror thread) : base (vm, EventType.Step) {
+ if (thread == null)
+ throw new ArgumentNullException ("thread");
+ CheckMirror (vm, thread);
+ this.step_thread = thread;
+ Depth = StepDepth.Into;
+ Size = StepSize.Min;
+ }
+
+ public override void Enable () {
+ var mods = new List <Modifier> ();
+ mods.Add (new StepModifier () { Thread = step_thread.Id, Depth = (int)Depth, Size = (int)Size, Filter = (int)Filter });
+ SendReq (mods);
+ }
+
+ public new ThreadMirror Thread {
+ get {
+ return step_thread;
+ }
+ }
+
+ public StepDepth Depth {
+ get {
+ return depth;
+ }
+ set {
+ CheckDisabled ();
+ depth = value;
+ }
+ }
+
+ public StepSize Size {
+ get {
+ return size;
+ }
+ set {
+ CheckDisabled ();
+ size = value;
+ }
+ }
+
+ public StepFilter Filter {
+ get {
+ return filter;
+ }
+ set {
+ CheckDisabled ();
+ filter = value;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/StringMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/StringMirror.cs
new file mode 100644
index 0000000..dea12b5
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/StringMirror.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections;
+
+namespace Mono.Debugger.Soft
+{
+ public class StringMirror : ObjectMirror {
+
+ int length;
+
+ internal StringMirror (VirtualMachine vm, long id) : base (vm, id) {
+ length = -1;
+ }
+
+ internal StringMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id, type, domain) {
+ length = -1;
+ }
+
+ public string Value {
+ get {
+ return vm.conn.String_GetValue (id);
+ }
+ }
+
+ // Since protocol version 2.10
+ public int Length {
+ get {
+ if (length == -1)
+ length = vm.conn.String_GetLength (id);
+ return length;
+ }
+ }
+
+ // Since protocol version 2.10
+ public char[] GetChars (int index, int length) {
+ // re-ordered to avoid possible integer overflow
+ if (index > Length - length)
+ throw new ArgumentException (Locale.GetText (
+ "index and length do not specify a valid range in string."));
+
+ return vm.conn.String_GetChars (id, index, length);
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/StructMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/StructMirror.cs
new file mode 100644
index 0000000..1db6037
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/StructMirror.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * Represents a valuetype value in the debuggee
+ */
+ public class StructMirror : Value {
+
+ TypeMirror type;
+ Value[] fields;
+
+ internal StructMirror (VirtualMachine vm, TypeMirror type, Value[] fields) : base (vm, 0) {
+ this.type = type;
+ this.fields = fields;
+ }
+
+ public TypeMirror Type {
+ get {
+ return type;
+ }
+ }
+
+ public Value[] Fields {
+ get {
+ return fields;
+ }
+ }
+
+ public Value this [String field] {
+ get {
+ FieldInfoMirror[] field_info = Type.GetFields ();
+ int nf = 0;
+ for (int i = 0; i < field_info.Length; ++i) {
+ if (!field_info [i].IsStatic) {
+ if (field_info [i].Name == field)
+ return Fields [nf];
+ nf++;
+ }
+ }
+ throw new ArgumentException ("Unknown struct field '" + field + "'.", "field");
+ }
+ }
+
+ internal void SetField (int index, Value value) {
+ fields [index] = value;
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, this, arguments, InvokeOptions.None);
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, this, arguments, options);
+ }
+
+ [Obsolete ("Use the overload without the 'vm' argument")]
+ public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return ObjectMirror.BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
+ }
+
+ public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return ObjectMirror.BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
+ }
+
+ public Value EndInvokeMethod (IAsyncResult asyncResult) {
+ return ObjectMirror.EndInvokeMethodInternal (asyncResult);
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/SuspendPolicy.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/SuspendPolicy.cs
new file mode 100644
index 0000000..b490ee7
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/SuspendPolicy.cs
@@ -0,0 +1,10 @@
+
+namespace Mono.Debugger.Soft
+{
+ // Keep it in sync with debugger-agent.h
+ public enum SuspendPolicy {
+ None = 0,
+ EventThread = 1,
+ All = 2
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadDeathEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadDeathEvent.cs
new file mode 100644
index 0000000..cf2c8ca
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadDeathEvent.cs
@@ -0,0 +1,8 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class ThreadDeathEvent : Event {
+ internal ThreadDeathEvent (VirtualMachine vm, int req_id, long id) : base (EventType.ThreadDeath, vm, req_id, id) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadMirror.cs
new file mode 100644
index 0000000..1acab89
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadMirror.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public class ThreadMirror : ObjectMirror
+ {
+ string name;
+
+ internal ThreadMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ internal ThreadMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id, type, domain) {
+ }
+
+ // FIXME: Cache, invalidate when the thread/runtime is resumed
+ public StackFrame[] GetFrames () {
+ FrameInfo[] frame_info = vm.conn.Thread_GetFrameInfo (id, 0, -1);
+
+ var frames = new List<StackFrame> ();
+
+ for (int i = 0; i < frame_info.Length; ++i) {
+ FrameInfo info = (FrameInfo)frame_info [i];
+ MethodMirror method = vm.GetMethod (info.method);
+ var f = new StackFrame (vm, info.id, this, method, info.il_offset, info.flags);
+ if (!(f.IsNativeTransition && !NativeTransitions))
+ frames.Add (f);
+ }
+
+ return frames.ToArray ();
+ }
+
+ public string Name {
+ get {
+ if (name == null)
+ name = vm.conn.Thread_GetName (id);
+ return name;
+ }
+ }
+
+ public new long Id {
+ get {
+ return id;
+ }
+ }
+
+ public ThreadState ThreadState {
+ get {
+ return (ThreadState)vm.conn.Thread_GetState (id);
+ }
+ }
+
+ public bool IsThreadPoolThread {
+ get {
+ ThreadInfo info = vm.conn.Thread_GetInfo (id);
+
+ return info.is_thread_pool;
+ }
+ }
+
+ long? thread_id;
+ /*
+ * Return a unique identifier for this thread, multiple ThreadMirror objects
+ * may have the same ThreadId because of appdomains.
+ */
+ public long ThreadId {
+ get {
+ if (thread_id == null)
+ thread_id = vm.conn.Thread_GetId (id);
+ return (long)thread_id;
+ }
+ }
+
+ /*
+ * Return the system thread id (TID) for this thread, this id is not unique since
+ * a newly started thread might reuse a dead thread's id.
+ */
+ public long TID {
+ get {
+ return vm.conn.Thread_GetTID (id);
+ }
+ }
+
+ /*
+ * Get/set whenever GetFrames () should return frames for managed-to-native
+ * transitions, i.e frames whose IsNativeTransition property is set.
+ * This is needed because some clients might not be able to deal with those
+ * frames.
+ */
+ public static bool NativeTransitions {
+ get; set;
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadStartEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadStartEvent.cs
new file mode 100644
index 0000000..92a1cef
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/ThreadStartEvent.cs
@@ -0,0 +1,8 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class ThreadStartEvent : Event {
+ internal ThreadStartEvent (VirtualMachine vm, int req_id, long id) : base (EventType.ThreadStart, vm, req_id, id) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeLoadEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeLoadEvent.cs
new file mode 100644
index 0000000..cd2886f
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeLoadEvent.cs
@@ -0,0 +1,20 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class TypeLoadEvent : Event {
+ TypeMirror type;
+ long id;
+
+ internal TypeLoadEvent (VirtualMachine vm, int req_id, long thread_id, long id) : base (EventType.TypeLoad, vm, req_id, thread_id) {
+ this.id = id;
+ }
+
+ public TypeMirror Type {
+ get {
+ if (type == null)
+ type = vm.GetType (id);
+ return type;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeLoadEventRequest.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeLoadEventRequest.cs
new file mode 100644
index 0000000..130742b
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeLoadEventRequest.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mono.Debugger.Soft
+{
+ public sealed class TypeLoadEventRequest : EventRequest {
+ string[] sourceFiles;
+ string[] typeNames;
+
+ internal TypeLoadEventRequest (VirtualMachine vm) : base (vm, EventType.TypeLoad) {
+ }
+
+ public string[] SourceFileFilter {
+ get {
+ return sourceFiles;
+ }
+ set {
+ CheckDisabled ();
+ sourceFiles = value;
+ }
+ }
+
+ public string[] TypeNameFilter {
+ get {
+ return typeNames;
+ }
+ set {
+ CheckDisabled ();
+ typeNames = value;
+ }
+ }
+
+ public override void Enable () {
+ var mods = new List <Modifier> ();
+ if (SourceFileFilter != null && SourceFileFilter.Length != 0)
+ mods.Add (new SourceFileModifier () { SourceFiles = SourceFileFilter });
+ if (TypeNameFilter != null && TypeNameFilter.Length != 0)
+ mods.Add (new TypeNameModifier () { TypeNames = TypeNameFilter });
+ SendReq (mods);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs
new file mode 100644
index 0000000..125d780
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs
@@ -0,0 +1,868 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using C = Mono.Cecil;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ /*
+ * Represents a type in the remote virtual machine.
+ * It might be better to make this a subclass of Type, but that could be
+ * difficult as some of our methods like GetMethods () return Mirror objects.
+ */
+ public class TypeMirror : Mirror
+ {
+ MethodMirror[] methods;
+ AssemblyMirror ass;
+ ModuleMirror module;
+ C.TypeDefinition meta;
+ FieldInfoMirror[] fields;
+ PropertyInfoMirror[] properties;
+ TypeInfo info;
+ TypeMirror base_type, element_type, gtd;
+ TypeMirror[] nested;
+ CustomAttributeDataMirror[] cattrs;
+ TypeMirror[] ifaces;
+ Dictionary<TypeMirror, InterfaceMappingMirror> iface_map;
+ TypeMirror[] type_args;
+ bool cached_base_type;
+ bool inited;
+
+ internal const BindingFlags DefaultBindingFlags =
+ BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
+
+ internal TypeMirror (VirtualMachine vm, long id) : base (vm, id) {
+ }
+
+ public string Name {
+ get {
+ return GetInfo ().name;
+ }
+ }
+
+ public string Namespace {
+ get {
+ return GetInfo ().ns;
+ }
+ }
+
+ public AssemblyMirror Assembly {
+ get {
+ if (ass == null) {
+ ass = vm.GetAssembly (GetInfo ().assembly);
+ }
+ return ass;
+ }
+ }
+
+ public ModuleMirror Module {
+ get {
+ if (module == null) {
+ module = vm.GetModule (GetInfo ().module);
+ }
+ return module;
+ }
+ }
+
+ public int MetadataToken {
+ get {
+ return GetInfo ().token;
+ }
+ }
+
+ public TypeAttributes Attributes {
+ get {
+ return (TypeAttributes)GetInfo ().attributes;
+ }
+ }
+
+ public TypeMirror BaseType {
+ get {
+ if (!cached_base_type) {
+ base_type = vm.GetType (GetInfo ().base_type);
+ cached_base_type = true;
+ }
+ return base_type;
+ }
+ }
+
+ public int GetArrayRank () {
+ GetInfo ();
+ if (info.rank == 0)
+ throw new ArgumentException ("Type must be an array type.");
+ return info.rank;
+ }
+
+
+ public bool IsAbstract {
+ get {
+ return (Attributes & TypeAttributes.Abstract) != 0;
+ }
+ }
+
+ public bool IsAnsiClass {
+ get {
+ return (Attributes & TypeAttributes.StringFormatMask)
+ == TypeAttributes.AnsiClass;
+ }
+ }
+
+ public bool IsArray {
+ get {
+ return IsArrayImpl ();
+ }
+ }
+
+ public bool IsAutoClass {
+ get {
+ return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
+ }
+ }
+
+ public bool IsAutoLayout {
+ get {
+ return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
+ }
+ }
+
+ public bool IsByRef {
+ get {
+ return IsByRefImpl ();
+ }
+ }
+
+ public bool IsClass {
+ get {
+ if (IsInterface)
+ return false;
+
+ return !IsValueType;
+ }
+ }
+
+ public bool IsCOMObject {
+ get {
+ return IsCOMObjectImpl ();
+ }
+ }
+
+ public bool IsContextful {
+ get {
+ return IsContextfulImpl ();
+ }
+ }
+
+ public bool IsEnum {
+ get {
+ return GetInfo ().is_enum;
+ }
+ }
+
+ public bool IsExplicitLayout {
+ get {
+ return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
+ }
+ }
+
+ public bool IsImport {
+ get {
+ return (Attributes & TypeAttributes.Import) != 0;
+ }
+ }
+
+ public bool IsInterface {
+ get {
+ return (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
+ }
+ }
+
+ public bool IsLayoutSequential {
+ get {
+ return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
+ }
+ }
+
+ public bool IsMarshalByRef {
+ get {
+ return IsMarshalByRefImpl ();
+ }
+ }
+
+ public bool IsNestedAssembly {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
+ }
+ }
+
+ public bool IsNestedFamANDAssem {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
+ }
+ }
+
+ public bool IsNestedFamily {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
+ }
+ }
+
+ public bool IsNestedFamORAssem {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
+ }
+ }
+
+ public bool IsNestedPrivate {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
+ }
+ }
+
+ public bool IsNestedPublic {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
+ }
+ }
+
+ public bool IsNotPublic {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
+ }
+ }
+
+ public bool IsPointer {
+ get {
+ return IsPointerImpl ();
+ }
+ }
+
+ public bool IsPrimitive {
+ get {
+ return IsPrimitiveImpl ();
+ }
+ }
+
+ public bool IsPublic {
+ get {
+ return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
+ }
+ }
+
+ public bool IsSealed {
+ get {
+ return (Attributes & TypeAttributes.Sealed) != 0;
+ }
+ }
+
+ public bool IsSerializable {
+ get {
+ if ((Attributes & TypeAttributes.Serializable) != 0)
+ return true;
+
+ // FIXME:
+ return false;
+ }
+ }
+
+ public bool IsSpecialName {
+ get {
+ return (Attributes & TypeAttributes.SpecialName) != 0;
+ }
+ }
+
+ public bool IsUnicodeClass {
+ get {
+ return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
+ }
+ }
+
+ public bool IsValueType {
+ get {
+ return IsValueTypeImpl ();
+ }
+ }
+
+ public bool HasElementType {
+ get {
+ return HasElementTypeImpl ();
+ }
+ }
+
+ // Since protocol version 2.12
+ public bool IsGenericTypeDefinition {
+ get {
+ vm.CheckProtocolVersion (2, 12);
+ GetInfo ();
+ return info.is_gtd;
+ }
+ }
+
+ public bool IsGenericType {
+ get {
+ if (vm.Version.AtLeast (2, 12)) {
+ return GetInfo ().is_generic_type;
+ } else {
+ return Name.IndexOf ('`') != -1;
+ }
+ }
+ }
+
+ public TypeMirror GetElementType () {
+ GetInfo ();
+ if (element_type == null && info.element_type != 0)
+ element_type = vm.GetType (info.element_type);
+ return element_type;
+ }
+
+ public TypeMirror GetGenericTypeDefinition () {
+ vm.CheckProtocolVersion (2, 12);
+ GetInfo ();
+ if (gtd == null) {
+ if (info.gtd == 0)
+ throw new InvalidOperationException ();
+ gtd = vm.GetType (info.gtd);
+ }
+ return gtd;
+ }
+
+ // Since protocol version 2.15
+ public TypeMirror[] GetGenericArguments () {
+ vm.CheckProtocolVersion (2, 15);
+ if (type_args == null)
+ type_args = vm.GetTypes (GetInfo ().type_args);
+ return type_args;
+ }
+
+ public string FullName {
+ get {
+ return GetInfo ().full_name;
+ }
+ }
+
+ public string CSharpName {
+ get {
+ if (IsArray) {
+ if (GetArrayRank () == 1)
+ return GetElementType ().CSharpName + "[]";
+ else {
+ string ranks = "";
+ for (int i = 0; i < GetArrayRank (); ++i)
+ ranks += ',';
+ return GetElementType ().CSharpName + "[" + ranks + "]";
+ }
+ }
+ if (IsPrimitive) {
+ switch (Name) {
+ case "Byte":
+ return "byte";
+ case "Sbyte":
+ return "sbyte";
+ case "Char":
+ return "char";
+ case "UInt16":
+ return "ushort";
+ case "Int16":
+ return "short";
+ case "UInt32":
+ return "uint";
+ case "Int32":
+ return "int";
+ case "UInt64":
+ return "ulong";
+ case "Int64":
+ return "long";
+ case "Single":
+ return "float";
+ case "Double":
+ return "double";
+ case "Boolean":
+ return "bool";
+ default:
+ return FullName;
+ }
+ }
+ // FIXME: Only do this for real corlib types
+ if (Namespace == "System") {
+ string s = Name;
+ switch (s) {
+ case "Decimal":
+ return "decimal";
+ case "Object":
+ return "object";
+ case "String":
+ return "string";
+ default:
+ return FullName;
+ }
+ } else {
+ return FullName;
+ }
+ }
+ }
+
+ public MethodMirror[] GetMethods () {
+ if (methods == null) {
+ long[] ids = vm.conn.Type_GetMethods (id);
+ MethodMirror[] m = new MethodMirror [ids.Length];
+ for (int i = 0; i < ids.Length; ++i) {
+ m [i] = vm.GetMethod (ids [i]);
+ }
+ methods = m;
+ }
+ return methods;
+ }
+
+ // FIXME: Sync this with Type
+ public MethodMirror GetMethod (string name) {
+ foreach (var m in GetMethods ())
+ if (m.Name == name)
+ return m;
+ return null;
+ }
+
+ public FieldInfoMirror[] GetFields () {
+ if (fields != null)
+ return fields;
+
+ string[] names;
+ long[] types;
+ int[] attrs;
+ long[] ids = vm.conn.Type_GetFields (id, out names, out types, out attrs);
+
+ FieldInfoMirror[] res = new FieldInfoMirror [ids.Length];
+ for (int i = 0; i < res.Length; ++i)
+ res [i] = new FieldInfoMirror (this, ids [i], names [i], vm.GetType (types [i]), (FieldAttributes)attrs [i]);
+
+ fields = res;
+ return fields;
+ }
+
+ public FieldInfoMirror GetField (string name) {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+ foreach (var f in GetFields ())
+ if (f.Name == name)
+ return f;
+ return null;
+ }
+
+ public TypeMirror[] GetNestedTypes ()
+ {
+ return GetNestedTypes (DefaultBindingFlags);
+ }
+
+ public TypeMirror[] GetNestedTypes (BindingFlags bindingAttr) {
+ if (nested != null)
+ return nested;
+
+ // FIXME: bindingAttr
+ GetInfo ();
+ var arr = new TypeMirror [info.nested.Length];
+ for (int i = 0; i < arr.Length; ++i)
+ arr [i] = vm.GetType (info.nested [i]);
+ nested = arr;
+
+ return nested;
+ }
+
+ public PropertyInfoMirror[] GetProperties () {
+ return GetProperties (DefaultBindingFlags);
+ }
+
+ public PropertyInfoMirror[] GetProperties (BindingFlags bindingAttr) {
+ if (properties != null)
+ return properties;
+
+ PropInfo[] info = vm.conn.Type_GetProperties (id);
+
+ PropertyInfoMirror[] res = new PropertyInfoMirror [info.Length];
+ for (int i = 0; i < res.Length; ++i)
+ res [i] = new PropertyInfoMirror (this, info [i].id, info [i].name, vm.GetMethod (info [i].get_method), vm.GetMethod (info [i].set_method), (PropertyAttributes)info [i].attrs);
+
+ properties = res;
+ return properties;
+ }
+
+ public PropertyInfoMirror GetProperty (string name) {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+ foreach (var p in GetProperties ())
+ if (p.Name == name)
+ return p;
+ return null;
+ }
+
+ public virtual bool IsAssignableFrom (TypeMirror c) {
+ if (c == null)
+ throw new ArgumentNullException ("c");
+
+ CheckMirror (c);
+
+ // This is complex so do it in the debuggee
+ return vm.conn.Type_IsAssignableFrom (id, c.Id);
+ }
+
+ public Value GetValue (FieldInfoMirror field) {
+ return GetValues (new FieldInfoMirror [] { field }) [0];
+ }
+
+ public Value[] GetValues (IList<FieldInfoMirror> fields, ThreadMirror thread) {
+ if (fields == null)
+ throw new ArgumentNullException ("fields");
+ foreach (FieldInfoMirror f in fields) {
+ if (f == null)
+ throw new ArgumentNullException ("field");
+ CheckMirror (f);
+ }
+ long[] ids = new long [fields.Count];
+ for (int i = 0; i < fields.Count; ++i)
+ ids [i] = fields [i].Id;
+ try {
+ return vm.DecodeValues (vm.conn.Type_GetValues (id, ids, thread != null ? thread.Id : 0));
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
+ throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
+ else
+ throw;
+ }
+ }
+
+ public Value[] GetValues (IList<FieldInfoMirror> fields) {
+ return GetValues (fields, null);
+ }
+
+ /*
+ * Return the value of the [ThreadStatic] field FIELD on the thread THREAD.
+ */
+ public Value GetValue (FieldInfoMirror field, ThreadMirror thread) {
+ if (thread == null)
+ throw new ArgumentNullException ("thread");
+ CheckMirror (thread);
+ return GetValues (new FieldInfoMirror [] { field }, thread) [0];
+ }
+
+ public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
+ if (fields == null)
+ throw new ArgumentNullException ("fields");
+ if (values == null)
+ throw new ArgumentNullException ("values");
+ foreach (FieldInfoMirror f in fields) {
+ if (f == null)
+ throw new ArgumentNullException ("field");
+ CheckMirror (f);
+ }
+ foreach (Value v in values) {
+ if (v == null)
+ throw new ArgumentNullException ("values");
+ CheckMirror (v);
+ }
+ long[] ids = new long [fields.Count];
+ for (int i = 0; i < fields.Count; ++i)
+ ids [i] = fields [i].Id;
+ try {
+ vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
+ throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
+ else
+ throw;
+ }
+ }
+
+ public void SetValue (FieldInfoMirror field, Value value) {
+ SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
+ }
+
+ public ObjectMirror GetTypeObject () {
+ return vm.GetObject (vm.conn.Type_GetObject (id));
+ }
+
+ /*
+ * Return a list of source files without path info, where methods of
+ * this type are defined. Return an empty list if the information is not
+ * available.
+ * This can be used by a debugger to find out which types occur in a
+ * given source file, to filter the list of methods whose locations
+ * have to be checked when placing breakpoints.
+ */
+ public string[] GetSourceFiles () {
+ return GetSourceFiles (false);
+ }
+
+ string[] source_files;
+ string[] source_files_full_path;
+ public string[] GetSourceFiles (bool returnFullPaths) {
+ string[] res = returnFullPaths ? source_files_full_path : source_files;
+ if (res == null) {
+ res = vm.conn.Type_GetSourceFiles (id, returnFullPaths);
+ if (returnFullPaths)
+ source_files_full_path = res;
+ else
+ source_files = res;
+ }
+ return res;
+ }
+
+ public C.TypeDefinition Metadata {
+ get {
+ if (meta == null) {
+ if (Assembly.Metadata == null || MetadataToken == 0)
+ return null;
+ meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
+ }
+ return meta;
+ }
+ }
+
+ TypeInfo GetInfo () {
+ if (info == null)
+ info = vm.conn.Type_GetInfo (id);
+ return info;
+ }
+
+ protected virtual TypeAttributes GetAttributeFlagsImpl () {
+ return (TypeAttributes)GetInfo ().attributes;
+ }
+
+ protected virtual bool HasElementTypeImpl () {
+ return IsArray || IsByRef || IsPointer;
+ }
+
+ protected virtual bool IsArrayImpl () {
+ return GetInfo ().rank > 0;
+ }
+
+ protected virtual bool IsByRefImpl () {
+ return GetInfo ().is_byref;
+ }
+
+ protected virtual bool IsCOMObjectImpl () {
+ return false;
+ }
+
+ protected virtual bool IsPointerImpl () {
+ return GetInfo ().is_pointer;
+ }
+
+ protected virtual bool IsPrimitiveImpl () {
+ return GetInfo ().is_primitive;
+ }
+
+ protected virtual bool IsValueTypeImpl ()
+ {
+ return GetInfo ().is_valuetype;
+ }
+
+ protected virtual bool IsContextfulImpl ()
+ {
+ // FIXME:
+ return false;
+ }
+
+ protected virtual bool IsMarshalByRefImpl ()
+ {
+ // FIXME:
+ return false;
+ }
+
+ // Same as Enum.GetUnderlyingType ()
+ public TypeMirror EnumUnderlyingType {
+ get {
+ if (!IsEnum)
+ throw new ArgumentException ("Type is not an enum type.");
+ foreach (FieldInfoMirror f in GetFields ()) {
+ if (!f.IsStatic)
+ return f.FieldType;
+ }
+ throw new NotImplementedException ();
+ }
+ }
+
+ /*
+ * Creating the custom attributes themselves could modify the behavior of the
+ * debuggee, so we return objects similar to the CustomAttributeData objects
+ * used by the reflection-only functionality on .net.
+ */
+ public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
+ return GetCustomAttrs (null, inherit);
+ }
+
+ public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
+ if (attributeType == null)
+ throw new ArgumentNullException ("attributeType");
+ return GetCustomAttrs (attributeType, inherit);
+ }
+
+ void AppendCustomAttrs (IList<CustomAttributeDataMirror> attrs, TypeMirror type, bool inherit)
+ {
+ if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
+ cattrs = new CustomAttributeDataMirror [0];
+
+ if (cattrs == null) {
+ CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
+ cattrs = CustomAttributeDataMirror.Create (vm, info);
+ }
+
+ foreach (var attr in cattrs) {
+ if (type == null || attr.Constructor.DeclaringType == type)
+ attrs.Add (attr);
+ }
+
+ if (inherit && BaseType != null)
+ BaseType.AppendCustomAttrs (attrs, type, inherit);
+ }
+
+ CustomAttributeDataMirror[] GetCustomAttrs (TypeMirror type, bool inherit) {
+ var attrs = new List<CustomAttributeDataMirror> ();
+ AppendCustomAttrs (attrs, type, inherit);
+ return attrs.ToArray ();
+ }
+
+ public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
+ if (vm.conn.Version.AtLeast (2, 6)) {
+ long[] ids = vm.conn.Type_GetMethodsByNameFlags (id, name, (int)flags, ignoreCase);
+ MethodMirror[] m = new MethodMirror [ids.Length];
+ for (int i = 0; i < ids.Length; ++i)
+ m [i] = vm.GetMethod (ids [i]);
+ return m;
+ } else {
+ if ((flags & BindingFlags.IgnoreCase) != 0) {
+ flags &= ~BindingFlags.IgnoreCase;
+ ignoreCase = true;
+ }
+
+ if (flags == BindingFlags.Default)
+ flags = BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static;
+
+ MethodAttributes access = (MethodAttributes) 0;
+ bool matchInstance = false;
+ bool matchStatic = false;
+
+ if ((flags & BindingFlags.NonPublic) != 0) {
+ access |= MethodAttributes.Private;
+ flags &= ~BindingFlags.NonPublic;
+ }
+ if ((flags & BindingFlags.Public) != 0) {
+ access |= MethodAttributes.Public;
+ flags &= ~BindingFlags.Public;
+ }
+ if ((flags & BindingFlags.Instance) != 0) {
+ flags &= ~BindingFlags.Instance;
+ matchInstance = true;
+ }
+ if ((flags & BindingFlags.Static) != 0) {
+ flags &= ~BindingFlags.Static;
+ matchStatic = true;
+ }
+
+ if ((int) flags != 0)
+ throw new NotImplementedException ();
+
+ var res = new List<MethodMirror> ();
+ foreach (MethodMirror m in GetMethods ()) {
+ if ((m.Attributes & access) == (MethodAttributes) 0)
+ continue;
+
+ if (!((matchStatic && m.IsStatic) || (matchInstance && !m.IsStatic)))
+ continue;
+
+ if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
+ res.Add (m);
+ }
+ return res.ToArray ();
+ }
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
+ }
+
+ public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
+ }
+
+ [Obsolete ("Use the overload without the 'vm' argument")]
+ public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
+ }
+
+ public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
+ return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
+ }
+
+ public Value EndInvokeMethod (IAsyncResult asyncResult) {
+ return ObjectMirror.EndInvokeMethodInternal (asyncResult);
+ }
+
+ public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
+ }
+
+ public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
+ return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
+ }
+
+ // Since protocol version 2.11
+ public TypeMirror[] GetInterfaces () {
+ if (ifaces == null)
+ ifaces = vm.GetTypes (vm.conn.Type_GetInterfaces (id));
+ return ifaces;
+ }
+
+ // Since protocol version 2.11
+ public InterfaceMappingMirror GetInterfaceMap (TypeMirror interfaceType) {
+ if (interfaceType == null)
+ throw new ArgumentNullException ("interfaceType");
+ if (!interfaceType.IsInterface)
+ throw new ArgumentException ("Argument must be an interface.", "interfaceType");
+ if (IsInterface)
+ throw new ArgumentException ("'this' type cannot be an interface itself");
+
+ if (iface_map == null) {
+ // Query the info in bulk
+ GetInterfaces ();
+ var ids = new long [ifaces.Length];
+ for (int i = 0; i < ifaces.Length; ++i)
+ ids [i] = ifaces [i].Id;
+
+ var ifacemap = vm.conn.Type_GetInterfaceMap (id, ids);
+
+ var imap = new Dictionary<TypeMirror, InterfaceMappingMirror> ();
+ for (int i = 0; i < ifacemap.Length; ++i) {
+ IfaceMapInfo info = ifacemap [i];
+
+ MethodMirror[] imethods = new MethodMirror [info.iface_methods.Length];
+ for (int j = 0; j < info.iface_methods.Length; ++j)
+ imethods [j] = vm.GetMethod (info.iface_methods [j]);
+
+ MethodMirror[] tmethods = new MethodMirror [info.iface_methods.Length];
+ for (int j = 0; j < info.target_methods.Length; ++j)
+ tmethods [j] = vm.GetMethod (info.target_methods [j]);
+
+ InterfaceMappingMirror map = new InterfaceMappingMirror (vm, this, vm.GetType (info.iface_id), imethods, tmethods);
+
+ imap [map.InterfaceType] = map;
+ }
+
+ iface_map = imap;
+ }
+
+ InterfaceMappingMirror res;
+ if (!iface_map.TryGetValue (interfaceType, out res))
+ throw new ArgumentException ("Interface not found", "interfaceType");
+ return res;
+ }
+
+ // Return whenever the type initializer of this type has ran
+ // Since protocol version 2.23
+ public bool IsInitialized {
+ get {
+ vm.CheckProtocolVersion (2, 23);
+ if (!inited)
+ inited = vm.conn.Type_IsInitialized (id);
+ return inited;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/UserBreakEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/UserBreakEvent.cs
new file mode 100644
index 0000000..4303dbc
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/UserBreakEvent.cs
@@ -0,0 +1,8 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class UserBreakEvent : Event {
+ internal UserBreakEvent (VirtualMachine vm, int req_id, long thread_id) : base (EventType.UserBreak, vm, req_id, thread_id) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/UserLogEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/UserLogEvent.cs
new file mode 100644
index 0000000..4b4b4b4
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/UserLogEvent.cs
@@ -0,0 +1,33 @@
+
+namespace Mono.Debugger.Soft
+{
+ public class UserLogEvent : Event {
+
+ int level;
+ string category, message;
+
+ internal UserLogEvent (VirtualMachine vm, int req_id, long thread_id, int level, string category, string message) : base (EventType.UserLog, vm, req_id, thread_id) {
+ this.level = level;
+ this.category = category;
+ this.message = message;
+ }
+
+ public int Level {
+ get {
+ return level;
+ }
+ }
+
+ public string Category {
+ get {
+ return category;
+ }
+ }
+
+ public string Message {
+ get {
+ return message;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDeathEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDeathEvent.cs
new file mode 100644
index 0000000..18eeb92
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDeathEvent.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class VMDeathEvent : Event
+ {
+ public VMDeathEvent (VirtualMachine vm, int req_id) : base (EventType.VMDeath, vm, req_id, -1) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectEvent.cs
new file mode 100644
index 0000000..7157fa2
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectEvent.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class VMDisconnectEvent : Event
+ {
+ public VMDisconnectEvent (VirtualMachine vm, int req_id) : base (EventType.VMDisconnect, vm, req_id, -1) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs
new file mode 100644
index 0000000..d26b1be
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMDisconnectedException.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class VMDisconnectedException : Exception {
+
+ public VMDisconnectedException () : base () {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VMMismatchException.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMMismatchException.cs
new file mode 100644
index 0000000..2d3fd81
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMMismatchException.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class VMMismatchException : Exception
+ {
+ public VMMismatchException () : base () {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VMStartEvent.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMStartEvent.cs
new file mode 100644
index 0000000..f694828
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VMStartEvent.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mono.Debugger.Soft
+{
+ public class VMStartEvent : Event
+ {
+ public VMStartEvent (VirtualMachine vm, int req_id, long thread_id) : base (EventType.VMStart, vm, req_id, thread_id) {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Value.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Value.cs
new file mode 100644
index 0000000..67e187b
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Value.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mono.Debugger.Soft
+{
+ public abstract class Value : Mirror {
+
+ // FIXME: Add a 'Value' field
+
+ internal Value (VirtualMachine vm, long id) : base (vm, id) {
+ }
+ }
+}
+
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
new file mode 100644
index 0000000..b77458b
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
@@ -0,0 +1,701 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Net;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+using Mono.Cecil.Metadata;
+
+namespace Mono.Debugger.Soft
+{
+ public class VirtualMachine : Mirror
+ {
+ Queue queue;
+ object queue_monitor;
+ object startup_monitor;
+ AppDomainMirror root_domain;
+ Dictionary<int, EventRequest> requests;
+ ITargetProcess process;
+
+ internal Connection conn;
+
+ VersionInfo version;
+
+ internal VirtualMachine (ITargetProcess process, Connection conn) : base () {
+ SetVirtualMachine (this);
+ queue = new Queue ();
+ queue_monitor = new Object ();
+ startup_monitor = new Object ();
+ requests = new Dictionary <int, EventRequest> ();
+ this.conn = conn;
+ this.process = process;
+ conn.ErrorHandler += ErrorHandler;
+ }
+
+ // The standard output of the process is available normally through Process
+ public StreamReader StandardOutput { get; set; }
+ public StreamReader StandardError { get; set; }
+
+
+ public Process Process {
+ get {
+ ProcessWrapper pw = process as ProcessWrapper;
+ if (pw == null)
+ throw new InvalidOperationException ("Process instance not available");
+ return pw.Process;
+ }
+ }
+
+ public ITargetProcess TargetProcess {
+ get {
+ return process;
+ }
+ }
+
+ public AppDomainMirror RootDomain {
+ get {
+ return root_domain;
+ }
+ }
+
+ public EndPoint EndPoint {
+ get {
+ var tcpConn = conn as TcpConnection;
+ if (tcpConn != null)
+ return tcpConn.EndPoint;
+ return null;
+ }
+ }
+
+ public VersionInfo Version {
+ get {
+ return version;
+ }
+ }
+
+ EventSet current_es;
+ int current_es_index;
+
+ /*
+ * It is impossible to determine when to resume when using this method, since
+ * the debuggee is suspended only once per event-set, not event.
+ */
+ [Obsolete ("Use GetNextEventSet () instead")]
+ public Event GetNextEvent () {
+ lock (queue_monitor) {
+ if (current_es == null || current_es_index == current_es.Events.Length) {
+ if (queue.Count == 0)
+ Monitor.Wait (queue_monitor);
+ current_es = (EventSet)queue.Dequeue ();
+ current_es_index = 0;
+ }
+ return current_es.Events [current_es_index ++];
+ }
+ }
+
+ public Event GetNextEvent (int timeout) {
+ throw new NotImplementedException ();
+ }
+
+ public EventSet GetNextEventSet () {
+ lock (queue_monitor) {
+ if (queue.Count == 0)
+ Monitor.Wait (queue_monitor);
+
+ current_es = null;
+ current_es_index = 0;
+
+ return (EventSet)queue.Dequeue ();
+ }
+ }
+
+ [Obsolete ("Use GetNextEventSet () instead")]
+ public T GetNextEvent<T> () where T : Event {
+ return GetNextEvent () as T;
+ }
+
+ public void Suspend () {
+ conn.VM_Suspend ();
+ }
+
+ public void Resume () {
+ try {
+ conn.VM_Resume ();
+ } catch (CommandException ex) {
+ if (ex.ErrorCode == ErrorCode.NOT_SUSPENDED)
+ throw new VMNotSuspendedException ();
+ else
+ throw;
+ }
+ }
+
+ public void Exit (int exitCode) {
+ conn.VM_Exit (exitCode);
+ }
+
+ public void Detach () {
+ conn.VM_Dispose ();
+ conn.Close ();
+ notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, 0, 0, null);
+ }
+
+ [Obsolete ("This method was poorly named; use the Detach() method instead")]
+ public void Dispose ()
+ {
+ Detach ();
+ }
+
+ public void ForceDisconnect ()
+ {
+ conn.ForceDisconnect ();
+ }
+
+ public IList<ThreadMirror> GetThreads () {
+ long[] ids = vm.conn.VM_GetThreads ();
+ ThreadMirror[] res = new ThreadMirror [ids.Length];
+ for (int i = 0; i < ids.Length; ++i)
+ res [i] = GetThread (ids [i]);
+ return res;
+ }
+
+ // Same as the mirrorOf methods in JDI
+ public PrimitiveValue CreateValue (object value) {
+ if (value == null)
+ return new PrimitiveValue (vm, null);
+
+ if (!value.GetType ().IsPrimitive)
+ throw new ArgumentException ("value must be of a primitive type instead of '" + value.GetType () + "'", "value");
+
+ return new PrimitiveValue (vm, value);
+ }
+
+ public EnumMirror CreateEnumMirror (TypeMirror type, PrimitiveValue value) {
+ return new EnumMirror (this, type, value);
+ }
+
+ //
+ // Enable send and receive timeouts on the connection and send a keepalive event
+ // every 'keepalive_interval' milliseconds.
+ //
+
+ public void SetSocketTimeouts (int send_timeout, int receive_timeout, int keepalive_interval)
+ {
+ conn.SetSocketTimeouts (send_timeout, receive_timeout, keepalive_interval);
+ }
+
+ //
+ // Methods to create event request objects
+ //
+ public BreakpointEventRequest CreateBreakpointRequest (MethodMirror method, long il_offset) {
+ return new BreakpointEventRequest (this, method, il_offset);
+ }
+
+ public BreakpointEventRequest CreateBreakpointRequest (Location loc) {
+ if (loc == null)
+ throw new ArgumentNullException ("loc");
+ CheckMirror (loc);
+ return new BreakpointEventRequest (this, loc.Method, loc.ILOffset);
+ }
+
+ public StepEventRequest CreateStepRequest (ThreadMirror thread) {
+ return new StepEventRequest (this, thread);
+ }
+
+ public MethodEntryEventRequest CreateMethodEntryRequest () {
+ return new MethodEntryEventRequest (this);
+ }
+
+ public MethodExitEventRequest CreateMethodExitRequest () {
+ return new MethodExitEventRequest (this);
+ }
+
+ public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type) {
+ return new ExceptionEventRequest (this, exc_type, true, true);
+ }
+
+ public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type, bool caught, bool uncaught) {
+ return new ExceptionEventRequest (this, exc_type, caught, uncaught);
+ }
+
+ public AssemblyLoadEventRequest CreateAssemblyLoadRequest () {
+ return new AssemblyLoadEventRequest (this);
+ }
+
+ public TypeLoadEventRequest CreateTypeLoadRequest () {
+ return new TypeLoadEventRequest (this);
+ }
+
+ public void EnableEvents (params EventType[] events) {
+ foreach (EventType etype in events) {
+ if (etype == EventType.Breakpoint)
+ throw new ArgumentException ("Breakpoint events cannot be requested using EnableEvents", "events");
+ conn.EnableEvent (etype, SuspendPolicy.All, null);
+ }
+ }
+
+ public BreakpointEventRequest SetBreakpoint (MethodMirror method, long il_offset) {
+ BreakpointEventRequest req = CreateBreakpointRequest (method, il_offset);
+
+ req.Enable ();
+
+ return req;
+ }
+
+ public void ClearAllBreakpoints () {
+ conn.ClearAllBreakpoints ();
+ }
+
+ public void Disconnect () {
+ conn.Close ();
+ }
+
+ //
+ // Return a list of TypeMirror objects for all loaded types which reference the
+ // source file FNAME. Might return false positives.
+ // Since protocol version 2.7.
+ //
+ public IList<TypeMirror> GetTypesForSourceFile (string fname, bool ignoreCase) {
+ long[] ids = conn.VM_GetTypesForSourceFile (fname, ignoreCase);
+ var res = new TypeMirror [ids.Length];
+ for (int i = 0; i < ids.Length; ++i)
+ res [i] = GetType (ids [i]);
+ return res;
+ }
+
+ //
+ // Return a list of TypeMirror objects for all loaded types named 'NAME'.
+ // NAME should be in the the same for as with Assembly.GetType ().
+ // Since protocol version 2.9.
+ //
+ public IList<TypeMirror> GetTypes (string name, bool ignoreCase) {
+ long[] ids = conn.VM_GetTypes (name, ignoreCase);
+ var res = new TypeMirror [ids.Length];
+ for (int i = 0; i < ids.Length; ++i)
+ res [i] = GetType (ids [i]);
+ return res;
+ }
+
+ internal void queue_event_set (EventSet es) {
+ lock (queue_monitor) {
+ queue.Enqueue (es);
+ Monitor.Pulse (queue_monitor);
+ }
+ }
+
+ internal void ErrorHandler (object sender, ErrorHandlerEventArgs args) {
+ switch (args.ErrorCode) {
+ case ErrorCode.INVALID_OBJECT:
+ throw new ObjectCollectedException ();
+ case ErrorCode.INVALID_FRAMEID:
+ throw new InvalidStackFrameException ();
+ case ErrorCode.NOT_SUSPENDED:
+ throw new VMNotSuspendedException ();
+ case ErrorCode.NOT_IMPLEMENTED:
+ throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
+ case ErrorCode.ABSENT_INFORMATION:
+ throw new AbsentInformationException ();
+ case ErrorCode.NO_SEQ_POINT_AT_IL_OFFSET:
+ throw new ArgumentException ("Cannot set breakpoint on the specified IL offset.");
+ default:
+ throw new CommandException (args.ErrorCode);
+ }
+ }
+
+ /* Wait for the debuggee to start up and connect to it */
+ internal void connect () {
+ conn.Connect ();
+
+ // Test the connection
+ version = conn.Version;
+ if (version.MajorVersion != Connection.MAJOR_VERSION)
+ throw new NotSupportedException (String.Format ("The debuggee implements protocol version {0}.{1}, while {2}.{3} is required.", version.MajorVersion, version.MinorVersion, Connection.MAJOR_VERSION, Connection.MINOR_VERSION));
+
+ long root_domain_id = conn.RootDomain;
+ root_domain = GetDomain (root_domain_id);
+ }
+
+ internal void notify_vm_event (EventType evtype, SuspendPolicy spolicy, int req_id, long thread_id, string vm_uri) {
+ //Console.WriteLine ("Event: " + evtype + "(" + vm_uri + ")");
+
+ switch (evtype) {
+ case EventType.VMStart:
+ /* Notify the main thread that the debuggee started up */
+ lock (startup_monitor) {
+ Monitor.Pulse (startup_monitor);
+ }
+ queue_event_set (new EventSet (this, spolicy, new Event[] { new VMStartEvent (vm, req_id, thread_id) }));
+ break;
+ case EventType.VMDeath:
+ queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDeathEvent (vm, req_id) }));
+ break;
+ case EventType.VMDisconnect:
+ queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDisconnectEvent (vm, req_id) }));
+ break;
+ default:
+ throw new Exception ();
+ }
+ }
+
+ //
+ // Methods to create instances of mirror objects
+ //
+
+ /*
+ class MirrorCache<T> {
+ static Dictionary <long, T> mirrors;
+ static object mirror_lock = new object ();
+
+ internal static T GetMirror (VirtualMachine vm, long id) {
+ lock (mirror_lock) {
+ if (mirrors == null)
+ mirrors = new Dictionary <long, T> ();
+ T obj;
+ if (!mirrors.TryGetValue (id, out obj)) {
+ obj = CreateMirror (vm, id);
+ mirrors [id] = obj;
+ }
+ return obj;
+ }
+ }
+
+ internal static T CreateMirror (VirtualMachine vm, long id) {
+ }
+ }
+ */
+
+ // FIXME: When to remove items from the cache ?
+
+ Dictionary <long, MethodMirror> methods;
+ object methods_lock = new object ();
+
+ internal MethodMirror GetMethod (long id) {
+ lock (methods_lock) {
+ if (methods == null)
+ methods = new Dictionary <long, MethodMirror> ();
+ MethodMirror obj;
+ if (id == 0)
+ return null;
+ if (!methods.TryGetValue (id, out obj)) {
+ obj = new MethodMirror (this, id);
+ methods [id] = obj;
+ }
+ return obj;
+ }
+ }
+
+ Dictionary <long, AssemblyMirror> assemblies;
+ object assemblies_lock = new object ();
+
+ internal AssemblyMirror GetAssembly (long id) {
+ lock (assemblies_lock) {
+ if (assemblies == null)
+ assemblies = new Dictionary <long, AssemblyMirror> ();
+ AssemblyMirror obj;
+ if (id == 0)
+ return null;
+ if (!assemblies.TryGetValue (id, out obj)) {
+ obj = new AssemblyMirror (this, id);
+ assemblies [id] = obj;
+ }
+ return obj;
+ }
+ }
+
+ Dictionary <long, ModuleMirror> modules;
+ object modules_lock = new object ();
+
+ internal ModuleMirror GetModule (long id) {
+ lock (modules_lock) {
+ if (modules == null)
+ modules = new Dictionary <long, ModuleMirror> ();
+ ModuleMirror obj;
+ if (id == 0)
+ return null;
+ if (!modules.TryGetValue (id, out obj)) {
+ obj = new ModuleMirror (this, id);
+ modules [id] = obj;
+ }
+ return obj;
+ }
+ }
+
+ Dictionary <long, AppDomainMirror> domains;
+ object domains_lock = new object ();
+
+ internal AppDomainMirror GetDomain (long id) {
+ lock (domains_lock) {
+ if (domains == null)
+ domains = new Dictionary <long, AppDomainMirror> ();
+ AppDomainMirror obj;
+ if (id == 0)
+ return null;
+ if (!domains.TryGetValue (id, out obj)) {
+ obj = new AppDomainMirror (this, id);
+ domains [id] = obj;
+ }
+ return obj;
+ }
+ }
+
+ Dictionary <long, TypeMirror> types;
+ object types_lock = new object ();
+
+ internal TypeMirror GetType (long id) {
+ lock (types_lock) {
+ if (types == null)
+ types = new Dictionary <long, TypeMirror> ();
+ TypeMirror obj;
+ if (id == 0)
+ return null;
+ if (!types.TryGetValue (id, out obj)) {
+ obj = new TypeMirror (this, id);
+ types [id] = obj;
+ }
+ return obj;
+ }
+ }
+
+ internal TypeMirror[] GetTypes (long[] ids) {
+ var res = new TypeMirror [ids.Length];
+ for (int i = 0; i < ids.Length; ++i)
+ res [i] = GetType (ids [i]);
+ return res;
+ }
+
+ Dictionary <long, ObjectMirror> objects;
+ object objects_lock = new object ();
+
+ internal T GetObject<T> (long id, long domain_id, long type_id) where T : ObjectMirror {
+ lock (objects_lock) {
+ if (objects == null)
+ objects = new Dictionary <long, ObjectMirror> ();
+ ObjectMirror obj;
+ if (!objects.TryGetValue (id, out obj)) {
+ /*
+ * Obtain the domain/type of the object to determine the type of
+ * object we need to create.
+ */
+ if (domain_id == 0 || type_id == 0) {
+ if (conn.Version.AtLeast (2, 5)) {
+ var info = conn.Object_GetInfo (id);
+ domain_id = info.domain_id;
+ type_id = info.type_id;
+ } else {
+ if (domain_id == 0)
+ domain_id = conn.Object_GetDomain (id);
+ if (type_id == 0)
+ type_id = conn.Object_GetType (id);
+ }
+ }
+ AppDomainMirror d = GetDomain (domain_id);
+ TypeMirror t = GetType (type_id);
+
+ if (t.Assembly == d.Corlib && t.Namespace == "System.Threading" && t.Name == "Thread")
+ obj = new ThreadMirror (this, id, t, d);
+ else if (t.Assembly == d.Corlib && t.Namespace == "System" && t.Name == "String")
+ obj = new StringMirror (this, id, t, d);
+ else if (typeof (T) == typeof (ArrayMirror))
+ obj = new ArrayMirror (this, id, t, d);
+ else
+ obj = new ObjectMirror (this, id, t, d);
+ objects [id] = obj;
+ }
+ return (T)obj;
+ }
+ }
+
+ internal T GetObject<T> (long id) where T : ObjectMirror {
+ return GetObject<T> (id, 0, 0);
+ }
+
+ internal ObjectMirror GetObject (long objid) {
+ return GetObject<ObjectMirror> (objid);
+ }
+
+ internal ThreadMirror GetThread (long id) {
+ return GetObject <ThreadMirror> (id);
+ }
+
+ object requests_lock = new object ();
+
+ internal void AddRequest (EventRequest req, int id) {
+ lock (requests_lock) {
+ requests [id] = req;
+ }
+ }
+
+ internal void RemoveRequest (EventRequest req, int id) {
+ lock (requests_lock) {
+ requests.Remove (id);
+ }
+ }
+
+ internal EventRequest GetRequest (int id) {
+ lock (requests_lock) {
+ return requests [id];
+ }
+ }
+
+ internal Value DecodeValue (ValueImpl v) {
+ if (v.Value != null)
+ return new PrimitiveValue (this, v.Value);
+
+ switch (v.Type) {
+ case ElementType.Void:
+ return null;
+ case ElementType.SzArray:
+ case ElementType.Array:
+ return GetObject<ArrayMirror> (v.Objid);
+ case ElementType.String:
+ return GetObject<StringMirror> (v.Objid);
+ case ElementType.Class:
+ case ElementType.Object:
+ return GetObject (v.Objid);
+ case ElementType.ValueType:
+ if (v.IsEnum)
+ return new EnumMirror (this, GetType (v.Klass), DecodeValues (v.Fields));
+ else
+ return new StructMirror (this, GetType (v.Klass), DecodeValues (v.Fields));
+ case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
+ return new PrimitiveValue (this, null);
+ default:
+ throw new NotImplementedException ("" + v.Type);
+ }
+ }
+
+ internal Value[] DecodeValues (ValueImpl[] values) {
+ Value[] res = new Value [values.Length];
+ for (int i = 0; i < values.Length; ++i)
+ res [i] = DecodeValue (values [i]);
+ return res;
+ }
+
+ internal ValueImpl EncodeValue (Value v) {
+ if (v is PrimitiveValue) {
+ object val = (v as PrimitiveValue).Value;
+ if (val == null)
+ return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
+ else
+ return new ValueImpl { Value = val };
+ } else if (v is ObjectMirror) {
+ return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
+ } else if (v is StructMirror) {
+ return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeValues ((v as StructMirror).Fields) };
+ } else {
+ throw new NotSupportedException ();
+ }
+ }
+
+ internal ValueImpl[] EncodeValues (IList<Value> values) {
+ ValueImpl[] res = new ValueImpl [values.Count];
+ for (int i = 0; i < values.Count; ++i)
+ res [i] = EncodeValue (values [i]);
+ return res;
+ }
+
+ internal void CheckProtocolVersion (int major, int minor) {
+ if (!conn.Version.AtLeast (major, minor))
+ throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
+ }
+ }
+
+ class EventHandler : MarshalByRefObject, IEventHandler
+ {
+ VirtualMachine vm;
+
+ public EventHandler (VirtualMachine vm) {
+ this.vm = vm;
+ }
+
+ public void Events (SuspendPolicy suspend_policy, EventInfo[] events) {
+ var l = new List<Event> ();
+
+ for (int i = 0; i < events.Length; ++i) {
+ EventInfo ei = events [i];
+ int req_id = ei.ReqId;
+ long thread_id = ei.ThreadId;
+ long id = ei.Id;
+ long loc = ei.Location;
+
+ switch (ei.EventType) {
+ case EventType.VMStart:
+ vm.notify_vm_event (EventType.VMStart, suspend_policy, req_id, thread_id, null);
+ break;
+ case EventType.VMDeath:
+ vm.notify_vm_event (EventType.VMDeath, suspend_policy, req_id, thread_id, null);
+ break;
+ case EventType.ThreadStart:
+ l.Add (new ThreadStartEvent (vm, req_id, id));
+ break;
+ case EventType.ThreadDeath:
+ l.Add (new ThreadDeathEvent (vm, req_id, id));
+ break;
+ case EventType.AssemblyLoad:
+ l.Add (new AssemblyLoadEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.AssemblyUnload:
+ l.Add (new AssemblyUnloadEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.TypeLoad:
+ l.Add (new TypeLoadEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.MethodEntry:
+ l.Add (new MethodEntryEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.MethodExit:
+ l.Add (new MethodExitEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.Breakpoint:
+ l.Add (new BreakpointEvent (vm, req_id, thread_id, id, loc));
+ break;
+ case EventType.Step:
+ l.Add (new StepEvent (vm, req_id, thread_id, id, loc));
+ break;
+ case EventType.Exception:
+ l.Add (new ExceptionEvent (vm, req_id, thread_id, id, loc));
+ break;
+ case EventType.AppDomainCreate:
+ l.Add (new AppDomainCreateEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.AppDomainUnload:
+ l.Add (new AppDomainUnloadEvent (vm, req_id, thread_id, id));
+ break;
+ case EventType.UserBreak:
+ l.Add (new UserBreakEvent (vm, req_id, thread_id));
+ break;
+ case EventType.UserLog:
+ l.Add (new UserLogEvent (vm, req_id, thread_id, ei.Level, ei.Category, ei.Message));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (l.Count > 0)
+ vm.queue_event_set (new EventSet (vm, suspend_policy, l.ToArray ()));
+ }
+
+ public void VMDisconnect (int req_id, long thread_id, string vm_uri) {
+ vm.notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, req_id, thread_id, vm_uri);
+ }
+ }
+
+ public class CommandException : Exception {
+
+ internal CommandException (ErrorCode error_code) : base ("Debuggee returned error code " + error_code + ".") {
+ ErrorCode = error_code;
+ }
+
+ public ErrorCode ErrorCode {
+ get; set;
+ }
+ }
+
+ public class VMNotSuspendedException : InvalidOperationException
+ {
+ public VMNotSuspendedException () : base ("The vm is not suspended.")
+ {
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachineManager.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachineManager.cs
new file mode 100644
index 0000000..a5bdf4f
--- /dev/null
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachineManager.cs
@@ -0,0 +1,339 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
+
+namespace Mono.Debugger.Soft
+{
+ public class LaunchOptions {
+ public string AgentArgs {
+ get; set;
+ }
+
+ public bool Valgrind {
+ get; set;
+ }
+
+ public ProcessLauncher CustomProcessLauncher {
+ get; set;
+ }
+
+ public TargetProcessLauncher CustomTargetProcessLauncher {
+ get; set;
+ }
+
+ public delegate Process ProcessLauncher (ProcessStartInfo info);
+ public delegate ITargetProcess TargetProcessLauncher (ProcessStartInfo info);
+ }
+
+ public class VirtualMachineManager
+ {
+ private delegate VirtualMachine LaunchCallback (ITargetProcess p, ProcessStartInfo info, Socket socket);
+ private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock);
+ private delegate VirtualMachine ConnectCallback (Socket dbg_sock, Socket con_sock, IPEndPoint dbg_ep, IPEndPoint con_ep);
+
+ internal VirtualMachineManager () {
+ }
+
+ public static VirtualMachine LaunchInternal (Process p, ProcessStartInfo info, Socket socket)
+ {
+ return LaunchInternal (new ProcessWrapper (p), info, socket);
+ }
+
+ public static VirtualMachine LaunchInternal (ITargetProcess p, ProcessStartInfo info, Socket socket) {
+ Socket accepted = null;
+ try {
+ accepted = socket.Accept ();
+ } catch (Exception) {
+ throw;
+ }
+
+ Connection conn = new TcpConnection (accepted);
+
+ VirtualMachine vm = new VirtualMachine (p, conn);
+
+ if (info.RedirectStandardOutput)
+ vm.StandardOutput = p.StandardOutput;
+
+ if (info.RedirectStandardError)
+ vm.StandardError = p.StandardError;
+
+ conn.EventHandler = new EventHandler (vm);
+
+ vm.connect ();
+
+ return vm;
+ }
+
+ public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback)
+ {
+ return BeginLaunch (info, callback, null);
+ }
+
+ public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options)
+ {
+ if (info == null)
+ throw new ArgumentNullException ("info");
+
+ Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
+ socket.Listen (1000);
+ IPEndPoint ep = (IPEndPoint) socket.LocalEndPoint;
+
+ // We need to inject our arguments into the psi
+ info.Arguments = string.Format ("{0} --debug --debugger-agent=transport=dt_socket,address={1}:{2}{3} {4}",
+ options == null || !options.Valgrind ? "" : info.FileName,
+ ep.Address,
+ ep.Port,
+ options == null || options.AgentArgs == null ? "" : "," + options.AgentArgs,
+ info.Arguments);
+
+ if (options != null && options.Valgrind)
+ info.FileName = "valgrind";
+
+ ITargetProcess p;
+ if (options != null && options.CustomProcessLauncher != null)
+ p = new ProcessWrapper (options.CustomProcessLauncher (info));
+ else if (options != null && options.CustomTargetProcessLauncher != null)
+ p = options.CustomTargetProcessLauncher (info);
+ else
+ p = new ProcessWrapper (Process.Start (info));
+
+ p.Exited += delegate (object sender, EventArgs eargs) {
+ socket.Close ();
+ };
+
+ LaunchCallback c = new LaunchCallback (LaunchInternal);
+ return c.BeginInvoke (p, info, socket, callback, socket);
+ }
+
+ public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
+
+ AsyncResult result = (AsyncResult) asyncResult;
+ LaunchCallback cb = (LaunchCallback) result.AsyncDelegate;
+ return cb.EndInvoke (asyncResult);
+ }
+
+ public static VirtualMachine Launch (ProcessStartInfo info)
+ {
+ return Launch (info, null);
+ }
+
+ public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options)
+ {
+ return EndLaunch (BeginLaunch (info, null, options));
+ }
+
+ public static VirtualMachine Launch (string[] args)
+ {
+ return Launch (args, null);
+ }
+
+ public static VirtualMachine Launch (string[] args, LaunchOptions options)
+ {
+ ProcessStartInfo pi = new ProcessStartInfo ("mono");
+ pi.Arguments = String.Join (" ", args);
+
+ return Launch (pi, options);
+ }
+
+ public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
+ Socket con_acc = null;
+ Socket dbg_acc = null;
+
+ if (con_sock != null) {
+ try {
+ con_acc = con_sock.Accept ();
+ } catch (Exception) {
+ try {
+ dbg_sock.Close ();
+ } catch {}
+ throw;
+ }
+ }
+
+ try {
+ dbg_acc = dbg_sock.Accept ();
+ } catch (Exception) {
+ if (con_sock != null) {
+ try {
+ con_sock.Close ();
+ con_acc.Close ();
+ } catch {}
+ }
+ throw;
+ }
+
+ if (con_sock != null) {
+ if (con_sock.Connected)
+ con_sock.Disconnect (false);
+ con_sock.Close ();
+ }
+
+ if (dbg_sock.Connected)
+ dbg_sock.Disconnect (false);
+ dbg_sock.Close ();
+
+ Connection transport = new TcpConnection (dbg_acc);
+ StreamReader console = con_acc != null? new StreamReader (new NetworkStream (con_acc)) : null;
+
+ return Connect (transport, console, null);
+ }
+
+ public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
+ return BeginListen (dbg_ep, null, callback);
+ }
+
+ public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback)
+ {
+ int dbg_port, con_port;
+ return BeginListen (dbg_ep, con_ep, callback, out dbg_port, out con_port);
+ }
+
+ public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback,
+ out int dbg_port, out int con_port)
+ {
+ dbg_port = con_port = 0;
+
+ Socket dbg_sock = null;
+ Socket con_sock = null;
+
+ dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ dbg_sock.Bind (dbg_ep);
+ dbg_sock.Listen (1000);
+ dbg_port = ((IPEndPoint) dbg_sock.LocalEndPoint).Port;
+
+ if (con_ep != null) {
+ con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ con_sock.Bind (con_ep);
+ con_sock.Listen (1000);
+ con_port = ((IPEndPoint) con_sock.LocalEndPoint).Port;
+ }
+
+ ListenCallback c = new ListenCallback (ListenInternal);
+ return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
+ }
+
+ public static VirtualMachine EndListen (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
+
+ AsyncResult result = (AsyncResult) asyncResult;
+ ListenCallback cb = (ListenCallback) result.AsyncDelegate;
+ return cb.EndInvoke (asyncResult);
+ }
+
+ public static VirtualMachine Listen (IPEndPoint dbg_ep)
+ {
+ return Listen (dbg_ep, null);
+ }
+
+ public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep)
+ {
+ return EndListen (BeginListen (dbg_ep, con_ep, null));
+ }
+
+ /*
+ * Connect to a virtual machine listening at the specified address.
+ */
+ public static VirtualMachine Connect (IPEndPoint endpoint) {
+ return Connect (endpoint, null);
+ }
+
+ public static VirtualMachine Connect (IPEndPoint endpoint, IPEndPoint consoleEndpoint) {
+ if (endpoint == null)
+ throw new ArgumentNullException ("endpoint");
+
+ return EndConnect (BeginConnect (endpoint, consoleEndpoint, null));
+ }
+
+ public static VirtualMachine ConnectInternal (Socket dbg_sock, Socket con_sock, IPEndPoint dbg_ep, IPEndPoint con_ep) {
+ if (con_sock != null) {
+ try {
+ con_sock.Connect (con_ep);
+ } catch (Exception) {
+ try {
+ dbg_sock.Close ();
+ } catch {}
+ throw;
+ }
+ }
+
+ try {
+ dbg_sock.Connect (dbg_ep);
+ } catch (Exception) {
+ if (con_sock != null) {
+ try {
+ con_sock.Close ();
+ } catch {}
+ }
+ throw;
+ }
+
+ Connection transport = new TcpConnection (dbg_sock);
+ StreamReader console = con_sock != null? new StreamReader (new NetworkStream (con_sock)) : null;
+
+ return Connect (transport, console, null);
+ }
+
+ public static IAsyncResult BeginConnect (IPEndPoint dbg_ep, AsyncCallback callback) {
+ return BeginConnect (dbg_ep, null, callback);
+ }
+
+ public static IAsyncResult BeginConnect (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
+ Socket dbg_sock = null;
+ Socket con_sock = null;
+
+ dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+
+ if (con_ep != null) {
+ con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ }
+
+ ConnectCallback c = new ConnectCallback (ConnectInternal);
+ return c.BeginInvoke (dbg_sock, con_sock, dbg_ep, con_ep, callback, con_sock ?? dbg_sock);
+ }
+
+ public static VirtualMachine EndConnect (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
+
+ AsyncResult result = (AsyncResult) asyncResult;
+ ConnectCallback cb = (ConnectCallback) result.AsyncDelegate;
+ return cb.EndInvoke (asyncResult);
+ }
+
+ public static void CancelConnection (IAsyncResult asyncResult)
+ {
+ ((Socket)asyncResult.AsyncState).Close ();
+ }
+
+ public static VirtualMachine Connect (Connection transport, StreamReader standardOutput, StreamReader standardError)
+ {
+ VirtualMachine vm = new VirtualMachine (null, transport);
+
+ vm.StandardOutput = standardOutput;
+ vm.StandardError = standardError;
+
+ transport.EventHandler = new EventHandler (vm);
+
+ vm.connect ();
+
+ return vm;
+ }
+ }
+}
diff --git a/Mono.Debugger.Soft/mono-git-revision b/Mono.Debugger.Soft/mono-git-revision
new file mode 100644
index 0000000..a702b4f
--- /dev/null
+++ b/Mono.Debugger.Soft/mono-git-revision
@@ -0,0 +1 @@
+75d1cf2f193e6bdfc9bdb025317283b83d31c67a
diff --git a/Mono.Debugger.Soft/mono.snk b/Mono.Debugger.Soft/mono.snk
new file mode 100644
index 0000000..380116c
Binary files /dev/null and b/Mono.Debugger.Soft/mono.snk differ
diff --git a/Mono.Debugging.Soft/ArrayAdaptor.cs b/Mono.Debugging.Soft/ArrayAdaptor.cs
new file mode 100644
index 0000000..462525a
--- /dev/null
+++ b/Mono.Debugging.Soft/ArrayAdaptor.cs
@@ -0,0 +1,89 @@
+//
+// ArrayAdaptor.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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.Linq;
+using Mono.Debugging.Evaluation;
+using Mono.Debugger.Soft;
+
+namespace Mono.Debugging.Soft
+{
+ public class ArrayAdaptor: ICollectionAdaptor
+ {
+ ArrayMirror array;
+ int[] dimensions;
+
+ public ArrayAdaptor (ArrayMirror array)
+ {
+ this.array = array;
+ }
+
+ public int[] GetDimensions ()
+ {
+ if (dimensions == null) {
+ dimensions = new int [array.Rank];
+ for (int n=0; n<array.Rank; n++)
+ dimensions [n] = array.GetLength (n);
+ }
+ return dimensions;
+ }
+
+ public object GetElement (int[] indices)
+ {
+ int i = GetIndex (indices);
+ return array.GetValues (i, 1)[0];
+ }
+
+ public Array GetElements (int[] indices, int count)
+ {
+ int i = GetIndex (indices);
+ return array.GetValues (i, count).ToArray ();
+ }
+
+ public void SetElement (int[] indices, object val)
+ {
+ array.SetValues (GetIndex (indices), new Value[] { (Value) val });
+ }
+
+ int GetIndex (int[] indices)
+ {
+ int ts = 1;
+ int i = 0;
+ int[] dims = GetDimensions ();
+ for (int n = indices.Length - 1; n >= 0; n--) {
+ i += indices [n] * ts;
+ ts *= dims [n];
+ }
+ return i;
+ }
+
+ public object ElementType {
+ get {
+ return array.Type.GetElementType ();
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/AssemblyInfo.cs b/Mono.Debugging.Soft/AssemblyInfo.cs
new file mode 100644
index 0000000..d70591c
--- /dev/null
+++ b/Mono.Debugging.Soft/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+//
+// AssemblyInfo.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson at novell.com>
+//
+// Copyright (c) 2010 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.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Mono.Debugging.Soft")]
\ No newline at end of file
diff --git a/Mono.Debugging.Soft/ChangeLog b/Mono.Debugging.Soft/ChangeLog
new file mode 100644
index 0000000..28f5b09
--- /dev/null
+++ b/Mono.Debugging.Soft/ChangeLog
@@ -0,0 +1,264 @@
+2010-06-29 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs: Show no window when starting the
+ app.
+
+2010-06-01 Levi Bard <levi at unity3d.com>
+
+ * SoftDebuggerSession.cs: Catch SocketException
+ on session exit.
+
+2010-05-31 Levi Bard <levi at unity3d.com>
+
+ * SoftDebuggerSession.cs: Account for multiple assemblies
+ being built from a single source file.
+
+2010-05-31 Levi Bard <levi at unity3d.com>
+
+ * SoftDebuggerSession.cs: Clear the source-to-type map on
+ assembly unload.
+
+2010-05-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Improved detection of null values.
+
+2010-05-10 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated to latest.
+
+ * SoftDebuggerAdaptor.cs: Handle the new
+ AbsentInformationException.
+
+2010-05-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftEvaluationContext.cs:
+ * SoftDebuggerBacktrace.cs: Track api changes.
+
+2010-05-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * PropertyValueReference.cs: Track api changes.
+
+2010-05-04 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs: Don't redirect output/error when
+ using an external console. Use TargetProcess instead of
+ Process, since Process doesn't work for external consoles.
+
+2010-04-29 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated from Mono.
+
+ * SoftDebuggerSession.cs:
+ * SoftDebuggerStartInfo.cs: Track API changes.
+
+ * SoftDebuggerAdaptor.cs: The call to ToString may return
+ null. Return an empty string in this case. Fixes bug
+ #599434.
+
+2010-04-26 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated.
+
+2010-04-19 Carlo Kok <ck at remobjects.com>
+ * SoftDebuggerSession.cs:
+ * SoftEvaluationContext.cs:
+ Allow for custom expression evaluator.
+
+2010-04-14 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: When getting the members of a type,
+ take into account overriden virtual properties. Fixes bug
+ #580994 - MD debugger hover window ignores virtual.
+
+2010-03-30 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs: Set the current request in the Step
+ Out command. Fixes bug #569418 - Debugger sometimes loses
+ track of stepping.
+
+2010-03-30 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs:
+ * SoftDebuggerStartInfo.cs: Fix external console support
+ again.
+
+2010-03-29 Levi Bard <levi at unity3d.com>
+
+ * SoftDebuggerSession.cs: Improve assembly matching.
+
+2010-03-26 Levi Bard <levi at unity3d.com>
+
+ * SoftDebuggerSession.cs: Handle assembly unload.
+
+2010-03-17 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Don't crash if something goes wrong
+ while getting type data.
+
+2010-03-09 Michael Hutchinson <mhutchinson at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Nicer log messages.
+
+ * LoggingService.cs: Use custom logger for the new LogMessage
+ call. Remove unnecessary string.Format call.
+
+2010-03-09 Martin Baulig <martin at ximian.com>
+
+ * SoftDebuggerSession.cs: Add protected virtual methods
+ OnHandleEvent(), OnVMStartEvent(), OnVMDeathEvent() and
+ OnBreakpointBound().
+
+2010-03-05 Martin Baulig <martin at ximian.com>
+
+ Use the new Soft Debugger API to abort invocations.
+
+ * SoftDebuggerAdaptor.cs (MethodCall.Abort): Implement this.
+
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated.
+
+2010-03-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs: Don't catch the thread abort
+ exception, unless there is a catchpoint for it. Based on a
+ patch by Levi Bard.
+
+2010-03-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Renamed variable to improve
+ readability.
+
+ * SoftEvaluationContext.cs: When calling a method, make sure
+ value type arguments are properly boxed when required.
+
+2010-03-01 Michael Hutchinson <mhutchinson at novell.com>
+
+ * SoftDebuggerSession.cs:
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated SDB dll, stops uncaught
+ exception handler getting all caught exceptions on older
+ Monos, and updates protocol.
+
+2010-03-01 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Improved support for indexers.
+ Improved GetType implementation, so that it can now properly
+ instantiate generic types.
+
+2010-02-26 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Implement enum conversions.
+
+2010-02-23 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated.
+
+ * SoftDebuggerSession.cs: Report unhandled exceptions.
+
+2010-02-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerBacktrace.cs: Don't crash if the debugger
+ stopped and the current thread could not be found.
+
+2010-02-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugger.Soft.dll:
+ * Mono.Debugger.Soft.dll.mdb: Updated.
+
+ * SoftDebuggerAdaptor.cs: Add missing null check.
+
+2010-02-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs:
+ * SoftDebuggerSession.cs: Implement GetCurrentException.
+
+2010-02-17 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.Soft.csproj: Fix assembly reference. Set the
+ autotools project flag, so it can properly resolve relative
+ paths.
+
+2010-02-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Soft.csproj: Track api changes. Some engine
+ info is now taken from extension node metadata.
+
+2010-02-10 Michael Hutchinson <mhutchinson at novell.com>
+
+ * SoftDebuggerSession.cs: Force-load System.Exception to work
+ around sdb currently not giving a type load for this. Warn
+ on duplicate type loads - they could cause problems because
+ we can't handle them and they currently might happen e.g.
+ with appdomains. Shorten stupidly long lines.
+
+ * LoggingService.cs: Only insert newline if exception is not
+ null.
+
+2010-02-04 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs: Dont print the expression when a
+ tracepoint is hit. UpdateListTraceValue will do it.
+
+2010-02-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Implemented GetTypeArgs. Report the
+ correct exception name when an exception is thrown in the
+ target. Fixes bug #576427 - Debugger hides any user
+ exception.
+
+2010-02-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerSession.cs: When a breakpoint can't be resolved,
+ set it as invalid. Set it to valid when resolved. Fixes bug
+ #564541 - Set breakpoint should work on expressions and not
+ lines.
+
+2010-02-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * ArrayAdaptor.cs:
+ * Mono.Debugger.Soft.dll:
+ * SoftDebuggerAdaptor.cs:
+ * FieldValueReference.cs:
+ * SoftDebuggerSession.cs:
+ * SoftEvaluationContext.cs:
+ * SoftDebuggerBacktrace.cs:
+ * VariableValueReference.cs:
+ * PropertyValueReference.cs:
+ * Mono.Debugger.Soft.dll.mdb: Use the new namespace for the
+ soft debugger. Updated the sdb client library.
+
+2010-01-25 Michael Hutchinson <mhutchinson at novell.com>
+
+ * SoftDebuggerSession.cs: Write a message to the debugger
+ output if unable to insert a breakpoint.
+
+2010-01-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * SoftDebuggerAdaptor.cs: Implement new ForceLoadType
+ overridable.
+
+2010-01-20 Michael Hutchinson <mhutchinson at novell.com>
+
+ * AssemblyInfo.cs:
+ * ArrayAdaptor.cs:
+ * LoggingService.cs:
+ * SoftDebuggerSession.cs:
+ * SoftDebuggerAdaptor.cs:
+ * Mono.Debugger.Soft.dll:
+ * FieldValueReference.cs:
+ * SoftDebuggerBacktrace.cs:
+ * SoftDebuggerStartInfo.cs:
+ * SoftEvaluationContext.cs:
+ * VariableValueReference.cs:
+ * PropertyValueReference.cs:
+ * Mono.Debugger.Soft.dll.mdb:
+ * Mono.Debugging.Soft.csproj: Split out a new dll
+ Mono.Debugging.Soft from the soft debugger addin. It has the
+ bits that have with no MD deps apart from Mono.Debugging,
+ and it's strongnamed so MonoVS can use it.
+
diff --git a/Mono.Debugging.Soft/FieldValueReference.cs b/Mono.Debugging.Soft/FieldValueReference.cs
new file mode 100644
index 0000000..5dc4161
--- /dev/null
+++ b/Mono.Debugging.Soft/FieldValueReference.cs
@@ -0,0 +1,170 @@
+//
+// FieldValueReference.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2009 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.Reflection;
+using Mono.Debugging.Evaluation;
+using Mono.Debugger.Soft;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Soft
+{
+ public class FieldValueReference: ValueReference
+ {
+ FieldInfoMirror field;
+ object obj;
+ TypeMirror declaringType;
+ ObjectValueFlags flags;
+ string vname;
+
+ public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType)
+ : this (ctx, field, obj, declaringType, null, ObjectValueFlags.Field)
+ {
+ }
+
+ public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, string vname, ObjectValueFlags vflags): base (ctx)
+ {
+ this.field = field;
+ this.obj = obj;
+ this.declaringType = declaringType;
+ this.vname = vname;
+ flags = vflags;
+
+ if (field.IsStatic)
+ this.obj = null;
+
+ flags |= GetFlags (field);
+
+ if (obj is PrimitiveValue)
+ flags |= ObjectValueFlags.ReadOnly;
+ }
+
+ internal static ObjectValueFlags GetFlags (FieldInfoMirror field)
+ {
+ var flags = ObjectValueFlags.Field;
+
+ if (field.IsStatic)
+ flags |= ObjectValueFlags.Global;
+
+ if (field.IsPublic)
+ flags |= ObjectValueFlags.Public;
+ else if (field.IsPrivate)
+ flags |= ObjectValueFlags.Private;
+ else if (field.IsFamily)
+ flags |= ObjectValueFlags.Protected;
+ else if (field.IsFamilyAndAssembly)
+ flags |= ObjectValueFlags.Internal;
+ else if (field.IsFamilyOrAssembly)
+ flags |= ObjectValueFlags.InternalProtected;
+
+ return flags;
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return flags;
+ }
+ }
+
+ public override string Name {
+ get {
+ return vname ?? field.Name;
+ }
+ }
+
+ public override object Type {
+ get {
+ return field.FieldType;
+ }
+ }
+
+ public override object DeclaringType {
+ get {
+ return field.DeclaringType;
+ }
+ }
+
+ public override object Value {
+ get {
+ if (obj == null) {
+ // If the type hasn't already been loaded, invoke the .cctor() for types w/ the BeforeFieldInit attribute.
+ Context.Adapter.ForceLoadType (Context, declaringType);
+
+ return declaringType.GetValue (field);
+ } else if (obj is ObjectMirror) {
+ return ((ObjectMirror)obj).GetValue (field);
+ } else if (obj is StructMirror) {
+ StructMirror sm = (StructMirror)obj;
+ int idx = 0;
+ foreach (FieldInfoMirror f in sm.Type.GetFields ()) {
+ if (f.IsStatic) continue;
+ if (f == field)
+ break;
+ idx++;
+ }
+ return sm.Fields [idx];
+ } else if (obj is StringMirror) {
+ SoftEvaluationContext cx = (SoftEvaluationContext) Context;
+ StringMirror val = (StringMirror) obj;
+ FieldInfo rfield = typeof(string).GetField (field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ return cx.Session.VirtualMachine.CreateValue (rfield.GetValue (val.Value));
+ } else {
+ SoftEvaluationContext cx = (SoftEvaluationContext) Context;
+ PrimitiveValue val = (PrimitiveValue) obj;
+ if (val.Value == null)
+ return null;
+ FieldInfo rfield = val.Value.GetType ().GetField (field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ return cx.Session.VirtualMachine.CreateValue (rfield.GetValue (val.Value));
+ }
+ }
+ set {
+ if (obj == null)
+ declaringType.SetValue (field, (Value)value);
+ else if (obj is ObjectMirror)
+ ((ObjectMirror)obj).SetValue (field, (Value)value);
+ else if (obj is StructMirror) {
+ StructMirror sm = (StructMirror)obj;
+ int idx = 0;
+ foreach (FieldInfoMirror f in sm.Type.GetFields ()) {
+ if (f.IsStatic) continue;
+ if (f == field)
+ break;
+ idx++;
+ }
+ if (idx != -1) {
+ sm.Fields [idx] = (Value)value;
+ // Structs are handled by-value in the debugger, so the source of the object has to be updated
+ if (ParentSource != null && obj != null)
+ ParentSource.Value = obj;
+ }
+ }
+ else
+ throw new NotSupportedException ();
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/Makefile.am b/Mono.Debugging.Soft/Makefile.am
new file mode 100644
index 0000000..c9cc874
--- /dev/null
+++ b/Mono.Debugging.Soft/Makefile.am
@@ -0,0 +1 @@
+include $(top_srcdir)/xbuild.include
diff --git a/Mono.Debugging.Soft/Mono.Debugging.Soft.csproj b/Mono.Debugging.Soft/Mono.Debugging.Soft.csproj
new file mode 100644
index 0000000..c6d1531
--- /dev/null
+++ b/Mono.Debugging.Soft/Mono.Debugging.Soft.csproj
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{DE40756E-57F6-4AF2-B155-55E3A88CCED8}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Mono.Debugging.Soft</RootNamespace>
+ <AssemblyName>Mono.Debugging.Soft</AssemblyName>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\Mono.Debugging\mono.debugging.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>True</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>False</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <GenerateDocumentation>true</GenerateDocumentation>
+ <NoWarn>1591;1573</NoWarn>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DebugSymbols>true</DebugSymbols>
+ <GenerateDocumentation>true</GenerateDocumentation>
+ <NoWarn>1591;1573</NoWarn>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Mono.Debugging\Mono.Debugging.csproj">
+ <Project>{90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}</Project>
+ <Name>Mono.Debugging</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\Mono.Debugger.Soft\Mono.Debugger.Soft.csproj">
+ <Project>{372E8E3E-29D5-4B4D-88A2-4711CD628C4E}</Project>
+ <Name>Mono.Debugger.Soft</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\cecil\Mono.Cecil.csproj">
+ <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
+ <Name>Mono.Cecil</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj">
+ <Project>{8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}</Project>
+ <Name>Mono.Cecil.Mdb</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ArrayAdaptor.cs" />
+ <Compile Include="FieldValueReference.cs" />
+ <Compile Include="PropertyValueReference.cs" />
+ <Compile Include="SoftDebuggerSession.cs" />
+ <Compile Include="VariableValueReference.cs" />
+ <Compile Include="SoftEvaluationContext.cs" />
+ <Compile Include="SoftDebuggerAdaptor.cs" />
+ <Compile Include="SoftDebuggerBacktrace.cs" />
+ <Compile Include="SoftDebuggerStartInfo.cs" />
+ <Compile Include="AssemblyInfo.cs" />
+ <Compile Include="StringAdaptor.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <None Include="Makefile.am" />
+ </ItemGroup>
+</Project>
diff --git a/Mono.Debugging.Soft/PropertyValueReference.cs b/Mono.Debugging.Soft/PropertyValueReference.cs
new file mode 100644
index 0000000..b3d446f
--- /dev/null
+++ b/Mono.Debugging.Soft/PropertyValueReference.cs
@@ -0,0 +1,128 @@
+//
+// PropertyValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Evaluation;
+using Mono.Debugger.Soft;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Soft
+{
+ public class PropertyValueReference: ValueReference
+ {
+ PropertyInfoMirror property;
+ object obj;
+ TypeMirror declaringType;
+ Value[] indexerArgs;
+ ObjectValueFlags flags;
+
+ public PropertyValueReference (EvaluationContext ctx, PropertyInfoMirror property, object obj, TypeMirror declaringType, MethodMirror getter, Value[] indexerArgs): base (ctx)
+ {
+ this.property = property;
+ this.obj = obj;
+ this.declaringType = declaringType;
+ this.indexerArgs = indexerArgs;
+
+ flags = GetFlags (property, getter);
+ }
+
+ internal static ObjectValueFlags GetFlags (PropertyInfoMirror property, MethodMirror getter)
+ {
+ var flags = ObjectValueFlags.Property;
+
+ if (property.GetSetMethod (true) == null)
+ flags |= ObjectValueFlags.ReadOnly;
+
+ if (getter.IsStatic)
+ flags |= ObjectValueFlags.Global;
+
+ if (getter.IsPublic)
+ flags |= ObjectValueFlags.Public;
+ else if (getter.IsPrivate)
+ flags |= ObjectValueFlags.Private;
+ else if (getter.IsFamily)
+ flags |= ObjectValueFlags.Protected;
+ else if (getter.IsFamilyAndAssembly)
+ flags |= ObjectValueFlags.Internal;
+ else if (getter.IsFamilyOrAssembly)
+ flags |= ObjectValueFlags.InternalProtected;
+
+ if (property.DeclaringType.IsValueType)
+ flags |= ObjectValueFlags.ReadOnly; // Setting property values on structs is not supported by sdb
+
+ return flags;
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return flags;
+ }
+ }
+
+ public override string Name {
+ get {
+ return property.Name;
+ }
+ }
+
+ public override object Type {
+ get {
+ return property.PropertyType;
+ }
+ }
+
+ public override object DeclaringType {
+ get {
+ return property.DeclaringType;
+ }
+ }
+
+ public override object Value {
+ get {
+ Context.AssertTargetInvokeAllowed ();
+ SoftEvaluationContext ctx = (SoftEvaluationContext) Context;
+ return ctx.RuntimeInvoke (property.GetGetMethod (true), obj ?? declaringType, indexerArgs);
+ }
+ set {
+ Context.AssertTargetInvokeAllowed ();
+ SoftEvaluationContext ctx = (SoftEvaluationContext) Context;
+ Value[] args = new Value [indexerArgs != null ? indexerArgs.Length + 1 : 1];
+ if (indexerArgs != null)
+ indexerArgs.CopyTo (args, 0);
+ args [args.Length - 1] = (Value) value;
+ MethodMirror setter = property.GetSetMethod (true);
+ if (setter == null)
+ throw new EvaluatorException ("Property is read-only");
+ ctx.RuntimeInvoke (setter, obj ?? declaringType, args);
+ }
+ }
+
+ protected override bool CanEvaluate (EvaluationOptions options)
+ {
+ return options.AllowTargetInvoke;
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/SoftDebuggerAdaptor.cs b/Mono.Debugging.Soft/SoftDebuggerAdaptor.cs
new file mode 100644
index 0000000..200833d
--- /dev/null
+++ b/Mono.Debugging.Soft/SoftDebuggerAdaptor.cs
@@ -0,0 +1,1825 @@
+//
+// SoftDebuggerAdaptor.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
+// Copyright (c) 2011,2012 Xamain 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.Linq;
+using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+using Mono.Debugger.Soft;
+using Mono.Debugging.Evaluation;
+using Mono.Debugging.Client;
+
+using ST = System.Threading;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Soft
+{
+ public class SoftDebuggerAdaptor : ObjectValueAdaptor
+ {
+ static readonly Dictionary<Type, OpCode> convertOps = new Dictionary<Type, OpCode> ();
+ delegate object TypeCastDelegate (object value);
+
+ static SoftDebuggerAdaptor ()
+ {
+ convertOps.Add (typeof (double), OpCodes.Conv_R8);
+ convertOps.Add (typeof (float), OpCodes.Conv_R4);
+ convertOps.Add (typeof (ulong), OpCodes.Conv_U8);
+ convertOps.Add (typeof (uint), OpCodes.Conv_U4);
+ convertOps.Add (typeof (ushort), OpCodes.Conv_U2);
+ convertOps.Add (typeof (char), OpCodes.Conv_U2);
+ convertOps.Add (typeof (byte), OpCodes.Conv_U1);
+ convertOps.Add (typeof (long), OpCodes.Conv_I8);
+ convertOps.Add (typeof (int), OpCodes.Conv_I4);
+ convertOps.Add (typeof (short), OpCodes.Conv_I2);
+ convertOps.Add (typeof (sbyte), OpCodes.Conv_I1);
+ }
+
+ public SoftDebuggerAdaptor ()
+ {
+ }
+
+ public override string CallToString (EvaluationContext ctx, object obj)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+
+ if (obj == null)
+ return null;
+
+ if (obj is StringMirror)
+ return ((StringMirror)obj).Value;
+
+ if (obj is EnumMirror)
+ return ((EnumMirror) obj).StringValue;
+
+ if (obj is PrimitiveValue)
+ return ((PrimitiveValue)obj).Value.ToString ();
+
+ if (obj is PointerValue)
+ return string.Format ("0x{0:x}", ((PointerValue)obj).Address);
+
+ if ((obj is StructMirror) && ((StructMirror)obj).Type.IsPrimitive) {
+ // Boxed primitive
+ StructMirror sm = (StructMirror) obj;
+ if (sm.Fields.Length > 0 && (sm.Fields[0] is PrimitiveValue))
+ return ((PrimitiveValue)sm.Fields[0]).Value.ToString ();
+ } else if ((obj is ObjectMirror) && cx.Options.AllowTargetInvoke) {
+ ObjectMirror ob = (ObjectMirror) obj;
+ MethodMirror method = OverloadResolve (cx, ob.Type, "ToString", null, new TypeMirror[0], true, false, false);
+ if (method != null && method.DeclaringType.FullName != "System.Object") {
+ StringMirror res = cx.RuntimeInvoke (method, obj, new Value[0]) as StringMirror;
+ return res != null ? res.Value : null;
+ }
+ } else if ((obj is StructMirror) && cx.Options.AllowTargetInvoke) {
+ StructMirror ob = (StructMirror) obj;
+ MethodMirror method = OverloadResolve (cx, ob.Type, "ToString", null, new TypeMirror[0], true, false, false);
+ if (method != null && method.DeclaringType.FullName != "System.ValueType") {
+ StringMirror res = cx.RuntimeInvoke (method, obj, new Value[0]) as StringMirror;
+ return res != null ? res.Value : null;
+ }
+ }
+
+ return GetDisplayTypeName (GetValueTypeName (ctx, obj));
+ }
+
+ public override object TryConvert (EvaluationContext ctx, object obj, object targetType)
+ {
+ object res = TryCast (ctx, obj, targetType);
+
+ if (res != null || obj == null)
+ return res;
+
+ object otype = GetValueType (ctx, obj);
+ if (otype is Type) {
+ if (targetType is TypeMirror)
+ targetType = Type.GetType (((TypeMirror)targetType).FullName, false);
+
+ Type tt = targetType as Type;
+ if (tt != null) {
+ try {
+ if (obj is PrimitiveValue)
+ obj = ((PrimitiveValue)obj).Value;
+ res = System.Convert.ChangeType (obj, tt);
+ return CreateValue (ctx, res);
+ } catch {
+ }
+ }
+ }
+ return null;
+ }
+
+ static TypeCastDelegate GenerateTypeCastDelegate (string methodName, Type fromType, Type toType)
+ {
+ var argTypes = new Type[] {
+ typeof (object)
+ };
+ var method = new DynamicMethod (methodName, typeof (object), argTypes, true);
+ ILGenerator il = method.GetILGenerator ();
+ ConstructorInfo ctorInfo;
+ MethodInfo methodInfo;
+ OpCode conv;
+
+ il.Emit (OpCodes.Ldarg_0);
+ il.Emit (OpCodes.Unbox_Any, fromType);
+
+ if (fromType.IsSubclassOf (typeof (System.Nullable))) {
+ PropertyInfo propInfo = fromType.GetProperty ("Value");
+ methodInfo = propInfo.GetGetMethod ();
+
+ il.Emit (OpCodes.Stloc_0);
+ il.Emit (OpCodes.Ldloca_S);
+ il.Emit (OpCodes.Call, methodInfo);
+
+ fromType = methodInfo.ReturnType;
+ }
+
+ if (!convertOps.TryGetValue (toType, out conv)) {
+ argTypes = new Type[] {
+ fromType
+ };
+
+ if (toType == typeof (string)) {
+ methodInfo = fromType.GetMethod ("ToString", new Type[0]);
+ il.Emit (OpCodes.Call, methodInfo);
+ } else if ((methodInfo = toType.GetMethod ("op_Explicit", argTypes)) != null) {
+ il.Emit (OpCodes.Call, methodInfo);
+ } else if ((methodInfo = toType.GetMethod ("op_Implicit", argTypes)) != null) {
+ il.Emit (OpCodes.Call, methodInfo);
+ } else if ((ctorInfo = toType.GetConstructor (argTypes)) != null) {
+ il.Emit (OpCodes.Call, ctorInfo);
+ } else {
+ // No idea what else to try...
+ throw new InvalidCastException ();
+ }
+ } else {
+ il.Emit (conv);
+ }
+
+ il.Emit (OpCodes.Box, toType);
+ il.Emit (OpCodes.Ret);
+
+ return (TypeCastDelegate) method.CreateDelegate (typeof (TypeCastDelegate));
+ }
+
+ static object DynamicCast (object value, Type target)
+ {
+ string methodName = string.Format ("CastFrom{0}To{1}", value.GetType ().Name, target.Name);
+ TypeCastDelegate method = GenerateTypeCastDelegate (methodName, value.GetType (), target);
+
+ return method.Invoke (value);
+ }
+
+ object TryForceCast (EvaluationContext ctx, Value value, TypeMirror fromType, TypeMirror toType)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ MethodMirror method;
+
+ method = OverloadResolve (cx, toType, "op_Explicit", null, new TypeMirror[] { fromType }, false, true, false);
+ if (method != null)
+ return cx.RuntimeInvoke (method, toType, new Value[] { value });
+
+ method = OverloadResolve (cx, toType, "op_Implicit", null, new TypeMirror[] { fromType }, false, true, false);
+ if (method != null)
+ return cx.RuntimeInvoke (method, toType, new Value[] { value });
+
+ // Finally, try a ctor...
+ try {
+ return CreateValue (ctx, toType, value);
+ } catch {
+ return null;
+ }
+ }
+
+ public override object TryCast (EvaluationContext ctx, object obj, object targetType)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ TypeMirror toType = targetType as TypeMirror;
+ TypeMirror fromType;
+
+ if (obj == null)
+ return null;
+
+ object valueType = GetValueType (ctx, obj);
+ if (valueType is TypeMirror) {
+ fromType = (TypeMirror) valueType;
+
+ if (toType != null && toType.IsAssignableFrom (fromType))
+ return obj;
+
+ // Try casting the primitive type of the enum
+ EnumMirror em = obj as EnumMirror;
+ if (em != null)
+ return TryCast (ctx, CreateValue (ctx, em.Value), targetType);
+
+ if (toType == null)
+ return null;
+
+ MethodMirror method;
+
+ if (toType.CSharpName == "string") {
+ method = OverloadResolve (cx, fromType, "ToString", null, new TypeMirror[0], true, false, false);
+ if (method != null)
+ return cx.RuntimeInvoke (method, obj, new Value[0]);
+ }
+
+ if (fromType.IsGenericType && fromType.FullName.StartsWith ("System.Nullable`1", StringComparison.Ordinal)) {
+ method = OverloadResolve (cx, fromType, "get_Value", null, new TypeMirror[0], true, false, false);
+ if (method != null) {
+ obj = cx.RuntimeInvoke (method, obj, new Value[0]);
+ return TryCast (ctx, obj, targetType);
+ }
+ }
+
+ return TryForceCast (ctx, (Value) obj, fromType, toType);
+ } else if (valueType is Type) {
+ if (toType != null) {
+ if (toType.IsEnum) {
+ PrimitiveValue casted = TryCast (ctx, obj, toType.EnumUnderlyingType) as PrimitiveValue;
+ if (casted == null)
+ return null;
+ return cx.Session.VirtualMachine.CreateEnumMirror (toType, casted);
+ }
+
+ targetType = Type.GetType (toType.FullName, false);
+ }
+
+ Type tt = targetType as Type;
+ if (tt != null) {
+ if (tt.IsAssignableFrom ((Type) valueType))
+ return obj;
+
+ try {
+ if (tt.IsPrimitive || tt == typeof (string)) {
+ if (obj is PrimitiveValue)
+ obj = ((PrimitiveValue) obj).Value;
+
+ if (obj == null)
+ return null;
+
+ object res;
+
+ try {
+ res = System.Convert.ChangeType (obj, tt);
+ } catch {
+ res = DynamicCast (obj, tt);
+ }
+
+ return CreateValue (ctx, res);
+ } else {
+ fromType = (TypeMirror) ForceLoadType (ctx, ((Type) valueType).FullName);
+ if (toType == null)
+ toType = (TypeMirror) ForceLoadType (ctx, tt.FullName);
+
+ return TryForceCast (ctx, (Value) obj, fromType, toType);
+ }
+ } catch {
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public override IStringAdaptor CreateStringAdaptor (EvaluationContext ctx, object str)
+ {
+ return new StringAdaptor ((StringMirror) str);
+ }
+
+ public override ICollectionAdaptor CreateArrayAdaptor (EvaluationContext ctx, object arr)
+ {
+ return new ArrayAdaptor ((ArrayMirror) arr);
+ }
+
+ public override object CreateNullValue (EvaluationContext ctx, object type)
+ {
+ return null;
+ }
+
+ public override object CreateTypeObject (EvaluationContext ctx, object type)
+ {
+ TypeMirror t = (TypeMirror) type;
+ return t.GetTypeObject ();
+ }
+
+ public override object CreateValue (EvaluationContext ctx, object type, params object[] args)
+ {
+ ctx.AssertTargetInvokeAllowed ();
+
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ TypeMirror t = (TypeMirror) type;
+
+ TypeMirror[] types = new TypeMirror [args.Length];
+ Value[] values = new Value[args.Length];
+ for (int n = 0; n < args.Length; n++) {
+ types[n] = ToTypeMirror (ctx, GetValueType (ctx, args[n]));
+ values[n] = (Value) args[n];
+ }
+
+ MethodMirror ctor = OverloadResolve (cx, t, ".ctor", null, types, true, true, true);
+ if (ctor == null)
+ return null;
+
+ return t.NewInstance (cx.Thread, ctor, values);
+ }
+
+ public override object CreateValue (EvaluationContext ctx, object value)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ if (value is string)
+ return cx.Thread.Domain.CreateString ((string)value);
+
+ return cx.Session.VirtualMachine.CreateValue (value);
+ }
+
+ public override object GetBaseValue (EvaluationContext ctx, object val)
+ {
+ return val;
+ }
+
+ public override bool NullableHasValue (EvaluationContext ctx, object type, object obj)
+ {
+ ValueReference hasValue = GetMember (ctx, type, obj, "has_value");
+
+ return (bool) hasValue.ObjectValue;
+ }
+
+ public override ValueReference NullableGetValue (EvaluationContext ctx, object type, object obj)
+ {
+ return GetMember (ctx, type, obj, "value");
+ }
+
+ public override object GetEnclosingType (EvaluationContext ctx)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ return cx.Frame.Method.DeclaringType;
+ }
+
+ public override string[] GetImportedNamespaces (EvaluationContext ctx)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ HashSet<string> namespaces = new HashSet<string> ();
+ foreach (TypeMirror type in cx.Session.GetAllTypes ())
+ namespaces.Add (type.Namespace);
+
+ string[] nss = new string [namespaces.Count];
+ namespaces.CopyTo (nss);
+ return nss;
+ }
+
+ public override ValueReference GetIndexerReference (EvaluationContext ctx, object target, object[] indices)
+ {
+ object valueType = GetValueType (ctx, target);
+ TypeMirror targetType = null;
+
+ if (valueType is Type)
+ targetType = (TypeMirror) ForceLoadType (ctx, ((Type) valueType).FullName);
+ else if (valueType is TypeMirror)
+ targetType = (TypeMirror) valueType;
+ else
+ return null;
+
+ Value[] values = new Value [indices.Length];
+ TypeMirror[] types = new TypeMirror [indices.Length];
+ for (int n=0; n<indices.Length; n++) {
+ types [n] = ToTypeMirror (ctx, GetValueType (ctx, indices [n]));
+ values [n] = (Value) indices [n];
+ }
+
+ List<MethodMirror> candidates = new List<MethodMirror> ();
+ List<PropertyInfoMirror> props = new List<PropertyInfoMirror> ();
+
+ TypeMirror type = targetType;
+ while (type != null) {
+ foreach (PropertyInfoMirror prop in type.GetProperties ()) {
+ MethodMirror met = prop.GetGetMethod (true);
+ if (met != null && !met.IsStatic && met.GetParameters ().Length > 0) {
+ candidates.Add (met);
+ props.Add (prop);
+ }
+ }
+ type = type.BaseType;
+ }
+
+ MethodMirror idx = OverloadResolve ((SoftEvaluationContext) ctx, targetType, null, null, types, candidates, true);
+ int i = candidates.IndexOf (idx);
+
+ MethodMirror getter = props[i].GetGetMethod (true);
+ if (getter == null)
+ return null;
+
+ return new PropertyValueReference (ctx, props[i], target, null, getter, values);
+ }
+
+ static bool InGeneratedClosureOrIteratorType (EvaluationContext ctx)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ if (cx.Frame.Method.IsStatic)
+ return false;
+ TypeMirror tm = cx.Frame.Method.DeclaringType;
+ return IsGeneratedType (tm);
+ }
+
+ internal static bool IsGeneratedType (TypeMirror tm)
+ {
+ //
+ // This should cover all C# generated special containers
+ // - anonymous methods
+ // - lambdas
+ // - iterators
+ // - async methods
+ //
+ // which allow stepping into
+ //
+ return tm.Name[0] == '<' &&
+ // mcs is of the form <${NAME}>.c__{KIND}${NUMBER}
+ (tm.Name.IndexOf (">c__", StringComparison.Ordinal) > 0 ||
+ // csc is of form <${NAME}>d__${NUMBER}
+ tm.Name.IndexOf (">d__", StringComparison.Ordinal) > 0);
+ }
+
+ internal static string GetNameFromGeneratedType (TypeMirror tm)
+ {
+ return tm.Name.Substring (1, tm.Name.IndexOf ('>') - 1);
+ }
+
+ static bool IsHoistedThisReference (FieldInfoMirror field)
+ {
+ // mcs is "<>f__this" or "$this" (if in an async compiler generated type)
+ // csc is "<>4__this"
+ return field.Name == "$this" ||
+ (field.Name.StartsWith ("<>", StringComparison.Ordinal) &&
+ field.Name.EndsWith ("__this", StringComparison.Ordinal));
+ }
+
+ static bool IsClosureReferenceField (FieldInfoMirror field)
+ {
+ // mcs is "<>f__ref"
+ // csc is "CS$<>"
+ return field.Name.StartsWith ("CS$<>", StringComparison.Ordinal) ||
+ field.Name.StartsWith ("<>f__ref", StringComparison.Ordinal);
+ }
+
+ static bool IsClosureReferenceLocal (LocalVariable local)
+ {
+ if (local.Name == null)
+ return false;
+
+ // mcs is "$locvar" or starts with '<'
+ // csc is "CS$<>"
+ return local.Name.Length == 0 || local.Name[0] == '<' || local.Name.StartsWith ("$locvar", StringComparison.Ordinal) ||
+ local.Name.StartsWith ("CS$<>", StringComparison.Ordinal);
+ }
+
+ static bool IsGeneratedTemporaryLocal (LocalVariable local)
+ {
+ // csc uses CS$ prefix for temporary variables and <>t__ prefix for async task-related state variables
+ return local.Name != null && (local.Name.StartsWith ("CS$", StringComparison.Ordinal) || local.Name.StartsWith ("<>t__", StringComparison.Ordinal));
+ }
+
+ static string GetHoistedIteratorLocalName (FieldInfoMirror field)
+ {
+ //mcs captured args, of form <$>name
+ if (field.Name.StartsWith ("<$>", StringComparison.Ordinal)) {
+ return field.Name.Substring (3);
+ }
+
+ // csc, mcs locals of form <name>__0
+ if (field.Name[0] == '<') {
+ int i = field.Name.IndexOf ('>');
+ if (i > 1) {
+ return field.Name.Substring (1, i - 1);
+ }
+ }
+ return null;
+ }
+
+ IEnumerable<ValueReference> GetHoistedLocalVariables (SoftEvaluationContext cx, ValueReference vthis)
+ {
+ if (vthis == null)
+ return new ValueReference [0];
+
+ object val = vthis.Value;
+ if (IsNull (cx, val))
+ return new ValueReference [0];
+
+ TypeMirror tm = (TypeMirror) vthis.Type;
+ bool isIterator = IsGeneratedType (tm);
+
+ var list = new List<ValueReference> ();
+ TypeMirror type = (TypeMirror) vthis.Type;
+ foreach (FieldInfoMirror field in type.GetFields ()) {
+ if (IsHoistedThisReference (field))
+ continue;
+ if (IsClosureReferenceField (field)) {
+ list.AddRange (GetHoistedLocalVariables (cx, new FieldValueReference (cx, field, val, type)));
+ continue;
+ }
+ if (field.Name[0] == '<') {
+ if (isIterator) {
+ var name = GetHoistedIteratorLocalName (field);
+ if (!string.IsNullOrEmpty (name)) {
+ list.Add (new FieldValueReference (cx, field, val, type, name, ObjectValueFlags.Variable));
+ }
+ }
+ } else if (!field.Name.Contains ("$")) {
+ list.Add (new FieldValueReference (cx, field, val, type, field.Name, ObjectValueFlags.Variable));
+ }
+ }
+ return list;
+ }
+
+ ValueReference GetHoistedThisReference (SoftEvaluationContext cx)
+ {
+ try {
+ Value val = cx.Frame.GetThis ();
+ TypeMirror type = (TypeMirror) GetValueType (cx, val);
+ return GetHoistedThisReference (cx, type, val);
+ } catch (AbsentInformationException) {
+ }
+ return null;
+ }
+
+ ValueReference GetHoistedThisReference (SoftEvaluationContext cx, TypeMirror type, object val)
+ {
+ foreach (FieldInfoMirror field in type.GetFields ()) {
+ if (IsHoistedThisReference (field))
+ return new FieldValueReference (cx, field, val, type, "this", ObjectValueFlags.Literal);
+
+ if (IsClosureReferenceField (field)) {
+ var fieldRef = new FieldValueReference (cx, field, val, type);
+ var thisRef = GetHoistedThisReference (cx, field.FieldType, fieldRef.Value);
+ if (thisRef != null)
+ return thisRef;
+ }
+ }
+
+ return null;
+ }
+
+ // if the local does not have a name, constructs one from the index
+ static string GetLocalName (SoftEvaluationContext cx, LocalVariable local)
+ {
+ if (!string.IsNullOrEmpty (local.Name) || cx.SourceCodeAvailable)
+ return local.Name;
+ return "loc" + local.Index;
+ }
+
+ protected override ValueReference OnGetLocalVariable (EvaluationContext ctx, string name)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ if (InGeneratedClosureOrIteratorType (cx))
+ return FindByName (OnGetLocalVariables (cx), v => v.Name, name, ctx.CaseSensitive);
+
+ try {
+ LocalVariable local = null;
+ if (!cx.SourceCodeAvailable) {
+ if (name.StartsWith ("loc", StringComparison.Ordinal)) {
+ int idx;
+ if (int.TryParse (name.Substring (3), out idx))
+ local = cx.Frame.Method.GetLocals ().FirstOrDefault (loc => loc.Index == idx);
+ }
+ } else {
+ local = ctx.CaseSensitive
+ ? cx.Frame.GetVisibleVariableByName (name)
+ : FindByName (cx.Frame.GetVisibleVariables(), v => v.Name, name, false);
+ }
+ if (local != null) {
+ return new VariableValueReference (ctx, GetLocalName (cx, local), local);
+ }
+ return FindByName (OnGetLocalVariables (ctx), v => v.Name, name, ctx.CaseSensitive);
+ } catch (AbsentInformationException) {
+ return null;
+ }
+ }
+
+ protected override IEnumerable<ValueReference> OnGetLocalVariables (EvaluationContext ctx)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ if (InGeneratedClosureOrIteratorType (cx)) {
+ ValueReference vthis = GetThisReference (cx);
+ return GetHoistedLocalVariables (cx, vthis).Union (GetLocalVariables (cx));
+ }
+
+ return GetLocalVariables (cx);
+ }
+
+ IEnumerable<ValueReference> GetLocalVariables (SoftEvaluationContext cx)
+ {
+ IList<LocalVariable> locals;
+ try {
+ locals = cx.Frame.GetVisibleVariables ();
+ } catch (AbsentInformationException) {
+ yield break;
+ }
+ foreach (LocalVariable local in locals) {
+ if (local.IsArg)
+ continue;
+ if (IsClosureReferenceLocal (local) && IsGeneratedType (local.Type)) {
+ foreach (var gv in GetHoistedLocalVariables (cx, new VariableValueReference (cx, local.Name, local))) {
+ yield return gv;
+ }
+ } else if (!IsGeneratedTemporaryLocal (local)) {
+ yield return new VariableValueReference (cx, GetLocalName (cx, local), local);
+ }
+ }
+ }
+
+ public override bool HasMember (EvaluationContext ctx, object type, string memberName, BindingFlags bindingFlags)
+ {
+ TypeMirror tm = (TypeMirror) type;
+
+ while (tm != null) {
+ FieldInfoMirror field = FindByName (tm.GetFields (), f => f.Name, memberName, ctx.CaseSensitive);
+ if (field != null)
+ return true;
+
+ PropertyInfoMirror prop = FindByName (tm.GetProperties (), p => p.Name, memberName, ctx.CaseSensitive);
+ if (prop != null) {
+ MethodMirror getter = prop.GetGetMethod (bindingFlags.HasFlag (BindingFlags.NonPublic));
+ if (getter != null)
+ return true;
+ }
+
+ if (bindingFlags.HasFlag (BindingFlags.DeclaredOnly))
+ break;
+
+ tm = tm.BaseType;
+ }
+
+ return false;
+ }
+
+ static bool IsAnonymousType (TypeMirror type)
+ {
+ return type.Name.StartsWith ("<>__AnonType", StringComparison.Ordinal);
+ }
+
+ protected override ValueReference GetMember (EvaluationContext ctx, object t, object co, string name)
+ {
+ TypeMirror type = t as TypeMirror;
+
+ while (type != null) {
+ FieldInfoMirror field = FindByName (type.GetFields (), f => f.Name, name, ctx.CaseSensitive);
+ if (field != null && (field.IsStatic || co != null))
+ return new FieldValueReference (ctx, field, co, type);
+
+ PropertyInfoMirror prop = FindByName (type.GetProperties (), p => p.Name, name, ctx.CaseSensitive);
+ if (prop != null && (IsStatic (prop) || co != null)) {
+ // Optimization: if the property has a CompilerGenerated backing field, use that instead.
+ // This way we avoid overhead of invoking methods on the debugee when the value is requested.
+ string cgFieldName = string.Format ("<{0}>{1}", prop.Name, IsAnonymousType (type) ? "" : "k__BackingField");
+ if ((field = FindByName (type.GetFields (), f => f.Name, cgFieldName, true)) != null && IsCompilerGenerated (field))
+ return new FieldValueReference (ctx, field, co, type, prop.Name, ObjectValueFlags.Property);
+
+ // Backing field not available, so do things the old fashioned way.
+ MethodMirror getter = prop.GetGetMethod (true);
+ if (getter == null)
+ return null;
+
+ return new PropertyValueReference (ctx, prop, co, type, getter, null);
+ }
+
+ type = type.BaseType;
+ }
+
+ return null;
+ }
+
+ static bool IsCompilerGenerated (FieldInfoMirror field)
+ {
+ var attrs = field.GetCustomAttributes (true);
+ var generated = GetAttribute<CompilerGeneratedAttribute> (attrs);
+
+ return generated != null;
+ }
+
+ static bool IsStatic (PropertyInfoMirror prop)
+ {
+ MethodMirror met = prop.GetGetMethod (true) ?? prop.GetSetMethod (true);
+ return met.IsStatic;
+ }
+
+ static T FindByName<T> (IEnumerable<T> elems, Func<T,string> getName, string name, bool caseSensitive)
+ {
+ T best = default(T);
+ foreach (T t in elems) {
+ string n = getName (t);
+ if (n == name)
+ return t;
+ if (!caseSensitive && n.Equals (name, StringComparison.CurrentCultureIgnoreCase))
+ best = t;
+ }
+ return best;
+ }
+
+ protected override IEnumerable<ValueReference> GetMembers (EvaluationContext ctx, object t, object co, BindingFlags bindingFlags)
+ {
+ Dictionary<string, PropertyInfoMirror> subProps = new Dictionary<string, PropertyInfoMirror> ();
+ TypeMirror type = t as TypeMirror;
+ TypeMirror realType = null;
+ if (co != null && (bindingFlags & BindingFlags.Instance) != 0)
+ realType = GetValueType (ctx, co) as TypeMirror;
+
+ // First of all, get a list of properties overriden in sub-types
+ while (realType != null && realType != type) {
+ foreach (PropertyInfoMirror prop in realType.GetProperties (bindingFlags | BindingFlags.DeclaredOnly)) {
+ MethodMirror met = prop.GetGetMethod (true);
+ if (met == null || met.GetParameters ().Length != 0 || met.IsAbstract || !met.IsVirtual || met.IsStatic)
+ continue;
+ if (met.IsPublic && ((bindingFlags & BindingFlags.Public) == 0))
+ continue;
+ if (!met.IsPublic && ((bindingFlags & BindingFlags.NonPublic) == 0))
+ continue;
+ subProps [prop.Name] = prop;
+ }
+ realType = realType.BaseType;
+ }
+
+ while (type != null) {
+ foreach (FieldInfoMirror field in type.GetFields ()) {
+ if (field.IsStatic && ((bindingFlags & BindingFlags.Static) == 0))
+ continue;
+ if (!field.IsStatic && ((bindingFlags & BindingFlags.Instance) == 0))
+ continue;
+ if (field.IsPublic && ((bindingFlags & BindingFlags.Public) == 0))
+ continue;
+ if (!field.IsPublic && ((bindingFlags & BindingFlags.NonPublic) == 0))
+ continue;
+ yield return new FieldValueReference (ctx, field, co, type);
+ }
+ foreach (PropertyInfoMirror prop in type.GetProperties (bindingFlags)) {
+ MethodMirror getter = prop.GetGetMethod (true);
+ if (getter == null || getter.GetParameters ().Length != 0 || getter.IsAbstract)
+ continue;
+ if (getter.IsStatic && ((bindingFlags & BindingFlags.Static) == 0))
+ continue;
+ if (!getter.IsStatic && ((bindingFlags & BindingFlags.Instance) == 0))
+ continue;
+ if (getter.IsPublic && ((bindingFlags & BindingFlags.Public) == 0))
+ continue;
+ if (!getter.IsPublic && ((bindingFlags & BindingFlags.NonPublic) == 0))
+ continue;
+
+ // If a property is overriden, return the override instead of the base property
+ PropertyInfoMirror overridden;
+ if (getter.IsVirtual && subProps.TryGetValue (prop.Name, out overridden)) {
+ getter = overridden.GetGetMethod (true);
+ if (getter == null)
+ continue;
+
+ yield return new PropertyValueReference (ctx, overridden, co, overridden.DeclaringType, getter, null);
+ } else {
+ yield return new PropertyValueReference (ctx, prop, co, type, getter, null);
+ }
+ }
+ if ((bindingFlags & BindingFlags.DeclaredOnly) != 0)
+ break;
+ type = type.BaseType;
+ }
+ }
+
+ static bool IsIEnumerable (TypeMirror type)
+ {
+ if (!type.IsInterface)
+ return false;
+
+ if (type.Namespace == "System.Collections" && type.Name == "IEnumerable")
+ return true;
+
+ if (type.Namespace == "System.Collections.Generic" && type.Name == "IEnumerable`1")
+ return true;
+
+ return false;
+ }
+
+ protected override CompletionData GetMemberCompletionData (EvaluationContext ctx, ValueReference vr)
+ {
+ HashSet<string> properties = new HashSet<string> ();
+ HashSet<string> methods = new HashSet<string> ();
+ HashSet<string> fields = new HashSet<string> ();
+ CompletionData data = new CompletionData ();
+ var type = vr.Type as TypeMirror;
+ bool isEnumerable = false;
+
+ while (type != null) {
+ if (!isEnumerable && IsIEnumerable (type))
+ isEnumerable = true;
+
+ foreach (var field in type.GetFields ()) {
+ if (field.IsStatic || field.IsSpecialName || !field.IsPublic)
+ continue;
+
+ if (fields.Add (field.Name))
+ data.Items.Add (new CompletionItem (field.Name, FieldValueReference.GetFlags (field)));
+ }
+
+ foreach (var property in type.GetProperties ()) {
+ var getter = property.GetGetMethod (true);
+
+ if (getter == null || getter.IsStatic || !getter.IsPublic)
+ continue;
+
+ if (properties.Add (property.Name))
+ data.Items.Add (new CompletionItem (property.Name, PropertyValueReference.GetFlags (property, getter)));
+ }
+
+ foreach (var method in type.GetMethods ()) {
+ if (method.IsStatic || method.IsConstructor || method.IsSpecialName || !method.IsPublic)
+ continue;
+
+ if (methods.Add (method.Name))
+ data.Items.Add (new CompletionItem (method.Name, ObjectValueFlags.Method | ObjectValueFlags.Public));
+ }
+
+ if (type.BaseType == null && type.FullName != "System.Object")
+ type = ctx.Adapter.GetType (ctx, "System.Object") as TypeMirror;
+ else
+ type = type.BaseType;
+ }
+
+ type = (TypeMirror) vr.Type;
+ foreach (var iface in type.GetInterfaces ()) {
+ if (!isEnumerable && IsIEnumerable (iface))
+ isEnumerable = true;
+ }
+
+ if (isEnumerable) {
+ // Look for LINQ extension methods...
+ var linq = ctx.Adapter.GetType (ctx, "System.Linq.Enumerable") as TypeMirror;
+ if (linq != null) {
+ foreach (var method in linq.GetMethods ()) {
+ if (!method.IsStatic || method.IsConstructor || method.IsSpecialName || !method.IsPublic)
+ continue;
+
+ if (methods.Add (method.Name))
+ data.Items.Add (new CompletionItem (method.Name, ObjectValueFlags.Method | ObjectValueFlags.Public));
+ }
+ }
+ }
+
+ data.ExpressionLength = 0;
+
+ return data;
+ }
+
+ public override void GetNamespaceContents (EvaluationContext ctx, string namspace, out string[] childNamespaces, out string[] childTypes)
+ {
+ var soft = (SoftEvaluationContext) ctx;
+ var types = new HashSet<string> ();
+ var namespaces = new HashSet<string> ();
+ var namspacePrefix = namspace.Length > 0 ? namspace + "." : "";
+
+ foreach (var type in soft.Session.GetAllTypes ()) {
+ if (type.Namespace == namspace || type.Namespace.StartsWith (namspacePrefix, StringComparison.InvariantCulture)) {
+ namespaces.Add (type.Namespace);
+ types.Add (type.FullName);
+ }
+ }
+
+ childNamespaces = new string [namespaces.Count];
+ namespaces.CopyTo (childNamespaces);
+
+ childTypes = new string [types.Count];
+ types.CopyTo (childTypes);
+ }
+
+ protected override IEnumerable<ValueReference> OnGetParameters (EvaluationContext ctx)
+ {
+ SoftEvaluationContext soft = (SoftEvaluationContext) ctx;
+ LocalVariable[] locals;
+
+ try {
+ locals = soft.Frame.Method.GetLocals ();
+ } catch (AbsentInformationException) {
+ yield break;
+ }
+
+ foreach (LocalVariable var in locals) {
+ if (var.IsArg) {
+ string name = !string.IsNullOrEmpty (var.Name) ? var.Name : "arg" + var.Index;
+ yield return new VariableValueReference (ctx, name, var);
+ }
+ }
+ }
+
+ protected override ValueReference OnGetThisReference (EvaluationContext ctx)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ if (InGeneratedClosureOrIteratorType (cx))
+ return GetHoistedThisReference (cx);
+
+ return GetThisReference (cx);
+ }
+
+ ValueReference GetThisReference (SoftEvaluationContext cx)
+ {
+ try {
+ if (cx.Frame.Method.IsStatic)
+ return null;
+ Value val = cx.Frame.GetThis ();
+ return LiteralValueReference.CreateTargetObjectLiteral (cx, "this", val);
+ } catch (AbsentInformationException) {
+ return null;
+ }
+ }
+
+ public override ValueReference GetCurrentException (EvaluationContext ctx)
+ {
+ try {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+ ObjectMirror exc = cx.Session.GetExceptionObject (cx.Thread);
+ if (exc != null)
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, ctx.Options.CurrentExceptionTag, exc);
+
+ return null;
+ } catch (AbsentInformationException) {
+ return null;
+ }
+ }
+
+ public override bool IsGenericType (EvaluationContext ctx, object type)
+ {
+ return type != null && ((TypeMirror) type).IsGenericType;
+ }
+
+ public override object[] GetTypeArgs (EvaluationContext ctx, object type)
+ {
+ TypeMirror tm = (TypeMirror) type;
+
+ if (tm.VirtualMachine.Version.AtLeast (2, 15))
+ return tm.GetGenericArguments ();
+
+ // fall back to parsing them from the from the FullName
+ List<string> names = new List<string> ();
+ string s = tm.FullName;
+ int i = s.IndexOf ('`');
+
+ if (i != -1) {
+ i = s.IndexOf ('[', i);
+ if (i == -1)
+ return new object [0];
+ int si = ++i;
+ int nt = 0;
+ for (; i < s.Length && (nt > 0 || s[i] != ']'); i++) {
+ if (s[i] == '[')
+ nt++;
+ else if (s[i] == ']')
+ nt--;
+ else if (s[i] == ',' && nt == 0) {
+ names.Add (s.Substring (si, i - si));
+ si = i + 1;
+ }
+ }
+ names.Add (s.Substring (si, i - si));
+ object[] types = new object [names.Count];
+ for (int n=0; n<names.Count; n++) {
+ string tn = names [n];
+ if (tn.StartsWith ("[", StringComparison.Ordinal))
+ tn = tn.Substring (1, tn.Length - 2);
+ types [n] = GetType (ctx, tn);
+ if (types [n] == null)
+ return new object [0];
+ }
+ return types;
+ }
+
+ return new object [0];
+ }
+
+ public override object GetType (EvaluationContext ctx, string name, object[] typeArgs)
+ {
+ SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
+
+ int i = name.IndexOf (',');
+ if (i != -1) {
+ // Find first comma outside brackets
+ int nest = 0;
+ for (int n = 0; n < name.Length; n++) {
+ char c = name [n];
+ if (c == '[')
+ nest++;
+ else if (c == ']')
+ nest--;
+ else if (c == ',' && nest == 0) {
+ name = name.Substring (0, n).Trim ();
+ break;
+ }
+ }
+ }
+
+ if (typeArgs != null && typeArgs.Length > 0) {
+ string args = "";
+ foreach (object t in typeArgs) {
+ if (args.Length > 0)
+ args += ",";
+ string tn;
+ if (t is TypeMirror) {
+ TypeMirror atm = (TypeMirror) t;
+ tn = atm.FullName + "," + atm.Assembly.GetName ();
+ } else {
+ Type atm = (Type) t;
+ tn = atm.FullName + "," + atm.Assembly.GetName ();
+ }
+ if (tn.IndexOf (',') != -1)
+ tn = "[" + tn + "]";
+ args += tn;
+ }
+ name += "[" +args + "]";
+ }
+
+ TypeMirror tm = cx.Session.GetType (name);
+ if (tm != null)
+ return tm;
+
+ foreach (AssemblyMirror asm in cx.Thread.Domain.GetAssemblies ()) {
+ tm = asm.GetType (name, false, false);
+ if (tm != null)
+ return tm;
+ }
+ return null;
+ }
+
+ public override object GetParentType (EvaluationContext ctx, object type)
+ {
+ TypeMirror tm = type as TypeMirror;
+
+ if (tm != null) {
+ int plus = tm.FullName.LastIndexOf ('+');
+
+ return plus != -1 ? GetType (ctx, tm.FullName.Substring (0, plus)) : null;
+ }
+
+ return ((Type) type).DeclaringType;
+ }
+
+ public override IEnumerable<object> GetNestedTypes (EvaluationContext ctx, object type)
+ {
+ TypeMirror t = (TypeMirror) type;
+ foreach (TypeMirror nt in t.GetNestedTypes ())
+ yield return nt;
+ }
+
+ public override string GetTypeName (EvaluationContext ctx, object type)
+ {
+ TypeMirror tm = type as TypeMirror;
+ if (tm != null) {
+ if (IsGeneratedType (tm)) {
+ // Return the name of the container-type.
+ return tm.FullName.Substring (0, tm.FullName.LastIndexOf ('+'));
+ }
+
+ return tm.FullName;
+ }
+
+ return ((Type)type).FullName;
+ }
+
+ public override object GetValueType (EvaluationContext ctx, object val)
+ {
+ if (val == null)
+ return typeof (Object);
+ if (val is ArrayMirror)
+ return ((ArrayMirror)val).Type;
+ if (val is ObjectMirror)
+ return ((ObjectMirror)val).Type;
+ if (val is EnumMirror)
+ return ((EnumMirror)val).Type;
+ if (val is StructMirror)
+ return ((StructMirror)val).Type;
+ if (val is PointerValue)
+ return ((PointerValue) val).Type;
+ if (val is PrimitiveValue) {
+ PrimitiveValue pv = (PrimitiveValue) val;
+ if (pv.Value == null)
+ return typeof(Object);
+
+ return pv.Value.GetType ();
+ }
+
+ throw new NotSupportedException ();
+ }
+
+ public override object GetBaseType (EvaluationContext ctx, object type)
+ {
+ if (type is TypeMirror)
+ return ((TypeMirror)type).BaseType;
+
+ return null;
+ }
+
+ public override bool HasMethod (EvaluationContext ctx, object targetType, string methodName, object[] genericTypeArgs, object[] argTypes, BindingFlags flags)
+ {
+ SoftEvaluationContext soft = (SoftEvaluationContext) ctx;
+ TypeMirror[] typeArgs = null;
+ TypeMirror[] types = null;
+
+ if (genericTypeArgs != null) {
+ typeArgs = new TypeMirror [genericTypeArgs.Length];
+ for (int n = 0; n < genericTypeArgs.Length; n++) {
+ if (genericTypeArgs[n] is TypeMirror)
+ typeArgs[n] = (TypeMirror) genericTypeArgs[n];
+ else
+ typeArgs[n] = (TypeMirror) GetType (soft, ((Type) genericTypeArgs[n]).FullName);
+ }
+ }
+
+ if (argTypes != null) {
+ types = new TypeMirror [argTypes.Length];
+ for (int n = 0; n < argTypes.Length; n++) {
+ if (argTypes[n] is TypeMirror)
+ types[n] = (TypeMirror) argTypes[n];
+ else
+ types[n] = (TypeMirror) GetType (soft, ((Type) argTypes[n]).FullName);
+ }
+ }
+
+ MethodMirror method = OverloadResolve (soft, (TypeMirror) targetType, methodName, typeArgs, types, (flags & BindingFlags.Instance) != 0, (flags & BindingFlags.Static) != 0, false);
+ return method != null;
+ }
+
+ public override bool IsExternalType (EvaluationContext ctx, object type)
+ {
+ TypeMirror tm = type as TypeMirror;
+
+ if (tm != null)
+ return ((SoftEvaluationContext) ctx).Session.IsExternalCode (tm);
+
+ return true;
+ }
+
+ public override bool IsString (EvaluationContext ctx, object val)
+ {
+ return val is StringMirror;
+ }
+
+ public override bool IsArray (EvaluationContext ctx, object val)
+ {
+ return val is ArrayMirror;
+ }
+
+ public override bool IsValueType (object type)
+ {
+ TypeMirror t = type as TypeMirror;
+ return t != null && t.IsValueType;
+ }
+
+ public override bool IsClass (EvaluationContext ctx, object type)
+ {
+ TypeMirror t = type as TypeMirror;
+ return t != null && (t.IsClass || t.IsValueType) && !t.IsPrimitive;
+ }
+
+ public override bool IsNull (EvaluationContext ctx, object val)
+ {
+ return val == null || ((val is PrimitiveValue) && ((PrimitiveValue)val).Value == null) || ((val is PointerValue) && ((PointerValue)val).Address == 0);
+ }
+
+ public override bool IsPrimitive (EvaluationContext ctx, object val)
+ {
+ return val is PrimitiveValue || val is StringMirror || ((val is StructMirror) && ((StructMirror)val).Type.IsPrimitive) || val is PointerValue;
+ }
+
+ public override bool IsPointer (EvaluationContext ctx, object val)
+ {
+ return val is PointerValue;
+ }
+
+ public override bool IsEnum (EvaluationContext ctx, object val)
+ {
+ return val is EnumMirror;
+ }
+
+ protected override TypeDisplayData OnGetTypeDisplayData (EvaluationContext ctx, object type)
+ {
+ SoftEvaluationContext soft = (SoftEvaluationContext) ctx;
+
+ Dictionary<string, DebuggerBrowsableState> memberData = null;
+ bool isCompilerGenerated = false;
+ string displayValue = null;
+ string displayName = null;
+ string displayType = null;
+ string proxyType = null;
+
+
+ try {
+ var tm = (TypeMirror) type;
+ foreach (var attr in tm.GetCustomAttributes (true)) {
+ string attrName = attr.Constructor.DeclaringType.FullName;
+ if (attrName == "System.Diagnostics.DebuggerDisplayAttribute") {
+ var display = BuildAttribute<DebuggerDisplayAttribute> (attr);
+ displayValue = display.Value;
+ displayName = display.Name;
+ displayType = display.Type;
+ } else if (attrName == "System.Diagnostics.DebuggerTypeProxyAttribute") {
+ var proxy = BuildAttribute<DebuggerTypeProxyAttribute> (attr);
+ proxyType = proxy.ProxyTypeName;
+ if (!string.IsNullOrEmpty (proxyType))
+ ForceLoadType (soft, proxyType);
+ } else if (attrName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute") {
+ isCompilerGenerated = true;
+ }
+ }
+
+ foreach (var field in tm.GetFields ()) {
+ var attrs = field.GetCustomAttributes (true);
+ var browsable = GetAttribute <DebuggerBrowsableAttribute> (attrs);
+
+ if (browsable == null) {
+ var generated = GetAttribute<CompilerGeneratedAttribute> (attrs);
+ if (generated != null)
+ browsable = new DebuggerBrowsableAttribute (DebuggerBrowsableState.Never);
+ }
+
+ if (browsable != null) {
+ if (memberData == null)
+ memberData = new Dictionary<string, DebuggerBrowsableState> ();
+ memberData [field.Name] = browsable.State;
+ }
+ }
+
+ foreach (var property in tm.GetProperties ()) {
+ var browsable = GetAttribute <DebuggerBrowsableAttribute> (property.GetCustomAttributes (true));
+ if (browsable != null) {
+ if (memberData == null)
+ memberData = new Dictionary<string, DebuggerBrowsableState> ();
+ memberData [property.Name] = browsable.State;
+ }
+ }
+ } catch (Exception ex) {
+ soft.Session.WriteDebuggerOutput (true, ex.ToString ());
+ }
+
+ return new TypeDisplayData (proxyType, displayValue, displayType, displayName, isCompilerGenerated, memberData);
+ }
+
+ static T GetAttribute<T> (CustomAttributeDataMirror[] attrs)
+ {
+ foreach (var attr in attrs) {
+ if (attr.Constructor.DeclaringType.FullName == typeof(T).FullName)
+ return BuildAttribute<T> (attr);
+ }
+
+ return default(T);
+ }
+
+ public override bool IsTypeLoaded (EvaluationContext ctx, string typeName)
+ {
+ var soft = (SoftEvaluationContext) ctx;
+
+ return soft.Session.GetType (typeName) != null;
+ }
+
+ public override bool IsTypeLoaded (EvaluationContext ctx, object type)
+ {
+ var tm = (TypeMirror) type;
+
+ if (tm.VirtualMachine.Version.AtLeast (2, 23))
+ return tm.IsInitialized;
+
+ return IsTypeLoaded (ctx, tm.FullName);
+ }
+
+ public override bool ForceLoadType (EvaluationContext ctx, object type)
+ {
+ var soft = (SoftEvaluationContext) ctx;
+ var tm = (TypeMirror) type;
+
+ if (!tm.VirtualMachine.Version.AtLeast (2, 23))
+ return IsTypeLoaded (ctx, tm.FullName);
+
+ if (tm.IsInitialized)
+ return true;
+
+ if (!tm.Attributes.HasFlag (TypeAttributes.BeforeFieldInit))
+ return false;
+
+ MethodMirror cctor = OverloadResolve (soft, tm, ".cctor", null, new TypeMirror[0], false, true, false);
+ if (cctor == null)
+ return true;
+
+ try {
+ tm.InvokeMethod (soft.Thread, cctor, new Value[0], InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded);
+ } catch {
+ return false;
+ } finally {
+ soft.Session.StackVersion++;
+ }
+
+ return true;
+ }
+
+ static T BuildAttribute<T> (CustomAttributeDataMirror attr)
+ {
+ List<object> args = new List<object> ();
+
+ foreach (CustomAttributeTypedArgumentMirror arg in attr.ConstructorArguments) {
+ object val = arg.Value;
+ if (val is TypeMirror) {
+ // The debugger attributes that take a type as parameter of the constructor have
+ // a corresponding constructor overload that takes a type name. We'll use that
+ // constructor because we can't load target types in the debugger process.
+ // So what we do here is convert the Type to a String.
+ TypeMirror tm = (TypeMirror) val;
+ val = tm.FullName + ", " + tm.Assembly.ManifestModule.Name;
+ } else if (val is EnumMirror) {
+ EnumMirror em = (EnumMirror) val;
+ val = em.Value;
+ }
+ args.Add (val);
+ }
+
+ Type type = typeof(T);
+ object at = Activator.CreateInstance (type, args.ToArray ());
+ foreach (CustomAttributeNamedArgumentMirror arg in attr.NamedArguments) {
+ object val = arg.TypedValue.Value;
+ string postFix = "";
+ if (arg.TypedValue.ArgumentType == typeof(Type))
+ postFix = "TypeName";
+ if (arg.Field != null)
+ type.GetField (arg.Field.Name + postFix).SetValue (at, val);
+ else if (arg.Property != null)
+ type.GetProperty (arg.Property.Name + postFix).SetValue (at, val, null);
+ }
+
+ return (T) at;
+ }
+
+ TypeMirror ToTypeMirror (EvaluationContext ctx, object type)
+ {
+ TypeMirror t = type as TypeMirror;
+ if (t != null)
+ return t;
+ return (TypeMirror) GetType (ctx, ((Type)type).FullName);
+ }
+
+ public override object RuntimeInvoke (EvaluationContext ctx, object targetType, object target, string methodName, object[] argTypes, object[] argValues)
+ {
+ return RuntimeInvoke (ctx, targetType, target, methodName, new object [0], argTypes, argValues);
+ }
+
+ public override object RuntimeInvoke (EvaluationContext ctx, object targetType, object target, string methodName, object[] genericTypeArgs, object[] argTypes, object[] argValues)
+ {
+ var type = ToTypeMirror (ctx, targetType);
+ var soft = (SoftEvaluationContext) ctx;
+
+ soft.AssertTargetInvokeAllowed ();
+
+ TypeMirror[] genericTypes = new TypeMirror [genericTypeArgs != null ? genericTypeArgs.Length : 0];
+ for (int n = 0; n < genericTypes.Length; n++)
+ genericTypes[n] = ToTypeMirror (soft, genericTypeArgs[n]);
+
+ TypeMirror[] types = new TypeMirror [argTypes.Length];
+ for (int n = 0; n < argTypes.Length; n++)
+ types[n] = ToTypeMirror (soft, argTypes[n]);
+
+ MethodMirror method = OverloadResolve (soft, type, methodName, genericTypes, types, target != null, target == null, true);
+
+ ParameterInfoMirror[] mparams = method.GetParameters ();
+ Value[] values = new Value [argValues.Length];
+ for (int n = 0; n < argValues.Length; n++) {
+ var param_type = mparams[n].ParameterType;
+
+ if (param_type.FullName != types[n].FullName && !param_type.IsAssignableFrom (types[n]) && param_type.IsGenericType) {
+ bool throwCastException = true;
+
+ if (method.VirtualMachine.Version.AtLeast (2, 15)) {
+ var args = param_type.GetGenericArguments ();
+
+ if (args.Length == genericTypes.Length) {
+ var real_type = soft.Adapter.GetType (soft, param_type.GetGenericTypeDefinition ().FullName, genericTypes);
+
+ values[n] = (Value) TryCast (soft, (Value) argValues[n], real_type);
+ if (!(values[n] == null && argValues[n] != null && !soft.Adapter.IsNull (soft, argValues[n])))
+ throwCastException = false;
+ }
+ }
+
+ if (throwCastException) {
+ string fromType = !IsGeneratedType (types[n]) ? soft.Adapter.GetDisplayTypeName (soft, types[n]) : types[n].FullName;
+ string toType = soft.Adapter.GetDisplayTypeName (soft, param_type);
+
+ throw new EvaluatorException ("Argument {0}: Cannot implicitly convert `{1}' to `{2}'", n, fromType, toType);
+ }
+ } else {
+ values[n] = (Value) argValues[n];
+ }
+ }
+
+ return soft.RuntimeInvoke (method, target ?? targetType, values);
+ }
+
+ public static MethodMirror OverloadResolve (SoftEvaluationContext ctx, TypeMirror type, string methodName, TypeMirror[] genericTypeArgs, TypeMirror[] argTypes, bool allowInstance, bool allowStatic, bool throwIfNotFound)
+ {
+ List<MethodMirror> candidates = new List<MethodMirror> ();
+ var cache = ctx.Session.OverloadResolveCache;
+ TypeMirror currentType = type;
+
+ while (currentType != null) {
+ MethodMirror[] methods = null;
+
+ if (ctx.CaseSensitive) {
+ lock (cache) {
+ cache.TryGetValue (Tuple.Create (currentType, methodName), out methods);
+ }
+ }
+
+ if (methods == null) {
+ if (currentType.VirtualMachine.Version.AtLeast (2, 7))
+ methods = currentType.GetMethodsByNameFlags (methodName, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static, !ctx.CaseSensitive);
+ else
+ methods = currentType.GetMethods ();
+
+ if (ctx.CaseSensitive) {
+ lock (cache) {
+ cache [Tuple.Create (currentType, methodName)] = methods;
+ }
+ }
+ }
+
+ foreach (MethodMirror method in methods) {
+ if (method.Name == methodName || (!ctx.CaseSensitive && method.Name.Equals (methodName, StringComparison.CurrentCultureIgnoreCase))) {
+ MethodMirror actualMethod;
+
+ if (genericTypeArgs != null && genericTypeArgs.Length > 0 && method.VirtualMachine.Version.AtLeast (2, 24) && method.IsGenericMethod) {
+ actualMethod = method.GetGenericMethodDefinition ().MakeGenericMethod (genericTypeArgs);
+ } else {
+ actualMethod = method;
+ }
+
+ ParameterInfoMirror[] parms = actualMethod.GetParameters ();
+ if (argTypes == null || parms.Length == argTypes.Length && ((actualMethod.IsStatic && allowStatic) || (!actualMethod.IsStatic && allowInstance)))
+ candidates.Add (actualMethod);
+ }
+ }
+
+ if (argTypes == null && candidates.Count > 0)
+ break; // when argtypes is null, we are just looking for *any* match (not a specific match)
+
+ if (methodName == ".ctor")
+ break; // Can't create objects using constructor from base classes
+
+ // Make sure that we always pull in at least System.Object methods (this is mostly needed for cases where 'type' was an interface)
+ if (currentType.BaseType == null && currentType.FullName != "System.Object")
+ currentType = ctx.Adapter.GetType (ctx, "System.Object") as TypeMirror;
+ else
+ currentType = currentType.BaseType;
+ }
+
+ return OverloadResolve (ctx, type, methodName, genericTypeArgs, argTypes, candidates, throwIfNotFound);
+ }
+
+ static bool IsApplicable (SoftEvaluationContext ctx, MethodMirror method, TypeMirror[] genericTypeArgs, TypeMirror[] types, out string error, out int matchCount)
+ {
+ ParameterInfoMirror[] mparams = method.GetParameters ();
+ matchCount = 0;
+
+ for (int i = 0; i < types.Length; i++) {
+ TypeMirror param_type = mparams[i].ParameterType;
+
+ if (param_type.FullName == types[i].FullName) {
+ matchCount++;
+ continue;
+ }
+
+ if (param_type.IsAssignableFrom (types[i]))
+ continue;
+
+ if (param_type.IsGenericType) {
+ if (genericTypeArgs != null && method.VirtualMachine.Version.AtLeast (2, 12)) {
+ // FIXME: how can we make this more definitive?
+ if (param_type.GetGenericArguments ().Length == genericTypeArgs.Length)
+ continue;
+ } else {
+ // no way to check... assume it'll work?
+ continue;
+ }
+ }
+
+ string fromType = !IsGeneratedType (types[i]) ? ctx.Adapter.GetDisplayTypeName (ctx, types[i]) : types[i].FullName;
+ string toType = ctx.Adapter.GetDisplayTypeName (ctx, param_type);
+
+ error = String.Format ("Argument {0}: Cannot implicitly convert `{1}' to `{2}'", i, fromType, toType);
+ return false;
+ }
+
+ error = null;
+ return true;
+ }
+
+ static MethodMirror OverloadResolve (SoftEvaluationContext ctx, TypeMirror type, string methodName, TypeMirror[] genericTypeArgs, TypeMirror[] argTypes, List<MethodMirror> candidates, bool throwIfNotFound)
+ {
+ if (candidates.Count == 0) {
+ if (throwIfNotFound) {
+ string typeName = ctx.Adapter.GetDisplayTypeName (ctx, type);
+
+ if (methodName == null)
+ throw new EvaluatorException ("Indexer not found in type `{0}'.", typeName);
+
+ if (genericTypeArgs != null && genericTypeArgs.Length > 0) {
+ var types = string.Join (", ", genericTypeArgs.Select (t => ctx.Adapter.GetDisplayTypeName (ctx, t)));
+
+ throw new EvaluatorException ("Method `{0}<{1}>' not found in type `{2}'.", methodName, types, typeName);
+ }
+
+ throw new EvaluatorException ("Method `{0}' not found in type `{1}'.", methodName, typeName);
+ }
+
+ return null;
+ }
+
+ if (argTypes == null) {
+ // This is just a probe to see if the type contains *any* methods of the given name
+ return candidates[0];
+ }
+
+ if (candidates.Count == 1) {
+ string error;
+ int matchCount;
+
+ if (IsApplicable (ctx, candidates[0], genericTypeArgs, argTypes, out error, out matchCount))
+ return candidates[0];
+
+ if (throwIfNotFound)
+ throw new EvaluatorException ("Invalid arguments for method `{0}': {1}", methodName, error);
+
+ return null;
+ }
+
+ // Ok, now we need to find an exact match.
+ MethodMirror match = null;
+ int bestCount = -1;
+ bool repeatedBestCount = false;
+
+ foreach (MethodMirror method in candidates) {
+ string error;
+ int matchCount;
+
+ if (!IsApplicable (ctx, method, genericTypeArgs, argTypes, out error, out matchCount))
+ continue;
+
+ if (matchCount == bestCount) {
+ repeatedBestCount = true;
+ } else if (matchCount > bestCount) {
+ match = method;
+ bestCount = matchCount;
+ repeatedBestCount = false;
+ }
+ }
+
+ if (match == null) {
+ if (!throwIfNotFound)
+ return null;
+
+ if (methodName != null)
+ throw new EvaluatorException ("Invalid arguments for method `{0}'.", methodName);
+
+ throw new EvaluatorException ("Invalid arguments for indexer.");
+ }
+
+ if (repeatedBestCount) {
+ // If there is an ambiguous match, just pick the first match. If the user was expecting
+ // something else, he can provide more specific arguments
+
+/* if (!throwIfNotFound)
+ return null;
+ if (methodName != null)
+ throw new EvaluatorException ("Ambiguous method `{0}'; need to use full name", methodName);
+ else
+ throw new EvaluatorException ("Ambiguous arguments for indexer.", methodName);
+*/ }
+
+ return match;
+ }
+
+ public override object TargetObjectToObject (EvaluationContext ctx, object obj)
+ {
+ if (obj is StringMirror) {
+ StringMirror mirror = (StringMirror) obj;
+ string str;
+
+ if (ctx.Options.EllipsizeStrings) {
+ if (mirror.VirtualMachine.Version.AtLeast (2, 10)) {
+ int length = mirror.Length;
+
+ if (length > ctx.Options.EllipsizedLength)
+ str = new string (mirror.GetChars (0, ctx.Options.EllipsizedLength)) + EvaluationOptions.Ellipsis;
+ else
+ str = mirror.Value;
+ } else {
+ str = mirror.Value;
+ if (str.Length > ctx.Options.EllipsizedLength)
+ str = str.Substring (0, ctx.Options.EllipsizedLength) + EvaluationOptions.Ellipsis;
+ }
+ } else {
+ str = mirror.Value;
+ }
+
+ return str;
+ } else if (obj is PrimitiveValue) {
+ return ((PrimitiveValue)obj).Value;
+ } else if (obj is PointerValue) {
+ return new IntPtr (((PointerValue)obj).Address);
+ } else if (obj is StructMirror) {
+ StructMirror sm = (StructMirror) obj;
+
+ if (sm.Type.IsPrimitive) {
+ // Boxed primitive
+ if (sm.Type.FullName == "System.IntPtr")
+ return new IntPtr ((long)((PrimitiveValue)sm.Fields[0]).Value);
+ if (sm.Fields.Length > 0 && (sm.Fields[0] is PrimitiveValue))
+ return ((PrimitiveValue)sm.Fields[0]).Value;
+ } else if (sm.Type.FullName == "System.Decimal") {
+ SoftEvaluationContext soft = (SoftEvaluationContext) ctx;
+ MethodMirror method = OverloadResolve (soft, sm.Type, "GetBits", null, new TypeMirror[1] { sm.Type }, false, true, false);
+ if (method != null) {
+ ArrayMirror array;
+
+ try {
+ array = sm.Type.InvokeMethod (soft.Thread, method, new Value[1] { sm }, InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded) as ArrayMirror;
+ } catch {
+ array = null;
+ } finally {
+ soft.Session.StackVersion++;
+ }
+
+ if (array != null) {
+ int[] bits = new int [4];
+ for (int i = 0; i < 4; i++)
+ bits[i] = (int) TargetObjectToObject (ctx, array[i]);
+
+ return new decimal (bits);
+ }
+ }
+ }
+ }
+ return base.TargetObjectToObject (ctx, obj);
+ }
+ }
+
+ class MethodCall: AsyncOperation
+ {
+ const InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
+
+ readonly ST.ManualResetEvent shutdownEvent = new ST.ManualResetEvent (false);
+ readonly SoftEvaluationContext ctx;
+ readonly MethodMirror function;
+ readonly Value[] args;
+ readonly object obj;
+ IAsyncResult handle;
+ Exception exception;
+ Value result;
+
+ public MethodCall (SoftEvaluationContext ctx, MethodMirror function, object obj, Value[] args)
+ {
+ this.ctx = ctx;
+ this.function = function;
+ this.obj = obj;
+ this.args = args;
+ }
+
+ public override string Description {
+ get {
+ return function.DeclaringType.FullName + "." + function.Name;
+ }
+ }
+
+ public override void Invoke ()
+ {
+ try {
+ if (obj is ObjectMirror)
+ handle = ((ObjectMirror)obj).BeginInvokeMethod (ctx.Thread, function, args, options, null, null);
+ else if (obj is TypeMirror)
+ handle = ((TypeMirror)obj).BeginInvokeMethod (ctx.Thread, function, args, options, null, null);
+ else if (obj is StructMirror)
+ handle = ((StructMirror)obj).BeginInvokeMethod (ctx.Thread, function, args, options, null, null);
+ else if (obj is PrimitiveValue)
+ handle = ((PrimitiveValue)obj).BeginInvokeMethod (ctx.Thread, function, args, options, null, null);
+ else
+ throw new ArgumentException ("Soft debugger method calls cannot be invoked on objects of type " + obj.GetType ().Name);
+ } catch (InvocationException ex) {
+ ctx.Session.StackVersion++;
+ exception = ex;
+ } catch (Exception ex) {
+ ctx.Session.StackVersion++;
+ DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
+ exception = ex;
+ }
+ }
+
+ public override void Abort ()
+ {
+ if (handle is IInvokeAsyncResult) {
+ var info = GetInfo ();
+ DebuggerLoggingService.LogMessage ("Aborting invocation of " + info);
+ ((IInvokeAsyncResult) handle).Abort ();
+ // Don't wait for the abort to finish. The engine will do it.
+ } else {
+ throw new NotSupportedException ();
+ }
+ }
+
+ public override void Shutdown ()
+ {
+ shutdownEvent.Set ();
+ }
+
+ void EndInvoke ()
+ {
+ try {
+ if (obj is ObjectMirror)
+ result = ((ObjectMirror)obj).EndInvokeMethod (handle);
+ else if (obj is TypeMirror)
+ result = ((TypeMirror)obj).EndInvokeMethod (handle);
+ else if (obj is StructMirror)
+ result = ((StructMirror)obj).EndInvokeMethod (handle);
+ else
+ result = ((PrimitiveValue)obj).EndInvokeMethod (handle);
+ } catch (InvocationException ex) {
+ if (!Aborting && ex.Exception != null) {
+ string ename = ctx.Adapter.GetValueTypeName (ctx, ex.Exception);
+ ValueReference vref = ctx.Adapter.GetMember (ctx, null, ex.Exception, "Message");
+ if (vref != null) {
+ exception = new Exception (ename + ": " + (string)vref.ObjectValue);
+ return;
+ } else {
+ exception = new Exception (ename);
+ return;
+ }
+ }
+ exception = ex;
+ } catch (Exception ex) {
+ DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
+ exception = ex;
+ } finally {
+ ctx.Session.StackVersion++;
+ }
+ }
+
+ string GetInfo ()
+ {
+ try {
+ TypeMirror type = null;
+ if (obj is ObjectMirror)
+ type = ((ObjectMirror)obj).Type;
+ else if (obj is TypeMirror)
+ type = (TypeMirror)obj;
+ else if (obj is StructMirror)
+ type = ((StructMirror)obj).Type;
+ return string.Format ("method {0} on object {1}",
+ function == null? "[null]" : function.FullName,
+ type == null? "[null]" : type.FullName);
+ } catch (Exception ex) {
+ DebuggerLoggingService.LogError ("Error getting info for SDB MethodCall", ex);
+ return "";
+ }
+ }
+
+ public override bool WaitForCompleted (int timeout)
+ {
+ if (handle == null)
+ return true;
+ int res = ST.WaitHandle.WaitAny (new ST.WaitHandle[] { handle.AsyncWaitHandle, shutdownEvent }, timeout);
+ if (res == 0) {
+ EndInvoke ();
+ return true;
+ }
+ // Return true if shut down.
+ return res == 1;
+ }
+
+ public Value ReturnValue {
+ get {
+ if (exception != null)
+ throw new EvaluatorException (exception.Message);
+ return result;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/SoftDebuggerBacktrace.cs b/Mono.Debugging.Soft/SoftDebuggerBacktrace.cs
new file mode 100644
index 0000000..caf7546
--- /dev/null
+++ b/Mono.Debugging.Soft/SoftDebuggerBacktrace.cs
@@ -0,0 +1,215 @@
+//
+// SoftDebuggerBacktrace.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2009 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.Linq;
+using System.Text;
+using System.Collections.Generic;
+using Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+using MDB = Mono.Debugger.Soft;
+using DC = Mono.Debugging.Client;
+using Mono.Debugging.Evaluation;
+
+namespace Mono.Debugging.Soft
+{
+ internal class SoftDebuggerStackFrame : Mono.Debugging.Client.StackFrame {
+ public Mono.Debugger.Soft.StackFrame StackFrame {
+ get; private set;
+ }
+
+ public SoftDebuggerStackFrame (Mono.Debugger.Soft.StackFrame frame, string addressSpace, SourceLocation location, string language, bool isExternalCode, bool hasDebugInfo, bool isDebuggerHidden, string fullModuleName, string fullTypeName)
+ : base (frame.ILOffset, addressSpace, location, language, isExternalCode, hasDebugInfo, isDebuggerHidden, fullModuleName, fullTypeName)
+ {
+ StackFrame = frame;
+ }
+ }
+
+ public class SoftDebuggerBacktrace: BaseBacktrace
+ {
+ MDB.StackFrame[] frames;
+ SoftDebuggerSession session;
+ MDB.ThreadMirror thread;
+ int stackVersion;
+
+ public SoftDebuggerBacktrace (SoftDebuggerSession session, MDB.ThreadMirror thread): base (session.Adaptor)
+ {
+ this.session = session;
+ this.thread = thread;
+ stackVersion = session.StackVersion;
+ if (thread != null)
+ this.frames = thread.GetFrames ();
+ else
+ this.frames = new MDB.StackFrame[0];
+ }
+
+ void ValidateStack ()
+ {
+ if (stackVersion != session.StackVersion && thread != null)
+ frames = thread.GetFrames ();
+ }
+
+ public override DC.StackFrame[] GetStackFrames (int firstIndex, int lastIndex)
+ {
+ ValidateStack ();
+
+ if (lastIndex < 0)
+ lastIndex = frames.Length - 1;
+
+ List<DC.StackFrame> list = new List<DC.StackFrame> ();
+ for (int n = firstIndex; n <= lastIndex && n < frames.Length; n++)
+ list.Add (CreateStackFrame (frames[n], n));
+
+ return list.ToArray ();
+ }
+
+ public override int FrameCount {
+ get {
+ ValidateStack ();
+ return frames.Length;
+ }
+ }
+
+ DC.StackFrame CreateStackFrame (MDB.StackFrame frame, int frameIndex)
+ {
+ MDB.MethodMirror method = frame.Method;
+ MDB.TypeMirror type = method.DeclaringType;
+ string fileName = frame.FileName;
+ string typeFullName = null;
+ string typeFQN = null;
+ string methodName;
+
+ if (fileName != null)
+ fileName = SoftDebuggerSession.NormalizePath (fileName);
+
+ if (method.VirtualMachine.Version.AtLeast (2, 12) && method.IsGenericMethod) {
+ StringBuilder name = new StringBuilder (method.Name);
+
+ name.Append ('<');
+
+ if (method.VirtualMachine.Version.AtLeast (2, 15)) {
+ bool first = true;
+
+ foreach (var argumentType in method.GetGenericArguments ()) {
+ if (!first)
+ name.Append (", ");
+
+ name.Append (session.Adaptor.GetDisplayTypeName (argumentType.FullName));
+ first = false;
+ }
+ }
+
+ name.Append ('>');
+
+ methodName = name.ToString ();
+ } else {
+ methodName = method.Name;
+ }
+
+ // Compiler generated anonymous/lambda methods
+ bool special_method = false;
+ if (methodName [0] == '<' && methodName.Contains (">m__")) {
+ int nidx = methodName.IndexOf (">m__", StringComparison.Ordinal) + 2;
+ methodName = "AnonymousMethod" + methodName.Substring (nidx, method.Name.Length - nidx);
+ special_method = true;
+ }
+
+ if (type != null) {
+ string typeDisplayName = session.Adaptor.GetDisplayTypeName (type.FullName);
+
+ if (SoftDebuggerAdaptor.IsGeneratedType (type)) {
+ // The user-friendly method name is embedded in the generated type name
+ var mn = SoftDebuggerAdaptor.GetNameFromGeneratedType (type);
+
+ // Strip off the generated type name
+ int dot = typeDisplayName.LastIndexOf ('.');
+ var tname = typeDisplayName.Substring (0, dot);
+
+ // Keep any type arguments
+ int targs = typeDisplayName.LastIndexOf ('<');
+ if (targs > dot + 1)
+ mn += typeDisplayName.Substring (targs, typeDisplayName.Length - targs);
+
+ typeDisplayName = tname;
+
+ if (special_method)
+ typeDisplayName += "." + mn;
+ else
+ methodName = mn;
+ }
+
+ methodName = typeDisplayName + "." + methodName;
+
+ typeFQN = type.Module.FullyQualifiedName;
+ typeFullName = type.FullName;
+ }
+
+ bool hidden = false;
+ if (session.VirtualMachine.Version.AtLeast (2, 21)) {
+ var ctx = GetEvaluationContext (frameIndex, session.EvaluationOptions);
+ var hiddenAttr = session.Adaptor.GetType (ctx, "System.Diagnostics.DebuggerHiddenAttribute") as MDB.TypeMirror;
+
+ hidden = method.GetCustomAttributes (hiddenAttr, true).Any ();
+ }
+
+ var location = new DC.SourceLocation (methodName, fileName, frame.LineNumber, frame.ColumnNumber);
+ var external = session.IsExternalCode (frame);
+ string addressSpace = string.Empty;
+ bool hasDebugInfo = false;
+ string language;
+
+ if (frame.Method != null) {
+ if (frame.IsNativeTransition) {
+ language = "Transition";
+ } else {
+ addressSpace = method.FullName;
+ language = "Managed";
+ hasDebugInfo = true;
+ }
+ } else {
+ language = "Native";
+ }
+
+ return new SoftDebuggerStackFrame (frame, addressSpace, location, language, external, hasDebugInfo, hidden, typeFQN, typeFullName);
+ }
+
+ protected override EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options)
+ {
+ ValidateStack ();
+ if (frameIndex >= frames.Length)
+ return null;
+
+ MDB.StackFrame frame = frames [frameIndex];
+ return new SoftEvaluationContext (session, frame, options);
+ }
+
+ public override AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count)
+ {
+ return session.Disassemble (frames [frameIndex], firstLine, count);
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs
new file mode 100644
index 0000000..f718e0e
--- /dev/null
+++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs
@@ -0,0 +1,2638 @@
+//
+// SoftDebuggerSession.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2009 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.
+
+//#define DEBUG_EVENT_QUEUEING
+
+using System;
+using System.IO;
+using System.Net;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Reflection;
+using System.Net.Sockets;
+using System.Globalization;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using Mono.Cecil.Mdb;
+using Mono.CompilerServices.SymbolWriter;
+using Mono.Debugging.Client;
+using Mono.Debugger.Soft;
+using Mono.Debugging.Evaluation;
+using MDB = Mono.Debugger.Soft;
+
+namespace Mono.Debugging.Soft
+{
+ public class SoftDebuggerSession : DebuggerSession
+ {
+ VirtualMachine vm;
+ Thread eventHandler;
+ Dictionary<string, List<TypeMirror>> source_to_type = new Dictionary<string, List<TypeMirror>> (PathComparer);
+ Dictionary<TypeMirror, string[]> type_to_source = new Dictionary<TypeMirror, string[]> ();
+ bool useFullPaths = true;
+ Dictionary<string,TypeMirror> types = new Dictionary<string, TypeMirror> ();
+ Dictionary<string, MonoSymbolFile> symbolFiles = new Dictionary<string, MonoSymbolFile> ();
+ Dictionary<EventRequest,BreakInfo> breakpoints = new Dictionary<EventRequest,BreakInfo> ();
+ List<BreakInfo> pending_bes = new List<BreakInfo> ();
+ ThreadMirror current_thread, recent_thread;
+ ProcessInfo[] procs;
+ ThreadInfo[] current_threads;
+ bool started;
+ bool autoStepInto;
+ internal int StackVersion;
+ StepEventRequest currentStepRequest;
+ long currentAddress = -1;
+ ExceptionEventRequest unhandledExceptionRequest;
+ string remoteProcessName;
+ Dictionary<long,long> localThreadIds = new Dictionary<long, long> ();
+ IConnectionDialog connectionDialog;
+ TypeLoadEventRequest typeLoadReq, typeLoadTypeNameReq;
+
+ Dictionary<long,ObjectMirror> activeExceptionsByThread = new Dictionary<long, ObjectMirror> ();
+
+ Thread outputReader;
+ Thread errorReader;
+
+ IAsyncResult connectionHandle;
+ SoftDebuggerStartArgs startArgs;
+
+ LinkedList<List<Event>> queuedEventSets = new LinkedList<List<Event>> ();
+
+ List<string> userAssemblyNames;
+ List<AssemblyMirror> assemblyFilters;
+ Dictionary<string, string> assemblyPathMap;
+
+ bool loggedSymlinkedRuntimesBug = false;
+
+ Dictionary<Tuple<TypeMirror,string>, MethodMirror[]> overloadResolveCache;
+
+ public SoftDebuggerAdaptor Adaptor {
+ get { return adaptor; }
+ }
+
+ readonly SoftDebuggerAdaptor adaptor = new SoftDebuggerAdaptor ();
+
+ public SoftDebuggerSession ()
+ {
+ Adaptor.BusyStateChanged += delegate(object sender, BusyStateEventArgs e) {
+ SetBusyState (e);
+ };
+ overloadResolveCache = new Dictionary<Tuple<TypeMirror,string>, MethodMirror[]> ();
+ }
+
+ protected override void OnRun (DebuggerStartInfo startInfo)
+ {
+ if (HasExited)
+ throw new InvalidOperationException ("Already exited");
+
+ var dsi = (SoftDebuggerStartInfo) startInfo;
+ if (dsi.StartArgs is SoftDebuggerLaunchArgs) {
+ StartLaunching (dsi);
+ } else if (dsi.StartArgs is SoftDebuggerConnectArgs) {
+ StartConnecting (dsi);
+ } else if (dsi.StartArgs is SoftDebuggerListenArgs) {
+ StartListening (dsi);
+ } else if (dsi.StartArgs.ConnectionProvider != null) {
+ StartConnection (dsi);
+ } else {
+ throw new ArgumentException ("StartArgs has no ConnectionProvider");
+ }
+ }
+
+ void StartConnection (SoftDebuggerStartInfo dsi)
+ {
+ startArgs = dsi.StartArgs;
+
+ RegisterUserAssemblies (dsi);
+
+ if (!String.IsNullOrEmpty (dsi.LogMessage))
+ LogWriter (false, dsi.LogMessage + "\n");
+
+ AsyncCallback callback = null;
+ int attemptNumber = 0;
+ int maxAttempts = startArgs.MaxConnectionAttempts;
+ int timeBetweenAttempts = startArgs.TimeBetweenConnectionAttempts;
+ callback = delegate (IAsyncResult ar) {
+ try {
+ string appName;
+ VirtualMachine vm;
+ startArgs.ConnectionProvider.EndConnect (ar, out vm, out appName);
+ remoteProcessName = appName;
+ ConnectionStarted (vm);
+ return;
+ } catch (Exception ex) {
+ attemptNumber++;
+ if (!ShouldRetryConnection (ex, attemptNumber)
+ || !startArgs.ConnectionProvider.ShouldRetryConnection (ex)
+ || attemptNumber == maxAttempts
+ || HasExited)
+ {
+ OnConnectionError (ex);
+ return;
+ }
+ }
+ try {
+ if (timeBetweenAttempts > 0)
+ Thread.Sleep (timeBetweenAttempts);
+ ConnectionStarting (startArgs.ConnectionProvider.BeginConnect (dsi, callback), dsi, false, 0);
+ } catch (Exception ex2) {
+ OnConnectionError (ex2);
+ }
+ };
+ //the "listening" value is never used, pass a dummy value
+ ConnectionStarting (startArgs.ConnectionProvider.BeginConnect (dsi, callback), dsi, false, 0);
+ }
+
+ void StartLaunching (SoftDebuggerStartInfo dsi)
+ {
+ var args = (SoftDebuggerLaunchArgs) dsi.StartArgs;
+ var runtime = string.IsNullOrEmpty (args.MonoRuntimePrefix) ? "mono" : Path.Combine (Path.Combine (args.MonoRuntimePrefix, "bin"), "mono");
+ RegisterUserAssemblies (dsi);
+
+ var psi = new System.Diagnostics.ProcessStartInfo (runtime) {
+ Arguments = string.Format ("\"{0}\" {1}", dsi.Command, dsi.Arguments),
+ WorkingDirectory = dsi.WorkingDirectory,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ };
+
+ LaunchOptions options = null;
+
+ if (dsi.UseExternalConsole && args.ExternalConsoleLauncher != null) {
+ options = new LaunchOptions ();
+ options.CustomTargetProcessLauncher = args.ExternalConsoleLauncher;
+ psi.RedirectStandardOutput = false;
+ psi.RedirectStandardError = false;
+ }
+
+ var sdbLog = Environment.GetEnvironmentVariable ("MONODEVELOP_SDB_LOG");
+ if (!string.IsNullOrEmpty (sdbLog)) {
+ options = options ?? new LaunchOptions ();
+ options.AgentArgs = string.Format ("loglevel=1,logfile='{0}'", sdbLog);
+ }
+
+ foreach (var env in args.MonoRuntimeEnvironmentVariables)
+ psi.EnvironmentVariables[env.Key] = env.Value;
+
+ foreach (var env in dsi.EnvironmentVariables)
+ psi.EnvironmentVariables[env.Key] = env.Value;
+
+ if (!String.IsNullOrEmpty (dsi.LogMessage))
+ OnDebuggerOutput (false, dsi.LogMessage + "\n");
+
+ var callback = HandleConnectionCallbackErrors ((IAsyncResult ar) => {
+ ConnectionStarted (VirtualMachineManager.EndLaunch (ar));
+ });
+ ConnectionStarting (VirtualMachineManager.BeginLaunch (psi, callback, options), dsi, true, 0);
+ }
+
+ /// <summary>Starts the debugger listening for a connection over TCP/IP</summary>
+ protected void StartListening (SoftDebuggerStartInfo dsi)
+ {
+ int dp, cp;
+ StartListening (dsi, out dp, out cp);
+ }
+
+ /// <summary>Starts the debugger listening for a connection over TCP/IP</summary>
+ protected void StartListening (SoftDebuggerStartInfo dsi, out int assignedDebugPort)
+ {
+ int cp;
+ StartListening (dsi, out assignedDebugPort, out cp);
+ }
+
+ /// <summary>Starts the debugger listening for a connection over TCP/IP</summary>
+ protected void StartListening (SoftDebuggerStartInfo dsi, out int assignedDebugPort, out int assignedConsolePort)
+ {
+
+ IPEndPoint dbgEP, conEP;
+ InitForRemoteSession (dsi, out dbgEP, out conEP);
+
+ var callback = HandleConnectionCallbackErrors (delegate (IAsyncResult ar) {
+ ConnectionStarted (VirtualMachineManager.EndListen (ar));
+ });
+ var a = VirtualMachineManager.BeginListen (dbgEP, conEP, callback, out assignedDebugPort, out assignedConsolePort);
+ ConnectionStarting (a, dsi, true, 0);
+ }
+
+ protected virtual bool ShouldRetryConnection (Exception ex, int attemptNumber)
+ {
+ var sx = ex as SocketException;
+ if (sx != null) {
+ if (sx.ErrorCode == 10061) //connection refused
+ return true;
+ }
+ return false;
+ }
+
+ protected void StartConnecting (SoftDebuggerStartInfo dsi)
+ {
+ StartConnecting (dsi, dsi.StartArgs.MaxConnectionAttempts, dsi.StartArgs.TimeBetweenConnectionAttempts);
+ }
+
+ /// <summary>Starts the debugger connecting to a remote IP</summary>
+ protected void StartConnecting (SoftDebuggerStartInfo dsi, int maxAttempts, int timeBetweenAttempts)
+ {
+ if (timeBetweenAttempts < 0 || timeBetweenAttempts > 10000)
+ throw new ArgumentException ("timeBetweenAttempts");
+
+ IPEndPoint dbgEP, conEP;
+ InitForRemoteSession (dsi, out dbgEP, out conEP);
+
+ AsyncCallback callback = null;
+ int attemptNumber = 0;
+ callback = delegate (IAsyncResult ar) {
+ try {
+ ConnectionStarted (VirtualMachineManager.EndConnect (ar));
+ return;
+ } catch (Exception ex) {
+ attemptNumber++;
+ if (!ShouldRetryConnection (ex, attemptNumber) || attemptNumber == maxAttempts || HasExited) {
+ OnConnectionError (ex);
+ return;
+ }
+ }
+ try {
+ if (timeBetweenAttempts > 0)
+ System.Threading.Thread.Sleep (timeBetweenAttempts);
+
+ ConnectionStarting (VirtualMachineManager.BeginConnect (dbgEP, conEP, callback), dsi, false, attemptNumber);
+
+ } catch (Exception ex2) {
+ OnConnectionError (ex2);
+ }
+ };
+
+ ConnectionStarting (VirtualMachineManager.BeginConnect (dbgEP, conEP, callback), dsi, false, 0);
+ }
+
+ void InitForRemoteSession (SoftDebuggerStartInfo dsi, out IPEndPoint dbgEP, out IPEndPoint conEP)
+ {
+ if (remoteProcessName != null)
+ throw new InvalidOperationException ("Cannot initialize connection more than once");
+
+ var args = (SoftDebuggerRemoteArgs) dsi.StartArgs;
+
+ remoteProcessName = args.AppName;
+
+ RegisterUserAssemblies (dsi);
+
+ dbgEP = new IPEndPoint (args.Address, args.DebugPort);
+ conEP = args.RedirectOutput? new IPEndPoint (args.Address, args.OutputPort) : null;
+
+ if (!String.IsNullOrEmpty (dsi.LogMessage))
+ LogWriter (false, dsi.LogMessage + "\n");
+ }
+
+ ///<summary>Catches errors in async callbacks and hands off to OnConnectionError</summary>
+ AsyncCallback HandleConnectionCallbackErrors (AsyncCallback callback)
+ {
+ return delegate (IAsyncResult ar) {
+ connectionHandle = null;
+ try {
+ callback (ar);
+ } catch (Exception ex) {
+ OnConnectionError (ex);
+ }
+ };
+ }
+
+ /// <summary>
+ /// Called if an error happens while making the connection. Default terminates the session.
+ /// </summary>
+ protected virtual void OnConnectionError (Exception ex)
+ {
+ //if the exception was caused by cancelling the session
+ if (HasExited)
+ return;
+
+ if (!HandleException (new ConnectionException (ex))) {
+ DebuggerLoggingService.LogAndShowException ("Unhandled error launching soft debugger", ex);
+ }
+
+ // The session is dead
+ // HandleException doesn't actually handle exceptions, it just displays them.
+ EndSession ();
+ }
+
+ void ConnectionStarting (IAsyncResult connectionHandle, DebuggerStartInfo dsi, bool listening, int attemptNumber)
+ {
+ if (this.connectionHandle != null && (attemptNumber == 0 || !this.connectionHandle.IsCompleted))
+ throw new InvalidOperationException ("Already connecting");
+
+ this.connectionHandle = connectionHandle;
+
+ if (ConnectionDialogCreator != null && attemptNumber == 0) {
+ connectionDialog = ConnectionDialogCreator ();
+ connectionDialog.UserCancelled += delegate {
+ EndSession ();
+ };
+ }
+ if (connectionDialog != null)
+ connectionDialog.SetMessage (dsi, GetConnectingMessage (dsi), listening, attemptNumber);
+ }
+
+ protected virtual string GetConnectingMessage (DebuggerStartInfo dsi)
+ {
+ return null;
+ }
+
+ void EndLaunch ()
+ {
+ HideConnectionDialog ();
+ if (connectionHandle != null) {
+ if (startArgs != null && startArgs.ConnectionProvider != null) {
+ startArgs.ConnectionProvider.CancelConnect (connectionHandle);
+ startArgs = null;
+ } else {
+ VirtualMachineManager.CancelConnection (connectionHandle);
+ }
+ connectionHandle = null;
+ }
+ }
+
+ protected virtual void EndSession ()
+ {
+ if (!HasExited) {
+ EndLaunch ();
+ OnTargetEvent (new TargetEventArgs (TargetEventType.TargetExited));
+ }
+ }
+
+ public Dictionary<Tuple<TypeMirror, string>, MethodMirror[]> OverloadResolveCache {
+ get {
+ return overloadResolveCache;
+ }
+ }
+
+ void HideConnectionDialog ()
+ {
+ if (connectionDialog != null) {
+ connectionDialog.Dispose ();
+ connectionDialog = null;
+ }
+ }
+
+ /// <summary>
+ /// If subclasses do an async connect in OnRun, they should pass the resulting VM to this method.
+ /// If the vm is null, the session will be closed.
+ /// </summary>
+ void ConnectionStarted (VirtualMachine vm)
+ {
+ if (this.vm != null)
+ throw new InvalidOperationException ("The VM has already connected");
+
+ if (vm == null) {
+ EndSession ();
+ return;
+ }
+
+ connectionHandle = null;
+
+ this.vm = vm;
+
+ //full paths, from GetSourceFiles (true), are only supported by sdb protocol 2.2 and later
+ useFullPaths = vm.Version.AtLeast (2, 2);
+
+ ConnectOutput (vm.StandardOutput, false);
+ ConnectOutput (vm.StandardError, true);
+
+ HideConnectionDialog ();
+
+ vm.EnableEvents (EventType.AssemblyLoad, EventType.ThreadStart, EventType.ThreadDeath,
+ EventType.AssemblyUnload, EventType.UserBreak, EventType.UserLog);
+ try {
+ unhandledExceptionRequest = vm.CreateExceptionRequest (null, false, true);
+ unhandledExceptionRequest.Enable ();
+ } catch (NotSupportedException) {
+ //Mono < 2.6.3 doesn't support catching unhandled exceptions
+ }
+
+ if (vm.Version.AtLeast (2, 9)) {
+ /* Created later */
+ } else {
+ vm.EnableEvents (EventType.TypeLoad);
+ }
+
+ started = true;
+
+ /* Wait for the VMStart event */
+ HandleEventSet (vm.GetNextEventSet ());
+
+ eventHandler = new Thread (EventHandler);
+ eventHandler.Name = "SDB Event Handler";
+ eventHandler.IsBackground = true;
+ eventHandler.Start ();
+ }
+
+ void RegisterUserAssemblies (SoftDebuggerStartInfo dsi)
+ {
+ if (Options.ProjectAssembliesOnly && dsi.UserAssemblyNames != null) {
+ assemblyFilters = new List<AssemblyMirror> ();
+ userAssemblyNames = dsi.UserAssemblyNames.Select (x => x.ToString ()).ToList ();
+ }
+
+ assemblyPathMap = dsi.AssemblyPathMap;
+ if (assemblyPathMap == null)
+ assemblyPathMap = new Dictionary<string, string> ();
+ }
+
+ protected bool SetSocketTimeouts (int sendTimeout, int receiveTimeout, int keepaliveInterval)
+ {
+ try {
+ if (vm.Version.AtLeast (2, 4)) {
+ vm.EnableEvents (EventType.KeepAlive);
+ vm.SetSocketTimeouts (sendTimeout, receiveTimeout, keepaliveInterval);
+ return true;
+ }
+
+ return false;
+ } catch {
+ return false;
+ }
+ }
+
+ protected void ConnectOutput (StreamReader reader, bool error)
+ {
+ Thread t = (error ? errorReader : outputReader);
+ if (t != null || reader == null)
+ return;
+ t = new Thread (delegate () {
+ ReadOutput (reader, error);
+ });
+ t.Name = error? "SDB error reader" : "SDB output reader";
+ t.IsBackground = true;
+ t.Start ();
+
+ if (error)
+ errorReader = t;
+ else
+ outputReader = t;
+ }
+
+ void ReadOutput (StreamReader reader, bool isError)
+ {
+ try {
+ var buffer = new char [1024];
+ while (!HasExited) {
+ int c = reader.Read (buffer, 0, buffer.Length);
+ if (c > 0) {
+ OnTargetOutput (isError, new string (buffer, 0, c));
+ } else {
+ //FIXME: workaround for buggy console stream that never blocks
+ Thread.Sleep (250);
+ }
+ }
+ } catch {
+ // Ignore
+ }
+ }
+
+ protected virtual void OnResumed ()
+ {
+ current_threads = null;
+ current_thread = null;
+ procs = null;
+ activeExceptionsByThread.Clear ();
+ }
+
+ public VirtualMachine VirtualMachine {
+ get { return vm; }
+ }
+
+ public TypeMirror GetType (string fullName)
+ {
+ TypeMirror tm;
+ types.TryGetValue (fullName, out tm);
+ return tm;
+ }
+
+ public IEnumerable<TypeMirror> GetAllTypes ()
+ {
+ return types.Values;
+ }
+
+ protected override bool AllowBreakEventChanges {
+ get { return true; }
+ }
+
+ public override void Dispose ()
+ {
+ base.Dispose ();
+
+ if (symbolFiles == null)
+ return;
+
+ if (!HasExited)
+ EndLaunch ();
+
+ foreach (var symfile in symbolFiles)
+ symfile.Value.Dispose ();
+
+ symbolFiles.Clear ();
+ symbolFiles = null;
+
+ if (!HasExited) {
+ if (vm != null) {
+ ThreadPool.QueueUserWorkItem (delegate {
+ try {
+ vm.Exit (0);
+ } catch (VMDisconnectedException) {
+ } catch (Exception ex) {
+ DebuggerLoggingService.LogError ("Error exiting SDB VM:", ex);
+ }
+ });
+ }
+ }
+
+ Adaptor.Dispose ();
+ }
+
+ protected override void OnAttachToProcess (long processId)
+ {
+ throw new NotSupportedException ();
+ }
+
+ protected override void OnContinue ()
+ {
+ ThreadPool.QueueUserWorkItem (delegate {
+ try {
+ Adaptor.CancelAsyncOperations (); // This call can block, so it has to run in background thread to avoid keeping the main session lock
+ OnResumed ();
+ vm.Resume ();
+ DequeueEventsForFirstThread ();
+ } catch (Exception ex) {
+ if (!HandleException (ex))
+ OnDebuggerOutput (true, ex.ToString ());
+ }
+ });
+ }
+
+ protected override void OnDetach ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ protected override void OnExit ()
+ {
+ HasExited = true;
+ EndLaunch ();
+ if (vm != null) {
+ try {
+ vm.Exit (0);
+ } catch (VMDisconnectedException) {
+ // The VM was already disconnected, ignore.
+ } catch (SocketException se) {
+ // This will often happen during normal operation
+ DebuggerLoggingService.LogError ("Error closing debugger session", se);
+ } catch (IOException ex) {
+ // This will often happen during normal operation
+ DebuggerLoggingService.LogError ("Error closing debugger session", ex);
+ }
+ }
+ QueueEnsureExited ();
+ }
+
+ void QueueEnsureExited ()
+ {
+ if (vm != null) {
+ //FIXME: this might never get reached if the IDE is Exited first
+ try {
+ if (vm.Process != null) {
+ ThreadPool.QueueUserWorkItem (delegate {
+ // This is a workaround for a mono bug
+ // Without this call, the process may become zombie in mono < 2.10.2
+ vm.Process.WaitForExit ();
+ });
+ }
+ } catch {
+ // Ignore
+ }
+ var t = new System.Timers.Timer ();
+ t.Interval = 3000;
+ t.Elapsed += delegate {
+ try {
+ t.Enabled = false;
+ t.Dispose ();
+ EnsureExited ();
+ } catch (Exception ex) {
+ DebuggerLoggingService.LogError ("Failed to force-terminate process", ex);
+ }
+ try {
+ if (vm != null) {
+ //this is a no-op if it already closed
+ vm.ForceDisconnect ();
+ }
+ } catch (Exception ex) {
+ DebuggerLoggingService.LogError ("Failed to force-close debugger connection", ex);
+ }
+ };
+ t.Enabled = true;
+ }
+ }
+
+ /// <summary>This is a fallback in case the debugger agent doesn't respond to an exit call</summary>
+ protected virtual void EnsureExited ()
+ {
+ try {
+ if (vm != null && vm.TargetProcess != null && !vm.TargetProcess.HasExited)
+ vm.TargetProcess.Kill ();
+ } catch (Exception ex) {
+ DebuggerLoggingService.LogError ("Error force-terminating soft debugger process", ex);
+ }
+ }
+
+ protected override void OnFinish ()
+ {
+ Step (StepDepth.Out, StepSize.Line);
+ }
+
+ protected override ProcessInfo[] OnGetProcesses ()
+ {
+ if (procs == null) {
+ if (remoteProcessName != null || vm.TargetProcess == null) {
+ procs = new ProcessInfo[] { new ProcessInfo (0, remoteProcessName ?? "mono") };
+ } else {
+ try {
+ procs = new ProcessInfo[] { new ProcessInfo (vm.TargetProcess.Id, vm.TargetProcess.ProcessName) };
+ } catch (Exception ex) {
+ if (!loggedSymlinkedRuntimesBug) {
+ loggedSymlinkedRuntimesBug = true;
+ DebuggerLoggingService.LogError ("Error getting debugger process info. Known Mono bug with symlinked runtimes.", ex);
+ }
+ procs = new ProcessInfo[] { new ProcessInfo (0, "mono") };
+ }
+ }
+ }
+ return new ProcessInfo[] { new ProcessInfo (procs[0].Id, procs[0].Name) };
+ }
+
+ protected override Backtrace OnGetThreadBacktrace (long processId, long threadId)
+ {
+ return GetThreadBacktrace (GetThread (processId, threadId));
+ }
+
+ Backtrace GetThreadBacktrace (ThreadMirror thread)
+ {
+ return new Backtrace (new SoftDebuggerBacktrace (this, thread));
+ }
+
+ string GetThreadName (ThreadMirror t)
+ {
+ string name = t.Name;
+ if (string.IsNullOrEmpty (name)) {
+ try {
+ if (t.IsThreadPoolThread)
+ return "<Thread Pool>";
+ } catch (ObjectCollectedException e) {
+ if (vm.Version.AtLeast (2, 2)) {
+ throw;
+ }
+ return "<Thread>";
+ }
+ }
+ return name;
+ }
+
+ protected override ThreadInfo[] OnGetThreads (long processId)
+ {
+ if (current_threads == null) {
+ IList<ThreadMirror> mirrors = vm.GetThreads ();
+ var threads = new ThreadInfo[mirrors.Count];
+ for (int i = 0; i < mirrors.Count; i++) {
+ ThreadMirror t = mirrors [i];
+ threads[i] = new ThreadInfo (processId, GetId (t), GetThreadName (t), null);
+ }
+ current_threads = threads;
+ }
+ return current_threads;
+ }
+
+ ThreadMirror GetThread (long processId, long threadId)
+ {
+ foreach (ThreadMirror t in vm.GetThreads ())
+ if (GetId (t) == threadId)
+ return t;
+ return null;
+ }
+
+ ThreadInfo GetThread (ProcessInfo process, ThreadMirror thread)
+ {
+ long tid = GetId (thread);
+ foreach (var t in OnGetThreads (process.Id))
+ if (t.Id == tid)
+ return t;
+ return null;
+ }
+
+ protected override BreakEventInfo OnInsertBreakEvent (BreakEvent ev)
+ {
+ lock (pending_bes) {
+ var bi = new BreakInfo ();
+
+ if (HasExited) {
+ bi.SetStatus (BreakEventStatus.Disconnected, null);
+ return bi;
+ }
+
+ if (ev is FunctionBreakpoint) {
+ var fb = (FunctionBreakpoint) ev;
+ bool resolved = false;
+
+ foreach (var location in FindFunctionLocations (fb.FunctionName, fb.ParamTypes)) {
+ string paramList = string.Empty;
+
+ if (fb.ParamTypes != null)
+ paramList = "(" + string.Join (", ", fb.ParamTypes) + ")";
+
+ OnDebuggerOutput (false, string.Format ("Resolved pending breakpoint for '{0}{1}' to {2}:{3} [0x{4:x5}].\n",
+ fb.FunctionName, paramList, location.SourceFile, location.LineNumber, location.ILOffset));
+
+ bi.FileName = location.SourceFile;
+ bi.Location = location;
+
+ InsertBreakpoint (fb, bi);
+ bi.SetStatus (BreakEventStatus.Bound, null);
+ resolved = true;
+ }
+
+ if (!resolved) {
+ // FIXME: handle types like GenericType<>, GenericType<SomeOtherType>, and GenericType<...>+NestedGenricType<...>
+ int dot = fb.FunctionName.LastIndexOf ('.');
+ if (dot != -1)
+ bi.TypeName = fb.FunctionName.Substring (0, dot);
+
+ bi.SetStatus (BreakEventStatus.NotBound, null);
+ pending_bes.Add (bi);
+ }
+ } else if (ev is Breakpoint) {
+ var bp = (Breakpoint) ev;
+ bool insideLoadedRange;
+ bool resolved = false;
+ bool generic;
+
+ bi.FileName = bp.FileName;
+
+ foreach (var location in FindLocationsByFile (bp.FileName, bp.Line, bp.Column, out generic, out insideLoadedRange)) {
+ OnDebuggerOutput (false, string.Format ("Resolved pending breakpoint at '{0}:{1},{2}' to {3} [0x{4:x5}].\n",
+ bp.FileName, bp.Line, bp.Column, GetPrettyMethodName (location.Method), location.ILOffset));
+
+ bi.Location = location;
+ InsertBreakpoint (bp, bi);
+ bi.SetStatus (BreakEventStatus.Bound, null);
+ resolved = true;
+ }
+
+ if (resolved) {
+ // Note: if the type or method is generic, there may be more instances so don't assume we are done resolving the breakpoint
+ if (generic)
+ pending_bes.Add (bi);
+ } else {
+ pending_bes.Add (bi);
+ if (insideLoadedRange)
+ bi.SetStatus (BreakEventStatus.Invalid, null);
+ else
+ bi.SetStatus (BreakEventStatus.NotBound, null);
+ }
+ } else if (ev is Catchpoint) {
+ var cp = (Catchpoint) ev;
+ TypeMirror type;
+
+ if (!types.TryGetValue (cp.ExceptionName, out type)) {
+ //
+ // Same as in FindLocationByFile (), fetch types matching the type name
+ if (vm.Version.AtLeast (2, 9)) {
+ foreach (TypeMirror t in vm.GetTypes (cp.ExceptionName, false))
+ ProcessType (t);
+ }
+ }
+
+ if (types.TryGetValue (cp.ExceptionName, out type)) {
+ InsertCatchpoint (cp, bi, type);
+ bi.SetStatus (BreakEventStatus.Bound, null);
+ } else {
+ bi.TypeName = cp.ExceptionName;
+ pending_bes.Add (bi);
+ bi.SetStatus (BreakEventStatus.NotBound, null);
+ }
+ }
+
+ /*
+ * TypeLoad events lead to too much wire traffic + suspend/resume work, so
+ * filter them using the file names used by pending breakpoints.
+ */
+ if (vm.Version.AtLeast (2, 9)) {
+ var sourceFileList = pending_bes.Where (b => b.FileName != null).Select (b => b.FileName).ToArray ();
+ if (sourceFileList.Length > 0) {
+ //HACK: explicitly try lowercased drivename on windows, since csc (when not hosted in VS) lowercases
+ //the drivename in the pdb files that get converted to mdbs as-is
+ //FIXME: we should really do a case-insensitive request on Win/Mac, when sdb supports that
+ if (IsWindows) {
+ int originalCount = sourceFileList.Length;
+ Array.Resize (ref sourceFileList, originalCount * 2);
+ for (int i = 0; i < originalCount; i++) {
+ string n = sourceFileList[i];
+ sourceFileList[originalCount + i] = char.ToLower (n[0]) + n.Substring (1);
+ }
+ }
+
+ if (typeLoadReq == null) {
+ typeLoadReq = vm.CreateTypeLoadRequest ();
+ }
+ typeLoadReq.Enabled = false;
+ typeLoadReq.SourceFileFilter = sourceFileList;
+ typeLoadReq.Enabled = true;
+ }
+
+ var typeNameList = pending_bes.Where (b => b.TypeName != null).Select (b => b.TypeName).ToArray ();
+ if (typeNameList.Length > 0) {
+ // Use a separate request since the filters are ANDed together
+ if (typeLoadTypeNameReq == null) {
+ typeLoadTypeNameReq = vm.CreateTypeLoadRequest ();
+ }
+ typeLoadTypeNameReq.Enabled = false;
+ typeLoadTypeNameReq.TypeNameFilter = typeNameList;
+ typeLoadTypeNameReq.Enabled = true;
+ }
+ }
+
+ return bi;
+ }
+ }
+
+ protected override void OnRemoveBreakEvent (BreakEventInfo binfo)
+ {
+ if (HasExited)
+ return;
+
+ lock (pending_bes) {
+ var bi = (BreakInfo) binfo;
+ if (bi.Requests.Count != 0) {
+ foreach (var request in bi.Requests)
+ request.Enabled = false;
+
+ RemoveQueuedBreakEvents (bi.Requests);
+ }
+
+ pending_bes.Remove (bi);
+ }
+ }
+
+ protected override void OnEnableBreakEvent (BreakEventInfo binfo, bool enable)
+ {
+ if (HasExited)
+ return;
+
+ lock (pending_bes) {
+ var bi = (BreakInfo) binfo;
+ if (bi.Requests.Count != 0) {
+ foreach (var request in bi.Requests)
+ request.Enabled = enable;
+
+ if (!enable)
+ RemoveQueuedBreakEvents (bi.Requests);
+ }
+ }
+ }
+
+ protected override void OnUpdateBreakEvent (BreakEventInfo binfo)
+ {
+ }
+
+ void InsertBreakpoint (Breakpoint bp, BreakInfo bi)
+ {
+ EventRequest request;
+
+ request = vm.SetBreakpoint (bi.Location.Method, bi.Location.ILOffset);
+ request.Enabled = bp.Enabled;
+ bi.Requests.Add (request);
+
+ breakpoints[request] = bi;
+
+ if (bi.Location.LineNumber != bp.Line || bi.Location.ColumnNumber != bp.Column)
+ bi.AdjustBreakpointLocation (bi.Location.LineNumber, bi.Location.ColumnNumber);
+ }
+
+ void InsertCatchpoint (Catchpoint cp, BreakInfo bi, TypeMirror excType)
+ {
+ ExceptionEventRequest request;
+
+ request = vm.CreateExceptionRequest (excType, true, true);
+ request.Count = cp.HitCount; // Note: need to set HitCount *before* enabling
+ request.Enabled = cp.Enabled;
+ if (vm.Version.AtLeast (2, 25))
+ request.IncludeSubclasses = cp.IncludeSubclasses;
+
+ bi.Requests.Add (request);
+ }
+
+ static bool CheckTypeName (string typeName, string name)
+ {
+ // if the name provided is empty, it matches anything.
+ if (name.Length == 0)
+ return true;
+
+ if (name.StartsWith ("global::", StringComparison.Ordinal)) {
+ if (typeName != name.Substring ("global::".Length))
+ return false;
+ } else if (name.StartsWith ("::", StringComparison.Ordinal)) {
+ if (typeName != name.Substring ("::".Length))
+ return false;
+ } else {
+ // be a little more flexible with what we match... i.e. "Console" should match "System.Console"
+ if (typeName.Length > name.Length) {
+ if (!typeName.EndsWith (name, StringComparison.InvariantCulture))
+ return false;
+
+ char delim = typeName[typeName.Length - name.Length];
+ if (delim != '.' && delim != '+')
+ return false;
+ } else if (typeName != name) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static bool CheckTypeName (TypeMirror type, string name)
+ {
+ if (name.Length == 0) {
+ // empty name matches anything
+ return true;
+ }
+
+ if (name[name.Length - 1] == '?') {
+ // canonicalize the user-specified nullable type
+ return CheckTypeName (type, string.Format ("System.Nullable<{0}>", name.Substring (0, name.Length - 1)));
+ }
+
+ if (type.IsArray) {
+ int startIndex = name.LastIndexOf ('[');
+ int endIndex = name.Length - 1;
+
+ if (startIndex == -1 || name[endIndex] != ']') {
+ // the user-specified type is not an array
+ return false;
+ }
+
+ var rank = name.Substring (startIndex + 1, endIndex - (startIndex + 1)).Split (new char[] { ',' });
+ if (rank.Length != type.GetArrayRank ())
+ return false;
+
+ return CheckTypeName (type.GetElementType (), name.Substring (0, startIndex).TrimEnd ());
+ }
+
+ if (type.IsPointer) {
+ if (name.Length < 2 || name[name.Length - 1] != '*')
+ return false;
+
+ return CheckTypeName (type.GetElementType (), name.Substring (0, name.Length - 1).TrimEnd ());
+ }
+
+ if (type.IsGenericType) {
+ int startIndex = name.IndexOf ('<');
+ int endIndex = name.Length - 1;
+
+ if (startIndex == -1 || name[endIndex] != '>') {
+ // the user-specified type is not a generic type
+ return false;
+ }
+
+ // make sure that the type name matches (minus generics)
+ string subName = name.Substring (0, startIndex);
+ string typeName = type.FullName;
+ int tick;
+
+ if ((tick = typeName.IndexOf ('`')) != -1)
+ typeName = typeName.Substring (0, tick);
+
+ if (!CheckTypeName (typeName, subName))
+ return false;
+
+ string[] paramTypes;
+ if (!FunctionBreakpoint.TryParseParameters (name, startIndex + 1, endIndex, out paramTypes))
+ return false;
+
+ TypeMirror[] argTypes = type.GetGenericArguments ();
+ if (paramTypes.Length != argTypes.Length)
+ return false;
+
+ for (int i = 0; i < paramTypes.Length; i++) {
+ if (!CheckTypeName (argTypes[i], paramTypes[i]))
+ return false;
+ }
+ } else if (!CheckTypeName (type.CSharpName, name)) {
+ if (!CheckTypeName (type.FullName, name))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool CheckMethodParams (MethodMirror method, string[] paramTypes)
+ {
+ if (paramTypes == null) {
+ // User supplied no params to match against, match anything we find.
+ return true;
+ }
+
+ var parameters = method.GetParameters ();
+ if (parameters.Length != paramTypes.Length)
+ return false;
+
+ for (int i = 0; i < paramTypes.Length; i++) {
+ if (!CheckTypeName (parameters[i].ParameterType, paramTypes[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool IsGenericMethod (MethodMirror method)
+ {
+ return vm.Version.AtLeast (2, 12) && method.IsGenericMethod;
+ }
+
+ IEnumerable<Location> FindFunctionLocations (string function, string[] paramTypes)
+ {
+ if (!started)
+ yield break;
+
+ if (vm.Version.AtLeast (2, 9)) {
+ int dot = function.LastIndexOf ('.');
+ if (dot == -1 || dot + 1 == function.Length)
+ yield break;
+
+ // FIXME: handle types like GenericType<>, GenericType<SomeOtherType>, and GenericType<...>+NestedGenricType<...>
+ string methodName = function.Substring (dot + 1);
+ string typeName = function.Substring (0, dot);
+
+ // FIXME: need a way of querying all types so we can substring match typeName (e.g. user may have typed "Console" instead of "System.Console")
+ foreach (var type in vm.GetTypes (typeName, false)) {
+ ProcessType (type);
+
+ foreach (var method in type.GetMethodsByNameFlags (methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, false)) {
+ if (!CheckMethodParams (method, paramTypes))
+ continue;
+
+ Location location = GetLocFromMethod (method);
+ if (location != null)
+ yield return location;
+ }
+ }
+ }
+
+ yield break;
+ }
+
+ IList<Location> FindLocationsByFile (string file, int line, int column, out bool genericTypeOrMethod, out bool insideLoadedRange)
+ {
+ List<Location> locations = new List<Location> ();
+
+ genericTypeOrMethod = false;
+ insideLoadedRange = false;
+
+ if (!started)
+ return locations;
+
+ string filename = PathToFileName (file);
+
+ //
+ // Fetch types matching the source file from the debuggee, and add them
+ // to the source file->type mapping tables.
+ // This is needed because we don't receive type load events for all types,
+ // just the ones which match a source file with an existing breakpoint.
+ //
+ if (vm.Version.AtLeast (2, 9)) {
+ //FIXME: do a case insensitive request on Win/Mac when sdb supports it (currently asserts NOTIMPLEMENTED)
+ var typesInFile = vm.GetTypesForSourceFile (filename, false);
+
+ //HACK: explicitly try lowercased drivename on windows, since csc (when not hosted in VS) lowercases
+ //the drivename in the pdb files that get converted to mdbs as-is
+ if (typesInFile.Count == 0 && IsWindows) {
+ string alternateCaseFilename = char.ToLower (filename[0]) + filename.Substring (1);
+ typesInFile = vm.GetTypesForSourceFile (alternateCaseFilename, false);
+ }
+
+ foreach (TypeMirror t in typesInFile)
+ ProcessType (t);
+ }
+
+ // Try already loaded types in the current source file
+ List<TypeMirror> types;
+
+ if (source_to_type.TryGetValue (filename, out types)) {
+ foreach (TypeMirror type in types) {
+ bool genericMethod;
+ bool insideRange;
+
+ var loc = GetLocFromType (type, filename, line, column, out genericMethod, out insideRange);
+ if (insideRange)
+ insideLoadedRange = true;
+
+ if (loc != null) {
+ if (genericMethod || type.IsGenericType)
+ genericTypeOrMethod = true;
+
+ locations.Add (loc);
+ }
+ }
+ }
+
+ return locations;
+ }
+
+ public override bool CanCancelAsyncEvaluations {
+ get {
+ return Adaptor.IsEvaluating;
+ }
+ }
+
+ protected override void OnCancelAsyncEvaluations ()
+ {
+ Adaptor.CancelAsyncOperations ();
+ }
+
+ protected override void OnNextInstruction ()
+ {
+ Step (StepDepth.Over, StepSize.Min);
+ }
+
+ protected override void OnNextLine ()
+ {
+ Step (StepDepth.Over, StepSize.Line);
+ }
+
+ void Step (StepDepth depth, StepSize size)
+ {
+ ThreadPool.QueueUserWorkItem (delegate {
+ try {
+ Adaptor.CancelAsyncOperations (); // This call can block, so it has to run in background thread to avoid keeping the main session lock
+ var req = vm.CreateStepRequest (current_thread);
+ req.Depth = depth;
+ req.Size = size;
+ req.Filter = StepFilter.StaticCtor | StepFilter.DebuggerHidden | StepFilter.DebuggerStepThrough;
+ if (assemblyFilters != null && assemblyFilters.Count > 0)
+ req.AssemblyFilter = assemblyFilters;
+ req.Enabled = true;
+ currentStepRequest = req;
+ OnResumed ();
+ vm.Resume ();
+ DequeueEventsForFirstThread ();
+ } catch (CommandException ex) {
+ string reason;
+
+ switch (ex.ErrorCode) {
+ case ErrorCode.INVALID_FRAMEID: reason = "invalid frame id"; break;
+ case ErrorCode.NOT_SUSPENDED: reason = "VM not suspended"; break;
+ case ErrorCode.ERR_UNLOADED: reason = "AppDomain has been unloaded"; break;
+ case ErrorCode.NO_SEQ_POINT_AT_IL_OFFSET: reason = "no sequence point at the specified IL offset"; break;
+ default: reason = ex.ErrorCode.ToString (); break;
+ }
+
+ OnDebuggerOutput (true, string.Format ("Step request failed: {0}.", reason));
+ DebuggerLoggingService.LogError ("Step request failed", ex);
+ } catch (Exception ex) {
+ OnDebuggerOutput (true, string.Format ("Step request failed: {0}", ex.Message));
+ DebuggerLoggingService.LogError ("Step request failed", ex);
+ }
+ });
+ }
+
+ void EventHandler ()
+ {
+ while (true) {
+ try {
+ EventSet e = vm.GetNextEventSet ();
+ var type = e[0].EventType;
+ if (type == EventType.VMDeath || type == EventType.VMDisconnect) {
+ break;
+ }
+ HandleEventSet (e);
+ } catch (Exception ex) {
+ if (HasExited)
+ break;
+
+ if (!HandleException (ex))
+ OnDebuggerOutput (true, ex.ToString ());
+
+ if (ex is VMDisconnectedException || ex is IOException || ex is SocketException)
+ break;
+ }
+ }
+
+ try {
+ // This is a workaround for a mono bug
+ // Without this call, the process may become zombie in mono < 2.10.2
+ if (vm.Process != null)
+ vm.Process.WaitForExit (1);
+ } catch {
+ // Ignore
+ }
+
+ OnTargetEvent (new TargetEventArgs (TargetEventType.TargetExited));
+ }
+
+ protected override bool HandleException (Exception ex)
+ {
+ HideConnectionDialog ();
+
+ if (HasExited)
+ return true;
+
+ if (ex is VMDisconnectedException || ex is IOException) {
+ ex = new DisconnectedException (ex);
+ HasExited = true;
+ } else if (ex is SocketException) {
+ ex = new DebugSocketException (ex);
+ HasExited = true;
+ }
+
+ return base.HandleException (ex);
+ }
+
+ // This method dispatches an event set.
+ //
+ // Based on the subset of events for which we register, and the contract for EventSet contents (equivalent to
+ // Java - http://download.oracle.com/javase/1.5.0/docs/guide/jpda/jdi/com/sun/jdi/event/EventSet.html)
+ // we know that event sets we receive are either:
+ // 1) Set of step and break events for a location in a single thread.
+ // 2) Set of catchpoints for a single exception.
+ // 3) A single event of any other kind.
+ // We verify these assumptions where possible, because things will break in horrible ways if they are wrong.
+ //
+ // If we are currently stopped on a thread, and the break events are on a different thread, we must queue
+ // that event set and dequeue it next time we resume. This eliminates race conditions when multiple threads
+ // hit breakpoints or catchpoints simultaneously.
+ //
+ void HandleEventSet (EventSet es)
+ {
+#if DEBUG_EVENT_QUEUEING
+ if (!(es[0] is TypeLoadEvent))
+ Console.WriteLine ("pp eventset({0}): {1}", es.Events.Length, es[0]);
+#endif
+ var type = es[0].EventType;
+ bool isBreakEvent = type == EventType.Step || type == EventType.Breakpoint || type == EventType.Exception || type == EventType.UserBreak;
+
+ if (isBreakEvent) {
+ if (current_thread != null && es[0].Thread.Id != current_thread.Id) {
+ QueueBreakEventSet (es.Events);
+ } else {
+ HandleBreakEventSet (es.Events, false);
+ }
+ } else {
+ if (es.Events.Length != 1)
+ throw new InvalidOperationException ("EventSet has unexpected combination of events");
+ HandleEvent (es[0]);
+
+ try {
+ vm.Resume ();
+ } catch (VMNotSuspendedException) {
+ var eventType = es [0].EventType;
+ var isTolerantEvent = eventType == EventType.VMStart || eventType == EventType.AssemblyLoad || eventType == EventType.TypeLoad
+ || eventType == EventType.ThreadStart || eventType == EventType.ThreadDeath
+ || eventType == EventType.AppDomainCreate || eventType == EventType.AppDomainUnload;
+
+ if (eventType != EventType.VMStart && (vm.Version.AtLeast (2, 2) || !isTolerantEvent)) {
+ throw;
+ }
+ }
+ }
+ }
+
+ static bool IsStepIntoRequest (StepEventRequest stepRequest)
+ {
+ return stepRequest.Depth == StepDepth.Into;
+ }
+
+ static bool IsStepOutRequest (StepEventRequest stepRequest)
+ {
+ return stepRequest.Depth == StepDepth.Out;
+ }
+
+ static bool IsPropertyOrOperatorMethod (MethodMirror method)
+ {
+ string name = method.Name;
+
+ return method.IsSpecialName &&
+ (name.StartsWith ("get_", StringComparison.Ordinal) ||
+ name.StartsWith ("set_", StringComparison.Ordinal) ||
+ name.StartsWith ("op_", StringComparison.Ordinal));
+ }
+
+ bool IsUserAssembly (AssemblyMirror assembly)
+ {
+ if (userAssemblyNames == null)
+ return true;
+
+ var name = assembly.GetName ().FullName;
+
+ foreach (var n in userAssemblyNames) {
+ if (n == name)
+ return true;
+ }
+
+ return false;
+ }
+
+ bool IsAutoGeneratedFrameworkEnumerator (TypeMirror type)
+ {
+ if (IsUserAssembly (type.Assembly))
+ return false;
+
+ if (!SoftDebuggerAdaptor.IsGeneratedType (type))
+ return false;
+
+ foreach (var iface in type.GetInterfaces ()) {
+ if (iface.Namespace == "System.Collections" && iface.Name == "IEnumerator")
+ return true;
+ }
+
+ return false;
+ }
+
+ void HandleBreakEventSet (Event[] es, bool dequeuing)
+ {
+ if (dequeuing && HasExited)
+ return;
+
+ bool resume = true;
+ bool steppedOut = false;
+ bool steppedInto = false;
+ bool redoCurrentStep = false;
+ ObjectMirror exception = null;
+ TargetEventType etype = TargetEventType.TargetStopped;
+ BreakEvent breakEvent = null;
+
+ if (es[0] is ExceptionEvent) {
+ var bad = es.FirstOrDefault (ee => ee.EventType != EventType.Exception);
+ if (bad != null)
+ throw new Exception ("Catchpoint eventset had unexpected event type " + bad.GetType ());
+ var ev = (ExceptionEvent)es[0];
+ if (ev.Request == unhandledExceptionRequest)
+ etype = TargetEventType.UnhandledException;
+ else
+ etype = TargetEventType.ExceptionThrown;
+ exception = ev.Exception;
+ if (ev.Request != unhandledExceptionRequest || exception.Type.FullName != "System.Threading.ThreadAbortException")
+ resume = false;
+ } else {
+ //always need to evaluate all breakpoints, some might be tracepoints or conditional bps with counters
+ foreach (Event e in es) {
+ if (e.EventType == EventType.Breakpoint) {
+ var be = (BreakpointEvent) e;
+ BreakInfo binfo;
+
+ if (!HandleBreakpoint (e.Thread, be.Request)) {
+ etype = TargetEventType.TargetHitBreakpoint;
+ autoStepInto = false;
+ resume = false;
+ }
+
+ if (breakpoints.TryGetValue (be.Request, out binfo)) {
+ if (currentStepRequest != null &&
+ binfo.Location.ILOffset == currentAddress &&
+ e.Thread.Id == currentStepRequest.Thread.Id)
+ redoCurrentStep = true;
+
+ breakEvent = binfo.BreakEvent;
+ }
+ } else if (e.EventType == EventType.Step) {
+ var stepRequest = e.Request as StepEventRequest;
+ steppedInto = IsStepIntoRequest (stepRequest);
+ steppedOut = IsStepOutRequest (stepRequest);
+ etype = TargetEventType.TargetStopped;
+ resume = false;
+ } else if (e.EventType == EventType.UserBreak) {
+ etype = TargetEventType.TargetStopped;
+ autoStepInto = false;
+ resume = false;
+ } else {
+ throw new Exception ("Break eventset had unexpected event type " + e.GetType ());
+ }
+ }
+ }
+
+ if (redoCurrentStep) {
+ StepDepth depth = currentStepRequest.Depth;
+ StepSize size = currentStepRequest.Size;
+
+ current_thread = recent_thread = es[0].Thread;
+ currentStepRequest.Enabled = false;
+ currentStepRequest = null;
+
+ Step (depth, size);
+ } else if (resume) {
+ //all breakpoints were conditional and evaluated as false
+ vm.Resume ();
+ DequeueEventsForFirstThread ();
+ } else {
+ if (currentStepRequest != null) {
+ currentStepRequest.Enabled = false;
+ currentStepRequest = null;
+ }
+
+ current_thread = recent_thread = es[0].Thread;
+
+ if (exception != null)
+ activeExceptionsByThread [current_thread.ThreadId] = exception;
+
+ var backtrace = GetThreadBacktrace (current_thread);
+ bool stepOut = false;
+
+ if (backtrace.FrameCount > 0) {
+ var frame = backtrace.GetFrame (0) as SoftDebuggerStackFrame;
+ currentAddress = frame != null ? frame.Address : -1;
+ if (frame != null) {
+ if (steppedInto) {
+ if (Options.StepOverPropertiesAndOperators && IsPropertyOrOperatorMethod (frame.StackFrame.Method)) {
+ // We will want to call StepInto once StepOut returns...
+ autoStepInto = true;
+ stepOut = true;
+ } else if (IsAutoGeneratedFrameworkEnumerator (frame.StackFrame.Method.DeclaringType)) {
+ // User asked to step in, but we landed in an autogenerated type (probably an iterator)
+ autoStepInto = true;
+ stepOut = true;
+ }
+ }
+ }
+ }
+
+ if (stepOut) {
+ Step (StepDepth.Out, StepSize.Min);
+ } else if (steppedOut && autoStepInto) {
+ autoStepInto = false;
+ Step (StepDepth.Into, StepSize.Min);
+ } else {
+ var args = new TargetEventArgs (etype);
+ args.Process = OnGetProcesses () [0];
+ args.Thread = GetThread (args.Process, current_thread);
+ args.Backtrace = backtrace;
+ args.BreakEvent = breakEvent;
+
+ OnTargetEvent (args);
+ }
+ }
+ }
+
+ void HandleEvent (Event e)
+ {
+ lock (pending_bes) {
+ switch (e.EventType) {
+ case EventType.AssemblyLoad: {
+ var ae = (AssemblyLoadEvent) e;
+ bool isExternal = !UpdateAssemblyFilters (ae.Assembly) && userAssemblyNames != null;
+ string flagExt = isExternal? " [External]" : "";
+ OnDebuggerOutput (false, string.Format ("Loaded assembly: {0}{1}\n", ae.Assembly.Location, flagExt));
+ break;
+ }
+ case EventType.AssemblyUnload: {
+ var aue = (AssemblyUnloadEvent) e;
+
+ if (assemblyFilters != null) {
+ int index = assemblyFilters.IndexOf (aue.Assembly);
+ if (index != -1)
+ assemblyFilters.RemoveAt (index);
+ }
+
+ // Mark affected breakpoints as pending again
+ var affectedBreakpoints = new List<KeyValuePair<EventRequest, BreakInfo>> (
+ breakpoints.Where (x=> (x.Value.Location.Method.DeclaringType.Assembly.Location.Equals (aue.Assembly.Location, StringComparison.OrdinalIgnoreCase)))
+ );
+ foreach (KeyValuePair<EventRequest,BreakInfo> breakpoint in affectedBreakpoints) {
+ string file = PathToFileName (breakpoint.Value.Location.SourceFile);
+ int line = breakpoint.Value.Location.LineNumber;
+ OnDebuggerOutput (false, string.Format ("Re-pending breakpoint at {0}:{1}\n", file, line));
+ breakpoints.Remove (breakpoint.Key);
+ pending_bes.Add (breakpoint.Value);
+ }
+
+ // Remove affected types from the loaded types list
+ var affectedTypes = new List<string> (
+ from pair in types
+ where pair.Value.Assembly.Location.Equals (aue.Assembly.Location, StringComparison.OrdinalIgnoreCase)
+ select pair.Key
+ );
+ foreach (string typename in affectedTypes) {
+ types.Remove (typename);
+ }
+
+ foreach (var pair in source_to_type) {
+ pair.Value.RemoveAll (delegate (TypeMirror mirror){
+ return mirror.Assembly.Location.Equals (aue.Assembly.Location, StringComparison.OrdinalIgnoreCase);
+ });
+ }
+ OnDebuggerOutput (false, string.Format ("Unloaded assembly: {0}\n", aue.Assembly.Location));
+ break;
+ }
+ case EventType.VMStart: {
+ OnStarted (new ThreadInfo (0, GetId (e.Thread), GetThreadName (e.Thread), null));
+ //HACK: 2.6.1 VM doesn't emit type load event, so work around it
+ var t = vm.RootDomain.Corlib.GetType ("System.Exception", false, false);
+ if (t != null)
+ ResolveBreakpoints (t);
+ break;
+ }
+ case EventType.TypeLoad: {
+ var t = ((TypeLoadEvent)e).Type;
+ string typeName = t.FullName;
+
+ if (types.ContainsKey (typeName)) {
+ /* This can happen since we manually add entries to 'types' */
+ /*
+ if (typeName != "System.Exception" && typeName != "<Module>")
+ DebuggerLoggingService.LogError ("Type '" + typeName + "' loaded more than once", null);
+ */
+ } else {
+ ResolveBreakpoints (t);
+ }
+ break;
+ }
+ case EventType.ThreadStart: {
+ var ts = (ThreadStartEvent) e;
+ var name = GetThreadName (ts.Thread);
+ var id = GetId (ts.Thread);
+ OnDebuggerOutput (false, string.Format ("Thread started: {0} #{1}\n", name, id));
+ OnTargetEvent (new TargetEventArgs (TargetEventType.ThreadStarted) {
+ Thread = new ThreadInfo (0, id, name, null),
+ });
+ break;
+ }
+ case EventType.ThreadDeath: {
+ var ts = (ThreadDeathEvent) e;
+ var name = GetThreadName (ts.Thread);
+ var id = GetId (ts.Thread);
+ OnDebuggerOutput (false, string.Format ("Thread finished: {0} #{1}\n", name, id));
+ OnTargetEvent (new TargetEventArgs (TargetEventType.ThreadStopped) {
+ Thread = new ThreadInfo (0, id, ts.Thread.Name, null),
+ });
+ break;
+ }
+ case EventType.UserLog: {
+ var ul = (UserLogEvent) e;
+ OnDebuggerOutput (false, string.Format ("[{0}:{1}] {2}\n", ul.Level, ul.Category, ul.Message));
+ break;
+ }
+ default:
+ DebuggerLoggingService.LogMessage ("Unknown debugger event type {0}", e.GetType ());
+ break;
+ }
+ }
+ }
+
+ public ObjectMirror GetExceptionObject (ThreadMirror thread)
+ {
+ ObjectMirror obj;
+ if (activeExceptionsByThread.TryGetValue (thread.ThreadId, out obj))
+ return obj;
+
+ return null;
+ }
+
+ void QueueBreakEventSet (Event[] eventSet)
+ {
+#if DEBUG_EVENT_QUEUEING
+ Console.WriteLine ("qq eventset({0}): {1}", eventSet.Length, eventSet[0]);
+#endif
+ var events = new List<Event> (eventSet);
+ lock (queuedEventSets) {
+ queuedEventSets.AddLast (events);
+ }
+ }
+
+ void RemoveQueuedBreakEvents (List<EventRequest> requests)
+ {
+ int resume = 0;
+
+ lock (queuedEventSets) {
+ var node = queuedEventSets.First;
+
+ while (node != null) {
+ List<Event> q = node.Value;
+
+ for (int i = 0; i < q.Count; i++) {
+ foreach (var request in requests) {
+ if (q[i].Request == request) {
+ q.RemoveAt (i--);
+ break;
+ }
+ }
+ }
+
+ if (q.Count == 0) {
+ var d = node;
+ node = node.Next;
+ queuedEventSets.Remove (d);
+ resume++;
+ } else {
+ node = node.Next;
+ }
+ }
+ }
+
+ for (int i = 0; i < resume; i++)
+ vm.Resume ();
+ }
+
+ void DequeueEventsForFirstThread ()
+ {
+ List<List<Event>> dequeuing;
+ lock (queuedEventSets) {
+ if (queuedEventSets.Count < 1)
+ return;
+
+ dequeuing = new List<List<Event>> ();
+ var node = queuedEventSets.First;
+
+ //making this the current thread means that all events from other threads will get queued
+ current_thread = node.Value[0].Thread;
+ while (node != null) {
+ if (node.Value[0].Thread.Id == current_thread.Id) {
+ var d = node;
+ node = node.Next;
+ dequeuing.Add (d.Value);
+ queuedEventSets.Remove (d);
+ } else {
+ node = node.Next;
+ }
+ }
+ }
+
+#if DEBUG_EVENT_QUEUEING
+ foreach (var e in dequeuing)
+ Console.WriteLine ("dq eventset({0}): {1}", e.Count, e[0]);
+#endif
+
+ //firing this off in a thread prevents possible infinite recursion
+ ThreadPool.QueueUserWorkItem (delegate {
+ if (!HasExited) {
+ foreach (var es in dequeuing) {
+ try {
+ HandleBreakEventSet (es.ToArray (), true);
+ } catch (Exception ex) {
+ if (!HandleException (ex))
+ OnDebuggerOutput (true, ex.ToString ());
+
+ if (ex is VMDisconnectedException || ex is IOException || ex is SocketException) {
+ OnTargetEvent (new TargetEventArgs (TargetEventType.TargetExited));
+ break;
+ }
+ }
+ }
+ }
+ });
+ }
+
+ bool HandleBreakpoint (ThreadMirror thread, EventRequest er)
+ {
+ BreakInfo binfo;
+ if (!breakpoints.TryGetValue (er, out binfo))
+ return false;
+
+ var bp = binfo.BreakEvent as Breakpoint;
+ if (bp == null)
+ return false;
+
+ binfo.IncrementHitCount ();
+ if (!binfo.HitCountReached)
+ return true;
+
+ if (!string.IsNullOrEmpty (bp.ConditionExpression)) {
+ string res = EvaluateExpression (thread, bp.ConditionExpression, bp);
+ if (bp.BreakIfConditionChanges) {
+ if (res == binfo.LastConditionValue)
+ return true;
+ binfo.LastConditionValue = res;
+ } else {
+ if (res == null || res.ToLowerInvariant () != "true")
+ return true;
+ }
+ }
+ if ((bp.HitAction & HitAction.CustomAction) != HitAction.None) {
+ // If custom action returns true, execution must continue
+ return binfo.RunCustomBreakpointAction (bp.CustomActionId);
+ }
+
+ if ((bp.HitAction & HitAction.PrintExpression) != HitAction.None) {
+ string exp = EvaluateTrace (thread, bp.TraceExpression);
+ binfo.UpdateLastTraceValue (exp);
+ }
+
+ // Continue execution if we don't have break action.
+ return (bp.HitAction & HitAction.Break) == HitAction.None;
+ }
+
+ string EvaluateTrace (ThreadMirror thread, string exp)
+ {
+ var sb = new StringBuilder ();
+ int last = 0;
+ int i = exp.IndexOf ('{');
+ while (i != -1) {
+ if (i < exp.Length - 1 && exp [i+1] == '{') {
+ sb.Append (exp.Substring (last, i - last + 1));
+ last = i + 2;
+ i = exp.IndexOf ('{', i + 2);
+ continue;
+ }
+ int j = exp.IndexOf ('}', i + 1);
+ if (j == -1)
+ break;
+ string se = exp.Substring (i + 1, j - i - 1);
+ se = EvaluateExpression (thread, se, null);
+ sb.Append (exp.Substring (last, i - last));
+ sb.Append (se);
+ last = j + 1;
+ i = exp.IndexOf ('{', last);
+ }
+ sb.Append (exp.Substring (last, exp.Length - last));
+ return sb.ToString ();
+ }
+
+ static SourceLocation GetSourceLocation (MDB.StackFrame frame)
+ {
+ return new SourceLocation (frame.Method.Name, frame.FileName, frame.LineNumber, frame.ColumnNumber);
+ }
+
+ static string FormatSourceLocation (Breakpoint bp)
+ {
+ if (string.IsNullOrEmpty (bp.FileName))
+ return null;
+
+ var location = Path.GetFileName (bp.FileName);
+ if (bp.OriginalLine > 0) {
+ location += ":" + bp.OriginalLine;
+ if (bp.OriginalColumn > 0)
+ location += "," + bp.OriginalColumn;
+ }
+
+ return location;
+ }
+
+ static bool IsBoolean (ValueReference vr)
+ {
+ if (vr.Type is Type && ((Type) vr.Type) == typeof (bool))
+ return true;
+
+ if (vr.Type is TypeMirror && ((TypeMirror) vr.Type).FullName == "System.Boolean")
+ return true;
+
+ return false;
+ }
+
+ string EvaluateExpression (ThreadMirror thread, string expression, Breakpoint bp)
+ {
+ try {
+ var frames = thread.GetFrames ();
+ if (frames.Length == 0)
+ return string.Empty;
+
+ EvaluationOptions ops = Options.EvaluationOptions.Clone ();
+ ops.AllowTargetInvoke = true;
+
+ var ctx = new SoftEvaluationContext (this, frames[0], ops);
+
+ if (bp != null) {
+ // validate conditional breakpoint expressions so that we can provide error reporting to the user
+ var vr = ctx.Evaluator.ValidateExpression (ctx, expression);
+ if (!vr.IsValid) {
+ string message = string.Format ("Invalid expression in conditional breakpoint. {0}", vr.Message);
+ string location = FormatSourceLocation (bp);
+
+ if (!string.IsNullOrEmpty (location))
+ message = location + ": " + message;
+
+ OnDebuggerOutput (true, message);
+ return string.Empty;
+ }
+
+ // resolve types...
+ if (ctx.SourceCodeAvailable)
+ expression = ctx.Evaluator.Resolve (this, GetSourceLocation (frames[0]), expression);
+ }
+
+ ValueReference val = ctx.Evaluator.Evaluate (ctx, expression);
+ if (bp != null && !bp.BreakIfConditionChanges && !IsBoolean (val)) {
+ string message = string.Format ("Expression in conditional breakpoint did not evaluate to a boolean value: {0}", bp.ConditionExpression);
+ string location = FormatSourceLocation (bp);
+
+ if (!string.IsNullOrEmpty (location))
+ message = location + ": " + message;
+
+ OnDebuggerOutput (true, message);
+ return string.Empty;
+ }
+
+ return val.CreateObjectValue (false).Value;
+ } catch (EvaluatorException ex) {
+ string message;
+
+ if (bp != null) {
+ message = string.Format ("Failed to evaluate expression in conditional breakpoint. {0}", ex.Message);
+ string location = FormatSourceLocation (bp);
+
+ if (!string.IsNullOrEmpty (location))
+ message = location + ": " + message;
+ } else {
+ message = ex.ToString ();
+ }
+
+ OnDebuggerOutput (true, message);
+ return string.Empty;
+ } catch (Exception ex) {
+ OnDebuggerOutput (true, ex.ToString ());
+ return string.Empty;
+ }
+ }
+
+ void ProcessType (TypeMirror t)
+ {
+ string typeName = t.FullName;
+
+ if (types.ContainsKey (typeName))
+ return;
+ types [typeName] = t;
+
+ //get the source file paths
+ //full paths, from GetSourceFiles (true), are only supported by sdb protocol 2.2 and later
+ string[] sourceFiles;
+ if (useFullPaths) {
+ sourceFiles = t.GetSourceFiles (true);
+ } else {
+ sourceFiles = t.GetSourceFiles ();
+
+ //HACK: if mdb paths are windows paths but the sdb agent is on unix, it won't map paths to filenames correctly
+ if (IsWindows) {
+ for (int i = 0; i < sourceFiles.Length; i++) {
+ string s = sourceFiles[i];
+ if (s != null && !s.StartsWith ("/", StringComparison.Ordinal))
+ sourceFiles[i] = Path.GetFileName (s);
+ }
+ }
+ }
+
+ for (int n=0; n<sourceFiles.Length; n++)
+ sourceFiles[n] = NormalizePath (sourceFiles[n]);
+
+ foreach (string s in sourceFiles) {
+ List<TypeMirror> typesList;
+
+ if (source_to_type.TryGetValue (s, out typesList)) {
+ typesList.Add (t);
+ } else {
+ typesList = new List<TypeMirror> ();
+ typesList.Add (t);
+ source_to_type[s] = typesList;
+ }
+ }
+
+ type_to_source [t] = sourceFiles;
+ }
+
+ static string[] GetParamTypes (MethodMirror method)
+ {
+ List<string> paramTypes = new List<string> ();
+
+ foreach (var param in method.GetParameters ())
+ paramTypes.Add (param.ParameterType.CSharpName);
+
+ return paramTypes.ToArray ();
+ }
+
+ string GetPrettyMethodName (MethodMirror method)
+ {
+ var name = new StringBuilder ();
+
+ name.Append (Adaptor.GetDisplayTypeName (method.ReturnType.FullName));
+ name.Append (" ");
+ name.Append (Adaptor.GetDisplayTypeName (method.DeclaringType.FullName));
+ name.Append (".");
+ name.Append (method.Name);
+
+ if (method.VirtualMachine.Version.AtLeast (2, 12)) {
+ if (method.IsGenericMethodDefinition || method.IsGenericMethod) {
+ name.Append ("<");
+ if (method.VirtualMachine.Version.AtLeast (2, 15)) {
+ var types = method.GetGenericArguments ();
+ for (int i = 0; i < types.Length; i++) {
+ if (i != 0)
+ name.Append (", ");
+ name.Append (Adaptor.GetDisplayTypeName (types[i].FullName));
+ }
+ }
+ name.Append (">");
+ }
+ }
+
+ name.Append (" (");
+ var @params = method.GetParameters ();
+ for (int i = 0; i < @params.Length; i++) {
+ if (i != 0)
+ name.Append (", ");
+ if (@params[i].Attributes.HasFlag (ParameterAttributes.Out)) {
+ if (@params[i].Attributes.HasFlag (ParameterAttributes.In))
+ name.Append ("ref ");
+ else
+ name.Append ("out ");
+ }
+ name.Append (Adaptor.GetDisplayTypeName (@params[i].ParameterType.FullName));
+ name.Append (" ");
+ name.Append (@params[i].Name);
+ }
+ name.Append (")");
+
+ return name.ToString ();
+ }
+
+ void ResolveBreakpoints (TypeMirror type)
+ {
+ var resolved = new List<BreakInfo> ();
+ Location loc;
+
+ ProcessType (type);
+
+ // First, resolve FunctionBreakpoints
+ foreach (var bi in pending_bes.Where (b => b.BreakEvent is FunctionBreakpoint)) {
+ if (CheckTypeName (type, bi.TypeName)) {
+ var bp = (FunctionBreakpoint) bi.BreakEvent;
+ string methodName = bp.FunctionName.Substring (bi.TypeName.Length + 1);
+
+ foreach (var method in type.GetMethodsByNameFlags (methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, false)) {
+ if (!CheckMethodParams (method, bp.ParamTypes))
+ continue;
+
+ loc = GetLocFromMethod (method);
+ if (loc != null) {
+ string paramList = "(" + string.Join (", ", bp.ParamTypes ?? GetParamTypes (method)) + ")";
+ OnDebuggerOutput (false, string.Format ("Resolved pending breakpoint for '{0}{1}' to {2}:{3} [0x{4:x5}].\n",
+ bp.FunctionName, paramList, loc.SourceFile, loc.LineNumber, loc.ILOffset));
+
+ ResolvePendingBreakpoint (bi, loc);
+
+ // Note: if the type or method is generic, there may be more instances so don't assume we are done resolving the breakpoint
+ if (bp.ParamTypes != null && !type.IsGenericType && !IsGenericMethod (method))
+ resolved.Add (bi);
+ }
+ }
+ }
+ }
+
+ foreach (var be in resolved)
+ pending_bes.Remove (be);
+ resolved.Clear ();
+
+ // Now resolve normal Breakpoints
+ foreach (string s in type_to_source [type]) {
+ foreach (var bi in pending_bes.Where (b => (b.BreakEvent is Breakpoint) && !(b.BreakEvent is FunctionBreakpoint))) {
+ var bp = (Breakpoint) bi.BreakEvent;
+ if (PathsAreEqual (PathToFileName (bp.FileName), s)) {
+ bool insideLoadedRange;
+ bool genericMethod;
+
+ loc = GetLocFromType (type, s, bp.Line, bp.Column, out genericMethod, out insideLoadedRange);
+ if (loc != null) {
+ OnDebuggerOutput (false, string.Format ("Resolved pending breakpoint at '{0}:{1},{2}' to {3} [0x{4:x5}].\n",
+ s, bp.Line, bp.Column, GetPrettyMethodName (loc.Method), loc.ILOffset));
+ ResolvePendingBreakpoint (bi, loc);
+
+ // Note: if the type or method is generic, there may be more instances so don't assume we are done resolving the breakpoint
+ if (!genericMethod && !type.IsGenericType)
+ resolved.Add (bi);
+ } else {
+ if (insideLoadedRange) {
+ bi.SetStatus (BreakEventStatus.Invalid, null);
+ }
+ }
+ }
+ }
+
+ foreach (var be in resolved)
+ pending_bes.Remove (be);
+ resolved.Clear ();
+ }
+
+ // Thirdly, resolve pending catchpoints
+ foreach (var bi in pending_bes.Where (b => b.BreakEvent is Catchpoint)) {
+ var cp = (Catchpoint) bi.BreakEvent;
+ if (cp.ExceptionName == type.FullName) {
+ ResolvePendingCatchpoint (bi, type);
+ resolved.Add (bi);
+ }
+ }
+
+ foreach (var be in resolved)
+ pending_bes.Remove (be);
+ }
+
+ internal static string NormalizePath (string path)
+ {
+ if (!IsWindows && path.StartsWith ("\\", StringComparison.Ordinal))
+ return path.Replace ('\\', '/');
+
+ return path;
+ }
+
+ string PathToFileName (string path)
+ {
+ if (useFullPaths)
+ return path;
+
+ return Path.GetFileName (path);
+ }
+
+ [DllImport ("libc")]
+ static extern IntPtr realpath (string path, IntPtr buffer);
+
+ static string ResolveFullPath (string path)
+ {
+ if (IsWindows)
+ return Path.GetFullPath (path);
+
+ const int PATHMAX = 4096 + 1;
+ IntPtr buffer = IntPtr.Zero;
+
+ try {
+ buffer = Marshal.AllocHGlobal (PATHMAX);
+ var result = realpath (path, buffer);
+ return result == IntPtr.Zero ? "" : Marshal.PtrToStringAuto (buffer);
+ } finally {
+ if (buffer != IntPtr.Zero)
+ Marshal.FreeHGlobal (buffer);
+ }
+ }
+
+ static bool PathsAreEqual (string p1, string p2)
+ {
+ if (string.IsNullOrWhiteSpace (p1) || string.IsNullOrWhiteSpace (p2))
+ return false;
+
+ if (PathComparer.Compare (p1, p2) == 0)
+ return true;
+
+ var rp1 = ResolveFullPath (p1);
+ var rp2 = ResolveFullPath (p2);
+
+ return PathComparer.Compare (rp1, rp2) == 0;
+ }
+
+ Location GetLocFromMethod (MethodMirror method)
+ {
+ // Return the location of the method.
+ return method.Locations.Count > 0 ? method.Locations[0] : null;
+ }
+
+ bool CheckBetterMatch (TypeMirror type, string file, int line, Location found)
+ {
+ if (type.Assembly == null)
+ return false;
+
+ string assemblyFileName;
+ if (!assemblyPathMap.TryGetValue (type.Assembly.GetName ().FullName, out assemblyFileName))
+ assemblyFileName = type.Assembly.Location;
+
+ if (assemblyFileName == null)
+ return false;
+
+ string mdbFileName = assemblyFileName + ".mdb";
+ int foundDelta = found.LineNumber - line;
+ MonoSymbolFile mdb;
+ int fileId = -1;
+
+ try {
+ if (!symbolFiles.TryGetValue (mdbFileName, out mdb)) {
+ if (!File.Exists (mdbFileName))
+ return false;
+
+ mdb = MonoSymbolFile.ReadSymbolFile (mdbFileName);
+ symbolFiles.Add (mdbFileName, mdb);
+ }
+
+ foreach (var src in mdb.Sources) {
+ if (src.FileName == file) {
+ fileId = src.Index;
+ break;
+ }
+ }
+
+ if (fileId == -1)
+ return false;
+
+ foreach (var method in mdb.Methods) {
+ var table = method.GetLineNumberTable ();
+ foreach (var entry in table.LineNumbers) {
+ if (entry.File != fileId)
+ continue;
+
+ if (entry.Row >= line && (entry.Row - line) < foundDelta)
+ return true;
+ }
+ }
+ } catch {
+ }
+
+ return false;
+ }
+
+ Location GetLocFromType (TypeMirror type, string file, int line, int column, out bool genericMethod, out bool insideTypeRange)
+ {
+ Location target_loc = null;
+ bool fuzzy = true;
+
+ insideTypeRange = false;
+ genericMethod = false;
+
+ //Console.WriteLine ("Trying to resolve {0}:{1},{2} in type {3}", file, line, column, type.Name);
+ foreach (MethodMirror method in type.GetMethods ()) {
+ List<Location> locations = new List<Location> ();
+ int rangeFirstLine = int.MaxValue;
+ int rangeLastLine = -1;
+
+ foreach (Location location in method.Locations) {
+ string srcFile = location.SourceFile;
+
+ //Console.WriteLine ("\tExamining {0}:{1}...", srcFile, location.LineNumber);
+
+ if (srcFile != null && PathsAreEqual (PathToFileName (NormalizePath (srcFile)), file)) {
+ if (location.LineNumber < rangeFirstLine)
+ rangeFirstLine = location.LineNumber;
+
+ if (location.LineNumber > rangeLastLine)
+ rangeLastLine = location.LineNumber;
+
+ if (line >= rangeFirstLine && line <= rangeLastLine)
+ insideTypeRange = true;
+
+ if (location.LineNumber >= line && line >= rangeFirstLine) {
+ if (target_loc != null) {
+ if (location.LineNumber > line) {
+ if (target_loc.LineNumber - line > location.LineNumber - line) {
+ // Grab the location closest to the requested line
+ //Console.WriteLine ("\t\tLocation is closest match. (ILOffset = 0x{0:x5})", location.ILOffset);
+ locations.Clear ();
+ locations.Add (location);
+ target_loc = location;
+ }
+ } else if (target_loc.LineNumber != line) {
+ // Previous match was a fuzzy match, but now we've found an exact line match
+ //Console.WriteLine ("\t\tLocation is exact line match. (ILOffset = 0x{0:x5})", location.ILOffset);
+ locations.Clear ();
+ locations.Add (location);
+ target_loc = location;
+ fuzzy = false;
+ } else {
+ // Line number matches exactly, use the location with the lowest ILOffset
+ if (location.ILOffset < target_loc.ILOffset)
+ target_loc = location;
+
+ locations.Add (location);
+ fuzzy = false;
+ }
+ } else {
+ //Console.WriteLine ("\t\tLocation is first possible match. (ILOffset = 0x{0:x5})", location.ILOffset);
+ fuzzy = location.LineNumber != line;
+ locations.Add (location);
+ target_loc = location;
+ }
+ }
+ } else {
+ rangeFirstLine = int.MaxValue;
+ rangeLastLine = -1;
+ }
+ }
+
+ if (target_loc != null) {
+ genericMethod = IsGenericMethod (method);
+
+ // If we got a fuzzy match, then we need to make sure that there isn't a better
+ // match in another method (e.g. code might have been extracted out into another
+ // method by the compiler.
+ if (!fuzzy) {
+ // Exact line match... now find the best column match.
+ locations.Sort (new LocationComparer ());
+
+ // Find the closest-matching location based on column.
+ target_loc = locations[0];
+ for (int i = 1; i < locations.Count; i++) {
+ if (locations[i].ColumnNumber > column)
+ break;
+
+ // if the column numbers match, then target_loc should have the lower ILOffset (which we want)
+ if (target_loc.ColumnNumber == locations[i].ColumnNumber)
+ continue;
+
+ target_loc = locations[i];
+ }
+
+ return target_loc;
+ }
+ }
+ }
+
+ if (target_loc != null && fuzzy && CheckBetterMatch (type, file, line, target_loc)) {
+ insideTypeRange = false;
+ return null;
+ }
+
+ return target_loc;
+ }
+
+ void ResolvePendingBreakpoint (BreakInfo bi, Location l)
+ {
+ bi.Location = l;
+ InsertBreakpoint ((Breakpoint) bi.BreakEvent, bi);
+ bi.SetStatus (BreakEventStatus.Bound, null);
+ }
+
+ void ResolvePendingCatchpoint (BreakInfo bi, TypeMirror type)
+ {
+ InsertCatchpoint ((Catchpoint) bi.BreakEvent, bi, type);
+ bi.SetStatus (BreakEventStatus.Bound, null);
+ }
+
+ bool UpdateAssemblyFilters (AssemblyMirror asm)
+ {
+ var name = asm.GetName ().FullName;
+ bool found = false;
+ if (userAssemblyNames != null) {
+ //HACK: not sure how else to handle xsp-compiled pages
+ if (name.StartsWith ("App_", StringComparison.Ordinal)) {
+ found = true;
+ } else {
+ foreach (var n in userAssemblyNames) {
+ if (n == name) {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (found) {
+ assemblyFilters.Add (asm);
+ return true;
+ }
+
+ return false;
+ }
+
+ internal void WriteDebuggerOutput (bool isError, string msg)
+ {
+ OnDebuggerOutput (isError, msg);
+ }
+
+ protected override void OnSetActiveThread (long processId, long threadId)
+ {
+ }
+
+ protected override void OnStepInstruction ()
+ {
+ Step (StepDepth.Into, StepSize.Min);
+ }
+
+ protected override void OnStepLine ()
+ {
+ Step (StepDepth.Into, StepSize.Line);
+ }
+
+ protected override void OnStop ()
+ {
+ vm.Suspend ();
+
+ //emit a stop event at the current position of the most recent thread
+ //we use "getprocesses" instead of "ongetprocesses" because it attaches the process to the session
+ //using private Mono.Debugging API, so our thread/backtrace calls will cache stuff that will get used later
+ var process = GetProcesses () [0];
+ EnsureRecentThreadIsValid (process);
+ current_thread = recent_thread;
+ OnTargetEvent (new TargetEventArgs (TargetEventType.TargetStopped) {
+ Process = process,
+ Thread = GetThread (process, recent_thread),
+ Backtrace = GetThreadBacktrace (recent_thread)});
+ }
+
+ void EnsureRecentThreadIsValid (ProcessInfo process)
+ {
+ var infos = process.GetThreads ();
+
+ if (ThreadIsAlive (recent_thread) && HasUserFrame (GetId (recent_thread), infos))
+ return;
+
+ var threads = vm.GetThreads ();
+ foreach (var thread in threads) {
+ if (ThreadIsAlive (thread) && HasUserFrame (GetId (thread), infos)) {
+ recent_thread = thread;
+ return;
+ }
+ }
+ recent_thread = threads[0];
+ }
+
+ long GetId (ThreadMirror thread)
+ {
+ long id;
+ if (!localThreadIds.TryGetValue (thread.ThreadId, out id)) {
+ id = localThreadIds.Count + 1;
+ localThreadIds [thread.ThreadId] = id;
+ }
+ return id;
+ }
+
+ static bool ThreadIsAlive (ThreadMirror thread)
+ {
+ if (thread == null)
+ return false;
+ var state = thread.ThreadState;
+ return state != ThreadState.Stopped && state != ThreadState.Aborted;
+ }
+
+ //we use the Mono.Debugging classes because they are cached
+ bool HasUserFrame (long tid, ThreadInfo[] infos)
+ {
+ foreach (var t in infos) {
+ if (t.Id != tid)
+ continue;
+ var bt = t.Backtrace;
+ for (int i = 0; i < bt.FrameCount; i++) {
+ var frame = bt.GetFrame (i);
+ if (frame != null && !frame.IsExternalCode)
+ return true;
+ }
+ return false;
+ }
+ return false;
+ }
+
+ public bool IsExternalCode (Mono.Debugger.Soft.StackFrame frame)
+ {
+ return frame.Method == null || string.IsNullOrEmpty (frame.FileName)
+ || (assemblyFilters != null && !assemblyFilters.Contains (frame.Method.DeclaringType.Assembly));
+ }
+
+ public bool IsExternalCode (TypeMirror type)
+ {
+ return assemblyFilters != null && !assemblyFilters.Contains (type.Assembly);
+ }
+
+ protected override AssemblyLine[] OnDisassembleFile (string file)
+ {
+ List<TypeMirror> types;
+ if (!source_to_type.TryGetValue (file, out types))
+ return new AssemblyLine [0];
+
+ var lines = new List<AssemblyLine> ();
+ foreach (TypeMirror type in types) {
+ foreach (MethodMirror met in type.GetMethods ()) {
+ string srcFile = met.SourceFile != null ? NormalizePath (met.SourceFile) : null;
+
+ if (srcFile == null || !PathsAreEqual (srcFile, file))
+ continue;
+
+ var body = met.GetMethodBody ();
+ int lastLine = -1;
+ int firstPos = lines.Count;
+ string addrSpace = met.FullName;
+
+ foreach (var ins in body.Instructions) {
+ Location loc = met.LocationAtILOffset (ins.Offset);
+ if (loc != null && lastLine == -1) {
+ lastLine = loc.LineNumber;
+ for (int n=firstPos; n<lines.Count; n++) {
+ AssemblyLine old = lines [n];
+ lines [n] = new AssemblyLine (old.Address, old.AddressSpace, old.Code, loc.LineNumber);
+ }
+ }
+ lines.Add (new AssemblyLine (ins.Offset, addrSpace, Disassemble (ins), loc != null ? loc.LineNumber : lastLine));
+ }
+ }
+ }
+ lines.Sort (delegate (AssemblyLine a1, AssemblyLine a2) {
+ int res = a1.SourceLine.CompareTo (a2.SourceLine);
+ if (res != 0)
+ return res;
+
+ return a1.Address.CompareTo (a2.Address);
+ });
+ return lines.ToArray ();
+ }
+
+ public AssemblyLine[] Disassemble (Mono.Debugger.Soft.StackFrame frame, int firstLine, int count)
+ {
+ MethodBodyMirror body = frame.Method.GetMethodBody ();
+ var instructions = body.Instructions;
+ ILInstruction current = null;
+ foreach (var ins in instructions) {
+ if (ins.Offset >= frame.ILOffset) {
+ current = ins;
+ break;
+ }
+ }
+ if (current == null)
+ return new AssemblyLine [0];
+
+ var result = new List<AssemblyLine> ();
+
+ int pos = firstLine;
+
+ while (firstLine < 0 && count > 0) {
+ if (current.Previous == null) {
+// result.Add (new AssemblyLine (99999, "<" + (pos++) + ">"));
+ result.Add (AssemblyLine.OutOfRange);
+ count--;
+ firstLine++;
+ } else {
+ current = current.Previous;
+ firstLine++;
+ }
+ }
+
+ while (current != null && firstLine > 0) {
+ current = current.Next;
+ firstLine--;
+ }
+
+ while (count > 0) {
+ if (current != null) {
+ Location loc = frame.Method.LocationAtILOffset (current.Offset);
+ result.Add (new AssemblyLine (current.Offset, frame.Method.FullName, Disassemble (current), loc != null ? loc.LineNumber : -1));
+ current = current.Next;
+ pos++;
+ } else
+ result.Add (AssemblyLine.OutOfRange);
+// result.Add (new AssemblyLine (99999, "<" + (pos++) + ">"));
+ count--;
+ }
+ return result.ToArray ();
+ }
+
+ static string EscapeString (string text)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ sb.Append ('"');
+ for (int i = 0; i < text.Length; i++) {
+ char c = text[i];
+ string txt;
+ switch (c) {
+ case '"': txt = "\\\""; break;
+ case '\0': txt = @"\0"; break;
+ case '\\': txt = @"\\"; break;
+ case '\a': txt = @"\a"; break;
+ case '\b': txt = @"\b"; break;
+ case '\f': txt = @"\f"; break;
+ case '\v': txt = @"\v"; break;
+ case '\n': txt = @"\n"; break;
+ case '\r': txt = @"\r"; break;
+ case '\t': txt = @"\t"; break;
+ default:
+ if (char.GetUnicodeCategory (c) == UnicodeCategory.OtherNotAssigned) {
+ sb.AppendFormat ("\\u{0:X4}", c);
+ } else {
+ sb.Append (c);
+ }
+ continue;
+ }
+ sb.Append (txt);
+ }
+ sb.Append ('"');
+
+ return sb.ToString ();
+ }
+
+ string Disassemble (ILInstruction ins)
+ {
+ string oper;
+ if (ins.Operand is MethodMirror)
+ oper = ((MethodMirror)ins.Operand).FullName;
+ else if (ins.Operand is TypeMirror)
+ oper = ((TypeMirror)ins.Operand).FullName;
+ else if (ins.Operand is ILInstruction)
+ oper = ((ILInstruction)ins.Operand).Offset.ToString ("x8");
+ else if (ins.Operand is string)
+ oper = EscapeString ((string) ins.Operand);
+ else if (ins.Operand == null)
+ oper = string.Empty;
+ else
+ oper = ins.Operand.ToString ();
+
+ return ins.OpCode + " " + oper;
+ }
+
+ readonly static bool IsWindows;
+ readonly static bool IsMac;
+ readonly static StringComparer PathComparer;
+
+ static bool IgnoreFilenameCase {
+ get {
+ return IsMac || IsWindows;
+ }
+ }
+
+ static SoftDebuggerSession ()
+ {
+ IsWindows = Path.DirectorySeparatorChar == '\\';
+ IsMac = !IsWindows && IsRunningOnMac();
+ PathComparer = (IgnoreFilenameCase)? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
+ ThreadMirror.NativeTransitions = true;
+ }
+
+ //From Managed.Windows.Forms/XplatUI
+ static bool IsRunningOnMac ()
+ {
+ IntPtr buf = IntPtr.Zero;
+ try {
+ buf = Marshal.AllocHGlobal (8192);
+ // This is a hacktastic way of getting sysname from uname ()
+ if (uname (buf) == 0) {
+ string os = Marshal.PtrToStringAnsi (buf);
+ if (os == "Darwin")
+ return true;
+ }
+ } catch {
+ } finally {
+ if (buf != IntPtr.Zero)
+ Marshal.FreeHGlobal (buf);
+ }
+ return false;
+ }
+
+ [System.Runtime.InteropServices.DllImport ("libc")]
+ static extern int uname (IntPtr buf);
+ }
+
+ class LocationComparer : IComparer<Location>
+ {
+ public int Compare (Location loc0, Location loc1)
+ {
+ if (loc0.LineNumber < loc1.LineNumber)
+ return -1;
+ if (loc0.LineNumber > loc1.LineNumber)
+ return 1;
+
+ if (loc0.ColumnNumber < loc1.ColumnNumber)
+ return -1;
+ if (loc0.ColumnNumber > loc1.ColumnNumber)
+ return 1;
+
+ return loc0.ILOffset - loc1.ILOffset;
+ }
+ }
+
+ class BreakInfo: BreakEventInfo
+ {
+ public Location Location;
+ public List<EventRequest> Requests = new List<EventRequest> ();
+ public string LastConditionValue;
+ public string FileName;
+ public string TypeName;
+ }
+
+ class DisconnectedException: DebuggerException
+ {
+ public DisconnectedException (Exception ex):
+ base ("The connection with the debugger has been lost. The target application may have exited.", ex)
+ {
+ }
+ }
+
+ class DebugSocketException: DebuggerException
+ {
+ public DebugSocketException (Exception ex):
+ base ("Could not open port for debugger. Another process may be using the port.", ex)
+ {
+ }
+ }
+
+ class ConnectionException : DebuggerException
+ {
+ public ConnectionException (Exception ex):
+ base ("Could not connect to the debugger.", ex)
+ {
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/SoftDebuggerStartInfo.cs b/Mono.Debugging.Soft/SoftDebuggerStartInfo.cs
new file mode 100644
index 0000000..d51e603
--- /dev/null
+++ b/Mono.Debugging.Soft/SoftDebuggerStartInfo.cs
@@ -0,0 +1,203 @@
+//
+// SoftDebuggerStartInfo.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson at novell.com>
+//
+// Copyright (c) 2010 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 Mono.Debugging.Client;
+using System.Collections.Generic;
+using System.Reflection;
+using System.IO;
+using System.Net;
+using Mono.Debugger.Soft;
+
+namespace Mono.Debugging.Soft
+{
+ public class SoftDebuggerStartInfo : DebuggerStartInfo
+ {
+ public SoftDebuggerStartInfo (string monoRuntimePrefix, Dictionary<string,string> monoRuntimeEnvironmentVariables)
+ : this (new SoftDebuggerLaunchArgs (monoRuntimePrefix, monoRuntimeEnvironmentVariables))
+ {
+ }
+
+ public SoftDebuggerStartInfo (SoftDebuggerStartArgs startArgs)
+ {
+ if (startArgs == null)
+ throw new ArgumentNullException ("startArgs");
+ this.StartArgs = startArgs;
+ }
+
+ /// <summary>
+ /// Names of assemblies that are user code.
+ /// </summary>
+ public List<AssemblyName> UserAssemblyNames { get; set; }
+
+ /// <summary>
+ /// A mapping of AssemblyNames to their paths.
+ /// </summary>
+ public Dictionary<string, string> AssemblyPathMap { get; set; }
+
+ /// <summary>
+ /// The session will output this to the debug log as soon as it starts. It can be used to log warnings from
+ /// creating the SoftDebuggerStartInfo
+ /// </summary>
+ public string LogMessage { get; set; }
+
+ /// <summary>
+ /// Args for starting the debugger connection.
+ /// </summary>
+ public SoftDebuggerStartArgs StartArgs { get; set; }
+ }
+
+ public interface ISoftDebuggerConnectionProvider
+ {
+ IAsyncResult BeginConnect (DebuggerStartInfo dsi, AsyncCallback callback);
+ void EndConnect (IAsyncResult result, out VirtualMachine vm, out string appName);
+ void CancelConnect (IAsyncResult result);
+ bool ShouldRetryConnection (Exception ex);
+ }
+
+ public abstract class SoftDebuggerStartArgs
+ {
+ public SoftDebuggerStartArgs ()
+ {
+ MaxConnectionAttempts = 1;
+ TimeBetweenConnectionAttempts = 500;
+ }
+
+ public abstract ISoftDebuggerConnectionProvider ConnectionProvider { get; }
+
+ /// <summary>
+ /// Maximum number of connection attempts. Zero or less means infinite attempts. Default is 1.
+ /// </summary>
+ public int MaxConnectionAttempts { get; set; }
+
+ /// <summary>
+ /// The time between connection attempts, in milliseconds. Default is 500.
+ /// </summary>
+ public int TimeBetweenConnectionAttempts { get; set; }
+ }
+
+ public abstract class SoftDebuggerRemoteArgs : SoftDebuggerStartArgs
+ {
+ public SoftDebuggerRemoteArgs (string appName, IPAddress address, int debugPort, int outputPort)
+ {
+ if (address == null)
+ throw new ArgumentNullException ("address");
+ if (debugPort < 0)
+ throw new ArgumentException ("Debug port cannot be less than zero", "debugPort");
+
+ this.AppName = appName;
+ this.Address = address;
+ this.DebugPort = debugPort;
+ this.OutputPort = outputPort;
+ }
+
+ /// <summary>
+ /// The IP address for the connection.
+ /// </summary>
+ public IPAddress Address { get; private set; }
+
+ /// <summary>
+ /// Port for the debugger connection. Zero means random port.
+ /// </summary>
+ public int DebugPort { get; private set; }
+
+ /// <summary>
+ /// Port for the console connection. Zero means random port, less than zero means that output is not redirected.
+ /// </summary>
+ public int OutputPort { get; private set; }
+
+ /// <summary>
+ /// Application name that will be shown in the debugger.
+ /// </summary>
+ public string AppName { get; private set; }
+
+ public bool RedirectOutput { get { return OutputPort >= 0; } }
+ }
+
+ /// <summary>
+ /// Args for the debugger to listen for an incoming connection from a debuggee.
+ /// </summary>
+ public sealed class SoftDebuggerListenArgs : SoftDebuggerRemoteArgs
+ {
+ public SoftDebuggerListenArgs (string appName, IPAddress address, int debugPort)
+ : this (appName, address, debugPort, -1) {}
+
+ public SoftDebuggerListenArgs (string appName, IPAddress address, int debugPort, int outputPort)
+ : base (appName, address, debugPort, outputPort)
+ {
+ }
+
+ public override ISoftDebuggerConnectionProvider ConnectionProvider { get { return null; } }
+ }
+
+ /// <summary>
+ /// Args for the debugger to connect to target that is listening.
+ /// </summary>
+ public sealed class SoftDebuggerConnectArgs : SoftDebuggerRemoteArgs
+ {
+ public SoftDebuggerConnectArgs (string appName, IPAddress address, int debugPort)
+ : this (appName, address, debugPort, -1) {}
+
+ public SoftDebuggerConnectArgs (string appName, IPAddress address, int debugPort, int outputPort)
+ : base (appName, address, debugPort, outputPort)
+ {
+ if (debugPort == 0)
+ throw new ArgumentException ("Debug port cannot be zero when connecting", "debugPort");
+ if (outputPort == 0)
+ throw new ArgumentException ("Output port cannot be zero when connecting", "outputPort");
+ }
+
+ public override ISoftDebuggerConnectionProvider ConnectionProvider { get { return null; } }
+ }
+
+ /// <summary>
+ /// Options for the debugger to start a process directly.
+ /// </summary>
+ public sealed class SoftDebuggerLaunchArgs : SoftDebuggerStartArgs
+ {
+ public SoftDebuggerLaunchArgs (string monoRuntimePrefix, Dictionary<string,string> monoRuntimeEnvironmentVariables)
+ {
+ this.MonoRuntimePrefix = monoRuntimePrefix;
+ this.MonoRuntimeEnvironmentVariables = monoRuntimeEnvironmentVariables;
+ }
+
+ /// <summary>
+ /// Prefix into which the target Mono runtime is installed.
+ /// </summary>
+ public string MonoRuntimePrefix { get; private set; }
+
+ /// <summary>
+ /// Environment variables for the Mono runtime.
+ /// </summary>
+ public Dictionary<string,string> MonoRuntimeEnvironmentVariables { get; private set; }
+
+ /// <summary>
+ /// Launcher for the external console. May be null if the app does not run on an external console.
+ /// </summary>
+ public Mono.Debugger.Soft.LaunchOptions.TargetProcessLauncher ExternalConsoleLauncher { get; set; }
+
+ public override ISoftDebuggerConnectionProvider ConnectionProvider { get { return null; } }
+ }
+}
\ No newline at end of file
diff --git a/Mono.Debugging.Soft/SoftEvaluationContext.cs b/Mono.Debugging.Soft/SoftEvaluationContext.cs
new file mode 100644
index 0000000..ced30d6
--- /dev/null
+++ b/Mono.Debugging.Soft/SoftEvaluationContext.cs
@@ -0,0 +1,186 @@
+//
+// SoftEvaluationContext.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Evaluation;
+using Mono.Debugger.Soft;
+using DC = Mono.Debugging.Client;
+
+namespace Mono.Debugging.Soft
+{
+ public class SoftEvaluationContext: EvaluationContext
+ {
+ SoftDebuggerSession session;
+ int stackVersion;
+ StackFrame frame;
+ bool sourceAvailable;
+
+ public ThreadMirror Thread { get; set; }
+
+ public SoftEvaluationContext (SoftDebuggerSession session, StackFrame frame, DC.EvaluationOptions options): base (options)
+ {
+ Frame = frame;
+ Thread = frame.Thread;
+
+ string method = frame.Method.Name;
+ if (frame.Method.DeclaringType != null)
+ method = frame.Method.DeclaringType.FullName + "." + method;
+ var location = new DC.SourceLocation (method, frame.FileName, frame.LineNumber, frame.ColumnNumber);
+ string language;
+
+ if (frame.Method != null) {
+ if (frame.IsNativeTransition) {
+ language = "Transition";
+ } else {
+ language = "Managed";
+ }
+ } else {
+ language = "Native";
+ }
+
+ Evaluator = session.GetEvaluator (new DC.StackFrame (frame.ILOffset, location, language, session.IsExternalCode (frame), true));
+ Adapter = session.Adaptor;
+ this.session = session;
+ this.stackVersion = session.StackVersion;
+ sourceAvailable = !string.IsNullOrEmpty (frame.FileName) && System.IO.File.Exists (frame.FileName);
+ }
+
+ public StackFrame Frame {
+ get {
+ if (stackVersion != session.StackVersion)
+ UpdateFrame ();
+ return frame;
+ }
+ set {
+ frame = value;
+ }
+ }
+
+ public bool SourceCodeAvailable {
+ get {
+ if (stackVersion != session.StackVersion)
+ sourceAvailable = !string.IsNullOrEmpty (Frame.FileName) && System.IO.File.Exists (Frame.FileName);
+ return sourceAvailable;
+ }
+ }
+
+ public SoftDebuggerSession Session {
+ get { return session; }
+ }
+
+ public override void WriteDebuggerError (Exception ex)
+ {
+ session.WriteDebuggerOutput (true, ex.ToString ());
+ }
+
+ public override void WriteDebuggerOutput (string message, params object[] values)
+ {
+ session.WriteDebuggerOutput (false, string.Format (message, values));
+ }
+
+ public override void CopyFrom (EvaluationContext ctx)
+ {
+ base.CopyFrom (ctx);
+ SoftEvaluationContext other = (SoftEvaluationContext) ctx;
+ frame = other.frame;
+ stackVersion = other.stackVersion;
+ Thread = other.Thread;
+ session = other.session;
+ }
+
+ static bool IsValueTypeOrPrimitive (TypeMirror type)
+ {
+ return type != null && (type.IsValueType || type.IsPrimitive);
+ }
+
+ static bool IsValueTypeOrPrimitive (Type type)
+ {
+ return type != null && (type.IsValueType || type.IsPrimitive);
+ }
+
+ public Value RuntimeInvoke (MethodMirror method, object target, Value[] values)
+ {
+ if (values != null) {
+ // Some arguments may need to be boxed
+ ParameterInfoMirror[] mparams = method.GetParameters ();
+ if (mparams.Length != values.Length)
+ throw new EvaluatorException ("Invalid number of arguments when calling: " + method.Name);
+
+ for (int n = 0; n < mparams.Length; n++) {
+ TypeMirror tm = mparams [n].ParameterType;
+ if (tm.IsValueType || tm.IsPrimitive)
+ continue;
+
+ object type = Adapter.GetValueType (this, values [n]);
+ TypeMirror argTypeMirror = type as TypeMirror;
+ Type argType = type as Type;
+
+ if (IsValueTypeOrPrimitive (argTypeMirror) || IsValueTypeOrPrimitive (argType)) {
+ // A value type being assigned to a parameter which is not a value type. The value has to be boxed.
+ try {
+ values [n] = Thread.Domain.CreateBoxedValue (values [n]);
+ } catch (NotSupportedException) {
+ // This runtime doesn't support creating boxed values
+ throw new EvaluatorException ("This runtime does not support creating boxed values.");
+ }
+ }
+ }
+ }
+
+ if (!method.IsStatic && method.DeclaringType.IsClass && !IsValueTypeOrPrimitive (method.DeclaringType)) {
+ object type = Adapter.GetValueType (this, target);
+ TypeMirror targetTypeMirror = type as TypeMirror;
+ Type targetType = type as Type;
+
+ if ((target is StructMirror && ((StructMirror) target).Type != method.DeclaringType) ||
+ (IsValueTypeOrPrimitive (targetTypeMirror) || IsValueTypeOrPrimitive (targetType))) {
+ // A value type being assigned to a parameter which is not a value type. The value has to be boxed.
+ try {
+ target = Thread.Domain.CreateBoxedValue ((Value) target);
+ } catch (NotSupportedException) {
+ // This runtime doesn't support creating boxed values
+ throw new EvaluatorException ("This runtime does not support creating boxed values.");
+ }
+ }
+ }
+
+ MethodCall mc = new MethodCall (this, method, target, values);
+ Adapter.AsyncExecute (mc, Options.EvaluationTimeout);
+ return mc.ReturnValue;
+ }
+
+ void UpdateFrame ()
+ {
+ stackVersion = session.StackVersion;
+ foreach (StackFrame f in Thread.GetFrames ()) {
+ if (f.FileName == Frame.FileName && f.LineNumber == Frame.LineNumber && f.ILOffset == Frame.ILOffset) {
+ Frame = f;
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/StringAdaptor.cs b/Mono.Debugging.Soft/StringAdaptor.cs
new file mode 100644
index 0000000..6fb73c0
--- /dev/null
+++ b/Mono.Debugging.Soft/StringAdaptor.cs
@@ -0,0 +1,76 @@
+//
+// StringAdaptor.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2012 Xamarin Inc.
+//
+// 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 Mono.Debugging.Evaluation;
+using Mono.Debugger.Soft;
+
+namespace Mono.Debugging.Soft
+{
+ public class StringAdaptor: IStringAdaptor
+ {
+ bool atleast_2_10;
+ StringMirror str;
+ string val;
+
+ public StringAdaptor (StringMirror str)
+ {
+ atleast_2_10 = str.VirtualMachine.Version.AtLeast (2, 10);
+ this.str = str;
+ }
+
+ public int Length {
+ get {
+ if (atleast_2_10)
+ return str.Length;
+
+ if (val == null)
+ val = str.Value;
+
+ return val.Length;
+ }
+ }
+
+ public string Value {
+ get {
+ if (val == null)
+ val = str.Value;
+
+ return val;
+ }
+ }
+
+ public string Substring (int index, int length)
+ {
+ if (val == null && atleast_2_10)
+ return new string (str.GetChars (index, length));
+
+ if (val == null)
+ val = str.Value;
+
+ return val.Substring (index, length);
+ }
+ }
+}
diff --git a/Mono.Debugging.Soft/VariableValueReference.cs b/Mono.Debugging.Soft/VariableValueReference.cs
new file mode 100644
index 0000000..cb04ea6
--- /dev/null
+++ b/Mono.Debugging.Soft/VariableValueReference.cs
@@ -0,0 +1,88 @@
+//
+// VariableValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Evaluation;
+using Mono.Debugging.Client;
+using Mono.Debugger.Soft;
+
+namespace Mono.Debugging.Soft
+{
+ public class VariableValueReference : ValueReference
+ {
+ string name;
+ LocalVariable variable;
+
+ public VariableValueReference (EvaluationContext ctx, string name, LocalVariable variable): base (ctx)
+ {
+ this.name = name;
+ this.variable = variable;
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.Variable;
+ }
+ }
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+
+ public override object Type {
+ get {
+ return variable.Type;
+ }
+ }
+
+ public override object Value {
+ get {
+ SoftEvaluationContext ctx = (SoftEvaluationContext) Context;
+ try {
+ var value = ctx.Frame.GetValue (variable);
+
+ if (variable.Type.IsPointer) {
+ long addr = (long) ((PrimitiveValue) value).Value;
+ value = new PointerValue (value.VirtualMachine, variable.Type, addr);
+ }
+
+ return value;
+ } catch (AbsentInformationException) {
+ throw new EvaluatorException ("Value not available");
+ } catch (ArgumentException ex) {
+ throw new EvaluatorException (ex.Message);
+ }
+ }
+ set {
+ SoftEvaluationContext ctx = (SoftEvaluationContext) Context;
+ ctx.Frame.SetValue (variable, (Value) value);
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/ChangeLog b/Mono.Debugging/ChangeLog
new file mode 100644
index 0000000..beef217
--- /dev/null
+++ b/Mono.Debugging/ChangeLog
@@ -0,0 +1,1032 @@
+2010-07-13 Levi Bard <levi at unity3d.com>
+
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ Add method for unescaping strings.
+
+2010-05-20 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Dispose
+ asynchronously.
+
+2010-05-20 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/BaseBacktrace.cs:
+ * Mono.Debugging.Evaluation/ExceptionInfoSource.cs: Fix crash
+ when getting locals which include the last thrown exception.
+
+2010-05-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Backend/IBacktrace.cs:
+ * Mono.Debugging.Client/ExceptionInfo.cs:
+ * Mono.Debugging.Evaluation/BaseBacktrace.cs:
+ * Mono.Debugging.Evaluation/ExceptionInfoSource.cs: Introduced
+ ExceptionInfo, which provides information about a caught
+ exception, including description and stack traces.
+
+ * Mono.Debugging.Client/RawValue.cs:
+ * Mono.Debugging.Evaluation/RemoteRawValue.cs:
+ * Mono.Debugging.Backend/IObjectValueSource.cs: Added
+ evaluation options to raw value methods.
+
+ * Mono.Debugging.Client/ObjectValue.cs: Connect children
+ directly added to the object value. Propagate eval options
+ to raw value objects.
+
+2010-05-11 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/AsyncOperationManager.cs: Fixed
+ deadlock while shuting down.
+
+2010-05-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs: Added HasDebugInfo
+ argument. When set to true, the stack frame won't try to get
+ any information from the underlaying frame.
+
+2010-05-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Fix
+ support for variable definition. Implement support for
+ pre/post increment/decrement.
+
+2010-05-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Backend/IObjectValueSource.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/NullValueReference.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/LiteralValueReference.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs:
+ * Mono.Debugging.Evaluation/NamespaceValueReference.cs: Added
+ an EvaluationOptions argument to all methods in
+ IObjectValueSource. With this change options are not cached
+ anymore in ValueReference objects. This fixes bug #602894
+ and allows MD to change the evaluation options in the middle
+ of a debugging session.
+
+2010-05-06 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/BaseBacktrace.cs: Use async
+ evaluation when getting the This and Execption values.
+
+2010-04-23 Carlo Kok <ck at remobjects.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Client/IExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ Allow for custom expression evaluators.
+
+
+2010-04-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/RawValue.cs:
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/RemoteRawValue.cs:
+ * Mono.Debugging.Backend/IObjectValueSource.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Add
+ support for getting raw values of members and variables.
+
+2010-04-13 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Fix bug
+ #595270 - Flags enums in debugger show the zero value.
+
+2010-03-23 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs: Child
+ selector fixes. Fixes bug #588307 - Cannot pin an element of
+ multidimensional array.
+
+2010-03-15 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/AsyncOperationManager.cs: Use
+ corrent constant for infinite waits.
+
+2010-03-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/TypeValueReference.cs: Fixed type
+ name formatting issue.
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Fixed
+ parsing of generic type names.
+
+2010-03-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/TypeValueReference.cs: Set the
+ correct type name for the type reference.
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Added hack
+ which allows parsing single generic type names (that is,
+ when the expression is a type name).
+
+2010-03-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Add a
+ better default implementation for ForceLoadType.
+
+2010-03-01 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Fix null ref.
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Type data
+ should not be static.
+
+ * Mono.Debugging.Evaluation/NRefactoryResolverVisitor.cs:
+ Improved resolution of generic types.
+
+2010-03-01 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Add
+ support for indexer with more than one parameter.
+
+2010-02-26 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/EvaluationOptions.cs: Added clone
+ method.
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Fix crash
+ when parsing enums.
+
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Reset
+ the child selector for values which are only visual group of
+ members.
+
+2010-02-24 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs: Add null check.
+
+2010-02-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Backend/IBacktrace.cs:
+ * Mono.Debugging.Client/TargetEventArgs.cs:
+ * Mono.Debugging.Evaluation/BaseBacktrace.cs:
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Added
+ method for getting the current exception when a catchpoint
+ is hit or an exception unhandled.
+
+2010-02-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs: Fix win32 build.
+
+2010-02-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Backend/IBacktrace.cs:
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Evaluation/BaseBacktrace.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Backend/IObjectValueSource.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Add
+ support for evaluating expressions. Allow specifying
+ evaluation options when setting a value. Added option for
+ displaying integers using hex format. Added wait handle for
+ waiting for async evaluation completion on ObjectValue.
+
+2010-02-04 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Added delegate
+ which is called when a tracepoint is hit.
+
+ * Mono.Debugging.Client/ObjectValue.cs: New ChildSelector
+ property.
+
+ * Mono.Debugging.Evaluation/NRefactoryResolverVisitor.cs: Fix
+ nullref.
+
+2010-02-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Added the
+ SetBreakEventStatus method, which can be used by subclasses
+ to set a breakpoint as invalid. Added some docs.
+
+2010-02-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/NRefactoryResolverVisitor.cs:
+ Properly resolve type references.
+
+2010-02-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Fix type
+ arg count code.
+
+2010-01-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/NRefactoryResolverVisitor.cs: Add
+ suport for an external type resolver. The first time an
+ expression is evaluated in a context, the debugger tries to
+ resolve the type references using the external resolver, and
+ will use the resolved expression to do the evaluation.
+
+ * Mono.Debugging.Client/SourceLocation.cs: Add column field.
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Added
+ method for forcing the loading of a type.
+
+2010-01-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Generate
+ NotSupported values when getting such exception.
+
+2010-01-20 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Makefile.am:
+ * mono.debugging.snk:
+ * Mono.Debugging.csproj: Sign and fix deps.
+
+2010-01-20 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Fix
+ potential string parsing issue. Fixes bug #571232 -
+ System.FormatException: Input string was not in a correct
+ format.
+
+2009-12-18 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Workaround for
+ possible deadlock.
+
+2009-12-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs: Report the
+ correct error for unsupported expressions. Fixes bug
+ #564452.
+
+2009-12-15 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs: Forgot assignment in
+ update method.
+
+ * Mono.Debugging.Backend/IObjectValueSource.cs:
+ * Mono.Debugging.Evaluation/LiteralValueReference.cs:
+ LiteralExp has been replaced by EvaluationResult.
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Improve
+ formatting of arrays, enums and types.
+
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs: Fix
+ formatting of boolean values. LiteralExp has been replaced
+ by EvaluationResult.
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Fix some
+ evaluation issues.
+
+2009-12-11 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Backend/IObjectValueSource.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/LiteralValueReference.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Added a
+ new EvaluationResult class to be used to provide expression
+ evaluation values. This result can contain a value and a
+ display value. The display value is shown in the value cell
+ of the watch window, the original value is used when
+ editing.
+
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: When
+ setting a value, try converting it to the target type.
+
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs: Add
+ support for character escapes.
+
+2009-12-09 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: When a
+ RootHidden member is found, hide everything but that member.
+
+2009-12-09 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerStartInfo.cs: Added properties
+ to support the external console option.
+
+2009-12-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Honor
+ DebuggerBrowsableState in private and static member groups.
+
+2009-12-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Evaluation/IObjectSource.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Created
+ the IObjectSource interface, which can be used to keep track
+ of the origin of an object. ValueReference objects now have
+ a reference to the IObjectSource that generated them. This
+ source can be used to update back struct instances.
+
+2009-12-02 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Evaluation/TimedEvaluator.cs: Name threads to
+ make debugging easier.
+
+2009-12-02 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: If there's an
+ exceptions when running, attaching, or finishing, exit the
+ session, instead of just stopping it.
+
+2009-12-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: By default,
+ don't group private members for user classes.
+
+2009-12-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/ObjectValueFlags.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/BaseTypeViewSource.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Added
+ new evaluation options. Grouping non-public and static
+ members is now optional. Added option for grouping members
+ from base classes in a base group. When disabled, show the
+ base class next to the member name when there are several
+ members with the same name.
+
+2009-12-01 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Added
+ several missing type and null checks.
+
+2009-11-30 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Prettify
+ type names.
+
+2009-11-25 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs: A frame should be
+ marked external when file name IS empty.
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Improve
+ error handling.
+
+2009-11-24 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs: Add property for
+ flagging frame as external code.
+
+2009-11-20 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSessionOptions.cs: Add setting
+ for user-code-only debugging.
+
+2009-11-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Fix calls
+ to GetTypeDisplayData.
+
+2009-11-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/TimedEvaluator.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs:
+ Properly dispose resources.
+
+2009-11-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Client/ObjectValueFlags.cs:
+ * Mono.Debugging.Evaluation/BaseBacktrace.cs:
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/TimedEvaluator.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs:
+ Improved async evaluation. If an evaluation is in process,
+ don't even try to create an evaluation context, just queue
+ the request. Added more evaluation options. Added default
+ implementations for some methods (in ObjectValueAdaptor) and
+ classes (BaseBacktrace), factorized from the soft debugger.
+
+2009-11-18 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs:
+ * Mono.Debugging.Client/StackFrame.cs: Fix some serialization
+ issues.
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Improve
+ error message.
+
+2009-11-18 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs: Add support for
+ refreshing object values.
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Backend/IBacktrace.cs:
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Client/ObjectValueFlags.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Client/EvaluationOptions.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Backend/IObjectValueSource.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Client/DebuggerSessionOptions.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/AsyncOperationManager.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs: Add
+ support for refreshing object values.
+
+2009-11-17 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Client/DebuggerSessionOptions.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs:
+ * Mono.Debugging.Evaluation/AsyncOperationManager.cs:
+ * Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs: Add an
+ Options argument to the methods that launch the debugger. By
+ default, run debugger operations in a background thread, to
+ avoid locking the main thread. Improve expression evaluation
+ timeout handling. If an evaluation can't be aborted, notify
+ the user and wait until done or stopped.
+
+2009-11-11 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs: Fix list
+ ArgumentOutOfRangeException when soft debugger is stopped in
+ unmanaged code. Not completely sure this is the right fix.
+
+2009-10-29 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.csproj: Flush.
+
+2009-10-18 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Fix Pocess/Process
+ spelling. Don't lock in IsRunning or MD can deadlock.
+
+2009-10-05 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ThreadInfo.cs:
+ * Mono.Debugging.Client/ProcessInfo.cs:
+ * Mono.Debugging.Client/DebuggerSession.cs: Use long for
+ thread and process id.
+
+2009-10-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Don't show
+ the static/non-public groups if they don't contain elements.
+ Fixes bug #543782 - Debug tooltip always shows Static
+ members group.
+
+2009-10-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs:
+ * Mono.Debugging.Evaluation/NamespaceValueReference.cs:
+ Alphabetically sort members of types. Fixes bug #543780 -
+ Debug tooltip shows members in random order.
+
+2009-10-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs: Allow setting the type
+ name.
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Added null
+ check.
+
+2009-09-29 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation\ObjectValueAdaptor.cs: Add missing
+ length check.
+
+2009-09-25 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Some minor
+ fixes.
+
+2009-09-23 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakpointStore.cs: Clear(): Properly
+ duplicate breakpoint list.
+
+2009-09-23 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs: Added some debug code.
+
+ * Mono.Debugging.Evaluation/ICollectionAdaptor.cs:
+ CreateElementValue is not used anymore.
+
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs: Make
+ serializable some exceptions.
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Added some
+ preventive error checks.
+
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs: When
+ generating an array item, use NameDisplayString when defined
+ for the type. Fixed upperBound value for multidimensional
+ arrays.
+
+2009-09-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Added
+ missing null check.
+
+2009-09-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Add
+ support for examining nested types.
+
+2009-09-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Improve error
+ handling. Exceptions can now be intercept using a delegate.
+
+2009-09-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Try to
+ resolve type names using the imported namespaces.
+
+2009-09-17 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakEvent.cs:
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Client/BreakpointStore.cs: Added support for
+ disabling changes in the breakpoint store. Some debuggers
+ may not support changing breakpoints while the debugger is
+ running.
+
+2009-09-17 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Don't crash if a
+ breakpoint can't be removed.
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/DebuggerException.cs: Added exception
+ to be used to report debugger errors to the user.
+
+2009-09-14 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Ignore '?'
+ prefix. We don't use it, but VS does.
+
+2009-09-14 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/EvaluationContext.cs: Added flag
+ for enabling/disabling execution of debugging target code
+ while inspecting expressions.
+
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Fix cast
+ expression evaluation.
+
+2009-08-28 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs: Allow
+ calling a method of the class of the current
+ debugging-scope. Fixes bug #525258.
+
+2009-07-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Evaluation/Backtrace.cs: Remove unused file.
+
+2009-07-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/Backtrace.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/ICollectionAdaptor.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/NullValueReference.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/ArrayValueReference.cs:
+ * Mono.Debugging.Evaluation/LiteralValueReference.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs:
+ * Mono.Debugging.Evaluation/UserVariableReference.cs:
+ * Mono.Debugging.Evaluation/NamespaceValueReference.cs: Get
+ rid of generic classes because they are causing a lot of
+ trouble in mono.
+
+2009-06-23 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs: Workaround
+ to a bug in mono 2.0. That mono version fails to compile an
+ anonymous method in GetExpressionValuesAsync.
+
+2009-06-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation\TypeValueReference.cs: Only show
+ static members as children of types.
+
+ * Mono.Debugging.Evaluation\NRefactoryEvaluator.cs: Don't
+ crash if a method evaluation returns 'void'.
+
+ * Mono.Debugging.Evaluation\LiteralValueReference.cs: Properly
+ support literal expressions.
+
+2009-06-15 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj: Added missing reference.
+
+2009-06-15 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Evaluation\NRefactoryEvaluator.cs: Small
+ optimization.
+
+2009-06-12 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Evaluation:
+ * Mono.Debugging.Evaluation/Backtrace.cs:
+ * Mono.Debugging.Evaluation/RawViewSource.cs:
+ * Mono.Debugging.Evaluation/ValueReference.cs:
+ * Mono.Debugging.Evaluation/TimedEvaluator.cs:
+ * Mono.Debugging.Evaluation/TimeOutException.cs:
+ * Mono.Debugging.Evaluation/ArrayElementGroup.cs:
+ * Mono.Debugging.Evaluation/EvaluationContext.cs:
+ * Mono.Debugging.Evaluation/RemoteFrameObject.cs:
+ * Mono.Debugging.Evaluation/TypeValueReference.cs:
+ * Mono.Debugging.Evaluation/NullValueReference.cs:
+ * Mono.Debugging.Evaluation/ICollectionAdaptor.cs:
+ * Mono.Debugging.Evaluation/ObjectValueAdaptor.cs:
+ * Mono.Debugging.Evaluation/NRefactoryEvaluator.cs:
+ * Mono.Debugging.Evaluation/ArrayValueReference.cs:
+ * Mono.Debugging.Evaluation/ExpressionEvaluator.cs:
+ * Mono.Debugging.Evaluation/LiteralValueReference.cs:
+ * Mono.Debugging.Evaluation/AsyncOperationManager.cs:
+ * Mono.Debugging.Evaluation/FilteredMembersSource.cs:
+ * Mono.Debugging.Evaluation/UserVariableReference.cs:
+ * Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs:
+ * Mono.Debugging.Evaluation/NamespaceValueReference.cs: Added
+ an expression evaluator factorized from the Mdb and Win32
+ debugger addins.
+
+2009-06-04 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Backend/IDebuggerSessionFrontend.cs: Added
+ NotifySourceFile(Un)Loaded to IDebuggerSessionFrontend.
+
+2009-05-25 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client\BreakpointStore.cs: Use case
+ insensitive compare for files on windows.
+
+ * Mono.Debugging.Client\DebuggerSession.cs: Fix crash when
+ updating breakpoints.
+
+2009-05-13 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client\DebuggerSession.cs: Protect access to
+ the breakpoints collection. Added method for notifying
+ loading/unloading of files.
+
+2009-04-27 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.csproj:
+ * Mono.Debugging.Client/IDebuggerEngine.cs: Moved
+ IDebuggerEngine to MD.Debugger.
+
+2009-03-04 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/IDebuggerEngine.cs: Removed unused
+ CanDebugPlatform and rename CanDebugFile to CanDebugCommand.
+
+2009-02-06 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.mdp:
+ * Mono.Debugging.csproj: Migrated to MSBuild file format.
+
+2009-01-26 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.mdp: Flush project format changes.
+
+2009-01-14 Michael Hutchinson <mhutchinson at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs: Remove Console.WriteLine noise.
+
+2008-12-19 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Makefile.am:
+ * Mono.Debugging.mdp:
+ * Mono.Debugging.Client/StackFrame.cs:
+ * Mono.Debugging.Backend/IBacktrace.cs:
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Backend/UpdateCallback.cs:
+ * Mono.Debugging.Client/ObjectValueFlags.cs:
+ * Mono.Debugging.Backend/IObjectValueUpdater.cs:
+ * Mono.Debugging.Backend/IObjectValueUpdateCallback.cs: Added support
+ for asynchronus evaluation of expressions, with support for timeouts.
+
+2008-12-04 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs:
+ * Mono.Debugging.Client/IDebuggerEngine.cs:
+ * Mono.Debugging.Client/DebuggerFeatures.cs: Improved support for
+ checking debugger features.
+
+2008-12-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs:
+ * Mono.Debugging.Client/ObjectValueFlags.cs: Added new kind of value:
+ not supported.
+
+ * Makefile.am: Fix to better support parallel building.
+
+2008-10-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ThreadInfo.cs: Added null check.
+
+2008-09-12 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.mdp: Updated.
+
+2008-09-03 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerFeatures.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/TargetEventArgs.cs, Mono.Debugging.mdp,
+ Makefile.am: When firing the TargetEvent for an Exception, provide
+ the exception object. Added property for getting the debugger
+ capabilities.
+
+2008-08-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.addin.xml, Mono.Debugging.mdp,
+ Mono.Debugging.Backend/DebuggerExtensionNode.cs, Makefile.am:
+ Remove Mono.Addins dependency.
+
+2008-08-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakpointStore.cs: Fire the change event when
+ a breakpoint is modified.
+ * Mono.Debugging.Client/DebuggerSession.cs: Made GetBreakpointHandle
+ protected so it can be used by add-ins.
+
+2008-08-06 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakpointStore.cs,
+ Mono.Debugging.Client/BreakEvent.cs,
+ Mono.Debugging.Client/DebuggerSession.cs, Mono.Debugging.mdp: Add
+ support for live updating of breakpoint's hit count.
+
+2008-08-05 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ThreadInfo.cs,
+ Mono.Debugging.Client/DebuggerSession.cs: Add location field to
+ ThreadInfo. Reset the cached process list when receiving a target
+ event.
+
+2008-07-25 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs,
+ Mono.Debugging.Backend/IBacktrace.cs: Added api for getting all
+ locals of a stack frame.
+
+2008-07-22 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakEvent.cs,
+ Mono.Debugging.Client/Catchpoint.cs,
+ Mono.Debugging.Client/Breakpoint.cs: Added copying methods. Added
+ property which allows stopping on a breakpoint after the given hit
+ count.
+
+2008-07-21 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValue.cs: Added some missing null checks.
+
+2008-07-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakpointStore.cs,
+ Mono.Debugging.Client/BreakEvent.cs,
+ Mono.Debugging.Client/Catchpoint.cs,
+ Mono.Debugging.Client/Breakpoint.cs, Mono.Debugging.mdp,
+ Makefile.am: Add serialization support to BreakpointStore.
+
+2008-07-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/CatchpointEventArgs.cs,
+ Mono.Debugging.Client/BreakpointStore.cs,
+ Mono.Debugging.Client/BreakEvent.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/TargetEventType.cs,
+ Mono.Debugging.Client/Catchpoint.cs,
+ Mono.Debugging.Client/Breakpoint.cs,
+ Mono.Debugging.Client/BreakEventArgs.cs, Mono.Debugging.mdp,
+ Makefile.am: Implemented support for catchpoints.
+
+2008-07-11 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakpointStore.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/Breakpoint.cs,
+ Mono.Debugging.Backend/IDebuggerSessionFrontend.cs: Added api to
+ support custom breakpoint hit actions.
+
+2008-07-09 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ThreadInfo.cs,
+ Mono.Debugging.Client/DebuggerSession.cs: Provide the process id
+ when setting the active thread.
+
+2008-07-09 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValueFlags.cs: Added Type and Namespace.
+ * Mono.Debugging.Client/ObjectValue.cs: Properly set the name when
+ creating an error object.
+
+2008-07-09 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/StackFrame.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/CompletionData.cs, Mono.Debugging.mdp,
+ Mono.Debugging.Backend/IBacktrace.cs, Makefile.am: Added support
+ for code completion.
+
+2008-07-07 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectValueFlags.cs,
+ Mono.Debugging.Client/StackFrame.cs,
+ Mono.Debugging.Client/ObjectValue.cs,
+ Mono.Debugging.Client/ObjectValueKind.cs, Mono.Debugging.mdp,
+ Mono.Debugging.Backend/IBacktrace.cs, Makefile.am: Added flags enum
+ to ObjectValue which give information about the origin of the
+ value.
+
+2008-07-02 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/ObjectPath.cs: Implemented ToString.
+ * Mono.Debugging.Client/AssemblyLine.cs,
+ Mono.Debugging.Client/DebuggerSession.cs: Added support for
+ disassembling files.
+ * Mono.Debugging.Client/ObjectValue.cs,
+ Mono.Debugging.Client/ObjectValueKind.cs,
+ Mono.Debugging.Backend/IObjectValueSource.cs: Implemented support
+ for changing the value of an ObjectValue. Improved error reporting.
+
+2008-07-01 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/BreakpointStore.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/Breakpoint.cs: Add support for "invalid"
+ breakpoints (breakpoints placed in locations where there is no
+ source code).
+
+2008-06-26 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs: Get only the first stack frame at
+ the begining.
+ * Mono.Debugging.Client/ThreadInfo.cs,
+ Mono.Debugging.Client/DebuggerSession.cs: Allow changing the active
+ thread.
+
+2008-06-20 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs: Improved thread safety.
+ Implemented Detach.
+
+2008-06-20 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs,
+ Mono.Debugging.Client/StackFrame.cs,
+ Mono.Debugging.Client/IDebuggerEngine.cs,
+ Mono.Debugging.Client/ObjectPath.cs,
+ Mono.Debugging.Client/ThreadInfo.cs,
+ Mono.Debugging.Client/AssemblyLine.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/ProcessInfo.cs,
+ Mono.Debugging.Client/ObjectValue.cs,
+ Mono.Debugging.Client/TargetEventArgs.cs,
+ Mono.Debugging.Client/ObjectValueKind.cs,
+ Mono.Debugging.Client/DebuggerEngine.cs, Mono.Debugging.mdp,
+ Mono.Debugging.Backend/DissassemblyBuffer.cs,
+ Mono.Debugging.Backend/IDebuggerSessionFrontend.cs,
+ Mono.Debugging.Backend/IBacktrace.cs,
+ Mono.Debugging.Backend/IDebuggerSessionFactory.cs, Makefile.am:
+ Added support for attaching processes and disassembling. Improved
+ API.
+
+2008-06-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs: Get 1 initial frame when creating
+ the backtrace.
+ * Mono.Debugging.Client/DebuggerSession.cs: Some methods don't need to
+ be virtual.
+ * Mono.Debugging.Client/StackFrame.cs: Improved frame description.
+
+2008-06-16 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.mdp: Fixed Mono.Addins reference.
+
+2008-05-27 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/DebuggerSession.cs, Mono.Debugging.mdp,
+ Mono.Debugging.Backend/IDebuggerSessionBackend.cs, Makefile.am:
+ Removed IDebuggerSessionBackend interface. Methods must now be
+ implemented using DebuggerSession overridables.
+
+2008-05-15 Lluis Sanchez Gual <lluis at novell.com>
+
+ * Mono.Debugging.Client/Backtrace.cs,
+ Mono.Debugging.Client/StackFrame.cs,
+ Mono.Debugging.Client/ObjectPath.cs,
+ Mono.Debugging.Client/DebuggerSession.cs,
+ Mono.Debugging.Client/ObjectValue.cs,
+ Mono.Debugging.Client/ObjectValueKind.cs, Mono.Debugging.mdp,
+ Mono.Debugging.Backend/IObjectValueSource.cs,
+ Mono.Debugging.Backend/IBacktrace.cs, Makefile.am: Added api for
+ querying variable and field values. Some improvements in
+ ObjectValue. Added new ObjectPath class.
+
+2008-05-06 Lluis Sanchez <lluis at novell.com>
+
+ * Imported library
+
diff --git a/Mono.Debugging/Makefile.am b/Mono.Debugging/Makefile.am
new file mode 100644
index 0000000..c9cc874
--- /dev/null
+++ b/Mono.Debugging/Makefile.am
@@ -0,0 +1 @@
+include $(top_srcdir)/xbuild.include
diff --git a/Mono.Debugging/Mono.Debugging.Backend/DissassemblyBuffer.cs b/Mono.Debugging/Mono.Debugging.Backend/DissassemblyBuffer.cs
new file mode 100644
index 0000000..13801ec
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/DissassemblyBuffer.cs
@@ -0,0 +1,154 @@
+// DissassemblyBuffer.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public abstract class DissassemblyBuffer
+ {
+ List<AssemblyLine> lines = new List<AssemblyLine> ();
+ int baseIndex = 0;
+ long baseAddress;
+
+ const int AddrPerLine = 4;
+ const int ExtraDownLines = 5;
+ const int ExtraUpLines = 20;
+
+ public DissassemblyBuffer (long baseAddress)
+ {
+ this.baseAddress = baseAddress;
+ }
+
+ public AssemblyLine[] GetLines (int firstIndex, int lastIndex)
+ {
+ //Console.WriteLine ("pp GET LINES: " + firstIndex + " " + lastIndex + " " + baseIndex);
+
+ if (lastIndex >= 0)
+ FillDown (lastIndex);
+ if (firstIndex < 0)
+ FillUp (firstIndex);
+
+ AssemblyLine[] array = new AssemblyLine [lastIndex - firstIndex + 1];
+ lines.CopyTo (baseIndex + firstIndex, array, 0, lastIndex - firstIndex + 1);
+ return array;
+ }
+
+ public void FillUp (int targetLine)
+ {
+ if (baseIndex + targetLine >= 0)
+ return;
+
+ // Lines we are missing
+ int linesReq = -(baseIndex + targetLine);
+
+ //Console.WriteLine ("pp FILLUP: " + linesReq);
+
+ // Last known valid address
+ long lastAddr = lines.Count > 0 ? lines [0].Address : baseAddress;
+
+ // Addresses we are going to query to get the required lines
+ long addr = lastAddr - (linesReq + ExtraUpLines) * AddrPerLine; // 4 is just a guess
+
+ int lastCount = 0;
+ bool limitFound = false;
+ AssemblyLine[] alines;
+ do {
+ alines = GetLines (addr, lastAddr);
+ if (alines.Length <= lastCount) {
+ limitFound = true;
+ break;
+ }
+ addr -= (linesReq + ExtraUpLines - alines.Length) * AddrPerLine;
+ lastCount = alines.Length;
+ }
+ while (alines.Length < linesReq + ExtraUpLines);
+
+ int max = limitFound ? alines.Length : alines.Length - ExtraUpLines;
+ if (max < 0) max = 0;
+
+ // Fill the lines
+ for (int n=0; n < max; n++)
+ lines.Insert (n, alines [n + (alines.Length - max)]);
+
+ long firstAddr = lines [0].Address;
+ for (int n=0; n < (linesReq - max); n++) {
+ AssemblyLine line = new AssemblyLine (--firstAddr, "");
+ lines.Insert (0, line);
+ max++;
+ }
+ baseIndex += max;
+ }
+
+ public void FillDown (int targetLine)
+ {
+ if (baseIndex + targetLine < lines.Count)
+ return;
+
+ // Lines we are missing
+ int linesReq = (baseIndex + targetLine) - lines.Count + 1;
+
+ //Console.WriteLine ("pp FILLDOWN: " + linesReq);
+
+ // Last known valid address
+ long lastAddr = lines.Count > 0 ? lines [lines.Count - 1].Address : baseAddress;
+
+ // Addresses we are going to query to get the required lines
+ long addr = lastAddr + (linesReq + ExtraDownLines) * AddrPerLine; // 4 is just a guess
+
+ int lastCount = 0;
+ bool limitFound = false;
+ AssemblyLine[] alines;
+ do {
+ alines = GetLines (lastAddr, addr);
+ if (alines.Length <= lastCount) {
+ limitFound = true;
+ break;
+ }
+ addr += (linesReq + ExtraDownLines - alines.Length) * AddrPerLine;
+ lastCount = alines.Length;
+ }
+ while (alines.Length < linesReq + ExtraDownLines);
+
+ int max = limitFound ? alines.Length : alines.Length - ExtraDownLines;
+
+ // Fill the lines
+ for (int n=0; n < max; n++)
+ lines.Add (alines [n]);
+
+ lastAddr = lines [lines.Count - 1].Address;
+ for (int n=0; n < (linesReq - max); n++) {
+ AssemblyLine line = new AssemblyLine (++lastAddr, "");
+ lines.Add (line);
+ }
+ }
+
+ public abstract AssemblyLine[] GetLines (long startAddr, long endAddr);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/EvaluationResult.cs b/Mono.Debugging/Mono.Debugging.Backend/EvaluationResult.cs
new file mode 100644
index 0000000..4ec7746
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/EvaluationResult.cs
@@ -0,0 +1,55 @@
+//
+// EvaluationResult.cs
+//
+// Author:
+// Lluis Sanchez <lluis at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+
+ [Serializable]
+ public class EvaluationResult
+ {
+ public EvaluationResult (string value)
+ {
+ Value = value;
+ }
+
+ public EvaluationResult (string value, string displayValue)
+ {
+ Value = value;
+ DisplayValue = displayValue;
+ }
+
+ public string Value { get; private set; }
+ public string DisplayValue { get; private set; }
+
+ public override string ToString ()
+ {
+ return Value;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IBacktrace.cs b/Mono.Debugging/Mono.Debugging.Backend/IBacktrace.cs
new file mode 100644
index 0000000..7ace999
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IBacktrace.cs
@@ -0,0 +1,20 @@
+
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public interface IBacktrace: IDebuggerBackendObject
+ {
+ int FrameCount { get; }
+ StackFrame[] GetStackFrames (int firstIndex, int lastIndex);
+ ObjectValue[] GetLocalVariables (int frameIndex, EvaluationOptions options);
+ ObjectValue[] GetParameters (int frameIndex, EvaluationOptions options);
+ ObjectValue GetThisReference (int frameIndex, EvaluationOptions options);
+ ExceptionInfo GetException (int frameIndex, EvaluationOptions options);
+ ObjectValue[] GetAllLocals (int frameIndex, EvaluationOptions options);
+ ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, EvaluationOptions options);
+ CompletionData GetExpressionCompletionData (int frameIndex, string exp);
+ AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count);
+ ValidationResult ValidateExpression (int frameIndex, string expression, EvaluationOptions options);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IDebuggerBackendObject.cs b/Mono.Debugging/Mono.Debugging.Backend/IDebuggerBackendObject.cs
new file mode 100644
index 0000000..2fcfc84
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IDebuggerBackendObject.cs
@@ -0,0 +1,34 @@
+//
+// IDebuggerBackendObject.cs
+//
+// Author:
+// Lluis Sanchez <lluis at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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 Mono.Debugging.Backend
+{
+ public interface IDebuggerBackendObject
+ {
+ }
+}
+
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IDebuggerSessionFrontend.cs b/Mono.Debugging/Mono.Debugging.Backend/IDebuggerSessionFrontend.cs
new file mode 100644
index 0000000..b340b35
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IDebuggerSessionFrontend.cs
@@ -0,0 +1,44 @@
+// IDebuggerSession.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public interface IDebuggerSessionFrontend
+ {
+ void NotifyTargetEvent (TargetEventArgs args);
+ void NotifyTargetOutput (bool isStderr, string line);
+ void NotifyDebuggerOutput (bool isStderr, string line);
+ void BindSourceFileBreakpoints (string fullFilePath);
+ void UnbindSourceFileBreakpoints (string fullFilePath);
+
+ // To be called when the process is ready to run.
+ void NotifyStarted ();
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IObjectValueSource.cs b/Mono.Debugging/Mono.Debugging.Backend/IObjectValueSource.cs
new file mode 100644
index 0000000..c9018e5
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IObjectValueSource.cs
@@ -0,0 +1,43 @@
+// IObjectValueSource.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public interface IObjectValueSource: IDebuggerBackendObject
+ {
+ ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options);
+ EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options);
+ ObjectValue GetValue (ObjectPath path, EvaluationOptions options);
+
+ object GetRawValue (ObjectPath path, EvaluationOptions options);
+ void SetRawValue (ObjectPath path, object value, EvaluationOptions options);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IObjectValueUpdateCallback.cs b/Mono.Debugging/Mono.Debugging.Backend/IObjectValueUpdateCallback.cs
new file mode 100644
index 0000000..0b480e6
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IObjectValueUpdateCallback.cs
@@ -0,0 +1,37 @@
+// IObjectValueUpdateCallback.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ internal interface IObjectValueUpdateCallback
+ {
+ void UpdateValue (ObjectValue newValue);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IObjectValueUpdater.cs b/Mono.Debugging/Mono.Debugging.Backend/IObjectValueUpdater.cs
new file mode 100644
index 0000000..5bc67dd
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IObjectValueUpdater.cs
@@ -0,0 +1,37 @@
+// IObjectValueUpdater.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public interface IObjectValueUpdater: IDebuggerBackendObject
+ {
+ void RegisterUpdateCallbacks (UpdateCallback[] callbacks);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IRawValue.cs b/Mono.Debugging/Mono.Debugging.Backend/IRawValue.cs
new file mode 100644
index 0000000..7391e97
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IRawValue.cs
@@ -0,0 +1,40 @@
+//
+// IRawValue.cs
+//
+// Author:
+// Lluis Sanchez <lluis at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+
+ public interface IRawValue: IDebuggerBackendObject
+ {
+ object CallMethod (string name, object[] parameters, EvaluationOptions options);
+ object GetMemberValue (string name, EvaluationOptions options);
+ void SetMemberValue (string name, object value, EvaluationOptions options);
+ }
+
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IRawValueArray.cs b/Mono.Debugging/Mono.Debugging.Backend/IRawValueArray.cs
new file mode 100644
index 0000000..d963e74
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IRawValueArray.cs
@@ -0,0 +1,40 @@
+//
+// IRawValueArray.cs
+//
+// Author:
+// Lluis Sanchez <lluis at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public interface IRawValueArray: IDebuggerBackendObject
+ {
+ object GetValue (int[] index);
+ Array GetValues (int[] index, int count);
+ void SetValue (int[] index, object value);
+ int[] Dimensions { get; }
+ Array ToArray ();
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/IRawValueString.cs b/Mono.Debugging/Mono.Debugging.Backend/IRawValueString.cs
new file mode 100644
index 0000000..f1b77fe
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/IRawValueString.cs
@@ -0,0 +1,39 @@
+//
+// IRawValueString.cs
+//
+// Author:
+// Lluis Sanchez <lluis at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ public interface IRawValueString: IDebuggerBackendObject
+ {
+ string Substring (int index, int length);
+ string Value { get; }
+ int Length { get; }
+ }
+
+}
diff --git a/Mono.Debugging/Mono.Debugging.Backend/UpdateCallback.cs b/Mono.Debugging/Mono.Debugging.Backend/UpdateCallback.cs
new file mode 100644
index 0000000..bdadddf
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Backend/UpdateCallback.cs
@@ -0,0 +1,68 @@
+// UpdateCallback.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Backend
+{
+ [Serializable]
+ public class UpdateCallback
+ {
+ ObjectPath path;
+ IObjectValueUpdateCallback callback;
+
+ internal UpdateCallback ()
+ {
+ }
+
+ internal UpdateCallback (IObjectValueUpdateCallback callback, ObjectPath path)
+ {
+ this.callback = callback;
+ this.path = path;
+ }
+
+ public ObjectPath Path {
+ get { return path; }
+ }
+
+ internal IObjectValueUpdateCallback Callback {
+ get {
+ return callback;
+ }
+ }
+
+ public void UpdateValue (ObjectValue newValue)
+ {
+ try {
+ callback.UpdateValue (newValue);
+ } catch {
+ // Ignore
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/AssemblyLine.cs b/Mono.Debugging/Mono.Debugging.Client/AssemblyLine.cs
new file mode 100644
index 0000000..830dc0b
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/AssemblyLine.cs
@@ -0,0 +1,90 @@
+// AssemblyLine.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ [Serializable]
+ public class AssemblyLine
+ {
+ long address;
+ string code;
+ int sourceLine;
+ string addressSpace;
+
+ public string Code {
+ get {
+ return code;
+ }
+ }
+
+ public long Address {
+ get {
+ return address;
+ }
+ }
+
+ public string AddressSpace {
+ get {
+ return addressSpace;
+ }
+ }
+
+ public int SourceLine {
+ get {
+ return sourceLine;
+ }
+ }
+
+ public bool IsOutOfRange {
+ get { return address == -1 && code == null; }
+ }
+
+ public static readonly AssemblyLine OutOfRange = new AssemblyLine (-1, null, null);
+
+ public AssemblyLine (long address, string code): this (address, "", code, -1)
+ {
+ }
+
+ public AssemblyLine (long address, string code, int sourceLine): this (address, "", code, sourceLine)
+ {
+ }
+
+ public AssemblyLine (long address, string addressSpace, string code): this (address, addressSpace, code, -1)
+ {
+ }
+
+ public AssemblyLine (long address, string addressSpace, string code, int sourceLine)
+ {
+ this.address = address;
+ this.code = code;
+ this.sourceLine = sourceLine;
+ this.addressSpace = addressSpace;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/Backtrace.cs b/Mono.Debugging/Mono.Debugging.Client/Backtrace.cs
new file mode 100644
index 0000000..72ebf82
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/Backtrace.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class Backtrace
+ {
+ IBacktrace serverBacktrace;
+ int count;
+
+ [NonSerialized]
+ DebuggerSession session;
+
+ List<StackFrame> frames;
+
+ public Backtrace (IBacktrace serverBacktrace)
+ {
+ this.serverBacktrace = serverBacktrace;
+
+ count = serverBacktrace.FrameCount;
+
+ // Get some initial frames
+ if (count > 0)
+ GetFrame (0);
+ }
+
+ internal void Attach (DebuggerSession session)
+ {
+ this.session = session;
+ serverBacktrace = session.WrapDebuggerObject (serverBacktrace);
+ if (frames != null) {
+ foreach (StackFrame f in frames) {
+ f.Attach (session);
+ f.SourceBacktrace = serverBacktrace;
+ }
+ }
+ }
+
+ public int FrameCount
+ {
+ get { return count; }
+ }
+
+ public StackFrame GetFrame (int n)
+ {
+ if (frames == null)
+ frames = new List<StackFrame>();
+
+ if (n >= frames.Count) {
+ StackFrame[] newSet = serverBacktrace.GetStackFrames(frames.Count, n + 20);
+ foreach (StackFrame sf in newSet) {
+ sf.SourceBacktrace = serverBacktrace;
+ sf.Index = frames.Count;
+ frames.Add (sf);
+ sf.Attach (session);
+ }
+ }
+
+ if (frames.Count > 0)
+ return frames[System.Math.Min (System.Math.Max (0, n), frames.Count - 1)];
+
+ return null;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakEvent.cs b/Mono.Debugging/Mono.Debugging.Client/BreakEvent.cs
new file mode 100644
index 0000000..53112bb
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakEvent.cs
@@ -0,0 +1,338 @@
+// BreakEvent.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Xml;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class BreakEvent
+ {
+ [NonSerialized] BreakpointStore store;
+ [NonSerialized] bool enabled = true;
+
+ HitAction hitAction = HitAction.Break;
+ string customActionId;
+ string traceExpression;
+ int hitCount;
+ string lastTraceValue;
+
+ public BreakEvent ()
+ {
+ }
+
+ internal BreakEvent (XmlElement elem)
+ {
+ string s = elem.GetAttribute ("enabled");
+ if (s.Length > 0)
+ bool.TryParse (s, out enabled);
+ s = elem.GetAttribute ("hitAction");
+ if (s.Length > 0)
+ Enum.TryParse<HitAction> (s, out hitAction);
+ s = elem.GetAttribute ("customActionId");
+ if (s.Length > 0)
+ customActionId = s;
+ s = elem.GetAttribute ("traceExpression");
+ if (s.Length > 0)
+ traceExpression = s;
+ s = elem.GetAttribute ("hitCountMode");
+ HitCountMode mode;
+ if (s.Length > 0 && Enum.TryParse<HitCountMode> (s, out mode))
+ HitCountMode = mode;
+ s = elem.GetAttribute ("hitCount");
+ if (s.Length > 0)
+ int.TryParse (s, out hitCount);
+
+ // this is to facilitate backward compatibility
+ if (hitCount > 0 && HitCountMode == HitCountMode.None)
+ HitCountMode = HitCountMode.GreaterThan;
+ }
+
+ internal virtual XmlElement ToXml (XmlDocument doc)
+ {
+ XmlElement elem = doc.CreateElement (GetType().Name);
+ if (!enabled)
+ elem.SetAttribute ("enabled", "false");
+ if ((hitAction & HitAction.Break) == HitAction.None)
+ elem.SetAttribute ("hitAction", hitAction.ToString ());
+ if (!string.IsNullOrEmpty (customActionId))
+ elem.SetAttribute ("customActionId", customActionId);
+ if (!string.IsNullOrEmpty (traceExpression))
+ elem.SetAttribute ("traceExpression", traceExpression);
+ if (HitCountMode != HitCountMode.None)
+ elem.SetAttribute ("hitCountMode", HitCountMode.ToString ());
+ if (hitCount > 0)
+ elem.SetAttribute ("hitCount", hitCount.ToString ());
+ return elem;
+ }
+
+ internal static BreakEvent FromXml (XmlElement elem)
+ {
+ if (elem.Name == "FunctionBreakpoint")
+ return new FunctionBreakpoint (elem);
+ if (elem.Name == "Breakpoint")
+ return new Breakpoint (elem);
+ if (elem.Name == "Catchpoint")
+ return new Catchpoint (elem);
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="Mono.Debugging.Client.BreakEvent"/> is enabled.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if enabled; otherwise, <c>false</c>.
+ /// </value>
+ /// <remarks>
+ /// Changes in this property are automatically applied. There is no need to call CommitChanges().
+ /// </remarks>
+ public bool Enabled {
+ get {
+ return enabled;
+ }
+ set {
+ if (store != null && store.IsReadOnly)
+ return;
+ enabled = value;
+ if (store != null)
+ store.EnableBreakEvent (this, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets the status of the break event
+ /// </summary>
+ /// <returns>
+ /// The status of the break event for the given debug session
+ /// </returns>
+ /// <param name='session'>
+ /// Session for which to get the status of the break event
+ /// </param>
+ public BreakEventStatus GetStatus (DebuggerSession session)
+ {
+ if (store == null || session == null)
+ return BreakEventStatus.Disconnected;
+ return session.GetBreakEventStatus (this);
+ }
+
+ /// <summary>
+ /// Gets a message describing the status of the break event
+ /// </summary>
+ /// <returns>
+ /// The status message of the break event for the given debug session
+ /// </returns>
+ /// <param name='session'>
+ /// Session for which to get the status message of the break event
+ /// </param>
+ public string GetStatusMessage (DebuggerSession session)
+ {
+ if (store == null || session == null)
+ return string.Empty;
+ return session.GetBreakEventStatusMessage (this);
+ }
+
+ /// <summary>
+ /// Gets or sets the expression to be traced when the breakpoint is hit
+ /// </summary>
+ /// <remarks>
+ /// If this break event is hit and the HitAction is TraceExpression, the debugger
+ /// will evaluate and print the value of this property.
+ /// The CommitChanges() method has to be called for changes in this
+ /// property to take effect.
+ /// </remarks>
+ public string TraceExpression {
+ get {
+ return traceExpression;
+ }
+ set {
+ traceExpression = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the last value traced.
+ /// </summary>
+ /// <remarks>
+ /// This property returns the last evaluation of TraceExpression.
+ /// </remarks>
+ public string LastTraceValue {
+ get {
+ return lastTraceValue;
+ }
+ internal set {
+ lastTraceValue = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the action to be performed when the breakpoint is hit
+ /// </summary>
+ /// <remarks>
+ /// If the value is Break, the debugger will pause the execution.
+ /// If the value is PrintExpression, the debugger will evaluate and
+ /// print the value of the TraceExpression property.
+ /// If the value is CustomAction, the debugger will execute the
+ /// CustomBreakEventHitHandler callback specified in DebuggerSession,
+ /// and will provide the value of CustomActionId as argument.
+ /// The CommitChanges() method has to be called for changes in this
+ /// property to take effect.
+ /// </remarks>
+ public HitAction HitAction {
+ get {
+ return hitAction;
+ }
+ set {
+ hitAction = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the hit count mode.
+ /// </summary>
+ /// <remarks>
+ /// When the break event is hit, the HitCountMode is used to compare the CurrentHitCount
+ /// with the TargetHitCount to determine if the break event should trigger.
+ /// </remarks>
+ public HitCountMode HitCountMode {
+ get; set;
+ }
+
+ /// <summary>
+ /// Gets or sets the target hit count.
+ /// </summary>
+ /// <remarks>
+ /// When the break event is hit, if the value of HitCountMode is not None, then
+ /// the value of CurrentHitCount will be incremented. Execution will immediately
+ /// resume if it is determined that the CurrentHitCount vs TargetHitCount
+ /// comparison does not meet the requirements of HitCountMode.
+ ///
+ /// The CommitChanges() method has to be called for changes in this property
+ /// to take effect.
+ /// </remarks>
+ ///
+ /// FIXME: rename this to TargetHitCount
+ public int HitCount {
+ get {
+ return hitCount;
+ }
+ set {
+ hitCount = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the current hit count.
+ /// </summary>
+ /// <remarks>
+ /// When the break event is hit, the HitCountMode is used to compare the CurrentHitCount
+ /// with the TargetHitCount to determine if the break event should trigger.
+ /// </remarks>
+ public int CurrentHitCount {
+ get; set;
+ }
+
+ /// <summary>
+ /// Gets or sets the custom action identifier.
+ /// </summary>
+ /// <remarks>
+ /// If this break event is hit and the value of HitAction is CustomAction,
+ /// the debugger will execute the CustomBreakEventHitHandler callback
+ /// specified in DebuggerSession, and will provide the value of this property
+ /// as argument.
+ /// The CommitChanges() method has to be called for changes in this
+ /// property to take effect.
+ /// </remarks>
+ public string CustomActionId {
+ get {
+ return customActionId;
+ }
+ set {
+ customActionId = value;
+ }
+ }
+
+ internal BreakpointStore Store {
+ get {
+ return store;
+ }
+ set {
+ store = value;
+ }
+ }
+
+ /// <summary>
+ /// Commits changes done in the break event properties
+ /// </summary>
+ /// <remarks>
+ /// This method must be called after doing changes in the break event properties.
+ /// </remarks>
+ public void CommitChanges ()
+ {
+ if (store != null)
+ store.NotifyBreakEventChanged (this);
+ }
+
+ internal void NotifyUpdate ()
+ {
+ if (store != null)
+ store.NotifyBreakEventUpdated (this);
+ }
+
+ public virtual bool Reset ()
+ {
+ bool changed = CurrentHitCount != 0;
+
+ CurrentHitCount = 0;
+
+ return changed;
+ }
+
+ /// <summary>
+ /// Clone this instance.
+ /// </summary>
+ public BreakEvent Clone ()
+ {
+ return (BreakEvent) MemberwiseClone ();
+ }
+
+ /// <summary>
+ /// Makes a copy of this instance
+ /// </summary>
+ /// <param name='ev'>
+ /// A break event from which to copy the data.
+ /// </param>
+ public virtual void CopyFrom (BreakEvent ev)
+ {
+ hitAction = ev.hitAction;
+ customActionId = ev.customActionId;
+ traceExpression = ev.traceExpression;
+ hitCount = ev.hitCount;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakEventArgs.cs b/Mono.Debugging/Mono.Debugging.Client/BreakEventArgs.cs
new file mode 100644
index 0000000..63c8c15
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakEventArgs.cs
@@ -0,0 +1,45 @@
+// BreakEventArgs.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ public class BreakEventArgs: EventArgs
+ {
+ BreakEvent be;
+
+ public BreakEventArgs (BreakEvent be)
+ {
+ this.be = be;
+ }
+
+ public BreakEvent BreakEvent {
+ get { return be; }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs b/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs
new file mode 100644
index 0000000..9d29f92
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs
@@ -0,0 +1,164 @@
+//
+// BreakEventInfo.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2011 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 Mono.Debugging.Client
+{
+ /// <summary>
+ /// This class can be used to manage and get information about a breakpoint
+ /// at debug-time. It is intended to be used by DebuggerSession subclasses.
+ /// </summary>
+ public class BreakEventInfo
+ {
+ DebuggerSession session;
+ int adjustedColumn = -1;
+ int adjustedLine = -1;
+
+ /// <summary>
+ /// Gets or sets the implementation specific handle of the breakpoint
+ /// </summary>
+ public object Handle { get; set; }
+
+ /// <summary>
+ /// Break event that this instance represents
+ /// </summary>
+ public BreakEvent BreakEvent { get; internal set; }
+
+ /// <summary>
+ /// Gets the status of the break event
+ /// </summary>
+ public BreakEventStatus Status { get; private set; }
+
+ /// <summary>
+ /// Gets a description of the status
+ /// </summary>
+ public string StatusMessage { get; private set; }
+
+ internal void AttachSession (DebuggerSession s, BreakEvent ev)
+ {
+ session = s;
+ BreakEvent = ev;
+ session.NotifyBreakEventStatusChanged (BreakEvent);
+ if (adjustedLine != -1 || adjustedColumn != -1)
+ session.AdjustBreakpointLocation ((Breakpoint)BreakEvent, adjustedLine, adjustedColumn);
+ }
+
+ /// <summary>
+ /// Adjusts the location of a breakpoint
+ /// </summary>
+ /// <param name='newLine'>
+ /// New line.
+ /// </param>
+ /// <remarks>
+ /// This method can be used to temporarily change source code line of the breakpoint.
+ /// This is useful, for example, when two adjacent lines are mapped to a single
+ /// native offset. If the breakpoint is set to the first of those lines, the debugger
+ /// might end stopping in the second line, because it has the same native offset.
+ /// To avoid this confusion situation, the debugger implementation may decide to
+ /// adjust the position of the breakpoint, and move it to the second line.
+ /// This line adjustment has effect only during the debug session, and is automatically
+ /// reset when it terminates.
+ /// </remarks>
+ public void AdjustBreakpointLocation (int newLine, int newColumn)
+ {
+ if (session != null) {
+ session.AdjustBreakpointLocation ((Breakpoint)BreakEvent, newLine, newColumn);
+ } else {
+ adjustedColumn = newColumn;
+ adjustedLine = newLine;
+ }
+ }
+
+ /// <summary>
+ /// Increments the hit count.
+ /// </summary>
+ /// <returns><c>true</c> if the break event should trigger, or <c>false</c> otherwise.</returns>
+ public bool HitCountReached
+ {
+ get {
+ switch (BreakEvent.HitCountMode) {
+ case HitCountMode.LessThan:
+ return BreakEvent.CurrentHitCount < BreakEvent.HitCount;
+ case HitCountMode.LessThanOrEqualTo:
+ return BreakEvent.CurrentHitCount <= BreakEvent.HitCount;
+ case HitCountMode.EqualTo:
+ return BreakEvent.CurrentHitCount == BreakEvent.HitCount;
+ case HitCountMode.GreaterThan:
+ return BreakEvent.CurrentHitCount > BreakEvent.HitCount;
+ case HitCountMode.GreaterThanOrEqualTo:
+ return BreakEvent.CurrentHitCount >= BreakEvent.HitCount;
+ case HitCountMode.MultipleOf:
+ return (BreakEvent.CurrentHitCount % BreakEvent.HitCount) == 0;
+ default:
+ return true;
+ }
+ }
+ }
+
+ public void IncrementHitCount ()
+ {
+ if (BreakEvent.HitCountMode != HitCountMode.None) {
+ BreakEvent.CurrentHitCount++;
+ BreakEvent.NotifyUpdate ();
+ }
+ }
+
+ [Obsolete ("Use IncrementHitCount() instead")]
+ public void UpdateHitCount (int count)
+ {
+ BreakEvent.CurrentHitCount = count;
+ BreakEvent.NotifyUpdate ();
+ }
+
+ public void SetStatus (BreakEventStatus s, string statusMessage)
+ {
+ if (s != Status) {
+ Status = s;
+ StatusMessage = statusMessage;
+ if (session != null)
+ session.NotifyBreakEventStatusChanged (BreakEvent);
+ }
+ }
+
+ public bool RunCustomBreakpointAction (string actionId)
+ {
+ BreakEventHitHandler h = session.CustomBreakEventHitHandler;
+ return h != null && h (actionId, BreakEvent);
+ }
+
+ public void UpdateLastTraceValue (string value)
+ {
+ BreakEvent.LastTraceValue = value;
+ BreakEvent.NotifyUpdate ();
+ if (value != null) {
+ if (session.BreakpointTraceHandler != null)
+ session.BreakpointTraceHandler (BreakEvent, value);
+ else
+ session.OnDebuggerOutput (false, value + "\n");
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakEventStatus.cs b/Mono.Debugging/Mono.Debugging.Client/BreakEventStatus.cs
new file mode 100644
index 0000000..24a94cf
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakEventStatus.cs
@@ -0,0 +1,57 @@
+//
+// BreakEventStatus.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2011 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 Mono.Debugging.Client
+{
+ public enum BreakEventStatus
+ {
+ /// <summary>
+ /// The breakpoint is not connected to any debug session
+ /// </summary>
+ Disconnected = 1,
+
+ /// <summary>
+ /// The breakpoint is not yet bound to a valid location
+ /// </summary>
+ NotBound = 2,
+
+ /// <summary>
+ /// The breakpoint is bound
+ /// </summary>
+ Bound = 3,
+
+ /// <summary>
+ /// The breakpoint could not be bound because the breakpoint location is invalid
+ /// </summary>
+ Invalid = 4,
+
+ /// <summary>
+ /// There was a debugger error while binding the breakpoint
+ /// </summary>
+ BindError = 5
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs b/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs
new file mode 100644
index 0000000..3d3fd7a
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs
@@ -0,0 +1,237 @@
+// Breakpoint.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Xml;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class Breakpoint: BreakEvent
+ {
+ bool breakIfConditionChanges;
+ string conditionExpression;
+ string lastConditionValue;
+ int adjustedColumn = -1;
+ int adjustedLine = -1;
+ string fileName;
+ int column;
+ int line;
+
+ public Breakpoint (string fileName, int line, int column)
+ {
+ FileName = fileName;
+ Column = column;
+ Line = line;
+ }
+
+ public Breakpoint (string fileName, int line) : this (fileName, line, 1)
+ {
+ }
+
+ internal Breakpoint (XmlElement elem): base (elem)
+ {
+ string s = elem.GetAttribute ("file");
+ if (!string.IsNullOrEmpty (s))
+ fileName = s;
+
+ s = elem.GetAttribute ("line");
+ if (string.IsNullOrEmpty (s) || !int.TryParse (s, out line))
+ line = 1;
+
+ s = elem.GetAttribute ("column");
+ if (string.IsNullOrEmpty (s) || !int.TryParse (s, out column))
+ column = 1;
+
+ s = elem.GetAttribute ("conditionExpression");
+ if (!string.IsNullOrEmpty (s))
+ conditionExpression = s;
+
+ s = elem.GetAttribute ("breakIfConditionChanges");
+ if (!string.IsNullOrEmpty (s) && !bool.TryParse (s, out breakIfConditionChanges))
+ breakIfConditionChanges = false;
+ }
+
+ internal override XmlElement ToXml (XmlDocument doc)
+ {
+ XmlElement elem = base.ToXml (doc);
+
+ if (!string.IsNullOrEmpty (fileName))
+ elem.SetAttribute ("file", fileName);
+
+ elem.SetAttribute ("line", line.ToString ());
+ elem.SetAttribute ("column", column.ToString ());
+
+ if (!string.IsNullOrEmpty (conditionExpression)) {
+ elem.SetAttribute ("conditionExpression", conditionExpression);
+ if (breakIfConditionChanges)
+ elem.SetAttribute ("breakIfConditionChanges", "True");
+ }
+
+ return elem;
+ }
+
+ public string FileName {
+ get { return fileName; }
+ protected set { fileName = value; }
+ }
+
+ public int OriginalColumn {
+ get { return column; }
+ }
+
+ public int Column {
+ get { return adjustedColumn == -1 ? column : adjustedColumn; }
+ protected set { column = value; }
+ }
+
+ public int OriginalLine {
+ get { return line; }
+ }
+
+ public int Line {
+ get { return adjustedLine == -1 ? line : adjustedLine; }
+ protected set { line = value; }
+ }
+
+ public void SetColumn (int newColumn)
+ {
+ ResetAdjustedColumn ();
+ column = newColumn;
+ }
+
+ public void SetLine (int newLine)
+ {
+ ResetAdjustedLine ();
+ line = newLine;
+ }
+
+ internal void SetAdjustedColumn (int newColumn)
+ {
+ adjustedColumn = newColumn;
+ }
+
+ internal void SetAdjustedLine (int newLine)
+ {
+ adjustedLine = newLine;
+ }
+
+ // FIXME: make this private
+ internal void ResetAdjustedColumn ()
+ {
+ adjustedColumn = -1;
+ }
+
+ // FIXME: make this private
+ internal void ResetAdjustedLine ()
+ {
+ adjustedLine = -1;
+ }
+
+ public override bool Reset ()
+ {
+ bool changed = base.Reset () || HasAdjustedLine || HasAdjustedColumn;
+
+ lastConditionValue = null;
+ adjustedColumn = -1;
+ adjustedLine = -1;
+
+ return changed;
+ }
+
+ // FIXME: make this private
+ internal bool HasAdjustedColumn {
+ get { return adjustedColumn != -1; }
+ }
+
+ // FIXME: make this private
+ internal bool HasAdjustedLine {
+ get { return adjustedLine != -1; }
+ }
+
+ public string ConditionExpression {
+ get {
+ return conditionExpression;
+ }
+ set {
+ conditionExpression = value;
+ }
+ }
+
+ public string LastConditionValue {
+ get {
+ return lastConditionValue;
+ }
+ set {
+ lastConditionValue = value;
+ }
+ }
+
+ public bool BreakIfConditionChanges {
+ get {
+ return breakIfConditionChanges;
+ }
+ set {
+ breakIfConditionChanges = value;
+ }
+ }
+
+ public override void CopyFrom (BreakEvent ev)
+ {
+ base.CopyFrom (ev);
+
+ Breakpoint bp = (Breakpoint) ev;
+
+ breakIfConditionChanges = bp.breakIfConditionChanges;
+ conditionExpression = bp.conditionExpression;
+ fileName = bp.fileName;
+ column = bp.column;
+ line = bp.line;
+ }
+ }
+
+ public enum HitCountMode {
+ None,
+ LessThan,
+ LessThanOrEqualTo,
+ EqualTo,
+ GreaterThan,
+ GreaterThanOrEqualTo,
+ MultipleOf
+ }
+
+ [Flags]
+ public enum HitAction
+ {
+ None = 0x0,
+ Break = 0x1,
+ PrintExpression = 0x2,
+ CustomAction = 0x4
+ }
+
+ public delegate bool BreakEventHitHandler (string actionId, BreakEvent be);
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakpointEventArgs.cs b/Mono.Debugging/Mono.Debugging.Client/BreakpointEventArgs.cs
new file mode 100644
index 0000000..928a863
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakpointEventArgs.cs
@@ -0,0 +1,45 @@
+// BreakpointEventArgs.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ public class BreakpointEventArgs: EventArgs
+ {
+ Breakpoint bp;
+
+ public BreakpointEventArgs (Breakpoint bp)
+ {
+ this.bp = bp;
+ }
+
+ public Breakpoint Breakpoint {
+ get { return bp; }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakpointStore.cs b/Mono.Debugging/Mono.Debugging.Client/BreakpointStore.cs
new file mode 100644
index 0000000..f959564
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakpointStore.cs
@@ -0,0 +1,583 @@
+// BreakpointStore.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.IO;
+using System.Linq;
+using System.Xml;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Runtime.InteropServices;
+
+namespace Mono.Debugging.Client
+{
+ public sealed class BreakpointStore: ICollection<BreakEvent>
+ {
+ static readonly StringComparer PathComparer;
+ static readonly bool IsWindows;
+ static readonly bool IsMac;
+
+ static BreakpointStore ()
+ {
+ IsWindows = Path.DirectorySeparatorChar == '\\';
+ IsMac = !IsWindows && IsRunningOnMac ();
+
+ PathComparer = IsWindows || IsMac ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
+ }
+
+ [DllImport ("libc")]
+ static extern int uname (IntPtr buf);
+
+ //From Managed.Windows.Forms/XplatUI
+ static bool IsRunningOnMac ()
+ {
+ IntPtr buf = IntPtr.Zero;
+ try {
+ buf = Marshal.AllocHGlobal (8192);
+ // This is a hacktastic way of getting sysname from uname ()
+ if (uname (buf) == 0) {
+ string os = Marshal.PtrToStringAnsi (buf);
+ if (os == "Darwin")
+ return true;
+ }
+ } catch {
+ } finally {
+ if (buf != IntPtr.Zero)
+ Marshal.FreeHGlobal (buf);
+ }
+ return false;
+ }
+
+ readonly List<BreakEvent> breakpoints = new List<BreakEvent> ();
+
+ public int Count {
+ get {
+ return breakpoints.Count;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ ReadOnlyCheckEventArgs args = new ReadOnlyCheckEventArgs ();
+ EventHandler<ReadOnlyCheckEventArgs> checkingReadOnly = CheckingReadOnly;
+ if (checkingReadOnly != null)
+ checkingReadOnly (this, args);
+ return args.IsReadOnly;
+ }
+ }
+
+ public Breakpoint Add (string filename, int line, int column)
+ {
+ return Add (filename, line, column, true);
+ }
+
+ public Breakpoint Add (string filename, int line)
+ {
+ return Add (filename, line, 1, true);
+ }
+
+ public Breakpoint Add (string filename, int line, int column, bool activate)
+ {
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ if (line < 1)
+ throw new ArgumentOutOfRangeException ("line");
+
+ if (column < 1)
+ throw new ArgumentOutOfRangeException ("column");
+
+ if (IsReadOnly)
+ return null;
+
+ Breakpoint bp = new Breakpoint (filename, line, column);
+ Add (bp);
+
+ return bp;
+ }
+
+ void ICollection<BreakEvent>.Add (BreakEvent bp)
+ {
+ Add (bp);
+ }
+
+ public bool Add (BreakEvent bp)
+ {
+ if (bp == null)
+ throw new ArgumentNullException ("bp");
+
+ if (IsReadOnly)
+ return false;
+
+ breakpoints.Add (bp);
+ bp.Store = this;
+ OnBreakEventAdded (bp);
+
+ return true;
+ }
+
+ public Catchpoint AddCatchpoint (string exceptionName)
+ {
+ if (exceptionName == null)
+ throw new ArgumentNullException ("exceptionName");
+
+ if (IsReadOnly)
+ return null;
+
+ Catchpoint cp = new Catchpoint (exceptionName);
+ Add (cp);
+
+ return cp;
+ }
+
+ public bool Remove (string filename, int line, int column)
+ {
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ if (IsReadOnly)
+ return false;
+
+ filename = Path.GetFullPath (filename);
+
+ for (int n=0; n<breakpoints.Count; n++) {
+ Breakpoint bp = breakpoints [n] as Breakpoint;
+ if (bp != null && FileNameEquals (bp.FileName, filename) &&
+ (bp.OriginalLine == line || bp.Line == line) &&
+ (bp.OriginalColumn == column || bp.Column == column)) {
+ breakpoints.RemoveAt (n);
+ OnBreakEventRemoved (bp);
+ n--;
+ }
+ }
+ return true;
+ }
+
+ public bool RemoveCatchpoint (string exceptionName)
+ {
+ if (exceptionName == null)
+ throw new ArgumentNullException ("exceptionName");
+
+ if (IsReadOnly)
+ return false;
+
+ for (int n=0; n<breakpoints.Count; n++) {
+ Catchpoint cp = breakpoints [n] as Catchpoint;
+ if (cp != null && cp.ExceptionName == exceptionName) {
+ breakpoints.RemoveAt (n);
+ OnBreakEventRemoved (cp);
+ n--;
+ }
+ }
+ return true;
+ }
+
+ public bool Remove (BreakEvent bp)
+ {
+ if (bp == null)
+ throw new ArgumentNullException ("bp");
+
+ if (!IsReadOnly && breakpoints.Remove (bp)) {
+ OnBreakEventRemoved (bp);
+ return true;
+ }
+
+ return false;
+ }
+
+ public Breakpoint Toggle (string filename, int line, int column)
+ {
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ if (line < 1)
+ throw new ArgumentOutOfRangeException ("line");
+
+ if (column < 1)
+ throw new ArgumentOutOfRangeException ("column");
+
+ if (IsReadOnly)
+ return null;
+
+ ReadOnlyCollection<Breakpoint> col = GetBreakpointsAtFileLine (filename, line);
+ if (col.Count > 0) {
+ // Remove only the most-recently-added breakpoint on the specified line
+ Remove (col[col.Count - 1]);
+ return null;
+ }
+
+ return Add (filename, line, column);
+ }
+
+ public ReadOnlyCollection<BreakEvent> GetBreakevents ()
+ {
+ return breakpoints.AsReadOnly ();
+ }
+
+ public ReadOnlyCollection<Breakpoint> GetBreakpoints ()
+ {
+ List<Breakpoint> list = new List<Breakpoint> ();
+ foreach (BreakEvent be in breakpoints) {
+ if (be is Breakpoint)
+ list.Add ((Breakpoint)be);
+ }
+ return list.AsReadOnly ();
+ }
+
+ public ReadOnlyCollection<Catchpoint> GetCatchpoints ()
+ {
+ List<Catchpoint> list = new List<Catchpoint> ();
+ foreach (BreakEvent be in breakpoints) {
+ if (be is Catchpoint)
+ list.Add ((Catchpoint) be);
+ }
+ return list.AsReadOnly ();
+ }
+
+ public ReadOnlyCollection<Breakpoint> GetBreakpointsAtFile (string filename)
+ {
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ var list = new List<Breakpoint> ();
+
+ try {
+ filename = Path.GetFullPath (filename);
+ } catch {
+ return list.AsReadOnly ();
+ }
+
+ foreach (BreakEvent be in breakpoints) {
+ Breakpoint bp = be as Breakpoint;
+ if (bp != null && FileNameEquals (bp.FileName, filename))
+ list.Add (bp);
+ }
+
+ return list.AsReadOnly ();
+ }
+
+ public ReadOnlyCollection<Breakpoint> GetBreakpointsAtFileLine (string filename, int line)
+ {
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ var list = new List<Breakpoint> ();
+
+ try {
+ filename = Path.GetFullPath (filename);
+ } catch {
+ return list.AsReadOnly ();
+ }
+
+ foreach (BreakEvent be in breakpoints) {
+ Breakpoint bp = be as Breakpoint;
+ if (bp != null && FileNameEquals (bp.FileName, filename) && (bp.OriginalLine == line || bp.Line == line))
+ list.Add (bp);
+ }
+
+ return list.AsReadOnly ();
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return breakpoints.GetEnumerator ();
+ }
+
+ IEnumerator<BreakEvent> IEnumerable<BreakEvent>.GetEnumerator ()
+ {
+ return breakpoints.GetEnumerator ();
+ }
+
+ public void Clear ()
+ {
+ List<BreakEvent> oldList = new List<BreakEvent> (breakpoints);
+ foreach (BreakEvent bp in oldList)
+ Remove (bp);
+ }
+
+ public void ClearBreakpoints ()
+ {
+ foreach (Breakpoint bp in GetBreakpoints ())
+ Remove (bp);
+ }
+
+ public void ClearCatchpoints ()
+ {
+ foreach (Catchpoint bp in GetCatchpoints ())
+ Remove (bp);
+ }
+
+ public bool Contains (BreakEvent item)
+ {
+ return breakpoints.Contains (item);
+ }
+
+ public void CopyTo (BreakEvent[] array, int arrayIndex)
+ {
+ breakpoints.CopyTo (array, arrayIndex);
+ }
+
+ public void UpdateBreakpointLine (Breakpoint bp, int newLine)
+ {
+ if (IsReadOnly)
+ return;
+
+ bp.SetLine (newLine);
+ NotifyBreakEventChanged (bp);
+ }
+
+ internal void AdjustBreakpointLine (Breakpoint bp, int newLine, int newColumn)
+ {
+ if (IsReadOnly)
+ return;
+
+ bp.SetAdjustedColumn (newColumn);
+ bp.SetAdjustedLine (newLine);
+ NotifyBreakEventChanged (bp);
+ }
+
+ internal void ResetAdjustedBreakpoints ()
+ {
+ if (IsReadOnly)
+ return;
+
+ foreach (Breakpoint bp in breakpoints.OfType<Breakpoint> ().ToArray ()) {
+ if (bp.Reset ())
+ NotifyBreakEventChanged (bp);
+ }
+ }
+
+ public XmlElement Save ()
+ {
+ XmlDocument doc = new XmlDocument ();
+ XmlElement elem = doc.CreateElement ("BreakpointStore");
+ foreach (BreakEvent ev in this) {
+ XmlElement be = ev.ToXml (doc);
+ elem.AppendChild (be);
+ }
+ return elem;
+ }
+
+ public void Load (XmlElement rootElem)
+ {
+ Clear ();
+ foreach (XmlNode n in rootElem.ChildNodes) {
+ XmlElement elem = n as XmlElement;
+ if (elem == null)
+ continue;
+ BreakEvent ev = BreakEvent.FromXml (elem);
+ if (ev != null)
+ Add (ev);
+ }
+ }
+
+ [DllImport ("libc")]
+ static extern IntPtr realpath (string path, IntPtr buffer);
+
+ static string ResolveFullPath (string path)
+ {
+ if (IsWindows)
+ return Path.GetFullPath (path);
+
+ const int PATHMAX = 4096 + 1;
+ IntPtr buffer = IntPtr.Zero;
+
+ try {
+ buffer = Marshal.AllocHGlobal (PATHMAX);
+ var result = realpath (path, buffer);
+ return result == IntPtr.Zero ? "" : Marshal.PtrToStringAuto (buffer);
+ } finally {
+ if (buffer != IntPtr.Zero)
+ Marshal.FreeHGlobal (buffer);
+ }
+ }
+
+ public static bool FileNameEquals (string file1, string file2)
+ {
+ if (file1 == null)
+ return file2 == null;
+
+ if (file2 == null)
+ return false;
+
+ if (PathComparer.Compare (file1, file2) == 0)
+ return true;
+
+ var rfile1 = ResolveFullPath (file1);
+ var rfile2 = ResolveFullPath (file2);
+
+ return PathComparer.Compare (rfile1, rfile2) == 0;
+ }
+
+ internal bool EnableBreakEvent (BreakEvent be, bool enabled)
+ {
+ if (IsReadOnly)
+ return false;
+
+ OnChanged ();
+ EventHandler<BreakEventArgs> evnt = BreakEventEnableStatusChanged;
+ if (evnt != null)
+ evnt (this, new BreakEventArgs (be));
+ NotifyStatusChanged (be);
+
+ return true;
+ }
+
+ void OnBreakEventAdded (BreakEvent be)
+ {
+ OnChanged ();
+ EventHandler<BreakEventArgs> breakEventAdded = BreakEventAdded;
+ if (breakEventAdded != null)
+ breakEventAdded (this, new BreakEventArgs ((BreakEvent)be));
+ if (be is Breakpoint) {
+ EventHandler<BreakpointEventArgs> breakpointAdded = BreakpointAdded;
+ if (breakpointAdded != null)
+ breakpointAdded (this, new BreakpointEventArgs ((Breakpoint)be));
+ } else if (be is Catchpoint) {
+ EventHandler<CatchpointEventArgs> catchpointAdded = CatchpointAdded;
+ if (catchpointAdded != null)
+ catchpointAdded (this, new CatchpointEventArgs ((Catchpoint)be));
+ }
+ }
+
+ void OnBreakEventRemoved (BreakEvent be)
+ {
+ OnChanged ();
+ EventHandler<BreakEventArgs> breakEventRemoved = BreakEventRemoved;
+ if (breakEventRemoved != null)
+ breakEventRemoved (this, new BreakEventArgs ((BreakEvent)be));
+ if (be is Breakpoint) {
+ EventHandler<BreakpointEventArgs> breakpointRemoved = BreakpointRemoved;
+ if (breakpointRemoved != null)
+ breakpointRemoved (this, new BreakpointEventArgs ((Breakpoint)be));
+ } else if (be is Catchpoint) {
+ EventHandler<CatchpointEventArgs> catchpointRemoved = CatchpointRemoved;
+ if (catchpointRemoved != null)
+ catchpointRemoved (this, new CatchpointEventArgs ((Catchpoint)be));
+ }
+ }
+
+ void OnChanged ()
+ {
+ EventHandler changed = Changed;
+ if (changed != null)
+ changed (this, EventArgs.Empty);
+ }
+
+ internal void NotifyStatusChanged (BreakEvent be)
+ {
+ try {
+ EventHandler<BreakEventArgs> breakEventStatusChanged = BreakEventStatusChanged;
+ if (breakEventStatusChanged != null)
+ breakEventStatusChanged (this, new BreakEventArgs ((BreakEvent)be));
+ if (be is Breakpoint) {
+ EventHandler<BreakpointEventArgs> breakpointStatusChanged = BreakpointStatusChanged;
+ if (breakpointStatusChanged != null)
+ breakpointStatusChanged (this, new BreakpointEventArgs ((Breakpoint)be));
+ } else if (be is Catchpoint) {
+ EventHandler<CatchpointEventArgs > catchpointStatusChanged = CatchpointStatusChanged;
+ if (catchpointStatusChanged != null)
+ catchpointStatusChanged (this, new CatchpointEventArgs ((Catchpoint)be));
+ }
+ } catch {
+ // Ignore
+ }
+ }
+
+ internal void NotifyBreakEventChanged (BreakEvent be)
+ {
+ try {
+ EventHandler<BreakEventArgs> breakEventModified = BreakEventModified;
+ if (breakEventModified != null)
+ breakEventModified (this, new BreakEventArgs ((BreakEvent)be));
+ if (be is Breakpoint) {
+ EventHandler<BreakpointEventArgs > breakpointModified = BreakpointModified;
+ if (breakpointModified != null)
+ breakpointModified (this, new BreakpointEventArgs ((Breakpoint)be));
+ } else if (be is Catchpoint) {
+ EventHandler<CatchpointEventArgs > catchpointModified = CatchpointModified;
+ if (catchpointModified != null)
+ catchpointModified (this, new CatchpointEventArgs ((Catchpoint)be));
+ }
+ OnChanged ();
+ } catch {
+ // Ignore
+ }
+ }
+
+ internal void NotifyBreakEventUpdated (BreakEvent be)
+ {
+ try {
+ EventHandler<BreakEventArgs> breakEventUpdated = BreakEventUpdated;
+ if (breakEventUpdated != null)
+ breakEventUpdated (this, new BreakEventArgs ((BreakEvent)be));
+ if (be is Breakpoint) {
+ EventHandler<BreakpointEventArgs> breakpointUpdated = BreakpointUpdated;
+ if (breakpointUpdated != null)
+ breakpointUpdated (this, new BreakpointEventArgs ((Breakpoint)be));
+ } else if (be is Catchpoint) {
+ EventHandler<CatchpointEventArgs> catchpointUpdated = CatchpointUpdated;
+ if (catchpointUpdated != null)
+ catchpointUpdated (this, new CatchpointEventArgs ((Catchpoint)be));
+ }
+ } catch {
+ // Ignore
+ }
+ }
+
+ public event EventHandler<BreakpointEventArgs> BreakpointAdded;
+ public event EventHandler<BreakpointEventArgs> BreakpointRemoved;
+ public event EventHandler<BreakpointEventArgs> BreakpointStatusChanged;
+ public event EventHandler<BreakpointEventArgs> BreakpointModified;
+ public event EventHandler<BreakpointEventArgs> BreakpointUpdated;
+ public event EventHandler<CatchpointEventArgs> CatchpointAdded;
+ public event EventHandler<CatchpointEventArgs> CatchpointRemoved;
+ public event EventHandler<CatchpointEventArgs> CatchpointStatusChanged;
+ public event EventHandler<CatchpointEventArgs> CatchpointModified;
+ public event EventHandler<CatchpointEventArgs> CatchpointUpdated;
+ public event EventHandler<BreakEventArgs> BreakEventAdded;
+ public event EventHandler<BreakEventArgs> BreakEventRemoved;
+ public event EventHandler<BreakEventArgs> BreakEventStatusChanged;
+ public event EventHandler<BreakEventArgs> BreakEventModified;
+ public event EventHandler<BreakEventArgs> BreakEventUpdated;
+ public event EventHandler Changed;
+ public event EventHandler<ReadOnlyCheckEventArgs> CheckingReadOnly;
+
+ internal event EventHandler<BreakEventArgs> BreakEventEnableStatusChanged;
+ }
+
+ public class ReadOnlyCheckEventArgs: EventArgs
+ {
+ internal bool IsReadOnly;
+
+ public void SetReadOnly (bool isReadOnly)
+ {
+ IsReadOnly = IsReadOnly || isReadOnly;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/Catchpoint.cs b/Mono.Debugging/Mono.Debugging.Client/Catchpoint.cs
new file mode 100644
index 0000000..0e0f2a1
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/Catchpoint.cs
@@ -0,0 +1,81 @@
+// Catchpoint.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Xml;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class Catchpoint: BreakEvent
+ {
+ string exceptionName;
+ bool includeSubclasses;
+
+ public Catchpoint (string exceptionName) : this (exceptionName, true)
+ {
+ }
+
+ public Catchpoint (string exceptionName, bool includeSubclasses)
+ {
+ this.exceptionName = exceptionName;
+ this.includeSubclasses = includeSubclasses;
+ }
+
+ internal Catchpoint (XmlElement elem): base (elem)
+ {
+ exceptionName = elem.GetAttribute ("exceptionName");
+ includeSubclasses = Boolean.Parse (elem.GetAttribute ("includeSubclasses"));
+ }
+
+ internal override XmlElement ToXml (XmlDocument doc)
+ {
+ XmlElement elem = base.ToXml (doc);
+ elem.SetAttribute ("exceptionName", exceptionName);
+ elem.SetAttribute ("includeSubclasses", includeSubclasses.ToString ());
+ return elem;
+ }
+
+
+ public string ExceptionName {
+ get { return exceptionName; }
+ }
+
+ public bool IncludeSubclasses {
+ get { return includeSubclasses; }
+ }
+
+ public override void CopyFrom (BreakEvent ev)
+ {
+ base.CopyFrom (ev);
+ Catchpoint cp = (Catchpoint) ev;
+ exceptionName = cp.exceptionName;
+ includeSubclasses = cp.includeSubclasses;
+ }
+
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/CatchpointEventArgs.cs b/Mono.Debugging/Mono.Debugging.Client/CatchpointEventArgs.cs
new file mode 100644
index 0000000..68abf67
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/CatchpointEventArgs.cs
@@ -0,0 +1,45 @@
+// CatchpointEventArgs.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ public class CatchpointEventArgs: EventArgs
+ {
+ Catchpoint cp;
+
+ public CatchpointEventArgs (Catchpoint cp)
+ {
+ this.cp = cp;
+ }
+
+ public Catchpoint Catchpoint {
+ get { return cp; }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/CompletionData.cs b/Mono.Debugging/Mono.Debugging.Client/CompletionData.cs
new file mode 100644
index 0000000..32ffc2a
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/CompletionData.cs
@@ -0,0 +1,77 @@
+// CompletionData.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class CompletionData
+ {
+ int expressionLength;
+ List<CompletionItem> items = new List<CompletionItem> ();
+
+ public int ExpressionLength {
+ get {
+ return expressionLength;
+ }
+ set {
+ expressionLength = value;
+ }
+ }
+
+ public List<CompletionItem> Items {
+ get { return items; }
+ }
+ }
+
+ [Serializable]
+ public class CompletionItem
+ {
+ string name;
+ ObjectValueFlags flags;
+
+ public CompletionItem (string name, ObjectValueFlags flags)
+ {
+ this.name = name;
+ this.flags = flags;
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public ObjectValueFlags Flags {
+ get {
+ return flags;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/DebuggerException.cs b/Mono.Debugging/Mono.Debugging.Client/DebuggerException.cs
new file mode 100644
index 0000000..5db7ded
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/DebuggerException.cs
@@ -0,0 +1,47 @@
+//
+// DebuggerException.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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.Runtime.Serialization;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class DebuggerException: Exception
+ {
+ public DebuggerException (SerializationInfo info, StreamingContext ctx): base (info, ctx)
+ {
+ }
+
+ public DebuggerException (string message): base (message)
+ {
+ }
+
+ public DebuggerException (string message, Exception inner): base (message, inner)
+ {
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/DebuggerFeatures.cs b/Mono.Debugging/Mono.Debugging.Client/DebuggerFeatures.cs
new file mode 100644
index 0000000..2060645
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/DebuggerFeatures.cs
@@ -0,0 +1,47 @@
+// DebuggerFeatures.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ [Flags]
+ public enum DebuggerFeatures: uint
+ {
+ None = 0,
+ ConditionalBreakpoints = 1,
+ Tracepoints = 1 << 1,
+ Catchpoints = 1 << 2,
+ Attaching = 1 << 3,
+ DebugFile = 1 << 4,
+ Stepping = 1 << 5,
+ Pause = 1 << 6,
+ Breakpoints = 1 << 7,
+ Disassembly = 1 << 8,
+ All = 0xffffffff
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/DebuggerLoggingService.cs b/Mono.Debugging/Mono.Debugging.Client/DebuggerLoggingService.cs
new file mode 100644
index 0000000..22c1662
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/DebuggerLoggingService.cs
@@ -0,0 +1,71 @@
+//
+// DebuggerLoggingService.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson at novell.com>
+//
+// Copyright (c) 2010 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 Mono.Debugging.Client
+{
+ /// <summary>
+ /// This is a simple abstraction so that MD can plug in its own logging service to handle the Mono.Debugging.Soft
+ /// error logging, without Mono.Debugging.Soft depending on MonoDevelop.Core.
+ /// In the absence of a custom logger, it writes to Console.
+ /// </summary>
+ public static class DebuggerLoggingService
+ {
+ public static ICustomLogger CustomLogger { get; set; }
+
+ public static void LogError (string message, Exception ex)
+ {
+ if (CustomLogger != null)
+ CustomLogger.LogError (message, ex);
+ else
+ Console.WriteLine (message + (ex != null? System.Environment.NewLine + ex.ToString () : string.Empty));
+ }
+
+ public static void LogMessage (string messageFormat, params object[] args)
+ {
+ if (CustomLogger != null)
+ CustomLogger.LogMessage (messageFormat, args);
+ else
+ Console.WriteLine (messageFormat, args);
+ }
+
+ //this is meant to show a GUI if possible
+ public static void LogAndShowException (string message, Exception ex)
+ {
+ if (CustomLogger != null)
+ CustomLogger.LogAndShowException (message, ex);
+ else
+ LogError (message, ex);
+ }
+ }
+
+ public interface ICustomLogger
+ {
+ void LogError (string message, System.Exception ex);
+ void LogAndShowException (string message, System.Exception ex);
+ void LogMessage (string messageFormat, params object[] args);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/DebuggerSession.cs b/Mono.Debugging/Mono.Debugging.Client/DebuggerSession.cs
new file mode 100644
index 0000000..ecd6bcf
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/DebuggerSession.cs
@@ -0,0 +1,1538 @@
+// DebuggerSession.cs
+//
+// Author:
+// Ankit Jain <jankit at novell.com>
+// Lluis Sanchez Gual <lluis at 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.Threading;
+using System.Collections.Generic;
+
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Client
+{
+ public delegate void TargetEventHandler (object sender, TargetEventArgs args);
+ public delegate void ProcessEventHandler (int processId);
+ public delegate void ThreadEventHandler (int threadId);
+ public delegate bool ExceptionHandler (Exception ex);
+ public delegate string TypeResolverHandler (string identifier, SourceLocation location);
+ public delegate void BreakpointTraceHandler (BreakEvent be, string trace);
+ public delegate IExpressionEvaluator GetExpressionEvaluatorHandler (string extension);
+ public delegate IConnectionDialog ConnectionDialogCreator ();
+
+ public abstract class DebuggerSession: IDisposable
+ {
+ readonly Dictionary<BreakEvent, BreakEventInfo> breakpoints = new Dictionary<BreakEvent, BreakEventInfo> ();
+ readonly Dictionary<string, string> resolvedExpressionCache = new Dictionary<string, string> ();
+ readonly InternalDebuggerSession frontend;
+ readonly object slock = new object ();
+ readonly object olock = new object ();
+ BreakpointStore breakpointStore;
+ OutputWriterDelegate outputWriter;
+ OutputWriterDelegate logWriter;
+ DebuggerSessionOptions options;
+ ProcessInfo[] currentProcesses;
+ ThreadInfo activeThread;
+ bool ownedBreakpointStore;
+ bool adjustingBreakpoints;
+ bool disposed;
+ bool attached;
+
+ /// <summary>
+ /// Reports a debugger event
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetEvent;
+
+ /// <summary>
+ /// Raised when the debugger resumes execution after being stopped
+ /// </summary>
+ public event EventHandler TargetStarted;
+
+ /// <summary>
+ /// Raised when the underlying debugging engine has been initialized and it is ready to start execution.
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetReady;
+
+ /// <summary>
+ /// Raised when the debugging session is paused
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetStopped;
+
+ /// <summary>
+ /// Raised when the execution is interrupted by an external event
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetInterrupted;
+
+ /// <summary>
+ /// Raised when a breakpoint is hit
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetHitBreakpoint;
+
+ /// <summary>
+ /// Raised when the execution is interrupted due to receiving a signal
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetSignaled;
+
+ /// <summary>
+ /// Raised when the debugged process exits
+ /// </summary>
+ public event EventHandler TargetExited;
+
+ /// <summary>
+ /// Raised when an exception for which there is a catchpoint is thrown
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetExceptionThrown;
+
+ /// <summary>
+ /// Raised when an exception is unhandled
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetUnhandledException;
+
+ /// <summary>
+ /// Raised when a thread is started in the debugged process
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetThreadStarted;
+
+ /// <summary>
+ /// Raised when a thread is stopped in the debugged process
+ /// </summary>
+ public event EventHandler<TargetEventArgs> TargetThreadStopped;
+
+ /// <summary>
+ /// Raised when the 'busy state' of the debugger changes.
+ /// The debugger may switch to busy state if it is in the middle
+ /// of an expression evaluation which can't be aborted.
+ /// </summary>
+ public event EventHandler<BusyStateEventArgs> BusyStateChanged;
+
+ protected DebuggerSession ()
+ {
+ UseOperationThread = true;
+ frontend = new InternalDebuggerSession (this);
+ }
+
+ /// <summary>
+ /// Releases all resource used by the <see cref="Mono.Debugging.Client.DebuggerSession"/> object.
+ /// </summary>
+ /// <remarks>
+ /// Call <see cref="Dispose"/> when you are finished using the <see cref="Mono.Debugging.Client.DebuggerSession"/>.
+ /// The <see cref="Dispose"/> method leaves the <see cref="Mono.Debugging.Client.DebuggerSession"/> in an unusable
+ /// state. After calling <see cref="Dispose"/>, you must release all references to the
+ /// <see cref="Mono.Debugging.Client.DebuggerSession"/> so the garbage collector can reclaim the memory that the
+ /// <see cref="Mono.Debugging.Client.DebuggerSession"/> was occupying.
+ /// </remarks>
+ public virtual void Dispose ()
+ {
+ Dispatch (delegate {
+ if (!disposed) {
+ disposed = true;
+ if (!ownedBreakpointStore)
+ Breakpoints = null;
+ }
+ });
+ }
+
+ /// <summary>
+ /// Gets or sets an exception handler to be invoked when an exception is raised by the debugger engine.
+ /// </summary>
+ /// <remarks>
+ /// Notice that this handler will be used to report exceptions in the debugger, not exceptions raised
+ /// in the debugged process.
+ /// </remarks>
+ public ExceptionHandler ExceptionHandler {
+ get; set;
+ }
+
+ /// <summary>
+ /// Gets or sets the connection dialog creator callback.
+ /// </summary>
+ public ConnectionDialogCreator ConnectionDialogCreator { get; set; }
+
+ /// <summary>
+ /// Gets or sets the breakpoint trace handler.
+ /// </summary>
+ /// <remarks>
+ /// This handler is invoked when the value of a tracepoint has to be printed
+ /// </remarks>
+ public BreakpointTraceHandler BreakpointTraceHandler { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type resolver handler.
+ /// </summary>
+ /// <remarks>
+ /// This handler is invoked when the expression evaluator needs to resolve a type name.
+ /// </remarks>
+ public TypeResolverHandler TypeResolverHandler { get; set; }
+
+ /// <summary>
+ /// Gets or sets the an expression evaluator provider
+ /// </summary>
+ /// <remarks>
+ /// This handler is invoked when the debugger needs to get an evaluator for a specific type of file
+ /// </remarks>
+ public GetExpressionEvaluatorHandler GetExpressionEvaluator { get; set; }
+
+ /// <summary>
+ /// Gets or sets the custom break event hit handler.
+ /// </summary>
+ /// <remarks>
+ /// This handler is invoked when a custom breakpoint is hit to determine if the debug session should
+ /// continue or stop.
+ /// </remarks>
+ public BreakEventHitHandler CustomBreakEventHitHandler {
+ get; set;
+ }
+
+ /// <summary>
+ /// Gets or sets the breakpoint store for the debugger session.
+ /// </summary>
+ public BreakpointStore Breakpoints {
+ get {
+ lock (slock) {
+ if (breakpointStore == null) {
+ Breakpoints = new BreakpointStore ();
+ ownedBreakpointStore = true;
+ }
+ return breakpointStore;
+ }
+ }
+ set {
+ lock (slock) {
+ if (breakpointStore != null) {
+ lock (breakpointStore) {
+ foreach (BreakEvent bp in breakpointStore) {
+ RemoveBreakEvent (bp);
+ NotifyBreakEventStatusChanged (bp);
+ }
+ }
+ breakpointStore.BreakEventAdded -= OnBreakpointAdded;
+ breakpointStore.BreakEventRemoved -= OnBreakpointRemoved;
+ breakpointStore.BreakEventModified -= OnBreakpointModified;
+ breakpointStore.BreakEventEnableStatusChanged -= OnBreakpointStatusChanged;
+ breakpointStore.CheckingReadOnly -= BreakpointStoreCheckingReadOnly;
+ breakpointStore.ResetAdjustedBreakpoints ();
+ }
+
+ breakpointStore = value;
+ ownedBreakpointStore = false;
+
+ if (breakpointStore != null) {
+ if (IsConnected) {
+ Dispatch (delegate {
+ if (IsConnected) {
+ lock (breakpointStore) {
+ foreach (BreakEvent bp in breakpointStore)
+ AddBreakEvent (bp);
+ }
+ }
+ });
+ }
+ breakpointStore.BreakEventAdded += OnBreakpointAdded;
+ breakpointStore.BreakEventRemoved += OnBreakpointRemoved;
+ breakpointStore.BreakEventModified += OnBreakpointModified;
+ breakpointStore.BreakEventEnableStatusChanged += OnBreakpointStatusChanged;
+ breakpointStore.CheckingReadOnly += BreakpointStoreCheckingReadOnly;
+ }
+ }
+ }
+ }
+
+ void Dispatch (Action action)
+ {
+ if (UseOperationThread) {
+ ThreadPool.QueueUserWorkItem (delegate {
+ lock (slock) {
+ action ();
+ }
+ });
+ } else {
+ lock (slock) {
+ action ();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Starts a debugging session
+ /// </summary>
+ /// <param name='startInfo'>
+ /// Startup information
+ /// </param>
+ /// <param name='options'>
+ /// Session options
+ /// </param>
+ /// <exception cref='ArgumentNullException'>
+ /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
+ /// </exception>
+ public void Run (DebuggerStartInfo startInfo, DebuggerSessionOptions options)
+ {
+ if (startInfo == null)
+ throw new ArgumentNullException ("startInfo");
+ if (options == null)
+ throw new ArgumentNullException ("options");
+
+ lock (slock) {
+ this.options = options;
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnRun (startInfo);
+ } catch (Exception ex) {
+ ForceExit ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Starts a debugging session by attaching the debugger to a running process
+ /// </summary>
+ /// <param name='proc'>
+ /// Process information
+ /// </param>
+ /// <param name='options'>
+ /// Debugging options
+ /// </param>
+ /// <exception cref='ArgumentNullException'>
+ /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
+ /// </exception>
+ public void AttachToProcess (ProcessInfo proc, DebuggerSessionOptions options)
+ {
+ if (proc == null)
+ throw new ArgumentNullException ("proc");
+ if (options == null)
+ throw new ArgumentNullException ("options");
+
+ lock (slock) {
+ this.options = options;
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnAttachToProcess (proc.Id);
+ attached = true;
+ } catch (Exception ex) {
+ ForceExit ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Detaches this debugging session from the debugged process
+ /// </summary>
+ public void Detach ()
+ {
+ lock (slock) {
+ try {
+ OnDetach ();
+ } catch (Exception ex) {
+ if (!HandleException (ex))
+ throw;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this <see cref="Mono.Debugging.Client.DebuggerSession"/> has been attached to a process using the Attach method.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if attached to process; otherwise, <c>false</c>.
+ /// </value>
+ public bool AttachedToProcess {
+ get { return attached; }
+ }
+
+ /// <summary>
+ /// Gets or sets the active thread.
+ /// </summary>
+ /// <remarks>
+ /// This property can only be used when the debugger is paused
+ /// </remarks>
+ public ThreadInfo ActiveThread {
+ get {
+ lock (slock) {
+ return activeThread;
+ }
+ }
+ set {
+ lock (slock) {
+ try {
+ activeThread = value;
+ OnSetActiveThread (activeThread.ProcessId, activeThread.Id);
+ } catch (Exception ex) {
+ if (!HandleException (ex))
+ throw;
+ }
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Executes one line of code
+ /// </summary>
+ public void NextLine ()
+ {
+ lock (slock) {
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnNextLine ();
+ } catch (Exception ex) {
+ ForceStop ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Executes one line of code, stepping into method invocations
+ /// </summary>
+ public void StepLine ()
+ {
+ lock (slock) {
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnStepLine ();
+ } catch (Exception ex) {
+ ForceStop ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Executes one low level instruction
+ /// </summary>
+ public void NextInstruction ()
+ {
+ lock (slock) {
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnNextInstruction ();
+ } catch (Exception ex) {
+ ForceStop ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Executes one low level instruction, stepping into method invocations
+ /// </summary>
+ public void StepInstruction ()
+ {
+ lock (slock) {
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnStepInstruction ();
+ } catch (Exception ex) {
+ ForceStop ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Resumes the execution of the debugger and stops when the current method is exited
+ /// </summary>
+ public void Finish ()
+ {
+ lock (slock) {
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnFinish ();
+ } catch (Exception ex) {
+ ForceExit ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Returns the status of a breakpoint for this debugger session.
+ /// </summary>
+ public BreakEventStatus GetBreakEventStatus (BreakEvent be)
+ {
+ if (IsConnected) {
+ BreakEventInfo binfo;
+ lock (breakpoints) {
+ if (breakpoints.TryGetValue (be, out binfo))
+ return binfo.Status;
+ }
+ }
+ return BreakEventStatus.NotBound;
+ }
+
+ /// <summary>
+ /// Returns a status message of a breakpoint for this debugger session.
+ /// </summary>
+ public string GetBreakEventStatusMessage (BreakEvent be)
+ {
+ if (IsConnected) {
+ BreakEventInfo binfo;
+ lock (breakpoints) {
+ if (breakpoints.TryGetValue (be, out binfo)) {
+ if (binfo.StatusMessage != null)
+ return binfo.StatusMessage;
+ switch (binfo.Status) {
+ case BreakEventStatus.BindError: return "The breakpoint could not be bound";
+ case BreakEventStatus.Bound: return "";
+ case BreakEventStatus.Disconnected: return "";
+ case BreakEventStatus.Invalid: return "The breakpoint location is invalid. Perhaps the source line does " +
+ "not contain any statements, or the source does not correspond to the current binary";
+ case BreakEventStatus.NotBound: return "The breakpoint could not yet be bound to a valid location";
+ }
+ }
+ }
+ }
+ return "The breakpoint will not currently be hit";
+ }
+
+ void AddBreakEvent (BreakEvent be)
+ {
+ try {
+ var eventInfo = OnInsertBreakEvent (be);
+ if (eventInfo == null)
+ throw new InvalidOperationException ("OnInsertBreakEvent can't return a null value. If the breakpoint can't be bound or is invalid, a BreakEventInfo with the corresponding status must be returned");
+ lock (breakpoints) {
+ breakpoints [be] = eventInfo;
+ }
+ eventInfo.AttachSession (this, be);
+ } catch (Exception ex) {
+ string msg;
+
+ if (be is FunctionBreakpoint)
+ msg = "Could not set breakpoint at location '" + ((FunctionBreakpoint) be).FunctionName + ":" + ((FunctionBreakpoint) be).Line + "'";
+ else if (be is Breakpoint)
+ msg = "Could not set breakpoint at location '" + ((Breakpoint) be).FileName + ":" + ((Breakpoint) be).Line + "'";
+ else
+ msg = "Could not set catchpoint for exception '" + ((Catchpoint) be).ExceptionName + "'";
+
+ msg += " (" + ex.Message + ")";
+ OnDebuggerOutput (false, msg + "\n");
+ HandleException (ex);
+ }
+ }
+
+ bool RemoveBreakEvent (BreakEvent be)
+ {
+ lock (breakpoints) {
+ BreakEventInfo binfo;
+ if (breakpoints.TryGetValue (be, out binfo)) {
+ try {
+ OnRemoveBreakEvent (binfo);
+ } catch (Exception ex) {
+ if (IsConnected)
+ OnDebuggerOutput (false, ex.Message);
+ HandleException (ex);
+ return false;
+ }
+ breakpoints.Remove (be);
+ }
+ return true;
+ }
+ }
+
+ void UpdateBreakEventStatus (BreakEvent be)
+ {
+ lock (breakpoints) {
+ BreakEventInfo binfo;
+ if (breakpoints.TryGetValue (be, out binfo)) {
+ try {
+ OnEnableBreakEvent (binfo, be.Enabled);
+ } catch (Exception ex) {
+ if (IsConnected)
+ OnDebuggerOutput (false, ex.Message);
+ HandleException (ex);
+ }
+ }
+ }
+ }
+
+ void UpdateBreakEvent (BreakEvent be)
+ {
+ lock (breakpoints) {
+ BreakEventInfo binfo;
+ if (breakpoints.TryGetValue (be, out binfo))
+ OnUpdateBreakEvent (binfo);
+ }
+ }
+
+ void OnBreakpointAdded (object s, BreakEventArgs args)
+ {
+ if (adjustingBreakpoints)
+ return;
+
+ if (IsConnected) {
+ Dispatch (delegate {
+ if (IsConnected)
+ AddBreakEvent (args.BreakEvent);
+ });
+ }
+ }
+
+ void OnBreakpointRemoved (object s, BreakEventArgs args)
+ {
+ if (adjustingBreakpoints)
+ return;
+
+ if (IsConnected) {
+ Dispatch (delegate {
+ if (IsConnected)
+ RemoveBreakEvent (args.BreakEvent);
+ });
+ }
+ }
+
+ void OnBreakpointModified (object s, BreakEventArgs args)
+ {
+ if (IsConnected) {
+ Dispatch (delegate {
+ if (IsConnected)
+ UpdateBreakEvent (args.BreakEvent);
+ });
+ }
+ }
+
+ void OnBreakpointStatusChanged (object s, BreakEventArgs args)
+ {
+ if (IsConnected) {
+ Dispatch (delegate {
+ if (IsConnected)
+ UpdateBreakEventStatus (args.BreakEvent);
+ });
+ }
+ }
+
+ void BreakpointStoreCheckingReadOnly (object sender, ReadOnlyCheckEventArgs e)
+ {
+ e.SetReadOnly (!AllowBreakEventChanges);
+ }
+
+ /// <summary>
+ /// Gets the debugger options object
+ /// </summary>
+ public DebuggerSessionOptions Options {
+ get { return options; }
+ }
+
+ /// <summary>
+ /// Gets or sets the evaluation options.
+ /// </summary>
+ public EvaluationOptions EvaluationOptions {
+ get { return options.EvaluationOptions; }
+ set { options.EvaluationOptions = value; }
+ }
+
+ /// <summary>
+ /// Resumes the execution of the debugger
+ /// </summary>
+ public void Continue ()
+ {
+ lock (slock) {
+ OnRunning ();
+ Dispatch (delegate {
+ try {
+ OnContinue ();
+ } catch (Exception ex) {
+ ForceStop ();
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+ }
+
+ /// <summary>
+ /// Pauses the execution of the debugger
+ /// </summary>
+ public void Stop ()
+ {
+ Dispatch (delegate {
+ try {
+ OnStop ();
+ } catch (Exception ex) {
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+
+ /// <summary>
+ /// Stops the execution of the debugger by killing the debugged process
+ /// </summary>
+ public void Exit ()
+ {
+ Dispatch (delegate {
+ try {
+ OnExit ();
+ } catch (Exception ex) {
+ if (!HandleException (ex))
+ throw;
+ }
+ });
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the debuggee is currently connected
+ /// </summary>
+ public bool IsConnected {
+ get; private set;
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the debuggee is currently running (not paused by the debugger)
+ /// </summary>
+ public bool IsRunning {
+ get; private set;
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the debuggee has exited.
+ /// </summary>
+ public bool HasExited {
+ get; protected set;
+ }
+
+ /// <summary>
+ /// Gets a list of all processes
+ /// </summary>
+ /// <remarks>
+ /// This method can only be used when the debuggee is stopped by the debugger
+ /// </remarks>
+ public ProcessInfo[] GetProcesses ()
+ {
+ lock (slock) {
+ if (currentProcesses == null) {
+ currentProcesses = OnGetProcesses ();
+ foreach (ProcessInfo p in currentProcesses)
+ p.Attach (this);
+ }
+ return currentProcesses;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the output writer callback.
+ /// </summary>
+ /// <remarks>
+ /// This callback is invoked to print debuggee output
+ /// </remarks>
+ public OutputWriterDelegate OutputWriter {
+ get { return outputWriter; }
+ set {
+ lock (olock) {
+ outputWriter = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the log writer.
+ /// </summary>
+ /// <remarks>
+ /// This callback is invoked to print debugger log messages
+ /// </remarks>
+ public OutputWriterDelegate LogWriter {
+ get { return logWriter; }
+ set {
+ lock (olock) {
+ logWriter = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the disassembly of a source code file
+ /// </summary>
+ /// <returns>
+ /// An array of AssemblyLine, with one element for each source code line that could be disassembled
+ /// </returns>
+ /// <param name='file'>
+ /// The file.
+ /// </param>
+ /// <remarks>
+ /// This method can only be used when the debuggee is stopped by the debugger
+ /// </remarks>
+ public AssemblyLine[] DisassembleFile (string file)
+ {
+ lock (slock) {
+ return OnDisassembleFile (file);
+ }
+ }
+
+ public string ResolveExpression (string expression, string file, int line, int column)
+ {
+ return ResolveExpression (expression, new SourceLocation (null, file, line, column));
+ }
+
+ public virtual string ResolveExpression (string expression, SourceLocation location)
+ {
+ string key = expression + " " + location;
+ string resolved;
+ if (!resolvedExpressionCache.TryGetValue (key, out resolved)) {
+ try {
+ resolved = OnResolveExpression (expression, location);
+ } catch (Exception ex) {
+ OnDebuggerOutput (true, "Error while resolving expression: " + ex.Message);
+ }
+ resolvedExpressionCache [key] = resolved;
+ }
+ return resolved ?? expression;
+ }
+
+ /// <summary>
+ /// Stops the execution of background evaluations being done by the debugger
+ /// </summary>
+ /// <remarks>
+ /// This method can only be used when the debuggee is stopped by the debugger
+ /// </remarks>
+ public void CancelAsyncEvaluations ()
+ {
+ if (UseOperationThread) {
+ ThreadPool.QueueUserWorkItem (delegate {
+ OnCancelAsyncEvaluations ();
+ });
+ } else
+ OnCancelAsyncEvaluations ();
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether there are background evaluations being done by the debugger
+ /// which can be cancelled.
+ /// </summary>
+ /// <remarks>
+ /// This method can only be used when the debuggee is stopped by the debugger
+ /// </remarks>
+ public virtual bool CanCancelAsyncEvaluations {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Override to stop the execution of background evaluations being done by the debugger
+ /// </summary>
+ protected virtual void OnCancelAsyncEvaluations ()
+ {
+ }
+
+ readonly Mono.Debugging.Evaluation.ExpressionEvaluator defaultResolver = new Mono.Debugging.Evaluation.NRefactoryExpressionEvaluator ();
+ readonly Dictionary <string, IExpressionEvaluator> evaluators = new Dictionary <string, IExpressionEvaluator> ();
+
+ internal IExpressionEvaluator FindExpressionEvaluator (StackFrame frame)
+ {
+ if (GetExpressionEvaluator == null)
+ return null;
+
+ string fn = frame.SourceLocation == null ? null : frame.SourceLocation.FileName;
+ if (String.IsNullOrEmpty (fn))
+ return null;
+
+ fn = System.IO.Path.GetExtension (fn);
+ IExpressionEvaluator result;
+ if (evaluators.TryGetValue (fn, out result))
+ return result;
+
+ result = GetExpressionEvaluator(fn);
+
+ evaluators[fn] = result;
+
+ return result;
+ }
+
+ public Mono.Debugging.Evaluation.ExpressionEvaluator GetEvaluator (StackFrame frame)
+ {
+ IExpressionEvaluator result = FindExpressionEvaluator (frame);
+ if (result == null)
+ return defaultResolver;
+ return result.Evaluator;
+ }
+
+
+ /// <summary>
+ /// Called when an expression needs to be resolved
+ /// </summary>
+ /// <param name='expression'>
+ /// The expression
+ /// </param>
+ /// <param name='location'>
+ /// The source code location
+ /// </param>
+ /// <returns>
+ /// The resolved expression
+ /// </returns>
+ protected virtual string OnResolveExpression (string expression, SourceLocation location)
+ {
+ return defaultResolver.Resolve (this, location, expression);
+ }
+
+ internal protected string ResolveIdentifierAsType (string identifier, SourceLocation location)
+ {
+ if (TypeResolverHandler != null)
+ return TypeResolverHandler (identifier, location);
+
+ return null;
+ }
+
+ internal ThreadInfo[] GetThreads (long processId)
+ {
+ lock (slock) {
+ ThreadInfo[] threads = OnGetThreads (processId);
+ foreach (ThreadInfo t in threads)
+ t.Attach (this);
+ return threads;
+ }
+ }
+
+ internal Backtrace GetBacktrace (long processId, long threadId)
+ {
+ lock (slock) {
+ Backtrace bt = OnGetThreadBacktrace (processId, threadId);
+ if (bt != null)
+ bt.Attach (this);
+ return bt;
+ }
+ }
+
+ void ForceStop ()
+ {
+ TargetEventArgs args = new TargetEventArgs (TargetEventType.TargetStopped);
+ OnTargetEvent (args);
+ }
+
+ void ForceExit ()
+ {
+ TargetEventArgs args = new TargetEventArgs (TargetEventType.TargetExited);
+ OnTargetEvent (args);
+ }
+
+ internal protected void OnTargetEvent (TargetEventArgs args)
+ {
+ currentProcesses = null;
+
+ if (args.Process != null)
+ args.Process.Attach (this);
+ if (args.Thread != null) {
+ args.Thread.Attach (this);
+ activeThread = args.Thread;
+ }
+ if (args.Backtrace != null)
+ args.Backtrace.Attach (this);
+
+ EventHandler<TargetEventArgs> evnt = null;
+ switch (args.Type) {
+ case TargetEventType.ExceptionThrown:
+ lock (slock) {
+ IsRunning = false;
+ args.IsStopEvent = true;
+ }
+ evnt = TargetExceptionThrown;
+ break;
+ case TargetEventType.TargetExited:
+ lock (slock) {
+ IsRunning = false;
+ IsConnected = false;
+ HasExited = true;
+ }
+ EventHandler handler = TargetExited;
+ if (handler != null)
+ handler (this, args);
+ break;
+ case TargetEventType.TargetHitBreakpoint:
+ lock (slock) {
+ IsRunning = false;
+ args.IsStopEvent = true;
+ }
+ evnt = TargetHitBreakpoint;
+ break;
+ case TargetEventType.TargetInterrupted:
+ lock (slock) {
+ IsRunning = false;
+ args.IsStopEvent = true;
+ }
+ evnt = TargetInterrupted;
+ break;
+ case TargetEventType.TargetSignaled:
+ lock (slock) {
+ IsRunning = false;
+ args.IsStopEvent = true;
+ }
+ evnt = TargetSignaled;
+ break;
+ case TargetEventType.TargetStopped:
+ lock (slock) {
+ IsRunning = false;
+ args.IsStopEvent = true;
+ }
+ evnt = TargetStopped;
+ break;
+ case TargetEventType.UnhandledException:
+ lock (slock) {
+ IsRunning = false;
+ args.IsStopEvent = true;
+ }
+ evnt = TargetUnhandledException;
+ break;
+ case TargetEventType.TargetReady:
+ evnt = TargetReady;
+ break;
+ case TargetEventType.ThreadStarted:
+ evnt = TargetThreadStarted;
+ break;
+ case TargetEventType.ThreadStopped:
+ evnt = TargetThreadStopped;
+ break;
+ }
+
+ if (evnt != null)
+ evnt (this, args);
+
+ EventHandler<TargetEventArgs> targetEvent = TargetEvent;
+ if (targetEvent != null)
+ targetEvent (this, args);
+ }
+
+ internal void OnRunning ()
+ {
+ IsRunning = true;
+ if (TargetStarted != null)
+ TargetStarted (this, EventArgs.Empty);
+ }
+
+ internal protected void OnStarted ()
+ {
+ OnStarted (null);
+ }
+
+ internal protected virtual void OnStarted (ThreadInfo t)
+ {
+ if (HasExited)
+ return;
+
+ OnTargetEvent (new TargetEventArgs (TargetEventType.TargetReady) { Thread = t });
+
+ lock (slock) {
+ if (!HasExited) {
+ IsConnected = true;
+ if (breakpointStore != null) {
+ lock (breakpointStore) {
+ foreach (BreakEvent bp in breakpointStore)
+ AddBreakEvent (bp);
+ }
+ }
+ }
+ }
+ }
+
+ internal protected void OnTargetOutput (bool isStderr, string text)
+ {
+ lock (olock) {
+ if (outputWriter != null)
+ outputWriter (isStderr, text);
+ }
+ }
+
+ internal protected void OnDebuggerOutput (bool isStderr, string text)
+ {
+ lock (olock) {
+ if (logWriter != null)
+ logWriter (isStderr, text);
+ }
+ }
+
+ internal protected void SetBusyState (BusyStateEventArgs args)
+ {
+ if (BusyStateChanged != null)
+ BusyStateChanged (this, args);
+ }
+
+ /// <summary>
+ /// Tries to bind all unbound breakpoints of a source file
+ /// </summary>
+ /// <param name='fullFilePath'>
+ /// Source file path
+ /// </param>
+ /// <remarks>
+ /// This method can be called by a subclass to ask the debugger session to attempt
+ /// to bind all unbound breakpoints defined on the given file. This method could
+ /// be called, for example, when a new assembly that contains this file is loaded
+ /// into memory. It is not necessary to use this method if the subclass keeps
+ /// track of unbound breakpoints by itself.
+ /// </remarks>
+ internal protected void BindSourceFileBreakpoints (string fullFilePath)
+ {
+ lock (breakpoints) {
+ // Make a copy of the breakpoints table since it can be modified while iterating
+ var breakpointsCopy = new Dictionary<BreakEvent, BreakEventInfo> (breakpoints);
+
+ foreach (KeyValuePair<BreakEvent, BreakEventInfo> bps in breakpointsCopy) {
+ Breakpoint bp = bps.Key as Breakpoint;
+ if (bp != null && bps.Value.Status == BreakEventStatus.NotBound) {
+ StringComparer comparer;
+
+ if (System.IO.Path.DirectorySeparatorChar == '\\')
+ comparer = StringComparer.InvariantCultureIgnoreCase;
+ else
+ comparer = StringComparer.InvariantCulture;
+
+ if (comparer.Compare (System.IO.Path.GetFullPath (bp.FileName), fullFilePath) == 0)
+ RetryEventBind (bps.Value);
+ }
+ }
+ }
+ }
+
+ void RetryEventBind (BreakEventInfo binfo)
+ {
+ // Try inserting the breakpoint again
+ BreakEvent be = binfo.BreakEvent;
+ try {
+ binfo = OnInsertBreakEvent (be);
+ if (binfo == null)
+ throw new InvalidOperationException ("OnInsertBreakEvent can't return a null value. If the breakpoint can't be bound or is invalid, a BreakEventInfo with the corresponding status must be returned");
+ lock (breakpoints) {
+ breakpoints [be] = binfo;
+ }
+ binfo.AttachSession (this, be);
+ } catch (Exception ex) {
+ Breakpoint bp = be as Breakpoint;
+ if (bp != null)
+ OnDebuggerOutput (false, "Could not set breakpoint at location '" + bp.FileName + ":" + bp.Line + " (" + ex.Message + ")\n");
+ else
+ OnDebuggerOutput (false, "Could not set catchpoint for exception '" + ((Catchpoint)be).ExceptionName + "' (" + ex.Message + ")\n");
+ HandleException (ex);
+ }
+ }
+
+ /// <summary>
+ /// Unbinds all bound breakpoints of a source file
+ /// </summary>
+ /// <param name='fullFilePath'>
+ /// The source file path
+ /// </param>
+ /// <remarks>
+ /// This method can be called by a subclass to ask the debugger session to
+ /// unbind all bound breakpoints defined on the given file. This method could
+ /// be called, for example, when an assembly that contains this file is unloaded
+ /// from memory. It is not necessary to use this method if the subclass keeps
+ /// track of unbound breakpoints by itself.
+ /// </remarks>
+ internal protected void UnbindSourceFileBreakpoints (string fullFilePath)
+ {
+ var toUpdate = new List<BreakEventInfo> ();
+
+ lock (breakpoints) {
+ // Make a copy of the breakpoints table since it can be modified while iterating
+ var breakpointsCopy = new Dictionary<BreakEvent, BreakEventInfo> (breakpoints);
+
+ foreach (KeyValuePair<BreakEvent, BreakEventInfo> bps in breakpointsCopy) {
+ var bp = bps.Key as Breakpoint;
+ if (bp != null && bps.Value.Status == BreakEventStatus.Bound) {
+ if (System.IO.Path.GetFullPath (bp.FileName) == fullFilePath)
+ toUpdate.Add (bps.Value);
+ }
+ }
+
+ foreach (BreakEventInfo be in toUpdate) {
+ breakpoints.Remove (be.BreakEvent);
+ NotifyBreakEventStatusChanged (be.BreakEvent);
+ }
+ }
+ }
+
+ internal void NotifyBreakEventStatusChanged (BreakEvent be)
+ {
+ var s = GetBreakEventStatus (be);
+ if (s == BreakEventStatus.BindError || s == BreakEventStatus.Invalid)
+ OnDebuggerOutput (true, GetBreakEventErrorMessage (be) + ": " + GetBreakEventStatusMessage (be) + "\n");
+ Breakpoints.NotifyStatusChanged (be);
+ }
+
+ static string GetBreakEventErrorMessage (BreakEvent be)
+ {
+ var bp = be as Breakpoint;
+ if (bp != null)
+ return string.Format ("Could not insert breakpoint at '{0}:{1}'", bp.FileName, bp.Line);
+ Catchpoint cp = (Catchpoint) be;
+ return string.Format ("Could not enable catchpoint for exception '{0}'", cp.ExceptionName);
+ }
+
+ /// <summary>
+ /// Reports an unhandled exception in the debugger
+ /// </summary>
+ /// <returns>
+ /// True if the debugger engine handles the exception. False otherwise.
+ /// </returns>
+ /// <param name='ex'>
+ /// The exception
+ /// </param>
+ /// <remarks>
+ /// This method can be used by subclasses to report errors in the debugger that must be reported
+ /// to the user.
+ /// </remarks>
+ protected virtual bool HandleException (Exception ex)
+ {
+ if (ExceptionHandler != null)
+ return ExceptionHandler (ex);
+
+ return false;
+ }
+
+ internal void AdjustBreakpointLocation (Breakpoint b, int newLine, int newColumn)
+ {
+ lock (slock) {
+ lock (breakpoints) {
+ try {
+ adjustingBreakpoints = true;
+ Breakpoints.AdjustBreakpointLine (b, newLine, newColumn);
+ } finally {
+ adjustingBreakpoints = false;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// When set, operations such as OnRun, OnAttachToProcess, OnStepLine, etc, are run in
+ /// a background thread, so it will not block the caller of the corresponding public methods.
+ /// </summary>
+ protected bool UseOperationThread { get; set; }
+
+ /// <summary>
+ /// Called to start the execution of the debugger
+ /// </summary>
+ /// <param name='startInfo'>
+ /// Startup information
+ /// </param>
+ protected abstract void OnRun (DebuggerStartInfo startInfo);
+
+ /// <summary>
+ /// Called to attach the debugger to a running process
+ /// </summary>
+ /// <param name='processId'>
+ /// Process identifier.
+ /// </param>
+ protected abstract void OnAttachToProcess (long processId);
+
+ /// <summary>
+ /// Called to detach the debugging session from the running process
+ /// </summary>
+ protected abstract void OnDetach ();
+
+ /// <summary>
+ /// Called when the active thread has to be changed
+ /// </summary>
+ /// <param name='processId'>
+ /// Process identifier.
+ /// </param>
+ /// <param name='threadId'>
+ /// Thread identifier.
+ /// </param>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnSetActiveThread (long processId, long threadId);
+
+ /// <summary>
+ /// Called when the debug session has to be paused
+ /// </summary>
+ protected abstract void OnStop ();
+
+ /// <summary>
+ /// Called when the target process has to be exited
+ /// </summary>
+ protected abstract void OnExit ();
+
+
+ /// <summary>
+ /// Called to step one source code line
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnStepLine ();
+
+ /// <summary>
+ /// Called to step one source line, but step over method calls
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnNextLine ();
+
+ /// <summary>
+ /// Called to step one instruction
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnStepInstruction ();
+
+ /// <summary>
+ /// Called to step one instruction, but step over method calls
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnNextInstruction ();
+
+ /// <summary>
+ /// Called to continue execution until leaving the current method
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnFinish ();
+
+ /// <summary>
+ /// Called to resume execution
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract void OnContinue ();
+
+ //breakpoints etc
+
+ /// <summary>
+ /// Called to insert a new breakpoint or catchpoint
+ /// </summary>
+ /// <param name='breakEvent'>
+ /// The break event.
+ /// </param>
+ /// <remarks>
+ /// Implementations of this method must: (1) create (and return) an instance of BreakEventInfo
+ /// (or a subclass of it). (2) Attempt to activate a breakpoint at the location
+ /// specified in breakEvent. If the breakpoint cannot be activated at the time this
+ /// method is called, it is the responsibility of the DebuggerSession subclass
+ /// to attempt it later on.
+ /// The BreakEventInfo object can be used to change the status of the breakpoint,
+ /// update the hit point, etc.
+ /// </remarks>
+ protected abstract BreakEventInfo OnInsertBreakEvent (BreakEvent breakEvent);
+
+ /// <summary>
+ /// Called when a breakpoint has been removed.
+ /// </summary>
+ /// <param name='eventInfo'>
+ /// The breakpoint
+ /// </param>
+ /// <remarks>
+ /// Implementations of this method should remove or disable the breakpoint
+ /// in the debugging engine.
+ /// </remarks>
+ protected abstract void OnRemoveBreakEvent (BreakEventInfo eventInfo);
+
+ /// <summary>
+ /// Called when information about a breakpoint has changed
+ /// </summary>
+ /// <param name='eventInfo'>
+ /// The break event
+ /// </param>
+ /// <remarks>
+ /// This method is called when some information about the breakpoint changes.
+ /// Notice that the file and line of a breakpoint or the exception name of
+ /// a catchpoint can't be modified. Changes of the Enabled property are
+ /// notified by calling OnEnableBreakEvent.
+ /// </remarks>
+ protected abstract void OnUpdateBreakEvent (BreakEventInfo eventInfo);
+
+ /// <summary>
+ /// Called when a break event is enabled or disabled
+ /// </summary>
+ /// <param name='eventInfo'>
+ /// The break event
+ /// </param>
+ /// <param name='enable'>
+ /// The new status
+ /// </param>
+ protected abstract void OnEnableBreakEvent (BreakEventInfo eventInfo, bool enable);
+
+ /// <summary>
+ /// Queried when the debugger session has to check if changes in breakpoints are allowed or not
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if break event changes are allowed; otherwise, <c>false</c>.
+ /// </value>
+ /// <remarks>
+ /// This property should return false if at the time it is invoked the debugger engine doesn't support
+ /// adding, removing or doing changes in breakpoints.
+ /// </remarks>
+ protected virtual bool AllowBreakEventChanges { get { return true; } }
+
+ /// <summary>
+ /// Called to get a list of the threads of a process
+ /// </summary>
+ /// <param name='processId'>
+ /// Process identifier.
+ /// </param>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract ThreadInfo[] OnGetThreads (long processId);
+
+ /// <summary>
+ /// Called to get a list of all debugee processes
+ /// </summary>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract ProcessInfo[] OnGetProcesses ();
+
+ /// <summary>
+ /// Called to get the backtrace of a thread
+ /// </summary>
+ /// <param name='processId'>
+ /// Process identifier.
+ /// </param>
+ /// <param name='threadId'>
+ /// Thread identifier.
+ /// </param>
+ /// <remarks>
+ /// This method can only be called when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected abstract Backtrace OnGetThreadBacktrace (long processId, long threadId);
+
+ /// <summary>
+ /// Called to gets the disassembly of a source code file
+ /// </summary>
+ /// <returns>
+ /// An array of AssemblyLine, with one element for each source code line that could be disassembled
+ /// </returns>
+ /// <param name='file'>
+ /// The file.
+ /// </param>
+ /// <remarks>
+ /// This method can only be used when the debuggee is stopped by the debugger
+ /// </remarks>
+ protected virtual AssemblyLine[] OnDisassembleFile (string file)
+ {
+ return null;
+ }
+
+ internal T WrapDebuggerObject<T> (T obj) where T:class,IDebuggerBackendObject
+ {
+ return obj != null ? OnWrapDebuggerObject (obj) : null;
+ }
+
+ /// <summary>
+ /// Called for every object that is obtained from the debugger engine.
+ /// Subclasses may want to create wrappers for some of those objects
+ /// </summary>
+ protected virtual T OnWrapDebuggerObject<T> (T obj) where T:class,IDebuggerBackendObject
+ {
+ return obj;
+ }
+
+ protected IDebuggerSessionFrontend Frontend {
+ get {
+ return frontend;
+ }
+ }
+ }
+
+ class InternalDebuggerSession: IDebuggerSessionFrontend
+ {
+ readonly DebuggerSession session;
+
+ public InternalDebuggerSession (DebuggerSession session)
+ {
+ this.session = session;
+ }
+
+ public void NotifyTargetEvent (TargetEventArgs args)
+ {
+ session.OnTargetEvent (args);
+ }
+
+ public void NotifyTargetOutput (bool isStderr, string text)
+ {
+ session.OnTargetOutput (isStderr, text);
+ }
+
+ public void NotifyDebuggerOutput (bool isStderr, string text)
+ {
+ session.OnDebuggerOutput (isStderr, text);
+ }
+
+ public void NotifyStarted (ThreadInfo t)
+ {
+ session.OnStarted (t);
+ }
+
+ public void NotifyStarted ()
+ {
+ session.OnStarted ();
+ }
+
+ public void BindSourceFileBreakpoints (string fullFilePath)
+ {
+ session.BindSourceFileBreakpoints (fullFilePath);
+ }
+
+ public void UnbindSourceFileBreakpoints (string fullFilePath)
+ {
+ session.UnbindSourceFileBreakpoints (fullFilePath);
+ }
+ }
+
+ public delegate void OutputWriterDelegate (bool isStderr, string text);
+
+ public class BusyStateEventArgs: EventArgs
+ {
+ public bool IsBusy { get; internal set; }
+
+ public string Description { get; internal set; }
+ }
+
+ public interface IConnectionDialog : IDisposable
+ {
+ event EventHandler UserCancelled;
+
+ //message may be null in which case the dialog should construct a default
+ void SetMessage (DebuggerStartInfo dsi, string message, bool listening, int attemptNumber);
+ }
+}
+
diff --git a/Mono.Debugging/Mono.Debugging.Client/DebuggerSessionOptions.cs b/Mono.Debugging/Mono.Debugging.Client/DebuggerSessionOptions.cs
new file mode 100644
index 0000000..695d009
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/DebuggerSessionOptions.cs
@@ -0,0 +1,38 @@
+//
+// DebuggerSessionOptions.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Client
+{
+ [Serializable]
+ public class DebuggerSessionOptions
+ {
+ public EvaluationOptions EvaluationOptions { get; set; }
+ public bool StepOverPropertiesAndOperators { get; set; }
+ public bool ProjectAssembliesOnly { get; set; }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/DebuggerStartInfo.cs b/Mono.Debugging/Mono.Debugging.Client/DebuggerStartInfo.cs
new file mode 100644
index 0000000..21f6ca1
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/DebuggerStartInfo.cs
@@ -0,0 +1,80 @@
+// DebuggerStartInfo.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class DebuggerStartInfo
+ {
+ string command;
+ string arguments;
+ string workingDirectory;
+ Dictionary<string, string> environmentVariables;
+
+ public string Command {
+ get {
+ return command;
+ }
+ set {
+ command = value;
+ }
+ }
+
+ public string Arguments {
+ get {
+ return arguments;
+ }
+ set {
+ arguments = value;
+ }
+ }
+
+ public string WorkingDirectory {
+ get {
+ return workingDirectory;
+ }
+ set {
+ workingDirectory = value;
+ }
+ }
+
+ public Dictionary<string, string> EnvironmentVariables {
+ get {
+ if (environmentVariables == null)
+ environmentVariables = new Dictionary<string,string> ();
+ return environmentVariables;
+ }
+ }
+
+ public bool UseExternalConsole { get; set; }
+
+ public bool CloseExternalConsoleOnExit { get; set; }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/EvaluationOptions.cs b/Mono.Debugging/Mono.Debugging.Client/EvaluationOptions.cs
new file mode 100644
index 0000000..04e543d
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/EvaluationOptions.cs
@@ -0,0 +1,117 @@
+//
+// EvaluationOptions.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Client
+{
+ [Serializable]
+ public class EvaluationOptions
+ {
+ bool allowMethodEvaluation;
+ bool allowToStringCalls;
+
+ public static readonly char Ellipsis = '…';
+
+ public static EvaluationOptions DefaultOptions {
+ get {
+ EvaluationOptions ops = new EvaluationOptions ();
+ ops.EvaluationTimeout = 1000;
+ ops.MemberEvaluationTimeout = 5000;
+ ops.AllowTargetInvoke = true;
+ ops.AllowMethodEvaluation = true;
+ ops.AllowToStringCalls = true;
+ ops.FlattenHierarchy = true;
+ ops.GroupPrivateMembers = true;
+ ops.GroupStaticMembers = true;
+ ops.GroupUserPrivateMembers = false;
+ ops.UseExternalTypeResolver = true;
+ ops.IntegerDisplayFormat = IntegerDisplayFormat.Decimal;
+ ops.CurrentExceptionTag = "$exception";
+ ops.EllipsizeStrings = true;
+ ops.EllipsizedLength = 100;
+ ops.ChunkRawStrings = false;
+ return ops;
+ }
+ }
+
+ public EvaluationOptions Clone ()
+ {
+ return (EvaluationOptions) MemberwiseClone ();
+ }
+
+ public bool ChunkRawStrings { get; set; }
+
+ public bool EllipsizeStrings { get; set; }
+ public int EllipsizedLength { get; set; }
+
+ public int EvaluationTimeout { get; set; }
+ public int MemberEvaluationTimeout { get; set; }
+ public bool AllowTargetInvoke { get; set; }
+
+ public bool AllowMethodEvaluation {
+ get { return allowMethodEvaluation && AllowTargetInvoke; }
+ set { allowMethodEvaluation = value; }
+ }
+
+ public bool AllowToStringCalls {
+ get { return allowToStringCalls && AllowTargetInvoke; }
+ set { allowToStringCalls = value; }
+ }
+
+ public bool AllowDisplayStringEvaluation {
+ get { return AllowTargetInvoke; }
+ }
+
+ public bool AllowDebuggerProxy {
+ get { return AllowTargetInvoke; }
+ }
+
+ public bool FlattenHierarchy { get; set; }
+
+ public bool GroupPrivateMembers { get; set; }
+
+ [Obsolete ("I don't see a point in even having this property")]
+ public bool GroupUserPrivateMembers { get; set; }
+
+ public bool GroupStaticMembers { get; set; }
+
+ public bool UseExternalTypeResolver { get; set; }
+
+ [Obsolete ("Use the type's BeforeFieldInit attribute instead")]
+ public bool AllowImplicitTypeLoading { get { return true; } set { } }
+
+ public IntegerDisplayFormat IntegerDisplayFormat { get; set; }
+
+ public string CurrentExceptionTag { get; set; }
+ }
+
+ public enum IntegerDisplayFormat
+ {
+ Decimal,
+ Hexadecimal
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ExceptionInfo.cs b/Mono.Debugging/Mono.Debugging.Client/ExceptionInfo.cs
new file mode 100644
index 0000000..6745dfc
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ExceptionInfo.cs
@@ -0,0 +1,254 @@
+//
+// ExceptionInfo.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2010 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.Text;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class ExceptionInfo
+ {
+ ObjectValue exception;
+ ObjectValue messageObject;
+
+ [NonSerialized]
+ ExceptionStackFrame[] frames;
+
+ [NonSerialized]
+ ExceptionInfo innerException;
+
+ /// <summary>
+ /// The provided value can have the following members:
+ /// Type of the object: type of the exception
+ /// Message: Message of the exception
+ /// Instance: Raw instance of the exception
+ /// StackTrace: an array of frames. Each frame must have:
+ /// Value of the object: display text of the frame
+ /// File: name of the file
+ /// Line: line
+ /// Col: column
+ /// InnerException: inner exception, following the same format described above.
+ /// </summary>
+ public ExceptionInfo (ObjectValue exception)
+ {
+ this.exception = exception;
+ if (exception.IsEvaluating || exception.IsEvaluatingGroup)
+ exception.ValueChanged += HandleExceptionValueChanged;
+ }
+
+ void LoadMessage ()
+ {
+ if (messageObject == null) {
+ messageObject = exception.GetChild ("Message");
+ if (messageObject != null && messageObject.IsEvaluating)
+ messageObject.ValueChanged += HandleMessageValueChanged;
+ }
+ }
+
+ void HandleMessageValueChanged (object sender, EventArgs e)
+ {
+ frames = null;
+ NotifyChanged ();
+ }
+
+ void HandleExceptionValueChanged (object sender, EventArgs e)
+ {
+ frames = null;
+ if (exception.IsEvaluatingGroup)
+ exception = exception.GetArrayItem (0);
+ LoadMessage ();
+ NotifyChanged ();
+ }
+
+ void NotifyChanged ()
+ {
+ EventHandler evnt = Changed;
+ if (evnt != null)
+ evnt (this, EventArgs.Empty);
+ }
+
+ public string Type {
+ get { return exception.TypeName; }
+ }
+
+ public string Message {
+ get {
+ LoadMessage ();
+ if (messageObject != null && messageObject.IsEvaluating)
+ return "Loading...";
+ return messageObject != null ? messageObject.Value : null;
+ }
+ }
+
+ public ObjectValue Instance {
+ get {
+ return exception.GetChild ("Instance");
+ }
+ }
+
+ public bool IsEvaluating {
+ get { return exception.IsEvaluating || exception.IsEvaluatingGroup; }
+ }
+
+ public bool StackIsEvaluating {
+ get {
+ ObjectValue stackTrace = exception.GetChild ("StackTrace");
+ if (stackTrace != null)
+ return stackTrace.IsEvaluating;
+ else
+ return false;
+ }
+ }
+
+ public ExceptionStackFrame[] StackTrace {
+ get {
+ if (frames != null)
+ return frames;
+
+ ObjectValue stackTrace = exception.GetChild ("StackTrace");
+ if (stackTrace == null)
+ return frames = new ExceptionStackFrame [0];
+
+ if (stackTrace.IsEvaluating) {
+ frames = new ExceptionStackFrame [0];
+ stackTrace.ValueChanged += HandleExceptionValueChanged;
+ return frames;
+ }
+ List<ExceptionStackFrame> list = new List<ExceptionStackFrame> ();
+ foreach (ObjectValue val in stackTrace.GetAllChildren ())
+ list.Add (new ExceptionStackFrame (val));
+ frames = list.ToArray ();
+ return frames;
+ }
+ }
+
+ public ExceptionInfo InnerException {
+ get {
+ if (innerException == null) {
+ ObjectValue innerVal = exception.GetChild ("InnerException");
+ if (innerVal == null || innerVal.IsError || innerVal.IsUnknown)
+ return null;
+ if (innerVal.IsEvaluating) {
+ innerVal.ValueChanged += delegate { NotifyChanged (); };
+ return null;
+ }
+ innerException = new ExceptionInfo (innerVal);
+ innerException.Changed += delegate {
+ NotifyChanged ();
+ };
+ }
+ return innerException;
+ }
+ }
+
+ public event EventHandler Changed;
+
+ internal void ConnectCallback (StackFrame parentFrame)
+ {
+ ObjectValue.ConnectCallbacks (parentFrame, exception);
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder ();
+ var chain = new List<ExceptionInfo> ();
+ ExceptionInfo e = this;
+ while (e != null) {
+ chain.Insert (0, e);
+ if (sb.Length > 0)
+ sb.Append (" ---> ");
+ sb.Append (e.Type).Append (": ").Append (e.Message);
+ e = e.InnerException;
+ }
+ sb.AppendLine ();
+ foreach (var ex in chain) {
+ if (ex != chain[0])
+ sb.AppendLine (" --- End of inner exception stack trace ---");
+ foreach (var f in ex.StackTrace) {
+ sb.Append (" at ").Append (f.DisplayText);
+ if (!string.IsNullOrEmpty (f.File))
+ sb.Append (" in ").Append (f.File).Append (":").Append (f.Line);
+ sb.AppendLine ();
+ }
+ }
+ return sb.ToString ();
+ }
+ }
+
+ public class ExceptionStackFrame
+ {
+ ObjectValue frame;
+
+ /// <summary>
+ /// The provided value must have a specific structure.
+ /// The Value property is the display text.
+ /// A child "File" member must be the name of the file.
+ /// A child "Line" member must be the line.
+ /// A child "Col" member must be the column.
+ /// </summary>
+ public ExceptionStackFrame (ObjectValue value)
+ {
+ frame = value;
+ }
+
+ public string File {
+ get {
+ ObjectValue file = frame.GetChild ("File");
+ if (file != null)
+ return file.Value;
+
+ return null;
+ }
+ }
+
+ public int Line {
+ get {
+ ObjectValue val = frame.GetChild ("Line");
+ if (val != null)
+ return int.Parse (val.Value);
+
+ return 0;
+ }
+ }
+
+ public int Column {
+ get {
+ ObjectValue val = frame.GetChild ("Column");
+ if (val != null)
+ return int.Parse (val.Value);
+
+ return 0;
+ }
+ }
+
+ public string DisplayText {
+ get { return frame.Value; }
+ }
+ }
+}
+
diff --git a/Mono.Debugging/Mono.Debugging.Client/FunctionBreakpoint.cs b/Mono.Debugging/Mono.Debugging.Client/FunctionBreakpoint.cs
new file mode 100644
index 0000000..58a0127
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/FunctionBreakpoint.cs
@@ -0,0 +1,189 @@
+//
+// FunctionBreakpoint.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2012 Xamarin Inc.
+//
+// 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.Xml;
+using System.Collections.Generic;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class FunctionBreakpoint : Breakpoint
+ {
+ public FunctionBreakpoint (string functionName, string language) : base (null, 1, 1)
+ {
+ FunctionName = functionName;
+ Language = language;
+ }
+
+ static bool SkipArrayRank (string text, ref int index, int endIndex)
+ {
+ char c;
+
+ while (index < endIndex) {
+ if ((c = text[index++]) == ']')
+ return true;
+
+ if (c != ',' && !char.IsWhiteSpace (c) && !char.IsDigit (c))
+ return false;
+ }
+
+ return false;
+ }
+
+ static bool SkipGenericArgs (string text, ref int index, int endIndex)
+ {
+ char c;
+
+ while (index < endIndex) {
+ if ((c = text[index++]) == '>')
+ return true;
+
+ if (c == '<') {
+ if (!SkipGenericArgs (text, ref index, endIndex))
+ return false;
+
+ while (index < endIndex && !char.IsWhiteSpace (text[index]))
+ index++;
+
+ // the only chars allowed after a '>' are: '>', '[', and ','
+ if (">[,".IndexOf (text[index]) == -1)
+ return false;
+ } else if (c == '[') {
+ if (!SkipArrayRank (text, ref index, endIndex))
+ return false;
+
+ while (index < endIndex && !char.IsWhiteSpace (text[index]))
+ index++;
+
+ // the only chars allowed after a ']' are: '>', '[', and ','
+ if (">[,".IndexOf (text[index]) == -1)
+ return false;
+ } else if (c != '.' && c != '+' && c != ',' && !char.IsWhiteSpace (c) && !char.IsLetterOrDigit (c)) {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ public static bool TryParseParameters (string text, int startIndex, int endIndex, out string[] paramTypes)
+ {
+ List<string> parsedParamTypes = new List<string> ();
+ int index = startIndex;
+ int start;
+ char c;
+
+ paramTypes = null;
+
+ while (index < endIndex) {
+ while (char.IsWhiteSpace (text[index]))
+ index++;
+
+ start = index;
+ while (index < endIndex) {
+ if ((c = text[index]) == ',')
+ break;
+
+ index++;
+
+ if (c == '<') {
+ if (!SkipGenericArgs (text, ref index, endIndex))
+ return false;
+ } else if (c == '[') {
+ if (!SkipArrayRank (text, ref index, endIndex))
+ return false;
+ }
+ }
+
+ parsedParamTypes.Add (text.Substring (start, index - start).TrimEnd ());
+
+ if (index < endIndex)
+ index++;
+ }
+
+ paramTypes = parsedParamTypes.ToArray ();
+
+ return true;
+ }
+
+ internal FunctionBreakpoint (XmlElement elem) : base (elem)
+ {
+ FunctionName = elem.GetAttribute ("function");
+
+ string text = elem.GetAttribute ("language");
+ if (string.IsNullOrEmpty (text))
+ Language = "C#";
+ else
+ Language = text;
+
+ if (elem.HasAttribute ("params")) {
+ string[] paramTypes;
+
+ text = elem.GetAttribute ("params").Trim ();
+ if (text.Length > 0 && TryParseParameters (text, 0, text.Length, out paramTypes))
+ ParamTypes = paramTypes;
+ else
+ ParamTypes = new string[0];
+ }
+
+ FileName = null;
+ }
+
+ internal override XmlElement ToXml (XmlDocument doc)
+ {
+ XmlElement elem = base.ToXml (doc);
+
+ elem.SetAttribute ("function", FunctionName);
+ elem.SetAttribute ("language", Language);
+
+ if (ParamTypes != null)
+ elem.SetAttribute ("params", string.Join (", ", ParamTypes));
+
+ return elem;
+ }
+
+ public string FunctionName {
+ get; set;
+ }
+
+ public string Language {
+ get; set;
+ }
+
+ public string[] ParamTypes {
+ get; set;
+ }
+
+ public override void CopyFrom (BreakEvent ev)
+ {
+ base.CopyFrom (ev);
+
+ FunctionBreakpoint bp = (FunctionBreakpoint) ev;
+ FunctionName = bp.FunctionName;
+ ParamTypes = bp.ParamTypes;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/IExpressionEvaluator.cs b/Mono.Debugging/Mono.Debugging.Client/IExpressionEvaluator.cs
new file mode 100644
index 0000000..f88cf68
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/IExpressionEvaluator.cs
@@ -0,0 +1,38 @@
+//
+// IExpressionEvaluator.cs
+//
+// Author:
+// Carlo kok <ck at remobjects.com>
+//
+// Copyright (c) 2010 RemObjects Software
+//
+// 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 Mono.Debugging.Evaluation;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Client
+{
+ public interface IExpressionEvaluator
+ {
+ ExpressionEvaluator Evaluator { get; }
+ ObjectValue[] GetLocals (StackFrame sf);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ObjectPath.cs b/Mono.Debugging/Mono.Debugging.Client/ObjectPath.cs
new file mode 100644
index 0000000..e9784f4
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ObjectPath.cs
@@ -0,0 +1,101 @@
+// ObjectPath.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public struct ObjectPath
+ {
+ string[] path;
+
+ public ObjectPath (params string[] path)
+ {
+ this.path = path;
+ }
+
+ public string this [int n] {
+ get {
+ if (path == null)
+ throw new IndexOutOfRangeException ();
+ return path [n];
+ }
+ }
+
+ public int Length {
+ get { return path != null ? path.Length : 0; }
+ }
+
+ public IEnumerable GetEnumerator ()
+ {
+ if (path != null)
+ return path;
+ else
+ return new string [0];
+ }
+
+ public ObjectPath GetSubpath (int start)
+ {
+ if (start == 0)
+ return this;
+ else {
+ string[] newPath = new string [path.Length - start];
+ Array.Copy (path, start, newPath, 0, newPath.Length);
+ return new ObjectPath (newPath);
+ }
+ }
+
+ public ObjectPath Append (string name)
+ {
+ string[] newPath = new string [path.Length + 1];
+ Array.Copy (path, newPath, path.Length);
+ newPath [path.Length] = name;
+ return new ObjectPath (newPath);
+ }
+
+ public string LastName {
+ get {
+ if (Length == 0)
+ return "";
+ else
+ return path [path.Length - 1];
+ }
+ }
+
+ public string Join (string separator)
+ {
+ return string.Join (separator, path);
+ }
+
+ public override string ToString ()
+ {
+ return Join ("/");
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ObjectValue.cs b/Mono.Debugging/Mono.Debugging.Client/ObjectValue.cs
new file mode 100644
index 0000000..0885869
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ObjectValue.cs
@@ -0,0 +1,787 @@
+// ObjectValue.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at 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.Text;
+using Mono.Debugging.Backend;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class ObjectValue
+ {
+ ObjectPath path;
+ int arrayCount = -1;
+ bool isNull;
+ string name;
+ string value;
+ string typeName;
+ string displayValue;
+ string childSelector;
+ ObjectValueFlags flags;
+ IObjectValueSource source;
+ IObjectValueUpdater updater;
+ List<ObjectValue> children;
+ ManualResetEvent evaluatedEvent;
+
+ [NonSerialized]
+ UpdateCallback updateCallback;
+
+ [NonSerialized]
+ EventHandler valueChanged;
+
+ [NonSerialized]
+ StackFrame parentFrame;
+
+ static ObjectValue Create (IObjectValueSource source, ObjectPath path, string typeName)
+ {
+ ObjectValue ob = new ObjectValue ();
+ ob.source = source;
+ ob.path = path;
+ ob.typeName = typeName;
+ return ob;
+ }
+
+ public static ObjectValue CreateObject (IObjectValueSource source, ObjectPath path, string typeName, string value, ObjectValueFlags flags, ObjectValue[] children)
+ {
+ return CreateObject (source, path, typeName, new EvaluationResult (value), flags, children);
+ }
+
+ public static ObjectValue CreateObject (IObjectValueSource source, ObjectPath path, string typeName, EvaluationResult value, ObjectValueFlags flags, ObjectValue[] children)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.path = path;
+ ob.flags = flags | ObjectValueFlags.Object;
+ ob.value = value.Value;
+ ob.displayValue = value.DisplayValue;
+ if (children != null) {
+ ob.children = new List<ObjectValue> ();
+ ob.children.AddRange (children);
+ }
+ return ob;
+ }
+
+ public static ObjectValue CreateNullObject (IObjectValueSource source, string name, string typeName, ObjectValueFlags flags)
+ {
+ return CreateNullObject (source, new ObjectPath (name), typeName, flags);
+ }
+
+ public static ObjectValue CreateNullObject (IObjectValueSource source, ObjectPath path, string typeName, ObjectValueFlags flags)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.flags = flags | ObjectValueFlags.Object;
+ ob.value = "(null)";
+ ob.isNull = true;
+ return ob;
+ }
+
+ public static ObjectValue CreatePrimitive (IObjectValueSource source, ObjectPath path, string typeName, EvaluationResult value, ObjectValueFlags flags)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.flags = flags | ObjectValueFlags.Primitive;
+ ob.value = value.Value;
+ ob.displayValue = value.DisplayValue;
+ return ob;
+ }
+
+ public static ObjectValue CreateArray (IObjectValueSource source, ObjectPath path, string typeName, int arrayCount, ObjectValueFlags flags, ObjectValue[] children)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.arrayCount = arrayCount;
+ ob.flags = flags | ObjectValueFlags.Array;
+ ob.value = "[" + arrayCount + "]";
+ if (children != null && children.Length > 0) {
+ ob.children = new List<ObjectValue> ();
+ ob.children.AddRange (children);
+ }
+ return ob;
+ }
+
+ public static ObjectValue CreateUnknown (IObjectValueSource source, ObjectPath path, string typeName)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.flags = ObjectValueFlags.Unknown | ObjectValueFlags.ReadOnly;
+ return ob;
+ }
+
+ public static ObjectValue CreateUnknown (string name)
+ {
+ return CreateUnknown (null, new ObjectPath (name), "");
+ }
+
+ public static ObjectValue CreateError (IObjectValueSource source, ObjectPath path, string typeName, string value, ObjectValueFlags flags)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.flags = flags | ObjectValueFlags.Error;
+ ob.value = value;
+ return ob;
+ }
+
+ public static ObjectValue CreateImplicitNotSupported (IObjectValueSource source, ObjectPath path, string typeName, ObjectValueFlags flags)
+ {
+ return CreateNotSupported (source, path, typeName, "Implicit evaluation is disabled", flags);
+ }
+
+ public static ObjectValue CreateNotSupported (IObjectValueSource source, ObjectPath path, string typeName, string message, ObjectValueFlags flags)
+ {
+ ObjectValue ob = Create (source, path, typeName);
+ ob.flags = flags | ObjectValueFlags.NotSupported;
+ ob.value = message;
+ return ob;
+ }
+
+ public static ObjectValue CreateFatalError (string name, string message, ObjectValueFlags flags)
+ {
+ ObjectValue ob = new ObjectValue ();
+ ob.flags = flags | ObjectValueFlags.Error;
+ ob.value = message;
+ ob.name = name;
+ return ob;
+ }
+
+ public static ObjectValue CreateEvaluating (IObjectValueUpdater updater, ObjectPath path, ObjectValueFlags flags)
+ {
+ ObjectValue ob = Create (null, path, null);
+ ob.updater = updater;
+ ob.path = path;
+ ob.flags = flags | ObjectValueFlags.Evaluating;
+ return ob;
+ }
+
+ /// <summary>
+ /// Gets the flags of the value
+ /// </summary>
+ public ObjectValueFlags Flags {
+ get { return flags; }
+ }
+
+ /// <summary>
+ /// Name of the value (for example, the property name)
+ /// </summary>
+ public string Name {
+ get {
+ if (name == null)
+ return path [path.Length - 1];
+
+ return name;
+ }
+ set {
+ name = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the value of the object
+ /// </summary>
+ /// <value>
+ /// The value.
+ /// </value>
+ /// <exception cref='InvalidOperationException'>
+ /// Is thrown when trying to set a value on a read-only ObjectValue
+ /// </exception>
+ /// <remarks>
+ /// This value is a string representation of the ObjectValue. The content depends on several evaluation
+ /// options. For example, if ToString calls are enabled, this value will be the result of calling
+ /// ToString.
+ /// If the object is a primitive type, in general the Value will be an expression that represents the
+ /// value in the target language. For example, when debugging C#, if the property is an string, the value
+ /// will include the quotation marks and chars like '\' will be properly escaped.
+ /// If you need to get the real CLR value of the object, use GetRawValue.
+ /// </remarks>
+ public virtual string Value {
+ get {
+ return value;
+ }
+ set {
+ if (IsReadOnly || source == null)
+ throw new InvalidOperationException ("Value is not editable");
+ EvaluationResult res = source.SetValue (path, value, null);
+ if (res != null) {
+ this.value = res.Value;
+ displayValue = res.DisplayValue;
+ isNull = value == null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the display value of this object
+ /// </summary>
+ /// <remarks>
+ /// This method returns a string to be used when showing the value of this object.
+ /// In most cases, the Value and DisplayValue properties return the same text, but there are some cases
+ /// in which DisplayValue may return a more convenient textual representation of the value, which
+ /// may not be a valid target language expression.
+ /// For example in C#, an enum Value includes the full enum type name (e.g. "Gtk.ResponseType.OK"),
+ /// while DisplayValue only has the enum value name ("OK").
+ /// </remarks>
+ public string DisplayValue {
+ get { return displayValue ?? Value; }
+ set { displayValue = value; }
+ }
+
+ /// <summary>
+ /// Sets the value of this object, using the default evaluation options
+ /// </summary>
+ public void SetValue (string value)
+ {
+ SetValue (value, parentFrame.DebuggerSession.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Sets the value of this object, using the specified evaluation options
+ /// </summary>
+ /// <param name='value'>
+ /// The value
+ /// </param>
+ /// <param name='options'>
+ /// The options
+ /// </param>
+ /// <exception cref='InvalidOperationException'>
+ /// Is thrown if the value is read-only
+ /// </exception>
+ public void SetValue (string value, EvaluationOptions options)
+ {
+ if (IsReadOnly || source == null)
+ throw new InvalidOperationException ("Value is not editable");
+ EvaluationResult res = source.SetValue (path, value, options);
+ if (res != null) {
+ this.value = res.Value;
+ displayValue = res.DisplayValue;
+ }
+ }
+
+ /// <summary>
+ /// Gets the raw value of this object
+ /// </summary>
+ /// <returns>
+ /// The raw value.
+ /// </returns>
+ /// <remarks>
+ /// This method can be used to get the CLR value of the object. For example, if this ObjectValue is
+ /// a property of type String, this method will return the System.String value of the property.
+ /// If this ObjectValue refers to an object instead of a primitive value, then a RawValue object
+ /// will be returned. RawValue can be used to get and set members of an object, and to call methods.
+ /// If this ObjectValue refers to an array, then a RawValueArray object will be returned.
+ /// </remarks>
+ public object GetRawValue ()
+ {
+ EvaluationOptions ops = parentFrame.DebuggerSession.EvaluationOptions.Clone ();
+ ops.EllipsizeStrings = false;
+
+ return GetRawValue (ops);
+ }
+
+ /// <summary>
+ /// Gets the raw value of this object
+ /// </summary>
+ /// <param name='options'>
+ /// The evaluation options
+ /// </param>
+ /// <returns>
+ /// The raw value.
+ /// </returns>
+ /// <remarks>
+ /// This method can be used to get the CLR value of the object. For example, if this ObjectValue is
+ /// a property of type String, this method will return the System.String value of the property.
+ /// If this ObjectValue refers to an object instead of a primitive value, then a RawValue object
+ /// will be returned. RawValue can be used to get and set members of an object, and to call methods.
+ /// If this ObjectValue refers to an array, then a RawValueArray object will be returned.
+ /// </remarks>
+ public object GetRawValue (EvaluationOptions options)
+ {
+ object res = source.GetRawValue (path, options);
+ IRawObject val = res as IRawObject;
+ if (val != null)
+ val.Connect (parentFrame.DebuggerSession, options);
+ return res;
+ }
+
+ /// <summary>
+ /// Sets the raw value of this object
+ /// </summary>
+ /// <param name='value'>
+ /// The value
+ /// </param>
+ /// <remarks>
+ /// The provided value can be a primitive type, a RawValue object or a RawValueArray object.
+ /// </remarks>
+ public void SetRawValue (object value)
+ {
+ SetRawValue (value, parentFrame.DebuggerSession.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Sets the raw value of this object
+ /// </summary>
+ /// <param name='value'>
+ /// The value
+ /// </param>
+ /// <param name='options'>
+ /// The evaluation options
+ /// </param>
+ /// <remarks>
+ /// The provided value can be a primitive type, a RawValue object or a RawValueArray object.
+ /// </remarks>
+ public void SetRawValue (object value, EvaluationOptions options)
+ {
+ source.SetRawValue (path, value, options);
+ }
+
+ /// <summary>
+ /// Full name of the type of the object
+ /// </summary>
+ public string TypeName {
+ get { return typeName; }
+ set { typeName = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the child selector.
+ /// </summary>
+ /// <remarks>
+ /// The child selector is an expression which can be concatenated to a parent expression to get this child.
+ /// For example, if this object is a reference to a field named 'foo' of an object, the child
+ /// selector is '.foo'.
+ /// </remarks>
+ public string ChildSelector {
+ get {
+ if (childSelector != null)
+ return childSelector;
+
+ if ((flags & ObjectValueFlags.ArrayElement) != 0)
+ return Name;
+
+ return "." + Name;
+ }
+ set { childSelector = value; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this object has children.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance has children; otherwise, <c>false</c>.
+ /// </value>
+ public bool HasChildren {
+ get {
+ if (isNull)
+ return false;
+ if (IsEvaluating)
+ return false;
+ if (children != null)
+ return children.Count > 0;
+ if (source == null)
+ return false;
+ if (IsArray)
+ return arrayCount > 0;
+ if (IsObject)
+ return true;
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets a child value
+ /// </summary>
+ /// <returns>
+ /// The child.
+ /// </returns>
+ /// <param name='name'>
+ /// Name of the member
+ /// </param>
+ /// <remarks>
+ /// This method can be used to get a member of an object (such as a field or property)
+ /// </remarks>
+ public ObjectValue GetChild (string name)
+ {
+ return GetChild (name, parentFrame.DebuggerSession.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Gets a child value
+ /// </summary>
+ /// <returns>
+ /// The child.
+ /// </returns>
+ /// <param name='name'>
+ /// Name of the member
+ /// </param>
+ /// <param name='options'>
+ /// Options to be used to evaluate the child
+ /// </param>
+ /// <remarks>
+ /// This method can be used to get a member of an object (such as a field or property)
+ /// </remarks>
+ public ObjectValue GetChild (string name, EvaluationOptions options)
+ {
+ if (IsArray)
+ throw new InvalidOperationException ("Object is an array.");
+ if (IsEvaluating)
+ return null;
+
+ if (children == null) {
+ children = new List<ObjectValue> ();
+ if (source != null) {
+ try {
+ ObjectValue[] cs = source.GetChildren (path, -1, -1, options);
+ ConnectCallbacks (parentFrame, cs);
+ children.AddRange (cs);
+ } catch (Exception ex) {
+ children = null;
+ return CreateFatalError ("", ex.Message, ObjectValueFlags.ReadOnly);
+ }
+ }
+ }
+
+ foreach (ObjectValue ob in children) {
+ if (ob.Name == name)
+ return ob;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets all children of the object
+ /// </summary>
+ /// <returns>
+ /// An array of all child values
+ /// </returns>
+ public ObjectValue[] GetAllChildren ()
+ {
+ return GetAllChildren (parentFrame.DebuggerSession.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Gets all children of the object
+ /// </summary>
+ /// <returns>
+ /// An array of all child values
+ /// </returns>
+ /// <param name='options'>
+ /// Options to be used to evaluate the children
+ /// </param>
+ public ObjectValue[] GetAllChildren (EvaluationOptions options)
+ {
+ if (IsEvaluating)
+ return new ObjectValue[0];
+
+ if (IsArray) {
+ GetArrayItem (arrayCount - 1);
+ return children.ToArray ();
+ }
+
+ if (children == null) {
+ children = new List<ObjectValue> ();
+ if (source != null) {
+ try {
+ ObjectValue[] cs = source.GetChildren (path, -1, -1, options);
+ ConnectCallbacks (parentFrame, cs);
+ children.AddRange (cs);
+ } catch (Exception ex) {
+ if (parentFrame != null)
+ parentFrame.DebuggerSession.OnDebuggerOutput (true, ex.ToString ());
+ children.Add (CreateFatalError ("", ex.Message, ObjectValueFlags.ReadOnly));
+ }
+ }
+ }
+
+ return children.ToArray ();
+ }
+
+ /// <summary>
+ /// Gets an item of an array
+ /// </summary>
+ /// <returns>
+ /// The array item.
+ /// </returns>
+ /// <param name='index'>
+ /// Item index
+ /// </param>
+ /// <exception cref='InvalidOperationException'>
+ /// Is thrown if this object is not an array (IsArray returns false)
+ /// </exception>
+ public ObjectValue GetArrayItem (int index)
+ {
+ return GetArrayItem (index, parentFrame.DebuggerSession.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Gets an item of an array
+ /// </summary>
+ /// <returns>
+ /// The array item.
+ /// </returns>
+ /// <param name='index'>
+ /// Item index
+ /// </param>
+ /// <param name='options'>
+ /// Options to be used to evaluate the item
+ /// </param>
+ /// <exception cref='InvalidOperationException'>
+ /// Is thrown if this object is not an array (IsArray returns false)
+ /// </exception>
+ public ObjectValue GetArrayItem (int index, EvaluationOptions options)
+ {
+ if (!IsArray)
+ throw new InvalidOperationException ("Object is not an array.");
+ if (index >= arrayCount || index < 0 || IsEvaluating)
+ throw new IndexOutOfRangeException ();
+
+ if (children == null)
+ children = new List<ObjectValue> ();
+ if (index >= children.Count) {
+ int nc = (index + 50);
+ if (nc > arrayCount) nc = arrayCount;
+ nc = nc - children.Count;
+ try {
+ ObjectValue[] items = source.GetChildren (path, children.Count, nc, options);
+ ConnectCallbacks (parentFrame, items);
+ children.AddRange (items);
+ } catch (Exception ex) {
+ return CreateFatalError ("", ex.Message, ObjectValueFlags.ArrayElement | ObjectValueFlags.ReadOnly);
+ }
+ }
+ return children [index];
+ }
+
+ /// <summary>
+ /// Gets the number of items of an array
+ /// </summary>
+ /// <exception cref='InvalidOperationException'>
+ /// Is thrown if this object is not an array (IsArray returns false)
+ /// </exception>
+ public int ArrayCount {
+ get {
+ if (!IsArray)
+ throw new InvalidOperationException ("Object is not an array.");
+ if (IsEvaluating)
+ return 0;
+ return arrayCount;
+ }
+ }
+
+ public bool IsReadOnly {
+ get { return HasFlag (ObjectValueFlags.ReadOnly); }
+ }
+
+ public bool IsArray {
+ get { return HasFlag (ObjectValueFlags.Array); }
+ }
+
+ public bool IsObject {
+ get { return HasFlag (ObjectValueFlags.Object); }
+ }
+
+ public bool IsPrimitive {
+ get { return HasFlag (ObjectValueFlags.Primitive); }
+ }
+
+ public bool IsUnknown {
+ get { return HasFlag (ObjectValueFlags.Unknown); }
+ }
+
+ public bool IsNotSupported {
+ get { return HasFlag (ObjectValueFlags.NotSupported); }
+ }
+
+ public bool IsError {
+ get { return HasFlag (ObjectValueFlags.Error); }
+ }
+
+ public bool IsEvaluating {
+ get { return HasFlag (ObjectValueFlags.Evaluating); }
+ }
+
+ public bool IsEvaluatingGroup {
+ get { return HasFlag (ObjectValueFlags.EvaluatingGroup); }
+ }
+
+ public bool CanRefresh {
+ get { return source != null && !HasFlag (ObjectValueFlags.NoRefresh); }
+ }
+
+ public bool HasFlag (ObjectValueFlags flag)
+ {
+ return (flags & flag) != 0;
+ }
+
+ public event EventHandler ValueChanged {
+ add {
+ lock (this) {
+ if (IsEvaluating)
+ valueChanged += value;
+ else
+ value (this, EventArgs.Empty);
+ }
+ }
+ remove {
+ lock (this) {
+ valueChanged -= value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Refreshes the value of this object
+ /// </summary>
+ /// <remarks>
+ /// This method can be called to get a more up-to-date value for this object.
+ /// </remarks>
+ public void Refresh ()
+ {
+ Refresh (parentFrame.DebuggerSession.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Refreshes the value of this object
+ /// </summary>
+ /// <remarks>
+ /// This method can be called to get a more up-to-date value for this object.
+ /// </remarks>
+ public void Refresh (EvaluationOptions options)
+ {
+ if (!CanRefresh)
+ return;
+ ObjectValue val = source.GetValue (path, options);
+ UpdateFrom (val, false);
+ }
+
+ /// <summary>
+ /// Gets a wait handle which can be used to wait for the evaluation of this object to end
+ /// </summary>
+ /// <value>
+ /// The wait handle.
+ /// </value>
+ public WaitHandle WaitHandle {
+ get {
+ lock (this) {
+ if (evaluatedEvent == null)
+ evaluatedEvent = new ManualResetEvent (!IsEvaluating);
+ return evaluatedEvent;
+ }
+ }
+ }
+
+ internal IObjectValueUpdater Updater {
+ get { return updater; }
+ }
+
+ internal void UpdateFrom (ObjectValue val, bool notify)
+ {
+ lock (this) {
+ arrayCount = val.arrayCount;
+ if (val.name != null)
+ name = val.name;
+ value = val.value;
+ displayValue = val.displayValue;
+ typeName = val.typeName;
+ flags = val.flags;
+ source = val.source;
+ children = val.children;
+ path = val.path;
+ updater = val.updater;
+ ConnectCallbacks (parentFrame, this);
+ if (evaluatedEvent != null)
+ evaluatedEvent.Set ();
+ if (notify && valueChanged != null)
+ valueChanged (this, EventArgs.Empty);
+ }
+ }
+
+ internal UpdateCallback GetUpdateCallback ()
+ {
+ if (IsEvaluating) {
+ if (updateCallback == null)
+ updateCallback = new UpdateCallback (new UpdateCallbackProxy (this), path);
+ return updateCallback;
+ }
+
+ return null;
+ }
+
+ ~ObjectValue ()
+ {
+ if (updateCallback != null)
+ System.Runtime.Remoting.RemotingServices.Disconnect ((UpdateCallbackProxy)updateCallback.Callback);
+ }
+
+ internal static void ConnectCallbacks (StackFrame parentFrame, params ObjectValue[] values)
+ {
+ Dictionary<IObjectValueUpdater, List<UpdateCallback>> callbacks = null;
+ List<ObjectValue> valueList = new List<ObjectValue> (values);
+ for (int n=0; n<valueList.Count; n++) {
+ ObjectValue val = valueList [n];
+ val.source = parentFrame.DebuggerSession.WrapDebuggerObject (val.source);
+ val.updater = parentFrame.DebuggerSession.WrapDebuggerObject (val.updater);
+ val.parentFrame = parentFrame;
+ UpdateCallback cb = val.GetUpdateCallback ();
+ if (cb != null) {
+ if (callbacks == null)
+ callbacks = new Dictionary<IObjectValueUpdater, List<UpdateCallback>> ();
+ List<UpdateCallback> list;
+ if (!callbacks.TryGetValue (val.Updater, out list)) {
+ list = new List<UpdateCallback> ();
+ callbacks [val.Updater] = list;
+ }
+ list.Add (cb);
+ }
+ if (val.children != null)
+ valueList.AddRange (val.children);
+ }
+ if (callbacks != null) {
+ // Do the callback connection in a background thread
+ ThreadPool.QueueUserWorkItem (delegate {
+ foreach (KeyValuePair<IObjectValueUpdater, List<UpdateCallback>> cbs in callbacks) {
+ cbs.Key.RegisterUpdateCallbacks (cbs.Value.ToArray ());
+ }
+ });
+ }
+ }
+ }
+
+ class UpdateCallbackProxy: MarshalByRefObject, IObjectValueUpdateCallback
+ {
+ readonly WeakReference valRef;
+
+ public void UpdateValue (ObjectValue newValue)
+ {
+ ObjectValue val = valRef.Target as ObjectValue;
+ if (val != null)
+ val.UpdateFrom (newValue, true);
+ }
+
+ public UpdateCallbackProxy (ObjectValue val)
+ {
+ valRef = new WeakReference (val);
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ObjectValueFlags.cs b/Mono.Debugging/Mono.Debugging.Client/ObjectValueFlags.cs
new file mode 100644
index 0000000..9157e26
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ObjectValueFlags.cs
@@ -0,0 +1,71 @@
+// ObjectValueKind.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ [Flags]
+ public enum ObjectValueFlags: uint {
+ None = 0,
+ Object = 1, // The value is an object
+ Array = 1 << 1, // The value is an array
+ Primitive = 1 << 2, // The value is a primitive value
+ Unknown = 1 << 3, // The evaluated identifier is unknown
+ Error = 1 << 4, // The expression evaluation returned an error
+ NotSupported = 1 << 5, // The expression is valid but its evaluation is not supported
+ Evaluating = 1 << 6, // The expression is being evaluated. The value will be updated when done.
+ KindMask = 0x000000ff,
+
+ Field = 1 << 8,
+ Property = 1 << 9,
+ Parameter = 1 << 10,
+ Variable = 1 << 11,
+ ArrayElement = 1 << 12,
+ Method = 1 << 13,
+ Literal = 1 << 14,
+ Type = 1 << 15,
+ Namespace = 1 << 16,
+ Group = 1 << 17,
+ OriginMask = 0x0003ff00,
+
+ Global = 1 << 18, // For fields, it means static
+ ReadOnly = 1 << 19,
+ NoRefresh = 1 << 20, // When set, this value can't be refreshed
+ EvaluatingGroup = 1 << 21, // When set, this value represents a set of values being evaluated
+ // When evaluation ends, the value is updated, and the children are the
+ // values represented by this group
+
+ // For field and property
+ Public = 1 << 24,
+ Protected = 1 << 25,
+ Internal = 1 << 26,
+ Private = 1 << 27,
+ InternalProtected = Internal | Protected,
+ AccessMask = Public | Protected | Internal | Private
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ProcessEventArgs.cs b/Mono.Debugging/Mono.Debugging.Client/ProcessEventArgs.cs
new file mode 100644
index 0000000..7c9aec8
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ProcessEventArgs.cs
@@ -0,0 +1,47 @@
+// ProcessEventArgs.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ public class ProcessEventArgs: EventArgs
+ {
+ int processId;
+
+ public int ProcessId {
+ get {
+ return processId;
+ }
+ }
+
+ public ProcessEventArgs (int processId)
+ {
+ this.processId = processId;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ProcessInfo.cs b/Mono.Debugging/Mono.Debugging.Client/ProcessInfo.cs
new file mode 100644
index 0000000..a972965
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ProcessInfo.cs
@@ -0,0 +1,78 @@
+// ProcessInfo.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ [Serializable]
+ public class ProcessInfo
+ {
+ long id;
+ string name;
+
+ [NonSerialized]
+ ThreadInfo[] currentThreads;
+
+ [NonSerialized]
+ DebuggerSession session;
+
+ internal void Attach (DebuggerSession session)
+ {
+ this.session = session;
+ if (currentThreads != null) {
+ foreach (ThreadInfo t in currentThreads)
+ t.Attach (session);
+ }
+ }
+
+ public long Id {
+ get {
+ return id;
+ }
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public ProcessInfo (long id, string name)
+ {
+ this.id = id;
+ this.name = name;
+ }
+
+ public ThreadInfo[] GetThreads ()
+ {
+ if (currentThreads == null)
+ currentThreads = session.GetThreads (id);
+ return currentThreads;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/RawValue.cs b/Mono.Debugging/Mono.Debugging.Client/RawValue.cs
new file mode 100644
index 0000000..b74a403
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/RawValue.cs
@@ -0,0 +1,280 @@
+//
+// RawValue.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2010 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 Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Client
+{
+ /// <summary>
+ /// Represents an object in the process being debugged
+ /// </summary>
+ [Serializable]
+ public class RawValue: IRawObject
+ {
+ IRawValue source;
+ EvaluationOptions options;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Mono.Debugging.Client.RawValue"/> class.
+ /// </summary>
+ /// <param name='source'>
+ /// Value source
+ /// </param>
+ public RawValue (IRawValue source)
+ {
+ this.source = source;
+ }
+
+ void IRawObject.Connect (DebuggerSession session, EvaluationOptions options)
+ {
+ this.options = options;
+ source = session.WrapDebuggerObject (source);
+ }
+
+ internal IRawValue Source {
+ get { return this.source; }
+ }
+
+ /// <summary>
+ /// Full name of the type of the object
+ /// </summary>
+ public string TypeName { get; set; }
+
+ /// <summary>
+ /// Invokes a method on the object
+ /// </summary>
+ /// <returns>
+ /// The result of the invocation
+ /// </returns>
+ /// <param name='methodName'>
+ /// The name of the method
+ /// </param>
+ /// <param name='parameters'>
+ /// The parameters (primitive type values, RawValue instances or RawValueArray instances)
+ /// </param>
+ public object CallMethod (string methodName, params object[] parameters)
+ {
+ object res = source.CallMethod (methodName, parameters, options);
+ RawValue val = res as RawValue;
+ if (val != null)
+ val.options = options;
+ return res;
+ }
+
+ /// <summary>
+ /// Gets the value of a field or property
+ /// </summary>
+ /// <returns>
+ /// The value (a primitive type value, a RawValue instance or a RawValueArray instance)
+ /// </returns>
+ /// <param name='name'>
+ /// Name of the field or property
+ /// </param>
+ public object GetMemberValue (string name)
+ {
+ object res = source.GetMemberValue (name, options);
+ RawValue val = res as RawValue;
+ if (val != null)
+ val.options = options;
+ return res;
+ }
+
+ /// <summary>
+ /// Sets the value of a field or property
+ /// </summary>
+ /// <param name='name'>
+ /// Name of the field or property
+ /// </param>
+ /// <param name='value'>
+ /// The value (a primitive type value, a RawValue instance or a RawValueArray instance)
+ /// </param>
+ public void SetMemberValue (string name, object value)
+ {
+ source.SetMemberValue (name, value, options);
+ }
+ }
+
+ /// <summary>
+ /// Represents an array of objects in the process being debugged
+ /// </summary>
+ [Serializable]
+ public class RawValueArray: IRawObject
+ {
+ IRawValueArray source;
+ int[] dimensions;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Mono.Debugging.Client.RawValueArray"/> class.
+ /// </summary>
+ /// <param name='source'>
+ /// Value source.
+ /// </param>
+ public RawValueArray (IRawValueArray source)
+ {
+ this.source = source;
+ }
+
+ void IRawObject.Connect (DebuggerSession session, EvaluationOptions options)
+ {
+ source = session.WrapDebuggerObject (source);
+ }
+
+ internal IRawValueArray Source {
+ get { return this.source; }
+ }
+
+ /// <summary>
+ /// Full type name of the array items
+ /// </summary>
+ public string ElementTypeName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item at the specified index.
+ /// </summary>
+ /// <param name='index'>
+ /// The index
+ /// </param>
+ /// <remarks>
+ /// The item value can be a primitive type value, a RawValue instance or a RawValueArray instance.
+ /// </remarks>
+ public object this [int index] {
+ get {
+ return source.GetValue (new int[] { index });
+ }
+ set {
+ source.SetValue (new int[] { index }, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets the values.
+ /// </summary>
+ /// <returns>The items.</returns>
+ /// <param name="index">The index.</param>
+ /// <param name="count">The number of items to get.</param>
+ /// <remarks>
+ /// This method is useful for incrementally fetching an array in order to avoid
+ /// long waiting periods when the array is too large for ToArray().
+ /// </remarks>
+ public Array GetValues (int index, int count)
+ {
+ return source.GetValues (new int[] { index }, count);
+ }
+
+ /// <summary>
+ /// Returns an array with all items of the RawValueArray
+ /// </summary>
+ /// <remarks>
+ /// This method is useful to avoid unnecessary debugger-debuggee roundtrips
+ /// when processing all items of an array. For example, if a RawValueArray
+ /// represents an image encoded in a byte[], getting the values one by one
+ /// using the indexer is very slow. The ToArray() will return the whole byte[]
+ /// in a single call.
+ /// </remarks>
+ public Array ToArray ()
+ {
+ return source.ToArray ();
+ }
+
+ /// <summary>
+ /// Gets the length of the array
+ /// </summary>
+ public int Length {
+ get {
+ if (dimensions == null)
+ dimensions = source.Dimensions;
+ return dimensions[0];
+ }
+ }
+ }
+
+ /// <summary>
+ /// Represents a string object in the process being debugged
+ /// </summary>
+ [Serializable]
+ public class RawValueString: IRawObject
+ {
+ IRawValueString source;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Mono.Debugging.Client.RawValueString"/> class.
+ /// </summary>
+ /// <param name='source'>
+ /// Value source.
+ /// </param>
+ public RawValueString (IRawValueString source)
+ {
+ this.source = source;
+ }
+
+ void IRawObject.Connect (DebuggerSession session, EvaluationOptions options)
+ {
+ source = session.WrapDebuggerObject (source);
+ }
+
+ internal IRawValueString Source {
+ get { return this.source; }
+ }
+
+ /// <summary>
+ /// Gets the length of the string
+ /// </summary>
+ public int Length {
+ get { return source.Length; }
+ }
+
+ /// <summary>
+ /// Gets a substring of the string
+ /// </summary>
+ /// <param name='index'>
+ /// The starting index of the requested substring.
+ /// </param>
+ /// <param name='length'>
+ /// The length of the requested substring.
+ /// </param>
+ public string Substring (int index, int length)
+ {
+ return source.Substring (index, length);
+ }
+
+ /// <summary>
+ /// Gets the value.
+ /// </summary>
+ /// <value>
+ /// The value.
+ /// </value>
+ public string Value {
+ get { return source.Value; }
+ }
+ }
+
+ internal interface IRawObject
+ {
+ void Connect (DebuggerSession session, EvaluationOptions options);
+ }
+}
+
diff --git a/Mono.Debugging/Mono.Debugging.Client/SourceLocation.cs b/Mono.Debugging/Mono.Debugging.Client/SourceLocation.cs
new file mode 100644
index 0000000..717eb9b
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/SourceLocation.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class SourceLocation
+ {
+ public string MethodName { get; private set; }
+ public string FileName { get; private set; }
+ public int Line { get; private set; }
+ public int Column { get; private set; }
+
+ public SourceLocation (string methodName, string fileName, int line)
+ : this (methodName, fileName, line, -1)
+ {
+ }
+
+ public SourceLocation (string methodName, string fileName, int line, int column)
+ {
+ this.MethodName = methodName;
+ this.FileName = fileName;
+ this.Line = line;
+ this.Column = column;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format("[SourceLocation Method={0}, Filename={1}, Line={2}, Column={3}]", MethodName, FileName, Line, Column);
+ }
+
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/StackFrame.cs b/Mono.Debugging/Mono.Debugging.Client/StackFrame.cs
new file mode 100644
index 0000000..b1e16ad
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/StackFrame.cs
@@ -0,0 +1,313 @@
+using System;
+using Mono.Debugging.Backend;
+using System.Collections.Generic;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class StackFrame
+ {
+ long address;
+ string addressSpace;
+ SourceLocation location;
+ IBacktrace sourceBacktrace;
+ string language;
+ int index;
+ bool isExternalCode;
+ bool isDebuggerHidden;
+ bool hasDebugInfo;
+ string fullModuleName;
+ string fullTypeName;
+
+ [NonSerialized]
+ DebuggerSession session;
+
+ public StackFrame (long address, string addressSpace, SourceLocation location, string language, bool isExternalCode, bool hasDebugInfo, bool isDebuggerHidden, string fullModuleName, string fullTypeName)
+ {
+ this.address = address;
+ this.addressSpace = addressSpace;
+ this.location = location;
+ this.language = language;
+ this.isExternalCode = isExternalCode;
+ this.isDebuggerHidden = isDebuggerHidden;
+ this.hasDebugInfo = hasDebugInfo;
+ this.fullModuleName = fullModuleName;
+ this.fullTypeName = fullTypeName;
+ }
+
+ public StackFrame (long address, string addressSpace, SourceLocation location, string language, bool isExternalCode, bool hasDebugInfo, string fullModuleName, string fullTypeName)
+ : this (address, addressSpace, location, language, isExternalCode, hasDebugInfo, false, fullModuleName, fullTypeName)
+ {
+ }
+
+ public StackFrame (long address, string addressSpace, SourceLocation location, string language)
+ : this (address, addressSpace, location, language, string.IsNullOrEmpty (location.FileName), true, "", "")
+ {
+ }
+
+ public StackFrame (long address, string addressSpace, string module, string method, string filename, int line, string language)
+ : this (address, addressSpace, new SourceLocation (method, filename, line), language)
+ {
+ }
+
+ public StackFrame (long address, SourceLocation location, string language, bool isExternalCode, bool hasDebugInfo)
+ : this (address, "", location, language, string.IsNullOrEmpty (location.FileName), true, "", "")
+ {
+ }
+
+ public StackFrame (long address, SourceLocation location, string language)
+ : this (address, "", location, language, string.IsNullOrEmpty (location.FileName), true, "", "")
+ {
+ }
+
+ internal void Attach (DebuggerSession session)
+ {
+ this.session = session;
+ }
+
+ public DebuggerSession DebuggerSession {
+ get { return session; }
+ }
+
+ public SourceLocation SourceLocation
+ {
+ get { return location; }
+ }
+
+ public long Address
+ {
+ get { return address; }
+ }
+
+ public string AddressSpace {
+ get { return addressSpace; }
+ }
+
+ internal IBacktrace SourceBacktrace {
+ get { return sourceBacktrace; }
+ set { sourceBacktrace = value; }
+ }
+
+ public int Index {
+ get { return index; }
+ internal set { index = value; }
+ }
+
+ public string Language {
+ get {
+ return language;
+ }
+ }
+
+ public bool IsExternalCode {
+ get { return isExternalCode; }
+ }
+
+ public bool IsDebuggerHidden {
+ get { return isDebuggerHidden; }
+ }
+
+ public bool HasDebugInfo {
+ get { return this.hasDebugInfo; }
+ }
+
+ public string FullModuleName {
+ get { return this.fullModuleName; }
+ }
+
+ public string FullTypeName {
+ get { return this.fullTypeName; }
+ }
+
+ public ObjectValue[] GetLocalVariables ()
+ {
+ return GetLocalVariables (session.EvaluationOptions);
+ }
+
+ public ObjectValue[] GetLocalVariables (EvaluationOptions options)
+ {
+ if (!hasDebugInfo)
+ return new ObjectValue [0];
+ ObjectValue[] values = sourceBacktrace.GetLocalVariables (index, options);
+ ObjectValue.ConnectCallbacks (this, values);
+ return values;
+ }
+
+ public ObjectValue[] GetParameters ()
+ {
+ return GetParameters (session.EvaluationOptions);
+ }
+
+ public ObjectValue[] GetParameters (EvaluationOptions options)
+ {
+ if (!hasDebugInfo)
+ return new ObjectValue [0];
+ ObjectValue[] values = sourceBacktrace.GetParameters (index, options);
+ ObjectValue.ConnectCallbacks (this, values);
+ return values;
+ }
+
+ public ObjectValue[] GetAllLocals ()
+ {
+ if (!hasDebugInfo)
+ return new ObjectValue [0];
+ IExpressionEvaluator evaluator = session.FindExpressionEvaluator (this);
+ if (evaluator != null)
+ return evaluator.GetLocals (this);
+ return GetAllLocals (session.EvaluationOptions);
+ }
+
+ public ObjectValue[] GetAllLocals (EvaluationOptions options)
+ {
+ if (!hasDebugInfo)
+ return new ObjectValue [0];
+ ObjectValue[] values = sourceBacktrace.GetAllLocals (index, options);
+ ObjectValue.ConnectCallbacks (this, values);
+ return values;
+ }
+
+ public ObjectValue GetThisReference ()
+ {
+ return GetThisReference (session.EvaluationOptions);
+ }
+
+ public ObjectValue GetThisReference (EvaluationOptions options)
+ {
+ if (!hasDebugInfo)
+ return null;
+ ObjectValue value = sourceBacktrace.GetThisReference (index, options);
+ if (value != null)
+ ObjectValue.ConnectCallbacks (this, value);
+ return value;
+ }
+
+ public ExceptionInfo GetException ()
+ {
+ return GetException (session.EvaluationOptions);
+ }
+
+ public ExceptionInfo GetException (EvaluationOptions options)
+ {
+ if (!hasDebugInfo)
+ return null;
+ ExceptionInfo value = sourceBacktrace.GetException (index, options);
+ if (value != null)
+ value.ConnectCallback (this);
+ return value;
+ }
+
+ public string ResolveExpression (string exp)
+ {
+ return session.ResolveExpression (exp, location);
+ }
+
+ public ObjectValue[] GetExpressionValues (string[] expressions, bool evaluateMethods)
+ {
+ EvaluationOptions options = session.EvaluationOptions.Clone ();
+ options.AllowMethodEvaluation = evaluateMethods;
+ return GetExpressionValues (expressions, options);
+ }
+
+ public ObjectValue[] GetExpressionValues (string[] expressions, EvaluationOptions options)
+ {
+ if (!hasDebugInfo) {
+ ObjectValue[] vals = new ObjectValue [expressions.Length];
+ for (int n=0; n<expressions.Length; n++)
+ vals [n] = ObjectValue.CreateUnknown (expressions [n]);
+ return vals;
+ }
+ if (options.UseExternalTypeResolver) {
+ string[] resolved = new string [expressions.Length];
+ for (int n=0; n<expressions.Length; n++)
+ resolved [n] = ResolveExpression (expressions [n]);
+ expressions = resolved;
+ }
+ ObjectValue[] values = sourceBacktrace.GetExpressionValues (index, expressions, options);
+ ObjectValue.ConnectCallbacks (this, values);
+ return values;
+ }
+
+ public ObjectValue GetExpressionValue (string expression, bool evaluateMethods)
+ {
+ EvaluationOptions options = session.EvaluationOptions.Clone ();
+ options.AllowMethodEvaluation = evaluateMethods;
+ return GetExpressionValue (expression, options);
+ }
+
+ public ObjectValue GetExpressionValue (string expression, EvaluationOptions options)
+ {
+ if (!hasDebugInfo)
+ return ObjectValue.CreateUnknown (expression);
+ if (options.UseExternalTypeResolver)
+ expression = ResolveExpression (expression);
+ ObjectValue[] values = sourceBacktrace.GetExpressionValues (index, new string[] { expression }, options);
+ ObjectValue.ConnectCallbacks (this, values);
+ return values [0];
+ }
+
+ /// <summary>
+ /// Returns True if the expression is valid and can be evaluated for this frame.
+ /// </summary>
+ public bool ValidateExpression (string expression)
+ {
+ return ValidateExpression (expression, session.EvaluationOptions);
+ }
+
+ /// <summary>
+ /// Returns True if the expression is valid and can be evaluated for this frame.
+ /// </summary>
+ public ValidationResult ValidateExpression (string expression, EvaluationOptions options)
+ {
+ if (options.UseExternalTypeResolver)
+ expression = ResolveExpression (expression);
+ return sourceBacktrace.ValidateExpression (index, expression, options);
+ }
+
+ public CompletionData GetExpressionCompletionData (string exp)
+ {
+ if (!hasDebugInfo)
+ return null;
+ return sourceBacktrace.GetExpressionCompletionData (index, exp);
+ }
+
+ // Returns disassembled code for this stack frame.
+ // firstLine is the relative code line. It can be negative.
+ public AssemblyLine[] Disassemble (int firstLine, int count)
+ {
+ return sourceBacktrace.Disassemble (index, firstLine, count);
+ }
+
+ public override string ToString()
+ {
+ string loc;
+ if (location.Line != -1 && !string.IsNullOrEmpty (location.FileName))
+ loc = " at " + location.FileName + ":" + location.Line;
+ else if (!string.IsNullOrEmpty (location.FileName))
+ loc = " at " + location.FileName;
+ else
+ loc = "";
+ return String.Format("0x{0:X} in {1}{2}", address, location.MethodName, loc);
+ }
+ }
+
+ [Serializable]
+ public struct ValidationResult
+ {
+ readonly string message;
+ readonly bool isValid;
+
+ public ValidationResult (bool isValid, string message)
+ {
+ this.isValid = isValid;
+ this.message = message;
+ }
+
+ public bool IsValid { get { return isValid; } }
+ public string Message { get { return message; } }
+
+ public static implicit operator bool (ValidationResult result)
+ {
+ return result.isValid;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/TargetEventArgs.cs b/Mono.Debugging/Mono.Debugging.Client/TargetEventArgs.cs
new file mode 100644
index 0000000..f025dab
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/TargetEventArgs.cs
@@ -0,0 +1,57 @@
+using System;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public class TargetEventArgs: EventArgs
+ {
+ TargetEventType type;
+ Backtrace backtrace;
+ ProcessInfo process;
+ ThreadInfo thread;
+
+ public TargetEventArgs (TargetEventType type)
+ {
+ this.type = type;
+ }
+
+ public TargetEventType Type
+ {
+ get { return type; }
+ set { type = value; }
+ }
+
+ public Backtrace Backtrace
+ {
+ get { return backtrace; }
+ set { backtrace = value; }
+ }
+
+ public ThreadInfo Thread {
+ get {
+ return thread;
+ }
+ set {
+ thread = value;
+ }
+ }
+
+ public ProcessInfo Process {
+ get {
+ return process;
+ }
+ set {
+ process = value;
+ }
+ }
+
+ public bool IsStopEvent {
+ get; set;
+ }
+
+ public BreakEvent BreakEvent {
+ get; set;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/TargetEventType.cs b/Mono.Debugging/Mono.Debugging.Client/TargetEventType.cs
new file mode 100644
index 0000000..f93a6cf
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/TargetEventType.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Mono.Debugging.Client
+{
+ [Serializable]
+ public enum TargetEventType
+ {
+ TargetReady,
+ TargetStopped,
+ TargetInterrupted,
+ TargetHitBreakpoint,
+ TargetSignaled,
+ TargetExited,
+ ExceptionThrown,
+ UnhandledException,
+ ThreadStarted,
+ ThreadStopped
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ThreadEventArgs.cs b/Mono.Debugging/Mono.Debugging.Client/ThreadEventArgs.cs
new file mode 100644
index 0000000..f1d8eb9
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ThreadEventArgs.cs
@@ -0,0 +1,47 @@
+// ThreadEventArgs.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ public class ThreadEventArgs: EventArgs
+ {
+ int threadId;
+
+ public int ThreadId {
+ get {
+ return threadId;
+ }
+ }
+
+ public ThreadEventArgs (int threadId)
+ {
+ this.threadId = threadId;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Client/ThreadInfo.cs b/Mono.Debugging/Mono.Debugging.Client/ThreadInfo.cs
new file mode 100644
index 0000000..78cd0bc
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Client/ThreadInfo.cs
@@ -0,0 +1,135 @@
+// ThreadInfo.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client
+{
+ [Serializable]
+ public class ThreadInfo
+ {
+ long id;
+ string name;
+ long processId;
+ string location;
+ Backtrace backtrace;
+
+ [NonSerialized]
+ DebuggerSession session;
+
+ internal void Attach (DebuggerSession session)
+ {
+ this.session = session;
+ }
+
+ public long Id {
+ get {
+ return id;
+ }
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public string Location {
+ get {
+ if (location == null) {
+ Backtrace bt = Backtrace;
+ if (bt != null && bt.FrameCount > 0)
+ location = bt.GetFrame (0).ToString ();
+ }
+ return location;
+ }
+ }
+
+ internal long ProcessId {
+ get { return processId; }
+ }
+
+ public Backtrace Backtrace {
+ get {
+ if (backtrace == null)
+ backtrace = session.GetBacktrace (processId, id);
+ return backtrace;
+ }
+ }
+
+ public void SetActive ()
+ {
+ session.ActiveThread = this;
+ }
+
+ public ThreadInfo (long processId, long id, string name, string location): this (processId, id, name, location, null)
+ {
+ }
+
+ public ThreadInfo (long processId, long id, string name, string location, Backtrace backtrace)
+ {
+ this.id = id;
+ this.name = name;
+ this.processId = processId;
+ this.location = location;
+ this.backtrace = backtrace;
+ }
+
+ public override bool Equals (object obj)
+ {
+ ThreadInfo ot = obj as ThreadInfo;
+ if (ot == null)
+ return false;
+ return id == ot.id && processId == ot.processId;
+ }
+
+ public override int GetHashCode ()
+ {
+ unchecked {
+ return (int) (id + processId*1000);
+ }
+ }
+
+ public static bool operator == (ThreadInfo t1, ThreadInfo t2)
+ {
+ if (object.ReferenceEquals (t1, t2))
+ return true;
+ if ((object)t1 == null || (object)t2 == null)
+ return false;
+ return t1.Equals (t2);
+ }
+
+ public static bool operator != (ThreadInfo t1, ThreadInfo t2)
+ {
+ if (object.ReferenceEquals (t1, t2))
+ return false;
+ if ((object)t1 == null || (object)t2 == null)
+ return true;
+ return !t1.Equals (t2);
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ArrayElementGroup.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ArrayElementGroup.cs
new file mode 100644
index 0000000..a7b95ed
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ArrayElementGroup.cs
@@ -0,0 +1,359 @@
+// ArrayElementGroup.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at 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.Text;
+using Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class ArrayElementGroup: RemoteFrameObject, IObjectValueSource
+ {
+ EvaluationContext ctx;
+ int[] baseIndices;
+ int firstIndex;
+ int lastIndex;
+ int[] bounds;
+ ICollectionAdaptor array;
+
+ const int MaxChildCount = 150;
+
+ public ArrayElementGroup (EvaluationContext ctx, ICollectionAdaptor array)
+ : this (ctx, array, new int [0])
+ {
+ }
+
+ public ArrayElementGroup (EvaluationContext ctx, ICollectionAdaptor array, int[] baseIndices)
+ : this (ctx, array, baseIndices, 0, -1)
+ {
+ }
+
+ public ArrayElementGroup (EvaluationContext ctx, ICollectionAdaptor array, int[] baseIndices, int firstIndex, int lastIndex)
+ {
+ this.array = array;
+ this.ctx = ctx;
+ this.bounds = array.GetDimensions ();
+ this.baseIndices = baseIndices;
+ this.firstIndex = firstIndex;
+ this.lastIndex = lastIndex;
+ }
+
+ public bool IsRange {
+ get { return lastIndex != -1; }
+ }
+
+ public ObjectValue CreateObjectValue ()
+ {
+ Connect ();
+ StringBuilder sb = new StringBuilder ("[");
+ for (int n=0; n<baseIndices.Length; n++) {
+ if (n > 0)
+ sb.Append (", ");
+ sb.Append (baseIndices [n].ToString ());
+ }
+ if (IsRange) {
+ if (baseIndices.Length > 0)
+ sb.Append (", ");
+ sb.Append (firstIndex.ToString ()).Append ("..").Append (lastIndex.ToString ());
+ }
+ if (bounds.Length > 1 && baseIndices.Length < bounds.Length)
+ sb.Append (", ...");
+
+ sb.Append ("]");
+
+ ObjectValue res = ObjectValue.CreateObject (this, new ObjectPath (sb.ToString ()), "", "", ObjectValueFlags.ArrayElement|ObjectValueFlags.ReadOnly|ObjectValueFlags.NoRefresh, null);
+ res.ChildSelector = "";
+ return res;
+ }
+
+ public ObjectValue[] GetChildren (EvaluationOptions options)
+ {
+ return GetChildren (new ObjectPath ("this"), -1, -1, options);
+ }
+
+ public ObjectValue[] GetChildren (ObjectPath path, int firstItemIndex, int count, EvaluationOptions options)
+ {
+ EvaluationContext cctx = ctx.WithOptions (options);
+ if (path.Length > 1) {
+ // Looking for children of an array element
+ int[] idx = StringToIndices (path [1]);
+ object obj = array.GetElement (idx);
+ return cctx.Adapter.GetObjectValueChildren (cctx, new ArrayObjectSource (array, path[1]), obj, firstItemIndex, count);
+ }
+
+ int lowerBound;
+ int upperBound;
+ bool isLastDimension;
+
+ if (bounds.Length > 1) {
+ int rank = baseIndices.Length;
+ lowerBound = 0;
+ upperBound = bounds [rank] - 1;
+ isLastDimension = rank == bounds.Length - 1;
+ } else {
+ lowerBound = 0;
+ upperBound = bounds [0] - 1;
+ isLastDimension = true;
+ }
+
+ int len;
+ int initalIndex;
+
+ if (!IsRange) {
+ initalIndex = lowerBound;
+ len = upperBound + 1;
+ }
+ else {
+ initalIndex = firstIndex;
+ len = lastIndex - firstIndex + 1;
+ }
+
+ if (firstItemIndex == -1) {
+ firstItemIndex = 0;
+ count = len;
+ }
+
+ // Make sure the group doesn't have too many elements. If so, divide
+ int div = 1;
+ while (len / div > MaxChildCount)
+ div *= 10;
+
+ if (div == 1 && isLastDimension) {
+ // Return array elements
+
+ ObjectValue[] values = new ObjectValue [count];
+ ObjectPath newPath = new ObjectPath ("this");
+
+ int[] curIndex = new int [baseIndices.Length + 1];
+ Array.Copy (baseIndices, curIndex, baseIndices.Length);
+ string curIndexStr = IndicesToString (baseIndices);
+ if (baseIndices.Length > 0) curIndexStr += ",";
+
+ for (int n=0; n < values.Length; n++) {
+ int index = n + initalIndex + firstItemIndex;
+ string sidx = curIndexStr + index.ToString ();
+ ObjectValue val;
+ string ename = "[" + sidx.Replace (",",", ") + "]";
+ if (index > upperBound)
+ val = ObjectValue.CreateUnknown (sidx);
+ else {
+ curIndex [curIndex.Length - 1] = index;
+ object elem = array.GetElement (curIndex);
+ val = cctx.Adapter.CreateObjectValue (cctx, this, newPath.Append (sidx), elem, ObjectValueFlags.ArrayElement);
+ if (elem != null && !cctx.Adapter.IsNull (cctx, elem)) {
+ TypeDisplayData tdata = cctx.Adapter.GetTypeDisplayData (cctx, cctx.Adapter.GetValueType (cctx, elem));
+ if (!string.IsNullOrEmpty (tdata.NameDisplayString))
+ ename = cctx.Adapter.EvaluateDisplayString (cctx, elem, tdata.NameDisplayString);
+ }
+ }
+ val.Name = ename;
+ values [n] = val;
+ }
+ return values;
+ }
+ else if (!isLastDimension && div == 1) {
+ // Return an array element group for each index
+
+ List<ObjectValue> list = new List<ObjectValue> ();
+ for (int i=0; i<count; i++) {
+ int index = i + initalIndex + firstItemIndex;
+ ObjectValue val;
+
+ // This array must be created at every call to avoid sharing
+ // changes with all array groups
+ int[] curIndex = new int [baseIndices.Length + 1];
+ Array.Copy (baseIndices, curIndex, baseIndices.Length);
+ curIndex [curIndex.Length - 1] = index;
+
+ if (index > upperBound)
+ val = ObjectValue.CreateUnknown ("");
+ else {
+ ArrayElementGroup grp = new ArrayElementGroup (cctx, array, curIndex);
+ val = grp.CreateObjectValue ();
+ }
+ list.Add (val);
+ }
+ return list.ToArray ();
+ }
+ else {
+ // Too many elements. Split the array.
+
+ // Don't make divisions of 10 elements, min is 100
+ if (div == 10)
+ div = 100;
+
+ // Create the child groups
+ int i = initalIndex + firstItemIndex;
+ len += i;
+ List<ObjectValue> list = new List<ObjectValue> ();
+ while (i < len) {
+ int end = i + div - 1;
+ if (end > len)
+ end = len - 1;
+ ArrayElementGroup grp = new ArrayElementGroup (cctx, array, baseIndices, i, end);
+ list.Add (grp.CreateObjectValue ());
+ i += div;
+ }
+ return list.ToArray ();
+ }
+ }
+
+ internal static string IndicesToString (int[] indices)
+ {
+ StringBuilder sb = new StringBuilder ();
+ for (int n=0; n<indices.Length; n++) {
+ if (n > 0)
+ sb.Append (',');
+ sb.Append (indices [n].ToString ());
+ }
+ return sb.ToString ();
+ }
+
+ internal static int[] StringToIndices (string str)
+ {
+ string[] sidx = str.Split (',');
+ int[] idx = new int [sidx.Length];
+ for (int n=0; n<sidx.Length; n++)
+ idx [n] = int.Parse (sidx [n]);
+ return idx;
+ }
+
+ public static string GetArrayDescription (int[] bounds)
+ {
+ if (bounds.Length == 0)
+ return "[...]";
+
+ StringBuilder sb = new StringBuilder ("[");
+ for (int n=0; n<bounds.Length; n++) {
+ if (n > 0)
+ sb.Append (", ");
+ sb.Append (bounds [n].ToString ());
+ }
+ sb.Append ("]");
+ return sb.ToString ();
+ }
+
+ public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
+ {
+ if (path.Length != 2)
+ throw new NotSupportedException ();
+
+ int[] idx = StringToIndices (path [1]);
+
+ object val;
+ try {
+ EvaluationContext cctx = ctx.Clone ();
+ EvaluationOptions ops = options ?? cctx.Options;
+ ops.AllowMethodEvaluation = true;
+ ops.AllowTargetInvoke = true;
+ cctx.Options = ops;
+ ValueReference var = ctx.Evaluator.Evaluate (ctx, value, array.ElementType);
+ val = var.Value;
+ val = ctx.Adapter.Convert (ctx, val, array.ElementType);
+ array.SetElement (idx, val);
+ } catch {
+ val = array.GetElement (idx);
+ }
+ try {
+ return ctx.Evaluator.TargetObjectToExpression (ctx, val);
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ return new EvaluationResult ("? (" + ex.Message + ")");
+ }
+ }
+
+ public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
+ {
+ if (path.Length != 2)
+ throw new NotSupportedException ();
+
+ int[] idx = StringToIndices (path [1]);
+ object elem = array.GetElement (idx);
+ EvaluationContext cctx = ctx.WithOptions (options);
+ ObjectValue val = cctx.Adapter.CreateObjectValue (cctx, this, path, elem, ObjectValueFlags.ArrayElement);
+ if (elem != null && !cctx.Adapter.IsNull (cctx, elem)) {
+ TypeDisplayData tdata = cctx.Adapter.GetTypeDisplayData (cctx, cctx.Adapter.GetValueType (cctx, elem));
+ if (!string.IsNullOrEmpty (tdata.NameDisplayString))
+ val.Name = cctx.Adapter.EvaluateDisplayString (cctx, elem, tdata.NameDisplayString);
+ }
+ return val;
+ }
+
+ public object GetRawValue (ObjectPath path, EvaluationOptions options)
+ {
+ if (path.Length != 2)
+ throw new NotSupportedException ();
+
+ int[] idx = StringToIndices (path [1]);
+ object elem = array.GetElement (idx);
+ EvaluationContext cctx = ctx.WithOptions (options);
+ return cctx.Adapter.ToRawValue (cctx, new ArrayObjectSource (array, idx), elem);
+ }
+
+ public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
+ {
+ if (path.Length != 2)
+ throw new NotSupportedException ();
+
+ int[] idx = StringToIndices (path [1]);
+
+ EvaluationContext cctx = ctx.WithOptions (options);
+ object val = cctx.Adapter.FromRawValue (cctx, value);
+ array.SetElement (idx, val);
+ }
+ }
+
+ class ArrayObjectSource: IObjectSource
+ {
+ ICollectionAdaptor source;
+ string path;
+
+ public ArrayObjectSource (ICollectionAdaptor source, string path)
+ {
+ this.source = source;
+ this.path = path;
+ }
+
+ public ArrayObjectSource (ICollectionAdaptor source, int[] index)
+ {
+ this.source = source;
+ this.path = ArrayElementGroup.IndicesToString (index);
+ }
+
+ public object Value {
+ get {
+ return source.GetElement (ArrayElementGroup.StringToIndices (path));
+ }
+ set {
+ source.SetElement (ArrayElementGroup.StringToIndices (path), value);
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ArrayValueReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ArrayValueReference.cs
new file mode 100644
index 0000000..58eb286
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ArrayValueReference.cs
@@ -0,0 +1,79 @@
+// ArrayValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Text;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class ArrayValueReference: ValueReference
+ {
+ readonly ICollectionAdaptor adaptor;
+ readonly int[] indices;
+
+ public ArrayValueReference (EvaluationContext ctx, object arr, int[] indices) : base (ctx)
+ {
+ this.indices = indices;
+ adaptor = ctx.Adapter.CreateArrayAdaptor (ctx, arr);
+ }
+
+ public override object Value {
+ get {
+ return adaptor.GetElement (indices);
+ }
+ set {
+ adaptor.SetElement (indices, value);
+ }
+ }
+
+ public override string Name {
+ get {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append ('[');
+ for (int n=0; n<indices.Length; n++) {
+ if (n > 0) sb.Append (", ");
+ sb.Append (indices [n]);
+ }
+ sb.Append (']');
+ return sb.ToString ();
+ }
+ }
+
+ public override object Type {
+ get {
+ return adaptor.ElementType;
+ }
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.ArrayElement;
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs b/Mono.Debugging/Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs
new file mode 100644
index 0000000..40c568e
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs
@@ -0,0 +1,147 @@
+// AsyncEvaluationTracker.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Evaluation
+{
+ public delegate ObjectValue ObjectEvaluatorDelegate ();
+
+ /// <summary>
+ /// This class can be used to generate an ObjectValue using a provided evaluation delegate.
+ /// The value is initialy evaluated synchronously (blocking the caller). If no result
+ /// is obtained after a short period (provided in the WaitTime property), evaluation
+ /// will then be made asynchronous and the Run method will immediately return an ObjectValue
+ /// with the Evaluating state.
+ /// </summary>
+ public class AsyncEvaluationTracker: RemoteFrameObject, IObjectValueUpdater, IDisposable
+ {
+ Dictionary<string, UpdateCallback> asyncCallbacks = new Dictionary<string, UpdateCallback> ();
+ Dictionary<string, ObjectValue> asyncResults = new Dictionary<string, ObjectValue> ();
+ int asyncCounter = 0;
+ int cancelTimestamp = 0;
+ TimedEvaluator runner = new TimedEvaluator ();
+
+ public int WaitTime {
+ get { return runner.RunTimeout; }
+ set { runner.RunTimeout = value; }
+ }
+
+ public bool IsEvaluating {
+ get { return runner.IsEvaluating; }
+ }
+
+ public ObjectValue Run (string name, ObjectValueFlags flags, ObjectEvaluatorDelegate evaluator)
+ {
+ string id;
+ int tid;
+ lock (asyncCallbacks) {
+ tid = asyncCounter++;
+ id = tid.ToString ();
+ }
+
+ ObjectValue val = null;
+ bool done = runner.Run (delegate {
+ if (tid >= cancelTimestamp)
+ val = evaluator ();
+ },
+ delegate {
+ if (tid >= cancelTimestamp)
+ OnEvaluationDone (id, val);
+ });
+
+ if (done)
+ return val ?? ObjectValue.CreateUnknown (name);
+ // 'val' may be null if the timed evaluator is disposed while evaluating
+ else
+ return ObjectValue.CreateEvaluating (this, new ObjectPath (id, name), flags);
+ }
+
+ public void Dispose ()
+ {
+ runner.Dispose ();
+ }
+
+
+ public void Stop ()
+ {
+ lock (asyncCallbacks) {
+ cancelTimestamp = asyncCounter;
+ runner.CancelAll ();
+ foreach (var cb in asyncCallbacks.Values) {
+ try {
+ cb.UpdateValue (ObjectValue.CreateFatalError ("", "Canceled", ObjectValueFlags.None));
+ } catch {
+ }
+ }
+ asyncCallbacks.Clear ();
+ asyncResults.Clear ();
+ }
+ }
+
+ public void WaitForStopped ()
+ {
+ runner.WaitForStopped ();
+ }
+
+ void OnEvaluationDone (string id, ObjectValue val)
+ {
+ if (val == null)
+ val = ObjectValue.CreateUnknown (null);
+ UpdateCallback cb = null;
+ lock (asyncCallbacks) {
+ if (asyncCallbacks.TryGetValue (id, out cb)) {
+ try {
+ cb.UpdateValue (val);
+ } catch {}
+ asyncCallbacks.Remove (id);
+ }
+ else
+ asyncResults [id] = val;
+ }
+ }
+
+ void IObjectValueUpdater.RegisterUpdateCallbacks (UpdateCallback[] callbacks)
+ {
+ foreach (UpdateCallback c in callbacks) {
+ lock (asyncCallbacks) {
+ ObjectValue val;
+ string id = c.Path[0];
+ if (asyncResults.TryGetValue (id, out val)) {
+ c.UpdateValue (val);
+ asyncResults.Remove (id);
+ } else {
+ asyncCallbacks [id] = c;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/AsyncOperationManager.cs b/Mono.Debugging/Mono.Debugging.Evaluation/AsyncOperationManager.cs
new file mode 100644
index 0000000..ea69b74
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/AsyncOperationManager.cs
@@ -0,0 +1,241 @@
+// RuntimeInvokeManager.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 ST = System.Threading;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class AsyncOperationManager: IDisposable
+ {
+ List<AsyncOperation> operationsToCancel = new List<AsyncOperation> ();
+ internal bool Disposing;
+
+ public void Invoke (AsyncOperation methodCall, int timeout)
+ {
+ methodCall.Aborted = false;
+ methodCall.Manager = this;
+
+ lock (operationsToCancel) {
+ operationsToCancel.Add (methodCall);
+ methodCall.Invoke ();
+ }
+
+ if (timeout > 0) {
+ if (!methodCall.WaitForCompleted (timeout)) {
+ bool wasAborted = methodCall.Aborted;
+ methodCall.InternalAbort ();
+ lock (operationsToCancel) {
+ operationsToCancel.Remove (methodCall);
+ ST.Monitor.PulseAll (operationsToCancel);
+ }
+ if (wasAborted)
+ throw new EvaluatorAbortedException ();
+ else
+ throw new TimeOutException ();
+ }
+ }
+ else {
+ methodCall.WaitForCompleted (System.Threading.Timeout.Infinite);
+ }
+
+ lock (operationsToCancel) {
+ operationsToCancel.Remove (methodCall);
+ ST.Monitor.PulseAll (operationsToCancel);
+ if (methodCall.Aborted) {
+ throw new EvaluatorAbortedException ();
+ }
+ }
+
+ if (!string.IsNullOrEmpty (methodCall.ExceptionMessage)) {
+ throw new Exception (methodCall.ExceptionMessage);
+ }
+ }
+
+ public void Dispose ()
+ {
+ Disposing = true;
+ lock (operationsToCancel) {
+ foreach (AsyncOperation op in operationsToCancel) {
+ op.InternalShutdown ();
+ }
+ operationsToCancel.Clear ();
+ }
+ }
+
+ public void AbortAll ()
+ {
+ lock (operationsToCancel) {
+ foreach (AsyncOperation op in operationsToCancel)
+ op.InternalAbort ();
+ }
+ }
+
+ public void EnterBusyState (AsyncOperation oper)
+ {
+ BusyStateEventArgs args = new BusyStateEventArgs ();
+ args.IsBusy = true;
+ args.Description = oper.Description;
+ if (BusyStateChanged != null)
+ BusyStateChanged (this, args);
+ }
+
+ public void LeaveBusyState (AsyncOperation oper)
+ {
+ BusyStateEventArgs args = new BusyStateEventArgs ();
+ args.IsBusy = false;
+ args.Description = oper.Description;
+ if (BusyStateChanged != null)
+ BusyStateChanged (this, args);
+ }
+
+ public event EventHandler<BusyStateEventArgs> BusyStateChanged;
+ }
+
+ public abstract class AsyncOperation
+ {
+ internal bool Aborted;
+ internal AsyncOperationManager Manager;
+
+ public bool Aborting { get; internal set; }
+
+ internal void InternalAbort ()
+ {
+ ST.Monitor.Enter (this);
+ if (Aborted) {
+ ST.Monitor.Exit (this);
+ return;
+ }
+
+ if (Aborting) {
+ // Somebody else is aborting this. Just wait for it to finish.
+ ST.Monitor.Exit (this);
+ WaitForCompleted (ST.Timeout.Infinite);
+ return;
+ }
+
+ Aborting = true;
+
+ int abortState = 0;
+ int abortRetryWait = 100;
+ bool abortRequested = false;
+
+ do {
+ if (abortState > 0)
+ ST.Monitor.Enter (this);
+
+ try {
+ if (!Aborted && !abortRequested) {
+ // The Abort() call doesn't block. WaitForCompleted is used below to wait for the abort to succeed
+ Abort ();
+ abortRequested = true;
+ }
+ // Short wait for the Abort to finish. If this wait is not enough, it will wait again in the next loop
+ if (WaitForCompleted (100)) {
+ ST.Monitor.Exit (this);
+ break;
+ }
+ } catch {
+ // If abort fails, try again after a short wait
+ }
+ abortState++;
+ if (abortState == 6) {
+ // Several abort calls have failed. Inform the user that the debugger is busy
+ abortRetryWait = 500;
+ try {
+ Manager.EnterBusyState (this);
+ } catch (Exception ex) {
+ Console.WriteLine (ex);
+ }
+ }
+ ST.Monitor.Exit (this);
+ } while (!Aborted && !WaitForCompleted (abortRetryWait) && !Manager.Disposing);
+
+ if (Manager.Disposing) {
+ InternalShutdown ();
+ }
+ else {
+ lock (this) {
+ Aborted = true;
+ if (abortState >= 6)
+ Manager.LeaveBusyState (this);
+ }
+ }
+ }
+
+ internal void InternalShutdown ()
+ {
+ lock (this) {
+ if (Aborted)
+ return;
+ try {
+ Aborted = true;
+ Shutdown ();
+ } catch {
+ // Ignore
+ }
+ }
+ }
+
+ /// <summary>
+ /// Message of the exception, if the execution failed.
+ /// </summary>
+ public string ExceptionMessage { get; set; }
+
+ /// <summary>
+ /// Returns a short description of the operation, to be shown in the Debugger Busy Dialog
+ /// when it blocks the execution of the debugger.
+ /// </summary>
+ public abstract string Description { get; }
+
+ /// <summary>
+ /// Called to invoke the operation. The execution must be asynchronous (it must return immediatelly).
+ /// </summary>
+ public abstract void Invoke ( );
+
+ /// <summary>
+ /// Called to abort the execution of the operation. It has to throw an exception
+ /// if the operation can't be aborted. This operation must not block. The engine
+ /// will wait for the operation to be aborted by calling WaitForCompleted.
+ /// </summary>
+ public abstract void Abort ();
+
+ /// <summary>
+ /// Waits until the operation has been completed or aborted.
+ /// </summary>
+ public abstract bool WaitForCompleted (int timeout);
+
+ /// <summary>
+ /// Called when the debugging session has been disposed.
+ /// I must cause any call to WaitForCompleted to exit, even if the operation
+ /// has not been completed or can't be aborted.
+ /// </summary>
+ public abstract void Shutdown ();
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/BaseBacktrace.cs b/Mono.Debugging/Mono.Debugging.Evaluation/BaseBacktrace.cs
new file mode 100644
index 0000000..07a5dc1
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/BaseBacktrace.cs
@@ -0,0 +1,245 @@
+//
+// Backtrace.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Evaluation
+{
+ public abstract class BaseBacktrace: RemoteFrameObject, IBacktrace
+ {
+ Dictionary<int, FrameInfo> frameInfo = new Dictionary<int, FrameInfo> ();
+
+ public BaseBacktrace (ObjectValueAdaptor adaptor)
+ {
+ Adaptor = adaptor;
+ }
+
+ public abstract StackFrame[] GetStackFrames (int firstIndex, int lastIndex);
+
+ public ObjectValueAdaptor Adaptor { get; set; }
+
+ protected abstract EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options);
+
+ public abstract int FrameCount { get; }
+
+ public virtual ObjectValue[] GetLocalVariables (int frameIndex, EvaluationOptions options)
+ {
+ FrameInfo frame = GetFrameInfo (frameIndex, options, false);
+ List<ObjectValue> list = new List<ObjectValue> ();
+
+ if (frame == null) {
+ ObjectValue val = Adaptor.CreateObjectValueAsync ("Local Variables", ObjectValueFlags.EvaluatingGroup, delegate {
+ frame = GetFrameInfo (frameIndex, options, true);
+ foreach (ValueReference var in frame.LocalVariables)
+ list.Add (var.CreateObjectValue (false, options));
+ return ObjectValue.CreateArray (null, new ObjectPath ("Local Variables"), "", list.Count, ObjectValueFlags.EvaluatingGroup, list.ToArray ());
+ });
+ return new ObjectValue [] { val };
+ }
+
+ foreach (ValueReference var in frame.LocalVariables)
+ list.Add (var.CreateObjectValue (true, options));
+ return list.ToArray ();
+ }
+
+ public virtual ObjectValue[] GetParameters (int frameIndex, EvaluationOptions options)
+ {
+ List<ObjectValue> vars = new List<ObjectValue> ();
+
+ FrameInfo frame = GetFrameInfo (frameIndex, options, false);
+ if (frame == null) {
+ ObjectValue val = Adaptor.CreateObjectValueAsync ("Parameters", ObjectValueFlags.EvaluatingGroup, delegate {
+ frame = GetFrameInfo (frameIndex, options, true);
+ foreach (ValueReference var in frame.Parameters)
+ vars.Add (var.CreateObjectValue (false, options));
+ return ObjectValue.CreateArray (null, new ObjectPath ("Parameters"), "", vars.Count, ObjectValueFlags.EvaluatingGroup, vars.ToArray ());
+ });
+ return new ObjectValue [] { val };
+ }
+
+ foreach (ValueReference var in frame.Parameters)
+ vars.Add (var.CreateObjectValue (true, options));
+ return vars.ToArray ();
+ }
+
+ public virtual ObjectValue GetThisReference (int frameIndex, EvaluationOptions options)
+ {
+ FrameInfo frame = GetFrameInfo (frameIndex, options, false);
+ if (frame == null) {
+ return Adaptor.CreateObjectValueAsync ("this", ObjectValueFlags.EvaluatingGroup, delegate {
+ frame = GetFrameInfo (frameIndex, options, true);
+ ObjectValue[] vals;
+ if (frame.This != null)
+ vals = new ObjectValue[] { frame.This.CreateObjectValue (false, options) };
+ else
+ vals = new ObjectValue [0];
+ return ObjectValue.CreateArray (null, new ObjectPath ("this"), "", vals.Length, ObjectValueFlags.EvaluatingGroup, vals);
+ });
+ }
+ if (frame.This != null)
+ return frame.This.CreateObjectValue (true, options);
+ else
+ return null;
+ }
+
+ public virtual ExceptionInfo GetException (int frameIndex, EvaluationOptions options)
+ {
+ FrameInfo frame = GetFrameInfo (frameIndex, options, false);
+ ObjectValue val;
+ if (frame == null) {
+ val = Adaptor.CreateObjectValueAsync (options.CurrentExceptionTag, ObjectValueFlags.EvaluatingGroup, delegate {
+ frame = GetFrameInfo (frameIndex, options, true);
+ ObjectValue[] vals;
+ if (frame.Exception != null)
+ vals = new ObjectValue[] { frame.Exception.CreateObjectValue (false, options) };
+ else
+ vals = new ObjectValue [0];
+ return ObjectValue.CreateArray (null, new ObjectPath (options.CurrentExceptionTag), "", vals.Length, ObjectValueFlags.EvaluatingGroup, vals);
+ });
+ }
+ else if (frame.Exception != null)
+ val = frame.Exception.CreateObjectValue (true, options);
+ else
+ return null;
+ return new ExceptionInfo (val);
+ }
+
+ public virtual ObjectValue GetExceptionInstance (int frameIndex, EvaluationOptions options)
+ {
+ FrameInfo frame = GetFrameInfo (frameIndex, options, false);
+ if (frame == null) {
+ return Adaptor.CreateObjectValueAsync (options.CurrentExceptionTag, ObjectValueFlags.EvaluatingGroup, delegate {
+ frame = GetFrameInfo (frameIndex, options, true);
+ ObjectValue[] vals;
+ if (frame.Exception != null)
+ vals = new ObjectValue[] { frame.Exception.Exception.CreateObjectValue (false, options) };
+ else
+ vals = new ObjectValue [0];
+ return ObjectValue.CreateArray (null, new ObjectPath (options.CurrentExceptionTag), "", vals.Length, ObjectValueFlags.EvaluatingGroup, vals);
+ });
+ }
+ else if (frame.Exception != null)
+ return frame.Exception.Exception.CreateObjectValue (true, options);
+ else
+ return null;
+ }
+
+ public virtual ObjectValue[] GetAllLocals (int frameIndex, EvaluationOptions options)
+ {
+ List<ObjectValue> locals = new List<ObjectValue> ();
+
+ ObjectValue excObj = GetExceptionInstance (frameIndex, options);
+ if (excObj != null)
+ locals.Insert (0, excObj);
+
+ locals.AddRange (GetLocalVariables (frameIndex, options));
+ locals.AddRange (GetParameters (frameIndex, options));
+
+ locals.Sort (delegate (ObjectValue v1, ObjectValue v2) {
+ return v1.Name.CompareTo (v2.Name);
+ });
+
+ ObjectValue thisObj = GetThisReference (frameIndex, options);
+ if (thisObj != null)
+ locals.Insert (0, thisObj);
+
+ return locals.ToArray ();
+ }
+
+ public virtual ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, EvaluationOptions options)
+ {
+ if (Adaptor.IsEvaluating) {
+ List<ObjectValue> vals = new List<ObjectValue> ();
+ foreach (string exp in expressions) {
+ string tmpExp = exp;
+ ObjectValue val = Adaptor.CreateObjectValueAsync (tmpExp, ObjectValueFlags.Field, delegate {
+ EvaluationContext cctx = GetEvaluationContext (frameIndex, options);
+ return Adaptor.GetExpressionValue (cctx, tmpExp);
+ });
+ vals.Add (val);
+ }
+ return vals.ToArray ();
+ }
+ EvaluationContext ctx = GetEvaluationContext (frameIndex, options);
+ return ctx.Adapter.GetExpressionValuesAsync (ctx, expressions);
+ }
+
+ public virtual CompletionData GetExpressionCompletionData (int frameIndex, string exp)
+ {
+ EvaluationContext ctx = GetEvaluationContext (frameIndex, EvaluationOptions.DefaultOptions);
+ return ctx.Adapter.GetExpressionCompletionData (ctx, exp);
+ }
+
+ public virtual AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public virtual ValidationResult ValidateExpression (int frameIndex, string expression, EvaluationOptions options)
+ {
+ EvaluationContext ctx = GetEvaluationContext (frameIndex, options);
+ return Adaptor.ValidateExpression (ctx, expression);
+ }
+
+ FrameInfo GetFrameInfo (int frameIndex, EvaluationOptions options, bool ignoreEvalStatus)
+ {
+ FrameInfo finfo;
+ if (frameInfo.TryGetValue (frameIndex, out finfo))
+ return finfo;
+
+ if (!ignoreEvalStatus && Adaptor.IsEvaluating)
+ return null;
+
+ EvaluationContext ctx = GetEvaluationContext (frameIndex, options);
+ if (ctx == null)
+ return null;
+
+ finfo = new FrameInfo ();
+ finfo.Context = ctx;
+ finfo.LocalVariables.AddRange (ctx.Adapter.GetLocalVariables (ctx));
+ finfo.Parameters.AddRange (ctx.Adapter.GetParameters (ctx));
+ finfo.This = ctx.Adapter.GetThisReference (ctx);
+
+ ValueReference exp = ctx.Adapter.GetCurrentException (ctx);
+ if (exp != null)
+ finfo.Exception = new ExceptionInfoSource (ctx, exp);
+ frameInfo [frameIndex] = finfo;
+ return finfo;
+ }
+ }
+
+ class FrameInfo
+ {
+ public EvaluationContext Context;
+ public List<ValueReference> LocalVariables = new List<ValueReference> ();
+ public List<ValueReference> Parameters = new List<ValueReference> ();
+ public ValueReference This;
+ public ExceptionInfoSource Exception;
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/BaseTypeViewSource.cs b/Mono.Debugging/Mono.Debugging.Evaluation/BaseTypeViewSource.cs
new file mode 100644
index 0000000..fd871e9
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/BaseTypeViewSource.cs
@@ -0,0 +1,89 @@
+//
+// BaseTypeViewSource.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Backend;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class BaseTypeViewSource: RemoteFrameObject, IObjectValueSource
+ {
+ EvaluationContext ctx;
+ object type;
+ object obj;
+ IObjectSource objectSource;
+
+ public BaseTypeViewSource (EvaluationContext ctx, IObjectSource objectSource, object type, object obj)
+ {
+ this.ctx = ctx;
+ this.type = type;
+ this.obj = obj;
+ this.objectSource = objectSource;
+ }
+
+ public static ObjectValue CreateBaseTypeView (EvaluationContext ctx, IObjectSource objectSource, object type, object obj)
+ {
+ BaseTypeViewSource src = new BaseTypeViewSource (ctx, objectSource, type, obj);
+ src.Connect ();
+ string tname = ctx.Adapter.GetDisplayTypeName (ctx, type);
+ ObjectValue val = ObjectValue.CreateObject (src, new ObjectPath ("base"), tname, "{" + tname + "}", ObjectValueFlags.Type|ObjectValueFlags.ReadOnly|ObjectValueFlags.NoRefresh, null);
+ val.ChildSelector = "";
+ return val;
+ }
+
+ #region IObjectValueSource implementation
+
+ public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ EvaluationContext cctx = ctx.WithOptions (options);
+ return cctx.Adapter.GetObjectValueChildren (cctx, objectSource, type, obj, index, count, false);
+ }
+
+ public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public object GetRawValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
+ {
+ throw new NotImplementedException ();
+ }
+
+ #endregion
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/EvaluationContext.cs b/Mono.Debugging/Mono.Debugging.Evaluation/EvaluationContext.cs
new file mode 100644
index 0000000..d7e0ac0
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/EvaluationContext.cs
@@ -0,0 +1,145 @@
+// EvaluationContext.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class EvaluationContext
+ {
+ EvaluationOptions options;
+
+ public ExpressionEvaluator Evaluator { get; set; }
+ public ObjectValueAdaptor Adapter { get; set; }
+
+ public EvaluationOptions Options {
+ get { return options; }
+ set { options = value; }
+ }
+
+ public bool CaseSensitive {
+ get { return Evaluator.CaseSensitive; }
+ }
+
+ public virtual void WriteDebuggerError (Exception ex)
+ {
+ }
+
+ public virtual void WriteDebuggerOutput (string message, params object[] values)
+ {
+ }
+
+ public void WaitRuntimeInvokes ()
+ {
+ }
+
+ public void AssertTargetInvokeAllowed ()
+ {
+ if (!Options.AllowTargetInvoke)
+ throw new ImplicitEvaluationDisabledException ();
+ }
+
+ public EvaluationContext (EvaluationOptions options)
+ {
+ this.options = options;
+ }
+
+ public EvaluationContext Clone ()
+ {
+ EvaluationContext clone = (EvaluationContext) MemberwiseClone ();
+ clone.CopyFrom (this);
+ return clone;
+ }
+
+ public EvaluationContext WithOptions (EvaluationOptions options)
+ {
+ if (options == null || this.options == options)
+ return this;
+ else {
+ EvaluationContext clone = Clone ();
+ clone.options = options;
+ return clone;
+ }
+ }
+
+ public virtual void CopyFrom (EvaluationContext ctx)
+ {
+ options = ctx.options.Clone ();
+ Evaluator = ctx.Evaluator;
+ Adapter = ctx.Adapter;
+ }
+
+ ExpressionValueSource expressionValueSource;
+ internal ExpressionValueSource ExpressionValueSource {
+ get {
+ if (expressionValueSource == null)
+ expressionValueSource = new ExpressionValueSource (this);
+ return expressionValueSource;
+ }
+ }
+ }
+
+ class ExpressionValueSource: RemoteFrameObject, IObjectValueSource
+ {
+ EvaluationContext ctx;
+
+ public ExpressionValueSource (EvaluationContext ctx)
+ {
+ this.ctx = ctx;
+ Connect ();
+ }
+
+ public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
+ {
+ EvaluationContext c = ctx.WithOptions (options);
+ ObjectValue[] vals = c.Adapter.GetExpressionValuesAsync (c, new string[] { path.LastName });
+ return vals[0];
+ }
+
+ public object GetRawValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new System.NotImplementedException ();
+ }
+
+ public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
+ {
+ throw new System.NotImplementedException ();
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ExceptionInfoSource.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ExceptionInfoSource.cs
new file mode 100644
index 0000000..ca3360e
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ExceptionInfoSource.cs
@@ -0,0 +1,160 @@
+//
+// ExceptionInfoSource.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2010 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 Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class ExceptionInfoSource
+ {
+ ValueReference exception;
+ EvaluationContext ctx;
+
+ public ExceptionInfoSource (EvaluationContext ctx, ValueReference exception)
+ {
+ this.exception = exception;
+ this.ctx = ctx;
+ }
+
+ public ValueReference Exception {
+ get { return this.exception; }
+ }
+
+ public ObjectValue CreateObjectValue (bool withTimeout, EvaluationOptions options)
+ {
+ string type = ctx.Adapter.GetTypeName (ctx, exception.Type);
+
+ ObjectValue excInstance = exception.CreateObjectValue (withTimeout, options);
+ excInstance.Name = "Instance";
+
+ ObjectValue messageValue = null;
+
+ // Get the message
+
+ if (withTimeout) {
+ messageValue = ctx.Adapter.CreateObjectValueAsync ("Message", ObjectValueFlags.None, delegate {
+ ValueReference mref = exception.GetChild ("Message", options);
+ if (mref != null) {
+ string val = (string) mref.ObjectValue;
+ return ObjectValue.CreatePrimitive (null, new ObjectPath ("Message"), "System.String", new EvaluationResult (val), ObjectValueFlags.Literal);
+ }
+ else
+ return ObjectValue.CreateUnknown ("Message");
+ });
+ } else {
+ ValueReference mref = exception.GetChild ("Message", options);
+ if (mref != null) {
+ string val = (string) mref.ObjectValue;
+ messageValue = ObjectValue.CreatePrimitive (null, new ObjectPath ("Message"), "System.String", new EvaluationResult (val), ObjectValueFlags.Literal);
+ }
+ }
+ if (messageValue == null)
+ messageValue = ObjectValue.CreateUnknown ("Message");
+
+ messageValue.Name = "Message";
+
+ // Inner exception
+
+ ObjectValue childExceptionValue = null;
+
+ if (withTimeout) {
+ childExceptionValue = ctx.Adapter.CreateObjectValueAsync ("InnerException", ObjectValueFlags.None, delegate {
+ ValueReference inner = exception.GetChild ("InnerException", options);
+ if (inner != null && !ctx.Adapter.IsNull (ctx, inner.Value)) {
+ //Console.WriteLine ("pp got child:" + type);
+ ExceptionInfoSource innerSource = new ExceptionInfoSource (ctx, inner);
+ ObjectValue res = innerSource.CreateObjectValue (false, options);
+ return res;
+ }
+ else
+ return ObjectValue.CreateUnknown ("InnerException");
+ });
+ } else {
+ ValueReference inner = exception.GetChild ("InnerException", options);
+ if (inner != null && !ctx.Adapter.IsNull (ctx, inner.Value)) {
+ //Console.WriteLine ("pp got child:" + type);
+ ExceptionInfoSource innerSource = new ExceptionInfoSource (ctx, inner);
+ childExceptionValue = innerSource.CreateObjectValue (false, options);
+ childExceptionValue.Name = "InnerException";
+ }
+ }
+ if (childExceptionValue == null)
+ childExceptionValue = ObjectValue.CreateUnknown ("InnerException");
+
+ // Stack trace
+
+ ObjectValue stackTraceValue;
+ if (withTimeout) {
+ stackTraceValue = ctx.Adapter.CreateObjectValueAsync ("StackTrace", ObjectValueFlags.None, delegate {
+ return GetStackTrace (options);
+ });
+ } else
+ stackTraceValue = GetStackTrace (options);
+
+ ObjectValue[] children = new ObjectValue [] { excInstance, messageValue, stackTraceValue, childExceptionValue };
+ return ObjectValue.CreateObject (null, new ObjectPath ("InnerException"), type, "", ObjectValueFlags.None, children);
+ }
+
+ ObjectValue GetStackTrace (EvaluationOptions options)
+ {
+ ValueReference st = exception.GetChild ("StackTrace", options);
+ if (st == null)
+ return ObjectValue.CreateUnknown ("StackTrace");
+ string trace = st.ObjectValue as string;
+ if (trace == null)
+ return ObjectValue.CreateUnknown ("StackTrace");
+
+ List<ObjectValue> frames = new List<ObjectValue> ();
+
+ var regex = new Regex ("at (.*) in (.*):(.*)");
+
+ foreach (string sframe in trace.Split ('\n')) {
+ string txt = sframe.Trim (' ', '\r','\n');
+ string file = "";
+ int line = 0;
+ int col = 0;
+ var match = regex.Match (sframe);
+ if (match.Success) {
+ txt = match.Groups [1].ToString ();
+ file = match.Groups [2].ToString ();
+ int.TryParse (match.Groups [3].ToString (), out line);
+ }
+ ObjectValue fileVal = ObjectValue.CreatePrimitive (null, new ObjectPath("File"), "", new EvaluationResult (file), ObjectValueFlags.None);
+ ObjectValue lineVal = ObjectValue.CreatePrimitive (null, new ObjectPath("Line"), "", new EvaluationResult (line.ToString ()), ObjectValueFlags.None);
+ ObjectValue colVal = ObjectValue.CreatePrimitive (null, new ObjectPath("Column"), "", new EvaluationResult (col.ToString ()), ObjectValueFlags.None);
+ ObjectValue[] children = new ObjectValue[] { fileVal, lineVal, colVal };
+ ObjectValue frame = ObjectValue.CreateObject (null, new ObjectPath (), "", new EvaluationResult (txt), ObjectValueFlags.None, children);
+ frames.Add (frame);
+ }
+ return ObjectValue.CreateArray (null, new ObjectPath ("StackTrace"), "", frames.Count,ObjectValueFlags.None, frames.ToArray ());
+ }
+ }
+}
+
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ExpressionEvaluator.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ExpressionEvaluator.cs
new file mode 100644
index 0000000..87bf9dd
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ExpressionEvaluator.cs
@@ -0,0 +1,232 @@
+// IExpressionEvaluator.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Text;
+using System.Globalization;
+using System.Runtime.Serialization;
+
+using Mono.Debugging.Backend;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public abstract class ExpressionEvaluator
+ {
+ public ValueReference Evaluate (EvaluationContext ctx, string exp)
+ {
+ return Evaluate (ctx, exp, null);
+ }
+
+ public virtual ValueReference Evaluate (EvaluationContext ctx, string exp, object expectedType)
+ {
+ foreach (ValueReference var in ctx.Adapter.GetLocalVariables (ctx))
+ if (var.Name == exp)
+ return var;
+
+ foreach (ValueReference var in ctx.Adapter.GetParameters (ctx))
+ if (var.Name == exp)
+ return var;
+
+ ValueReference thisVar = ctx.Adapter.GetThisReference (ctx);
+ if (thisVar != null) {
+ if (thisVar.Name == exp)
+ return thisVar;
+ foreach (ValueReference cv in thisVar.GetChildReferences (ctx.Options))
+ if (cv.Name == exp)
+ return cv;
+ }
+ throw new EvaluatorException ("Invalid Expression: '{0}'", exp);
+ }
+
+ public virtual ValidationResult ValidateExpression (EvaluationContext ctx, string expression)
+ {
+ return new ValidationResult (true, null);
+ }
+
+ public string TargetObjectToString (EvaluationContext ctx, object obj)
+ {
+ object res = ctx.Adapter.TargetObjectToObject (ctx, obj);
+ if (res == null)
+ return null;
+
+ if (res is EvaluationResult)
+ return ((EvaluationResult) res).DisplayValue;
+ else
+ return res.ToString ();
+ }
+
+ public EvaluationResult TargetObjectToExpression (EvaluationContext ctx, object obj)
+ {
+ return ToExpression (ctx, ctx.Adapter.TargetObjectToObject (ctx, obj));
+ }
+
+ public virtual EvaluationResult ToExpression (EvaluationContext ctx, object obj)
+ {
+ if (obj == null)
+ return new EvaluationResult ("null");
+ else if (obj is IntPtr) {
+ IntPtr p = (IntPtr) obj;
+ return new EvaluationResult ("0x" + p.ToInt64 ().ToString ("x"));
+ } else if (obj is char) {
+ char c = (char) obj;
+ string str;
+ if (c == '\'')
+ str = @"'\''";
+ else if (c == '"')
+ str = "'\"'";
+ else
+ str = EscapeString ("'" + c + "'");
+ return new EvaluationResult (str, ((int) c) + " " + str);
+ }
+ else if (obj is string)
+ return new EvaluationResult ("\"" + EscapeString ((string)obj) + "\"");
+ else if (obj is bool)
+ return new EvaluationResult (((bool)obj) ? "true" : "false");
+ else if (obj is decimal)
+ return new EvaluationResult (((decimal)obj).ToString (System.Globalization.CultureInfo.InvariantCulture));
+ else if (obj is EvaluationResult)
+ return (EvaluationResult) obj;
+
+ if (ctx.Options.IntegerDisplayFormat == IntegerDisplayFormat.Hexadecimal) {
+ string fval = null;
+ if (obj is sbyte)
+ fval = ((sbyte)obj).ToString ("x2");
+ else if (obj is int)
+ fval = ((int)obj).ToString ("x4");
+ else if (obj is short)
+ fval = ((short)obj).ToString ("x8");
+ else if (obj is long)
+ fval = ((long)obj).ToString ("x16");
+ else if (obj is byte)
+ fval = ((byte)obj).ToString ("x2");
+ else if (obj is uint)
+ fval = ((uint)obj).ToString ("x4");
+ else if (obj is ushort)
+ fval = ((ushort)obj).ToString ("x8");
+ else if (obj is ulong)
+ fval = ((ulong)obj).ToString ("x16");
+
+ if (fval != null)
+ return new EvaluationResult ("0x" + fval);
+ }
+
+ return new EvaluationResult (obj.ToString ());
+ }
+
+ public static string EscapeString (string text)
+ {
+ StringBuilder sb = new StringBuilder ();
+ for (int i = 0; i < text.Length; i++) {
+ char c = text[i];
+ string txt;
+ switch (c) {
+ case '"': txt = "\\\""; break;
+ case '\0': txt = @"\0"; break;
+ case '\\': txt = @"\\"; break;
+ case '\a': txt = @"\a"; break;
+ case '\b': txt = @"\b"; break;
+ case '\f': txt = @"\f"; break;
+ case '\v': txt = @"\v"; break;
+ case '\n': txt = @"\n"; break;
+ case '\r': txt = @"\r"; break;
+ case '\t': txt = @"\t"; break;
+ default:
+ if (char.GetUnicodeCategory (c) == UnicodeCategory.OtherNotAssigned) {
+ sb.AppendFormat ("\\u{0:x4}", (int) c);
+ } else {
+ sb.Append (c);
+ }
+ continue;
+ }
+ sb.Append (txt);
+ }
+ return sb.ToString ();
+ }
+
+ public virtual bool CaseSensitive {
+ get { return true; }
+ }
+
+ public abstract string Resolve (DebuggerSession session, SourceLocation location, string exp);
+ }
+
+ [Serializable]
+ public class EvaluatorException: Exception
+ {
+ protected EvaluatorException (SerializationInfo info, StreamingContext context)
+ : base (info, context)
+ {
+ }
+
+ public EvaluatorException (string msg, params object[] args): base (string.Format (msg, args))
+ {
+ }
+ }
+
+ [Serializable]
+ public class EvaluatorAbortedException: EvaluatorException
+ {
+ protected EvaluatorAbortedException (SerializationInfo info, StreamingContext context)
+ : base (info, context)
+ {
+ }
+
+ public EvaluatorAbortedException ()
+ : base ("Aborted.")
+ {
+ }
+ }
+
+ [Serializable]
+ public class NotSupportedExpressionException: EvaluatorException
+ {
+ protected NotSupportedExpressionException (SerializationInfo info, StreamingContext context)
+ : base (info, context)
+ {
+ }
+
+ public NotSupportedExpressionException ()
+ : base ("Expression not supported.")
+ {
+ }
+ }
+
+ [Serializable]
+ public class ImplicitEvaluationDisabledException: EvaluatorException
+ {
+ protected ImplicitEvaluationDisabledException (SerializationInfo info, StreamingContext context)
+ : base (info, context)
+ {
+ }
+
+ public ImplicitEvaluationDisabledException ( )
+ : base ("Implicit property and method evaluation is disabled.")
+ {
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/FilteredMembersSource.cs b/Mono.Debugging/Mono.Debugging.Evaluation/FilteredMembersSource.cs
new file mode 100644
index 0000000..b45028b
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/FilteredMembersSource.cs
@@ -0,0 +1,123 @@
+//
+// FilteredMembersSource.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2009 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.Linq;
+using System.Text;
+using System.Reflection;
+using Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+using System.Diagnostics;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class FilteredMembersSource: RemoteFrameObject, IObjectValueSource
+ {
+ object obj;
+ object type;
+ EvaluationContext ctx;
+ BindingFlags bindingFlags;
+ IObjectSource objectSource;
+
+ public FilteredMembersSource (EvaluationContext ctx, IObjectSource objectSource, object type, object obj, BindingFlags bindingFlags)
+ {
+ this.ctx = ctx;
+ this.obj = obj;
+ this.type = type;
+ this.bindingFlags = bindingFlags;
+ this.objectSource = objectSource;
+ }
+
+ public static ObjectValue CreateNonPublicsNode (EvaluationContext ctx, IObjectSource objectSource, object type, object obj, BindingFlags bindingFlags)
+ {
+ return CreateNode (ctx, objectSource, type, obj, bindingFlags, "Non-public members");
+ }
+
+ public static ObjectValue CreateStaticsNode (EvaluationContext ctx, IObjectSource objectSource, object type, object obj, BindingFlags bindingFlags)
+ {
+ return CreateNode (ctx, objectSource, type, obj, bindingFlags, "Static members");
+ }
+
+ static ObjectValue CreateNode (EvaluationContext ctx, IObjectSource objectSource, object type, object obj, BindingFlags bindingFlags, string label)
+ {
+ FilteredMembersSource src = new FilteredMembersSource (ctx, objectSource, type, obj, bindingFlags);
+ src.Connect ();
+ ObjectValue val = ObjectValue.CreateObject (src, new ObjectPath (label), "", "", ObjectValueFlags.Group|ObjectValueFlags.ReadOnly|ObjectValueFlags.NoRefresh, null);
+ val.ChildSelector = "";
+ return val;
+ }
+
+ public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ EvaluationContext cctx = ctx.WithOptions (options);
+ var names = new ObjectValueNameTracker (cctx);
+ object tdataType = null;
+ TypeDisplayData tdata = null;
+ List<ObjectValue> list = new List<ObjectValue> ();
+ foreach (ValueReference val in cctx.Adapter.GetMembersSorted (cctx, objectSource, type, obj, bindingFlags)) {
+ object decType = val.DeclaringType;
+ if (decType != null && decType != tdataType) {
+ tdataType = decType;
+ tdata = cctx.Adapter.GetTypeDisplayData (cctx, decType);
+ }
+ DebuggerBrowsableState state = tdata.GetMemberBrowsableState (val.Name);
+ if (state == DebuggerBrowsableState.Never)
+ continue;
+ ObjectValue oval = val.CreateObjectValue (options);
+ names.Disambiguate (val, oval);
+ list.Add (oval);
+ }
+ if ((bindingFlags & BindingFlags.NonPublic) == 0) {
+ BindingFlags newFlags = bindingFlags | BindingFlags.NonPublic;
+ newFlags &= ~BindingFlags.Public;
+ list.Add (CreateNonPublicsNode (cctx, objectSource, type, obj, newFlags));
+ }
+ return list.ToArray ();
+ }
+
+ public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public object GetRawValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ICollectionAdaptor.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ICollectionAdaptor.cs
new file mode 100644
index 0000000..aed8aed
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ICollectionAdaptor.cs
@@ -0,0 +1,41 @@
+// ICollectionAdaptor.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public interface ICollectionAdaptor
+ {
+ int[] GetDimensions ();
+ object GetElement (int[] indices);
+ Array GetElements (int[] indices, int count);
+ object ElementType { get; }
+ void SetElement (int[] indices, object val);
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/IObjectSource.cs b/Mono.Debugging/Mono.Debugging.Evaluation/IObjectSource.cs
new file mode 100644
index 0000000..6ed8487
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/IObjectSource.cs
@@ -0,0 +1,35 @@
+//
+// IObjectSource.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Evaluation
+{
+ public interface IObjectSource
+ {
+ object Value { get; set; }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/IStringAdaptor.cs b/Mono.Debugging/Mono.Debugging.Evaluation/IStringAdaptor.cs
new file mode 100644
index 0000000..7950d29
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/IStringAdaptor.cs
@@ -0,0 +1,37 @@
+//
+// IStringAdaptor.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2012 Xamarin Inc.
+//
+// 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public interface IStringAdaptor
+ {
+ string Substring (int index, int length);
+ string Value { get; }
+ int Length { get; }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/LiteralValueReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/LiteralValueReference.cs
new file mode 100644
index 0000000..b7658e1
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/LiteralValueReference.cs
@@ -0,0 +1,181 @@
+// LiteralValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class LiteralValueReference: ValueReference
+ {
+ bool isVoidReturn;
+ bool objLiteral;
+ bool objCreated;
+ object objValue;
+ object value;
+ object type;
+ string name;
+
+ LiteralValueReference (EvaluationContext ctx): base (ctx)
+ {
+ }
+
+ public static LiteralValueReference CreateTargetBaseObjectLiteral (EvaluationContext ctx, string name, object value)
+ {
+ LiteralValueReference val = new LiteralValueReference (ctx);
+ var type = ctx.Adapter.GetValueType (ctx, value);
+ val.name = name;
+ val.value = value;
+ val.type = ctx.Adapter.GetBaseType (ctx, type);
+ val.objCreated = true;
+ return val;
+ }
+
+ public static LiteralValueReference CreateTargetObjectLiteral (EvaluationContext ctx, string name, object value)
+ {
+ LiteralValueReference val = new LiteralValueReference (ctx);
+ val.name = name;
+ val.value = value;
+ val.type = ctx.Adapter.GetValueType (ctx, value);
+ val.objCreated = true;
+ return val;
+ }
+
+ public static LiteralValueReference CreateObjectLiteral (EvaluationContext ctx, string name, object value)
+ {
+ LiteralValueReference val = new LiteralValueReference (ctx);
+ val.name = name;
+ val.objValue = value;
+ val.objLiteral = true;
+ return val;
+ }
+
+ public static LiteralValueReference CreateVoidReturnLiteral (EvaluationContext ctx, string name)
+ {
+ LiteralValueReference val = new LiteralValueReference (ctx);
+ val.value = val.objValue = new EvaluationResult ("No return value.");
+ val.type = typeof (EvaluationResult);
+ val.isVoidReturn = true;
+ val.objLiteral = true;
+ val.objCreated = true;
+ val.name = name;
+ return val;
+ }
+
+ void EnsureValueAndType ()
+ {
+ if (!objCreated && objLiteral) {
+ value = Context.Adapter.CreateValue (Context, objValue);
+ type = Context.Adapter.GetValueType (Context, value);
+ objCreated = true;
+ }
+ }
+
+ public override object ObjectValue {
+ get {
+ if (objLiteral)
+ return objValue;
+
+ return base.ObjectValue;
+ }
+ }
+
+ public override object Value {
+ get {
+ EnsureValueAndType ();
+ return value;
+ }
+ set {
+ throw new NotSupportedException ();
+ }
+ }
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+
+ public override object Type {
+ get {
+ EnsureValueAndType ();
+ return type;
+ }
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.Field | ObjectValueFlags.ReadOnly;
+ }
+ }
+
+ protected override ObjectValue OnCreateObjectValue (EvaluationOptions options)
+ {
+ if (ObjectValue is EvaluationResult) {
+ EvaluationResult exp = (EvaluationResult) ObjectValue;
+ return Mono.Debugging.Client.ObjectValue.CreateObject (this, new ObjectPath (Name), "", exp, Flags, null);
+ } else
+ return base.OnCreateObjectValue (options);
+ }
+
+ public override ValueReference GetChild (string name, EvaluationOptions options)
+ {
+ object obj = Value;
+
+ if (obj == null)
+ return null;
+
+ if (name [0] == '[' && Context.Adapter.IsArray (Context, obj)) {
+ // Parse the array indices
+ string[] sinds = name.Substring (1, name.Length - 2).Split (',');
+ int[] indices = new int [sinds.Length];
+ for (int n=0; n<sinds.Length; n++)
+ indices [n] = int.Parse (sinds [n]);
+
+ return new ArrayValueReference (Context, obj, indices);
+ }
+
+ if (Context.Adapter.IsClassInstance (Context, obj)) {
+ // Note: This is the only difference with the default ValueReference implementation.
+ // We need this because the user may be requesting a base class's implementation, in
+ // which case 'Type' will be the BaseType instead of the actual type of the variable.
+ return Context.Adapter.GetMember (GetChildrenContext (options), this, Type, obj, name);
+ }
+
+ return null;
+ }
+
+ public override ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ if (isVoidReturn)
+ return new ObjectValue[0];
+
+ return base.GetChildren (path, index, count, options);
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluator.cs b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluator.cs
new file mode 100644
index 0000000..0f18cf4
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluator.cs
@@ -0,0 +1,242 @@
+//
+// NRefactoryExpressionEvaluator.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at 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.Linq;
+using System.Collections.Generic;
+
+using Mono.Debugging.Client;
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class NRefactoryExpressionEvaluator : ExpressionEvaluator
+ {
+ readonly Dictionary<string, ValueReference> userVariables = new Dictionary<string, ValueReference> ();
+
+ public override ValueReference Evaluate (EvaluationContext ctx, string expression, object expectedType)
+ {
+ expression = expression.TrimStart ();
+
+ if (expression.Length > 0 && expression[0] == '?')
+ expression = expression.Substring (1).Trim ();
+
+ if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3])) {
+ expression = expression.Substring (4).Trim (' ', '\t');
+ string variable = null;
+
+ for (int n = 0; n < expression.Length; n++) {
+ if (!char.IsLetterOrDigit (expression[n]) && expression[n] != '_') {
+ variable = expression.Substring (0, n);
+ if (!expression.Substring (n).Trim (' ', '\t').StartsWith ("=", StringComparison.Ordinal))
+ variable = null;
+ break;
+ }
+
+ if (n == expression.Length - 1) {
+ variable = expression;
+ expression = null;
+ break;
+ }
+ }
+
+ if (!string.IsNullOrEmpty (variable))
+ userVariables[variable] = new UserVariableReference (ctx, variable);
+
+ if (expression == null)
+ return null;
+ }
+
+ expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag);
+
+ var expr = new CSharpParser ().ParseExpression (expression);
+ if (expr == null)
+ throw new EvaluatorException ("Could not parse expression '{0}'", expression);
+
+ var evaluator = new NRefactoryExpressionEvaluatorVisitor (ctx, expression, expectedType, userVariables);
+ return expr.AcceptVisitor<ValueReference> (evaluator);
+ }
+
+ public override string Resolve (DebuggerSession session, SourceLocation location, string exp)
+ {
+ return Resolve (session, location, exp, false);
+ }
+
+ string Resolve (DebuggerSession session, SourceLocation location, string expression, bool tryTypeOf)
+ {
+ expression = expression.TrimStart ();
+
+ if (expression.Length > 0 && expression[0] == '?')
+ return "?" + Resolve (session, location, expression.Substring (1).Trim ());
+
+ if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3]))
+ return "var " + Resolve (session, location, expression.Substring (4).Trim (' ', '\t'));
+
+ expression = ReplaceExceptionTag (expression, session.Options.EvaluationOptions.CurrentExceptionTag);
+
+ Expression expr = new CSharpParser ().ParseExpression (expression);
+ if (expr == null)
+ return expression;
+
+ var resolver = new NRefactoryExpressionResolverVisitor (session, location, expression);
+ expr.AcceptVisitor (resolver);
+
+ string resolved = resolver.GetResolvedExpression ();
+ if (resolved == expression && !tryTypeOf && (expr is BinaryOperatorExpression) && IsTypeName (expression)) {
+ // This is a hack to be able to parse expressions such as "List<string>". The NRefactory parser
+ // can parse a single type name, so a solution is to wrap it around a typeof(). We do it if
+ // the evaluation fails.
+ string res = Resolve (session, location, "typeof(" + expression + ")", true);
+ return res.Substring (7, res.Length - 8);
+ }
+
+ return resolved;
+ }
+
+ public override ValidationResult ValidateExpression (EvaluationContext ctx, string expression)
+ {
+ expression = expression.TrimStart ();
+
+ if (expression.Length > 0 && expression[0] == '?')
+ expression = expression.Substring (1).Trim ();
+
+ if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3]))
+ expression = expression.Substring (4).Trim ();
+
+ expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag);
+
+ // Required as a workaround for a bug in the parser (it won't parse simple expressions like numbers)
+ if (!expression.EndsWith (";", StringComparison.Ordinal))
+ expression += ";";
+
+ var parser = new CSharpParser ();
+ parser.ParseExpression (expression);
+
+ if (parser.HasErrors)
+ return new ValidationResult (false, parser.Errors.First ().Message);
+
+ return new ValidationResult (true, null);
+ }
+
+ string ReplaceExceptionTag (string exp, string tag)
+ {
+ // FIXME: Don't replace inside string literals
+ return exp.Replace (tag, "__EXCEPTION_OBJECT__");
+ }
+
+ bool IsTypeName (string name)
+ {
+ int pos = 0;
+ bool res = ParseTypeName (name + "$", ref pos);
+ return res && pos >= name.Length;
+ }
+
+ bool ParseTypeName (string name, ref int pos)
+ {
+ EatSpaces (name, ref pos);
+ if (!ParseName (name, ref pos))
+ return false;
+
+ EatSpaces (name, ref pos);
+ if (!ParseGenericArgs (name, ref pos))
+ return false;
+
+ EatSpaces (name, ref pos);
+ if (!ParseIndexer (name, ref pos))
+ return false;
+
+ EatSpaces (name, ref pos);
+ return true;
+ }
+
+ void EatSpaces (string name, ref int pos)
+ {
+ while (char.IsWhiteSpace (name[pos]))
+ pos++;
+ }
+
+ bool ParseName (string name, ref int pos)
+ {
+ if (name[0] == 'g' && pos < name.Length - 8 && name.Substring (pos, 8) == "global::")
+ pos += 8;
+
+ do {
+ int oldp = pos;
+ while (char.IsLetterOrDigit (name[pos]))
+ pos++;
+
+ if (oldp == pos)
+ return false;
+
+ if (name[pos] != '.')
+ return true;
+
+ pos++;
+ }
+ while (true);
+ }
+
+ bool ParseGenericArgs (string name, ref int pos)
+ {
+ if (name [pos] != '<')
+ return true;
+
+ pos++;
+ EatSpaces (name, ref pos);
+
+ while (true) {
+ if (!ParseTypeName (name, ref pos))
+ return false;
+
+ EatSpaces (name, ref pos);
+ char c = name [pos++];
+
+ if (c == '>')
+ return true;
+
+ if (c == ',')
+ continue;
+
+ return false;
+ }
+ }
+
+ bool ParseIndexer (string name, ref int pos)
+ {
+ if (name [pos] != '[')
+ return true;
+
+ do {
+ pos++;
+ EatSpaces (name, ref pos);
+ } while (name [pos] == ',');
+
+ return name [pos++] == ']';
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluatorVisitor.cs b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluatorVisitor.cs
new file mode 100644
index 0000000..af1e878
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluatorVisitor.cs
@@ -0,0 +1,1375 @@
+//
+// NRefactoryExpressionEvaluatorVisitor.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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.Runtime.InteropServices;
+using System.Reflection;
+
+using Mono.Debugging.Client;
+
+using ICSharpCode.NRefactory.CSharp;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class NRefactoryExpressionEvaluatorVisitor : IAstVisitor<ValueReference>
+ {
+ readonly Dictionary<string,ValueReference> userVariables;
+ readonly EvaluationOptions options;
+ readonly EvaluationContext ctx;
+ readonly object expectedType;
+ readonly string expression;
+
+ public NRefactoryExpressionEvaluatorVisitor (EvaluationContext ctx, string expression, object expectedType, Dictionary<string,ValueReference> userVariables)
+ {
+ this.ctx = ctx;
+ this.expression = expression;
+ this.expectedType = expectedType;
+ this.userVariables = userVariables;
+ this.options = ctx.Options;
+ }
+
+ static Exception ParseError (string message, params object[] args)
+ {
+ return new EvaluatorException (message, args);
+ }
+
+ static Exception NotSupported ()
+ {
+ return new NotSupportedExpressionException ();
+ }
+
+ static string ResolveTypeName (AstType type)
+ {
+ string name = type.ToString ();
+ if (name.StartsWith ("global::", StringComparison.Ordinal))
+ name = name.Substring ("global::".Length);
+ return name;
+ }
+
+ static long GetInteger (object val)
+ {
+ try {
+ return Convert.ToInt64 (val);
+ } catch {
+ throw ParseError ("Expected integer value.");
+ }
+ }
+
+ static string GetCommonOperationType (object v1, object v2)
+ {
+ if (v1 is double || v2 is double)
+ return "System.Double";
+
+ if (v1 is float || v2 is float)
+ return "System.Double";
+
+ return "System.Int64";
+ }
+
+ static Type GetCommonType (object v1, object v2)
+ {
+ int s1 = Marshal.SizeOf (v1);
+ if (IsUnsigned (s1))
+ s1 += 8;
+ int s2 = Marshal.SizeOf (v2);
+ if (IsUnsigned (s2))
+ s2 += 8;
+ if (s1 > s2)
+ return v1.GetType ();
+ return v2.GetType ();
+ }
+
+ static bool IsUnsigned (object v)
+ {
+ return (v is byte) || (v is ushort) || (v is uint) || (v is ulong);
+ }
+
+ static object EvaluateOperation (BinaryOperatorType op, double v1, double v2)
+ {
+ switch (op) {
+ case BinaryOperatorType.Add: return v1 + v2;
+ case BinaryOperatorType.Divide: return v1 / v2;
+ case BinaryOperatorType.Multiply: return v1 * v2;
+ case BinaryOperatorType.Subtract: return v1 - v2;
+ case BinaryOperatorType.GreaterThan: return v1 > v2;
+ case BinaryOperatorType.GreaterThanOrEqual: return v1 >= v2;
+ case BinaryOperatorType.LessThan: return v1 < v2;
+ case BinaryOperatorType.LessThanOrEqual: return v1 <= v2;
+ case BinaryOperatorType.Equality: return v1 == v2;
+ case BinaryOperatorType.InEquality: return v1 != v2;
+ default: throw ParseError ("Invalid binary operator.");
+ }
+ }
+
+ static object EvaluateOperation (BinaryOperatorType op, long v1, long v2)
+ {
+ switch (op) {
+ case BinaryOperatorType.Add: return v1 + v2;
+ case BinaryOperatorType.BitwiseAnd: return v1 & v2;
+ case BinaryOperatorType.BitwiseOr: return v1 | v2;
+ case BinaryOperatorType.ExclusiveOr: return v1 ^ v2;
+ case BinaryOperatorType.Divide: return v1 / v2;
+ case BinaryOperatorType.Modulus: return v1 % v2;
+ case BinaryOperatorType.Multiply: return v1 * v2;
+ case BinaryOperatorType.ShiftLeft: return v1 << (int) v2;
+ case BinaryOperatorType.ShiftRight: return v1 >> (int) v2;
+ case BinaryOperatorType.Subtract: return v1 - v2;
+ case BinaryOperatorType.GreaterThan: return v1 > v2;
+ case BinaryOperatorType.GreaterThanOrEqual: return v1 >= v2;
+ case BinaryOperatorType.LessThan: return v1 < v2;
+ case BinaryOperatorType.LessThanOrEqual: return v1 <= v2;
+ case BinaryOperatorType.Equality: return v1 == v2;
+ case BinaryOperatorType.InEquality: return v1 != v2;
+ default: throw ParseError ("Invalid binary operator.");
+ }
+ }
+
+ static object EvaluateStringOperation (BinaryOperatorType op, object v1, object v2)
+ {
+ switch (op) {
+ case BinaryOperatorType.Equality:
+ if (!(v1 == null || v1 is string) || !(v2 == null || v2 is string))
+ throw ParseError ("Invalid operands in binary operator.");
+ return ((string) v1) == ((string) v2);
+ case BinaryOperatorType.InEquality:
+ if (!(v1 == null || v1 is string) || !(v2 == null || v2 is string))
+ throw ParseError ("Invalid operands in binary operator.");
+ return ((string) v1) != ((string) v2);
+ case BinaryOperatorType.Add:
+ if (v1 == null) return v2.ToString ();
+ if (v2 == null) return v1.ToString ();
+ return v1.ToString () + v2.ToString ();
+ default:
+ throw ParseError ("Invalid operands in binary operator.");
+ }
+ }
+
+ static void ConvertValues<T> (EvaluationContext ctx, object actualV1, object actualV2, object toType, out T v1, out T v2)
+ {
+ try {
+ object c1 = ctx.Adapter.Cast (ctx, actualV1, toType);
+ v1 = (T) ctx.Adapter.TargetObjectToObject (ctx, c1);
+
+ object c2 = ctx.Adapter.Cast (ctx, actualV2, toType);
+ v2 = (T) ctx.Adapter.TargetObjectToObject (ctx, c2);
+ } catch {
+ throw ParseError ("Invalid operands in binary operator.");
+ }
+ }
+
+ static bool CheckReferenceEquality (EvaluationContext ctx, object v1, object v2)
+ {
+ if (v1 == null && v2 == null)
+ return true;
+
+ if (v1 == null || v2 == null)
+ return false;
+
+ object objectType = ctx.Adapter.GetType (ctx, "System.Object");
+ object[] argTypes = new object[] {
+ objectType, objectType
+ };
+ object[] args = new object[] {
+ v1, v2
+ };
+
+ object result = ctx.Adapter.RuntimeInvoke (ctx, objectType, null, "ReferenceEquals", argTypes, args);
+ var literal = LiteralValueReference.CreateTargetObjectLiteral (ctx, "result", result);
+
+ return (bool) literal.ObjectValue;
+ }
+
+ static bool CheckEquality (EvaluationContext ctx, bool negate, object v1, object v2)
+ {
+ if (v1 == null && v2 == null)
+ return true;
+
+ if (v1 == null || v2 == null)
+ return false;
+
+ string method = negate ? "op_Inequality" : "op_Equality";
+ object v1type = ctx.Adapter.GetValueType (ctx, v1);
+ object v2type = ctx.Adapter.GetValueType (ctx, v2);
+ object[] argTypes = new object[] { v2type };
+ object target, targetType;
+ object[] args;
+
+ if (ctx.Adapter.HasMethod (ctx, v1type, method, argTypes, BindingFlags.Instance | BindingFlags.Public)) {
+ args = new object[] { v2 };
+ targetType = v1type;
+ negate = false;
+ target = v1;
+ } else {
+ method = ctx.Adapter.IsValueType (v1type) ? "Equals" : "ReferenceEquals";
+ targetType = ctx.Adapter.GetType (ctx, "System.Object");
+ argTypes = new object[] { targetType, targetType };
+ args = new object[] { v1, v2 };
+ target = null;
+ }
+
+ object result = ctx.Adapter.RuntimeInvoke (ctx, targetType, target, method, argTypes, args);
+ var literal = LiteralValueReference.CreateTargetObjectLiteral (ctx, "result", result);
+ bool retval = (bool) literal.ObjectValue;
+
+ return negate ? !retval : retval;
+ }
+
+ ValueReference EvaluateBinaryOperatorExpression (BinaryOperatorType op, ValueReference left, Expression rightExp)
+ {
+ if (op == BinaryOperatorType.ConditionalAnd) {
+ object val = left.ObjectValue;
+ if (!(val is bool))
+ throw ParseError ("Left operand of logical And must be a boolean.");
+ if (!(bool)val)
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, false);
+ ValueReference vr = rightExp.AcceptVisitor<ValueReference> (this);
+ if (vr == null || ctx.Adapter.GetTypeName (ctx, vr.Type) != "System.Boolean")
+ throw ParseError ("Right operand of logical And must be a boolean.");
+ return vr;
+ }
+
+ if (op == BinaryOperatorType.ConditionalOr) {
+ object val = left.ObjectValue;
+ if (!(val is bool))
+ throw ParseError ("Left operand of logical Or must be a boolean.");
+ if ((bool)val)
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, true);
+ ValueReference vr = rightExp.AcceptVisitor<ValueReference> (this);
+ if (vr == null || ctx.Adapter.GetTypeName (ctx, vr.Type) != "System.Boolean")
+ throw ParseError ("Right operand of logical Or must be a boolean.");
+ return vr;
+ }
+
+ ValueReference right = rightExp.AcceptVisitor<ValueReference> (this);
+ object targetVal1 = left.Value;
+ object targetVal2 = right.Value;
+ object val1 = left.ObjectValue;
+ object val2 = right.ObjectValue;
+
+ if (op == BinaryOperatorType.Add) {
+ if (val1 is string || val2 is string) {
+ if (!(val1 is string) && val1 != null)
+ val1 = ctx.Adapter.CallToString (ctx, targetVal1);
+ if (!(val2 is string) && val2 != null)
+ val2 = ctx.Adapter.CallToString (ctx, targetVal2);
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, (string) val1 + (string) val2);
+ }
+ }
+
+ if ((op == BinaryOperatorType.ExclusiveOr) && (val1 is bool) && (val2 is bool))
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, (bool) val1 ^ (bool) val2);
+
+ if ((val1 == null || !ctx.Adapter.IsPrimitive (ctx, targetVal1)) && (val2 == null || !ctx.Adapter.IsPrimitive (ctx, targetVal2))) {
+ switch (op) {
+ case BinaryOperatorType.Equality:
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, CheckEquality (ctx, false, targetVal1, targetVal2));
+ case BinaryOperatorType.InEquality:
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, CheckEquality (ctx, true, targetVal1, targetVal2));
+ }
+ }
+
+ object res;
+
+ if (val1 is string || val2 is string) {
+ res = EvaluateStringOperation (op, val1, val2);
+ } else {
+ if (val1 == null || val2 == null || (val1 is bool) || (val2 is bool))
+ throw ParseError ("Invalid operands in binary operator.");
+
+ string opTypeName = GetCommonOperationType (val1, val2);
+ object opType = ctx.Adapter.GetType (ctx, opTypeName);
+
+ if (opTypeName == "System.Double") {
+ double v1, v2;
+
+ ConvertValues<double> (ctx, targetVal1, targetVal2, opType, out v1, out v2);
+ res = EvaluateOperation (op, v1, v2);
+ } else {
+ long v1, v2;
+
+ ConvertValues<long> (ctx, targetVal1, targetVal2, opType, out v1, out v2);
+ res = EvaluateOperation (op, v1, v2);
+ }
+ }
+
+ if (!(res is bool) && !(res is string)) {
+ if (ctx.Adapter.IsEnum (ctx, targetVal1)) {
+ object tval = ctx.Adapter.Cast (ctx, ctx.Adapter.CreateValue (ctx, res), ctx.Adapter.GetValueType (ctx, targetVal1));
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, expression, tval);
+ }
+
+ if (ctx.Adapter.IsEnum (ctx, targetVal2)) {
+ object tval = ctx.Adapter.Cast (ctx, ctx.Adapter.CreateValue (ctx, res), ctx.Adapter.GetValueType (ctx, targetVal2));
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, expression, tval);
+ }
+
+ res = Convert.ChangeType (res, GetCommonType (val1, val2));
+ }
+
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, res);
+ }
+
+ static string ResolveType (EvaluationContext ctx, MemberReferenceExpression mre, List<object> args)
+ {
+ string parent, name;
+
+ if (mre.Target is MemberReferenceExpression) {
+ parent = ResolveType (ctx, (MemberReferenceExpression) mre.Target, args);
+ } else if (mre.Target is IdentifierExpression) {
+ parent = ((IdentifierExpression) mre.Target).Identifier;
+ } else {
+ return null;
+ }
+
+ name = parent + "." + mre.MemberName;
+ if (mre.TypeArguments.Count > 0) {
+ name += "`" + mre.TypeArguments.Count;
+ foreach (var arg in mre.TypeArguments) {
+ object resolved = arg.Resolve (ctx);
+
+ if (resolved == null)
+ return null;
+
+ args.Add (resolved);
+ }
+ }
+
+ return name;
+ }
+
+ static object ResolveType (EvaluationContext ctx, MemberReferenceExpression mre)
+ {
+ var args = new List<object> ();
+ var name = ResolveType (ctx, mre, args);
+
+ if (name == null)
+ return null;
+
+ if (args.Count > 0)
+ return ctx.Adapter.GetType (ctx, name, args.ToArray ());
+
+ return ctx.Adapter.GetType (ctx, name);
+ }
+
+ static ValueReference ResolveTypeValueReference (EvaluationContext ctx, MemberReferenceExpression mre)
+ {
+ object resolved = ResolveType (ctx, mre);
+
+ if (resolved != null) {
+ ctx.Adapter.ForceLoadType (ctx, resolved);
+
+ return new TypeValueReference (ctx, resolved);
+ }
+
+ throw ParseError ("Could not resolve type: {0}", mre);
+ }
+
+ static ValueReference ResolveTypeValueReference (EvaluationContext ctx, AstType type)
+ {
+ object resolved = type.Resolve (ctx);
+
+ if (resolved != null) {
+ ctx.Adapter.ForceLoadType (ctx, resolved);
+
+ return new TypeValueReference (ctx, resolved);
+ }
+
+ throw ParseError ("Could not resolve type: {0}", ResolveTypeName (type));
+ }
+
+ #region IAstVisitor implementation
+
+ public ValueReference VisitAnonymousMethodExpression (AnonymousMethodExpression anonymousMethodExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitUndocumentedExpression (UndocumentedExpression undocumentedExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitArrayCreateExpression (ArrayCreateExpression arrayCreateExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitAsExpression (AsExpression asExpression)
+ {
+ var type = asExpression.Type.AcceptVisitor<ValueReference> (this) as TypeValueReference;
+ if (type == null)
+ throw ParseError ("Invalid type in cast.");
+
+ var val = asExpression.Expression.AcceptVisitor<ValueReference> (this);
+ var result = ctx.Adapter.TryCast (ctx, val.Value, type.Type);
+
+ if (result == null)
+ return new NullValueReference (ctx, type.Type);
+
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, expression, result);
+ }
+
+ public ValueReference VisitAssignmentExpression (AssignmentExpression assignmentExpression)
+ {
+ if (!options.AllowMethodEvaluation)
+ throw NotSupported ();
+
+ var left = assignmentExpression.Left.AcceptVisitor<ValueReference> (this);
+
+ if (assignmentExpression.Operator == AssignmentOperatorType.Assign) {
+ var right = assignmentExpression.Right.AcceptVisitor<ValueReference> (this);
+ left.Value = right.Value;
+ } else {
+ BinaryOperatorType op;
+
+ switch (assignmentExpression.Operator) {
+ case AssignmentOperatorType.Add: op = BinaryOperatorType.Add; break;
+ case AssignmentOperatorType.Subtract: op = BinaryOperatorType.Subtract; break;
+ case AssignmentOperatorType.Multiply: op = BinaryOperatorType.Multiply; break;
+ case AssignmentOperatorType.Divide: op = BinaryOperatorType.Divide; break;
+ case AssignmentOperatorType.Modulus: op = BinaryOperatorType.Modulus; break;
+ case AssignmentOperatorType.ShiftLeft: op = BinaryOperatorType.ShiftLeft; break;
+ case AssignmentOperatorType.ShiftRight: op = BinaryOperatorType.ShiftRight; break;
+ case AssignmentOperatorType.BitwiseAnd: op = BinaryOperatorType.BitwiseAnd; break;
+ case AssignmentOperatorType.BitwiseOr: op = BinaryOperatorType.BitwiseOr; break;
+ case AssignmentOperatorType.ExclusiveOr: op = BinaryOperatorType.ExclusiveOr; break;
+ default: throw ParseError ("Invalid operator in assignment.");
+ }
+
+ var result = EvaluateBinaryOperatorExpression (op, left, assignmentExpression.Right);
+ left.Value = result.Value;
+ }
+
+ return left;
+ }
+
+ public ValueReference VisitBaseReferenceExpression (BaseReferenceExpression baseReferenceExpression)
+ {
+ var self = ctx.Adapter.GetThisReference (ctx);
+
+ if (self != null)
+ return LiteralValueReference.CreateTargetBaseObjectLiteral (ctx, expression, self.Value);
+
+ throw ParseError ("'base' reference not available in static methods.");
+ }
+
+ public ValueReference VisitBinaryOperatorExpression (BinaryOperatorExpression binaryOperatorExpression)
+ {
+ var left = binaryOperatorExpression.Left.AcceptVisitor<ValueReference> (this);
+
+ return EvaluateBinaryOperatorExpression (binaryOperatorExpression.Operator, left, binaryOperatorExpression.Right);
+ }
+
+ public ValueReference VisitCastExpression (CastExpression castExpression)
+ {
+ var type = castExpression.Type.AcceptVisitor<ValueReference> (this) as TypeValueReference;
+ if (type == null)
+ throw ParseError ("Invalid type in cast.");
+
+ var val = castExpression.Expression.AcceptVisitor<ValueReference> (this);
+ object result = ctx.Adapter.TryCast (ctx, val.Value, type.Type);
+ if (result == null)
+ throw ParseError ("Invalid cast.");
+
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, expression, result);
+ }
+
+ public ValueReference VisitCheckedExpression (CheckedExpression checkedExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitConditionalExpression (ConditionalExpression conditionalExpression)
+ {
+ ValueReference val = conditionalExpression.Condition.AcceptVisitor<ValueReference> (this);
+ if (val is TypeValueReference)
+ throw NotSupported ();
+
+ if ((bool) val.ObjectValue)
+ return conditionalExpression.TrueExpression.AcceptVisitor<ValueReference> (this);
+
+ return conditionalExpression.FalseExpression.AcceptVisitor<ValueReference> (this);
+ }
+
+ public ValueReference VisitDefaultValueExpression (DefaultValueExpression defaultValueExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitDirectionExpression (DirectionExpression directionExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitIdentifierExpression (IdentifierExpression identifierExpression)
+ {
+ var name = identifierExpression.Identifier;
+
+ if (name == "__EXCEPTION_OBJECT__")
+ return ctx.Adapter.GetCurrentException (ctx);
+
+ // Look in user defined variables
+
+ ValueReference userVar;
+ if (userVariables.TryGetValue (name, out userVar))
+ return userVar;
+
+ // Look in variables
+
+ ValueReference var = ctx.Adapter.GetLocalVariable (ctx, name);
+ if (var != null)
+ return var;
+
+ // Look in parameters
+
+ var = ctx.Adapter.GetParameter (ctx, name);
+ if (var != null)
+ return var;
+
+ // Look in instance fields and properties
+
+ ValueReference self = ctx.Adapter.GetThisReference (ctx);
+
+ if (self != null) {
+ // check for fields and properties in this instance
+ var = ctx.Adapter.GetMember (ctx, self, self.Type, self.Value, name);
+ if (var != null)
+ return var;
+ }
+
+ // Look in static fields & properties of the enclosing type and all parent types
+
+ object type = ctx.Adapter.GetEnclosingType (ctx);
+ object vtype = type;
+
+ while (vtype != null) {
+ // check for static fields and properties
+ var = ctx.Adapter.GetMember (ctx, null, vtype, null, name);
+ if (var != null)
+ return var;
+
+ vtype = ctx.Adapter.GetParentType (ctx, vtype);
+ }
+
+ // Look in types
+
+ vtype = ctx.Adapter.GetType (ctx, name);
+ if (vtype != null)
+ return new TypeValueReference (ctx, vtype);
+
+ // Look in nested types
+
+ if (type != null) {
+ foreach (object ntype in ctx.Adapter.GetNestedTypes (ctx, type)) {
+ if (TypeValueReference.GetTypeName (ctx.Adapter.GetTypeName (ctx, ntype)) == name)
+ return new TypeValueReference (ctx, ntype);
+ }
+
+ string[] namespaces = ctx.Adapter.GetImportedNamespaces (ctx);
+ if (namespaces.Length > 0) {
+ // Look in namespaces
+ foreach (string ns in namespaces) {
+ string nm = ns + "." + name;
+ vtype = ctx.Adapter.ForceLoadType (ctx, nm);
+ if (vtype != null)
+ return new TypeValueReference (ctx, vtype);
+ }
+
+ foreach (string ns in namespaces) {
+ if (ns == name || ns.StartsWith (name + ".", StringComparison.InvariantCulture))
+ return new NamespaceValueReference (ctx, name);
+ }
+ }
+ }
+
+ if (self == null && ctx.Adapter.HasMember (ctx, type, name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+ string message = string.Format ("An object reference is required for the non-static field, method, or property '{0}.{1}'.",
+ ctx.Adapter.GetDisplayTypeName (ctx, type), name);
+ throw ParseError (message);
+ }
+
+ throw ParseError ("Unknown identifier: {0}", name);
+ }
+
+ public ValueReference VisitIndexerExpression (IndexerExpression indexerExpression)
+ {
+ int n = 0;
+
+ var target = indexerExpression.Target.AcceptVisitor<ValueReference> (this);
+ if (target is TypeValueReference)
+ throw NotSupported ();
+
+ if (ctx.Adapter.IsArray (ctx, target.Value)) {
+ int[] indexes = new int [indexerExpression.Arguments.Count];
+
+ foreach (var arg in indexerExpression.Arguments) {
+ var index = arg.AcceptVisitor<ValueReference> (this);
+ indexes[n++] = (int) Convert.ChangeType (index.ObjectValue, typeof (int));
+ }
+
+ return new ArrayValueReference (ctx, target.Value, indexes);
+ }
+
+ object[] args = new object [indexerExpression.Arguments.Count];
+ foreach (var arg in indexerExpression.Arguments)
+ args[n++] = arg.AcceptVisitor<ValueReference> (this).Value;
+
+ var indexer = ctx.Adapter.GetIndexerReference (ctx, target.Value, args);
+ if (indexer == null)
+ throw NotSupported ();
+
+ return indexer;
+ }
+
+ string ResolveMethodName (MemberReferenceExpression mre, out object[] typeArgs)
+ {
+ if (mre.TypeArguments.Count > 0) {
+ List<object> args = new List<object> ();
+
+ foreach (var arg in mre.TypeArguments) {
+ var type = arg.AcceptVisitor (this);
+ args.Add (type.Type);
+ }
+
+ typeArgs = args.ToArray ();
+ } else {
+ typeArgs = null;
+ }
+
+ return mre.MemberName;
+ }
+
+ public ValueReference VisitInvocationExpression (InvocationExpression invocationExpression)
+ {
+ if (!options.AllowMethodEvaluation)
+ throw NotSupported ();
+
+ bool invokeBaseMethod = false;
+ ValueReference target = null;
+ string methodName;
+
+ object[] types = new object [invocationExpression.Arguments.Count];
+ object[] args = new object [invocationExpression.Arguments.Count];
+ object[] typeArgs = null;
+ int n = 0;
+
+ foreach (var arg in invocationExpression.Arguments) {
+ var vref = arg.AcceptVisitor<ValueReference> (this);
+ args[n] = vref.Value;
+ types[n] = ctx.Adapter.GetValueType (ctx, args[n]);
+ n++;
+ }
+
+ if (invocationExpression.Target is MemberReferenceExpression) {
+ var field = (MemberReferenceExpression) invocationExpression.Target;
+ target = field.Target.AcceptVisitor<ValueReference> (this);
+ if (field.Target is BaseReferenceExpression)
+ invokeBaseMethod = true;
+ methodName = ResolveMethodName (field, out typeArgs);
+ } else if (invocationExpression.Target is IdentifierExpression) {
+ methodName = ((IdentifierExpression) invocationExpression.Target).Identifier;
+ var vref = ctx.Adapter.GetThisReference (ctx);
+
+ if (vref != null && ctx.Adapter.HasMethod (ctx, vref.Type, methodName, BindingFlags.Instance)) {
+ // There is an instance method for 'this', although it may not have an exact signature match. Check it now.
+ if (ctx.Adapter.HasMethod (ctx, vref.Type, methodName, types, BindingFlags.Instance)) {
+ target = vref;
+ } else {
+ // There isn't an instance method with exact signature match.
+ // If there isn't a static method, then use the instance method,
+ // which will report the signature match error when invoked
+ object etype = ctx.Adapter.GetEnclosingType (ctx);
+ if (!ctx.Adapter.HasMethod (ctx, etype, methodName, types, BindingFlags.Static))
+ target = vref;
+ }
+ } else {
+ if (ctx.Adapter.HasMethod (ctx, ctx.Adapter.GetEnclosingType (ctx), methodName, types, BindingFlags.Instance))
+ throw new EvaluatorException ("Cannot invoke an instance method from a static method.");
+ target = null;
+ }
+ } else {
+ throw NotSupported ();
+ }
+
+ object vtype = target != null ? target.Type : ctx.Adapter.GetEnclosingType (ctx);
+ object vtarget = (target is TypeValueReference) || target == null ? null : target.Value;
+
+ if (invokeBaseMethod) {
+ vtype = ctx.Adapter.GetBaseType (ctx, vtype);
+ } else if (target != null && !ctx.Adapter.HasMethod (ctx, vtype, methodName, typeArgs, types, BindingFlags.Instance | BindingFlags.Static)) {
+ // Look for LINQ extension methods...
+ var linq = ctx.Adapter.GetType (ctx, "System.Linq.Enumerable");
+ if (linq != null) {
+ object[] xtypeArgs = typeArgs;
+
+ if (xtypeArgs == null) {
+ // try to infer the generic type arguments from the type of the object...
+ object xtype = vtype;
+ while (xtype != null && !ctx.Adapter.IsGenericType (ctx, xtype))
+ xtype = ctx.Adapter.GetBaseType (ctx, xtype);
+
+ if (xtype != null)
+ xtypeArgs = ctx.Adapter.GetTypeArgs (ctx, xtype);
+ }
+
+ if (xtypeArgs != null) {
+ var xtypes = new object[types.Length + 1];
+ Array.Copy (types, 0, xtypes, 1, types.Length);
+ xtypes[0] = vtype;
+
+ var xargs = new object[args.Length + 1];
+ Array.Copy (args, 0, xargs, 1, args.Length);
+ xargs[0] = vtarget;
+
+ if (ctx.Adapter.HasMethod (ctx, linq, methodName, xtypeArgs, xtypes, BindingFlags.Static)) {
+ vtarget = null;
+ vtype = linq;
+
+ typeArgs = xtypeArgs;
+ types = xtypes;
+ args = xargs;
+ }
+ }
+ }
+ }
+
+ object result = ctx.Adapter.RuntimeInvoke (ctx, vtype, vtarget, methodName, typeArgs, types, args);
+ if (result != null)
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, expression, result);
+
+ return LiteralValueReference.CreateVoidReturnLiteral (ctx, expression);
+ }
+
+ public ValueReference VisitIsExpression (IsExpression isExpression)
+ {
+ // FIXME: we could probably implement this one...
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitLambdaExpression (LambdaExpression lambdaExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitMemberReferenceExpression (MemberReferenceExpression memberReferenceExpression)
+ {
+ if (memberReferenceExpression.TypeArguments.Count > 0)
+ return ResolveTypeValueReference (ctx, memberReferenceExpression);
+
+ var target = memberReferenceExpression.Target.AcceptVisitor<ValueReference> (this);
+ var member = target.GetChild (memberReferenceExpression.MemberName, ctx.Options);
+
+ if (member == null) {
+ if (!(target is TypeValueReference)) {
+ if (ctx.Adapter.IsNull (ctx, target.Value))
+ throw new EvaluatorException ("{0} is null", target.Name);
+ }
+
+ throw ParseError ("Unknown member: {0}", memberReferenceExpression.MemberName);
+ }
+
+ return member;
+ }
+
+ public ValueReference VisitNamedArgumentExpression (NamedArgumentExpression namedArgumentExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitNamedExpression (NamedExpression namedExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitNullReferenceExpression (NullReferenceExpression nullReferenceExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitObjectCreateExpression (ObjectCreateExpression objectCreateExpression)
+ {
+ var type = objectCreateExpression.Type.AcceptVisitor<ValueReference> (this) as TypeValueReference;
+ var args = new List<object> ();
+
+ foreach (var arg in objectCreateExpression.Arguments) {
+ var val = arg.AcceptVisitor<ValueReference> (this);
+ args.Add (val != null ? val.Value : null);
+ }
+
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, expression, ctx.Adapter.CreateValue (ctx, type.Type, args.ToArray ()));
+ }
+
+ public ValueReference VisitAnonymousTypeCreateExpression (AnonymousTypeCreateExpression anonymousTypeCreateExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression)
+ {
+ return parenthesizedExpression.Expression.AcceptVisitor<ValueReference> (this);
+ }
+
+ public ValueReference VisitPointerReferenceExpression (PointerReferenceExpression pointerReferenceExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitPrimitiveExpression (PrimitiveExpression primitiveExpression)
+ {
+ if (primitiveExpression.Value != null)
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, primitiveExpression.Value);
+
+ if (expectedType != null)
+ return new NullValueReference (ctx, expectedType);
+
+ return new NullValueReference (ctx, ctx.Adapter.GetType (ctx, "System.Object"));
+ }
+
+ public ValueReference VisitSizeOfExpression (SizeOfExpression sizeOfExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitStackAllocExpression (StackAllocExpression stackAllocExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitThisReferenceExpression (ThisReferenceExpression thisReferenceExpression)
+ {
+ var self = ctx.Adapter.GetThisReference (ctx);
+
+ if (self == null)
+ throw ParseError ("'this' reference not available in the current evaluation context.");
+
+ return self;
+ }
+
+ public ValueReference VisitTypeOfExpression (TypeOfExpression typeOfExpression)
+ {
+ var name = ResolveTypeName (typeOfExpression.Type);
+ var type = typeOfExpression.Type.Resolve (ctx);
+
+ if (type == null)
+ throw ParseError ("Could not load type: {0}", name);
+
+ object result = ctx.Adapter.CreateTypeObject (ctx, type);
+ if (result == null)
+ throw NotSupported ();
+
+ return LiteralValueReference.CreateTargetObjectLiteral (ctx, name, result);
+ }
+
+ public ValueReference VisitTypeReferenceExpression (TypeReferenceExpression typeReferenceExpression)
+ {
+ var type = typeReferenceExpression.Type.Resolve (ctx);
+
+ if (type != null) {
+ ctx.Adapter.ForceLoadType (ctx, type);
+
+ return new TypeValueReference (ctx, type);
+ }
+
+ var name = ResolveTypeName (typeReferenceExpression.Type);
+
+ // Assume it is a namespace.
+ return new NamespaceValueReference (ctx, name);
+ }
+
+ public ValueReference VisitUnaryOperatorExpression (UnaryOperatorExpression unaryOperatorExpression)
+ {
+ var vref = unaryOperatorExpression.Expression.AcceptVisitor<ValueReference> (this);
+ var val = vref.ObjectValue;
+ object newVal;
+ long num;
+
+ switch (unaryOperatorExpression.Operator) {
+ case UnaryOperatorType.BitNot:
+ num = ~GetInteger (val);
+ val = Convert.ChangeType (num, val.GetType ());
+ break;
+ case UnaryOperatorType.Minus:
+ num = -GetInteger (val);
+ val = Convert.ChangeType (num, val.GetType ());
+ break;
+ case UnaryOperatorType.Not:
+ if (!(val is bool))
+ throw ParseError ("Expected boolean type in Not operator.");
+
+ val = !(bool) val;
+ break;
+ case UnaryOperatorType.PostDecrement:
+ num = GetInteger (val) - 1;
+ newVal = Convert.ChangeType (num, val.GetType ());
+ vref.Value = ctx.Adapter.CreateValue (ctx, newVal);
+ break;
+ case UnaryOperatorType.Decrement:
+ num = GetInteger (val) - 1;
+ val = Convert.ChangeType (num, val.GetType ());
+ vref.Value = ctx.Adapter.CreateValue (ctx, val);
+ break;
+ case UnaryOperatorType.PostIncrement:
+ num = GetInteger (val) + 1;
+ newVal = Convert.ChangeType (num, val.GetType ());
+ vref.Value = ctx.Adapter.CreateValue (ctx, newVal);
+ break;
+ case UnaryOperatorType.Increment:
+ num = GetInteger (val) + 1;
+ val = Convert.ChangeType (num, val.GetType ());
+ vref.Value = ctx.Adapter.CreateValue (ctx, val);
+ break;
+ case UnaryOperatorType.Plus:
+ break;
+ default:
+ throw NotSupported ();
+ }
+
+ return LiteralValueReference.CreateObjectLiteral (ctx, expression, val);
+ }
+
+ public ValueReference VisitUncheckedExpression (UncheckedExpression uncheckedExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitEmptyExpression (EmptyExpression emptyExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryExpression (QueryExpression queryExpression)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryContinuationClause (QueryContinuationClause queryContinuationClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryFromClause (QueryFromClause queryFromClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryLetClause (QueryLetClause queryLetClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryWhereClause (QueryWhereClause queryWhereClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryJoinClause (QueryJoinClause queryJoinClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryOrderClause (QueryOrderClause queryOrderClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryOrdering (QueryOrdering queryOrdering)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQuerySelectClause (QuerySelectClause querySelectClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitQueryGroupClause (QueryGroupClause queryGroupClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitAttribute (ICSharpCode.NRefactory.CSharp.Attribute attribute)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitAttributeSection (AttributeSection attributeSection)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitDelegateDeclaration (DelegateDeclaration delegateDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitTypeDeclaration (TypeDeclaration typeDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitUsingAliasDeclaration (UsingAliasDeclaration usingAliasDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitUsingDeclaration (UsingDeclaration usingDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitExternAliasDeclaration (ExternAliasDeclaration externAliasDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitBlockStatement (BlockStatement blockStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitBreakStatement (BreakStatement breakStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitCheckedStatement (CheckedStatement checkedStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitContinueStatement (ContinueStatement continueStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitDoWhileStatement (DoWhileStatement doWhileStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitEmptyStatement (EmptyStatement emptyStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitExpressionStatement (ExpressionStatement expressionStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitFixedStatement (FixedStatement fixedStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitForeachStatement (ForeachStatement foreachStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitForStatement (ForStatement forStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitGotoCaseStatement (GotoCaseStatement gotoCaseStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitGotoDefaultStatement (GotoDefaultStatement gotoDefaultStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitGotoStatement (GotoStatement gotoStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitIfElseStatement (IfElseStatement ifElseStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitLabelStatement (LabelStatement labelStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitLockStatement (LockStatement lockStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitReturnStatement (ReturnStatement returnStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitSwitchStatement (SwitchStatement switchStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitSwitchSection (SwitchSection switchSection)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitCaseLabel (CaseLabel caseLabel)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitThrowStatement (ThrowStatement throwStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitTryCatchStatement (TryCatchStatement tryCatchStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitCatchClause (CatchClause catchClause)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitUncheckedStatement (UncheckedStatement uncheckedStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitUnsafeStatement (UnsafeStatement unsafeStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitUsingStatement (UsingStatement usingStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitWhileStatement (WhileStatement whileStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitYieldBreakStatement (YieldBreakStatement yieldBreakStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitYieldReturnStatement (YieldReturnStatement yieldReturnStatement)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitAccessor (Accessor accessor)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitConstructorInitializer (ConstructorInitializer constructorInitializer)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitEnumMemberDeclaration (EnumMemberDeclaration enumMemberDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitEventDeclaration (EventDeclaration eventDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitCustomEventDeclaration (CustomEventDeclaration customEventDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitFieldDeclaration (FieldDeclaration fieldDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitMethodDeclaration (MethodDeclaration methodDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitVariableInitializer (VariableInitializer variableInitializer)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitFixedFieldDeclaration (FixedFieldDeclaration fixedFieldDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitFixedVariableInitializer (FixedVariableInitializer fixedVariableInitializer)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitSyntaxTree (SyntaxTree syntaxTree)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitSimpleType (SimpleType simpleType)
+ {
+ return ResolveTypeValueReference (ctx, simpleType);
+ }
+
+ public ValueReference VisitMemberType (MemberType memberType)
+ {
+ return ResolveTypeValueReference (ctx, memberType);
+ }
+
+ public ValueReference VisitComposedType (ComposedType composedType)
+ {
+ return ResolveTypeValueReference (ctx, composedType);
+ }
+
+ public ValueReference VisitArraySpecifier (ArraySpecifier arraySpecifier)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitPrimitiveType (PrimitiveType primitiveType)
+ {
+ return ResolveTypeValueReference (ctx, primitiveType);
+ }
+
+ public ValueReference VisitComment (Comment comment)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitWhitespace (WhitespaceNode whitespaceNode)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitText (TextNode textNode)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitNewLine (NewLineNode newLineNode)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitDocumentationReference (DocumentationReference documentationReference)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitTypeParameterDeclaration (TypeParameterDeclaration typeParameterDeclaration)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitConstraint (Constraint constraint)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitCSharpTokenNode (CSharpTokenNode cSharpTokenNode)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitIdentifier (Identifier identifier)
+ {
+ throw NotSupported ();
+ }
+
+ public ValueReference VisitPatternPlaceholder (AstNode placeholder, ICSharpCode.NRefactory.PatternMatching.Pattern pattern)
+ {
+ throw NotSupported ();
+ }
+
+ #endregion
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionResolverVisitor.cs b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionResolverVisitor.cs
new file mode 100644
index 0000000..9369de6
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionResolverVisitor.cs
@@ -0,0 +1,131 @@
+//
+// NRefactoryExpressionResolverVisitor.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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.Text;
+using System.Collections.Generic;
+
+using ICSharpCode.NRefactory.CSharp;
+
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ // FIXME: if we passed the DebuggerSession and SourceLocation into the NRefactoryExpressionEvaluatorVisitor,
+ // we wouldn't need to do this resolve step.
+ public class NRefactoryExpressionResolverVisitor : DepthFirstAstVisitor
+ {
+ readonly List<Replacement> replacements = new List<Replacement> ();
+ readonly SourceLocation location;
+ readonly DebuggerSession session;
+ readonly string expression;
+
+ class Replacement
+ {
+ public string NewText;
+ public int Offset;
+ public int Length;
+ }
+
+ public NRefactoryExpressionResolverVisitor (DebuggerSession session, SourceLocation location, string expression)
+ {
+ this.expression = expression.Replace ("\n", "").Replace ("\r", "");
+ this.session = session;
+ this.location = location;
+ }
+
+ internal string GetResolvedExpression ()
+ {
+ if (replacements.Count == 0)
+ return expression;
+
+ replacements.Sort ((Replacement r1, Replacement r2) => r1.Offset.CompareTo (r2.Offset));
+ StringBuilder sb = new StringBuilder ();
+ int i = 0;
+
+ foreach (Replacement r in replacements) {
+ sb.Append (expression, i, r.Offset - i);
+ sb.Append (r.NewText);
+ i = r.Offset + r.Length;
+ }
+
+ Replacement last = replacements [replacements.Count - 1];
+ sb.Append (expression, last.Offset + last.Length, expression.Length - (last.Offset + last.Length));
+
+ return sb.ToString ();
+ }
+
+ void ReplaceType (string name, int offset, int length)
+ {
+ string type = session.ResolveIdentifierAsType (name, location);
+ if (!string.IsNullOrEmpty (type)) {
+ type = "global::" + type;
+ Replacement r = new Replacement () { Offset = offset, Length = length, NewText = type };
+ replacements.Add (r);
+ }
+ }
+
+ void ReplaceType (AstType type)
+ {
+ int length = type.EndLocation.Column - type.StartLocation.Column;
+ int offset = type.StartLocation.Column - 1;
+
+ ReplaceType (type.ToString (), offset, length);
+ }
+
+ public override void VisitIdentifierExpression (IdentifierExpression identifierExpression)
+ {
+ base.VisitIdentifierExpression (identifierExpression);
+
+ int length = identifierExpression.EndLocation.Column - identifierExpression.StartLocation.Column;
+ int offset = identifierExpression.StartLocation.Column - 1;
+
+ ReplaceType (identifierExpression.Identifier, offset, length);
+ }
+
+ public override void VisitTypeReferenceExpression (TypeReferenceExpression typeReferenceExpression)
+ {
+ ReplaceType (typeReferenceExpression.Type);
+ }
+
+ public override void VisitComposedType (ComposedType composedType)
+ {
+ // Note: we specifically do not handle this case because the 'base' implementation will eventually
+ // call VisitMemberType() or VisitSimpleType() on the ComposedType.BaseType which is all we really
+ // care to resolve.
+ base.VisitComposedType (composedType);
+ }
+
+ public override void VisitMemberType (MemberType memberType)
+ {
+ ReplaceType (memberType);
+ }
+
+ public override void VisitSimpleType (SimpleType simpleType)
+ {
+ ReplaceType (simpleType);
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExtensions.cs b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExtensions.cs
new file mode 100644
index 0000000..cb8eb0d
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExtensions.cs
@@ -0,0 +1,182 @@
+//
+// NRefactoryExtensions.cs
+//
+// Author: Jeffrey Stedfast <jeff at xamarin.com>
+//
+// Copyright (c) 2013 Xamarin Inc.
+//
+// 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 ICSharpCode.NRefactory.CSharp;
+
+namespace Mono.Debugging.Evaluation
+{
+ public static class NRefactoryExtensions
+ {
+ #region AstType
+
+ public static object Resolve (this AstType type, EvaluationContext ctx)
+ {
+ var args = new List<object> ();
+ var name = type.Resolve (ctx, args);
+
+ //if (name.StartsWith ("global::", StringComparison.Ordinal))
+ // name = name.Substring ("global::".Length);
+
+ if (args.Count > 0)
+ return ctx.Adapter.GetType (ctx, name, args.ToArray ());
+
+ return ctx.Adapter.GetType (ctx, name);
+ }
+
+ static string Resolve (this AstType type, EvaluationContext ctx, List<object> args)
+ {
+ if (type is PrimitiveType)
+ return Resolve ((PrimitiveType) type, ctx, args);
+ else if (type is ComposedType)
+ return Resolve ((ComposedType) type, ctx, args);
+ else if (type is MemberType)
+ return Resolve ((MemberType) type, ctx, args);
+ else if (type is SimpleType)
+ return Resolve ((SimpleType) type, ctx, args);
+
+ return null;
+ }
+
+ #endregion AstType
+
+ #region ComposedType
+
+ static string Resolve (this ComposedType type, EvaluationContext ctx, List<object> args)
+ {
+ string name;
+
+ if (type.HasNullableSpecifier) {
+ args.Insert (0, type.BaseType.Resolve (ctx));
+ name = "System.Nullable`1";
+ } else {
+ name = type.BaseType.Resolve (ctx, args);
+ }
+
+ if (type.PointerRank > 0)
+ name += new string ('*', type.PointerRank);
+
+ if (type.ArraySpecifiers.Count > 0) {
+ foreach (var spec in type.ArraySpecifiers) {
+ if (spec.Dimensions > 1)
+ name += "[" + new string (',', spec.Dimensions - 1) + "]";
+ else
+ name += "[]";
+ }
+ }
+
+ return name;
+ }
+
+ #endregion ComposedType
+
+ #region MemberType
+
+ static string Resolve (this MemberType type, EvaluationContext ctx, List<object> args)
+ {
+ string name;
+
+ if (!type.IsDoubleColon) {
+ var parent = type.Target.Resolve (ctx, args);
+ name = parent + "." + type.MemberName;
+ } else {
+ name = type.MemberName;
+ }
+
+ if (type.TypeArguments.Count > 0) {
+ name += "`" + type.TypeArguments.Count;
+ foreach (var arg in type.TypeArguments) {
+ object resolved;
+
+ if ((resolved = arg.Resolve (ctx)) == null)
+ return null;
+
+ args.Add (resolved);
+ }
+ }
+
+ return name;
+ }
+
+ #endregion MemberType
+
+ #region PrimitiveType
+
+ public static string Resolve (this PrimitiveType type)
+ {
+ switch (type.Keyword) {
+ case "bool": return "System.Boolean";
+ case "sbyte": return "System.SByte";
+ case "byte": return "System.Byte";
+ case "char": return "System.Char";
+ case "short": return "System.Int16";
+ case "ushort": return "System.UInt16";
+ case "int": return "System.Int32";
+ case "uint": return "System.UInt32";
+ case "long": return "System.Int64";
+ case "ulong": return "System.UInt64";
+ case "float": return "System.Single";
+ case "double": return "System.Double";
+ case "decimal": return "System.Decimal";
+ case "string": return "System.String";
+ case "object": return "System.Object";
+ case "void": return "System.Void";
+ default: return null;
+ }
+ }
+
+ static string Resolve (this PrimitiveType type, EvaluationContext ctx, List<object> args)
+ {
+ return Resolve (type);
+ }
+
+ #endregion PrimitiveType
+
+ #region SimpleType
+
+ static string Resolve (this SimpleType type, EvaluationContext ctx, List<object> args)
+ {
+ string name = type.Identifier;
+
+ if (type.TypeArguments.Count > 0) {
+ name += "`" + type.TypeArguments.Count;
+ foreach (var arg in type.TypeArguments) {
+ object resolved;
+
+ if ((resolved = arg.Resolve (ctx)) == null)
+ return null;
+
+ args.Add (resolved);
+ }
+ }
+
+ return name;
+ }
+
+ #endregion SimpleType
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/NamespaceValueReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/NamespaceValueReference.cs
new file mode 100644
index 0000000..5975124
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/NamespaceValueReference.cs
@@ -0,0 +1,150 @@
+// NamespaceValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class NamespaceValueReference: ValueReference
+ {
+ readonly string namspace;
+ readonly string name;
+
+ public NamespaceValueReference (EvaluationContext ctx, string name) : base (ctx)
+ {
+ this.namspace = name;
+ int i = namspace.LastIndexOf ('.');
+ if (i != -1)
+ this.name = namspace.Substring (i+1);
+ else
+ this.name = namspace;
+ }
+
+ public override object Value {
+ get {
+ throw new NotSupportedException();
+ }
+ set {
+ throw new NotSupportedException();
+ }
+ }
+
+
+ public override object Type {
+ get {
+ throw new NotSupportedException();
+ }
+ }
+
+
+ public override object ObjectValue {
+ get {
+ throw new NotSupportedException ();
+ }
+ }
+
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.Namespace;
+ }
+ }
+
+ public override ValueReference GetChild (string name, EvaluationOptions options)
+ {
+ string newNs = namspace + "." + name;
+
+ EvaluationContext ctx = GetContext (options);
+ object t = ctx.Adapter.GetType (ctx, newNs);
+ if (t != null)
+ return new TypeValueReference (ctx, t);
+
+ return new NamespaceValueReference (ctx, newNs);
+ }
+
+ public override ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ List<ObjectValue> obs = new List<ObjectValue> ();
+ foreach (ValueReference val in GetChildReferences (options)) {
+ obs.Add (val.CreateObjectValue (options));
+ }
+ return obs.ToArray ();
+ }
+
+ public override IEnumerable<ValueReference> GetChildReferences (EvaluationOptions options)
+ {
+ // Child types
+
+ string[] childNamespaces;
+ string[] childTypes;
+
+ EvaluationContext ctx = GetContext (options);
+ ctx.Adapter.GetNamespaceContents (ctx, namspace, out childNamespaces, out childTypes);
+
+ List<ValueReference> list = new List<ValueReference> ();
+ foreach (string typeName in childTypes) {
+ object tt = ctx.Adapter.GetType (ctx, typeName);
+ if (tt != null)
+ list.Add (new TypeValueReference (ctx, tt));
+ }
+ list.Sort (delegate (ValueReference v1, ValueReference v2) {
+ return v1.Name.CompareTo (v2.Name);
+ });
+
+ // Child namespaces
+
+ List<ValueReference> listNs = new List<ValueReference> ();
+ foreach (string ns in childNamespaces)
+ listNs.Add (new NamespaceValueReference (ctx, ns));
+ listNs.Sort (delegate (ValueReference v1, ValueReference v2) {
+ return v1.Name.CompareTo (v2.Name);
+ });
+ list.AddRange (listNs);
+ return list;
+ }
+
+ protected override Mono.Debugging.Client.ObjectValue OnCreateObjectValue (EvaluationOptions options)
+ {
+ return Mono.Debugging.Client.ObjectValue.CreateObject (this, new ObjectPath (Name), "<namespace>", namspace, Flags, null);
+ }
+
+ public override string CallToString ()
+ {
+ return namspace;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/NullValueReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/NullValueReference.cs
new file mode 100644
index 0000000..5f67c85
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/NullValueReference.cs
@@ -0,0 +1,97 @@
+// NullValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class NullValueReference: ValueReference
+ {
+ readonly object type;
+ object obj;
+ bool valueCreated;
+
+ public NullValueReference (EvaluationContext ctx, object type) : base (ctx)
+ {
+ this.type = type;
+ }
+
+ public override object Value {
+ get {
+ if (!valueCreated) {
+ valueCreated = true;
+ obj = Context.Adapter.CreateNullValue (Context, type);
+ }
+ return obj;
+ }
+ set {
+ throw new NotSupportedException();
+ }
+ }
+
+ public override object Type {
+ get {
+ return type;
+ }
+ }
+
+ public override object ObjectValue {
+ get {
+ return null;
+ }
+ }
+
+ public override string Name {
+ get {
+ return "null";
+ }
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.Literal;
+ }
+ }
+
+ protected override ObjectValue OnCreateObjectValue (EvaluationOptions options)
+ {
+ string tn = Context.Adapter.GetTypeName (GetContext (options), Type);
+ return Mono.Debugging.Client.ObjectValue.CreateObject (null, new ObjectPath (Name), tn, "null", Flags, null);
+ }
+
+ public override ValueReference GetChild (string name, EvaluationOptions options)
+ {
+ return null;
+ }
+
+ public override ObjectValue[] GetChildren (Mono.Debugging.Client.ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ return new ObjectValue [0];
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ObjectValueAdaptor.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ObjectValueAdaptor.cs
new file mode 100644
index 0000000..950d2fe
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ObjectValueAdaptor.cs
@@ -0,0 +1,1380 @@
+//
+// ObjectValueAdaptor.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at 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.Linq;
+using System.Text;
+using System.Reflection;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+using Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+
+namespace Mono.Debugging.Evaluation
+{
+ public abstract class ObjectValueAdaptor: IDisposable
+ {
+ readonly Dictionary<string, TypeDisplayData> typeDisplayData = new Dictionary<string, TypeDisplayData> ();
+
+ // Time to wait while evaluating before switching to async mode
+ public int DefaultEvaluationWaitTime { get; set; }
+
+ public event EventHandler<BusyStateEventArgs> BusyStateChanged;
+
+ static readonly Dictionary<string, string> CSharpTypeNames = new Dictionary<string, string> ();
+ readonly AsyncEvaluationTracker asyncEvaluationTracker = new AsyncEvaluationTracker ();
+ readonly AsyncOperationManager asyncOperationManager = new AsyncOperationManager ();
+
+ static ObjectValueAdaptor ()
+ {
+ CSharpTypeNames["System.Void"] = "void";
+ CSharpTypeNames["System.Object"] = "object";
+ CSharpTypeNames["System.Boolean"] = "bool";
+ CSharpTypeNames["System.Byte"] = "byte";
+ CSharpTypeNames["System.SByte"] = "sbyte";
+ CSharpTypeNames["System.Char"] = "char";
+ CSharpTypeNames["System.Enum"] = "enum";
+ CSharpTypeNames["System.Int16"] = "short";
+ CSharpTypeNames["System.Int32"] = "int";
+ CSharpTypeNames["System.Int64"] = "long";
+ CSharpTypeNames["System.UInt16"] = "ushort";
+ CSharpTypeNames["System.UInt32"] = "uint";
+ CSharpTypeNames["System.UInt64"] = "ulong";
+ CSharpTypeNames["System.Single"] = "float";
+ CSharpTypeNames["System.Double"] = "double";
+ CSharpTypeNames["System.Decimal"] = "decimal";
+ CSharpTypeNames["System.String"] = "string";
+ }
+
+ protected ObjectValueAdaptor ()
+ {
+ DefaultEvaluationWaitTime = 100;
+
+ asyncOperationManager.BusyStateChanged += delegate(object sender, BusyStateEventArgs e) {
+ OnBusyStateChanged (e);
+ };
+ asyncEvaluationTracker.WaitTime = DefaultEvaluationWaitTime;
+ }
+
+ public void Dispose ()
+ {
+ asyncEvaluationTracker.Dispose ();
+ asyncOperationManager.Dispose ();
+ }
+
+ public ObjectValue CreateObjectValue (EvaluationContext ctx, IObjectValueSource source, ObjectPath path, object obj, ObjectValueFlags flags)
+ {
+ try {
+ return CreateObjectValueImpl (ctx, source, path, obj, flags);
+ } catch (EvaluatorAbortedException ex) {
+ return ObjectValue.CreateFatalError (path.LastName, ex.Message, flags);
+ } catch (EvaluatorException ex) {
+ return ObjectValue.CreateFatalError (path.LastName, ex.Message, flags);
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ return ObjectValue.CreateFatalError (path.LastName, ex.Message, flags);
+ }
+ }
+
+ public virtual string GetDisplayTypeName (string typeName)
+ {
+ return GetDisplayTypeName (typeName.Replace ('+', '.'), 0, typeName.Length);
+ }
+
+ public string GetDisplayTypeName (EvaluationContext ctx, object type)
+ {
+ return GetDisplayTypeName (GetTypeName (ctx, type));
+ }
+
+ string GetDisplayTypeName (string typeName, int startIndex, int endIndex)
+ {
+ // Note: '[' denotes the start of an array
+ // '`' denotes a generic type
+ // ',' denotes the start of the assembly name
+ int tokenIndex = typeName.IndexOfAny (new char [] { '[', '`', ',' }, startIndex, endIndex - startIndex);
+ List<string> genericArgs = null;
+ string array = string.Empty;
+ int genericEndIndex = -1;
+ int typeEndIndex;
+
+ retry:
+ if (tokenIndex == -1) // Simple type
+ return GetShortTypeName (typeName.Substring (startIndex, endIndex - startIndex));
+
+ if (typeName[tokenIndex] == ',') // Simple type with an assembly name
+ return GetShortTypeName (typeName.Substring (startIndex, tokenIndex - startIndex));
+
+ // save the index of the end of the type name
+ typeEndIndex = tokenIndex;
+
+ // decode generic args first, if this is a generic type
+ if (typeName[tokenIndex] == '`') {
+ genericEndIndex = typeName.IndexOf ('[', tokenIndex, endIndex - tokenIndex);
+ if (genericEndIndex == -1) {
+ // Mono's compiler seems to generate non-generic types with '`'s in the name
+ // e.g. __EventHandler`1_FileCopyEventArgs_DelegateFactory_2
+ tokenIndex = typeName.IndexOfAny (new char [] { '[', ',' }, tokenIndex, endIndex - tokenIndex);
+ goto retry;
+ }
+
+ tokenIndex = genericEndIndex;
+ genericArgs = GetGenericArguments (typeName, ref tokenIndex, endIndex);
+ }
+
+ // decode array rank info
+ while (tokenIndex < endIndex && typeName[tokenIndex] == '[') {
+ int arrayEndIndex = typeName.IndexOf (']', tokenIndex, endIndex - tokenIndex);
+ if (arrayEndIndex == -1)
+ break;
+ arrayEndIndex++;
+ array += typeName.Substring (tokenIndex, arrayEndIndex - tokenIndex);
+ tokenIndex = arrayEndIndex;
+ }
+
+ string name = typeName.Substring (startIndex, typeEndIndex - startIndex);
+
+ if (genericArgs == null)
+ return GetShortTypeName (name) + array;
+
+ // Use the prettier name for nullable types
+ if (name == "System.Nullable" && genericArgs.Count == 1)
+ return genericArgs[0] + "?" + array;
+
+ // Insert the generic arguments next to each type.
+ // for example: Foo`1+Bar`1[System.Int32,System.String]
+ // is converted to: Foo<int>.Bar<string>
+ StringBuilder sb = new StringBuilder (name);
+ int i = typeEndIndex + 1;
+ int genericIndex = 0;
+ int argCount, next;
+
+ while (i < genericEndIndex) {
+ // decode the argument count
+ argCount = 0;
+ while (i < genericEndIndex && char.IsDigit (typeName[i])) {
+ argCount = (argCount * 10) + (typeName[i] - '0');
+ i++;
+ }
+
+ // insert the argument types
+ sb.Append ('<');
+ while (argCount > 0 && genericIndex < genericArgs.Count) {
+ sb.Append (genericArgs[genericIndex++]);
+ if (--argCount > 0)
+ sb.Append (',');
+ }
+ sb.Append ('>');
+
+ // Find the end of the next generic type component
+ if ((next = typeName.IndexOf ('`', i, genericEndIndex - i)) == -1)
+ next = genericEndIndex;
+
+ // Append the next generic type component
+ sb.Append (typeName.Substring (i, next - i));
+
+ i = next + 1;
+ }
+
+ return sb.ToString () + array;
+ }
+
+ List<string> GetGenericArguments (string typeName, ref int i, int endIndex)
+ {
+ // Get a list of the generic arguments.
+ // When returning, i points to the next char after the closing ']'
+ List<string> genericArgs = new List<string> ();
+ i++;
+ while (i < endIndex && typeName [i] != ']') {
+ int pend = FindTypeEnd (typeName, i, endIndex);
+ bool escaped = typeName [i] == '[';
+ genericArgs.Add (GetDisplayTypeName (typeName, escaped ? i + 1 : i, escaped ? pend - 1 : pend));
+ i = pend;
+ if (i < endIndex && typeName[i] == ',')
+ i++;
+ }
+ i++;
+ return genericArgs;
+ }
+
+ int FindTypeEnd (string s, int i, int endIndex)
+ {
+ int bc = 0;
+ while (i < endIndex) {
+ char c = s[i];
+ if (c == '[')
+ bc++;
+ else if (c == ']') {
+ if (bc > 0)
+ bc--;
+ else
+ return i;
+ }
+ else if (c == ',' && bc == 0)
+ return i;
+ i++;
+ }
+ return i;
+ }
+
+ public virtual string GetShortTypeName (string typeName)
+ {
+ int star = typeName.IndexOf ('*');
+ string name, ptr, csharp;
+
+ if (star != -1) {
+ name = typeName.Substring (0, star);
+ ptr = typeName.Substring (star);
+ } else {
+ ptr = string.Empty;
+ name = typeName;
+ }
+
+ if (CSharpTypeNames.TryGetValue (name, out csharp))
+ return csharp + ptr;
+
+ return typeName;
+ }
+
+ public virtual void OnBusyStateChanged (BusyStateEventArgs e)
+ {
+ EventHandler<BusyStateEventArgs> evnt = BusyStateChanged;
+ if (evnt != null)
+ evnt (this, e);
+ }
+
+ public abstract ICollectionAdaptor CreateArrayAdaptor (EvaluationContext ctx, object arr);
+ public abstract IStringAdaptor CreateStringAdaptor (EvaluationContext ctx, object str);
+
+ public abstract bool IsNull (EvaluationContext ctx, object val);
+ public abstract bool IsPrimitive (EvaluationContext ctx, object val);
+ public abstract bool IsPointer (EvaluationContext ctx, object val);
+ public abstract bool IsString (EvaluationContext ctx, object val);
+ public abstract bool IsArray (EvaluationContext ctx, object val);
+ public abstract bool IsEnum (EvaluationContext ctx, object val);
+ public abstract bool IsValueType (object type);
+ public abstract bool IsClass (EvaluationContext ctx, object type);
+ public abstract object TryCast (EvaluationContext ctx, object val, object type);
+
+ public abstract object GetValueType (EvaluationContext ctx, object val);
+ public abstract string GetTypeName (EvaluationContext ctx, object type);
+ public abstract object[] GetTypeArgs (EvaluationContext ctx, object type);
+ public abstract object GetBaseType (EvaluationContext ctx, object type);
+
+ public virtual bool IsGenericType (EvaluationContext ctx, object type)
+ {
+ return type != null && GetTypeName (ctx, type).IndexOf ('`') != -1;
+ }
+
+ public virtual bool IsNullableType (EvaluationContext ctx, object type)
+ {
+ return type != null && GetTypeName (ctx, type).StartsWith ("System.Nullable`1", StringComparison.Ordinal);
+ }
+
+ public virtual bool NullableHasValue (EvaluationContext ctx, object type, object obj)
+ {
+ ValueReference hasValue = GetMember (ctx, type, obj, "HasValue");
+
+ return (bool) hasValue.ObjectValue;
+ }
+
+ public virtual ValueReference NullableGetValue (EvaluationContext ctx, object type, object obj)
+ {
+ return GetMember (ctx, type, obj, "Value");
+ }
+
+ public virtual bool IsFlagsEnumType (EvaluationContext ctx, object type)
+ {
+ return true;
+ }
+
+ public virtual IEnumerable<EnumMember> GetEnumMembers (EvaluationContext ctx, object type)
+ {
+ object longType = GetType (ctx, "System.Int64");
+ TypeValueReference tref = new TypeValueReference (ctx, type);
+ foreach (ValueReference cr in tref.GetChildReferences (ctx.Options)) {
+ object c = TryCast (ctx, cr.Value, longType);
+ if (c == null)
+ continue;
+ long val = (long) TargetObjectToObject (ctx, c);
+ EnumMember em = new EnumMember () { Name = cr.Name, Value = val };
+ yield return em;
+ }
+ }
+
+ public object GetBaseType (EvaluationContext ctx, object type, bool includeObjectClass)
+ {
+ object bt = GetBaseType (ctx, type);
+ string tn = bt != null ? GetTypeName (ctx, bt) : null;
+ if (!includeObjectClass && bt != null && (tn == "System.Object" || tn == "System.ValueType"))
+ return null;
+ else
+ return bt;
+ }
+
+ public virtual bool IsClassInstance (EvaluationContext ctx, object val)
+ {
+ return IsClass (ctx, GetValueType (ctx, val));
+ }
+
+ public virtual bool IsExternalType (EvaluationContext ctx, object type)
+ {
+ return false;
+ }
+
+ public object GetType (EvaluationContext ctx, string name)
+ {
+ return GetType (ctx, name, null);
+ }
+
+ public abstract object GetType (EvaluationContext ctx, string name, object[] typeArgs);
+
+ public virtual string GetValueTypeName (EvaluationContext ctx, object val)
+ {
+ return GetTypeName (ctx, GetValueType (ctx, val));
+ }
+
+ public virtual object CreateTypeObject (EvaluationContext ctx, object type)
+ {
+ return default (object);
+ }
+
+ public virtual bool IsTypeLoaded (EvaluationContext ctx, string typeName)
+ {
+ object t = GetType (ctx, typeName);
+
+ if (t == null)
+ return false;
+
+ return IsTypeLoaded (ctx, t);
+ }
+
+ public virtual bool IsTypeLoaded (EvaluationContext ctx, object type)
+ {
+ return true;
+ }
+
+ public virtual object ForceLoadType (EvaluationContext ctx, string typeName)
+ {
+ object t = GetType (ctx, typeName);
+
+ if (t == null || IsTypeLoaded (ctx, t))
+ return t;
+
+ if (ForceLoadType (ctx, t))
+ return t;
+
+ return null;
+ }
+
+ public virtual bool ForceLoadType (EvaluationContext ctx, object type)
+ {
+ return true;
+ }
+
+ public abstract object CreateValue (EvaluationContext ctx, object value);
+
+ public abstract object CreateValue (EvaluationContext ctx, object type, params object[] args);
+
+ public abstract object CreateNullValue (EvaluationContext ctx, object type);
+
+ public virtual object GetBaseValue (EvaluationContext ctx, object val)
+ {
+ return val;
+ }
+
+ public virtual string[] GetImportedNamespaces (EvaluationContext ctx)
+ {
+ return new string[0];
+ }
+
+ public virtual void GetNamespaceContents (EvaluationContext ctx, string namspace, out string[] childNamespaces, out string[] childTypes)
+ {
+ childTypes = childNamespaces = new string[0];
+ }
+
+ protected virtual ObjectValue CreateObjectValueImpl (EvaluationContext ctx, Mono.Debugging.Backend.IObjectValueSource source, ObjectPath path, object obj, ObjectValueFlags flags)
+ {
+ object type = obj != null ? GetValueType (ctx, obj) : null;
+ string typeName = type != null ? GetTypeName (ctx, type) : "";
+
+ if (obj == null || IsNull (ctx, obj)) {
+ return ObjectValue.CreateNullObject (source, path, GetDisplayTypeName (typeName), flags);
+ }
+ else if (IsPrimitive (ctx, obj) || IsEnum (ctx,obj)) {
+ return ObjectValue.CreatePrimitive (source, path, GetDisplayTypeName (typeName), ctx.Evaluator.TargetObjectToExpression (ctx, obj), flags);
+ }
+ else if (IsArray (ctx, obj)) {
+ return ObjectValue.CreateObject (source, path, GetDisplayTypeName (typeName), ctx.Evaluator.TargetObjectToExpression (ctx, obj), flags, null);
+ }
+ else {
+ EvaluationResult tvalue = null;
+ TypeDisplayData tdata = null;
+ string tname;
+
+ if (IsNullableType (ctx, type)) {
+ if (NullableHasValue (ctx, type, obj)) {
+ ValueReference value = NullableGetValue (ctx, type, obj);
+
+ tdata = GetTypeDisplayData (ctx, value.Type);
+ obj = value.Value;
+ } else {
+ tdata = GetTypeDisplayData (ctx, type);
+ tvalue = new EvaluationResult ("null");
+ }
+
+ tname = GetDisplayTypeName (typeName);
+ } else {
+ tdata = GetTypeDisplayData (ctx, type);
+
+ if (!string.IsNullOrEmpty (tdata.TypeDisplayString) && ctx.Options.AllowDisplayStringEvaluation)
+ tname = EvaluateDisplayString (ctx, obj, tdata.TypeDisplayString);
+ else
+ tname = GetDisplayTypeName (typeName);
+ }
+
+ if (tvalue == null) {
+ if (!string.IsNullOrEmpty (tdata.ValueDisplayString) && ctx.Options.AllowDisplayStringEvaluation)
+ tvalue = new EvaluationResult (EvaluateDisplayString (ctx, obj, tdata.ValueDisplayString));
+ else
+ tvalue = ctx.Evaluator.TargetObjectToExpression (ctx, obj);
+ }
+
+ ObjectValue oval = ObjectValue.CreateObject (source, path, tname, tvalue, flags, null);
+ if (!string.IsNullOrEmpty (tdata.NameDisplayString) && ctx.Options.AllowDisplayStringEvaluation)
+ oval.Name = EvaluateDisplayString (ctx, obj, tdata.NameDisplayString);
+ return oval;
+ }
+ }
+
+ public ObjectValue[] GetObjectValueChildren (EvaluationContext ctx, IObjectSource objectSource, object obj, int firstItemIndex, int count)
+ {
+ return GetObjectValueChildren (ctx, objectSource, GetValueType (ctx, obj), obj, firstItemIndex, count, true);
+ }
+
+ public virtual ObjectValue[] GetObjectValueChildren (EvaluationContext ctx, IObjectSource objectSource, object type, object obj, int firstItemIndex, int count, bool dereferenceProxy)
+ {
+ if (obj is EvaluationResult)
+ return new ObjectValue[0];
+
+ if (IsArray (ctx, obj)) {
+ ArrayElementGroup agroup = new ArrayElementGroup (ctx, CreateArrayAdaptor (ctx, obj));
+ return agroup.GetChildren (ctx.Options);
+ }
+
+ if (IsPrimitive (ctx, obj))
+ return new ObjectValue[0];
+
+ if (IsNullableType (ctx, type)) {
+ if (NullableHasValue (ctx, type, obj)) {
+ ValueReference value = NullableGetValue (ctx, type, obj);
+
+ return GetObjectValueChildren (ctx, objectSource, value.Type, value.Value, firstItemIndex, count, dereferenceProxy);
+ } else {
+ return new ObjectValue[0];
+ }
+ }
+
+ bool showRawView = false;
+
+ // If there is a proxy, it has to show the members of the proxy
+ object proxy = obj;
+ if (dereferenceProxy) {
+ proxy = GetProxyObject (ctx, obj);
+ if (proxy != obj) {
+ type = GetValueType (ctx, proxy);
+ showRawView = true;
+ }
+ }
+
+ TypeDisplayData tdata = GetTypeDisplayData (ctx, type);
+ bool groupPrivateMembers = ctx.Options.GroupPrivateMembers || IsExternalType (ctx, type);
+
+ List<ObjectValue> values = new List<ObjectValue> ();
+ BindingFlags flattenFlag = ctx.Options.FlattenHierarchy ? (BindingFlags)0 : BindingFlags.DeclaredOnly;
+ BindingFlags nonPublicFlag = !(groupPrivateMembers || showRawView) ? BindingFlags.NonPublic : (BindingFlags) 0;
+ BindingFlags staticFlag = ctx.Options.GroupStaticMembers ? (BindingFlags)0 : BindingFlags.Static;
+ BindingFlags access = BindingFlags.Public | BindingFlags.Instance | flattenFlag | nonPublicFlag | staticFlag;
+
+ // Load all members to a list before creating the object values,
+ // to avoid problems with objects being invalidated due to evaluations in the target,
+ List<ValueReference> list = new List<ValueReference> ();
+ list.AddRange (GetMembersSorted (ctx, objectSource, type, proxy, access));
+ var names = new ObjectValueNameTracker (ctx);
+ object tdataType = type;
+
+ foreach (ValueReference val in list) {
+ try {
+ object decType = val.DeclaringType;
+ if (decType != null && decType != tdataType) {
+ tdataType = decType;
+ tdata = GetTypeDisplayData (ctx, decType);
+ }
+ DebuggerBrowsableState state = tdata.GetMemberBrowsableState (val.Name);
+ if (state == DebuggerBrowsableState.Never)
+ continue;
+
+ if (state == DebuggerBrowsableState.RootHidden && dereferenceProxy) {
+ object ob = val.Value;
+ if (ob != null) {
+ values.Clear ();
+ values.AddRange (GetObjectValueChildren (ctx, val, ob, -1, -1));
+ showRawView = true;
+ break;
+ }
+ }
+ else {
+ ObjectValue oval = val.CreateObjectValue (true);
+ names.Disambiguate (val, oval);
+ values.Add (oval);
+ }
+
+ }
+ catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ values.Add (ObjectValue.CreateError (null, new ObjectPath (val.Name), GetDisplayTypeName (GetTypeName (ctx, val.Type)), ex.Message, val.Flags));
+ }
+ }
+
+ if (showRawView) {
+ values.Add (RawViewSource.CreateRawView (ctx, objectSource, obj));
+ }
+ else {
+ if (IsArray (ctx, proxy)) {
+ ICollectionAdaptor col = CreateArrayAdaptor (ctx, proxy);
+ ArrayElementGroup agroup = new ArrayElementGroup (ctx, col);
+ ObjectValue val = ObjectValue.CreateObject (null, new ObjectPath ("Raw View"), "", "", ObjectValueFlags.ReadOnly, values.ToArray ());
+ values = new List<ObjectValue> ();
+ values.Add (val);
+ values.AddRange (agroup.GetChildren (ctx.Options));
+ }
+ else {
+ if (ctx.Options.GroupStaticMembers && HasMembers (ctx, type, proxy, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | flattenFlag)) {
+ access = BindingFlags.Static | BindingFlags.Public | flattenFlag | nonPublicFlag;
+ values.Add (FilteredMembersSource.CreateStaticsNode (ctx, objectSource, type, proxy, access));
+ }
+ if (groupPrivateMembers && HasMembers (ctx, type, proxy, BindingFlags.Instance | BindingFlags.NonPublic | flattenFlag | staticFlag))
+ values.Add (FilteredMembersSource.CreateNonPublicsNode (ctx, objectSource, type, proxy, BindingFlags.Instance | BindingFlags.NonPublic | flattenFlag | staticFlag));
+
+ if (!ctx.Options.FlattenHierarchy) {
+ object baseType = GetBaseType (ctx, type, false);
+ if (baseType != null)
+ values.Insert (0, BaseTypeViewSource.CreateBaseTypeView (ctx, objectSource, baseType, proxy));
+ }
+ }
+ }
+ return values.ToArray ();
+ }
+
+ public ObjectValue[] GetExpressionValuesAsync (EvaluationContext ctx, string[] expressions)
+ {
+ ObjectValue[] values = new ObjectValue[expressions.Length];
+ for (int n = 0; n < values.Length; n++) {
+ string exp = expressions[n];
+ // This is a workaround to a bug in mono 2.0. That mono version fails to compile
+ // an anonymous method here
+ ExpData edata = new ExpData (ctx, exp, this);
+ values[n] = asyncEvaluationTracker.Run (exp, ObjectValueFlags.Literal, edata.Run);
+ }
+ return values;
+ }
+
+ class ExpData
+ {
+ readonly ObjectValueAdaptor adaptor;
+ readonly EvaluationContext ctx;
+ readonly string exp;
+
+ public ExpData (EvaluationContext ctx, string exp, ObjectValueAdaptor adaptor)
+ {
+ this.ctx = ctx;
+ this.exp = exp;
+ this.adaptor = adaptor;
+ }
+
+ public ObjectValue Run ()
+ {
+ return adaptor.GetExpressionValue (ctx, exp);
+ }
+ }
+
+ public virtual ValueReference GetIndexerReference (EvaluationContext ctx, object target, object[] indices)
+ {
+ return null;
+ }
+
+ public ValueReference GetLocalVariable (EvaluationContext ctx, string name)
+ {
+ return OnGetLocalVariable (ctx, name);
+ }
+
+ protected virtual ValueReference OnGetLocalVariable (EvaluationContext ctx, string name)
+ {
+ ValueReference best = null;
+ foreach (ValueReference var in GetLocalVariables (ctx)) {
+ if (var.Name == name)
+ return var;
+ if (!ctx.Evaluator.CaseSensitive && var.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase))
+ best = var;
+ }
+ return best;
+ }
+
+ public virtual ValueReference GetParameter (EvaluationContext ctx, string name)
+ {
+ return OnGetParameter (ctx, name);
+ }
+
+ protected virtual ValueReference OnGetParameter (EvaluationContext ctx, string name)
+ {
+ ValueReference best = null;
+ foreach (ValueReference var in GetParameters (ctx)) {
+ if (var.Name == name)
+ return var;
+ if (!ctx.Evaluator.CaseSensitive && var.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase))
+ best = var;
+ }
+ return best;
+ }
+
+ public IEnumerable<ValueReference> GetLocalVariables (EvaluationContext ctx)
+ {
+ return OnGetLocalVariables (ctx);
+ }
+
+ public ValueReference GetThisReference (EvaluationContext ctx)
+ {
+ return OnGetThisReference (ctx);
+ }
+
+ public IEnumerable<ValueReference> GetParameters (EvaluationContext ctx)
+ {
+ return OnGetParameters (ctx);
+ }
+
+ protected virtual IEnumerable<ValueReference> OnGetLocalVariables (EvaluationContext ctx)
+ {
+ yield break;
+ }
+
+ protected virtual IEnumerable<ValueReference> OnGetParameters (EvaluationContext ctx)
+ {
+ yield break;
+ }
+
+ protected virtual ValueReference OnGetThisReference (EvaluationContext ctx)
+ {
+ return null;
+ }
+
+ public virtual ValueReference GetCurrentException (EvaluationContext ctx)
+ {
+ return null;
+ }
+
+ public virtual object GetEnclosingType (EvaluationContext ctx)
+ {
+ return null;
+ }
+
+ protected virtual CompletionData GetMemberCompletionData (EvaluationContext ctx, ValueReference vr)
+ {
+ CompletionData data = new CompletionData ();
+
+ foreach (ValueReference cv in vr.GetChildReferences (ctx.Options))
+ data.Items.Add (new CompletionItem (cv.Name, cv.Flags));
+
+ data.ExpressionLength = 0;
+
+ return data;
+ }
+
+ public virtual CompletionData GetExpressionCompletionData (EvaluationContext ctx, string expr)
+ {
+ if (string.IsNullOrEmpty (expr))
+ return null;
+
+ if (expr[expr.Length - 1] == '.') {
+ try {
+ var vr = ctx.Evaluator.Evaluate (ctx, expr.Substring (0, expr.Length - 1), null);
+ if (vr != null)
+ return GetMemberCompletionData (ctx, vr);
+
+ // FIXME: handle types and namespaces...
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ }
+
+ return null;
+ }
+
+ bool lastWastLetter = false;
+ int i = expr.Length - 1;
+
+ while (i >= 0) {
+ char c = expr[i--];
+ if (!char.IsLetterOrDigit (c) && c != '_')
+ break;
+
+ lastWastLetter = !char.IsDigit (c);
+ }
+
+ if (lastWastLetter) {
+ string partialWord = expr.Substring (i+1);
+
+ CompletionData data = new CompletionData ();
+ data.ExpressionLength = partialWord.Length;
+
+ // Local variables
+
+ foreach (ValueReference vc in GetLocalVariables (ctx))
+ if (vc.Name.StartsWith (partialWord, StringComparison.InvariantCulture))
+ data.Items.Add (new CompletionItem (vc.Name, vc.Flags));
+
+ // Parameters
+
+ foreach (ValueReference vc in GetParameters (ctx))
+ if (vc.Name.StartsWith (partialWord, StringComparison.InvariantCulture))
+ data.Items.Add (new CompletionItem (vc.Name, vc.Flags));
+
+ // Members
+
+ ValueReference thisobj = GetThisReference (ctx);
+
+ if (thisobj != null)
+ data.Items.Add (new CompletionItem ("this", ObjectValueFlags.Field | ObjectValueFlags.ReadOnly));
+
+ object type = GetEnclosingType (ctx);
+
+ foreach (ValueReference vc in GetMembers (ctx, null, type, thisobj != null ? thisobj.Value : null))
+ if (vc.Name.StartsWith (partialWord, StringComparison.InvariantCulture))
+ data.Items.Add (new CompletionItem (vc.Name, vc.Flags));
+
+ if (data.Items.Count > 0)
+ return data;
+ }
+
+ return null;
+ }
+
+ public IEnumerable<ValueReference> GetMembers (EvaluationContext ctx, IObjectSource objectSource, object t, object co)
+ {
+ foreach (ValueReference val in GetMembers (ctx, t, co, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) {
+ val.ParentSource = objectSource;
+ yield return val;
+ }
+ }
+
+ public ValueReference GetMember (EvaluationContext ctx, IObjectSource objectSource, object co, string name)
+ {
+ return GetMember (ctx, objectSource, GetValueType (ctx, co), co, name);
+ }
+
+ public ValueReference GetMember (EvaluationContext ctx, IObjectSource objectSource, object t, object co, string name)
+ {
+ ValueReference m = GetMember (ctx, t, co, name);
+ if (m != null)
+ m.ParentSource = objectSource;
+ return m;
+ }
+
+ protected virtual ValueReference GetMember (EvaluationContext ctx, object t, object co, string name)
+ {
+ ValueReference best = null;
+ foreach (ValueReference var in GetMembers (ctx, t, co, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) {
+ if (var.Name == name)
+ return var;
+ if (!ctx.Evaluator.CaseSensitive && var.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase))
+ best = var;
+ }
+ return best;
+ }
+
+ internal IEnumerable<ValueReference> GetMembersSorted (EvaluationContext ctx, IObjectSource objectSource, object t, object co)
+ {
+ return GetMembersSorted (ctx, objectSource, t, co, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ }
+
+ internal IEnumerable<ValueReference> GetMembersSorted (EvaluationContext ctx, IObjectSource objectSource, object t, object co, BindingFlags bindingFlags)
+ {
+ List<ValueReference> list = new List<ValueReference> ();
+ foreach (ValueReference vr in GetMembers (ctx, t, co, bindingFlags)) {
+ vr.ParentSource = objectSource;
+ list.Add (vr);
+ }
+ list.Sort (delegate (ValueReference v1, ValueReference v2) {
+ return v1.Name.CompareTo (v2.Name);
+ });
+ return list;
+ }
+
+ public bool HasMembers (EvaluationContext ctx, object t, object co, BindingFlags bindingFlags)
+ {
+ return GetMembers (ctx, t, co, bindingFlags).Any ();
+ }
+
+ public bool HasMember (EvaluationContext ctx, object type, string memberName)
+ {
+ return HasMember (ctx, type, memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ }
+
+ public abstract bool HasMember (EvaluationContext ctx, object type, string memberName, BindingFlags bindingFlags);
+
+ /// <summary>
+ /// Returns all members of a type. The following binding flags have to be honored:
+ /// BindingFlags.Static, BindingFlags.Instance, BindingFlags.Public, BindingFlags.NonPublic, BindingFlags.DeclareOnly
+ /// </summary>
+ protected abstract IEnumerable<ValueReference> GetMembers (EvaluationContext ctx, object t, object co, BindingFlags bindingFlags);
+
+ public virtual IEnumerable<object> GetNestedTypes (EvaluationContext ctx, object type)
+ {
+ yield break;
+ }
+
+ public virtual object GetParentType (EvaluationContext ctx, object type)
+ {
+ if ((type is Type))
+ return ((Type) type).DeclaringType;
+
+ var name = GetTypeName (ctx, type);
+ int plus = name.LastIndexOf ('+');
+
+ return plus != -1 ? GetType (ctx, name.Substring (0, plus)) : null;
+ }
+
+ public virtual object CreateArray (EvaluationContext ctx, object type, object[] values)
+ {
+ object arrType = GetType (ctx, "System.Collections.ArrayList");
+ object arrayList = CreateValue (ctx, arrType, new object[0]);
+ object[] objTypes = new object[] { GetType (ctx, "System.Object") };
+ foreach (object value in values)
+ RuntimeInvoke (ctx, arrType, arrayList, "Add", objTypes, new object[] { value });
+
+ object typof = CreateTypeObject (ctx, type);
+ objTypes = new object[] { GetType (ctx, "System.Type") };
+ return RuntimeInvoke (ctx, arrType, arrayList, "ToArray", objTypes, new object[] { typof });
+ }
+
+ public virtual object ToRawValue (EvaluationContext ctx, IObjectSource source, object obj)
+ {
+ if (IsEnum (ctx, obj)) {
+ object longType = GetType (ctx, "System.Int64");
+ object c = Cast (ctx, obj, longType);
+ return TargetObjectToObject (ctx, c);
+ }
+
+ if (ctx.Options.ChunkRawStrings && IsString (ctx, obj)) {
+ IStringAdaptor adaptor = CreateStringAdaptor (ctx, obj);
+ return new RawValueString (new RemoteRawValueString (adaptor, obj));
+ }
+
+ if (IsPrimitive (ctx, obj))
+ return TargetObjectToObject (ctx, obj);
+
+ if (IsArray (ctx, obj)) {
+ ICollectionAdaptor adaptor = CreateArrayAdaptor (ctx, obj);
+ return new RawValueArray (new RemoteRawValueArray (ctx, source, adaptor, obj));
+ }
+
+ return new RawValue (new RemoteRawValue (ctx, source, obj));
+ }
+
+ public virtual object FromRawValue (EvaluationContext ctx, object obj)
+ {
+ if (obj is RawValue) {
+ RemoteRawValue val = ((RawValue)obj).Source as RemoteRawValue;
+ if (val == null)
+ throw new InvalidOperationException ("Unknown RawValue source: " + ((RawValue)obj).Source);
+ return val.TargetObject;
+ }
+ else if (obj is RawValueArray) {
+ RemoteRawValueArray val = ((RawValueArray)obj).Source as RemoteRawValueArray;
+ if (val == null)
+ throw new InvalidOperationException ("Unknown RawValueArray source: " + ((RawValueArray)obj).Source);
+ return val.TargetObject;
+ }
+ else if (obj is RawValueString) {
+ RemoteRawValueString val = ((RawValueString)obj).Source as RemoteRawValueString;
+ if (val == null)
+ throw new InvalidOperationException ("Unknown RawValueString source: " + ((RawValueString)obj).Source);
+ return val.TargetObject;
+ }
+ else {
+ if (obj is Array) {
+ Array arr = (Array) obj;
+ if (obj.GetType ().GetElementType () == typeof(RawValue)) {
+ throw new NotSupportedException ();
+ } else {
+ object elemType = GetType (ctx, obj.GetType ().GetElementType ().FullName);
+ if (elemType == null)
+ throw new EvaluatorException ("Unknown target type: {0}", obj.GetType ().GetElementType ().FullName);
+ object[] values = new object [arr.Length];
+ for (int n=0; n<values.Length; n++)
+ values [n] = FromRawValue (ctx, arr.GetValue (n));
+ return CreateArray (ctx, elemType, values);
+ }
+ }
+ return CreateValue (ctx, obj);
+ }
+ }
+
+ public virtual object TargetObjectToObject (EvaluationContext ctx, object obj)
+ {
+ if (IsNull (ctx, obj))
+ return null;
+
+ if (IsArray (ctx, obj)) {
+ ICollectionAdaptor adaptor = CreateArrayAdaptor (ctx, obj);
+ string ename = GetDisplayTypeName (GetTypeName (ctx, adaptor.ElementType));
+ int[] dims = adaptor.GetDimensions ();
+ StringBuilder tn = new StringBuilder ("[");
+ for (int n=0; n<dims.Length; n++) {
+ if (n>0)
+ tn.Append (',');
+ tn.Append (dims[n]);
+ }
+ tn.Append ("]");
+ int i = ename.LastIndexOf ('>');
+ if (i == -1) i = 0;
+ i = ename.IndexOf ('[', i);
+ if (i != -1)
+ return new EvaluationResult ("{" + ename.Substring (0, i) + tn + ename.Substring (i) + "}");
+
+ return new EvaluationResult ("{" + ename + tn + "}");
+ }
+
+ if (IsEnum (ctx, obj)) {
+ object type = GetValueType (ctx, obj);
+ object longType = GetType (ctx, "System.Int64");
+ object c = Cast (ctx, obj, longType);
+ long val = (long) TargetObjectToObject (ctx, c);
+ long rest = val;
+ string typeName = GetTypeName (ctx, type);
+ string composed = string.Empty;
+ string composedDisplay = string.Empty;
+ foreach (EnumMember em in GetEnumMembers (ctx, type)) {
+ if (em.Value == val)
+ return new EvaluationResult (typeName + "." + em.Name, em.Name);
+ else {
+ if (em.Value != 0 && (rest & em.Value) == em.Value) {
+ rest &= ~em.Value;
+ if (composed.Length > 0) {
+ composed += "|";
+ composedDisplay += "|";
+ }
+ composed += typeName + "." + em.Name;
+ composedDisplay += em.Name;
+ }
+ }
+ }
+
+ if (IsFlagsEnumType (ctx, type) && rest == 0 && composed.Length > 0)
+ return new EvaluationResult (composed, composedDisplay);
+
+ return new EvaluationResult (val.ToString ());
+ }
+
+ if (GetValueTypeName (ctx, obj) == "System.Decimal") {
+ string res = CallToString (ctx, obj);
+ // This returns the decimal formatted using the current culture. It has to be converted to invariant culture.
+ decimal dec = decimal.Parse (res);
+ res = dec.ToString (System.Globalization.CultureInfo.InvariantCulture);
+ return new EvaluationResult (res);
+ }
+
+ if (IsClassInstance (ctx, obj)) {
+ TypeDisplayData tdata = GetTypeDisplayData (ctx, GetValueType (ctx, obj));
+ if (!string.IsNullOrEmpty (tdata.ValueDisplayString) && ctx.Options.AllowDisplayStringEvaluation)
+ return new EvaluationResult (EvaluateDisplayString (ctx, obj, tdata.ValueDisplayString));
+
+ // Return the type name
+ if (ctx.Options.AllowToStringCalls) {
+ try {
+ return new EvaluationResult ("{" + CallToString (ctx, obj) + "}");
+ } catch (TimeOutException) {
+ // ToString() timed out, fall back to default behavior.
+ }
+ }
+
+ if (!string.IsNullOrEmpty (tdata.TypeDisplayString) && ctx.Options.AllowDisplayStringEvaluation)
+ return new EvaluationResult ("{" + EvaluateDisplayString (ctx, obj, tdata.TypeDisplayString) + "}");
+
+ return new EvaluationResult ("{" + GetDisplayTypeName (GetValueTypeName (ctx, obj)) + "}");
+ }
+
+ return new EvaluationResult ("{" + CallToString (ctx, obj) + "}");
+ }
+
+ public object Convert (EvaluationContext ctx, object obj, object targetType)
+ {
+ if (obj == null)
+ return null;
+
+ object res = TryConvert (ctx, obj, targetType);
+ if (res != null)
+ return res;
+
+ throw new EvaluatorException ("Can't convert an object of type '{0}' to type '{1}'", GetValueTypeName (ctx, obj), GetTypeName (ctx, targetType));
+ }
+
+ public virtual object TryConvert (EvaluationContext ctx, object obj, object targetType)
+ {
+ return TryCast (ctx, obj, targetType);
+ }
+
+ public virtual object Cast (EvaluationContext ctx, object obj, object targetType)
+ {
+ if (obj == null)
+ return null;
+
+ object res = TryCast (ctx, obj, targetType);
+ if (res != null)
+ return res;
+
+ throw new EvaluatorException ("Can't cast an object of type '{0}' to type '{1}'", GetValueTypeName (ctx, obj), GetTypeName (ctx, targetType));
+ }
+
+ public virtual string CallToString (EvaluationContext ctx, object obj)
+ {
+ return GetValueTypeName (ctx, obj);
+ }
+
+ public object GetProxyObject (EvaluationContext ctx, object obj)
+ {
+ TypeDisplayData data = GetTypeDisplayData (ctx, GetValueType (ctx, obj));
+ if (string.IsNullOrEmpty (data.ProxyType) || !ctx.Options.AllowDebuggerProxy)
+ return obj;
+
+ string proxyType = data.ProxyType;
+ object[] typeArgs = null;
+
+ int index = proxyType.IndexOf ('`');
+ if (index != -1) {
+ // The proxy type is an uninstantiated generic type.
+ // The number of type args of the proxy must match the args of the target object
+ int startIndex = index + 1;
+ int endIndex = index + 1;
+
+ while (endIndex < proxyType.Length && char.IsDigit (proxyType[endIndex]))
+ endIndex++;
+
+ int num = int.Parse (proxyType.Substring (startIndex, endIndex - startIndex));
+ typeArgs = GetTypeArgs (ctx, GetValueType (ctx, obj));
+ if (typeArgs.Length != num)
+ return obj;
+
+ if (endIndex < proxyType.Length) {
+ // chop off the []'d list of generic type arguments
+ proxyType = proxyType.Substring (0, endIndex);
+ }
+ }
+
+ object ttype = GetType (ctx, proxyType, typeArgs);
+ if (ttype == null) {
+ // the proxy type string might be in the form: "Namespace.TypeName, Assembly...", chop off the ", Assembly..." bit.
+ if ((index = proxyType.IndexOf (',')) != -1)
+ ttype = GetType (ctx, proxyType.Substring (0, index).Trim (), typeArgs);
+ }
+ if (ttype == null)
+ throw new EvaluatorException ("Unknown type '{0}'", data.ProxyType);
+
+ try {
+ object val = CreateValue (ctx, ttype, obj);
+ return val ?? obj;
+ } catch (EvaluatorException) {
+ // probably couldn't find the .ctor for the proxy type because the linker stripped it out
+ return obj;
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ return obj;
+ }
+ }
+
+ public TypeDisplayData GetTypeDisplayData (EvaluationContext ctx, object type)
+ {
+ if (!IsClass (ctx, type))
+ return TypeDisplayData.Default;
+
+ TypeDisplayData td;
+ string tname = GetTypeName (ctx, type);
+ if (typeDisplayData.TryGetValue (tname, out td))
+ return td;
+
+ try {
+ td = OnGetTypeDisplayData (ctx, type);
+ }
+ catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ }
+ if (td == null)
+ typeDisplayData[tname] = td = TypeDisplayData.Default;
+ else
+ typeDisplayData[tname] = td;
+ return td;
+ }
+
+ protected virtual TypeDisplayData OnGetTypeDisplayData (EvaluationContext ctx, object type)
+ {
+ return null;
+ }
+
+ static bool IsQuoted (string str)
+ {
+ return str.Length >= 2 && str[0] == '"' && str[str.Length - 1] == '"';
+ }
+
+ public string EvaluateDisplayString (EvaluationContext ctx, object obj, string expr)
+ {
+ StringBuilder sb = new StringBuilder ();
+ int i = expr.IndexOf ('{');
+ int last = 0;
+
+ while (i != -1 && i < expr.Length) {
+ sb.Append (expr.Substring (last, i - last));
+ i++;
+
+ int j = expr.IndexOf ('}', i);
+ if (j == -1)
+ return expr;
+
+ string memberExpr = expr.Substring (i, j - i).Trim ();
+ if (memberExpr.Length == 0)
+ return expr;
+
+ int comma = memberExpr.LastIndexOf (',');
+ bool noquotes = false;
+ if (comma != -1) {
+ var option = memberExpr.Substring (comma + 1).Trim ();
+ memberExpr = memberExpr.Substring (0, comma).Trim ();
+ if (option == "nq")
+ noquotes = true;
+ }
+
+ string[] props = memberExpr.Split (new char[] { '.' });
+ ValueReference member = null;
+ object val = obj;
+
+ for (int k = 0; k < props.Length; k++) {
+ member = GetMember (ctx, null, GetValueType (ctx, val), val, props[k]);
+ if (member == null)
+ break;
+
+ val = member.Value;
+ }
+
+ if (member != null) {
+ var str = ctx.Evaluator.TargetObjectToString (ctx, val);
+ if (str == null)
+ sb.Append ("null");
+ else if (noquotes && IsQuoted (str))
+ sb.Append (str.Substring (1, str.Length - 2));
+ else
+ sb.Append (str);
+ } else {
+ sb.Append ("{Unknown member '" + memberExpr + "'}");
+ }
+
+ last = j + 1;
+ i = expr.IndexOf ('{', last);
+ }
+
+ sb.Append (expr.Substring (last));
+
+ return sb.ToString ();
+ }
+
+ public void AsyncExecute (AsyncOperation operation, int timeout)
+ {
+ asyncOperationManager.Invoke (operation, timeout);
+ }
+
+ public ObjectValue CreateObjectValueAsync (string name, ObjectValueFlags flags, ObjectEvaluatorDelegate evaluator)
+ {
+ return asyncEvaluationTracker.Run (name, flags, evaluator);
+ }
+
+ public bool IsEvaluating {
+ get { return asyncEvaluationTracker.IsEvaluating; }
+ }
+
+ public void CancelAsyncOperations ( )
+ {
+ asyncEvaluationTracker.Stop ();
+ asyncOperationManager.AbortAll ();
+ asyncEvaluationTracker.WaitForStopped ();
+ }
+
+ public ObjectValue GetExpressionValue (EvaluationContext ctx, string exp)
+ {
+ try {
+ ValueReference var = ctx.Evaluator.Evaluate (ctx, exp);
+ if (var != null)
+ return var.CreateObjectValue (ctx.Options);
+
+ return ObjectValue.CreateUnknown (exp);
+ } catch (ImplicitEvaluationDisabledException) {
+ return ObjectValue.CreateImplicitNotSupported (ctx.ExpressionValueSource, new ObjectPath (exp), "", ObjectValueFlags.None);
+ } catch (NotSupportedExpressionException ex) {
+ return ObjectValue.CreateNotSupported (ctx.ExpressionValueSource, new ObjectPath (exp), ex.Message, "", ObjectValueFlags.None);
+ } catch (EvaluatorException ex) {
+ return ObjectValue.CreateError (ctx.ExpressionValueSource, new ObjectPath (exp), "", ex.Message, ObjectValueFlags.None);
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ return ObjectValue.CreateUnknown (exp);
+ }
+ }
+
+ public bool HasMethod (EvaluationContext ctx, object targetType, string methodName)
+ {
+ BindingFlags flags = BindingFlags.Instance | BindingFlags.Static;
+ if (!ctx.Evaluator.CaseSensitive)
+ flags |= BindingFlags.IgnoreCase;
+ return HasMethod (ctx, targetType, methodName, null, null, flags);
+ }
+
+ public bool HasMethod (EvaluationContext ctx, object targetType, string methodName, BindingFlags flags)
+ {
+ return HasMethod (ctx, targetType, methodName, null, null, flags);
+ }
+
+ // argTypes can be null, meaning that it has to return true if there is any method with that name
+ // flags will only contain Static or Instance flags
+ // FIXME: this should become non-virtual
+ public virtual bool HasMethod (EvaluationContext ctx, object targetType, string methodName, object[] argTypes, BindingFlags flags)
+ {
+ return HasMethod (ctx, targetType, methodName, null, argTypes, flags);
+ }
+
+ // argTypes can be null, meaning that it has to return true if there is any method with that name
+ // flags will only contain Static or Instance flags
+ public virtual bool HasMethod (EvaluationContext ctx, object targetType, string methodName, object[] genericTypeArgs, object[] argTypes, BindingFlags flags)
+ {
+ return false;
+ }
+
+ // FIXME: this should become non-virtual and simply call the newer method
+ public virtual object RuntimeInvoke (EvaluationContext ctx, object targetType, object target, string methodName, object[] argTypes, object[] argValues)
+ {
+ return null;
+ }
+
+ public virtual object RuntimeInvoke (EvaluationContext ctx, object targetType, object target, string methodName, object[] genericTypeArgs, object[] argTypes, object[] argValues)
+ {
+ // Note: this is for backward compatibility with debugger backends that haven't yet implemented this particular overload
+ return RuntimeInvoke (ctx, targetType, target, methodName, argTypes, argValues);
+ }
+
+ public virtual ValidationResult ValidateExpression (EvaluationContext ctx, string expression)
+ {
+ return ctx.Evaluator.ValidateExpression (ctx, expression);
+ }
+ }
+
+ public class TypeDisplayData
+ {
+ public string ProxyType { get; internal set; }
+ public string ValueDisplayString { get; internal set; }
+ public string TypeDisplayString { get; internal set; }
+ public string NameDisplayString { get; internal set; }
+ public bool IsCompilerGenerated { get; internal set; }
+
+ public bool IsProxyType {
+ get { return ProxyType != null; }
+ }
+
+ public static readonly TypeDisplayData Default = new TypeDisplayData (null, null, null, null, false, null);
+
+ public Dictionary<string, DebuggerBrowsableState> MemberData { get; internal set; }
+
+ public TypeDisplayData (string proxyType, string valueDisplayString, string typeDisplayString,
+ string nameDisplayString, bool isCompilerGenerated, Dictionary<string, DebuggerBrowsableState> memberData)
+ {
+ ProxyType = proxyType;
+ ValueDisplayString = valueDisplayString;
+ TypeDisplayString = typeDisplayString;
+ NameDisplayString = nameDisplayString;
+ IsCompilerGenerated = isCompilerGenerated;
+ MemberData = memberData;
+ }
+
+ public DebuggerBrowsableState GetMemberBrowsableState (string name)
+ {
+ if (MemberData == null)
+ return DebuggerBrowsableState.Collapsed;
+
+ DebuggerBrowsableState state;
+ if (MemberData.TryGetValue (name, out state))
+ return state;
+
+ return DebuggerBrowsableState.Collapsed;
+ }
+ }
+
+ class ObjectValueNameTracker
+ {
+ Dictionary<string,KeyValuePair<ObjectValue, ValueReference>> names = new Dictionary<string,KeyValuePair<ObjectValue, ValueReference>> ();
+ EvaluationContext ctx;
+
+ public ObjectValueNameTracker (EvaluationContext ctx)
+ {
+ this.ctx = ctx;
+ }
+
+ /// <summary>
+ /// Disambiguate the ObjectValue's name (in the case where the property name also exists in a base class).
+ /// </summary>
+ /// <param name='val'>
+ /// The ValueReference.
+ /// </param>
+ /// <param name='oval'>
+ /// The ObjectValue.
+ /// </param>
+ public void Disambiguate (ValueReference val, ObjectValue oval)
+ {
+ KeyValuePair<ObjectValue, ValueReference> other;
+ if (names.TryGetValue (oval.Name, out other)) {
+ object tn = val.DeclaringType;
+
+ if (tn != null)
+ oval.Name += " (" + ctx.Adapter.GetDisplayTypeName (ctx, tn) + ")";
+ if (!other.Key.Name.EndsWith (")", StringComparison.Ordinal)) {
+ tn = other.Value.DeclaringType;
+ if (tn != null)
+ other.Key.Name += " (" + ctx.Adapter.GetDisplayTypeName (ctx, tn) + ")";
+ }
+ }
+
+ names [oval.Name] = new KeyValuePair<ObjectValue, ValueReference> (oval, val);
+ }
+ }
+
+ public struct EnumMember
+ {
+ public string Name { get; set; }
+ public long Value { get; set; }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/RawViewSource.cs b/Mono.Debugging/Mono.Debugging.Evaluation/RawViewSource.cs
new file mode 100644
index 0000000..5c063c9
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/RawViewSource.cs
@@ -0,0 +1,83 @@
+// RawViewSource.cs
+//
+// Authors: Lluis Sanchez Gual <lluis at novell.com>
+// Jeffrey Stedfast <jeff at 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 Mono.Debugging.Backend;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class RawViewSource: RemoteFrameObject, IObjectValueSource
+ {
+ object obj;
+ EvaluationContext ctx;
+ IObjectSource objectSource;
+
+ public RawViewSource (EvaluationContext ctx, IObjectSource objectSource, object obj)
+ {
+ this.ctx = ctx;
+ this.obj = obj;
+ this.objectSource = objectSource;
+ }
+
+ public static ObjectValue CreateRawView (EvaluationContext ctx, IObjectSource objectSource, object obj)
+ {
+ RawViewSource src = new RawViewSource (ctx, objectSource, obj);
+ src.Connect ();
+ ObjectValue val = ObjectValue.CreateObject (src, new ObjectPath ("Raw View"), "", "", ObjectValueFlags.Group|ObjectValueFlags.ReadOnly|ObjectValueFlags.NoRefresh, null);
+ val.ChildSelector = "";
+ return val;
+ }
+
+ public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ EvaluationContext cctx = ctx.WithOptions (options);
+ return cctx.Adapter.GetObjectValueChildren (cctx, objectSource, cctx.Adapter.GetValueType (cctx, obj), obj, index, count, false);
+ }
+
+ public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public object GetRawValue (ObjectPath path, EvaluationOptions options)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/RemoteFrameObject.cs b/Mono.Debugging/Mono.Debugging.Evaluation/RemoteFrameObject.cs
new file mode 100644
index 0000000..e4411eb
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/RemoteFrameObject.cs
@@ -0,0 +1,76 @@
+// RemoteFrameObject.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class RemoteFrameObject: MarshalByRefObject
+ {
+ static List<RemoteFrameObject> connectedValues = new List<RemoteFrameObject> ();
+
+ public static bool TrackConnections { get; set; }
+
+ bool connected;
+
+ public void Connect ()
+ {
+ if (!TrackConnections)
+ return;
+
+ // Registers the value reference. Once a remote reference of this object
+ // is created, it will never be released, until DisconnectAll is called,
+ // which is done every time the current backtrace changes
+
+ lock (connectedValues) {
+ if (!connected) {
+ connectedValues.Add (this);
+ connected = true;
+ }
+ }
+ }
+
+ public static void DisconnectAll ()
+ {
+ lock (connectedValues) {
+ foreach (RemoteFrameObject val in connectedValues) {
+ System.Runtime.Remoting.RemotingServices.Disconnect (val);
+ IDisposable disp = val as IDisposable;
+ if (disp != null)
+ disp.Dispose ();
+ }
+ connectedValues.Clear ();
+ }
+ }
+
+ public override object InitializeLifetimeService ()
+ {
+ return null;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/RemoteRawValue.cs b/Mono.Debugging/Mono.Debugging.Evaluation/RemoteRawValue.cs
new file mode 100644
index 0000000..73c6c67
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/RemoteRawValue.cs
@@ -0,0 +1,214 @@
+//
+// RemoteRawValue.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2010 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 Mono.Debugging.Backend;
+using System.Collections;
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ internal class RemoteRawValue: RemoteFrameObject, IRawValue
+ {
+ object targetObject;
+ EvaluationContext ctx;
+ IObjectSource source;
+
+ public RemoteRawValue (EvaluationContext gctx, IObjectSource source, object targetObject)
+ {
+ this.ctx = gctx.Clone ();
+ ctx.Options.AllowTargetInvoke = true;
+ ctx.Options.AllowMethodEvaluation = true;
+ this.targetObject = targetObject;
+ this.source = source;
+ Connect ();
+ }
+
+ public object TargetObject {
+ get { return this.targetObject; }
+ }
+
+ #region IRawValue implementation
+ public object CallMethod (string name, object[] parameters, EvaluationOptions options)
+ {
+ EvaluationContext localContext = ctx.WithOptions (options);
+
+ object[] argValues = new object [parameters.Length];
+ object[] argTypes = new object [parameters.Length];
+ for (int n=0; n<argValues.Length; n++) {
+ argValues[n] = localContext.Adapter.FromRawValue (localContext, parameters[n]);
+ argTypes[n] = localContext.Adapter.GetValueType (localContext, argValues[n]);
+ }
+ object type = localContext.Adapter.GetValueType (localContext, targetObject);
+ object res = localContext.Adapter.RuntimeInvoke (localContext, type, targetObject, name, argTypes, argValues);
+ return localContext.Adapter.ToRawValue (localContext, null, res);
+ }
+
+ public object GetMemberValue (string name, EvaluationOptions options)
+ {
+ EvaluationContext localContext = ctx.WithOptions (options);
+ object type = localContext.Adapter.GetValueType (localContext, targetObject);
+ ValueReference val = localContext.Adapter.GetMember (localContext, source, type, targetObject, name);
+ if (val == null)
+ throw new EvaluatorException ("Member '{0}' not found", name);
+ return localContext.Adapter.ToRawValue (localContext, val, val.Value);
+ }
+
+ public void SetMemberValue (string name, object value, EvaluationOptions options)
+ {
+ EvaluationContext localContext = ctx.WithOptions (options);
+ object type = localContext.Adapter.GetValueType (localContext, targetObject);
+ ValueReference val = localContext.Adapter.GetMember (localContext, source, type, targetObject, name);
+ if (val == null)
+ throw new EvaluatorException ("Member '{0}' not found", name);
+ val.Value = localContext.Adapter.FromRawValue (localContext, value);
+ }
+
+ #endregion
+ }
+
+ internal class RemoteRawValueArray: RemoteFrameObject, IRawValueArray
+ {
+ object targetObject;
+ EvaluationContext ctx;
+ IObjectSource source;
+ ICollectionAdaptor targetArray;
+
+ public RemoteRawValueArray (EvaluationContext ctx, IObjectSource source, ICollectionAdaptor targetArray, object targetObject)
+ {
+ this.ctx = ctx;
+ this.targetArray = targetArray;
+ this.targetObject = targetObject;
+ this.source = source;
+ Connect ();
+ }
+
+ public object TargetObject {
+ get { return this.targetObject; }
+ }
+
+ public object GetValue (int[] index)
+ {
+ return ctx.Adapter.ToRawValue (ctx, source, targetArray.GetElement (index));
+ }
+
+ public Array GetValues (int[] index, int count)
+ {
+ var values = targetArray.GetElements (index, count);
+ var idx = new int[index.Length];
+ var array = new ArrayList ();
+
+ for (int i = 0; i < index.Length; i++)
+ idx[i] = index[i];
+
+ Type commonType = null;
+ for (int i = 0; i < count; i++) {
+ var rv = ctx.Adapter.ToRawValue (ctx, new ArrayObjectSource (targetArray, idx), values.GetValue (i));
+ if (commonType == null)
+ commonType = rv.GetType ();
+ else if (commonType != rv.GetType ())
+ commonType = typeof (void);
+ array.Add (rv);
+
+ idx[idx.Length - 1]++;
+ }
+
+ if (array.Count > 0 && commonType != typeof (void))
+ return array.ToArray (commonType);
+
+ return array.ToArray ();
+ }
+
+ public void SetValue (int[] index, object value)
+ {
+ targetArray.SetElement (index, ctx.Adapter.FromRawValue (ctx, value));
+ }
+
+ public int[] Dimensions {
+ get {
+ return targetArray.GetDimensions ();
+ }
+ }
+
+ public Array ToArray ()
+ {
+ int[] dims = targetArray.GetDimensions ();
+ var array = new ArrayList ();
+
+ if (dims.Length != 1)
+ throw new NotSupportedException ();
+
+ int[] idx = new int [1];
+ Type commonType = null;
+ for (int n = 0; n < dims[0]; n++) {
+ idx[0] = n;
+
+ var rv = ctx.Adapter.ToRawValue (ctx, new ArrayObjectSource (targetArray, idx), targetArray.GetElement (idx));
+ if (commonType == null)
+ commonType = rv.GetType ();
+ else if (commonType != rv.GetType ())
+ commonType = typeof(void);
+ array.Add (rv);
+ }
+
+ if (array.Count > 0 && commonType != typeof(void))
+ return array.ToArray (commonType);
+
+ return array.ToArray ();
+ }
+ }
+
+ internal class RemoteRawValueString: RemoteFrameObject, IRawValueString
+ {
+ object targetObject;
+ IStringAdaptor targetString;
+
+ public RemoteRawValueString (IStringAdaptor targetString, object targetObject)
+ {
+ this.targetString = targetString;
+ this.targetObject = targetObject;
+ Connect ();
+ }
+
+ public object TargetObject {
+ get { return this.targetObject; }
+ }
+
+ public int Length {
+ get { return targetString.Length; }
+ }
+
+ public string Value {
+ get { return targetString.Value; }
+ }
+
+ public string Substring (int index, int length)
+ {
+ return targetString.Substring (index, length);
+ }
+ }
+}
+
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/TimeOutException.cs b/Mono.Debugging/Mono.Debugging.Evaluation/TimeOutException.cs
new file mode 100644
index 0000000..d169381
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/TimeOutException.cs
@@ -0,0 +1,38 @@
+// TimeOutException.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Evaluation
+{
+ public class TimeOutException: EvaluatorException
+ {
+ public TimeOutException (): base ("Timed out.")
+ {
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/TimedEvaluator.cs b/Mono.Debugging/Mono.Debugging.Evaluation/TimedEvaluator.cs
new file mode 100644
index 0000000..f62c004
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/TimedEvaluator.cs
@@ -0,0 +1,254 @@
+// EvaluationContext.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Threading;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class TimedEvaluator
+ {
+ int maxThreads = 1;
+
+ object runningLock = new object ();
+ Queue<Task> pendingTasks = new Queue<Task> ();
+ AutoResetEvent newTaskEvent = new AutoResetEvent (false);
+ Task currentTask;
+ int runningThreads;
+ bool mainThreadBusy;
+ bool useTimeout;
+ bool disposed;
+
+ public TimedEvaluator (): this (true)
+ {
+ }
+
+ public TimedEvaluator (bool useTimeout)
+ {
+ RunTimeout = 1000;
+ this.useTimeout = useTimeout;
+ }
+
+ public int RunTimeout { get; set; }
+
+ public bool IsEvaluating {
+ get {
+ lock (runningLock) {
+ return pendingTasks.Count > 0 || mainThreadBusy;
+ }
+ }
+ }
+
+ void OnStartEval ()
+ {
+// Console.WriteLine ("Eval Started");
+ }
+
+ void OnEndEval ()
+ {
+// lock (runningLock) {
+// Console.WriteLine ("Eval Finished ({0} pending)", pendingTasks.Count);
+// }
+ }
+
+ /// <summary>
+ /// Executes the provided evaluator. If a result is obtained before RunTimeout milliseconds,
+ /// the method ends returning True.
+ /// If it does not finish after RunTimeout milliseconds, the method ends retuning False, although
+ /// the evaluation continues in the background. In that case, when evaluation ends, the provided
+ /// delayedDoneCallback delegate is called.
+ /// </summary>
+ public bool Run (EvaluatorDelegate evaluator, EvaluatorDelegate delayedDoneCallback)
+ {
+ if (!useTimeout) {
+ SafeRun (evaluator);
+ return true;
+ }
+
+ Task task = new Task ();
+ task.Evaluator = evaluator;
+ task.FinishedCallback = delayedDoneCallback;
+
+ lock (runningLock) {
+ if (disposed)
+ return false;
+ if (mainThreadBusy || runningThreads == 0) {
+ if (runningThreads < maxThreads) {
+ runningThreads++;
+ Thread tr = new Thread (Runner);
+ tr.Name = "Debugger evaluator";
+ tr.IsBackground = true;
+ tr.Start ();
+ } else {
+ // The main thread is busy evaluating and we can't tell
+ // how much time it will take, so we can't wait for it.
+ task.TimedOut = true;
+ pendingTasks.Enqueue (task);
+ return false;
+ }
+ }
+ mainThreadBusy = true;
+ currentTask = task;
+ }
+
+ OnStartEval ();
+ newTaskEvent.Set ();
+ task.RunningEvent.WaitOne ();
+
+ lock (task) {
+ if (!task.RunFinishedEvent.WaitOne (RunTimeout, false)) {
+ task.TimedOut = true;
+ return false;
+ } else {
+ lock (runningLock) {
+ mainThreadBusy = false;
+ Monitor.PulseAll (runningLock);
+ }
+ }
+ }
+ return true;
+ }
+
+ void Runner ()
+ {
+ Task threadTask = null;
+
+ while (!disposed) {
+
+ if (threadTask == null) {
+ newTaskEvent.WaitOne ();
+
+ lock (runningLock) {
+ if (disposed) {
+ runningThreads--;
+ return;
+ }
+ threadTask = currentTask;
+ currentTask = null;
+ }
+ }
+
+ threadTask.RunningEvent.Set ();
+ SafeRun (threadTask.Evaluator);
+ threadTask.RunFinishedEvent.Set ();
+
+ Task curTask = threadTask;
+ threadTask = null;
+
+ OnEndEval ();
+
+ lock (runningLock) {
+ if (disposed) {
+ runningThreads--;
+ return;
+ }
+ }
+
+ lock (curTask) {
+ if (!curTask.TimedOut)
+ continue; // Done. Keep waiting for more tasks.
+
+ SafeRun (curTask.FinishedCallback);
+ }
+
+ // The task timed out, so more threads may already have
+ // been created while this one was busy.
+
+ lock (runningLock) {
+ Monitor.PulseAll (runningLock);
+ if (pendingTasks.Count > 0) {
+ // There is pending work to do.
+ OnStartEval ();
+ threadTask = pendingTasks.Dequeue ();
+ }
+ else if (mainThreadBusy) {
+ // More threads have been created and all are busy.
+ // This will now be the main thread.
+ mainThreadBusy = false;
+ }
+ else {
+ // More threads have been created and one of them is waiting for tasks
+ // This thread is not needed anymore, die
+ runningThreads--;
+ break;
+ }
+ }
+ }
+ }
+
+ public void Dispose ()
+ {
+ lock (runningLock) {
+ disposed = true;
+ CancelAll ();
+ newTaskEvent.Set ();
+ }
+ }
+
+ public void CancelAll ()
+ {
+ lock (runningLock) {
+ // If there is a task waiting the be picked by the runner,
+ // set the task wait events to avoid deadlocking the caller.
+ if (currentTask != null) {
+ currentTask.RunningEvent.Set ();
+ currentTask.RunFinishedEvent.Set ();
+ }
+ pendingTasks.Clear ();
+ Monitor.PulseAll (runningLock);
+ }
+ }
+
+ public void WaitForStopped ()
+ {
+ lock (runningLock) {
+ while (mainThreadBusy)
+ Monitor.Wait (runningLock);
+ }
+ }
+
+ void SafeRun (EvaluatorDelegate del)
+ {
+ try {
+ del ();
+ } catch {
+ }
+ }
+
+ class Task
+ {
+ public AutoResetEvent RunningEvent = new AutoResetEvent (false);
+ public AutoResetEvent RunFinishedEvent = new AutoResetEvent (false);
+ public EvaluatorDelegate Evaluator;
+ public EvaluatorDelegate FinishedCallback;
+ public bool TimedOut;
+ }
+ }
+
+ public delegate void EvaluatorDelegate ();
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/TypeValueReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/TypeValueReference.cs
new file mode 100644
index 0000000..a749220
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/TypeValueReference.cs
@@ -0,0 +1,207 @@
+// TypeValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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.Linq;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Reflection;
+
+using Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class TypeValueReference: ValueReference
+ {
+ readonly string fullName;
+ readonly string name;
+ readonly object type;
+
+ public TypeValueReference (EvaluationContext ctx, object type) : base (ctx)
+ {
+ this.type = type;
+ fullName = ctx.Adapter.GetDisplayTypeName (ctx, type);
+ name = GetTypeName (fullName);
+ }
+
+ internal static string GetTypeName (string tname)
+ {
+ tname = tname.Replace ('+', '.');
+
+ int sep1 = tname.IndexOf ('<');
+ int sep2 = tname.IndexOf ('[');
+
+ if (sep2 != -1 && (sep2 < sep1 || sep1 == -1))
+ sep1 = sep2;
+
+ if (sep1 == -1)
+ sep1 = tname.Length - 1;
+
+ int i = tname.LastIndexOf ('.', sep1);
+
+ if (i != -1)
+ return tname.Substring (i + 1);
+
+ return tname;
+ }
+
+ public override object Value {
+ get {
+ throw new NotSupportedException ();
+ }
+ set {
+ throw new NotSupportedException();
+ }
+ }
+
+ public override object Type {
+ get {
+ return type;
+ }
+ }
+
+ public override object ObjectValue {
+ get {
+ throw new NotSupportedException ();
+ }
+ }
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.Type;
+ }
+ }
+
+ protected override ObjectValue OnCreateObjectValue (EvaluationOptions options)
+ {
+ return Mono.Debugging.Client.ObjectValue.CreateObject (this, new ObjectPath (Name), "<type>", fullName, Flags, null);
+ }
+
+ public override ValueReference GetChild (string name, EvaluationOptions options)
+ {
+ EvaluationContext ctx = GetContext (options);
+ foreach (ValueReference val in ctx.Adapter.GetMembers (ctx, this, type, null)) {
+ if (val.Name == name)
+ return val;
+ }
+ foreach (object t in ctx.Adapter.GetNestedTypes (ctx, type)) {
+ string tn = ctx.Adapter.GetTypeName (ctx, t);
+ if (GetTypeName (tn) == name)
+ return new TypeValueReference (ctx, t);
+ }
+ return null;
+ }
+
+ public override ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ EvaluationContext ctx = GetContext (options);
+ try {
+ List<ObjectValue> list = new List<ObjectValue> ();
+ BindingFlags flattenFlag = options.FlattenHierarchy ? (BindingFlags)0 : BindingFlags.DeclaredOnly;
+ BindingFlags flags = BindingFlags.Static | BindingFlags.Public | flattenFlag;
+ bool groupPrivateMembers = options.GroupPrivateMembers || ctx.Adapter.IsExternalType (ctx, type);
+ if (!groupPrivateMembers)
+ flags |= BindingFlags.NonPublic;
+
+ TypeDisplayData tdata = ctx.Adapter.GetTypeDisplayData (ctx, type);
+ object tdataType = type;
+
+ foreach (ValueReference val in ctx.Adapter.GetMembersSorted (ctx, this, type, null, flags)) {
+ object decType = val.DeclaringType;
+ if (decType != null && decType != tdataType) {
+ tdataType = decType;
+ tdata = ctx.Adapter.GetTypeDisplayData (ctx, decType);
+ }
+ DebuggerBrowsableState state = tdata.GetMemberBrowsableState (val.Name);
+ if (state == DebuggerBrowsableState.Never)
+ continue;
+
+ ObjectValue oval = val.CreateObjectValue (options);
+ list.Add (oval);
+ }
+
+ List<ObjectValue> nestedTypes = new List<ObjectValue> ();
+ foreach (object t in ctx.Adapter.GetNestedTypes (ctx, type))
+ nestedTypes.Add (new TypeValueReference (ctx, t).CreateObjectValue (options));
+
+ nestedTypes.Sort (delegate (ObjectValue v1, ObjectValue v2) {
+ return v1.Name.CompareTo (v2.Name);
+ });
+
+ list.AddRange (nestedTypes);
+
+ if (groupPrivateMembers)
+ list.Add (FilteredMembersSource.CreateNonPublicsNode (ctx, this, type, null, BindingFlags.NonPublic | BindingFlags.Static | flattenFlag));
+
+ if (!options.FlattenHierarchy) {
+ object baseType = ctx.Adapter.GetBaseType (ctx, type, false);
+ if (baseType != null) {
+ TypeValueReference baseRef = new TypeValueReference (ctx, baseType);
+ ObjectValue baseVal = baseRef.CreateObjectValue (false);
+ baseVal.Name = "base";
+ list.Insert (0, baseVal);
+ }
+ }
+
+ return list.ToArray ();
+ } catch (Exception ex) {
+ Console.WriteLine (ex);
+ ctx.WriteDebuggerOutput (ex.Message);
+ return new ObjectValue [0];
+ }
+ }
+
+ public override IEnumerable<ValueReference> GetChildReferences (EvaluationOptions options)
+ {
+ EvaluationContext ctx = GetContext (options);
+ try {
+ List<ValueReference> list = new List<ValueReference> ();
+ list.AddRange (ctx.Adapter.GetMembersSorted (ctx, this, type, null, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static));
+
+ List<ValueReference> nestedTypes = new List<ValueReference> ();
+ foreach (object t in ctx.Adapter.GetNestedTypes (ctx, type))
+ nestedTypes.Add (new TypeValueReference (ctx, t));
+
+ nestedTypes.Sort (delegate (ValueReference v1, ValueReference v2) {
+ return v1.Name.CompareTo (v2.Name);
+ });
+ list.AddRange (nestedTypes);
+ return list;
+ } catch (Exception ex) {
+ Console.WriteLine (ex);
+ ctx.WriteDebuggerOutput (ex.Message);
+ return new ValueReference[0];
+ }
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/UserVariableReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/UserVariableReference.cs
new file mode 100644
index 0000000..50049d7
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/UserVariableReference.cs
@@ -0,0 +1,73 @@
+//
+// UserVariableReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public class UserVariableReference: ValueReference
+ {
+ readonly string name;
+ object currentValue;
+
+ public UserVariableReference (EvaluationContext ctx, string name): base (ctx)
+ {
+ this.name = name;
+ }
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+
+ public override object Value {
+ get {
+ if (currentValue != null)
+ return currentValue;
+ else
+ throw new EvaluatorException ("Value undefined.");
+ }
+ set {
+ currentValue = value;
+ }
+ }
+
+ public override object Type {
+ get {
+ return Context.Adapter.GetValueType (Context, Value);
+ }
+ }
+
+ public override ObjectValueFlags Flags {
+ get {
+ return ObjectValueFlags.Variable;
+ }
+ }
+
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.Evaluation/ValueReference.cs b/Mono.Debugging/Mono.Debugging.Evaluation/ValueReference.cs
new file mode 100644
index 0000000..56e68ea
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.Evaluation/ValueReference.cs
@@ -0,0 +1,266 @@
+// ValueReference.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at 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 Mono.Debugging.Client;
+using Mono.Debugging.Backend;
+using DC = Mono.Debugging.Client;
+
+namespace Mono.Debugging.Evaluation
+{
+ public abstract class ValueReference: RemoteFrameObject, IObjectValueSource, IObjectSource
+ {
+ readonly EvaluationOptions originalOptions;
+ EvaluationContext ctx;
+
+ protected ValueReference (EvaluationContext ctx)
+ {
+ this.ctx = ctx;
+ originalOptions = ctx.Options;
+ }
+
+ public virtual object ObjectValue {
+ get {
+ object ob = Value;
+ if (ctx.Adapter.IsNull (Context, ob))
+ return null;
+
+ if (ctx.Adapter.IsPrimitive (Context, ob))
+ return ctx.Adapter.TargetObjectToObject (ctx, ob);
+
+ return ob;
+ }
+ }
+
+ public abstract object Value { get; set; }
+ public abstract string Name { get; }
+ public abstract object Type { get; }
+ public abstract ObjectValueFlags Flags { get; }
+
+ // For class members, the type declaring the member (null otherwise)
+ public virtual object DeclaringType {
+ get { return null; }
+ }
+
+ public EvaluationContext Context {
+ get {
+ return ctx;
+ }
+ }
+
+ public EvaluationContext GetContext (EvaluationOptions options)
+ {
+ return ctx.WithOptions (options);
+ }
+
+ public ObjectValue CreateObjectValue (bool withTimeout)
+ {
+ return CreateObjectValue (withTimeout, Context.Options);
+ }
+
+ public ObjectValue CreateObjectValue (bool withTimeout, EvaluationOptions options)
+ {
+ if (!CanEvaluate (options))
+ return DC.ObjectValue.CreateImplicitNotSupported (this, new ObjectPath (Name), ctx.Adapter.GetTypeName (GetContext (options), Type), Flags);
+ if (withTimeout) {
+ return ctx.Adapter.CreateObjectValueAsync (Name, Flags, delegate {
+ return CreateObjectValue (options);
+ });
+ }
+
+ return CreateObjectValue (options);
+ }
+
+ public ObjectValue CreateObjectValue (EvaluationOptions options)
+ {
+ if (!CanEvaluate (options))
+ return DC.ObjectValue.CreateImplicitNotSupported (this, new ObjectPath (Name), ctx.Adapter.GetTypeName (GetContext (options), Type), Flags);
+
+ Connect ();
+ try {
+ return OnCreateObjectValue (options);
+ } catch (ImplicitEvaluationDisabledException) {
+ return DC.ObjectValue.CreateImplicitNotSupported (this, new ObjectPath (Name), ctx.Adapter.GetTypeName (GetContext (options), Type), Flags);
+ } catch (NotSupportedExpressionException ex) {
+ return DC.ObjectValue.CreateNotSupported (this, new ObjectPath (Name), ex.Message, ctx.Adapter.GetTypeName (GetContext (options), Type), Flags);
+ } catch (EvaluatorException ex) {
+ return DC.ObjectValue.CreateError (this, new ObjectPath (Name), "", ex.Message, Flags);
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ return DC.ObjectValue.CreateUnknown (Name);
+ }
+ }
+
+ protected virtual bool CanEvaluate (EvaluationOptions options)
+ {
+ return true;
+ }
+
+ protected virtual ObjectValue OnCreateObjectValue (EvaluationOptions options)
+ {
+ string name = Name;
+ if (string.IsNullOrEmpty (name))
+ name = "?";
+
+ EvaluationContext newCtx = GetContext (options);
+ EvaluationContext oldCtx = Context;
+ object val = null;
+
+ try {
+ // Note: The Value property implementation may make use of the EvaluationOptions,
+ // so we need to override our context temporarily to do the evaluation.
+ ctx = newCtx;
+ val = Value;
+ } finally {
+ ctx = oldCtx;
+ }
+
+ if (val != null)
+ return newCtx.Adapter.CreateObjectValue (newCtx, this, new ObjectPath (name), val, Flags);
+
+ return Mono.Debugging.Client.ObjectValue.CreateNullObject (this, name, newCtx.Adapter.GetTypeName (newCtx, Type), Flags);
+ }
+
+ ObjectValue IObjectValueSource.GetValue (ObjectPath path, EvaluationOptions options)
+ {
+ return CreateObjectValue (true, options);
+ }
+
+ EvaluationResult IObjectValueSource.SetValue (ObjectPath path, string value, EvaluationOptions options)
+ {
+ try {
+ ctx.WaitRuntimeInvokes ();
+ EvaluationContext cctx = GetContext (options);
+ cctx.Options.AllowMethodEvaluation = true;
+ cctx.Options.AllowTargetInvoke = true;
+ ValueReference vref = cctx.Evaluator.Evaluate (cctx, value, Type);
+ object newValue = cctx.Adapter.Convert (cctx, vref.Value, Type);
+ Value = newValue;
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ ctx.WriteDebuggerOutput ("Value assignment failed: {0}: {1}\n", ex.GetType (), ex.Message);
+ }
+
+ try {
+ return ctx.Evaluator.TargetObjectToExpression (ctx, Value);
+ } catch (Exception ex) {
+ ctx.WriteDebuggerError (ex);
+ ctx.WriteDebuggerOutput ("Value assignment failed: {0}: {1}\n", ex.GetType (), ex.Message);
+ }
+
+ return null;
+ }
+
+ object IObjectValueSource.GetRawValue (ObjectPath path, EvaluationOptions options)
+ {
+ return ctx.Adapter.ToRawValue (GetContext (options), this, Value);
+ }
+
+ void IObjectValueSource.SetRawValue (ObjectPath path, object value, EvaluationOptions options)
+ {
+ Value = ctx.Adapter.FromRawValue (GetContext (options), value);
+ }
+
+ ObjectValue[] IObjectValueSource.GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ return GetChildren (path, index, count, options);
+ }
+
+ public virtual string CallToString ()
+ {
+ return ctx.Adapter.CallToString (ctx, Value);
+ }
+
+ public virtual ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
+ {
+ try {
+ return ctx.Adapter.GetObjectValueChildren (GetChildrenContext (options), this, Value, index, count);
+ } catch (Exception ex) {
+ return new ObjectValue [] { Mono.Debugging.Client.ObjectValue.CreateFatalError ("", ex.Message, ObjectValueFlags.ReadOnly) };
+ }
+ }
+
+ public virtual IEnumerable<ValueReference> GetChildReferences (EvaluationOptions options)
+ {
+ try {
+ object val = Value;
+ if (ctx.Adapter.IsClassInstance (Context, val))
+ return ctx.Adapter.GetMembersSorted (GetChildrenContext (options), this, Type, val);
+ } catch {
+ // Ignore
+ }
+ return new ValueReference [0];
+ }
+
+ public IObjectSource ParentSource { get; internal set; }
+
+ protected EvaluationContext GetChildrenContext (EvaluationOptions options)
+ {
+ EvaluationContext newCtx = ctx.Clone ();
+ if (options != null)
+ newCtx.Options = options;
+ newCtx.Options.EvaluationTimeout = originalOptions.MemberEvaluationTimeout;
+ return newCtx;
+ }
+
+ public virtual ValueReference GetChild (ObjectPath vpath, EvaluationOptions options)
+ {
+ if (vpath.Length == 0)
+ return this;
+
+ ValueReference val = GetChild (vpath[0], options);
+ if (val != null)
+ return val.GetChild (vpath.GetSubpath (1), options);
+
+ return null;
+ }
+
+ public virtual ValueReference GetChild (string name, EvaluationOptions options)
+ {
+ object obj = Value;
+
+ if (obj == null)
+ return null;
+
+ if (name[0] == '[' && ctx.Adapter.IsArray (Context, obj)) {
+ // Parse the array indices
+ string[] sinds = name.Substring (1, name.Length - 2).Split (',');
+ int[] indices = new int [sinds.Length];
+ for (int n=0; n<sinds.Length; n++)
+ indices [n] = int.Parse (sinds [n]);
+
+ return new ArrayValueReference (ctx, obj, indices);
+ }
+
+ if (ctx.Adapter.IsClassInstance (Context, obj))
+ return ctx.Adapter.GetMember (GetChildrenContext (options), this, obj, name);
+
+ return null;
+ }
+ }
+}
diff --git a/Mono.Debugging/Mono.Debugging.csproj b/Mono.Debugging/Mono.Debugging.csproj
new file mode 100644
index 0000000..cfd61c9
--- /dev/null
+++ b/Mono.Debugging/Mono.Debugging.csproj
@@ -0,0 +1,140 @@
+<?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>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Mono.Debugging</RootNamespace>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>mono.debugging.snk</AssemblyOriginatorKeyFile>
+ <AssemblyName>Mono.Debugging</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>True</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>False</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>False</ConsolePause>
+ <Execution>
+ <Execution clr-version="Net_2_0" />
+ </Execution>
+ <GenerateDocumentation>true</GenerateDocumentation>
+ <NoWarn>1591;1573</NoWarn>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>False</ConsolePause>
+ <Execution>
+ <Execution clr-version="Net_2_0" />
+ </Execution>
+ <DebugSymbols>true</DebugSymbols>
+ <GenerateDocumentation>true</GenerateDocumentation>
+ <NoWarn>1591;1573</NoWarn>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Core" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Mono.Debugging.Client\IExpressionEvaluator.cs" />
+ <Compile Include="Mono.Debugging.Client\Breakpoint.cs" />
+ <Compile Include="Mono.Debugging.Client\DebuggerSession.cs" />
+ <Compile Include="Mono.Debugging.Client\Backtrace.cs" />
+ <Compile Include="Mono.Debugging.Client\DebuggerStartInfo.cs" />
+ <Compile Include="Mono.Debugging.Client\ProcessEventArgs.cs" />
+ <Compile Include="Mono.Debugging.Client\SourceLocation.cs" />
+ <Compile Include="Mono.Debugging.Client\StackFrame.cs" />
+ <Compile Include="Mono.Debugging.Client\TargetEventArgs.cs" />
+ <Compile Include="Mono.Debugging.Client\TargetEventType.cs" />
+ <Compile Include="Mono.Debugging.Client\ThreadEventArgs.cs" />
+ <Compile Include="Mono.Debugging.Backend\IBacktrace.cs" />
+ <Compile Include="Mono.Debugging.Backend\IDebuggerSessionFrontend.cs" />
+ <Compile Include="Mono.Debugging.Client\BreakpointStore.cs" />
+ <Compile Include="Mono.Debugging.Client\BreakpointEventArgs.cs" />
+ <Compile Include="Mono.Debugging.Client\ObjectValue.cs" />
+ <Compile Include="Mono.Debugging.Backend\IObjectValueSource.cs" />
+ <Compile Include="Mono.Debugging.Client\ObjectValueFlags.cs" />
+ <Compile Include="Mono.Debugging.Client\ObjectPath.cs" />
+ <Compile Include="Mono.Debugging.Client\ThreadInfo.cs" />
+ <Compile Include="Mono.Debugging.Client\ProcessInfo.cs" />
+ <Compile Include="Mono.Debugging.Client\AssemblyLine.cs" />
+ <Compile Include="Mono.Debugging.Backend\DissassemblyBuffer.cs" />
+ <Compile Include="Mono.Debugging.Client\CompletionData.cs" />
+ <Compile Include="Mono.Debugging.Client\Catchpoint.cs" />
+ <Compile Include="Mono.Debugging.Client\BreakEvent.cs" />
+ <Compile Include="Mono.Debugging.Client\CatchpointEventArgs.cs" />
+ <Compile Include="Mono.Debugging.Client\BreakEventArgs.cs" />
+ <Compile Include="Mono.Debugging.Client\DebuggerFeatures.cs" />
+ <Compile Include="Mono.Debugging.Backend\IObjectValueUpdater.cs" />
+ <Compile Include="Mono.Debugging.Backend\IObjectValueUpdateCallback.cs" />
+ <Compile Include="Mono.Debugging.Backend\UpdateCallback.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ArrayElementGroup.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ArrayValueReference.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\AsyncEvaluationTracker.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\AsyncOperationManager.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\EvaluationContext.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ExpressionEvaluator.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\FilteredMembersSource.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ICollectionAdaptor.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\LiteralValueReference.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\NamespaceValueReference.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\NullValueReference.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ObjectValueAdaptor.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\RawViewSource.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\RemoteFrameObject.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\TimedEvaluator.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\TimeOutException.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\TypeValueReference.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ValueReference.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\UserVariableReference.cs" />
+ <Compile Include="Mono.Debugging.Client\DebuggerException.cs" />
+ <Compile Include="Mono.Debugging.Client\DebuggerSessionOptions.cs" />
+ <Compile Include="Mono.Debugging.Client\EvaluationOptions.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\BaseBacktrace.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\BaseTypeViewSource.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\IObjectSource.cs" />
+ <Compile Include="Mono.Debugging.Client\RawValue.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\RemoteRawValue.cs" />
+ <Compile Include="Mono.Debugging.Client\ExceptionInfo.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\ExceptionInfoSource.cs" />
+ <Compile Include="Mono.Debugging.Client\BreakEventStatus.cs" />
+ <Compile Include="Mono.Debugging.Client\BreakEventInfo.cs" />
+ <Compile Include="Mono.Debugging.Client\FunctionBreakpoint.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\IStringAdaptor.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\NRefactoryExpressionEvaluator.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\NRefactoryExpressionEvaluatorVisitor.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\NRefactoryExpressionResolverVisitor.cs" />
+ <Compile Include="Mono.Debugging.Evaluation\NRefactoryExtensions.cs" />
+ <Compile Include="Mono.Debugging.Backend\IDebuggerBackendObject.cs" />
+ <Compile Include="Mono.Debugging.Backend\IRawValue.cs" />
+ <Compile Include="Mono.Debugging.Backend\IRawValueArray.cs" />
+ <Compile Include="Mono.Debugging.Backend\IRawValueString.cs" />
+ <Compile Include="Mono.Debugging.Backend\EvaluationResult.cs" />
+ <Compile Include="Mono.Debugging.Client\DebuggerLoggingService.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Folder Include="Mono.Debugging.Evaluation\" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\nrefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
+ <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
+ <Name>ICSharpCode.NRefactory</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\nrefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
+ <Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
+ <Name>ICSharpCode.NRefactory.CSharp</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project>
diff --git a/Mono.Debugging/mono.debugging.snk b/Mono.Debugging/mono.debugging.snk
new file mode 100644
index 0000000..47df15f
Binary files /dev/null and b/Mono.Debugging/mono.debugging.snk differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7050d5c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+This repository contains several libraries which can be used to control the Mono debugger.
+
+* Mono.Debugger.Soft: The Mono Soft Debugger low level API
+* Mono.Debugging: Pluggable debugger API abstraction. It provides a common API to be used as frontend to different debuggers.
+* Mono.Debugging.Soft: Mono.Debugging backend for the Mono Soft Debugger.
+
+Dependencies
+============
+
+The libraries in this repository have external dependencies, specifically:
+
+* cecil (git://github.com/mono/cecil.git)
+* nrefactory (git://github.com/icsharpcode/NRefactory.git)
+
+Those libraries must be cloned side by side with debugger-libs.
\ No newline at end of file
diff --git a/UnitTests/UnitTests/DebugTests.cs b/UnitTests/UnitTests/DebugTests.cs
new file mode 100644
index 0000000..cdcdfa9
--- /dev/null
+++ b/UnitTests/UnitTests/DebugTests.cs
@@ -0,0 +1,110 @@
+//
+// DebugTests.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 NUnit.Framework;
+using Mono.Debugging.Client;
+using System.IO;
+using System.Threading;
+
+namespace Mono.Debugging.UnitTests
+{
+ public abstract class DebugTests
+ {
+ protected abstract DebuggerStartInfo CreateDebuggerStartInfo ();
+ protected abstract DebuggerSession CreateDebuggerSession ();
+
+ protected DebuggerSession Start (string test)
+ {
+ try {
+ DebuggerStartInfo si = CreateDebuggerStartInfo ();
+ si.Command = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "UnitTests.TestApp.exe");
+ si.Arguments = test;
+
+ DebuggerSessionOptions ops = new DebuggerSessionOptions ();
+ ops.EvaluationOptions = EvaluationOptions.DefaultOptions;
+ ops.EvaluationOptions.EvaluationTimeout = 100000;
+
+ DebuggerSession session = CreateDebuggerSession ();
+ string path = Path.Combine (GetTestsDir (), "UnitTests.TestApp", "Main.cs");
+ path = Path.GetFullPath (path);
+
+ ManualResetEvent done = new ManualResetEvent (false);
+
+ session.OutputWriter = delegate (bool isStderr, string text) {
+ Console.WriteLine ("PROC:" + text);
+ };
+
+ session.TargetStopped += delegate {
+ done.Set ();
+ };
+
+ session.Run (si, ops);
+ if (!done.WaitOne (3000))
+ throw new Exception ("Timeout while waiting for initial breakpoint");
+
+ return session;
+ } catch (Exception ex) {
+ Console.WriteLine (ex);
+ throw;
+ }
+ }
+
+ public static string GetTestsDir ()
+ {
+ var p = typeof(DebugTests).Assembly.Location;
+ return Path.Combine (Path.GetDirectoryName (p), "..", "..", "..");
+ }
+ }
+
+ static class EvalHelper
+ {
+ public static ObjectValue Sync (this ObjectValue val)
+ {
+ if (!val.IsEvaluating)
+ return val;
+
+ object locker = new object ();
+ EventHandler h = delegate {
+ lock (locker) {
+ Monitor.PulseAll (locker);
+ }
+ };
+
+ val.ValueChanged += h;
+
+ lock (locker) {
+ while (val.IsEvaluating) {
+ if (!Monitor.Wait (locker, 4000))
+ throw new Exception ("Timeout while waiting for value evaluation");
+ }
+ }
+
+ val.ValueChanged -= h;
+ return val;
+ }
+ }
+}
diff --git a/UnitTests/UnitTests/EvaluationTests.cs b/UnitTests/UnitTests/EvaluationTests.cs
new file mode 100644
index 0000000..69037f2
--- /dev/null
+++ b/UnitTests/UnitTests/EvaluationTests.cs
@@ -0,0 +1,695 @@
+//
+// EvaluationTests.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 Mono.Debugging.Client;
+using NUnit.Framework;
+
+namespace Mono.Debugging.UnitTests
+{
+ public abstract class EvaluationTests: DebugTests
+ {
+ DebuggerSession ds;
+ StackFrame frame;
+
+ [TestFixtureSetUp]
+ public void Setup ()
+ {
+ ds = Start ("TestEvaluation");
+ frame = ds.ActiveThread.Backtrace.GetFrame (0);
+ }
+
+ [TestFixtureTearDown]
+ public void TearDown ()
+ {
+ ds.Exit ();
+ ds.Dispose ();
+ }
+
+
+ ObjectValue Eval (string exp)
+ {
+ return frame.GetExpressionValue (exp, true).Sync ();
+ }
+
+ [Test()]
+ public void This ()
+ {
+ ObjectValue val = Eval ("this");
+ Assert.AreEqual ("{UnitTests.TestApp.MainClass}", val.Value);
+ Assert.AreEqual ("UnitTests.TestApp.MainClass", val.TypeName);
+ }
+
+ [Test()]
+ public void UnaryOperators ()
+ {
+ ObjectValue val = Eval ("~1234");
+ Assert.AreEqual ((~1234).ToString (), val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("!true");
+ Assert.AreEqual ("false", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("!false");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("-1234");
+ Assert.AreEqual ("-1234", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("+1234");
+ Assert.AreEqual ("1234", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+ }
+
+ [Test()]
+ public void TypeReference ()
+ {
+ ObjectValue val = Eval ("System.String");
+ Assert.AreEqual ("string", val.Value);
+ Assert.AreEqual ("<type>", val.TypeName);
+ Assert.AreEqual (ObjectValueFlags.Type, val.Flags & ObjectValueFlags.OriginMask);
+
+ val = Eval ("MainClass");
+ Assert.AreEqual ("UnitTests.TestApp.MainClass", val.Value);
+ Assert.AreEqual ("<type>", val.TypeName);
+ Assert.AreEqual (ObjectValueFlags.Type, val.Flags & ObjectValueFlags.OriginMask);
+
+ val = Eval ("UnitTests.TestApp.MainClass");
+ Assert.AreEqual ("MonoDevelop.Debugger.Tests.TestApp.MainClass", val.Value);
+ Assert.AreEqual ("<type>", val.TypeName);
+ Assert.AreEqual (ObjectValueFlags.Type, val.Flags & ObjectValueFlags.OriginMask);
+ }
+
+ [Test()]
+ public virtual void TypeReferenceGeneric ()
+ {
+ ObjectValue val = Eval ("System.Collections.Generic.Dictionary<string,int>");
+ Assert.AreEqual ("System.Collections.Generic.Dictionary<string,int>", val.Value);
+ Assert.AreEqual ("<type>", val.TypeName);
+ Assert.AreEqual (ObjectValueFlags.Type, val.Flags & ObjectValueFlags.OriginMask);
+ }
+
+ [Test()]
+ public virtual void Typeof ()
+ {
+ ObjectValue val = Eval ("typeof(System.Console)");
+ Assert.IsTrue (val.TypeName == "System.MonoType" || val.TypeName == "System.RuntimeType", "Incorrect type name: " + val.TypeName);
+ Assert.AreEqual ("{System.Console}", val.Value);
+ }
+
+ [Test()]
+ public void MethodInvoke ()
+ {
+ ObjectValue val;
+ val = Eval ("TestMethod ()");
+ Assert.AreEqual ("1", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("TestMethod (\"23\")");
+ Assert.AreEqual ("24", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("TestMethod (42)");
+ Assert.AreEqual ("43", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("TestMethod (false)");
+ Assert.AreEqual ("2", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("this.TestMethod ()");
+ Assert.AreEqual ("1", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("this.TestMethod (\"23\")");
+ Assert.AreEqual ("24", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("this.TestMethod (42)");
+ Assert.AreEqual ("43", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("System.Int32.Parse (\"67\")");
+ Assert.AreEqual ("67", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("this.BoxingTestMethod (43)");
+ Assert.AreEqual ("\"43\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+ }
+
+ [Test()]
+ public void Indexers ()
+ {
+ ObjectValue val = Eval ("numbers[0]");
+ Assert.AreEqual ("\"one\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("numbers[1]");
+ Assert.AreEqual ("\"two\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("numbers[2]");
+ Assert.AreEqual ("\"three\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("staticString[2]");
+ Assert.AreEqual ("'m'", val.Value);
+ Assert.AreEqual ("char", val.TypeName);
+
+ val = Eval ("alist[0]");
+ Assert.AreEqual ("1", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("alist[1]");
+ Assert.AreEqual ("\"two\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("alist[2]");
+ Assert.AreEqual ("3", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+ }
+
+ [Test()]
+ public void MemberReference ()
+ {
+ ObjectValue val = Eval ("alist.Count");
+ Assert.AreEqual ("3", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ Eval ("var tt = this");
+
+ val = Eval ("tt.someString");
+ Assert.AreEqual ("\"hi\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("UnitTests");
+ Assert.AreEqual ("UnitTests", val.Value);
+ Assert.AreEqual ("<namespace>", val.TypeName);
+
+ val = Eval ("UnitTests.TestApp.MainClass");
+ Assert.AreEqual ("UnitTests.TestApp.MainClass", val.Value);
+ Assert.AreEqual ("<type>", val.TypeName);
+
+ val = Eval ("UnitTests.TestApp.MainClass.staticString");
+ Assert.AreEqual ("\"some static\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+ }
+
+ [Test()]
+ public void ConditionalExpression ()
+ {
+ ObjectValue val = Eval ("true ? \"yes\" : \"no\"");
+ Assert.AreEqual ("\"yes\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("false ? \"yes\" : \"no\"");
+ Assert.AreEqual ("\"no\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+ }
+
+ [Test()]
+ public void Cast ()
+ {
+ ObjectValue val;
+ val = Eval ("(byte)n");
+ Assert.AreEqual ("32", val.Value);
+ Assert.AreEqual ("byte", val.TypeName);
+
+ val = Eval ("(int)n");
+ Assert.AreEqual ("32", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("(long)n");
+ Assert.AreEqual ("32", val.Value);
+ Assert.AreEqual ("long", val.TypeName);
+
+ val = Eval ("(float)n");
+ Assert.AreEqual ("32", val.Value);
+ Assert.AreEqual ("float", val.TypeName);
+
+ val = Eval ("(double)n");
+ Assert.AreEqual ("32", val.Value);
+ Assert.AreEqual ("double", val.TypeName);
+
+ val = Eval ("(string)staticString");
+ Assert.AreEqual ("\"some static\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("(int)numbers");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("(int)this");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("(C)a");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("(C)b");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("(C)c");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("(B)a");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("(B)b");
+ Assert.AreEqual ("{B}", val.Value);
+ Assert.AreEqual ("B", val.TypeName);
+
+ val = Eval ("(B)c");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("(A)a");
+ Assert.AreEqual ("{A}", val.Value);
+ Assert.AreEqual ("A", val.TypeName);
+
+ val = Eval ("(A)b");
+ Assert.AreEqual ("{B}", val.Value);
+ Assert.AreEqual ("B", val.TypeName);
+
+ val = Eval ("(A)c");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ // Try cast
+
+ val = Eval ("c as A");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("c as B");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("c as C");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("b as A");
+ Assert.AreEqual ("{B}", val.Value);
+ Assert.AreEqual ("B", val.TypeName);
+
+ val = Eval ("b as B");
+ Assert.AreEqual ("{B}", val.Value);
+ Assert.AreEqual ("B", val.TypeName);
+
+ val = Eval ("b as C");
+ Assert.AreEqual ("null", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("a as A");
+ Assert.AreEqual ("{A}", val.Value);
+ Assert.AreEqual ("A", val.TypeName);
+
+ val = Eval ("a as B");
+ Assert.AreEqual ("null", val.Value);
+ Assert.AreEqual ("B", val.TypeName);
+
+ val = Eval ("a as C");
+ Assert.AreEqual ("null", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ // Enum cast
+
+ val = Eval ("(int)SomeEnum.two");
+ Assert.AreEqual ("2", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+
+ val = Eval ("(long)SomeEnum.two");
+ Assert.AreEqual ("2", val.Value);
+ Assert.AreEqual ("long", val.TypeName);
+
+ val = Eval ("(SomeEnum)2");
+ Assert.AreEqual ("SomeEnum.two", val.Value);
+ Assert.AreEqual ("two", val.DisplayValue);
+ Assert.AreEqual ("SomeEnum", val.TypeName);
+
+ val = Eval ("(SomeEnum)3");
+ Assert.AreEqual ("SomeEnum.one|SomeEnum.two", val.Value);
+ Assert.AreEqual ("one|two", val.DisplayValue);
+ Assert.AreEqual ("SomeEnum", val.TypeName);
+ }
+
+ [Test()]
+ public void BinaryOperators ()
+ {
+ ObjectValue val;
+
+ // Boolean
+
+ val = Eval ("true && true");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("true && false");
+ Assert.AreEqual ("false", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("false && true");
+ Assert.AreEqual ("false", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("false && false");
+ Assert.AreEqual ("false", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("false || false");
+ Assert.AreEqual ("false", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("false || true");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("true || false");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("true || true");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("false || 1");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("1 || true");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("true && 1");
+ Assert.IsTrue (val.IsError);
+
+ val = Eval ("1 && true");
+ Assert.IsTrue (val.IsError);
+
+ // Concat string
+
+ val = Eval ("\"a\" + \"b\"");
+ Assert.AreEqual ("\"ab\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("\"a\" + 2");
+ Assert.AreEqual ("\"a2\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("2 + \"a\"");
+ Assert.AreEqual ("\"2a\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ val = Eval ("this + \"a\"");
+ Assert.AreEqual ("\"UnitTests.TestApp.MainClassa\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+
+ // Equality
+
+ val = Eval ("2 == 2");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("2 == 3");
+ Assert.AreEqual ("false", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ val = Eval ("(long)2 == (int)2");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+
+ // Arithmetic
+
+ val = Eval ("2 + 3");
+ Assert.AreEqual ("5", val.Value);
+
+ val = Eval ("2 + 2 == 4");
+ Assert.AreEqual ("true", val.Value);
+ Assert.AreEqual ("bool", val.TypeName);
+ }
+
+ [Test()]
+ public virtual void Assignment ()
+ {
+ ObjectValue val;
+ Eval ("n = 6");
+ val = Eval ("n");
+ Assert.AreEqual ("6", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+ Eval ("n = 32");
+ val = Eval ("n");
+ Assert.AreEqual ("32", val.Value);
+
+ Eval ("someString = \"test\"");
+ val = Eval ("someString");
+ Assert.AreEqual ("\"test\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+ Eval ("someString = \"hi\"");
+ val = Eval ("someString");
+ Assert.AreEqual ("\"hi\"", val.Value);
+
+ Eval ("numbers[0] = \"test\"");
+ val = Eval ("numbers[0]");
+ Assert.AreEqual ("\"test\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+ Eval ("numbers[0] = \"one\"");
+ val = Eval ("numbers[0]");
+ Assert.AreEqual ("\"one\"", val.Value);
+
+ Eval ("alist[0] = 6");
+ val = Eval ("alist[0]");
+ Assert.AreEqual ("6", val.Value);
+ Assert.AreEqual ("int", val.TypeName);
+ Eval ("alist[0] = 1");
+ val = Eval ("alist[0]");
+ Assert.AreEqual ("1", val.Value);
+ }
+
+ [Test()]
+ public virtual void AssignmentStatic ()
+ {
+ ObjectValue val;
+
+ Eval ("staticString = \"test\"");
+ val = Eval ("staticString");
+ Assert.AreEqual ("\"test\"", val.Value);
+ Assert.AreEqual ("string", val.TypeName);
+ Eval ("staticString = \"some static\"");
+ val = Eval ("staticString");
+ Assert.AreEqual ("\"some static\"", val.Value);
+ }
+
+ [Test()]
+ public void FormatBool ()
+ {
+ ObjectValue val;
+ val = Eval ("true");
+ Assert.AreEqual ("true", val.Value);
+ val = Eval ("false");
+ Assert.AreEqual ("false", val.Value);
+ }
+
+ [Test()]
+ public void FormatNumber ()
+ {
+ ObjectValue val;
+ val = Eval ("(int)123");
+ Assert.AreEqual ("123", val.Value);
+ val = Eval ("(int)-123");
+ Assert.AreEqual ("-123", val.Value);
+
+ val = Eval ("(long)123");
+ Assert.AreEqual ("123", val.Value);
+ val = Eval ("(long)-123");
+ Assert.AreEqual ("-123", val.Value);
+
+ val = Eval ("(byte)123");
+ Assert.AreEqual ("123", val.Value);
+
+ val = Eval ("(uint)123");
+ Assert.AreEqual ("123", val.Value);
+
+ val = Eval ("(ulong)123");
+ Assert.AreEqual ("123", val.Value);
+
+ val = Eval ("dec");
+ Assert.AreEqual ("123.456", val.Value);
+ }
+
+ [Test()]
+ public void FormatString ()
+ {
+ ObjectValue val;
+ val = Eval ("\"hi\"");
+ Assert.AreEqual ("\"hi\"", val.Value);
+
+ val = Eval ("EscapedStrings");
+ Assert.AreEqual ("\" \\\" \\\\ \\a \\b \\f \\v \\n \\r \\t\"", val.Value);
+
+ val = Eval ("\" \\\" \\\\ \\a \\b \\f \\v \\n \\r \\t\"");
+ Assert.AreEqual ("\" \\\" \\\\ \\a \\b \\f \\v \\n \\r \\t\"", val.Value);
+ }
+
+ [Test()]
+ public void FormatChar ()
+ {
+ ObjectValue val;
+ val = Eval ("'A'");
+ Assert.AreEqual ("'A'", val.Value);
+ Assert.AreEqual ("65 'A'", val.DisplayValue);
+
+ val = Eval ("'\\0'");
+ Assert.AreEqual ("'\\0'", val.Value);
+ Assert.AreEqual ("0 '\\0'", val.DisplayValue);
+
+ val = Eval ("'\"'");
+ Assert.AreEqual ("'\"'", val.Value);
+ Assert.AreEqual ("34 '\"'", val.DisplayValue);
+
+ val = Eval ("'\\''");
+ Assert.AreEqual ("'\\''", val.Value);
+ Assert.AreEqual ("39 '\\''", val.DisplayValue);
+
+ val = Eval ("'\\\\'");
+ Assert.AreEqual ("'\\\\'", val.Value);
+ Assert.AreEqual ("92 '\\\\'", val.DisplayValue);
+
+ val = Eval ("'\\a'");
+ Assert.AreEqual ("'\\a'", val.Value);
+ Assert.AreEqual ("7 '\\a'", val.DisplayValue);
+
+ val = Eval ("'\\b'");
+ Assert.AreEqual ("'\\b'", val.Value);
+ Assert.AreEqual ("8 '\\b'", val.DisplayValue);
+
+ val = Eval ("'\\f'");
+ Assert.AreEqual ("'\\f'", val.Value);
+ Assert.AreEqual ("12 '\\f'", val.DisplayValue);
+
+ val = Eval ("'\\v'");
+ Assert.AreEqual ("'\\v'", val.Value);
+ Assert.AreEqual ("11 '\\v'", val.DisplayValue);
+
+ val = Eval ("'\\n'");
+ Assert.AreEqual ("'\\n'", val.Value);
+ Assert.AreEqual ("10 '\\n'", val.DisplayValue);
+
+ val = Eval ("'\\r'");
+ Assert.AreEqual ("'\\r'", val.Value);
+ Assert.AreEqual ("13 '\\r'", val.DisplayValue);
+
+ val = Eval ("'\\t'");
+ Assert.AreEqual ("'\\t'", val.Value);
+ Assert.AreEqual ("9 '\\t'", val.DisplayValue);
+ }
+
+ [Test()]
+ public void FormatObject ()
+ {
+ ObjectValue val;
+
+ val = Eval ("c");
+ Assert.AreEqual ("{C}", val.Value);
+ Assert.AreEqual ("C", val.TypeName);
+
+ val = Eval ("withDisplayString");
+ Assert.AreEqual ("Some one Value 2 End", val.Value);
+ Assert.AreEqual ("WithDisplayString", val.TypeName);
+
+ val = Eval ("withProxy");
+ Assert.AreEqual ("{WithProxy}", val.Value);
+ Assert.AreEqual ("WithProxy", val.TypeName);
+
+/* val = Eval ("withToString");
+ Assert.AreEqual ("{SomeString}", val.Value);
+ Assert.AreEqual ("WithToString", val.TypeName);*/
+ }
+
+ [Test()]
+ public void FormatArray ()
+ {
+ ObjectValue val;
+
+ val = Eval ("numbers");
+ Assert.AreEqual ("{string[3]}", val.Value);
+ Assert.AreEqual ("string[]", val.TypeName);
+
+ val = Eval ("numbersArrays");
+ Assert.AreEqual ("{int[2][]}", val.Value);
+ Assert.AreEqual ("int[][]", val.TypeName);
+
+ val = Eval ("numbersMulti");
+ Assert.AreEqual ("{int[3,4,5]}", val.Value);
+ Assert.AreEqual ("int[,,]", val.TypeName);
+ }
+
+ [Test()]
+ public void FormatGeneric ()
+ {
+ ObjectValue val;
+
+ ds.Options.EvaluationOptions.AllowTargetInvoke = false;
+ val = Eval ("dict");
+ ds.Options.EvaluationOptions.AllowTargetInvoke = true;
+ Assert.AreEqual ("{System.Collections.Generic.Dictionary<int,string[]>}", val.Value);
+ Assert.AreEqual ("System.Collections.Generic.Dictionary<int,string[]>", val.TypeName);
+
+ ds.Options.EvaluationOptions.AllowTargetInvoke = false;
+ val = Eval ("dictArray");
+ ds.Options.EvaluationOptions.AllowTargetInvoke = true;
+ Assert.AreEqual ("{System.Collections.Generic.Dictionary<int,string[]>[2,3]}", val.Value);
+ Assert.AreEqual ("System.Collections.Generic.Dictionary<int,string[]>[,]", val.TypeName);
+
+ val = Eval ("thing.done");
+ Assert.AreEqual ("{Thing<string>.Done<int>[1]}", val.Value);
+ Assert.AreEqual ("Thing<string>.Done<int>[]", val.TypeName);
+
+ val = Eval ("done");
+ Assert.AreEqual ("{Thing<string>.Done<int>}", val.Value);
+ Assert.AreEqual ("Thing<string>.Done<int>", val.TypeName);
+ }
+
+ [Test()]
+ public void FormatEnum ()
+ {
+ ObjectValue val;
+
+ val = Eval ("SomeEnum.one");
+ Assert.AreEqual ("SomeEnum.one", val.Value);
+ Assert.AreEqual ("one", val.DisplayValue);
+
+ val = Eval ("SomeEnum.two");
+ Assert.AreEqual ("SomeEnum.two", val.Value);
+ Assert.AreEqual ("two", val.DisplayValue);
+
+ val = Eval ("SomeEnum.one | SomeEnum.two");
+ Assert.AreEqual ("SomeEnum.one|SomeEnum.two", val.Value);
+ Assert.AreEqual ("one|two", val.DisplayValue);
+ }
+ }
+}
diff --git a/UnitTests/UnitTests/SdbEvaluationTests.cs b/UnitTests/UnitTests/SdbEvaluationTests.cs
new file mode 100644
index 0000000..ed26d34
--- /dev/null
+++ b/UnitTests/UnitTests/SdbEvaluationTests.cs
@@ -0,0 +1,48 @@
+//
+// SdbEvaluationTests.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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 NUnit.Framework;
+using Mono.Debugging.Client;
+using Mono.Debugging.Soft;
+using System.Collections.Generic;
+
+namespace Mono.Debugging.UnitTests
+{
+ [TestFixture()]
+ public class SdbEvaluationTests: EvaluationTests
+ {
+ protected override DebuggerSession CreateDebuggerSession ()
+ {
+ return new SoftDebuggerSession ();
+ }
+
+ protected override DebuggerStartInfo CreateDebuggerStartInfo ()
+ {
+ return new SoftDebuggerStartInfo (null, new Dictionary<string,string> ());
+ }
+ }
+}
diff --git a/UnitTests/UnitTests/SdbStackFrameTests.cs b/UnitTests/UnitTests/SdbStackFrameTests.cs
new file mode 100644
index 0000000..70b271b
--- /dev/null
+++ b/UnitTests/UnitTests/SdbStackFrameTests.cs
@@ -0,0 +1,49 @@
+//
+// SdbStackFrameTests.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2010 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 NUnit.Framework;
+using Mono.Debugging.Client;
+using Mono.Debugging.Soft;
+using System.Collections.Generic;
+
+namespace Mono.Debugging.UnitTests
+{
+ [TestFixture()]
+ public class SdbStackFrameTests: StackFrameTests
+ {
+ protected override DebuggerSession CreateDebuggerSession ()
+ {
+ return new SoftDebuggerSession ();
+ }
+
+ protected override DebuggerStartInfo CreateDebuggerStartInfo ()
+ {
+ return new SoftDebuggerStartInfo (null, new Dictionary<string,string> ());
+ }
+ }
+}
+
diff --git a/UnitTests/UnitTests/StackFrameTests.cs b/UnitTests/UnitTests/StackFrameTests.cs
new file mode 100644
index 0000000..59127a8
--- /dev/null
+++ b/UnitTests/UnitTests/StackFrameTests.cs
@@ -0,0 +1,122 @@
+//
+// StackFrameTests.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2010 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 Mono.Debugging.Client;
+using NUnit.Framework;
+
+namespace Mono.Debugging.UnitTests
+{
+ public abstract class StackFrameTests: DebugTests
+ {
+ DebuggerSession ds;
+ StackFrame frame;
+
+ [TestFixtureSetUp]
+ public void Setup ()
+ {
+ ds = Start ("TestEvaluation");
+ frame = ds.ActiveThread.Backtrace.GetFrame (0);
+ }
+
+ [TestFixtureTearDown]
+ public void TearDown ()
+ {
+ ds.Exit ();
+ ds.Dispose ();
+ }
+
+ public StackFrame Frame {
+ get { return frame; }
+ }
+
+ [Test]
+ public void VirtualProperty ()
+ {
+ EvaluationOptions ops = EvaluationOptions.DefaultOptions.Clone ();
+ ops.FlattenHierarchy = false;
+
+ ObjectValue val = Frame.GetExpressionValue ("c", ops);
+ Assert.IsNotNull (val);
+ val.WaitHandle.WaitOne ();
+ Assert.IsFalse (val.IsError);
+ Assert.IsFalse (val.IsUnknown);
+
+ // The C class does not have a Prop property
+
+ ObjectValue prop = val.GetChild ("Prop", ops);
+ Assert.IsNull (prop);
+
+ prop = val.GetChild ("PropNoVirt1", ops);
+ Assert.IsNull (prop);
+
+ prop = val.GetChild ("PropNoVirt2", ops);
+ Assert.IsNull (prop);
+
+ val = val.GetChild ("base", ops);
+ Assert.IsNotNull (val);
+ val.WaitHandle.WaitOne ();
+ Assert.IsFalse (val.IsError);
+ Assert.IsFalse (val.IsUnknown);
+
+ // The B class has a Prop property, value is 2
+
+ prop = val.GetChild ("Prop", ops);
+ Assert.IsNotNull (prop);
+ Assert.AreEqual ("2", prop.Value);
+
+ prop = val.GetChild ("PropNoVirt1", ops);
+ Assert.IsNotNull (prop);
+ Assert.AreEqual ("2", prop.Value);
+
+ prop = val.GetChild ("PropNoVirt2", ops);
+ Assert.IsNotNull (prop);
+ Assert.AreEqual ("2", prop.Value);
+
+ val = val.GetChild ("base", ops);
+ Assert.IsNotNull (val);
+ val.WaitHandle.WaitOne ();
+ Assert.IsFalse (val.IsError);
+ Assert.IsFalse (val.IsUnknown);
+
+ // The A class has a Prop property, value is 1, but must return 2 becasue it is overriden
+
+ prop = val.GetChild ("Prop", ops);
+ Assert.IsNotNull (prop);
+ Assert.AreEqual ("2", prop.Value);
+
+ prop = val.GetChild ("PropNoVirt1", ops);
+ Assert.IsNotNull (prop);
+ Assert.AreEqual ("1", prop.Value);
+
+ prop = val.GetChild ("PropNoVirt2", ops);
+ Assert.IsNotNull (prop);
+ Assert.AreEqual ("1", prop.Value);
+ }
+
+ }
+}
+
diff --git a/UnitTests/UnitTests/UnitTests.TestApp/Main.cs b/UnitTests/UnitTests/UnitTests.TestApp/Main.cs
new file mode 100644
index 0000000..8de7934
--- /dev/null
+++ b/UnitTests/UnitTests/UnitTests.TestApp/Main.cs
@@ -0,0 +1,179 @@
+//
+// Main.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis at novell.com>
+//
+// Copyright (c) 2009 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.Diagnostics;
+
+namespace UnitTests.TestApp
+{
+ class MainClass
+ {
+ public static void Main (string[] args)
+ {
+ MainClass mc = new MainClass ();
+ typeof (MainClass).GetMethod (args[0]).Invoke (mc, null);
+ }
+
+ // Tests
+
+ static string staticString = "some static";
+ string someString = "hi";
+ string[] numbers = new string[] { "one","two","three" };
+
+ public void TestEvaluation ()
+ {
+ int n = 32;
+ decimal dec = 123.456m;
+ ArrayList alist = new ArrayList ();
+ alist.Add (1);
+ alist.Add ("two");
+ alist.Add (3);
+
+ A c = new C ();
+ A b = new B ();
+ A a = new A ();
+
+ WithDisplayString withDisplayString = new WithDisplayString ();
+ WithProxy withProxy = new WithProxy ();
+ WithToString withToString = new WithToString ();
+
+ int[][] numbersArrays = new int [2][];
+ int[,,] numbersMulti = new int [3,4,5];
+
+ var dict = new Dictionary<int, string[]> ();
+ var dictArray = new Dictionary<int, string[]> [2,3];
+ var thing = new Thing<string> ();
+ var done = new Thing<string>.Done<int> ();
+
+ Console.WriteLine (n); Debugger.Break ();
+ }
+
+ public int TestMethod ()
+ {
+ float c = 4;
+ return 1;
+ }
+
+ public int TestMethod (string a)
+ {
+ return int.Parse (a) + 1;
+ }
+
+ public int TestMethod (int a)
+ {
+ return a + 1;
+ }
+
+ public static int TestMethod (bool b)
+ {
+ return b ? 1 : 2;
+ }
+
+ public string BoxingTestMethod (object a)
+ {
+ return a.ToString ();
+ }
+
+ public string EscapedStrings {
+ get { return " \" \\ \a \b \f \v \n \r \t"; }
+ }
+ }
+}
+
+class A
+{
+ public virtual int Prop { get { return 1; } }
+ public int PropNoVirt1 { get { return 1; } }
+ public virtual int PropNoVirt2 { get { return 1; } }
+}
+
+class B: A
+{
+ public override int Prop { get { return 2; } }
+ public new int PropNoVirt1 { get { return 2; } }
+ public new int PropNoVirt2 { get { return 2; } }
+}
+
+class C: B
+{
+}
+
+[DebuggerDisplay ("Some {Val1} Value {Val2} End")]
+class WithDisplayString
+{
+ internal string Val1 = "one";
+ public int Val2 { get { return 2; } }
+}
+
+class WithToString
+{
+ public override string ToString ()
+ {
+ return "SomeString";
+ }
+}
+
+[DebuggerTypeProxy (typeof(TheProxy))]
+class WithProxy
+{
+ public string Val1 {
+ get { return "one"; }
+ }
+}
+
+class TheProxy
+{
+ WithProxy wp;
+
+ public TheProxy (WithProxy wp)
+ {
+ this.wp = wp;
+ }
+
+ public string Val1 {
+ get { return wp.Val1; }
+ }
+}
+
+class Thing<T>
+{
+ public class Done<U>
+ {
+ }
+
+ public Done<int>[] done = new Done<int> [1];
+}
+
+[Flags]
+enum SomeEnum
+{
+ none=0,
+ one=1,
+ two=2,
+ four=4
+}
diff --git a/UnitTests/UnitTests/UnitTests.TestApp/Properties/AssemblyInfo.cs b/UnitTests/UnitTests/UnitTests.TestApp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c1fb439
--- /dev/null
+++ b/UnitTests/UnitTests/UnitTests.TestApp/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("UnitTests.TestApp")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Xamarin Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/UnitTests/UnitTests/UnitTests.TestApp/UnitTests.TestApp.csproj b/UnitTests/UnitTests/UnitTests.TestApp/UnitTests.TestApp.csproj
new file mode 100644
index 0000000..f3b415a
--- /dev/null
+++ b/UnitTests/UnitTests/UnitTests.TestApp/UnitTests.TestApp.csproj
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{19C3E201-4625-48B7-8E89-4ED9BA3BBD52}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>UnitTests.TestApp</RootNamespace>
+ <AssemblyName>UnitTests.TestApp</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Externalconsole>true</Externalconsole>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Externalconsole>true</Externalconsole>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Main.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file
diff --git a/UnitTests/UnitTests/UnitTests.csproj b/UnitTests/UnitTests/UnitTests.csproj
new file mode 100644
index 0000000..37be7da
--- /dev/null
+++ b/UnitTests/UnitTests/UnitTests.csproj
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{0349A5CF-1F90-4055-A3B2-BDAA347AED71}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>UnitTests</RootNamespace>
+ <AssemblyName>UnitTests</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="nunit.framework">
+ <Private>False</Private>
+ </Reference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Compile Include="DebugTests.cs" />
+ <Compile Include="EvaluationTests.cs" />
+ <Compile Include="SdbEvaluationTests.cs" />
+ <Compile Include="SdbStackFrameTests.cs" />
+ <Compile Include="StackFrameTests.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Mono.Debugging\Mono.Debugging.csproj">
+ <Project>{90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}</Project>
+ <Name>Mono.Debugging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Mono.Debugging.Soft\Mono.Debugging.Soft.csproj">
+ <Project>{DE40756E-57F6-4AF2-B155-55E3A88CCED8}</Project>
+ <Name>Mono.Debugging.Soft</Name>
+ </ProjectReference>
+ <ProjectReference Include="UnitTests.TestApp\UnitTests.TestApp.csproj">
+ <Project>{19C3E201-4625-48B7-8E89-4ED9BA3BBD52}</Project>
+ <Name>UnitTests.TestApp</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Mono.Debugger.Soft\Mono.Debugger.Soft.csproj">
+ <Project>{372E8E3E-29D5-4B4D-88A2-4711CD628C4E}</Project>
+ <Name>Mono.Debugger.Soft</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/debugger-libs.sln b/debugger-libs.sln
new file mode 100644
index 0000000..649b0e0
--- /dev/null
+++ b/debugger-libs.sln
@@ -0,0 +1,302 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugger.Soft", "Mono.Debugger.Soft\Mono.Debugger.Soft.csproj", "{372E8E3E-29D5-4B4D-88A2-4711CD628C4E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "..\cecil\Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "..\nrefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSharp", "..\nrefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj", "{53DCA265-3C3C-42F9-B647-F72BA678122B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugging", "Mono.Debugging\Mono.Debugging.csproj", "{90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Mdb", "..\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj", "{8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Debugging.Soft", "Mono.Debugging.Soft\Mono.Debugging.Soft.csproj", "{DE40756E-57F6-4AF2-B155-55E3A88CCED8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unit Tests", "Unit Tests", "{66CF303B-09F8-4123-B869-0608D54B1970}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests\UnitTests.csproj", "{0349A5CF-1F90-4055-A3B2-BDAA347AED71}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.TestApp", "UnitTests\UnitTests\UnitTests.TestApp\UnitTests.TestApp.csproj", "{19C3E201-4625-48B7-8E89-4ED9BA3BBD52}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ net_2_0_Debug|Any CPU = net_2_0_Debug|Any CPU
+ net_2_0_Release|Any CPU = net_2_0_Release|Any CPU
+ net_3_5_Debug|Any CPU = net_3_5_Debug|Any CPU
+ net_3_5_Release|Any CPU = net_3_5_Release|Any CPU
+ net_4_0_Debug|Any CPU = net_4_0_Debug|Any CPU
+ net_4_0_Release|Any CPU = net_4_0_Release|Any CPU
+ silverlight_Debug|Any CPU = silverlight_Debug|Any CPU
+ silverlight_Release|Any CPU = silverlight_Release|Any CPU
+ winphone_Debug|Any CPU = winphone_Debug|Any CPU
+ winphone_Release|Any CPU = winphone_Release|Any CPU
+ net_4_5_Debug|Any CPU = net_4_5_Debug|Any CPU
+ net_4_5_Release|Any CPU = net_4_5_Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.net_4_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.net_4_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.Release|Any CPU.Build.0 = Release|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.net_4_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {372E8E3E-29D5-4B4D-88A2-4711CD628C4E}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_5_Debug|Any CPU.ActiveCfg = net_4_5_Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_5_Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_5_Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.net_4_5_Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_5_Debug|Any CPU.ActiveCfg = net_4_5_Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_5_Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_5_Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.net_4_5_Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {53DCA265-3C3C-42F9-B647-F72BA678122B}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_5_Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_5_Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_5_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.net_4_5_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.silverlight_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {8559DD7F-A16F-46D0-A05A-9139FAEBA8FD}.winphone_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.net_4_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {90C99ADB-7D4B-4EB4-98C2-40BD1B14C7D2}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_2_0_Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Debug|Any CPU.Build.0 = net_3_5_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_3_5_Release|Any CPU.Build.0 = net_3_5_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_0_Release|Any CPU.Build.0 = net_4_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_5_Debug|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_5_Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_5_Release|Any CPU.ActiveCfg = net_2_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.net_4_5_Release|Any CPU.Build.0 = net_2_0_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_2_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_2_0_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Debug|Any CPU.ActiveCfg = silverlight_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Debug|Any CPU.Build.0 = silverlight_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Release|Any CPU.ActiveCfg = silverlight_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.silverlight_Release|Any CPU.Build.0 = silverlight_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.ActiveCfg = winphone_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Debug|Any CPU.Build.0 = winphone_Debug|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.ActiveCfg = winphone_Release|Any CPU
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.winphone_Release|Any CPU.Build.0 = winphone_Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_2_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_2_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_2_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_2_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_3_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_3_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_3_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_3_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_0_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_0_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_0_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_0_Release|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_5_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_5_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_5_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.net_4_5_Release|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.silverlight_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.silverlight_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.silverlight_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.silverlight_Release|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.winphone_Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.winphone_Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.winphone_Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE40756E-57F6-4AF2-B155-55E3A88CCED8}.winphone_Release|Any CPU.Build.0 = Debug|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {0349A5CF-1F90-4055-A3B2-BDAA347AED71} = {66CF303B-09F8-4123-B869-0608D54B1970}
+ {19C3E201-4625-48B7-8E89-4ED9BA3BBD52} = {66CF303B-09F8-4123-B869-0608D54B1970}
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = Mono.Debugger.Soft\Mono.Debugger.Soft.csproj
+ EndGlobalSection
+EndGlobal
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-cli-libs/packages/mono-debugger-libs.git
More information about the Pkg-cli-libs-commits
mailing list