Mono.Debugging

This commit is contained in:
Ivan Bondarev 2023-04-10 21:04:27 +02:00
parent 592ef8f783
commit f2faa957b7
104 changed files with 24678 additions and 0 deletions

View file

@ -0,0 +1,154 @@
// DissassemblyBuffer.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using 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);
}
}

View file

@ -0,0 +1,55 @@
//
// EvaluationResult.cs
//
// Author:
// Lluis Sanchez <lluis@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;
}
}
}

View file

@ -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);
}
}

View file

@ -0,0 +1,34 @@
//
// IDebuggerBackendObject.cs
//
// Author:
// Lluis Sanchez <lluis@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
{
}
}

View file

@ -0,0 +1,44 @@
// IDebuggerSession.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using 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 ();
}
}

View file

@ -0,0 +1,43 @@
// IObjectValueSource.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using 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);
}
}

View file

@ -0,0 +1,37 @@
// IObjectValueUpdateCallback.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using Mono.Debugging.Client;
namespace Mono.Debugging.Backend
{
internal interface IObjectValueUpdateCallback
{
void UpdateValue (ObjectValue newValue);
}
}

View file

@ -0,0 +1,37 @@
// IObjectValueUpdater.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using Mono.Debugging.Client;
namespace Mono.Debugging.Backend
{
public interface IObjectValueUpdater: IDebuggerBackendObject
{
void RegisterUpdateCallbacks (UpdateCallback[] callbacks);
}
}

View file

@ -0,0 +1,39 @@
//
// IRawValue.cs
//
// Author:
// Lluis Sanchez <lluis@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 CallMethod (string name, object[] parameters, out object[] outArgs, EvaluationOptions options);
object GetMemberValue (string name, EvaluationOptions options);
void SetMemberValue (string name, object value, EvaluationOptions options);
}
}

View file

@ -0,0 +1,40 @@
//
// IRawValueArray.cs
//
// Author:
// Lluis Sanchez <lluis@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 ();
}
}

View file

@ -0,0 +1,35 @@
//
// IRawValueString.cs
//
// Author:
// Lluis Sanchez <lluis@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.
namespace Mono.Debugging.Backend
{
public interface IRawValueString: IDebuggerBackendObject
{
string Substring (int index, int length);
string Value { get; }
int Length { get; }
}
}

View file

@ -0,0 +1,68 @@
// UpdateCallback.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using 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
}
}
}
}

View file

@ -0,0 +1,133 @@
//
// Assembly.cs
//
// Author:
// Jonathan Chang <t-jochang@microsoft.com>
//
// Copyright (c) 2022
//
// 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>
/// Represents the assembly loaded during the debugging session.
/// </summary>
public class Assembly
{
public Assembly (string name, string path, bool optimized, bool userCode, string symbolStatus, string symbolFile, int? order, string version, string timestamp, string address, string process, string appdomain, long? processId, bool hasSymbol = false, bool isDynamic = false)
{
Name = name;
Path = path;
Optimized = optimized;
SymbolStatus = symbolStatus;
SymbolFile = symbolFile;
Order = order.GetValueOrDefault (-1);
TimeStamp = timestamp;
Address = address;
Process = process;
AppDomain = appdomain;
Version = version;
UserCode = userCode;
ProcessId = processId;
IsDynamic = isDynamic;
HasSymbols = hasSymbol;
}
public Assembly (string path)
{
Path = path;
}
/// <summary>
/// Represents the name of the assembly.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Represents the local path of the assembly is loaded from.
/// </summary>
public string Path { get; private set; }
/// <summary>
/// Shows if the assembly has been optimized, true if the assembly is optimized.
/// </summary>
public bool Optimized { get; private set; }
/// <summary>
/// Shows if the assembly is considered 'user code' by a debugger that supports 'Just My Code'.True if it's considered.
/// </summary>
public bool UserCode { get; private set; }
/// <summary>
/// Represents the Description on if symbols were found for the assembly (ex: 'Symbols Loaded', 'Symbols not found', etc.
/// </summary>
public string SymbolStatus { get; private set; }
/// <summary>
/// Represents the Logical full path to the symbol file. The exact definition is implementation defined.
/// </summary>
public string SymbolFile { get; private set; }
/// <summary>
/// Represents the order in which the assembly was loaded.
/// </summary>
public int Order { get; private set; } = -1;
/// <summary>
/// Represents the version of assembly.
/// </summary>
public string Version { get; private set; }
/// <summary>
/// Represents the time when the assembly was built in the units of UNIX timestamp formatted as a 64-bit unsigned decimal number in a string.
/// </summary>
public string TimeStamp { get; private set; }
/// <summary>
/// Represents the Address where the assembly was loaded as a 64-bit unsigned decimal number.
/// </summary>
public string Address { get; private set; }
/// <summary>
/// Represent the process name and process ID the assembly is loaded.
/// </summary>
public string Process { get; private set; }
/// <summary>
/// Represent the name of the AppDomain where the assembly is loaded.
/// </summary>
public string AppDomain { get; private set; }
/// <summary>
/// Represent the process ID the assembly is loaded.
/// </summary>
public long? ProcessId { get; private set; } = -1;
/// <summary>
/// Indicates if the assembly has symbol file. Mainly use for mono project.
/// </summary>
public bool HasSymbols { get; private set; }
/// <summary>
/// Indicate if the assembly is a dynamic. Mainly use for mono project.
/// </summary>
public bool IsDynamic { get; private set; }
}
}

View file

@ -0,0 +1,53 @@
//
// AssemblyEventArg.cs
//
// Author:
// Matt Ward <matt.ward@microsoft.com>
//
// Copyright (c) 2018 Microsoft
//
// 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 AssemblyEventArgs : EventArgs
{
public AssemblyEventArgs (Assembly assembly)
{
Location = assembly.Path;
Assembly = assembly;
}
public AssemblyEventArgs (string location)
{
Location = location;
Assembly = new Assembly (location);
}
public string Location {
get; private set;
}
public Assembly Assembly {
get; private set;
}
}
}

View file

@ -0,0 +1,90 @@
// AssemblyLine.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace 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;
}
}
}

View file

@ -0,0 +1,76 @@
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 first frame, which is most used(for thread location)
if (count > 0)
GetFrame (0, 1);
}
internal void Attach (DebuggerSession debuggerSession)
{
session = debuggerSession;
serverBacktrace = session.WrapDebuggerObject (serverBacktrace);
if (frames != null) {
foreach (var frame in frames) {
frame.Attach (debuggerSession);
frame.SourceBacktrace = serverBacktrace;
}
}
}
public DebuggerSession DebuggerSession {
get { return session; }
}
public int FrameCount {
get { return count; }
}
public StackFrame GetFrame (int n)
{
return GetFrame (n, 20);
}
StackFrame GetFrame (int index, int fetchMultipleCount)
{
if (frames == null)
frames = new List<StackFrame>();
if (index >= frames.Count) {
var stackFrames = serverBacktrace.GetStackFrames (frames.Count, index + fetchMultipleCount);
foreach (var frame in stackFrames) {
frame.SourceBacktrace = serverBacktrace;
frame.Index = frames.Count;
frames.Add (frame);
frame.Attach (session);
}
}
if (frames.Count > 0)
return frames[Math.Min (Math.Max (0, index), frames.Count - 1)];
return null;
}
}
}

View file

@ -0,0 +1,398 @@
// BreakEvent.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Xml;
namespace Mono.Debugging.Client
{
[Serializable]
public class BreakEvent
{
bool breakIfConditionChanges;
string conditionExpression;
string lastConditionValue;
[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 baseDir)
{
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;
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 virtual XmlElement ToXml (XmlDocument doc, string baseDir)
{
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 ());
if (!string.IsNullOrEmpty (conditionExpression)) {
elem.SetAttribute ("conditionExpression", conditionExpression);
if (breakIfConditionChanges)
elem.SetAttribute ("breakIfConditionChanges", "True");
}
return elem;
}
internal static BreakEvent FromXml (XmlElement elem, string baseDir)
{
if (elem.Name == "FunctionBreakpoint")
return new FunctionBreakpoint (elem, baseDir);
if (elem.Name == "Breakpoint")
return new Breakpoint (elem, baseDir);
if (elem.Name == "Catchpoint")
return new Catchpoint (elem, baseDir);
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;
bool previous = enabled;
enabled = value;
if (store != null)
store.EnableBreakEvent (this, previous, 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;
}
}
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;
}
}
/// <summary>
/// NonUserBreakpoint is special kind of breakpoint that is not placed by user but by IDE/Add-In.
/// This breakpoint is usually used by AddIn to execute code on debugee at certain point in application execution.
/// IDE must hide this breakpoint from user. In breakpoints list and it must not stop execution(show breakpoint hit location).
/// WARNING: Code that adds this breakpoint must also make sure to call session.Continue(); when breakpoint is hit.
/// </summary>
public bool NonUserBreakpoint {
get;
set;
}
/// <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;
lastConditionValue = null;
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;
breakIfConditionChanges = ev.breakIfConditionChanges;
conditionExpression = ev.conditionExpression;
}
}
}

View file

@ -0,0 +1,43 @@
// BreakEventArgs.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Client
{
public class BreakEventArgs : EventArgs
{
public BreakEventArgs (BreakEvent be)
{
BreakEvent = be;
}
public BreakEvent BreakEvent {
get; private set;
}
}
}

View file

@ -0,0 +1,159 @@
//
// BreakEventInfo.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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; }
public Breakpoint Breakpoint { get; 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 ();
}
}
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)
{
var 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.OnTargetDebug (0, "", value + Environment.NewLine);
}
}
}
}

View file

@ -0,0 +1,57 @@
//
// BreakEventStatus.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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
}
}

View file

@ -0,0 +1,209 @@
// Breakpoint.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.IO;
using System.Xml;
namespace Mono.Debugging.Client
{
[Serializable]
public class Breakpoint: BreakEvent
{
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, string baseDir) : base (elem, baseDir)
{
string s = elem.GetAttribute ("relfile");
if (!string.IsNullOrEmpty (s) && baseDir != null) {
fileName = Path.Combine (baseDir, s);
} else {
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;
}
internal override XmlElement ToXml (XmlDocument doc, string baseDir)
{
XmlElement elem = base.ToXml (doc, baseDir);
if (!string.IsNullOrEmpty (fileName)) {
elem.SetAttribute ("file", fileName);
if (baseDir != null) {
if (fileName.StartsWith (baseDir, StringComparison.Ordinal))
elem.SetAttribute ("relfile", fileName.Substring (baseDir.Length).TrimStart (Path.DirectorySeparatorChar));
}
}
elem.SetAttribute ("line", line.ToString ());
elem.SetAttribute ("column", column.ToString ());
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 bool UpdatedByEnC { get; set; }
public void SetLine (int newLine)
{
ResetAdjustedLine ();
line = newLine;
}
internal void SetFileName (string newFileName)
{
fileName = newFileName;
}
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;
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 override void CopyFrom (BreakEvent ev)
{
base.CopyFrom (ev);
Breakpoint bp = (Breakpoint) ev;
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,
PrintTrace = 0x8
}
public delegate bool BreakEventHitHandler (string actionId, BreakEvent be);
}

View file

@ -0,0 +1,43 @@
// BreakpointEventArgs.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Client
{
public class BreakpointEventArgs : EventArgs
{
public BreakpointEventArgs (Breakpoint bp)
{
Breakpoint = bp;
}
public Breakpoint Breakpoint {
get; private set;
}
}
}

View file

@ -0,0 +1,687 @@
// BreakpointStore.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Collections.Concurrent;
namespace Mono.Debugging.Client
{
public sealed class BreakpointStore: ICollection<BreakEvent>
{
static readonly StringComparer PathComparer;
static readonly bool IsWindows;
static readonly bool IsMac;
readonly object breakpointLock = new object ();
List<BreakEvent> breakpoints = new List<BreakEvent>();
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 ()
{
var buf = IntPtr.Zero;
try {
buf = Marshal.AllocHGlobal (8192);
// This is a hacktastic way of getting sysname from uname ()
if (uname (buf) == 0) {
var os = Marshal.PtrToStringAnsi (buf);
if (os == "Darwin")
return true;
}
} catch {
} finally {
if (buf != IntPtr.Zero)
Marshal.FreeHGlobal (buf);
}
return false;
}
public int Count {
get {
return InternalGetBreakpoints().Count;
}
}
public bool IsReadOnly {
get {
var args = new ReadOnlyCheckEventArgs ();
CheckingReadOnly?.Invoke (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 (nameof (filename));
if (line < 1)
throw new ArgumentOutOfRangeException (nameof (line));
if (column < 1)
throw new ArgumentOutOfRangeException (nameof (column));
if (IsReadOnly)
return null;
var bp = new Breakpoint (filename, line, column);
Add (bp);
return bp;
}
void ICollection<BreakEvent>.Add (BreakEvent bp)
{
Add (bp);
}
public bool Add (BreakEvent be)
{
if (be == null)
throw new ArgumentNullException (nameof (be));
if (IsReadOnly)
return false;
if (be is Breakpoint bp) {
bp.SetFileName (ResolveFullPath(bp.FileName));
}
lock (breakpointLock) {
breakpoints.Add(be);
SetBreakpoints(breakpoints);
be.Store = this;
}
OnBreakEventAdded (be);
return true;
}
public Catchpoint AddCatchpoint (string exceptionName)
{
return AddCatchpoint (exceptionName, true);
}
public Catchpoint AddCatchpoint (string exceptionName, bool includeSubclasses)
{
if (exceptionName == null)
throw new ArgumentNullException (nameof (exceptionName));
if (IsReadOnly)
return null;
var cp = new Catchpoint (exceptionName, includeSubclasses);
Add (cp);
return cp;
}
public bool Remove (string filename, int line, int column)
{
if (filename == null)
throw new ArgumentNullException (nameof (filename));
if (IsReadOnly)
return false;
filename = Path.GetFullPath (filename);
var breakpointsToRemove = new List<BreakEvent> ();
foreach (var b in InternalGetBreakpoints ()) {
if (b is Breakpoint bp && FileNameEquals(bp.FileName, filename) &&
(bp.OriginalLine == line || bp.Line == line) &&
(bp.OriginalColumn == column || bp.Column == column)) {
breakpointsToRemove.Add (bp);
}
}
RemoveRange (breakpointsToRemove);
return true;
}
public bool RemoveCatchpoint (string exceptionName)
{
if (exceptionName == null)
throw new ArgumentNullException (nameof (exceptionName));
if (IsReadOnly)
return false;
var breakpointsToRemove = new List<BreakEvent> ();
foreach (var b in InternalGetBreakpoints ()) {
if (b is Catchpoint cp && cp.ExceptionName == exceptionName) {
breakpointsToRemove.Add (cp);
}
}
RemoveRange (breakpointsToRemove);
return true;
}
public void RemoveRunToCursorBreakpoints ()
{
if (IsReadOnly)
return;
var breakpointsToRemove = InternalGetBreakpoints ().OfType<RunToCursorBreakpoint> ().ToList ();
RemoveRange (breakpointsToRemove);
}
public bool Remove (BreakEvent bp)
{
if (bp == null)
throw new ArgumentNullException (nameof (bp));
if (!IsReadOnly) {
var wasRemoved = false;
lock (breakpointLock) {
if (breakpoints.Contains (bp)) {
breakpoints.Remove(bp);
SetBreakpoints(breakpoints);
wasRemoved = true;
}
}
if (wasRemoved) {
OnBreakEventRemoved (bp);
return true;
}
}
return false;
}
void RemoveRange (IEnumerable<BreakEvent> breakEvents)
{
List<BreakEvent> oldEvents;
if (!IsReadOnly) {
lock (breakpointLock) {
foreach (var b in breakEvents)
breakpoints.Remove(b);
oldEvents = SetBreakpoints(breakpoints);
}
List<BreakEvent> breakEventsRemoved = new List<BreakEvent> ();
foreach (var bp in breakEvents) {
if (oldEvents.Contains(bp)) {
breakEventsRemoved.Add (bp);
}
}
OnBreakEventsRemoved (breakEventsRemoved);
}
}
public Breakpoint Toggle (string filename, int line, int column)
{
if (filename == null)
throw new ArgumentNullException (nameof (filename));
if (line < 1)
throw new ArgumentOutOfRangeException (nameof (line));
if (column < 1)
throw new ArgumentOutOfRangeException (nameof (column));
if (IsReadOnly)
return null;
var 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 new ReadOnlyCollection<BreakEvent>(InternalGetBreakpoints ());
}
public ReadOnlyCollection<Breakpoint> GetBreakpoints ()
{
var list = new List<Breakpoint> ();
foreach (var bp in InternalGetBreakpoints ().OfType<Breakpoint> ()) {
if (!(bp is RunToCursorBreakpoint))
list.Add (bp);
}
return list.AsReadOnly ();
}
public ReadOnlyCollection<Catchpoint> GetCatchpoints ()
{
return InternalGetBreakpoints ().OfType<Catchpoint> ().ToList ().AsReadOnly ();
}
public ReadOnlyCollection<Breakpoint> GetBreakpointsAtFile (string filename)
{
if (filename == null)
throw new ArgumentNullException (nameof (filename));
var list = new List<Breakpoint> ();
if (string.IsNullOrEmpty (filename))
return list.AsReadOnly ();
try {
filename = Path.GetFullPath (filename);
} catch {
return list.AsReadOnly ();
}
foreach (var bp in InternalGetBreakpoints ().OfType<Breakpoint> ()) {
if (!(bp is RunToCursorBreakpoint) && FileNameEquals(bp.FileName, filename))
list.Add (bp);
}
return list.AsReadOnly ();
}
public ReadOnlyCollection<Breakpoint> GetBreakpointsAtFileLine (string filename, int line)
{
if (filename == null)
throw new ArgumentNullException (nameof (filename));
var list = new List<Breakpoint> ();
try {
filename = Path.GetFullPath (filename);
} catch {
return list.AsReadOnly ();
}
foreach (var bp in InternalGetBreakpoints ().OfType<Breakpoint> ()) {
if (!(bp is RunToCursorBreakpoint) && FileNameEquals(bp.FileName, filename) && (bp.OriginalLine == line || bp.Line == line))
list.Add (bp);
}
return list.AsReadOnly ();
}
public IEnumerator GetEnumerator ()
{
return ((IEnumerable)InternalGetBreakpoints()).GetEnumerator ();
}
IEnumerator<BreakEvent> IEnumerable<BreakEvent>.GetEnumerator ()
{
return ((IEnumerable<BreakEvent>)InternalGetBreakpoints ()).GetEnumerator ();
}
public void Clear ()
{
Clear (true);
}
public void Clear (bool clearNonUserBreakpoints)
{
var breakpointsToRemove = InternalGetBreakpoints ()
.Where (bp => clearNonUserBreakpoints || !bp.NonUserBreakpoint);
RemoveRange (breakpointsToRemove);
}
public void ClearBreakpoints ()
{
RemoveRange (GetBreakpoints ());
}
public void ClearCatchpoints ()
{
RemoveRange (GetCatchpoints ());
}
public bool Contains (BreakEvent item)
{
return InternalGetBreakpoints ().Contains (item);
}
public void CopyTo (BreakEvent[] array, int arrayIndex)
{
InternalGetBreakpoints ().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 ResetBreakpoints ()
{
if (IsReadOnly)
return;
foreach (var bp in InternalGetBreakpoints ()) {
if (bp.Reset ()) {
NotifyBreakEventChanged (bp);
}
}
}
public XmlElement Save (string baseDir = null)
{
XmlDocument doc = new XmlDocument ();
XmlElement elem = doc.CreateElement ("BreakpointStore");
foreach (BreakEvent ev in this) {
if (ev.NonUserBreakpoint)
continue;
XmlElement be = ev.ToXml (doc, baseDir);
elem.AppendChild (be);
}
return elem;
}
public void Load (XmlElement rootElem, string baseDir = null)
{
Clear ();
var loadedBreakpoints = new List<BreakEvent> ();
foreach (XmlNode n in rootElem.ChildNodes) {
XmlElement elem = n as XmlElement;
if (elem == null)
continue;
BreakEvent ev = BreakEvent.FromXml (elem, baseDir);
if (ev != null) {
loadedBreakpoints.Add (ev);
ev.Store = this;
}
}
lock (breakpointLock) {
SetBreakpoints (new List<BreakEvent> (loadedBreakpoints));
}
// preserve behaviour by sending an event for each breakpoint that was loaded
OnBreakEventsAdded (loadedBreakpoints);
}
[DllImport("libc")]
static extern string realpath(string path, IntPtr buffer);
/// <summary>
/// Resolves the full path of the given file
/// </summary>
/// <param name="path"></param>
/// <returns>The full path if a file is given, or returns the parameter if it is null or empty</returns>
static string ResolveFullPath (string path)
{
// If there is no path given, return the same path back
if (string.IsNullOrEmpty(path))
return path;
string result = null;
try {
result = realpath(path, IntPtr.Zero);
}
catch {
}
return string.IsNullOrEmpty(result) ? Path.GetFullPath(path) : result;
}
public static bool FileNameEquals (string file1, string file2)
{
if (file1 == null)
return file2 == null;
if (file2 == null)
return false;
return PathComparer.Compare (file1, file2) == 0;
}
internal bool EnableBreakEvent (BreakEvent be, bool previouslyEnabled, bool enabled)
{
if (IsReadOnly)
return false;
if (previouslyEnabled != enabled) {
OnChanged ();
BreakEventEnableStatusChanged?.Invoke (this, new BreakEventArgs (be));
NotifyStatusChanged (be);
}
return true;
}
void OnBreakEventAdded (BreakEvent be)
{
BreakEventAdded?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointAdded?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointAdded?.Invoke (this, new CatchpointEventArgs (ce));
}
OnChanged ();
}
void OnBreakEventsAdded (List<BreakEvent> bes)
{
foreach (BreakEvent be in bes) {
BreakEventAdded?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointAdded?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointAdded?.Invoke (this, new CatchpointEventArgs (ce));
}
}
OnChanged ();
}
void OnBreakEventRemoved (BreakEvent be)
{
BreakEventRemoved?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointRemoved?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointRemoved?.Invoke (this, new CatchpointEventArgs (ce));
}
OnChanged ();
}
void OnBreakEventsRemoved (List<BreakEvent> bes)
{
foreach (BreakEvent be in bes) {
BreakEventRemoved?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointRemoved?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointRemoved?.Invoke (this, new CatchpointEventArgs (ce));
}
}
OnChanged ();
}
void OnChanged ()
{
Changed?.Invoke (this, EventArgs.Empty);
}
internal void NotifyStatusChanged (BreakEvent be)
{
try {
BreakEventStatusChanged?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointStatusChanged?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointStatusChanged?.Invoke (this, new CatchpointEventArgs (ce));
}
} catch {
// Ignore
}
}
internal void NotifyBreakEventChanged (BreakEvent be)
{
try {
BreakEventModified?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointModified?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointModified?.Invoke (this, new CatchpointEventArgs (ce));
}
OnChanged ();
} catch {
// Ignore
}
}
internal void NotifyBreakEventUpdated (BreakEvent be)
{
try {
BreakEventUpdated?.Invoke (this, new BreakEventArgs (be));
if (be is Breakpoint bp) {
BreakpointUpdated?.Invoke (this, new BreakpointEventArgs (bp));
} else if (be is Catchpoint ce) {
CatchpointUpdated?.Invoke (this, new CatchpointEventArgs (ce));
}
} 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 void FileRenamed (string oldPath, string newPath)
{
if (IsReadOnly)
return;
foreach (var bp in GetBreakpointsAtFile (oldPath)) {
Remove (bp);
bp.SetFileName (newPath);
Add (bp);
}
}
List<BreakEvent> SetBreakpoints (List<BreakEvent> newBreakpoints)
{
System.Diagnostics.Debug.Assert (System.Threading.Monitor.IsEntered (breakpointLock), "SetBreakpoints must be called during a lock");
foreach (BreakEvent be in newBreakpoints) {
if (be is Breakpoint bp) {
bp.SetFileName (ResolveFullPath(bp.FileName));
}
}
var oldEvents = breakpoints;
breakpoints = newBreakpoints;
return oldEvents;
}
List<BreakEvent> InternalGetBreakpoints ()
{
lock (breakpointLock) {
return breakpoints;
}
}
}
public class ReadOnlyCheckEventArgs: EventArgs
{
internal bool IsReadOnly;
public void SetReadOnly (bool isReadOnly)
{
IsReadOnly = IsReadOnly || isReadOnly;
}
}
}

View file

@ -0,0 +1,126 @@
// Catchpoint.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using System.Linq;
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, string baseDir): base (elem, baseDir)
{
exceptionName = elem.GetAttribute ("exceptionName");
var str = elem.GetAttribute ("includeSubclasses");
if (string.IsNullOrEmpty (str) || !bool.TryParse (str, out includeSubclasses)) {
// fall back to the old default behavior
includeSubclasses = true;
}
foreach (var child in elem.ChildNodes.OfType<XmlElement>()) {
Ignored.Add (child.InnerText);
}
}
internal override XmlElement ToXml (XmlDocument doc, string baseDir)
{
var elem = base.ToXml (doc, baseDir);
elem.SetAttribute ("exceptionName", exceptionName);
elem.SetAttribute ("includeSubclasses", includeSubclasses.ToString ());
foreach (var item in Ignored.OrderBy(s => s)) {
var newChild = doc.CreateElement ("Ignore");
newChild.InnerText = item;
elem.AppendChild (newChild);
}
return elem;
}
public string ExceptionName {
get { return exceptionName; }
set { exceptionName = value; }
}
public bool IncludeSubclasses {
get { return includeSubclasses; }
set { includeSubclasses = value; }
}
/// <summary>
/// When an exception first happens, we are given the frame of the exception.
/// However by the time the user chooses "Ignore this location" in the exception dialog,
/// the current frame might be a different frame (the one with source code),
/// and not necessarily the bottom frame of the stack.
/// Make sure we remember the original frame where the exception happened
/// so that when it happens next time, we use the same frame signature to compare
/// against.
/// </summary>
public string CurrentLocationSignature { get; set; }
public HashSet<string> Ignored { get; private set; } = new HashSet<string> (StringComparer.Ordinal);
public bool ShouldIgnore(string type, string locationSignature)
{
return Ignored.Contains (type) || Ignored.Contains (locationSignature);
}
public override void CopyFrom (BreakEvent ev)
{
base.CopyFrom (ev);
var cp = (Catchpoint) ev;
exceptionName = cp.exceptionName;
includeSubclasses = cp.includeSubclasses;
Ignored = cp.Ignored;
}
public void AddIgnore (string ignore)
{
Ignored.Add (ignore);
}
public void RemoveIgnore (string ignore)
{
Ignored.Remove (ignore);
}
}
}

View file

@ -0,0 +1,43 @@
// CatchpointEventArgs.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Client
{
public class CatchpointEventArgs : EventArgs
{
public CatchpointEventArgs (Catchpoint cp)
{
Catchpoint = cp;
}
public Catchpoint Catchpoint {
get; private set;
}
}
}

View file

@ -0,0 +1,77 @@
// CompletionData.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
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;
}
}
}
}

View file

@ -0,0 +1,47 @@
//
// DebuggerException.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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)
{
}
}
}

View file

@ -0,0 +1,47 @@
// DebuggerFeatures.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace 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
}
}

View file

@ -0,0 +1,76 @@
//
// DebuggerLoggingService.cs
//
// Author:
// Michael Hutchinson <mhutchinson@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);
/// <summary>
/// Gets the new debugger log filename. It may return null which means disable logging.
/// </summary>
/// <returns>The new debugger log filename or null.</returns>
string GetNewDebuggerLogFilename ();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
//
// DebuggerSessionOptions.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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;
namespace Mono.Debugging.Client
{
[Serializable]
public enum AutomaticSourceDownload
{
Ask,
Always,
Never
}
[Serializable]
public class DebuggerSessionOptions
{
public EvaluationOptions EvaluationOptions { get; set; }
public bool StepOverPropertiesAndOperators { get; set; }
public bool ProjectAssembliesOnly { get; set; }
public AutomaticSourceDownload AutomaticSourceLinkDownload { get; set; }
public bool DebugSubprocesses { get; set; }
public List<SymbolSource> SymbolSearchPaths { get; set; } = new List<SymbolSource>();
public bool SearchMicrosoftSymbolServer { get; set; }
public bool SearchNuGetSymbolServer { get; set; }
}
[Serializable]
public class SymbolSource
{
public SymbolSource ()
{
// For deserialization
}
public SymbolSource (string path, string name, bool isEnabled)
{
Path = path;
Name = name;
IsEnabled = isEnabled;
}
public string Name { get; set; }
public string Path { get; set; }
public bool IsEnabled { get; set; }
}
}

View file

@ -0,0 +1,92 @@
// DebuggerStartInfo.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
namespace Mono.Debugging.Client
{
[Serializable]
public class DebuggerStartInfo
{
string command;
string arguments;
string runtimeArguments;
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 RuntimeArguments {
get {
return runtimeArguments;
}
set {
runtimeArguments = 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; }
public bool RequiresManualStart { get; set; }
}
}

View file

@ -0,0 +1,201 @@
//
// DebuggerStatistics.cs
//
// Author:
// Jeffrey Stedfast <jestedfa@microsoft.com>
//
// Copyright (c) 2019 Microsoft Corp.
//
// 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.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Mono.Debugging.Client
{
public class DebuggerStatistics
{
static readonly int[] UpperTimeLimits = { 10, 50, 100, 250, 500, 1000, 1500, 2000, 5000, 10000 };
readonly int[] buckets = new int[UpperTimeLimits.Length + 1];
readonly object mutex = new object ();
TimeSpan minTime = TimeSpan.MaxValue;
TimeSpan maxTime, totalTime;
public DebuggerStatistics(string name)
{
Name = name;
}
public double MaxTime {
get { return maxTime.TotalMilliseconds; }
}
public double MinTime {
get { return minTime.TotalMilliseconds; }
}
public double AverageTime {
get {
if (TimingsCount > 0)
return totalTime.TotalMilliseconds / TimingsCount;
return 0;
}
}
public int TimingsCount { get; private set; }
public int FailureCount { get; private set; }
public string Name { get; }
public DebuggerTimer StartTimer (string name)
{
return new DebuggerTimer (this, name);
}
int GetBucketIndex (TimeSpan duration)
{
var ms = (long) duration.TotalMilliseconds;
for (var bucket = 0; bucket < UpperTimeLimits.Length; bucket++) {
if (ms <= UpperTimeLimits[bucket])
return bucket;
}
return buckets.Length - 1;
}
public void AddTime (TimeSpan duration)
{
lock (mutex) {
if (duration > maxTime)
maxTime = duration;
if (duration < minTime)
minTime = duration;
buckets[GetBucketIndex (duration)]++;
totalTime += duration;
TimingsCount++;
}
}
public void IncrementFailureCount ()
{
lock (mutex) {
FailureCount++;
}
}
public void Serialize (Dictionary<string, object> metadata)
{
metadata["AverageDuration"] = AverageTime;
metadata["MaximumDuration"] = MaxTime;
metadata["MinimumDuration"] = MinTime;
metadata["FailureCount"] = FailureCount;
metadata["SuccessCount"] = TimingsCount;
for (int i = 0; i < buckets.Length; i++)
metadata[$"Bucket{i}"] = buckets[i];
}
}
public class DebuggerTimer : IDisposable
{
readonly DebuggerStatistics stats;
readonly Stopwatch stopwatch;
static readonly TraceListener traceListener = new TraceSource (nameof (DebuggerTimer)).Listeners.OfType<TraceListener> ().FirstOrDefault (l => l.Name == nameof (DebuggerTimer));
static int traceSeq = 0;
int traceId;
public DebuggerTimer (DebuggerStatistics stats, string name)
{
stopwatch = Stopwatch.StartNew ();
this.stats = stats;
if (stats != null && traceListener != null) {
traceId = Interlocked.Increment (ref traceSeq);
traceListener.TraceEvent (null, stats.Name, TraceEventType.Start, traceId, name);
}
}
/// <summary>
/// Indicates if the debugger operation was successful. If this is false the
/// timing will not be reported and a failure will be indicated.
/// </summary>
public bool Success { get; set; }
public TimeSpan Elapsed {
get { return stopwatch.Elapsed; }
}
public void Stop (bool success)
{
stopwatch.Stop ();
Success = success;
if (stats == null)
return;
traceListener?.TraceEvent (null, stats.Name, TraceEventType.Stop, traceId, "Stop1");
if (success)
stats.AddTime (stopwatch.Elapsed);
else
stats.IncrementFailureCount ();
}
public void Stop (ObjectValue val)
{
stopwatch.Stop ();
if (stats == null)
return;
traceListener?.TraceEvent (null, stats.Name, TraceEventType.Stop, traceId, "Stop2");
if (val.IsEvaluating || val.IsEvaluatingGroup) {
// Do not capture timing - evaluation not finished.
} else if (val.IsError || val.IsImplicitNotSupported || val.IsNotSupported || val.IsUnknown) {
stats.IncrementFailureCount ();
} else {
// Success
stats.AddTime (stopwatch.Elapsed);
}
}
public void Dispose ()
{
if (stopwatch.IsRunning) {
stopwatch.Stop ();
if (stats == null)
return;
traceListener?.TraceEvent (null, stats.Name, TraceEventType.Stop, traceId, "Dispose");
if (Success)
stats.AddTime (stopwatch.Elapsed);
else
stats.IncrementFailureCount ();
}
}
}
}

View file

@ -0,0 +1,149 @@
//
// EvaluationOptions.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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 const 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.UseExternalTypeResolver = true;
ops.IntegerDisplayFormat = IntegerDisplayFormat.Decimal;
ops.CurrentExceptionTag = "$exception";
ops.EllipsizeStrings = true;
ops.EllipsizedLength = 100;
ops.ChunkRawStrings = false;
ops.StackFrameFormat = new StackFrameFormat ();
return ops;
}
}
public EvaluationOptions Clone ()
{
var clone = (EvaluationOptions)MemberwiseClone ();
clone.StackFrameFormat = new StackFrameFormat (StackFrameFormat);
return clone;
}
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; }
public bool GroupStaticMembers { get; set; }
public bool UseExternalTypeResolver { get; set; }
public IntegerDisplayFormat IntegerDisplayFormat { get; set; }
public string CurrentExceptionTag { get; set; }
public bool IEnumerable { get; set; }
public StackFrameFormat StackFrameFormat { get; set; }
}
public class StackFrameFormat
{
public bool Line { get; set; } = true;
public bool Module { get; set; } = false;
public bool ParameterNames { get; set; } = true;
public bool ParameterTypes { get; set; } = true;
public bool ParameterValues { get; set; } = false;
/// <summary>
/// Default is null. Which means do same as "ProjectAssembliesOnly" setting.
/// </summary>
public bool? ExternalCode { get; set; } = null;
public StackFrameFormat ()
{
}
public StackFrameFormat (StackFrameFormat copy)
{
Line = copy.Line;
Module = copy.Module;
ParameterNames = copy.ParameterNames;
ParameterTypes = copy.ParameterTypes;
ParameterValues = copy.ParameterValues;
ExternalCode = copy.ExternalCode;
}
}
public enum IntegerDisplayFormat
{
Decimal,
Hexadecimal
}
}

View file

@ -0,0 +1,320 @@
//
// ExceptionInfo.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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;
[NonSerialized]
ObjectValue instance;
/// <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
/// Column: 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;
}
}
ObjectValue helpLinkObject;
public string HelpLink {
get {
if (helpLinkObject == null) {
helpLinkObject = exception.GetChild ("HelpLink");
if (helpLinkObject != null && helpLinkObject.IsEvaluating) {
helpLinkObject.ValueChanged += delegate {
NotifyChanged ();
};
}
}
return helpLinkObject != null ? helpLinkObject.Value : null;
}
}
public ObjectValue Instance {
get {
if (instance == null)
instance = exception.GetChild ("Instance");
if (instance == null)
return exception;
return 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;
return false;
}
}
public ExceptionStackFrame[] StackTrace {
get {
if (frames != null)
return frames;
var stackTrace = exception.GetChild ("StackTrace");
if (stackTrace == null || stackTrace.IsNull)
return frames = new ExceptionStackFrame [0];
if (stackTrace.IsEvaluating) {
frames = new ExceptionStackFrame [0];
stackTrace.ValueChanged += HandleExceptionValueChanged;
return frames;
}
if (stackTrace.TypeName == "string") {
stackTrace = Debugging.Evaluation.ExceptionInfoSource.GetStackTrace (stackTrace.Value);
}
if (!stackTrace.IsArray) {
return frames = new ExceptionStackFrame [0];
}
var list = new List<ExceptionStackFrame> ();
for (int i = 0; i < stackTrace.ArrayCount; i++)
list.Add (new ExceptionStackFrame (stackTrace.GetArrayItem (i, EvaluationOptions.DefaultOptions)));
frames = list.ToArray ();
return frames;
}
}
public ExceptionInfo InnerException {
get {
if (innerException == null) {
ObjectValue innerVal = exception.GetChild ("InnerException");
if (innerVal == null || innerVal.IsNull || 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;
}
}
List<ExceptionInfo> innerExceptions;
public List<ExceptionInfo> InnerExceptions {
get {
if (innerExceptions == null) {
ObjectValue innerVal = exception.GetChild ("InnerExceptions");
if (innerVal == null || innerVal.IsError || innerVal.IsUnknown)
return null;
if (innerVal.IsEvaluating) {
innerVal.ValueChanged += delegate { NotifyChanged (); };
return null;
}
innerExceptions = new List<ExceptionInfo> ();
foreach (var inner in innerVal.GetAllChildren ()) {
var innerObj = new ExceptionInfo (inner);
innerObj.Changed += delegate {
NotifyChanged ();
};
innerExceptions.Add (innerObj);
}
}
return innerExceptions;
}
}
public event EventHandler Changed;
internal void ConnectCallback (StackFrame parentFrame)
{
ObjectValue.ConnectCallbacks (parentFrame, exception);
}
public override string ToString ()
{
var sb = new StringBuilder ();
var chain = new List<ExceptionInfo> ();
var 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 frame in ex.StackTrace) {
sb.Append (" at ").Append (frame.DisplayText);
if (!string.IsNullOrEmpty (frame.File)) {
sb.Append (" in ").Append (frame.File).Append (':').Append (frame.Line);
if (frame.Column != 0)
sb.Append (',').Append (frame.Column);
}
sb.AppendLine ();
}
}
return sb.ToString ();
}
}
public class ExceptionStackFrame
{
readonly 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 "Column" member must be the column.
/// </summary>
public ExceptionStackFrame (ObjectValue value)
{
frame = value;
}
public string File {
get {
var file = frame.GetChild ("File", EvaluationOptions.DefaultOptions);
if (file != null)
return file.Value;
return null;
}
}
public int Line {
get {
var val = frame.GetChild ("Line", EvaluationOptions.DefaultOptions);
if (val != null)
return int.Parse (val.Value);
return 0;
}
}
public int Column {
get {
var val = frame.GetChild ("Column", EvaluationOptions.DefaultOptions);
if (val != null)
return int.Parse (val.Value);
return 0;
}
}
public string DisplayText {
get { return frame.Value; }
}
}
}

View file

@ -0,0 +1,233 @@
//
// FunctionBreakpoint.cs
//
// Author: Jeffrey Stedfast <jeff@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)
{
Language = language;
ParseTypeAndMethodName (functionName);
}
private void ParseTypeAndMethodName (string functionName)
{
FunctionName = functionName;
var bracket = functionName.IndexOf ('(');
int dot;
if (bracket != -1) {
//Handle stuff like SomeNamespace.SomeType.Method(SomeOtherNamespace.SomeOtherType)
dot = functionName.LastIndexOf('.', bracket);
} else {
dot = functionName.LastIndexOf('.');
}
if (dot == -1 || dot + 1 == functionName.Length)
return;
// FIXME: handle types like GenericType<>, GenericType<SomeOtherType>, and GenericType<...>+NestedGenricType<...>
string methodName;
string typeName = functionName.Substring (0, dot);
if (bracket == -1) {
methodName = functionName.Substring (dot + 1);
} else {
methodName = functionName.Substring (dot + 1, bracket - (dot + 1));
}
TypeName = typeName;
MethodName = methodName;
}
public FunctionBreakpoint (string typeName, string methodName, string language) : base (null, 1, 1)
{
Language = language;
TypeName = typeName;
MethodName = methodName;
FunctionName = TypeName + "." + MethodName;
}
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, string baseDir) : base (elem, baseDir)
{
var functionName = elem.GetAttribute ("function");
ParseTypeAndMethodName (functionName);
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, string baseDir)
{
XmlElement elem = base.ToXml (doc, baseDir);
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 TypeName {
get; set;
}
public string MethodName {
get; set;
}
public string Language {
get; set;
}
public string[] ParamTypes {
get; set;
}
public override void CopyFrom (BreakEvent ev)
{
base.CopyFrom (ev);
var bp = (FunctionBreakpoint) ev;
FunctionName = bp.FunctionName;
MethodName = bp.MethodName;
TypeName = bp.TypeName;
ParamTypes = bp.ParamTypes;
}
}
}

View file

@ -0,0 +1,36 @@
//
// IExpressionEvaluator.cs
//
// Author:
// Carlo kok <ck@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 Mono.Debugging.Evaluation;
namespace Mono.Debugging.Client
{
public interface IExpressionEvaluator
{
ExpressionEvaluator Evaluator { get; }
ObjectValue[] GetLocals (StackFrame sf);
}
}

View file

@ -0,0 +1,101 @@
// ObjectPath.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections;
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;
return new string [0];
}
public ObjectPath GetSubpath (int start)
{
if (start == 0)
return this;
var newPath = new string [path.Length - start];
Array.Copy (path, start, newPath, 0, newPath.Length);
return new ObjectPath (newPath);
}
public ObjectPath Append (string name)
{
var 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 "";
return path[path.Length - 1];
}
}
public string Join (string separator)
{
return string.Join (separator, path);
}
public override string ToString ()
{
return Join ("/");
}
}
}

View file

@ -0,0 +1,882 @@
// ObjectValue.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using Mono.Debugging.Backend;
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]
readonly object mutex = new object ();
[NonSerialized]
UpdateCallback updateCallback;
[NonSerialized]
EventHandler valueChanged;
[NonSerialized]
StackFrame parentFrame;
static ObjectValue Create (IObjectValueSource source, ObjectPath path, string typeName)
{
var val = new ObjectValue ();
val.typeName = typeName;
val.source = source;
val.path = path;
return val;
}
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)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.Object;
val.displayValue = value.DisplayValue;
val.value = value.Value;
if (children != null) {
val.children = new List<ObjectValue> ();
val.children.AddRange (children);
}
return val;
}
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)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.Object;
val.value = "(null)";
val.isNull = true;
return val;
}
public static ObjectValue CreatePrimitive (IObjectValueSource source, ObjectPath path, string typeName, EvaluationResult value, ObjectValueFlags flags)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.Primitive;
val.displayValue = value.DisplayValue;
val.value = value.Value;
return val;
}
public static ObjectValue CreateArray (IObjectValueSource source, ObjectPath path, string typeName, int arrayCount, ObjectValueFlags flags, ObjectValue[] children)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.Array;
val.value = "[" + arrayCount + "]";
val.arrayCount = arrayCount;
if (children != null && children.Length > 0) {
val.children = new List<ObjectValue> ();
val.children.AddRange (children);
}
return val;
}
public static ObjectValue CreateUnknown (IObjectValueSource source, ObjectPath path, string typeName)
{
var val = Create (source, path, typeName);
val.flags = ObjectValueFlags.Unknown | ObjectValueFlags.ReadOnly;
return val;
}
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)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.Error;
val.value = value;
return val;
}
public static ObjectValue CreateImplicitNotSupported (IObjectValueSource source, ObjectPath path, string typeName, ObjectValueFlags flags)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.ImplicitNotSupported;
val.value = "Implicit evaluation is disabled";
return val;
}
public static ObjectValue CreateNotSupported (IObjectValueSource source, ObjectPath path, string typeName, string message, ObjectValueFlags flags)
{
var val = Create (source, path, typeName);
val.flags = flags | ObjectValueFlags.NotSupported;
val.value = message;
return val;
}
public static ObjectValue CreateFatalError (string name, string message, ObjectValueFlags flags)
{
var val = new ObjectValue ();
val.flags = flags | ObjectValueFlags.Error;
val.value = message;
val.name = name;
return val;
}
public static ObjectValue CreateEvaluating (IObjectValueUpdater updater, ObjectPath path, ObjectValueFlags flags)
{
var val = Create (null, path, null);
val.flags = flags | ObjectValueFlags.Evaluating;
val.updater = updater;
return val;
}
public static ObjectValue CreateShowMore ()
{
return new ObjectValue () {
flags = ObjectValueFlags.IEnumerable,
name = ""
};
}
public DebuggerSession DebuggerSession {
get {
return parentFrame?.DebuggerSession;
}
}
/// <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 { return name ?? path[path.Length - 1]; }
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");
var 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");
var 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 ()
{
var 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)
{
if (source == null && (IsEvaluating || IsEvaluatingGroup)) {
if (!WaitHandle.WaitOne (options.EvaluationTimeout)) {
throw new Evaluation.TimeOutException ();
}
}
var res = source.GetRawValue (path, options);
if (res is IRawObject raw)
raw.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)
{
if (source == null && (IsEvaluating || IsEvaluatingGroup)) {
if (!WaitHandle.WaitOne (options.EvaluationTimeout)) {
throw new Evaluation.TimeOutException ();
}
}
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 {
var 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 (var child in children) {
if (child.Name == name)
return child;
}
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 {
var 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 ();
}
public ObjectValue[] GetRangeOfChildren (int index, int count)
{
return GetRangeOfChildren (index, count, parentFrame.DebuggerSession.EvaluationOptions);
}
public ObjectValue[] GetRangeOfChildren (int index, int count, EvaluationOptions options)
{
if (IsEvaluating)
return new ObjectValue[0];
if (IsArray) {
GetArrayItem (arrayCount - 1);
if (index >= ArrayCount)
return new ObjectValue[0];
return children.Skip (index).Take (Math.Min (count, ArrayCount - index)).ToArray ();
}
if (children == null) {
children = new List<ObjectValue> ();
}
if (children.Count < index + count) {
if (source != null) {
try {
ObjectValue[] cs = source.GetChildren (path, children.Count, index + count, 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));
}
}
}
if (index >= children.Count)
return new ObjectValue[0];
return children.Skip (index).Take (Math.Min (count, children.Count - index)).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 {
var 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 IsNull {
get { return isNull; }
}
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 IsImplicitNotSupported {
get { return HasFlag (ObjectValueFlags.ImplicitNotSupported); }
}
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 (mutex) {
valueChanged += value;
if (!IsEvaluating)
value (this, EventArgs.Empty);
}
}
remove {
lock (mutex) {
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;
var val = source.GetValue (path, options);
UpdateFrom (val, true);
}
/// <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 (mutex) {
if (evaluatedEvent == null)
evaluatedEvent = new ManualResetEvent (!IsEvaluating);
return evaluatedEvent;
}
}
}
internal IObjectValueUpdater Updater {
get { return updater; }
}
internal void UpdateFrom (ObjectValue val, bool notify)
{
lock (mutex) {
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 !NETCOREAPP
if (updateCallback != null)
System.Runtime.Remoting.RemotingServices.Disconnect ((UpdateCallbackProxy)updateCallback.Callback);
#endif
}
internal static void ConnectCallbacks (StackFrame parentFrame, params ObjectValue[] values)
{
Dictionary<IObjectValueUpdater, List<UpdateCallback>> callbacks = null;
var valueList = new List<ObjectValue> (values);
for (int n = 0; n < valueList.Count; n++) {
var val = valueList [n];
val.source = parentFrame.DebuggerSession.WrapDebuggerObject (val.source);
val.updater = parentFrame.DebuggerSession.WrapDebuggerObject (val.updater);
val.parentFrame = parentFrame;
var 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)
{
var val = valRef.Target as ObjectValue;
if (val != null)
val.UpdateFrom (newValue, true);
}
public UpdateCallbackProxy (ObjectValue val)
{
valRef = new WeakReference (val);
}
}
}

View file

@ -0,0 +1,73 @@
// ObjectValueKind.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace 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.
ImplicitNotSupported = 1 << 7, // The expression is valid but it can't be performed implicitly.
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
IEnumerable = 1 << 22,
// For field and property
Public = 1 << 24,
Protected = 1 << 25,
Internal = 1 << 26,
Private = 1 << 27,
InternalProtected = Internal | Protected,
AccessMask = Public | Protected | Internal | Private
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mono.Debugging.Client
{
[Serializable]
public class OutputOptions
{
public bool ModuleLoaded { get; set; }
public bool ModuleUnoaded { get; set; }
public bool ExceptionMessage { get; set; }
public bool SymbolSearch { get; set; }
public bool ThreadExited { get; set; }
public bool ProcessExited { get; set; }
}
}

View file

@ -0,0 +1,43 @@
// ProcessEventArgs.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Client
{
public class ProcessEventArgs : EventArgs
{
public ProcessEventArgs (int processId)
{
ProcessId = processId;
}
public int ProcessId {
get; private set;
}
}
}

View file

@ -0,0 +1,90 @@
// ProcessInfo.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Client
{
[Serializable]
public class ProcessInfo
{
long id;
string name;
string description;
[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 Description {
get {
return description;
}
}
public ProcessInfo (string name, string description)
{
this.name = name;
this.description = description;
}
public ProcessInfo (long id, string name)
{
this.id = id;
this.name = name;
}
public ThreadInfo[] GetThreads ()
{
return session.GetThreads (id);
}
/// <summary>
/// Gets assemblies from the debugger session that matches the process ID.
/// </summary>
public Assembly[] GetAssemblies ()
{
return session.GetAssemblies (id);
}
}
}

View file

@ -0,0 +1,311 @@
//
// RawValue.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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;
DebuggerSession session;
/// <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;
this.session = session;
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;
IRawObject raw = res as IRawObject;
if (raw != null)
raw.Connect (session, options);
return res;
}
public object CallMethod (string methodName, out object [] outArgs, params object [] parameters)
{
object res = source.CallMethod (methodName, parameters, out outArgs, options);
RawValue val = res as RawValue;
if (val != null)
val.options = options;
IRawObject raw = res as IRawObject;
if (raw != null)
raw.Connect (session, 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;
IRawObject raw = res as IRawObject;
if (raw != null)
raw.Connect (session, 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;
EvaluationOptions options;
DebuggerSession session;
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)
{
this.options = options;
this.session = session;
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 ()
{
var array = source.ToArray ();
for (int i = 0; i < array.Length; i++) {
var val = array.GetValue (i) as IRawObject;
if (val != null) {
val.Connect (session, options);
}
}
return array;
}
/// <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 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; }
}
}
interface IRawObject
{
void Connect (DebuggerSession session, EvaluationOptions options);
}
}

View file

@ -0,0 +1,34 @@
//
// RunToCursorBreakpoint.cs
//
// Author: Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2014 Xamarin Inc. (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.
namespace Mono.Debugging.Client
{
public sealed class RunToCursorBreakpoint : Breakpoint
{
public RunToCursorBreakpoint (string fileName, int line, int column) : base (fileName, line, column)
{
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.IO;
namespace Mono.Debugging.Client
{
[Serializable]
public class SourceLink
{
public string Uri { get; }
public string RelativeFilePath { get; }
public SourceLink (string uri, string relativeFilePath)
{
RelativeFilePath = relativeFilePath;
Uri = uri;
}
public string GetDownloadLocation (string cachePath)
{
var uri = new Uri (Uri);
return Path.Combine (cachePath, uri.Host + uri.PathAndQuery);
}
}
}

View file

@ -0,0 +1,190 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Security.Cryptography;
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 int EndLine { get; private set; }
public int EndColumn { get; private set; }
public byte[] FileHash { get; private set; }
public SourceLink SourceLink { get; private set; }
[Obsolete]
public SourceLocation (string methodName, string fileName, int line)
: this (methodName, fileName, line, -1, -1, -1, null)
{
}
public SourceLocation (string methodName, string fileName, int line, int column, int endLine, int endColumn)
: this (methodName, fileName, line, column, endLine, endColumn, null, null)
{
}
public SourceLocation (string methodName, string fileName, int line, int column, int endLine, int endColumn, byte [] hash = null)
: this (methodName, fileName, line, column, endLine, endColumn, hash, null)
{
}
public SourceLocation (string methodName, string fileName, int line, int column, int endLine, int endColumn, byte[] hash = null, SourceLink sourceLink = null)
{
this.MethodName = methodName;
this.FileName = fileName;
this.Line = line;
this.Column = column;
this.EndLine = endLine;
this.EndColumn = endColumn;
this.FileHash = hash;
this.SourceLink = sourceLink;
}
public override string ToString ()
{
return string.Format("[SourceLocation Method={0}, Filename={1}, Line={2}, Column={3}]", MethodName, FileName, Line, Column);
}
static void ComputeHashes (Stream stream, HashAlgorithm hash, HashAlgorithm dos, HashAlgorithm unix)
{
var unixBuffer = new byte[4096 + 1];
var dosBuffer = new byte[8192 + 1];
var buffer = new byte[4096];
byte pc = 0;
int count;
try {
while ((count = stream.Read (buffer, 0, buffer.Length)) > 0) {
int unixIndex = 0, dosIndex = 0;
for (int i = 0; i < count; i++) {
var c = buffer[i];
if (c == (byte) '\r') {
if (pc == (byte) '\r')
unixBuffer[unixIndex++] = pc;
dosBuffer[dosIndex++] = c;
} else if (c == (byte) '\n') {
if (pc != (byte) '\r')
dosBuffer[dosIndex++] = (byte) '\r';
unixBuffer[unixIndex++] = c;
dosBuffer[dosIndex++] = c;
} else {
if (pc == (byte) '\r')
unixBuffer[unixIndex++] = pc;
unixBuffer[unixIndex++] = c;
dosBuffer[dosIndex++] = c;
}
pc = c;
}
hash.TransformBlock (buffer, 0, count, outputBuffer: null, outputOffset: 0);
dos.TransformBlock (dosBuffer, 0, dosIndex, outputBuffer: null, outputOffset: 0);
unix.TransformBlock (unixBuffer, 0, unixIndex, outputBuffer: null, outputOffset: 0);
}
hash.TransformFinalBlock (buffer, 0, 0);
dos.TransformFinalBlock (buffer, 0, 0);
unix.TransformFinalBlock (buffer, 0, 0);
} finally {
}
}
public static List<byte[]> ComputeChecksums (string path, string algorithm)
{
using (var stream = File.OpenRead (path)) {
using (var hash = HashAlgorithm.Create (algorithm)) {
using (var dos = HashAlgorithm.Create (algorithm)) {
using (var unix = HashAlgorithm.Create (algorithm)) {
ComputeHashes (stream, hash, dos, unix);
var checksums = new List<byte[]> (3);
checksums.Add (hash.Hash);
checksums.Add (dos.Hash);
checksums.Add (unix.Hash);
return checksums;
}
}
}
}
}
static bool ChecksumsEqual (byte[] calculated, byte[] checksum, int skip = 0)
{
if (skip > 0) {
if (calculated.Length < checksum.Length - skip)
return false;
} else {
if (calculated.Length != checksum.Length)
return false;
}
for (int i = 0, csi = skip; csi < checksum.Length; i++, csi++) {
if (calculated[i] != checksum[csi])
return false;
}
return true;
}
static bool CheckHash (Stream stream, string algorithm, byte[] checksum)
{
using (var hash = HashAlgorithm.Create (algorithm)) {
int size = hash.HashSize / 8;
using (var dos = HashAlgorithm.Create (algorithm)) {
using (var unix = HashAlgorithm.Create (algorithm)) {
stream.Position = 0;
ComputeHashes (stream, hash, dos, unix);
if (checksum [0] == size && checksum.Length < size) {
return ChecksumsEqual (hash.Hash, checksum, 1) ||
ChecksumsEqual (unix.Hash, checksum, 1) ||
ChecksumsEqual (dos.Hash, checksum, 1);
}
return ChecksumsEqual (hash.Hash, checksum) ||
ChecksumsEqual (unix.Hash, checksum) ||
ChecksumsEqual (dos.Hash, checksum);
}
}
}
}
public static bool CheckFileHash (string path, byte[] checksum)
{
if (checksum == null || checksum.Length == 0 || !File.Exists (path))
return false;
using (var stream = File.OpenRead (path)) {
if (checksum.Length == 16) {
// Note: Roslyn SHA1 hashes are 16 bytes and start w/ 20
if (checksum[0] == 20 && CheckHash (stream, "SHA1", checksum))
return true;
// Note: Roslyn SHA256 hashes are 16 bytes and start w/ 32
if (checksum[0] == 32 && CheckHash (stream, "SHA256", checksum))
return true;
return CheckHash (stream, "MD5", checksum);
}
if (checksum.Length == 20)
return CheckHash (stream, "SHA1", checksum);
if (checksum.Length == 32)
return CheckHash (stream, "SHA256", checksum);
}
return false;
}
}
}

View file

@ -0,0 +1,475 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Mono.Debugging.Backend;
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 fullTypeName;
[NonSerialized]
DebuggerSession session;
[NonSerialized]
bool haveParameterValues;
[NonSerialized]
ObjectValue[] parameters;
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)
{
}
[Obsolete]
public StackFrame (long address, string addressSpace, SourceLocation location, string language)
: this (address, addressSpace, location, language, string.IsNullOrEmpty (location.FileName), true, "", "")
{
}
[Obsolete]
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) || isExternalCode, hasDebugInfo, "", "")
{
}
public StackFrame (long address, SourceLocation location, string language)
: this (address, "", location, language, string.IsNullOrEmpty (location.FileName), true, "", "")
{
}
internal void Attach (DebuggerSession debugSession)
{
session = debugSession;
}
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 hasDebugInfo; }
}
public string FullModuleName { get; protected set; }
public string FullTypeName {
get { return fullTypeName; }
}
/// <summary>
/// Gets the full name of the stackframe. Which respects Session.EvaluationOptions.StackFrameFormat
/// </summary>
[Obsolete]
public string FullStackframeText {
get { return GetFullStackFrameText (); }
}
/// <summary>
/// Used to ignore a first-chance exception in the given location (module, type, method and IL offset).
/// </summary>
public string GetLocationSignature ()
{
string methodName = this.SourceLocation.MethodName;
if (methodName != null && !methodName.Contains("!")) {
methodName = $"{Path.GetFileName (this.FullModuleName)}!{methodName}";
}
if (this.Address != 0) {
methodName = $"{methodName}:{Address}";
}
return methodName;
}
public string GetFullStackFrameText ()
{
return GetFullStackFrameText (session.EvaluationOptions);
}
public virtual string GetFullStackFrameText (EvaluationOptions options)
{
using (var cts = new CancellationTokenSource (options.MemberEvaluationTimeout))
return GetFullStackFrameTextAsync (options, false, cts.Token).GetAwaiter ().GetResult ();
}
public Task<string> GetFullStackFrameTextAsync (CancellationToken cancellationToken = default (CancellationToken))
{
return GetFullStackFrameTextAsync (session.EvaluationOptions, true, cancellationToken);
}
public virtual Task<string> GetFullStackFrameTextAsync (EvaluationOptions options, CancellationToken cancellationToken = default (CancellationToken))
{
return GetFullStackFrameTextAsync (options, true, cancellationToken);
}
async Task<string> GetFullStackFrameTextAsync (EvaluationOptions options, bool doAsync, CancellationToken cancellationToken)
{
// If MethodName starts with "[", then it's something like [ExternalCode]
if (SourceLocation.MethodName.StartsWith ("[", StringComparison.Ordinal))
return SourceLocation.MethodName;
options = options.Clone ();
if (options.StackFrameFormat.ParameterValues) {
options.AllowMethodEvaluation = true;
options.AllowToStringCalls = true;
options.AllowTargetInvoke = true;
} else {
options.AllowMethodEvaluation = false;
options.AllowToStringCalls = false;
options.AllowTargetInvoke = false;
}
// Cache the method parameters. Only refresh the method params iff the cached args do not
// already have parameter values. Once we have parameter values, we never have to
// refresh the cached parameters because we can just omit the parameter values when
// constructing the display string.
if (parameters == null || (options.StackFrameFormat.ParameterValues && !haveParameterValues)) {
haveParameterValues = options.StackFrameFormat.ParameterValues;
parameters = GetParameters (options);
}
var methodNameBuilder = new StringBuilder ();
if (options.StackFrameFormat.Module && !string.IsNullOrEmpty (FullModuleName)) {
methodNameBuilder.Append (Path.GetFileName (FullModuleName));
methodNameBuilder.Append ('!');
}
methodNameBuilder.Append (SourceLocation.MethodName);
if (options.StackFrameFormat.ParameterTypes || options.StackFrameFormat.ParameterNames || options.StackFrameFormat.ParameterValues) {
methodNameBuilder.Append ('(');
for (int n = 0; n < parameters.Length; n++) {
if (parameters[n].IsEvaluating) {
var tcs = new TaskCompletionSource<bool> ();
EventHandler updated = (s, e) => {
tcs.TrySetResult (true);
};
parameters[n].ValueChanged += updated;
try {
using (var registration = cancellationToken.Register (() => tcs.TrySetCanceled ())) {
if (parameters[n].IsEvaluating) {
if (doAsync) {
await tcs.Task.ConfigureAwait (false);
} else {
tcs.Task.Wait (cancellationToken);
}
}
}
} finally {
parameters[n].ValueChanged -= updated;
}
}
if (n > 0)
methodNameBuilder.Append (", ");
if (options.StackFrameFormat.ParameterTypes) {
methodNameBuilder.Append (parameters[n].TypeName);
if (options.StackFrameFormat.ParameterNames)
methodNameBuilder.Append (' ');
}
if (options.StackFrameFormat.ParameterNames)
methodNameBuilder.Append (parameters[n].Name);
if (options.StackFrameFormat.ParameterValues) {
if (options.StackFrameFormat.ParameterTypes || options.StackFrameFormat.ParameterNames)
methodNameBuilder.Append (" = ");
var val = parameters[n].Value ?? string.Empty;
methodNameBuilder.Append (val.Replace ("\r\n", " ").Replace ("\n", " "));
}
}
methodNameBuilder.Append (')');
}
return methodNameBuilder.ToString ();
}
public ObjectValue[] GetLocalVariables ()
{
return GetLocalVariables (session.EvaluationOptions);
}
public ObjectValue[] GetLocalVariables (EvaluationOptions options)
{
if (!hasDebugInfo) {
DebuggerLoggingService.LogMessage ("Cannot get local variables: no debugging symbols for frame: {0}", this);
return new ObjectValue [0];
}
var 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) {
DebuggerLoggingService.LogMessage ("Cannot get parameters: no debugging symbols for frame: {0}", this);
return new ObjectValue [0];
}
var values = sourceBacktrace.GetParameters (index, options);
ObjectValue.ConnectCallbacks (this, values);
return values;
}
public ObjectValue[] GetAllLocals ()
{
if (!hasDebugInfo) {
DebuggerLoggingService.LogMessage ("Cannot get local variables: no debugging symbols for frame: {0}", this);
return new ObjectValue [0];
}
var evaluator = session.FindExpressionEvaluator (this);
return evaluator != null ? evaluator.GetLocals (this) : GetAllLocals (session.EvaluationOptions);
}
public ObjectValue[] GetAllLocals (EvaluationOptions options)
{
if (!hasDebugInfo) {
DebuggerLoggingService.LogMessage ("Cannot get local variables: no debugging symbols for frame: {0}", this);
return new ObjectValue [0];
}
var 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) {
DebuggerLoggingService.LogMessage ("Cannot get `this' reference: no debugging symbols for frame: {0}", this);
return null;
}
var 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)
{
var 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)
{
var options = session.EvaluationOptions.Clone ();
options.AllowMethodEvaluation = evaluateMethods;
return GetExpressionValues (expressions, options);
}
public ObjectValue[] GetExpressionValues (string[] expressions, EvaluationOptions options)
{
if (!hasDebugInfo) {
DebuggerLoggingService.LogMessage ("Cannot get expression values: no debugging symbols for frame: {0}", this);
var vals = new ObjectValue [expressions.Length];
for (int n = 0; n < expressions.Length; n++)
vals[n] = ObjectValue.CreateUnknown (expressions[n]);
return vals;
}
if (options.UseExternalTypeResolver) {
var resolved = new string [expressions.Length];
for (int n = 0; n < expressions.Length; n++)
resolved[n] = ResolveExpression (expressions[n]);
expressions = resolved;
}
var values = sourceBacktrace.GetExpressionValues (index, expressions, options);
ObjectValue.ConnectCallbacks (this, values);
return values;
}
public ObjectValue GetExpressionValue (string expression, bool evaluateMethods)
{
var options = session.EvaluationOptions.Clone ();
options.AllowMethodEvaluation = evaluateMethods;
return GetExpressionValue (expression, options);
}
public ObjectValue GetExpressionValue (string expression, EvaluationOptions options)
{
if (!hasDebugInfo) {
DebuggerLoggingService.LogMessage ("Cannot get expression value: no debugging symbols for frame: {0}", this);
return ObjectValue.CreateUnknown (expression);
}
if (options.UseExternalTypeResolver)
expression = ResolveExpression (expression);
var values = sourceBacktrace.GetExpressionValues (index, new [] { 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)
{
return hasDebugInfo ? sourceBacktrace.GetExpressionCompletionData (index, exp) : null;
}
// 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;
if (location.Column != 0)
loc += "," + location.Column;
} else if (!string.IsNullOrEmpty (location.FileName)) {
loc = " at " + location.FileName;
} else {
loc = string.Empty;
}
return string.Format ("0x{0:X} in {1}{2}", address, location.MethodName, loc);
}
public void UpdateSourceFile (string newFilePath)
{
location = new SourceLocation (location.MethodName, newFilePath, location.Line, location.Column, location.EndLine, location.EndColumn, location.FileHash, location.SourceLink);
}
}
[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;
}
}
}

View file

@ -0,0 +1,61 @@
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;
}
public int? ExitCode {
get; set;
}
}
}

View file

@ -0,0 +1,19 @@
using System;
namespace Mono.Debugging.Client
{
[Serializable]
public enum TargetEventType
{
TargetReady,
TargetStopped,
TargetInterrupted,
TargetHitBreakpoint,
TargetSignaled,
TargetExited,
ExceptionThrown,
UnhandledException,
ThreadStarted,
ThreadStopped
}
}

View file

@ -0,0 +1,43 @@
// ThreadEventArgs.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Client
{
public class ThreadEventArgs : EventArgs
{
public ThreadEventArgs (int threadId)
{
ThreadId = threadId;
}
public int ThreadId {
get; private set;
}
}
}

View file

@ -0,0 +1,146 @@
// ThreadInfo.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace 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) {
PrefetchBacktrace ();
if (backtrace != null && backtrace.FrameCount > 0)
location = backtrace.GetFrame (0).ToString ();
}
return location;
}
}
internal long ProcessId {
get { return processId; }
}
public Backtrace Backtrace {
get {
PrefetchBacktrace ();
return backtrace;
}
}
public long ElapsedTime {
get {
var elapsedTime = session.GetElapsedTime (processId, id);
return elapsedTime;
}
}
public void SetActive ()
{
session.ActiveThread = this;
}
public void PrefetchBacktrace ()
{
if (backtrace == null)
backtrace = session.GetBacktrace (processId, id);
}
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)
{
if (obj is ThreadInfo ot)
return id == ot.id && processId == ot.processId && session == ot.session;
return false;
}
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 (t1 == null || t2 == null)
return true;
return !t1.Equals (t2);
}
}
}

View file

@ -0,0 +1,55 @@
//
// UsageCounter.cs
//
// Author:
// Jeffrey Stedfast <jestedfa@microsoft.com>
//
// Copyright (c) 2020 Microsoft Corp.
//
// 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.Collections.Generic;
namespace Mono.Debugging.Client
{
public class UsageCounter
{
readonly Dictionary<string, int> stats = new Dictionary<string, int> ();
public UsageCounter ()
{
}
public bool HasUsageStats {
get { return stats.Count > 0; }
}
public void IncrementUsage (string action)
{
stats.TryGetValue (action, out var value);
stats[action] = value + 1;
}
public void Serialize (Dictionary<string, object> metadata)
{
foreach (var kvp in stats)
metadata[kvp.Key] = kvp.Value;
}
}
}

View file

@ -0,0 +1,382 @@
// ArrayElementGroup.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using System.Text;
using Mono.Debugging.Client;
using Mono.Debugging.Backend;
namespace Mono.Debugging.Evaluation
{
public class ArrayElementGroup: RemoteFrameObject, IObjectValueSource
{
readonly ICollectionAdaptor array;
readonly EvaluationContext ctx;
int[] baseIndices;
int[] dimensions;
int firstIndex;
int lastIndex;
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.dimensions = array.GetDimensions ();
this.baseIndices = baseIndices;
this.firstIndex = firstIndex;
this.lastIndex = lastIndex;
}
public bool IsRange {
get { return lastIndex != -1; }
}
public ObjectValue CreateObjectValue ()
{
Connect ();
var sb = new StringBuilder ("[");
for (int i = 0; i < baseIndices.Length; i++) {
if (i > 0)
sb.Append (", ");
sb.Append (baseIndices[i].ToString ());
}
if (IsRange) {
if (baseIndices.Length > 0)
sb.Append (", ");
sb.Append (firstIndex.ToString ()).Append ("..").Append (lastIndex.ToString ());
}
if (dimensions.Length > 1 && baseIndices.Length < dimensions.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 (dimensions.Length > 1) {
int rank = baseIndices.Length;
lowerBound = array.GetLowerBounds () [rank];
upperBound = lowerBound + dimensions [rank] - 1;
isLastDimension = rank == dimensions.Length - 1;
} else {
lowerBound = array.GetLowerBounds () [0];
upperBound = lowerBound + dimensions [0] - 1;
isLastDimension = true;
}
int len;
int initalIndex;
if (!IsRange) {
initalIndex = lowerBound;
len = upperBound + 1 - lowerBound;
} 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 += ",";
curIndex [curIndex.Length - 1] = initalIndex + firstItemIndex;
var elems = array.GetElements (curIndex, System.Math.Min (values.Length, upperBound - lowerBound + 1));
for (int n = 0; n < values.Length; n++) {
int index = n + initalIndex + firstItemIndex;
string sidx = curIndexStr + index;
ObjectValue val;
string ename = "[" + sidx.Replace (",", ", ") + "]";
if (index > upperBound)
val = ObjectValue.CreateUnknown (sidx);
else {
curIndex [curIndex.Length - 1] = index;
val = cctx.Adapter.CreateObjectValue (cctx, this, newPath.Append (sidx), elems.GetValue (n), ObjectValueFlags.ArrayElement);
if (elems.GetValue (n) != null && !cctx.Adapter.IsNull (cctx, elems.GetValue (n))) {
TypeDisplayData tdata = cctx.Adapter.GetTypeDisplayData (cctx, cctx.Adapter.GetValueType (cctx, elems.GetValue (n)));
if (!string.IsNullOrEmpty (tdata.NameDisplayString)) {
try {
ename = cctx.Adapter.EvaluateDisplayString (cctx, elems.GetValue (n), tdata.NameDisplayString);
} catch (MissingMemberException) {
// missing property or otherwise malformed DebuggerDisplay string
}
}
}
}
val.Name = ename;
values [n] = val;
}
return values;
}
if (!isLastDimension && div == 1) {
// Return an array element group for each index
var 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;
var 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)
{
var sb = new StringBuilder ();
for (int i = 0; i < indices.Length; i++) {
if (i > 0)
sb.Append (',');
sb.Append (indices[i].ToString ());
}
return sb.ToString ();
}
internal static int[] StringToIndices (string str)
{
var sidx = str.Split (',');
var idx = new int [sidx.Length];
for (int i = 0; i < sidx.Length; i++)
idx[i] = int.Parse (sidx[i]);
return idx;
}
public static string GetArrayDescription (int[] bounds)
{
if (bounds.Length == 0)
return "[...]";
var sb = new StringBuilder ("[");
for (int i = 0; i < bounds.Length; i++) {
if (i > 0)
sb.Append (", ");
sb.Append (bounds [i].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)) {
try {
val.Name = cctx.Adapter.EvaluateDisplayString (cctx, elem, tdata.NameDisplayString);
} catch (MissingMemberException) {
// missing property or otherwise malformed DebuggerDisplay string
}
}
}
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
{
readonly ICollectionAdaptor source;
readonly 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);
}
}
}
}

View file

@ -0,0 +1,82 @@
// ArrayValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.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 {
var name = new StringBuilder ();
name.Append ('[');
for (int n = 0; n < indices.Length; n++) {
if (n > 0)
name.Append (", ");
name.Append (indices[n]);
}
name.Append (']');
return name.ToString ();
}
}
public override object Type {
get {
return adaptor.ElementType;
}
}
public override ObjectValueFlags Flags {
get {
return ObjectValueFlags.ArrayElement;
}
}
}
}

View file

@ -0,0 +1,163 @@
// AsyncEvaluationTracker.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
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; }
}
internal DebuggerSession Session { get; set; }
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) {
var session = Session;
if (session == null || (flags == ObjectValueFlags.EvaluatingGroup)) {
// Cannot report timing if session is null. If a group is being
// evaluated then individual timings are not possible and must
// be done elsewhere.
val = evaluator ();
} else {
using (var timer = session.EvaluationStats.StartTimer (name)) {
val = evaluator ();
timer.Stop (val);
}
}
}
},
delegate {
if (tid >= cancelTimestamp)
OnEvaluationDone (id, val);
});
if (done) {
// 'val' may be null if the timed evaluator is disposed while evaluating
return val ?? ObjectValue.CreateUnknown (name);
}
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;
}
}
}
}
}
}

View file

@ -0,0 +1,257 @@
// RuntimeInvokeManager.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using ST = System.Threading;
using Mono.Debugging.Client;
namespace Mono.Debugging.Evaluation
{
public class AsyncOperationManager: IDisposable
{
readonly 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)) {
var wasAborted = methodCall.Aborted;
methodCall.InternalAbort ();
lock (operationsToCancel) {
operationsToCancel.Remove (methodCall);
ST.Monitor.PulseAll (operationsToCancel);
}
if (wasAborted)
throw new EvaluatorAbortedException ();
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 (var op in operationsToCancel) {
op.InternalShutdown ();
}
operationsToCancel.Clear ();
}
}
public void AbortAll ()
{
lock (operationsToCancel) {
foreach (var op in operationsToCancel)
op.InternalAbort ();
}
}
public void EnterBusyState (AsyncOperation oper)
{
var args = new BusyStateEventArgs {
IsBusy = true,
Description = oper.Description,
EvaluationContext = oper.EvaluationContext
};
BusyStateChanged?.Invoke (this, args);
}
public void LeaveBusyState (AsyncOperation oper)
{
var args = new BusyStateEventArgs {
IsBusy = false,
Description = oper.Description,
EvaluationContext = oper.EvaluationContext
};
BusyStateChanged?.Invoke (this, args);
}
public event EventHandler<BusyStateEventArgs> BusyStateChanged;
}
public abstract class AsyncOperation
{
internal AsyncOperationManager Manager;
internal bool Aborted;
public bool Aborting { get; internal set; }
public EvaluationContext EvaluationContext {
get; private set;
}
protected AsyncOperation (EvaluationContext ctx)
{
EvaluationContext = ctx;
}
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 ();
}
}

View file

@ -0,0 +1,296 @@
//
// Backtrace.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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
{
readonly Dictionary<int, FrameInfo> frameInfo = new Dictionary<int, FrameInfo> ();
protected 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)
{
var frame = GetFrameInfo (frameIndex, options, false);
var list = new List<ObjectValue> ();
if (frame == null) {
var val = Adaptor.CreateObjectValueAsync ("Local Variables", ObjectValueFlags.EvaluatingGroup, delegate {
frame = GetFrameInfo (frameIndex, options, true);
foreach (var local in frame.LocalVariables) {
using (var timer = StartEvaluationTimer (local.Name)) {
var localValue = local.CreateObjectValue (false, options);
timer.Stop (localValue);
list.Add (localValue);
}
}
return ObjectValue.CreateArray (null, new ObjectPath ("Local Variables"), "", list.Count, ObjectValueFlags.EvaluatingGroup, list.ToArray ());
});
return new [] { val };
}
foreach (var local in frame.LocalVariables)
list.Add (local.CreateObjectValue (true, options));
return list.ToArray ();
}
public virtual ObjectValue[] GetParameters (int frameIndex, EvaluationOptions options)
{
var frame = GetFrameInfo (frameIndex, options, false);
var values = new List<ObjectValue> ();
if (frame == null) {
var value = Adaptor.CreateObjectValueAsync ("Parameters", ObjectValueFlags.EvaluatingGroup, delegate {
frame = GetFrameInfo (frameIndex, options, true);
foreach (var param in frame.Parameters) {
using (var timer = StartEvaluationTimer (param.Name)) {
var paramValue = param.CreateObjectValue (false, options);
timer.Stop (paramValue);
values.Add (paramValue);
}
}
return ObjectValue.CreateArray (null, new ObjectPath ("Parameters"), "", values.Count, ObjectValueFlags.EvaluatingGroup, values.ToArray ());
});
return new [] { value };
}
foreach (var param in frame.Parameters)
values.Add (param.CreateObjectValue (true, options));
return values.ToArray ();
}
public virtual ObjectValue GetThisReference (int frameIndex, EvaluationOptions options)
{
var frame = GetFrameInfo (frameIndex, options, false);
if (frame == null) {
return Adaptor.CreateObjectValueAsync ("this", ObjectValueFlags.EvaluatingGroup, delegate {
frame = GetFrameInfo (frameIndex, options, true);
ObjectValue[] values;
if (frame.This != null) {
using (var timer = StartEvaluationTimer ("this")) {
var thisValue = frame.This.CreateObjectValue (false, options);
timer.Stop (thisValue);
values = new [] { thisValue };
}
} else
values = new ObjectValue [0];
return ObjectValue.CreateArray (null, new ObjectPath ("this"), "", values.Length, ObjectValueFlags.EvaluatingGroup, values);
});
}
return frame.This != null ? frame.This.CreateObjectValue (true, options) : null;
}
public virtual ExceptionInfo GetException (int frameIndex, EvaluationOptions options)
{
var frame = GetFrameInfo (frameIndex, options, false);
ObjectValue value;
if (frame == null) {
value = Adaptor.CreateObjectValueAsync (options.CurrentExceptionTag, ObjectValueFlags.EvaluatingGroup, delegate {
frame = GetFrameInfo (frameIndex, options, true);
ObjectValue[] values;
if (frame.Exception != null) {
using (var timer = StartEvaluationTimer ("Exception")) {
var exceptionValue = frame.Exception.CreateObjectValue (false, options);
timer.Stop (exceptionValue);
values = new [] { exceptionValue };
}
} else
values = new ObjectValue [0];
return ObjectValue.CreateArray (null, new ObjectPath (options.CurrentExceptionTag), "", values.Length, ObjectValueFlags.EvaluatingGroup, values);
});
} else if (frame.Exception != null) {
value = frame.Exception.CreateObjectValue (true, options);
} else {
return null;
}
return new ExceptionInfo (value);
}
public virtual ObjectValue GetExceptionInstance (int frameIndex, EvaluationOptions options)
{
var frame = GetFrameInfo (frameIndex, options, false);
if (frame == null) {
return Adaptor.CreateObjectValueAsync (options.CurrentExceptionTag, ObjectValueFlags.EvaluatingGroup, delegate {
frame = GetFrameInfo (frameIndex, options, true);
ObjectValue[] values;
if (frame.Exception != null) {
using (var timer = StartEvaluationTimer ("Exception")) {
var exceptionValue = frame.Exception.Exception.CreateObjectValue (false, options);
timer.Stop (exceptionValue);
values = new [] { exceptionValue };
}
} else
values = new ObjectValue [0];
return ObjectValue.CreateArray (null, new ObjectPath (options.CurrentExceptionTag), "", values.Length, ObjectValueFlags.EvaluatingGroup, values);
});
}
return frame.Exception != null ? frame.Exception.Exception.CreateObjectValue (true, options) : null;
}
public virtual ObjectValue[] GetAllLocals (int frameIndex, EvaluationOptions options)
{
var locals = new List<ObjectValue> ();
var excObj = GetExceptionInstance (frameIndex, options);
if (excObj != null)
locals.Insert (0, excObj);
locals.AddRange (GetLocalVariables (frameIndex, options));
locals.AddRange (GetParameters (frameIndex, options));
locals.Sort ((v1, v2) => StringComparer.InvariantCulture.Compare (v1.Name, v2.Name));
var 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) {
var values = new List<ObjectValue> ();
foreach (var expression in expressions) {
string tmpExp = expression;
var value = Adaptor.CreateObjectValueAsync (tmpExp, ObjectValueFlags.Field, delegate {
var cctx = GetEvaluationContext (frameIndex, options);
return Adaptor.GetExpressionValue (cctx, tmpExp);
});
value.Name = expression;
values.Add (value);
}
return values.ToArray ();
}
var ctx = GetEvaluationContext (frameIndex, options);
return ctx.Adapter.GetExpressionValuesAsync (ctx, expressions);
}
public virtual CompletionData GetExpressionCompletionData (int frameIndex, string exp)
{
var ctx = GetEvaluationContext (frameIndex, EvaluationOptions.DefaultOptions);
return ctx.Adapter.GetExpressionCompletionData (ctx, exp);
}
public virtual AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count)
{
throw new NotImplementedException ();
}
public virtual ValidationResult ValidateExpression (int frameIndex, string expression, EvaluationOptions options)
{
var ctx = GetEvaluationContext (frameIndex, options);
return Adaptor.ValidateExpression (ctx, expression);
}
FrameInfo GetFrameInfo (int frameIndex, EvaluationOptions options, bool ignoreEvalStatus)
{
FrameInfo finfo;
lock (frameInfo) {
if (frameInfo.TryGetValue (frameIndex, out finfo))
return finfo;
if (!ignoreEvalStatus && Adaptor.IsEvaluating)
return null;
var ctx = GetEvaluationContext (frameIndex, options);
if (ctx == null)
return null;
finfo = new FrameInfo ();
finfo.Context = ctx;
//Don't try to optimize lines below with lazy loading, you won't gain anything(in communication with runtime)
finfo.LocalVariables.AddRange (ctx.Evaluator.GetLocalVariables (ctx));
finfo.Parameters.AddRange (ctx.Evaluator.GetParameters (ctx));
finfo.This = ctx.Evaluator.GetThisReference (ctx);
var ex = ctx.Evaluator.GetCurrentException (ctx);
if (ex != null)
finfo.Exception = new ExceptionInfoSource (ctx, ex);
frameInfo[frameIndex] = finfo;
}
return finfo;
}
DebuggerTimer StartEvaluationTimer (string name)
{
return new DebuggerTimer (Adaptor.DebuggerSession?.EvaluationStats, name);
}
}
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;
}
}

View file

@ -0,0 +1,89 @@
//
// BaseTypeViewSource.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@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
}
}

View file

@ -0,0 +1,163 @@
//
// IEnumerableSource.cs
//
// Author:
// David Karlaš <david.karlas@xamarin.com>
//
// Copyright (c) 2014 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 Mono.Debugging.Backend;
using Mono.Debugging.Client;
using System.Collections.Generic;
namespace Mono.Debugging.Evaluation
{
class EnumerableSource : IObjectValueSource
{
object obj;
object objType;
EvaluationContext ctx;
List<ObjectValue> elements;
List<object> values;
int currentIndex = 0;
object enumerator;
object enumeratorType;
public EnumerableSource (object source, object type, EvaluationContext ctx)
{
this.obj = source;
this.objType = type;
this.ctx = ctx;
}
bool MoveNext ()
{
return (bool)ctx.Adapter.TargetObjectToObject (ctx, ctx.Adapter.RuntimeInvoke (ctx, enumeratorType, enumerator, "MoveNext", new object[0], new object[0]));
}
void Fetch (int maxIndex)
{
if (elements == null) {
elements = new List<ObjectValue> ();
values = new List<object> ();
enumerator = ctx.Adapter.RuntimeInvoke (ctx, objType, obj, "GetEnumerator", new object[0], new object[0]);
enumeratorType = ctx.Adapter.GetImplementedInterfaces (ctx, ctx.Adapter.GetValueType (ctx, enumerator)).First (f => ctx.Adapter.GetTypeName (ctx, f) == "System.Collections.IEnumerator");
}
while (maxIndex > elements.Count && MoveNext ()) {
var valCurrent = ctx.Adapter.GetMember (ctx, null, enumeratorType, enumerator, "Current");
var val = valCurrent.Value;
values.Add (val);
if (val != null) {
elements.Add (ctx.Adapter.CreateObjectValue (ctx, valCurrent, new ObjectPath ("[" + currentIndex + "]"), val, ObjectValueFlags.ReadOnly));
} else {
elements.Add (Mono.Debugging.Client.ObjectValue.CreateNullObject (this, "[" + currentIndex + "]", ctx.Adapter.GetDisplayTypeName (ctx.Adapter.GetTypeName (ctx, valCurrent.Type)), ObjectValueFlags.ReadOnly));
}
currentIndex++;
}
}
public object GetElement (int idx)
{
return values [idx];
}
public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
{
int idx;
if (int.TryParse (path.LastName.Replace ("[", "").Replace ("]", ""), out idx)) {
return ctx.Adapter.GetObjectValueChildren (ctx, null, values [idx], -1, -1);
}
if (index < 0)
index = 0;
if (count == 0)
return new ObjectValue[0];
if (count == -1)
count = int.MaxValue;
Fetch (index + count);
if (count < 0 || index + count > elements.Count) {
return elements.Skip (index).ToArray ();
} else {
if (index < elements.Count) {
return elements.Skip (index).Take (System.Math.Min (count, elements.Count - index)).ToArray ();
} else {
return new ObjectValue[0];
}
}
}
public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
{
throw new InvalidOperationException ("Elements of IEnumerable can not be set");
}
public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
{
int idx;
if (int.TryParse (path.LastName.Replace ("[", "").Replace ("]", ""), out idx)) {
var element = elements [idx];
element.Refresh (options);
return element;
}
return null;
}
public object GetRawValue (ObjectPath path, EvaluationOptions options)
{
int idx = int.Parse (path.LastName.Replace ("[", "").Replace ("]", ""));
EvaluationContext cctx = ctx.WithOptions (options);
return cctx.Adapter.ToRawValue (cctx, new EnumerableObjectSource (this, idx), GetElement (idx));
}
public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
{
throw new InvalidOperationException ("Elements of IEnumerable can not be set");
}
}
class EnumerableObjectSource : IObjectSource
{
EnumerableSource enumerableSource;
int idx;
public EnumerableObjectSource (EnumerableSource enumerableSource, int idx)
{
this.enumerableSource = enumerableSource;
this.idx = idx;
}
#region IObjectSource implementation
public object Value {
get {
return enumerableSource.GetElement (idx);
}
set {
throw new InvalidOperationException ("Elements of IEnumerable can not be set");
}
}
#endregion
}
}

View file

@ -0,0 +1,147 @@
// EvaluationContext.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using Mono.Debugging.Client;
using Mono.Debugging.Backend;
namespace Mono.Debugging.Evaluation
{
public class EvaluationContext
{
public ExpressionEvaluator Evaluator { get; set; }
public ObjectValueAdaptor Adapter { get; set; }
public EvaluationOptions Options {
get; set;
}
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)
{
Options = options;
}
public EvaluationContext Clone ()
{
var clone = (EvaluationContext) MemberwiseClone ();
clone.CopyFrom (this);
return clone;
}
public EvaluationContext WithOptions (EvaluationOptions options)
{
if (options == null || Options == options)
return this;
var 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;
}
}
public virtual bool SupportIEnumerable {
get {
return false;
}
}
}
class ExpressionValueSource: RemoteFrameObject, IObjectValueSource
{
readonly EvaluationContext ctx;
public ExpressionValueSource (EvaluationContext ctx)
{
this.ctx = ctx;
Connect ();
}
public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
{
throw new NotImplementedException ();
}
public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
{
throw new NotImplementedException ();
}
public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
{
EvaluationContext c = ctx.WithOptions (options);
var vals = c.Adapter.GetExpressionValuesAsync (c, new string[] { path.LastName });
return vals[0];
}
public object GetRawValue (ObjectPath path, EvaluationOptions options)
{
throw new NotImplementedException ();
}
public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
{
throw new NotImplementedException ();
}
}
}

View file

@ -0,0 +1,244 @@
//
// ExceptionInfoSource.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Mono.Debugging.Client;
using Mono.Debugging.Backend;
namespace Mono.Debugging.Evaluation
{
public class ExceptionInfoSource
{
EvaluationContext ctx;
public ExceptionInfoSource (EvaluationContext ctx, ValueReference exception)
{
Exception = exception;
this.ctx = ctx;
}
public ValueReference Exception {
get; private set;
}
public ObjectValue CreateObjectValue (bool withTimeout, EvaluationOptions options)
{
options = options.Clone ();
options.EllipsizeStrings = false;
options.AllowTargetInvoke = true;
ctx = ctx.WithOptions (options);
string type = ctx.Adapter.GetValueTypeName (ctx, Exception.ObjectValue);
var excInstance = Exception.CreateObjectValue (withTimeout, options);
excInstance.Name = "Instance";
ObjectValue messageValue = null;
ObjectValue helpLinkValue = null;
var exceptionType = ctx.Adapter.GetValueType (ctx, Exception.Value);
// Get the message
if (withTimeout) {
messageValue = ctx.Adapter.CreateObjectValueAsync ("Message", ObjectValueFlags.None, delegate {
var mref = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "Message");
if (mref != null) {
string val = (string)mref.ObjectValue;
return ObjectValue.CreatePrimitive (null, new ObjectPath ("Message"), "string", new EvaluationResult (val), ObjectValueFlags.Literal);
}
return ObjectValue.CreateUnknown ("Message");
});
} else {
var mref = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "Message");
if (mref != null) {
string val = (string)mref.ObjectValue;
messageValue = ObjectValue.CreatePrimitive (null, new ObjectPath ("Message"), "string", new EvaluationResult (val), ObjectValueFlags.Literal);
}
}
if (messageValue == null)
messageValue = ObjectValue.CreateUnknown ("Message");
messageValue.Name = "Message";
// Get the help link
if (withTimeout) {
helpLinkValue = ctx.Adapter.CreateObjectValueAsync ("HelpLink", ObjectValueFlags.None, delegate {
var mref = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "HelpLink");
if (mref != null) {
string val = (string)mref.ObjectValue;
return ObjectValue.CreatePrimitive (null, new ObjectPath ("HelpLink"), "string", new EvaluationResult (val), ObjectValueFlags.Literal);
}
return ObjectValue.CreateUnknown ("HelpLink");
});
} else {
var mref = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "HelpLink");
if (mref != null) {
string val = (string)mref.ObjectValue;
helpLinkValue = ObjectValue.CreatePrimitive (null, new ObjectPath ("HelpLink"), "string", new EvaluationResult (val), ObjectValueFlags.Literal);
}
}
if (helpLinkValue == null)
helpLinkValue = ObjectValue.CreateUnknown ("HelpLink");
helpLinkValue.Name = "HelpLink";
// Inner exception
ObjectValue childExceptionValue = null;
if (withTimeout) {
childExceptionValue = ctx.Adapter.CreateObjectValueAsync ("InnerException", ObjectValueFlags.None, delegate {
var inner = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "InnerException");
if (inner != null && !ctx.Adapter.IsNull (ctx, inner.Value)) {
//Console.WriteLine ("pp got child:" + type);
var innerSource = new ExceptionInfoSource (ctx, inner);
var res = innerSource.CreateObjectValue (false, options);
return res;
}
return ObjectValue.CreateUnknown ("InnerException");
});
} else {
var inner = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "InnerException");
if (inner != null && !ctx.Adapter.IsNull (ctx, inner.Value)) {
//Console.WriteLine ("pp got child:" + type);
var innerSource = new ExceptionInfoSource (ctx, inner);
childExceptionValue = innerSource.CreateObjectValue (false, options);
childExceptionValue.Name = "InnerException";
}
}
if (childExceptionValue == null)
childExceptionValue = ObjectValue.CreateUnknown ("InnerException");
// Inner exceptions in case of AgregatedException
ObjectValue childExceptionsValue = null;
ObjectEvaluatorDelegate getInnerExceptionsDelegate = delegate {
var inner = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "InnerExceptions");
if (inner != null && !ctx.Adapter.IsNull (ctx, inner.Value)) {
var obj = inner.GetValue (ctx);
var objType = ctx.Adapter.GetValueType (ctx, obj);
var count = (int)ctx.Adapter.GetMember(ctx, null, obj, "Count").ObjectValue;
var childrenList = new List<ObjectValue>();
for (int i = 0; i < count; i++) {
childrenList.Add (new ExceptionInfoSource(ctx, ctx.Adapter.GetIndexerReference(ctx, obj, objType, new object[] { ctx.Adapter.CreateValue(ctx, i) })).CreateObjectValue (withTimeout, ctx.Options));
}
return ObjectValue.CreateObject (null, new ObjectPath("InnerExceptions"), "", "", ObjectValueFlags.None, childrenList.ToArray ());
}
return ObjectValue.CreateUnknown ("InnerExceptions");
};
if (withTimeout) {
childExceptionsValue = ctx.Adapter.CreateObjectValueAsync ("InnerExceptions", ObjectValueFlags.None, getInnerExceptionsDelegate);
} else {
childExceptionsValue = getInnerExceptionsDelegate ();
}
if (childExceptionsValue == null)
childExceptionsValue = ObjectValue.CreateUnknown ("InnerExceptions");
// Stack trace
ObjectValue stackTraceValue;
if (withTimeout) {
stackTraceValue = ctx.Adapter.CreateObjectValueAsync ("StackTrace", ObjectValueFlags.None, delegate {
var stackTrace = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "StackTrace");
if (stackTrace == null)
return ObjectValue.CreateUnknown ("StackTrace");
return GetStackTrace (stackTrace.ObjectValue as string);
});
} else {
var stackTrace = ctx.Adapter.GetMember (ctx, Exception, exceptionType, Exception.Value, "StackTrace");
if (stackTrace == null)
return ObjectValue.CreateUnknown ("StackTrace");
stackTraceValue = GetStackTrace (stackTrace.ObjectValue as string);
}
var children = new ObjectValue [] { excInstance, messageValue, helpLinkValue, stackTraceValue, childExceptionValue, childExceptionsValue };
return ObjectValue.CreateObject (null, new ObjectPath ("InnerException"), type, "", ObjectValueFlags.None, children);
}
public static ObjectValue GetStackTrace (string trace)
{
if (trace == null)
return ObjectValue.CreateUnknown ("StackTrace");
var regex = new Regex ("at (?<MethodName>.*) in (?<FileName>.*):(?<LineNumber>\\d+)(,(?<Column>\\d+))?");
var regexLine = new Regex ("at (?<MethodName>.*) in (?<FileName>.*):line (?<LineNumber>\\d+)(,(?<Column>\\d+))?");
var frames = new List<ObjectValue> ();
foreach (var sframe in trace.Split ('\n')) {
string text = sframe.Trim (' ', '\r', '\t', '"');
string file = "";
int column = 0;
int line = 0;
if (text.Length == 0)
continue;
//Ignore entries like "--- End of stack trace from previous location where exception was thrown ---"
if (text.StartsWith ("---", StringComparison.Ordinal))
continue;
var match = regex.Match (text);
if (match.Success) {
text = match.Groups ["MethodName"].ToString ();
file = match.Groups ["FileName"].ToString ();
int.TryParse (match.Groups ["LineNumber"].ToString (), out line);
int.TryParse (match.Groups ["Column"].ToString (), out column);
} else {
match = regexLine.Match (text);
if (match.Success) {
text = match.Groups ["MethodName"].ToString ();
file = match.Groups ["FileName"].ToString ();
int.TryParse (match.Groups ["LineNumber"].ToString (), out line);
int.TryParse (match.Groups ["Column"].ToString (), out column);
}
}
var fileVal = ObjectValue.CreatePrimitive (null, new ObjectPath ("File"), "", new EvaluationResult (file), ObjectValueFlags.None);
var lineVal = ObjectValue.CreatePrimitive (null, new ObjectPath ("Line"), "", new EvaluationResult (line.ToString ()), ObjectValueFlags.None);
var colVal = ObjectValue.CreatePrimitive (null, new ObjectPath ("Column"), "", new EvaluationResult (column.ToString ()), ObjectValueFlags.None);
var children = new ObjectValue [] { fileVal, lineVal, colVal };
var frame = ObjectValue.CreateObject (null, new ObjectPath (), "", new EvaluationResult (text), ObjectValueFlags.None, children);
frames.Add (frame);
}
return ObjectValue.CreateArray (null, new ObjectPath ("StackTrace"), "", frames.Count, ObjectValueFlags.None, frames.ToArray ());
}
}
}

View file

@ -0,0 +1,267 @@
// IExpressionEvaluator.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Text;
using System.Globalization;
using System.Collections.Generic;
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 expression)
{
return Evaluate (ctx, expression, null);
}
public virtual ValueReference Evaluate (EvaluationContext ctx, string expression, object expectedType)
{
foreach (var variable in ctx.Adapter.GetLocalVariables (ctx))
if (variable.Name == expression)
return variable;
foreach (var parameter in ctx.Adapter.GetParameters (ctx))
if (parameter.Name == expression)
return parameter;
var thisVar = ctx.Adapter.GetThisReference (ctx);
if (thisVar != null) {
if (thisVar.Name == expression)
return thisVar;
foreach (var cv in thisVar.GetChildReferences (ctx.Options))
if (cv.Name == expression)
return cv;
}
throw new EvaluatorException ("Invalid Expression: '{0}'", expression);
}
public virtual ValidationResult ValidateExpression (EvaluationContext ctx, string expression)
{
return new ValidationResult (true, null);
}
public string TargetObjectToString (EvaluationContext ctx, object obj)
{
var res = ctx.Adapter.TargetObjectToObject (ctx, obj);
if (res == null)
return null;
if (res is EvaluationResult)
return ((EvaluationResult) res).DisplayValue ?? ((EvaluationResult) res).Value;
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");
if (obj is IntPtr ptr)
return new EvaluationResult ("0x" + ptr.ToInt64 ().ToString ("x"));
if (obj is char c) {
string str;
if (c == '\'')
str = @"'\''";
else if (c == '"')
str = "'\"'";
else
str = EscapeString ("'" + c + "'");
return new EvaluationResult (str, ((int) c) + " " + str);
}
if (obj is string s)
return new EvaluationResult ("\"" + EscapeString (s) + "\"");
if (obj is bool b)
return new EvaluationResult (b ? "true" : "false");
if (obj is decimal d)
return new EvaluationResult (d.ToString (CultureInfo.InvariantCulture));
if (obj is EvaluationResult result)
return result;
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)
{
var 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 expression);
public virtual IEnumerable<ValueReference> GetLocalVariables (EvaluationContext ctx)
{
return ctx.Adapter.GetLocalVariables (ctx);
}
public virtual ValueReference GetThisReference (EvaluationContext ctx)
{
return ctx.Adapter.GetThisReference (ctx);
}
public virtual IEnumerable<ValueReference> GetParameters (EvaluationContext ctx)
{
return ctx.Adapter.GetParameters (ctx);
}
public virtual ValueReference GetCurrentException (EvaluationContext ctx)
{
return ctx.Adapter.GetCurrentException (ctx);
}
}
[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))
{
}
public EvaluatorException (Exception innerException, string msg, params object [] args) : base (string.Format (msg, args), innerException)
{
}
}
[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.")
{
}
}
}

View file

@ -0,0 +1,123 @@
//
// FilteredMembersSource.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@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 ();
}
}
}

View file

@ -0,0 +1,42 @@
// ICollectionAdaptor.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using Mono.Debugging.Client;
namespace Mono.Debugging.Evaluation
{
public interface ICollectionAdaptor
{
int[] GetLowerBounds ();
int[] GetDimensions ();
object GetElement (int[] indices);
Array GetElements (int[] indices, int count);
object ElementType { get; }
void SetElement (int[] indices, object val);
}
}

View file

@ -0,0 +1,35 @@
//
// IObjectSource.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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; }
}
}

View file

@ -0,0 +1,34 @@
//
// IStringAdaptor.cs
//
// Author: Jeffrey Stedfast <jeff@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.
namespace Mono.Debugging.Evaluation
{
public interface IStringAdaptor
{
string Substring (int index, int length);
string Value { get; }
int Length { get; }
}
}

View file

@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Mono.Debugging.Client;
namespace Mono.Debugging.Evaluation
{
// Outputs lambda expression inputted on Immediate Pad. Also
// this class works for followings.
// - Check if body of lambda has not-supported expression
// - Output reserved words like `this` or `base` with generated
// identifer.
// - Collect variable references for outside the lambda
// (local variables/properties...)
/*public class LambdaBodyOutputVisitor : CSharpSyntaxWalker
{
readonly Dictionary<string, ValueReference> userVariables;
readonly EvaluationContext ctx;
Dictionary<string, Tuple<string, object>> localValues;
List<string> definedIdentifier;
int gensymCount;
public LambdaBodyOutputVisitor (EvaluationContext ctx, Dictionary<string, ValueReference> userVariables)
{
this.ctx = ctx;
this.userVariables = userVariables;
this.localValues = new Dictionary<string, Tuple<string, object>> ();
this.definedIdentifier = new List<string> ();
}
public Tuple<string, object>[] GetLocalValues ()
{
var locals = new Tuple<string, object>[localValues.Count];
int n = 0;
foreach (var localv in localValues.Values) {
locals[n] = localv;
n++;
}
return locals;
}
static Exception NotSupported ()
{
return new NotSupportedExpressionException ();
}
static Exception EvaluationError (string message, params object[] args)
{
return new EvaluatorException (message, args);
}
bool IsPublicValueFlag (ObjectValueFlags flags)
{
var isField = (flags & ObjectValueFlags.Field) != 0;
var isProperty = (flags & ObjectValueFlags.Property) != 0;
var isPublic = (flags & ObjectValueFlags.Public) != 0;
return !(isField || isProperty) || isPublic;
}
void AssertPublicType (object type)
{
if (!ctx.Adapter.IsPublic (ctx, type)) {
var typeName = ctx.Adapter.GetDisplayTypeName (ctx, type);
throw EvaluationError ("Not Support to reference non-public type: `{0}'", typeName);
}
}
void AssertPublicValueReference (ValueReference vr)
{
if (!(vr is NamespaceValueReference)) {
var typ = vr.Type;
AssertPublicType (typ);
}
if (!IsPublicValueFlag (vr.Flags)) {
throw EvaluationError ("Not Support to reference non-public thing: `{0}'", vr.Name);
}
}
ValueReference Evaluate (IdentifierNameSyntax t)
{
var visitor = new NRefactoryExpressionEvaluatorVisitor (ctx, t.Identifier.ValueText, null, userVariables);
return visitor.Visit (t);
}
ValueReference Evaluate (BaseExpressionSyntax t)
{
var visitor = new NRefactoryExpressionEvaluatorVisitor (ctx, "base", null, userVariables);
return visitor.Visit (t);
}
ValueReference Evaluate (ThisExpressionSyntax t)
{
var visitor = new NRefactoryExpressionEvaluatorVisitor (ctx, "this", null, userVariables);
return visitor.Visit (t);
}
string GenerateSymbol (string s)
{
var prefix = "__" + s;
var sym = prefix;
while (ExistsLocalName (sym)) {
sym = prefix + gensymCount++;
}
return sym;
}
string AddToLocals (string name, ValueReference vr, bool shouldRename = false)
{
if (localValues.ContainsKey (name))
return GetLocalName (name);
string localName;
if (shouldRename) {
localName = GenerateSymbol (name);
} else if (!ExistsLocalName (name)) {
localName = name;
} else {
throw EvaluationError ("Cannot use a variable named {0} inside lambda", name);
}
AssertPublicValueReference (vr);
if (!(vr is NamespaceValueReference)) {
var valu = vr?.Value;
var pair = Tuple.Create(localName, valu);
localValues.Add(name, pair);
}
return localName;
}
string GetLocalName (string name)
{
Tuple<string, object> pair;
if (localValues.TryGetValue (name, out pair))
return pair.Item1;
return null;
}
bool ExistsLocalName (string localName)
{
foreach (var pair in localValues.Values) {
if (pair.Item1 == localName)
return true;
}
return definedIdentifier.Contains (localName);
}
#region IAstVisitor implementation
public override void VisitAssignmentExpression (AssignmentExpressionSyntax node)
{
throw EvaluationError ("Not support assignment expression inside lambda");
}
public override void VisitBaseExpression (BaseExpressionSyntax node)
{
var basee = "base";
var localbase = GetLocalName (basee);
if (localbase == null) {
var vr = Evaluate (node);
localbase = AddToLocals (basee, vr, true);
}
}
public override void VisitIdentifierName (IdentifierNameSyntax node)
{
var identifier = node.Identifier.ValueText;
var localIdentifier = "";
if (definedIdentifier.Contains (identifier)) {
localIdentifier = identifier;
} else {
localIdentifier = GetLocalName (identifier);
if (localIdentifier == null) {
var vr = Evaluate (node);
localIdentifier = AddToLocals (identifier, vr);
}
}
}
public override void VisitGenericName (GenericNameSyntax node)
{
foreach (var arg in node.TypeArgumentList.Arguments) {
Visit (arg);
}
}
public override void VisitInvocationExpression (InvocationExpressionSyntax node)
{
var invocationTarget = node.Expression;
if (!(invocationTarget is IdentifierNameSyntax method)) {
Visit(invocationTarget);
return;
}
var argc = node.ArgumentList.Arguments.Count;
var methodName = method.Identifier.ValueText;
var vref = ctx.Adapter.GetThisReference (ctx);
var vtype = ctx.Adapter.GetEnclosingType (ctx);
string accessor = null;
var hasInstanceMethod = ctx.Adapter.HasMethodWithParamLength (ctx, vtype, methodName, BindingFlags.Instance, argc);
var hasStaticMethod = ctx.Adapter.HasMethodWithParamLength (ctx, vtype, methodName, BindingFlags.Static, argc);
var publicFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
var hasPublicMethod = ctx.Adapter.HasMethodWithParamLength (ctx, vtype, methodName, publicFlags, argc);
if ((hasInstanceMethod || hasStaticMethod) && !hasPublicMethod)
throw EvaluationError ("Only support public method invocation inside lambda");
if (vref == null && hasStaticMethod) {
AssertPublicType (vtype);
var typeName = ctx.Adapter.GetTypeName (ctx, vtype);
accessor = ctx.Adapter.GetDisplayTypeName (typeName);
} else if (vref != null) {
AssertPublicValueReference (vref);
if (hasInstanceMethod) {
if (hasStaticMethod) {
// It's hard to determine which one is expected because
// we don't have any information of parameter types now.
throw EvaluationError ("Not supported invocation of static/instance overloaded method");
}
accessor = GetLocalName ("this");
if (accessor == null)
accessor = AddToLocals ("this", vref, true);
} else if (hasStaticMethod) {
var typeName = ctx.Adapter.GetTypeName (ctx, vtype);
accessor = ctx.Adapter.GetDisplayTypeName (typeName);
}
}
for (int i = 0; i < node.ArgumentList.Arguments.Count; i++) {
Visit (node.ArgumentList.Arguments[i]);
}
}
public override void VisitSimpleLambdaExpression (SimpleLambdaExpressionSyntax node)
{
if (node.Parameter.Modifiers.Count > 0)
throw NotSupported ();
definedIdentifier.Add (node.Parameter.Identifier.ValueText);
Visit (node.Body);
}
public override void VisitThisExpression (ThisExpressionSyntax node)
{
var thiss = "this";
var localthis = GetLocalName (thiss);
if (localthis == null) {
var vr = Evaluate (node);
localthis = AddToLocals (thiss, vr, true);
}
}
#endregion
}*/
}

View file

@ -0,0 +1,180 @@
// LiteralValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using 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)
{
var 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, object type = null)
{
var val = new LiteralValueReference (ctx);
val.name = name;
val.value = value;
val.type = type ?? ctx.Adapter.GetValueType (ctx, value);
val.objCreated = true;
return val;
}
public static LiteralValueReference CreateObjectLiteral (EvaluationContext ctx, string name, object value)
{
var val = new LiteralValueReference (ctx);
val.name = name;
val.objValue = value;
val.objLiteral = true;
return val;
}
public static LiteralValueReference CreateVoidReturnLiteral (EvaluationContext ctx, string name)
{
var 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 {
return objLiteral ? objValue : 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);
}
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
var tokens = name.Substring (1, name.Length - 2).Split (',');
var indices = new int [tokens.Length];
for (int n = 0; n < tokens.Length; n++)
indices[n] = int.Parse (tokens[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);
}
}
}

View file

@ -0,0 +1,237 @@
//
// NRefactoryExpressionEvaluator.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Linq;
using System.Collections.Generic;
using Mono.Debugging.Client;
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.Trim ();
if (expression.Length > 0 && expression[0] == '?')
expression = expression.Substring (1).TrimStart ();
if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3])) {
expression = expression.Substring (4).TrimStart ();
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).TrimStart ().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 = SyntaxFactory.ParseExpression (expression);
if (expr == null)
throw new EvaluatorException ("Could not parse expression '{0}'", expression);
var evaluator = new NRefactoryExpressionEvaluatorVisitor (ctx, expression, expectedType, userVariables);
return evaluator.Visit (expr);
}
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.Trim ();
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);
var expr = SyntaxFactory.ParseExpression (expression);
if (expr == null)
return expression;
var resolver = new NRefactoryExpressionResolverVisitor (session, location, expression);
resolver.Visit (expr);
string resolved = resolver.GetResolvedExpression ();
if (resolved == expression && !tryTypeOf && (expr is BinaryExpressionSyntax) && 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.Trim ();
if (expression.Length > 0 && expression[0] == '?')
expression = expression.Substring (1).TrimStart ();
if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3]))
expression = expression.Substring (4).TrimStart ();
expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag);
ParseOptions options = new CSharpParseOptions ();
var expr = SyntaxFactory.ParseExpression (expression, options: options);
if (expr.ContainsDiagnostics)
return new ValidationResult (false, expr.GetDiagnostics().First ().GetMessage());
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++] == ']';
}
}*/
}

View file

@ -0,0 +1,157 @@
//
// NRefactoryExpressionResolverVisitor.cs
//
// Author: Jeffrey Stedfast <jeff@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 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 : CSharpSyntaxWalker
{
readonly List<Replacement> replacements = new List<Replacement> ();
readonly SourceLocation location;
readonly DebuggerSession session;
readonly string expression;
string parentType;
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 ((r1, r2) => r1.Offset.CompareTo (r2.Offset));
var resolved = new StringBuilder ();
int i = 0;
foreach (var replacement in replacements) {
resolved.Append (expression, i, replacement.Offset - i);
resolved.Append (replacement.NewText);
i = replacement.Offset + replacement.Length;
}
var last = replacements [replacements.Count - 1];
resolved.Append (expression, last.Offset + last.Length, expression.Length - (last.Offset + last.Length));
return resolved.ToString ();
}
string GenerateGenericArgs (int genericArgs)
{
if (genericArgs == 0)
return "";
string result = "<";
for (int i = 0; i < genericArgs; i++)
result += "int,";
return result.Remove (result.Length - 1) + ">";
}
void ReplaceType (string name, int genericArgs, int offset, int length, bool memberType = false)
{
string type;
if (genericArgs == 0)
type = session.ResolveIdentifierAsType (name, location);
else
type = session.ResolveIdentifierAsType (name + "`" + genericArgs, location);
if (string.IsNullOrEmpty (type)) {
parentType = null;
} else {
if (memberType) {
type = type.Substring (type.LastIndexOf ('.') + 1);
}
parentType = type + GenerateGenericArgs (genericArgs);
if (type != name) {
var lengthDelta = type.Length - name.Length;
var start = offset - lengthDelta;
if (start >= 0 && expression.Substring(offset - lengthDelta, type.Length) == type)
return;
var replacement = new Replacement { Offset = offset, Length = length, NewText = type };
replacements.Add(replacement);
}
}
}
void ReplaceType (SyntaxNode type)
{
int length = type.Span.Length;
int offset = type.Span.Start;
ReplaceType (type.ToString(), 0, offset, length);
}
public override void VisitIdentifierName (IdentifierNameSyntax node)
{
//base.VisitIdentifierName (node);
var loc = node.Identifier.GetLocation();
int length = loc.SourceSpan.Length;
int offset = loc.SourceSpan.Start;
ReplaceType (node.Identifier.ValueText, node.Arity, offset, length);
}
public override void VisitSimpleBaseType (SimpleBaseTypeSyntax node)
{
ReplaceType (node);
}
public override void VisitPredefinedType (PredefinedTypeSyntax node)
{
ReplaceType (node);
}
public override void VisitGenericName(GenericNameSyntax node)
{
var loc = node.Identifier.GetLocation();
int length = loc.SourceSpan.Length;
int offset = loc.SourceSpan.Start;
ReplaceType(node.Identifier.ValueText, node.TypeArgumentList.Arguments.Count, offset, length);
}
}*/
}

View file

@ -0,0 +1,213 @@
//
// NRefactoryExtensions.cs
//
// Author: Jeffrey Stedfast <jeff@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;
namespace Mono.Debugging.Evaluation
{
/*public static class NRefactoryExtensions
{
#region AstType
public static object Resolve (this TypeSyntax 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 (string.IsNullOrEmpty (name))
return null;
if (args.Count > 0)
return ctx.Adapter.GetType (ctx, name, args.ToArray ());
return ctx.Adapter.GetType (ctx, name);
}
static string Resolve (this ExpressionSyntax type, EvaluationContext ctx, List<object> args)
{
if (type is PredefinedTypeSyntax)
return Resolve ((PredefinedTypeSyntax) type, ctx, args);
else if (type is PointerTypeSyntax)
return Resolve ((PointerTypeSyntax)type, ctx, args);
else if (type is NullableTypeSyntax)
return Resolve ((NullableTypeSyntax)type, ctx, args);
else if (type is RefTypeSyntax)
return Resolve ((RefTypeSyntax)type, ctx, args);
else if (type is QualifiedNameSyntax)
return Resolve ((QualifiedNameSyntax) type, ctx, args);
else if (type is IdentifierNameSyntax)
return Resolve ((IdentifierNameSyntax)type, ctx, args);
else if (type is GenericNameSyntax)
return Resolve ((GenericNameSyntax)type, ctx, args);
return null;
}
#endregion AstType
#region ComposedType
static string Resolve (this PointerTypeSyntax type, EvaluationContext ctx, List<object> args)
{
return type.ElementType.Resolve (ctx, args) + "*";
}
static string Resolve (this RefTypeSyntax type, EvaluationContext ctx, List<object> args)
{
return type.Type.Resolve (ctx, args);
}
static string Resolve (this NullableTypeSyntax type, EvaluationContext ctx, List<object> args)
{
args.Insert (0, type.ElementType.Resolve (ctx));
return "System.Nullable`1";
}
#endregion ComposedType
#region MemberType
static string Resolve (this QualifiedNameSyntax type, EvaluationContext ctx, List<object> args)
{
string name;
if (!(type.Left is AliasQualifiedNameSyntax)) {
var parent = type.Left.Resolve (ctx, args);
name = parent + "." + type.Right.Identifier.ValueText;
} else {
name = type.Right.Identifier.ValueText;
}
if (type.Right is GenericNameSyntax genericName) {
name += "`" + genericName.TypeArgumentList.Arguments.Count;
foreach (var arg in genericName.TypeArgumentList.Arguments) {
object resolved;
if ((resolved = arg.Resolve (ctx)) == null)
return null;
args.Add (resolved);
}
}
return name;
}
#endregion MemberType
#region PrimitiveType
public static string Resolve (this PredefinedTypeSyntax type)
{
switch (type.Keyword.Kind()) {
case SyntaxKind.BoolKeyword: return "System.Boolean";
case SyntaxKind.SByteKeyword: return "System.SByte";
case SyntaxKind.ByteKeyword: return "System.Byte";
case SyntaxKind.CharKeyword: return "System.Char";
case SyntaxKind.ShortKeyword: return "System.Int16";
case SyntaxKind.UShortKeyword: return "System.UInt16";
case SyntaxKind.IntKeyword: return "System.Int32";
case SyntaxKind.UIntKeyword: return "System.UInt32";
case SyntaxKind.LongKeyword: return "System.Int64";
case SyntaxKind.ULongKeyword: return "System.UInt64";
case SyntaxKind.FloatKeyword: return "System.Single";
case SyntaxKind.DoubleKeyword: return "System.Double";
case SyntaxKind.DecimalKeyword: return "System.Decimal";
case SyntaxKind.StringKeyword: return "System.String";
case SyntaxKind.ObjectKeyword: return "System.Object";
case SyntaxKind.VoidKeyword: return "System.Void";
default: return null;
}
}
public static string Resolve(string shortTypeName)
{
string longName;
switch (shortTypeName) {
case "bool": longName = "System.Boolean"; break;
case "byte": longName = "System.Byte"; break;
case "sbyte": longName = "System.SByte"; break;
case "char": longName = "System.Char"; break;
case "decimal": longName = "System.Decimal"; break;
case "double": longName = "System.Double"; break;
case "float": longName = "System.Single"; break;
case "int": longName = "System.Int32"; break;
case "uint": longName = "System.UInt32"; break;
case "nint": longName = "System.IntPtr"; break;
case "nuint": longName = "System.UIntPtr"; break;
case "long": longName = "System.Int64"; break;
case "ulong": longName = "System.UInt64"; break;
case "short": longName = "System.Int16"; break;
case "ushort": longName = "System.UInt16"; break;
case "object": longName = "System.Object"; break;
case "string": longName = "System.String"; break;
case "dynamic": longName = "System.Object"; break;
default: throw new ArgumentException($"Unknown type {shortTypeName}");
}
return longName;
}
static string Resolve (this PredefinedTypeSyntax type, EvaluationContext ctx, List<object> args)
{
return Resolve (type);
}
#endregion PrimitiveType
#region SimpleType
static string Resolve (this GenericNameSyntax type, EvaluationContext ctx, List<object> args)
{
string name = type.Identifier.ValueText;
if (type.TypeArgumentList.Arguments.Count > 0) {
name += "`" + type.TypeArgumentList.Arguments.Count;
foreach (var arg in type.TypeArgumentList.Arguments) {
object resolved;
if ((resolved = arg.Resolve (ctx)) == null)
return null;
args.Add (resolved);
}
}
return type.Identifier.ValueText;
}
static string Resolve (this IdentifierNameSyntax type, EvaluationContext ctx, List<object> args)
{
return type.Identifier.ValueText;
}
#endregion SimpleType
}*/
}

View file

@ -0,0 +1,148 @@
// NamespaceValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using 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)
{
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;
var ctx = GetContext (options);
var type = ctx.Adapter.GetType (ctx, newNs);
if (type != null)
return new TypeValueReference (ctx, type);
return new NamespaceValueReference (ctx, newNs);
}
public override ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
{
var children = new List<ObjectValue> ();
foreach (var val in GetChildReferences (options))
children.Add (val.CreateObjectValue (options));
return children.ToArray ();
}
public override IEnumerable<ValueReference> GetChildReferences (EvaluationOptions options)
{
// Child types
string[] childNamespaces;
string[] childTypes;
var ctx = GetContext (options);
ctx.Adapter.GetNamespaceContents (ctx, namspace, out childNamespaces, out childTypes);
var 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 ((v1, v2) => string.Compare (v1.Name, v2.Name, StringComparison.CurrentCulture));
// Child namespaces
var listNs = new List<ValueReference> ();
foreach (string ns in childNamespaces)
listNs.Add (new NamespaceValueReference (ctx, ns));
listNs.Sort ((v1, v2) => string.Compare (v1.Name, v2.Name, StringComparison.CurrentCulture));
list.AddRange (listNs);
return list;
}
protected override ObjectValue OnCreateObjectValue (EvaluationOptions options)
{
return Mono.Debugging.Client.ObjectValue.CreateObject (this, new ObjectPath (Name), "<namespace>", namspace, Flags, null);
}
public override string CallToString ()
{
return namspace;
}
}
}

View file

@ -0,0 +1,97 @@
// NullValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using 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 (ObjectPath path, int index, int count, EvaluationOptions options)
{
return new ObjectValue [0];
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
// RawViewSource.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using 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 ();
}
}
}

View file

@ -0,0 +1,78 @@
// RemoteFrameObject.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
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) {
#if !NETCOREAPP
System.Runtime.Remoting.RemotingServices.Disconnect (val);
#endif
IDisposable disp = val as IDisposable;
if (disp != null)
disp.Dispose ();
}
connectedValues.Clear ();
}
}
public override object InitializeLifetimeService ()
{
return null;
}
}
}

View file

@ -0,0 +1,241 @@
//
// RemoteRawValue.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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
{
class RemoteRawValue: RemoteFrameObject, IRawValue
{
readonly EvaluationContext ctx;
readonly IObjectSource source;
readonly object targetObject;
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 targetObject; }
}
#region IRawValue implementation
public object CallMethod (string name, object[] parameters, EvaluationOptions options)
{
object[] outArgs;
return CallMethod (name, parameters, false, out outArgs, options);
}
public object CallMethod (string name, object[] parameters, out object[] outArgs, EvaluationOptions options)
{
return CallMethod (name, parameters, true, out outArgs, options);
}
private object CallMethod (string name, object[] parameters, bool enableOutArgs, out object[] outArgs, EvaluationOptions options)
{
var localContext = ctx.WithOptions (options);
var argValues = new object [parameters.Length];
var 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]);
}
var type = localContext.Adapter.GetValueType (localContext, targetObject);
if (enableOutArgs) {
object[] outArgsTemp;
var res = localContext.Adapter.RuntimeInvoke (localContext, type, targetObject, name, null, argTypes, argValues, out outArgsTemp);
outArgs = new object[outArgsTemp.Length];
for (int i = 0; i < outArgs.Length; i++) {
outArgs [i] = localContext.Adapter.ToRawValue (localContext, null, outArgsTemp [i]);
}
return localContext.Adapter.ToRawValue (localContext, null, res);
} else {
outArgs = null;
var res = localContext.Adapter.RuntimeInvoke (localContext, type, targetObject, name, argTypes, argValues);
return localContext.Adapter.ToRawValue (localContext, null, res);
}
}
public object GetMemberValue (string name, EvaluationOptions options)
{
var localContext = ctx.WithOptions (options);
var type = localContext.Adapter.GetValueType (localContext, targetObject);
var 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)
{
var localContext = ctx.WithOptions (options);
var type = localContext.Adapter.GetValueType (localContext, targetObject);
var 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
}
class RemoteRawValueArray: RemoteFrameObject, IRawValueArray
{
readonly ICollectionAdaptor targetArray;
readonly EvaluationContext ctx;
readonly IObjectSource source;
readonly object targetObject;
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 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 ();
var 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 ();
}
}
class RemoteRawValueString: RemoteFrameObject, IRawValueString
{
readonly IStringAdaptor targetString;
readonly object targetObject;
public RemoteRawValueString (IStringAdaptor targetString, object targetObject)
{
this.targetString = targetString;
this.targetObject = targetObject;
Connect ();
}
public object TargetObject {
get { return 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);
}
}
}

View file

@ -0,0 +1,38 @@
// TimeOutException.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
namespace Mono.Debugging.Evaluation
{
public class TimeOutException: EvaluatorException
{
public TimeOutException (): base ("Timed out.")
{
}
}
}

View file

@ -0,0 +1,219 @@
// EvaluationContext.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using System.Threading;
namespace Mono.Debugging.Evaluation
{
public class TimedEvaluator
{
const int maxThreads = 1;
object runningLock = new object ();
Queue<Task> pendingTasks = new Queue<Task> ();
ManualResetEvent newTaskEvent = new ManualResetEvent (false);
AutoResetEvent threadNotBusyEvent = new AutoResetEvent (false);
ManualResetEvent disposedEvent = new ManualResetEvent (false);
List<Task> executingTasks = new List<Task> ();
int runningThreads;
int busyThreads;
bool useTimeout;
bool disposed;
static int threadNameId;
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 || busyThreads > 0;
}
}
}
/// <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 (busyThreads == runningThreads && runningThreads < maxThreads) {
runningThreads++;
var tr = new Thread (Runner);
tr.Name = "Debugger evaluator " + threadNameId++;
tr.IsBackground = true;
tr.Start ();
}
pendingTasks.Enqueue (task);
if (busyThreads == runningThreads) {
task.TimedOut = true;
return false;
}
newTaskEvent.Set ();
}
WaitHandle.WaitAny (new WaitHandle [] { task.RunningEvent, disposedEvent });
if (WaitHandle.WaitAny (new WaitHandle [] { task.RunFinishedEvent, disposedEvent }, TimeSpan.FromMilliseconds (RunTimeout), false) != 0) {
lock (task) {
if (task.Processed) {
return true;
} else {
task.TimedOut = true;
return false;
}
}
}
return true;
}
void Runner ()
{
Task threadTask = null;
while (!disposed) {
if (threadTask == null) {
lock (runningLock) {
if (disposed) {
runningThreads--;
return;
}
if (pendingTasks.Count > 0) {
threadTask = pendingTasks.Dequeue ();
executingTasks.Add (threadTask);
busyThreads++;
} else if (busyThreads + 1 < runningThreads) {
runningThreads--;//If we got extra non-busy threads, close this one...
return;
}
if (threadTask == null) {
newTaskEvent.Reset ();
}
}
//No pending task, wait for it
if (threadTask == null) {
WaitHandle.WaitAny (new WaitHandle [] { newTaskEvent, disposedEvent });
continue;
}
} else {
lock (runningLock) {
executingTasks.Remove (threadTask);
busyThreads--;
}
threadNotBusyEvent.Set ();
threadTask = null;
continue;
}
threadTask.RunningEvent.Set ();
SafeRun (threadTask.Evaluator);
threadTask.RunFinishedEvent.Set ();
lock (threadTask) {
threadTask.Processed = true;
if (threadTask.TimedOut && !disposed) {
SafeRun (threadTask.FinishedCallback);
}
}
}
}
public void Dispose ()
{
lock (runningLock) {
disposed = true;
CancelAll ();
disposedEvent.Set ();
}
}
public void CancelAll ()
{
lock (runningLock) {
pendingTasks.Clear ();
// If there is a task waiting the be picked by the runner,
// set the task wait events to avoid deadlocking the caller.
executingTasks.ForEach (t => {
t.RunningEvent.Set ();
t.RunFinishedEvent.Set ();
});
}
}
public void WaitForStopped ()
{
while (busyThreads > 0) {
threadNotBusyEvent.WaitOne (1000);
}
}
void SafeRun (EvaluatorDelegate del)
{
try {
del ();
} catch {
}
}
class Task
{
public ManualResetEvent RunningEvent = new ManualResetEvent (false);
public ManualResetEvent RunFinishedEvent = new ManualResetEvent (false);
public EvaluatorDelegate Evaluator;
public EvaluatorDelegate FinishedCallback;
public bool TimedOut;
public bool Processed;
}
}
public delegate void EvaluatorDelegate ();
}

View file

@ -0,0 +1,207 @@
// TypeValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
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 dot = tname.LastIndexOf ('.', sep1);
return dot != -1 ? tname.Substring (dot + 1) : 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)
{
var ctx = GetContext (options);
foreach (var val in ctx.Adapter.GetMembers (ctx, this, type, null)) {
if (val.Name == name)
return val;
}
foreach (var nestedType in ctx.Adapter.GetNestedTypes (ctx, type)) {
string typeName = ctx.Adapter.GetTypeName (ctx, nestedType);
if (GetTypeName (typeName) == name)
return new TypeValueReference (ctx, nestedType);
}
return null;
}
public override ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
{
var ctx = GetContext (options);
try {
BindingFlags flattenFlag = options.FlattenHierarchy ? (BindingFlags)0 : BindingFlags.DeclaredOnly;
BindingFlags flags = BindingFlags.Static | BindingFlags.Public | flattenFlag;
bool groupPrivateMembers = options.GroupPrivateMembers || ctx.Adapter.IsExternalType (ctx, type);
var list = new List<ObjectValue> ();
if (!groupPrivateMembers)
flags |= BindingFlags.NonPublic;
var tdata = ctx.Adapter.GetTypeDisplayData (ctx, type);
var tdataType = type;
foreach (var val in ctx.Adapter.GetMembersSorted (ctx, this, type, null, flags)) {
var decType = val.DeclaringType;
if (decType != null && decType != tdataType) {
tdataType = decType;
tdata = ctx.Adapter.GetTypeDisplayData (ctx, decType);
}
var state = tdata.GetMemberBrowsableState (val.Name);
if (state == DebuggerBrowsableState.Never)
continue;
var oval = val.CreateObjectValue (options);
list.Add (oval);
}
var nestedTypes = new List<ObjectValue> ();
foreach (var nestedType in ctx.Adapter.GetNestedTypes (ctx, type))
nestedTypes.Add (new TypeValueReference (ctx, nestedType).CreateObjectValue (options));
nestedTypes.Sort ((v1, v2) => string.Compare (v1.Name, v2.Name, StringComparison.CurrentCulture));
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) {
var baseRef = new TypeValueReference (ctx, baseType);
var baseVal = baseRef.CreateObjectValue (false);
baseVal.Name = "base";
list.Insert (0, baseVal);
}
}
return list.ToArray ();
} catch (Exception ex) {
ctx.WriteDebuggerOutput (ex.Message);
return new ObjectValue [0];
}
}
public override IEnumerable<ValueReference> GetChildReferences (EvaluationOptions options)
{
var ctx = GetContext (options);
try {
var list = new List<ValueReference> ();
list.AddRange (ctx.Adapter.GetMembersSorted (ctx, this, type, null, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static));
var nestedTypes = new List<ValueReference> ();
foreach (var nestedType in ctx.Adapter.GetNestedTypes (ctx, type))
nestedTypes.Add (new TypeValueReference (ctx, nestedType));
nestedTypes.Sort ((v1, v2) => string.Compare (v1.Name, v2.Name, StringComparison.CurrentCulture));
list.AddRange (nestedTypes);
return list;
} catch (Exception ex) {
ctx.WriteDebuggerOutput (ex.Message);
return new ValueReference[0];
}
}
}
}

View file

@ -0,0 +1,71 @@
//
// UserVariableReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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 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;
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;
}
}
}
}

View file

@ -0,0 +1,307 @@
// ValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Collections.Generic;
using 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;
protected ValueReference (EvaluationContext ctx)
{
originalOptions = ctx.Options;
Context = ctx;
}
public virtual object ObjectValue {
get {
object ob = Value;
if (Context.Adapter.IsNull (Context, ob))
return null;
if (Context.Adapter.IsPrimitive (Context, ob))
return Context.Adapter.TargetObjectToObject (Context, 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; set;
}
public EvaluationContext GetContext (EvaluationOptions options)
{
return Context.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), Context.Adapter.GetDisplayTypeName (GetContext (options), Type), Flags);
if (withTimeout) {
return Context.Adapter.CreateObjectValueAsync (Name, Flags, delegate {
return CreateObjectValue (options);
});
}
return CreateObjectValue (options);
}
public ObjectValue CreateObjectValue (EvaluationOptions options)
{
if (!CanEvaluate (options)) {
if (options.AllowTargetInvoke)//If it can't evaluate and target invoke is allowed, mark it as not supported.
return DC.ObjectValue.CreateNotSupported (this, new ObjectPath (Name), Context.Adapter.GetDisplayTypeName (GetContext (options), Type), "Can not evaluate", Flags);
return DC.ObjectValue.CreateImplicitNotSupported (this, new ObjectPath (Name), Context.Adapter.GetDisplayTypeName (GetContext (options), Type), Flags);
}
Connect ();
try {
return OnCreateObjectValue (options);
} catch (ImplicitEvaluationDisabledException) {
return DC.ObjectValue.CreateImplicitNotSupported (this, new ObjectPath (Name), Context.Adapter.GetDisplayTypeName (GetContext (options), Type), Flags);
} catch (NotSupportedExpressionException ex) {
return DC.ObjectValue.CreateNotSupported (this, new ObjectPath (Name), Context.Adapter.GetDisplayTypeName (GetContext (options), Type), ex.Message, Flags);
} catch (EvaluatorException ex) {
return DC.ObjectValue.CreateError (this, new ObjectPath (Name), Context.Adapter.GetDisplayTypeName (GetContext (options), Type), ex.Message, Flags);
} catch (Exception ex) {
Context.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 = "?";
var ctx = GetContext (options);
object val = null;
// Note: The Value property implementation may make use of the EvaluationOptions,
// so we need to override our context temporarily to do the evaluation.
val = GetValue (ctx);
if (val != null && !ctx.Adapter.IsNull (ctx, val))
return ctx.Adapter.CreateObjectValue (ctx, this, new ObjectPath (name), val, Flags);
return DC.ObjectValue.CreateNullObject (this, name, ctx.Adapter.GetDisplayTypeName (ctx.Adapter.GetTypeName (ctx, Type)), Flags);
}
ObjectValue IObjectValueSource.GetValue (ObjectPath path, EvaluationOptions options)
{
return CreateObjectValue (true, options);
}
EvaluationResult IObjectValueSource.SetValue (ObjectPath path, string value, EvaluationOptions options)
{
try {
Context.WaitRuntimeInvokes ();
var ctx = GetContext (options);
ctx.Options.AllowMethodEvaluation = true;
ctx.Options.AllowTargetInvoke = true;
var vref = ctx.Evaluator.Evaluate (ctx, value, Type);
var newValue = ctx.Adapter.Convert (ctx, vref.Value, Type);
SetValue (ctx, newValue);
} catch (Exception ex) {
Context.WriteDebuggerError (ex);
Context.WriteDebuggerOutput ("Value assignment failed: {0}: {1}\n", ex.GetType (), ex.Message);
}
try {
return Context.Evaluator.TargetObjectToExpression (Context, Value);
} catch (Exception ex) {
Context.WriteDebuggerError (ex);
Context.WriteDebuggerOutput ("Value assignment failed: {0}: {1}\n", ex.GetType (), ex.Message);
}
return null;
}
object IObjectValueSource.GetRawValue (ObjectPath path, EvaluationOptions options)
{
var ctx = GetContext (options);
return ctx.Adapter.ToRawValue (ctx, this, GetValue (ctx));
}
void IObjectValueSource.SetRawValue (ObjectPath path, object value, EvaluationOptions options)
{
SetRawValue (path, value, options);
}
public object GetRawValue (EvaluationOptions options)
{
var ctx = GetContext (options);
return ctx.Adapter.ToRawValue (ctx, this, GetValue (ctx));
}
public void SetRawValue (object value, EvaluationOptions options)
{
SetRawValue (new ObjectPath (), value, options);
}
protected virtual void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
{
var ctx = GetContext (options);
SetValue (ctx, Context.Adapter.FromRawValue (ctx, value));
}
ObjectValue[] IObjectValueSource.GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
{
return GetChildren (path, index, count, options);
}
public virtual string CallToString ()
{
return Context.Adapter.CallToString (Context, Value);
}
public virtual object GetValue (EvaluationContext ctx)
{
return Value;
}
public virtual void SetValue (EvaluationContext ctx, object value)
{
Value = value;
}
[Obsolete ("Use GetValue(EvaluationContext) instead.")]
protected virtual object GetValueExplicitly ()
{
var options = Context.Options.Clone ();
options.AllowTargetInvoke = true;
var ctx = GetContext (options);
return GetValue (ctx);
}
public virtual ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
{
try {
var ctx = GetChildrenContext (options);
return ctx.Adapter.GetObjectValueChildren (ctx, this, GetValue (ctx), index, count);
} catch (Exception ex) {
return new [] { DC.ObjectValue.CreateFatalError ("", ex.Message, ObjectValueFlags.ReadOnly) };
}
}
public virtual IEnumerable<ValueReference> GetChildReferences (EvaluationOptions options)
{
try {
object val = Value;
if (Context.Adapter.IsClassInstance (Context, val))
return Context.Adapter.GetMembersSorted (GetChildrenContext (options), this, Type, val);
} catch {
// Ignore
}
return new ValueReference [0];
}
public IObjectSource ParentSource { get; set; }
protected EvaluationContext GetChildrenContext (EvaluationOptions options)
{
var ctx = Context.Clone ();
if (options != null)
ctx.Options = options;
ctx.Options.EvaluationTimeout = originalOptions.MemberEvaluationTimeout;
return ctx;
}
public virtual ValueReference GetChild (ObjectPath vpath, EvaluationOptions options)
{
if (vpath.Length == 0)
return this;
var val = GetChild (vpath[0], options);
return val != null ? val.GetChild (vpath.GetSubpath (1), options) : null;
}
public virtual 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
var tokens = name.Substring (1, name.Length - 2).Split (',');
var indices = new int [tokens.Length];
for (int n = 0; n < tokens.Length; n++)
indices[n] = int.Parse (tokens[n]);
return new ArrayValueReference (Context, obj, indices);
}
if (Context.Adapter.IsClassInstance (Context, obj))
return Context.Adapter.GetMember (GetChildrenContext (options), this, Type, obj, name);
return null;
}
}
}

View file

@ -0,0 +1,102 @@
//
// ArrayAdaptor.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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
{
readonly ArrayMirror array;
int[] dimensions, bounds;
public ArrayAdaptor (ArrayMirror array)
{
this.array = array;
}
public int[] GetLowerBounds ()
{
if (bounds == null) {
bounds = new int[array.Rank];
for (int i = 0; i < array.Rank; i++)
bounds[i] = array.GetLowerBound (i);
}
return bounds;
}
public int[] GetDimensions ()
{
if (dimensions == null) {
dimensions = new int[array.Rank];
for (int i = 0; i < array.Rank; i++)
dimensions[i] = array.GetLength (i);
}
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 ();
var lowerBounds = GetLowerBounds ();
for (int n = indices.Length - 1; n >= 0; n--) {
i += (indices [n] - lowerBounds [n]) * ts;
ts *= dims [n];
}
return i;
}
public object ElementType {
get {
return array.Type.GetElementType ();
}
}
}
}

View file

@ -0,0 +1,66 @@
//
// FieldReferenceBatch.cs
//
// Authors: David Karlaš <david.karlas@xamarin.com>
//
// Copyright (c) 2014 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 Mono.Debugger.Soft;
using System.Collections.Generic;
namespace Mono.Debugging.Soft
{
public class FieldReferenceBatch
{
readonly object locker = new object ();
readonly object obj;
List<FieldInfoMirror> fields = new List<FieldInfoMirror> ();
object[] results;
public FieldReferenceBatch (object obj)
{
this.obj = obj;
}
public void Add (FieldInfoMirror fieldVal)
{
lock (locker) {
fields.Add (fieldVal);
}
}
public object GetValue (FieldInfoMirror field)
{
lock (locker) {
if (results == null || fields.Count != results.Length)
results = ((ObjectMirror)obj).GetValues (fields);
return results [fields.IndexOf (field)];
}
}
public void Invalidate ()
{
lock (locker) {
results = null;
}
}
}
}

View file

@ -0,0 +1,213 @@
//
// FieldValueReference.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@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;
using System.Collections.Generic;
using System.Linq;
namespace Mono.Debugging.Soft
{
public class FieldValueReference: SoftValueReference
{
FieldInfoMirror field;
object obj;
TypeMirror declaringType;
ObjectValueFlags flags;
string vname;
FieldReferenceBatch batch;
public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, FieldReferenceBatch batch = null)
: this (ctx, field, obj, declaringType, null, ObjectValueFlags.Field, batch)
{
}
public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, string vname, ObjectValueFlags vflags, FieldReferenceBatch batch = null): base (ctx)
{
this.field = field;
this.obj = obj;
this.declaringType = declaringType;
this.vname = vname;
this.batch = batch;
if (field.IsStatic)
this.obj = null;
var objectMirror = obj as ObjectMirror;
if (objectMirror != null)
EnsureContextHasDomain (objectMirror.Domain);
flags = GetFlags (field);
// if `vflags` already has an origin specified, we need to unset the `Field` flag which is always returned by GetFlags().
if ((vflags & ObjectValueFlags.OriginMask) != 0)
flags &= ~ObjectValueFlags.Field;
flags |= vflags;
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, ((SoftEvaluationContext)Context).Thread);
} else if (obj is ObjectMirror) {
if (batch != null)
return batch.GetValue (field);
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) {
if (batch != null)
batch.Invalidate ();
((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 ();
}
}
internal string [] GetTupleElementNames ()
{
return GetTupleElementNames (field.GetCustomAttributes (true));
}
internal static string [] GetTupleElementNames (CustomAttributeDataMirror [] attrs)
{
var attr = attrs.FirstOrDefault (at => at.Constructor.DeclaringType.Name == "TupleElementNamesAttribute");
if (attr == null)
return null;
var attributeValue = attr.ConstructorArguments.Single ().Value;
var array = attributeValue as ArrayMirror;
if (array == null)
return null;
var values = array.GetValues (0, array.Length);
if (!values.Any ())
return null;
var result = new string [values.Count];
for (int i = 0; i < result.Length; i++) {
if (values [i] is StringMirror s)//other than string is null
result [i] = s.Value;
}
return result;
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Debugging.Client;
namespace Mono.Debugging.Soft
{
[Serializable]
public class InstructionBreakpoint : Breakpoint
{
public string MethodName { get; set; }
public long ILOffset { get; private set; }
public InstructionBreakpoint (string fileName, int line, int column, long ilOffset) : base (fileName, line, column)
{
this.ILOffset = ilOffset;
}
}
}

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Mono.Debugging.Soft
{
public class JsonSourceLink
{
public Dictionary<string, string> Maps { get; set; }
}
}

View file

@ -0,0 +1,83 @@
//
// LocalVariableValueBatch.cs
//
// Author: Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2014 Xamarin Inc. (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.Debugger.Soft;
namespace Mono.Debugging.Soft
{
public class LocalVariableBatch
{
readonly LocalVariable[] variables;
Value[] values;
int version;
public LocalVariableBatch (LocalVariable[] variables)
{
this.variables = variables;
}
public Value GetValue (SoftEvaluationContext ctx, LocalVariable variable)
{
if (variable == null)
throw new ArgumentNullException ("variable");
if (values == null || version != ctx.Session.StackVersion) {
values = ctx.Frame.GetValues (variables);
version = ctx.Session.StackVersion;
}
for (int i = 0; i < variables.Length; i++) {
if (variable == variables[i])
return values[i];
}
throw new ArgumentOutOfRangeException ("variable");
}
public void SetValue (SoftEvaluationContext ctx, LocalVariable variable, Value value)
{
var canUpdateCache = values != null && version == ctx.Session.StackVersion;
ctx.Frame.SetValue (variable, value);
ctx.Session.StackVersion++;
if (canUpdateCache) {
for (int i = 0; i < variables.Length; i++) {
if (variable == variables[i]) {
values[i] = value;
break;
}
}
version = ctx.Session.StackVersion;
} else {
values = null;
version = 0;
}
}
}
}

View file

@ -0,0 +1,171 @@
//
// PortablePdbData.cs
//
// Author:
// David Karlaš <david.karlas@xamarin.com>
//
// Copyright (c) 2017 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.Debugger.Soft;
using System.IO;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Linq;
namespace Mono.Debugging.Soft
{
class PortablePdbData
{
static readonly Guid AsyncMethodSteppingInformationBlob = new Guid ("54FD2AC5-E925-401A-9C2A-F94F171072F8");
static readonly Guid StateMachineHoistedLocalScopes = new Guid ("6DA9A61E-F8C7-4874-BE62-68BC5630DF71");
static readonly Guid DynamicLocalVariables = new Guid ("83C563C4-B4F3-47D5-B824-BA5441477EA8");
static readonly Guid TupleElementNames = new Guid ("ED9FDF71-8879-4747-8ED3-FE5EDE3CE710");
static readonly Guid DefaultNamespace = new Guid ("58b2eab6-209f-4e4e-a22c-b2d0f910c782");
static readonly Guid EncLocalSlotMap = new Guid ("755F52A8-91C5-45BE-B4B8-209571E552BD");
static readonly Guid EncLambdaAndClosureMap = new Guid ("A643004C-0240-496F-A783-30D64F4979DE");
static readonly Guid SourceLinkGuid = new Guid ("CC110556-A091-4D38-9FEC-25AB9A351A6A");
static readonly Guid EmbeddedSource = new Guid ("0E8A571B-6926-466E-B4AD-8AB04611F5FE");
public static bool IsPortablePdb (string pdbFileName)
{
if (string.IsNullOrEmpty (pdbFileName) || !File.Exists (pdbFileName))
return false;
using (var file = new FileStream (pdbFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
var data = new byte [4];
int read = file.Read (data, 0, data.Length);
return read == 4 && BitConverter.ToUInt32 (data, 0) == 0x424a5342;
}
}
readonly byte [] pdbBytes;
private readonly string pdbFileName;
public PortablePdbData (string pdbFileName)
{
this.pdbFileName = Path.GetFullPath (pdbFileName);
}
public PortablePdbData (byte [] pdbBytes)
{
this.pdbBytes = pdbBytes ?? throw new ArgumentNullException (nameof(pdbBytes));
}
internal class SoftScope
{
public int LiveRangeStart;
public int LiveRangeEnd;
}
Stream GetStream()
{
if (pdbBytes != null)
return new MemoryStream (pdbBytes);
return new FileStream (pdbFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
}
public string GetSourceLinkBlob ()
{
/*using (var provider = MetadataReaderProvider.FromPortablePdbStream (GetStream ())) {
var pdbReader = provider.GetMetadataReader ();
var jsonBlob =
pdbReader.GetCustomDebugInformation (EntityHandle.ModuleDefinition)
.Select (cdiHandle => pdbReader.GetCustomDebugInformation (cdiHandle))
.Where (cdi => pdbReader.GetGuid (cdi.Kind) == SourceLinkGuid)
.Select (cdi => pdbReader.GetBlobBytes (cdi.Value))
.FirstOrDefault ();
if (jsonBlob == null)
return null;
return System.Text.Encoding.UTF8.GetString (jsonBlob);
}*/
return null;
}
// We need proxy method to make sure VS2013/15 doesn't crash(this method won't be called if portable .pdb file doesn't exist, which means 2017+)
[MethodImpl (MethodImplOptions.NoInlining)]
internal SoftScope [] GetHoistedScopes (MethodMirror method) => GetHoistedScopesPrivate (method);
internal SoftScope [] GetHoistedScopesPrivate (MethodMirror method)
{
/*using (var metadataReader = MetadataReaderProvider.FromPortablePdbStream (GetStream ())) {
var reader = metadataReader.GetMetadataReader ();
var methodHandle = MetadataTokens.MethodDefinitionHandle (method.MetadataToken);
var customDebugInfos = reader.GetCustomDebugInformation (methodHandle);
foreach (var item in customDebugInfos) {
var debugInfo = reader.GetCustomDebugInformation (item);
if (reader.GetGuid (debugInfo.Kind) == StateMachineHoistedLocalScopes) {
var bytes = reader.GetBlobBytes (debugInfo.Value);
var result = new SoftScope [bytes.Length / 8];
for (int i = 0; i < bytes.Length; i += 8) {
var offset = BitConverter.ToInt32 (bytes, i);
var len = BitConverter.ToInt32 (bytes, i + 4);
result [i / 8] = new SoftScope () {
LiveRangeStart = offset,
LiveRangeEnd = offset + len
};
}
return result;
}
}
}*/
return null;
}
// We need proxy method to make sure VS2013/15 doesn't crash(this method won't be called if portable .pdb file doesn't exist, which means 2017+)
[MethodImpl (MethodImplOptions.NoInlining)]
internal string [] GetTupleElementNames (MethodMirror method, int localVariableIndex) => TupleElementNamesPrivate (method, localVariableIndex);
/*private static string [] DecodeTupleElementNames (BlobReader reader)
{
var list = new List<string> ();
while (reader.RemainingBytes > 0) {
int byteCount = reader.IndexOf (0);
string value = reader.ReadUTF8 (byteCount);
byte terminator = reader.ReadByte ();
list.Add (value.Length == 0 ? null : value);
}
return list.ToArray ();
}*/
internal string [] TupleElementNamesPrivate (MethodMirror method, int localVariableIndex)
{
/*using (var metadataReader = MetadataReaderProvider.FromPortablePdbStream (GetStream())) {
var reader = metadataReader.GetMetadataReader ();
var methodHandle = MetadataTokens.MethodDefinitionHandle (method.MetadataToken);
var localScopes = reader.GetLocalScopes (methodHandle);
// localVariableIndex is not really il_index, but sequential index when fetching locals
// hence use Skip(index) instead of Index matching.
var localVar = localScopes.Select (s => reader.GetLocalScope (s)).SelectMany (s => s.GetLocalVariables ()).Skip (localVariableIndex).First ();
var customDebugInfos = reader.GetCustomDebugInformation (localVar);
foreach (var item in customDebugInfos) {
var debugInfo = reader.GetCustomDebugInformation (item);
if (reader.GetGuid (debugInfo.Kind) == TupleElementNames) {
return DecodeTupleElementNames (reader.GetBlobReader (debugInfo.Value));
}
}
}*/
return null;
}
}
}

View file

@ -0,0 +1,182 @@
//
// PropertyValueReference.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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 Mono.Debugging.Evaluation;
using Mono.Debugger.Soft;
using Mono.Debugging.Client;
using System;
using System.Collections.Generic;
namespace Mono.Debugging.Soft
{
public class PropertyValueReference: SoftValueReference
{
PropertyInfoMirror property;
TypeMirror declaringType;
ObjectValueFlags flags;
MethodMirror getter;
Value[] indexerArgs;
object obj, value;
bool haveValue;
bool safe;
public PropertyValueReference (EvaluationContext ctx, PropertyInfoMirror property, object obj, TypeMirror declaringType, MethodMirror getter, Value[] indexerArgs): base (ctx)
{
this.safe = Context.Adapter.IsSafeToInvokeMethod (ctx, getter, obj ?? declaringType);
this.declaringType = declaringType;
this.indexerArgs = indexerArgs;
this.property = property;
this.getter = getter;
this.obj = obj;
if (getter.IsStatic)
this.obj = null;
var objectMirror = obj as ObjectMirror;
if (objectMirror != null)
EnsureContextHasDomain (objectMirror.Domain);
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 {
return GetValue (Context);
}
set {
SetValue (Context, value);
}
}
public override object GetValue (EvaluationContext ctx)
{
if (!haveValue) {
if (!safe)
throw new EvaluatorException ("This property is not safe to evaluate.");
value = ((SoftEvaluationContext) ctx).RuntimeInvoke (getter, obj ?? declaringType, indexerArgs);
haveValue = true;
}
return value;
}
public override void SetValue (EvaluationContext ctx, object value)
{
ctx.AssertTargetInvokeAllowed ();
var args = new Value [indexerArgs != null ? indexerArgs.Length + 1 : 1];
if (indexerArgs != null)
indexerArgs.CopyTo (args, 0);
args [args.Length - 1] = (Value) value;
var setter = property.GetSetMethod (true);
if (setter == null)
throw new EvaluatorException ("Property is read-only");
this.value = null;
haveValue = false;
((SoftEvaluationContext) ctx).RuntimeInvoke (setter, obj ?? declaringType, args);
this.value = value;
haveValue = true;
}
protected override bool CanEvaluate (EvaluationOptions options)
{
if (options.AllowTargetInvoke)
return safe;
if (!safe)
return false;
try {
GetValue (Context.WithOptions (options));
return true;
} catch (ImplicitEvaluationDisabledException) {
return false;
}
}
internal string [] GetTupleElementNames ()
{
return FieldValueReference.GetTupleElementNames (property.GetCustomAttributes (true));
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,232 @@
//
// SoftDebuggerBacktrace.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@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
{
readonly SoftDebuggerSession session;
readonly MDB.ThreadMirror thread;
readonly int stackVersion;
MDB.StackFrame[] frames;
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;
}
if (string.IsNullOrEmpty (methodName))
methodName = "[Function Without 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 external = false;
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;
if (hiddenAttr != null)
hidden = method.GetCustomAttributes (hiddenAttr, true).Any ();
}
if (hidden) {
external = true;
} else {
external = session.IsExternalCode (frame);
if (!external && session.Options.ProjectAssembliesOnly && session.VirtualMachine.Version.AtLeast (2, 21)) {
var ctx = GetEvaluationContext (frameIndex, session.EvaluationOptions);
var nonUserCodeAttr = session.Adaptor.GetType (ctx, "System.Diagnostics.DebuggerNonUserCodeAttribute") as MDB.TypeMirror;
if (nonUserCodeAttr != null)
external = method.GetCustomAttributes (nonUserCodeAttr, true).Any ();
}
}
var sourceLink = session.GetSourceLink (frame.Method, frame.FileName);
var location = new DC.SourceLocation (methodName, fileName, frame.LineNumber, frame.ColumnNumber, frame.Location.EndLineNumber, frame.Location.EndColumnNumber, frame.Location.SourceFileHash, sourceLink);
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;
var 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);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,215 @@
//
// SoftDebuggerStartInfo.cs
//
// Author:
// Michael Hutchinson <mhutchinson@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>
/// A mapping of AssemblyNames to their symbol paths. If no symbols maps are provided, the symbols will be found next to the assemblies in AssemblyPathMap.
/// </summary>
public Dictionary<string, string> SymbolPathMap { 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
{
protected 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
{
protected 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; }
/// <summary>
/// Gets or sets the name of the mono executable file. e.g. "mono", "mono32", "mono64"...
/// </summary>
public string MonoExecutableFileName { get; set; }
public override ISoftDebuggerConnectionProvider ConnectionProvider { get { return null; } }
internal Mono.Debugger.Soft.LaunchOptions.ProcessLauncher CustomProcessLauncher { get; set; }
}
}

View file

@ -0,0 +1,226 @@
//
// SoftEvaluationContext.cs
//
// Author:
// Lluis Sanchez Gual <lluis@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;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Mono.Debugging.Soft
{
public class SoftEvaluationContext: EvaluationContext
{
SoftDebuggerSession session;
int stackVersion;
StackFrame frame;
bool sourceAvailable;
public ThreadMirror Thread { get; set; }
public AppDomainMirror Domain { get; set; }
public SoftEvaluationContext (SoftDebuggerSession session, StackFrame frame, DC.EvaluationOptions options): base (options)
{
Frame = frame;
Thread = frame.Thread;
Domain = frame.Domain;
string method = frame.Method.Name;
if (frame.Method.DeclaringType != null)
method = frame.Method.DeclaringType.FullName + "." + method;
var sourceLink = session.GetSourceLink(frame.Method, frame.FileName);
var location = new DC.SourceLocation (method, frame.FileName, frame.LineNumber, frame.ColumnNumber, frame.EndLineNumber, frame.EndColumnNumber, frame.Location.SourceFileHash, sourceLink);
string language;
if (frame.Method != null) {
language = frame.IsNativeTransition ? "Transition" : "Managed";
} else {
language = "Native";
}
Evaluator = session.GetEvaluator (new DC.StackFrame (frame.ILOffset, location, language, session.IsExternalCode (frame), true));
Adapter = session.Adaptor;
this.session = session;
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);
var other = (SoftEvaluationContext) ctx;
frame = other.frame;
stackVersion = other.stackVersion;
Thread = other.Thread;
session = other.session;
Domain = other.Domain;
}
internal 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)
{
Value[] outArgs;
return RuntimeInvoke (method, target, values, false, out outArgs);
}
public Value RuntimeInvoke (MethodMirror method, object target, Value[] values, out Value[] outArgs)
{
return RuntimeInvoke (method, target, values, true, out outArgs);
}
Value RuntimeInvoke (MethodMirror method, object target, Value[] values, bool enableOutArgs, out Value[] outArgs)
{
outArgs = null;
if (values != null) {
// Some arguments may need to be boxed
var 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++) {
var tm = mparams[n].ParameterType;
if (tm.IsValueType || tm.IsPrimitive || tm.FullName.StartsWith ("System.Nullable`1", StringComparison.Ordinal))
continue;
var type = Adapter.GetValueType (this, values[n]);
var argTypeMirror = type as TypeMirror;
var 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);
var targetTypeMirror = type as TypeMirror;
var 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.");
}
}
}
try {
return method.Evaluate (target is TypeMirror ? null : (Value) target, values);
} catch (NotSupportedException) {
AssertTargetInvokeAllowed ();
var threadState = Thread.ThreadState;
if ((threadState & ThreadState.WaitSleepJoin) == ThreadState.WaitSleepJoin) {
DC.DebuggerLoggingService.LogMessage ("Thread state before evaluation is {0}", threadState);
throw new EvaluatorException ("Evaluation is not allowed when the thread is in 'Wait' state");
}
var mc = new MethodCall (this, method, target, values, enableOutArgs);
//Since runtime is returning NOT_SUSPENDED error if two methods invokes are executed
//at same time we have to lock invoking to prevent this...
lock (method.VirtualMachine) {
Adapter.AsyncExecute (mc, Options.EvaluationTimeout);
}
if (enableOutArgs) {
outArgs = mc.OutArgs;
}
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;
}
}
}
public override bool SupportIEnumerable {
get {
return session.VirtualMachine.Version.AtLeast (2, 35);
}
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using Mono.Debugging.Evaluation;
using Mono.Debugger.Soft;
namespace Mono.Debugging.Soft
{
public abstract class SoftValueReference: ValueReference
{
public SoftValueReference (EvaluationContext ctx) : base(ctx)
{
}
protected void EnsureContextHasDomain (AppDomainMirror domain)
{
var softEvaluationContext = (SoftEvaluationContext)Context;
if (softEvaluationContext.Domain == domain)
return;
var clone = (SoftEvaluationContext)softEvaluationContext.Clone ();
clone.Domain = domain;
Context = clone;
}
}
}

View file

@ -0,0 +1,14 @@
namespace Mono.Debugging.Soft
{
internal class SourceLinkMap
{
public string RelativePathWildcard { get; }
public string UriWildcard { get; }
public SourceLinkMap (string relativePathWildcard, string uriWildcard)
{
UriWildcard = uriWildcard;
RelativePathWildcard = relativePathWildcard;
}
}
}

View file

@ -0,0 +1,75 @@
//
// StringAdaptor.cs
//
// Author: Jeffrey Stedfast <jeff@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 Mono.Debugging.Evaluation;
using Mono.Debugger.Soft;
namespace Mono.Debugging.Soft
{
public class StringAdaptor: IStringAdaptor
{
readonly bool atleast_2_10;
readonly 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);
}
}
}

Some files were not shown because too many files have changed in this diff Show more