Browse Source

Merged partial classes

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5115 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
abbec177d9
  1. 6
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
  2. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/CollectionWithEvents.cs
  3. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger.cs
  4. 349
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs
  5. 462
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs
  6. 28
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/ProcessEventArgs.cs
  7. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs
  8. 52
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/GetValueException.cs
  9. 115
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.Array.cs
  10. 262
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.Object.cs
  11. 66
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.Primitive.cs
  12. 538
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.cs

6
src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj

@ -66,7 +66,7 @@ @@ -66,7 +66,7 @@
<Compile Include="Src\Control\AppDomainCollection.cs" />
<Compile Include="Src\Control\EvalCollection.cs" />
<Compile Include="Src\Control\ModuleCollection.cs" />
<Compile Include="Src\Control\Process-StateControl.cs" />
<Compile Include="Src\Control\ProcessEventArgs.cs" />
<Compile Include="Src\Control\ThreadCollection.cs" />
<Compile Include="Src\Control\Process.cs" />
<Compile Include="Src\Control\StackFrame.cs" />
@ -270,10 +270,8 @@ @@ -270,10 +270,8 @@
<Compile Include="Src\Util\HighPrecisionTimer.cs" />
<Compile Include="Src\Values\ArrayDimension.cs" />
<Compile Include="Src\Values\ArrayDimensions.cs" />
<Compile Include="Src\Values\Value.Array.cs" />
<Compile Include="Src\Values\GetValueException.cs" />
<Compile Include="Src\Values\Value.cs" />
<Compile Include="Src\Values\Value.Object.cs" />
<Compile Include="Src\Values\Value.Primitive.cs" />
<Compile Include="Src\Wrappers\CorDebug\Autogenerated\CorDebug.cs" />
<Compile Include="Src\Wrappers\CorDebug\Autogenerated\CorDebugChainReason.cs" />
<Compile Include="Src\Wrappers\CorDebug\Autogenerated\CorDebugClass.cs" />

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/CollectionWithEvents.cs

@ -88,7 +88,7 @@ namespace Debugger @@ -88,7 +88,7 @@ namespace Debugger
if (list.Remove(item)) {
OnRemoved(item);
} else {
throw new DebuggerException("Item is not in the collecti");
throw new DebuggerException("Item is not in the collection");
}
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger.cs

@ -16,7 +16,7 @@ using Debugger.Wrappers.CorDebug; @@ -16,7 +16,7 @@ using Debugger.Wrappers.CorDebug;
namespace Debugger
{
public partial class NDebugger: DebuggerObject
public class NDebugger: DebuggerObject
{
ICorDebug corDebug;
ManagedCallbackSwitch managedCallbackSwitch;

349
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs

@ -1,349 +0,0 @@ @@ -1,349 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.NRefactory.Ast;
using System;
using System.Collections.Generic;
namespace Debugger
{
internal enum DebuggeeStateAction { Keep, Clear }
public partial class Process
{
internal bool TerminateCommandIssued = false;
internal Queue<Breakpoint> BreakpointHitEventQueue = new Queue<Breakpoint>();
internal Dictionary<INode, Value> CachedExpressions = new Dictionary<INode, Value>();
#region Events
public event EventHandler<ProcessEventArgs> Paused;
public event EventHandler<ProcessEventArgs> Resumed;
// HACK: public
public virtual void OnPaused()
{
AssertPaused();
// No real purpose - just additional check
if (callbackInterface.IsInCallback) throw new DebuggerException("Can not raise event within callback.");
TraceMessage ("Debugger event: OnPaused()");
if (Paused != null) {
foreach(Delegate d in Paused.GetInvocationList()) {
if (IsRunning) {
TraceMessage ("Skipping OnPaused delegate because process has resumed");
break;
}
if (this.TerminateCommandIssued || this.HasExited) {
TraceMessage ("Skipping OnPaused delegate because process has exited");
break;
}
d.DynamicInvoke(this, new ProcessEventArgs(this));
}
}
}
protected virtual void OnResumed()
{
AssertRunning();
// No real purpose - just additional check
if (callbackInterface.IsInCallback) throw new DebuggerException("Can not raise event within callback.");
TraceMessage ("Debugger event: OnResumed()");
if (Resumed != null) {
Resumed(this, new ProcessEventArgs(this));
}
}
#endregion
#region PauseSession & DebugeeState
PauseSession pauseSession;
DebuggeeState debuggeeState;
/// <summary>
/// Indentification of the current debugger session. This value changes whenever debugger is continued
/// </summary>
public PauseSession PauseSession {
get {
return pauseSession;
}
}
/// <summary>
/// Indentification of the state of the debugee. This value changes whenever the state of the debugee significatntly changes
/// </summary>
public DebuggeeState DebuggeeState {
get {
return debuggeeState;
}
}
/// <summary> Puts the process into a paused state </summary>
internal void NotifyPaused(PausedReason pauseReason)
{
AssertRunning();
pauseSession = new PauseSession(this, pauseReason);
if (debuggeeState == null) {
debuggeeState = new DebuggeeState(this);
}
}
/// <summary> Puts the process into a resumed state </summary>
internal void NotifyResumed(DebuggeeStateAction action)
{
AssertPaused();
pauseSession = null;
if (action == DebuggeeStateAction.Clear) {
if (debuggeeState == null) throw new DebuggerException("Debugee state already cleared");
debuggeeState = null;
this.CachedExpressions.Clear();
}
}
/// <summary> Sets up the eviroment and raises user events </summary>
internal void RaisePausedEvents()
{
DisableAllSteppers();
CheckSelectedStackFrames();
SelectMostRecentStackFrameWithLoadedSymbols();
if (this.PauseSession.PausedReason == PausedReason.Exception) {
ExceptionEventArgs args = new ExceptionEventArgs(this, this.SelectedThread.CurrentException, this.SelectedThread.CurrentExceptionType, this.SelectedThread.CurrentExceptionIsUnhandled);
OnExceptionThrown(args);
// The event could have resumed or killed the process
if (this.IsRunning || this.TerminateCommandIssued || this.HasExited) return;
}
while(BreakpointHitEventQueue.Count > 0) {
Breakpoint breakpoint = BreakpointHitEventQueue.Dequeue();
breakpoint.NotifyHit();
// The event could have resumed or killed the process
if (this.IsRunning || this.TerminateCommandIssued || this.HasExited) return;
}
OnPaused();
// The event could have resumed the process
if (this.IsRunning || this.TerminateCommandIssued || this.HasExited) return;
}
#endregion
#region Exceptions
bool pauseOnHandledException = false;
public event EventHandler<ExceptionEventArgs> ExceptionThrown;
public bool PauseOnHandledException {
get {
return pauseOnHandledException;
}
set {
pauseOnHandledException = value;
}
}
protected internal virtual void OnExceptionThrown(ExceptionEventArgs e)
{
TraceMessage ("Debugger event: OnExceptionThrown()");
if (ExceptionThrown != null) {
ExceptionThrown(this, e);
}
}
#endregion
internal void AssertPaused()
{
if (IsRunning) {
throw new DebuggerException("Process is not paused.");
}
}
internal void AssertRunning()
{
if (IsPaused) {
throw new DebuggerException("Process is not running.");
}
}
public bool IsRunning {
get {
return pauseSession == null;
}
}
public bool IsPaused {
get {
return !IsRunning;
}
}
public void Break()
{
AssertRunning();
corProcess.Stop(uint.MaxValue); // Infinite; ignored anyway
NotifyPaused(PausedReason.ForcedBreak);
RaisePausedEvents();
}
public void Detach()
{
if (IsRunning) {
corProcess.Stop(uint.MaxValue);
NotifyPaused(PausedReason.ForcedBreak);
}
corProcess.Detach();
NotifyHasExited();
}
#region Convenience methods
public void Continue()
{
AsyncContinue();
WaitForPause();
}
#endregion
public void AsyncContinue()
{
AsyncContinue(DebuggeeStateAction.Clear);
}
internal void AsyncContinue(DebuggeeStateAction action)
{
AssertPaused();
NotifyResumed(action);
corProcess.Continue(0);
if (this.Options.Verbose) {
this.TraceMessage("Continue");
}
if (action == DebuggeeStateAction.Clear) {
OnResumed();
}
}
/// <summary> Terminates the execution of the process </summary>
public void Terminate()
{
AsyncTerminate();
// Wait until ExitProcess callback is received
WaitForExit();
}
/// <summary> Terminates the execution of the process </summary>
public void AsyncTerminate()
{
// Resume stoped tread
if (this.IsPaused) {
// We might get more callbacks so we should maintain consistent sate
//AsyncContinue(); // Continue the process to get remaining callbacks
}
// Expose race condition - drain callback queue
System.Threading.Thread.Sleep(0);
// Stop&terminate - both must be called
corProcess.Stop(uint.MaxValue);
corProcess.Terminate(0);
this.TerminateCommandIssued = true;
// Do not mark the process as exited
// This is done once ExitProcess callback is received
}
void SelectSomeThread()
{
if (this.SelectedThread != null && !this.SelectedThread.IsInValidState) {
this.SelectedThread = null;
}
if (this.SelectedThread == null) {
foreach(Thread thread in this.Threads) {
if (thread.IsInValidState) {
this.SelectedThread = thread;
break;
}
}
}
}
internal void CheckSelectedStackFrames()
{
foreach(Thread thread in this.Threads) {
if (thread.IsInValidState) {
if (thread.SelectedStackFrame != null && thread.SelectedStackFrame.IsInvalid) {
thread.SelectedStackFrame = null;
}
} else {
thread.SelectedStackFrame = null;
}
}
}
internal void SelectMostRecentStackFrameWithLoadedSymbols()
{
SelectSomeThread();
if (this.SelectedThread != null) {
this.SelectedThread.SelectedStackFrame = this.SelectedThread.MostRecentStackFrameWithLoadedSymbols;
}
}
internal void DisableAllSteppers()
{
foreach(Thread thread in this.Threads) {
thread.CurrentStepIn = null;
foreach(Stepper stepper in thread.Steppers) {
stepper.Ignore = true;
}
}
}
/// <summary>
/// Waits until the debugger pauses unless it is already paused.
/// Use PausedReason to find out why it paused.
/// </summary>
public void WaitForPause()
{
while(this.IsRunning && !this.HasExited) {
debugger.MTA2STA.WaitForCall();
debugger.MTA2STA.PerformAllCalls();
}
if (this.HasExited) throw new ProcessExitedException();
}
public void WaitForPause(TimeSpan timeout)
{
DateTime endTime = Util.HighPrecisionTimer.Now + timeout;
while(this.IsRunning && !this.HasExited) {
TimeSpan timeLeft = endTime - Util.HighPrecisionTimer.Now;
if (timeLeft <= TimeSpan.FromMilliseconds(10)) break;
//this.TraceMessage("Time left: " + timeLeft.TotalMilliseconds);
debugger.MTA2STA.WaitForCall(timeLeft);
debugger.MTA2STA.PerformCall();
}
if (this.HasExited) throw new ProcessExitedException();
}
/// <summary>
/// Waits until the precesses exits.
/// </summary>
public void WaitForExit()
{
while(!this.HasExited) {
debugger.MTA2STA.WaitForCall();
debugger.MTA2STA.PerformAllCalls();
}
}
}
}

462
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs

@ -5,13 +5,16 @@ @@ -5,13 +5,16 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.NRefactory.Ast;
using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
public partial class Process: DebuggerObject
internal enum DebuggeeStateAction { Keep, Clear }
public class Process: DebuggerObject
{
NDebugger debugger;
@ -23,51 +26,24 @@ namespace Debugger @@ -23,51 +26,24 @@ namespace Debugger
ThreadCollection threads;
AppDomainCollection appDomains;
#region IExpirable
bool hasExited = false;
public event EventHandler Exited;
public bool HasExited {
get {
return hasExited;
}
public NDebugger Debugger {
get { return debugger; }
}
internal void NotifyHasExited()
{
if(!hasExited) {
hasExited = true;
if (Exited != null) {
Exited(this, new ProcessEventArgs(this));
}
// Expire pause seesion first
if (IsPaused) {
NotifyResumed(DebuggeeStateAction.Clear);
}
debugger.Processes.Remove(this);
}
internal ICorDebugProcess CorProcess {
get { return corProcess; }
}
#endregion
public NDebugger Debugger {
get {
return debugger;
}
public Options Options {
get { return debugger.Options; }
}
public Options Options {
get {
return debugger.Options;
}
public string DebuggeeVersion {
get { return debugger.DebuggeeVersion; }
}
internal ManagedCallback CallbackInterface {
get {
return callbackInterface;
}
get { return callbackInterface; }
}
public EvalCollection ActiveEvals {
@ -91,6 +67,26 @@ namespace Debugger @@ -91,6 +67,26 @@ namespace Debugger
set { this.Threads.Selected = value; }
}
public StackFrame SelectedStackFrame {
get {
if (SelectedThread == null) {
return null;
} else {
return SelectedThread.SelectedStackFrame;
}
}
}
public SourcecodeSegment NextStatement {
get {
if (SelectedStackFrame == null || IsRunning) {
return null;
} else {
return SelectedStackFrame.NextStatement;
}
}
}
public AppDomainCollection AppDomains {
get { return appDomains; }
}
@ -108,12 +104,6 @@ namespace Debugger @@ -108,12 +104,6 @@ namespace Debugger
appDomains = new AppDomainCollection(debugger);
}
internal ICorDebugProcess CorProcess {
get {
return corProcess;
}
}
static unsafe public Process CreateProcess(NDebugger debugger, string filename, string workingDirectory, string arguments)
{
debugger.TraceMessage("Executing " + filename);
@ -149,25 +139,7 @@ namespace Debugger @@ -149,25 +139,7 @@ namespace Debugger
return new Process(debugger, outProcess);
}
public string DebuggeeVersion {
get {
return debugger.DebuggeeVersion;
}
}
public StackFrame SelectedStackFrame {
get {
if (SelectedThread == null) {
return null;
} else {
return SelectedThread.SelectedStackFrame;
}
}
}
/// <summary>
/// Fired when System.Diagnostics.Trace.WriteLine() is called in debuged process
/// </summary>
/// <summary> Fired when System.Diagnostics.Trace.WriteLine() is called in debuged process </summary>
public event EventHandler<MessageEventArgs> LogMessage;
protected internal virtual void OnLogMessage(MessageEventArgs arg)
@ -180,25 +152,12 @@ namespace Debugger @@ -180,25 +152,12 @@ namespace Debugger
public void TraceMessage(string message, params object[] args)
{
TraceMessage(string.Format(message, args));
}
public void TraceMessage(string message)
{
if (args.Length > 0)
message = string.Format(message, args);
System.Diagnostics.Debug.WriteLine("Debugger:" + message);
debugger.OnDebuggerTraceMessage(new MessageEventArgs(this, message));
}
public SourcecodeSegment NextStatement {
get {
if (SelectedStackFrame == null || IsRunning) {
return null;
} else {
return SelectedStackFrame.NextStatement;
}
}
}
/// <summary> Read the specified amount of memory at the given memory address </summary>
/// <returns> The content of the memory. The amount of the read memory may be less then requested. </returns>
public unsafe byte[] ReadMemory(ulong address, int size)
@ -223,20 +182,347 @@ namespace Debugger @@ -223,20 +182,347 @@ namespace Debugger
}
return written;
}
}
[Serializable]
public class ProcessEventArgs: DebuggerEventArgs
{
Process process;
public Process Process {
get { return process; }
#region Exceptions
bool pauseOnHandledException = false;
public event EventHandler<ExceptionEventArgs> ExceptionThrown;
public bool PauseOnHandledException {
get { return pauseOnHandledException; }
set { pauseOnHandledException = value; }
}
protected internal virtual void OnExceptionThrown(ExceptionEventArgs e)
{
TraceMessage ("Debugger event: OnExceptionThrown()");
if (ExceptionThrown != null) {
ExceptionThrown(this, e);
}
}
#endregion
// State control for the process
internal bool TerminateCommandIssued = false;
internal Queue<Breakpoint> BreakpointHitEventQueue = new Queue<Breakpoint>();
internal Dictionary<INode, Value> CachedExpressions = new Dictionary<INode, Value>();
#region Events
public event EventHandler<ProcessEventArgs> Paused;
public event EventHandler<ProcessEventArgs> Resumed;
// HACK: public
public virtual void OnPaused()
{
AssertPaused();
// No real purpose - just additional check
if (callbackInterface.IsInCallback) throw new DebuggerException("Can not raise event within callback.");
TraceMessage ("Debugger event: OnPaused()");
if (Paused != null) {
foreach(Delegate d in Paused.GetInvocationList()) {
if (IsRunning) {
TraceMessage ("Skipping OnPaused delegate because process has resumed");
break;
}
if (this.TerminateCommandIssued || this.HasExited) {
TraceMessage ("Skipping OnPaused delegate because process has exited");
break;
}
d.DynamicInvoke(this, new ProcessEventArgs(this));
}
}
}
protected virtual void OnResumed()
{
AssertRunning();
// No real purpose - just additional check
if (callbackInterface.IsInCallback) throw new DebuggerException("Can not raise event within callback.");
TraceMessage ("Debugger event: OnResumed()");
if (Resumed != null) {
Resumed(this, new ProcessEventArgs(this));
}
}
#endregion
#region PauseSession & DebugeeState
PauseSession pauseSession;
DebuggeeState debuggeeState;
/// <summary>
/// Indentification of the current debugger session. This value changes whenever debugger is continued
/// </summary>
public PauseSession PauseSession {
get { return pauseSession; }
}
/// <summary>
/// Indentification of the state of the debugee. This value changes whenever the state of the debugee significatntly changes
/// </summary>
public DebuggeeState DebuggeeState {
get { return debuggeeState; }
}
/// <summary> Puts the process into a paused state </summary>
internal void NotifyPaused(PausedReason pauseReason)
{
AssertRunning();
pauseSession = new PauseSession(this, pauseReason);
if (debuggeeState == null) {
debuggeeState = new DebuggeeState(this);
}
}
/// <summary> Puts the process into a resumed state </summary>
internal void NotifyResumed(DebuggeeStateAction action)
{
AssertPaused();
pauseSession = null;
if (action == DebuggeeStateAction.Clear) {
if (debuggeeState == null) throw new DebuggerException("Debugee state already cleared");
debuggeeState = null;
this.CachedExpressions.Clear();
}
}
/// <summary> Sets up the eviroment and raises user events </summary>
internal void RaisePausedEvents()
{
DisableAllSteppers();
CheckSelectedStackFrames();
SelectMostRecentStackFrameWithLoadedSymbols();
if (this.PauseSession.PausedReason == PausedReason.Exception) {
ExceptionEventArgs args = new ExceptionEventArgs(this, this.SelectedThread.CurrentException, this.SelectedThread.CurrentExceptionType, this.SelectedThread.CurrentExceptionIsUnhandled);
OnExceptionThrown(args);
// The event could have resumed or killed the process
if (this.IsRunning || this.TerminateCommandIssued || this.HasExited) return;
}
while(BreakpointHitEventQueue.Count > 0) {
Breakpoint breakpoint = BreakpointHitEventQueue.Dequeue();
breakpoint.NotifyHit();
// The event could have resumed or killed the process
if (this.IsRunning || this.TerminateCommandIssued || this.HasExited) return;
}
OnPaused();
// The event could have resumed the process
if (this.IsRunning || this.TerminateCommandIssued || this.HasExited) return;
}
#endregion
internal void AssertPaused()
{
if (IsRunning) {
throw new DebuggerException("Process is not paused.");
}
}
internal void AssertRunning()
{
if (IsPaused) {
throw new DebuggerException("Process is not running.");
}
}
public bool IsRunning {
get { return pauseSession == null; }
}
public bool IsPaused {
get { return !IsRunning; }
}
bool hasExited = false;
public event EventHandler Exited;
public bool HasExited {
get {
return hasExited;
}
}
internal void NotifyHasExited()
{
if(!hasExited) {
hasExited = true;
if (Exited != null) {
Exited(this, new ProcessEventArgs(this));
}
// Expire pause seesion first
if (IsPaused) {
NotifyResumed(DebuggeeStateAction.Clear);
}
debugger.Processes.Remove(this);
}
}
public void Break()
{
AssertRunning();
corProcess.Stop(uint.MaxValue); // Infinite; ignored anyway
NotifyPaused(PausedReason.ForcedBreak);
RaisePausedEvents();
}
public void Detach()
{
if (IsRunning) {
corProcess.Stop(uint.MaxValue);
NotifyPaused(PausedReason.ForcedBreak);
}
corProcess.Detach();
NotifyHasExited();
}
public void Continue()
{
AsyncContinue();
WaitForPause();
}
public void AsyncContinue()
{
AsyncContinue(DebuggeeStateAction.Clear);
}
internal void AsyncContinue(DebuggeeStateAction action)
{
AssertPaused();
NotifyResumed(action);
corProcess.Continue(0);
if (this.Options.Verbose) {
this.TraceMessage("Continue");
}
if (action == DebuggeeStateAction.Clear) {
OnResumed();
}
}
/// <summary> Terminates the execution of the process </summary>
public void Terminate()
{
AsyncTerminate();
// Wait until ExitProcess callback is received
WaitForExit();
}
/// <summary> Terminates the execution of the process </summary>
public void AsyncTerminate()
{
// Resume stoped tread
if (this.IsPaused) {
// We might get more callbacks so we should maintain consistent sate
//AsyncContinue(); // Continue the process to get remaining callbacks
}
// Expose race condition - drain callback queue
System.Threading.Thread.Sleep(0);
// Stop&terminate - both must be called
corProcess.Stop(uint.MaxValue);
corProcess.Terminate(0);
this.TerminateCommandIssued = true;
// Do not mark the process as exited
// This is done once ExitProcess callback is received
}
public ProcessEventArgs(Process process): base(process == null ? null : process.Debugger)
void SelectSomeThread()
{
this.process = process;
if (this.SelectedThread != null && !this.SelectedThread.IsInValidState) {
this.SelectedThread = null;
}
if (this.SelectedThread == null) {
foreach(Thread thread in this.Threads) {
if (thread.IsInValidState) {
this.SelectedThread = thread;
break;
}
}
}
}
internal void CheckSelectedStackFrames()
{
foreach(Thread thread in this.Threads) {
if (thread.IsInValidState) {
if (thread.SelectedStackFrame != null && thread.SelectedStackFrame.IsInvalid) {
thread.SelectedStackFrame = null;
}
} else {
thread.SelectedStackFrame = null;
}
}
}
internal void SelectMostRecentStackFrameWithLoadedSymbols()
{
SelectSomeThread();
if (this.SelectedThread != null) {
this.SelectedThread.SelectedStackFrame = this.SelectedThread.MostRecentStackFrameWithLoadedSymbols;
}
}
internal void DisableAllSteppers()
{
foreach(Thread thread in this.Threads) {
thread.CurrentStepIn = null;
foreach(Stepper stepper in thread.Steppers) {
stepper.Ignore = true;
}
}
}
/// <summary>
/// Waits until the debugger pauses unless it is already paused.
/// Use PausedReason to find out why it paused.
/// </summary>
public void WaitForPause()
{
while(this.IsRunning && !this.HasExited) {
debugger.MTA2STA.WaitForCall();
debugger.MTA2STA.PerformAllCalls();
}
if (this.HasExited) throw new ProcessExitedException();
}
public void WaitForPause(TimeSpan timeout)
{
DateTime endTime = Util.HighPrecisionTimer.Now + timeout;
while(this.IsRunning && !this.HasExited) {
TimeSpan timeLeft = endTime - Util.HighPrecisionTimer.Now;
if (timeLeft <= TimeSpan.FromMilliseconds(10)) break;
//this.TraceMessage("Time left: " + timeLeft.TotalMilliseconds);
debugger.MTA2STA.WaitForCall(timeLeft);
debugger.MTA2STA.PerformCall();
}
if (this.HasExited) throw new ProcessExitedException();
}
/// <summary>
/// Waits until the precesses exits.
/// </summary>
public void WaitForExit()
{
while(!this.HasExited) {
debugger.MTA2STA.WaitForCall();
debugger.MTA2STA.PerformAllCalls();
}
}
}
}

28
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/ProcessEventArgs.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
[Serializable]
public class ProcessEventArgs: DebuggerEventArgs
{
Process process;
public Process Process {
get { return process; }
}
public ProcessEventArgs(Process process): base(process == null ? null : process.Debugger)
{
this.process = process;
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs

@ -15,7 +15,7 @@ using Debugger.Wrappers.CorDebug; @@ -15,7 +15,7 @@ using Debugger.Wrappers.CorDebug;
namespace Debugger
{
public partial class Thread: DebuggerObject
public class Thread: DebuggerObject
{
// AppDomain for thread can be changing
Process process;

52
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/GetValueException.cs

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.NRefactory.Ast;
using System;
using System.Collections.Generic;
using Debugger.MetaData;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
public class GetValueException: DebuggerException
{
INode expression;
string error;
/// <summary> Expression that has caused this exception to occur </summary>
public INode Expression {
get { return expression; }
set { expression = value; }
}
public string Error {
get { return error; }
}
public override string Message {
get {
if (expression == null) {
return error;
} else {
return String.Format("Error evaluating \"{0}\": {1}", expression.PrettyPrint(), error);
}
}
}
public GetValueException(INode expression, string error):base(error)
{
this.expression = expression;
this.error = error;
}
public GetValueException(string error):base(error)
{
this.error = error;
}
}
}

115
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.Array.cs

@ -1,115 +0,0 @@ @@ -1,115 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.NRefactory.Ast;
using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug;
// TODO: Test non-zero LowerBound
// TODO: Test very large arrays (Length > Int32.MaxValue)
namespace Debugger
{
// This part of the class provides support for arrays
public partial class Value
{
ICorDebugArrayValue CorArrayValue {
get {
if (IsNull) throw new GetValueException("Value is null");
if (!this.Type.IsArray) throw new DebuggerException("Value is not an array");
return this.CorReferenceValue.Dereference().CastTo<ICorDebugArrayValue>();
}
}
/// <summary>
/// Gets the number of elements in the array.
/// eg new object[4,5] returns 20
/// </summary>
/// <returns> 0 for non-arrays </returns>
public int ArrayLength {
get {
if (!this.Type.IsArray) return 0;
return (int)CorArrayValue.Count;
}
}
/// <summary>
/// Gets the number of dimensions of the array.
/// eg new object[4,5] returns 2
/// </summary>
/// <returns> 0 for non-arrays </returns>
public int ArrayRank {
get {
if (!this.Type.IsArray) return 0;
return (int)CorArrayValue.Rank;
}
}
/// <summary> Gets the dimensions of the array </summary>
/// <returns> null for non-arrays </returns>
public ArrayDimensions ArrayDimensions {
get {
if (!this.Type.IsArray) return null;
int rank = this.ArrayRank;
uint[] baseIndicies;
if (CorArrayValue.HasBaseIndicies() == 1) {
baseIndicies = CorArrayValue.BaseIndicies;
} else {
baseIndicies = new uint[this.ArrayRank];
}
uint[] dimensionCounts = CorArrayValue.Dimensions;
List<ArrayDimension> dimensions = new List<ArrayDimension>();
for(int i = 0; i < rank; i++) {
dimensions.Add(new ArrayDimension((int)baseIndicies[i], (int)baseIndicies[i] + (int)dimensionCounts[i] - 1));
}
return new ArrayDimensions(dimensions);
}
}
/// <summary> Returns an element of a single-dimensional array </summary>
public Value GetArrayElement(int index)
{
return GetArrayElement(new int[] {index});
}
/// <summary> Returns an element of an array </summary>
public Value GetArrayElement(int[] elementIndices)
{
int[] indices = (int[])elementIndices.Clone();
return new Value(this.AppDomain, GetCorValueOfArrayElement(indices));
}
// May be called later
ICorDebugValue GetCorValueOfArrayElement(int[] indices)
{
if (indices.Length != ArrayRank) {
throw new GetValueException("Given indicies do not have the same dimension as array.");
}
if (!this.ArrayDimensions.IsIndexValid(indices)) {
throw new GetValueException("Given indices are out of range of the array");
}
return CorArrayValue.GetElement(indices);
}
/// <summary> Returns all elements in the array </summary>
public Value[] GetArrayElements()
{
if (!this.Type.IsArray) return null;
List<Value> values = new List<Value>();
foreach(int[] indices in this.ArrayDimensions.Indices) {
values.Add(GetArrayElement(indices));
}
return values.ToArray();
}
}
}

262
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.Object.cs

@ -1,262 +0,0 @@ @@ -1,262 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using Debugger.MetaData;
using Debugger.Wrappers.CorDebug;
using ICSharpCode.NRefactory.Ast;
using System.Reflection;
namespace Debugger
{
// This part of the class provides support for classes and structures
public partial class Value
{
internal ICorDebugObjectValue CorObjectValue {
get {
if (IsNull) throw new GetValueException("Value is null");
ICorDebugValue corValue = this.CorValue;
// Dereference and unbox if necessary
if (corValue.Is<ICorDebugReferenceValue>())
corValue = corValue.CastTo<ICorDebugReferenceValue>().Dereference();
if (corValue.Is<ICorDebugBoxValue>())
return corValue.CastTo<ICorDebugBoxValue>().Object;
if (!corValue.Is<ICorDebugObjectValue>())
throw new DebuggerException("Value is not an object");
return corValue.CastTo<ICorDebugObjectValue>();
}
}
static void CheckObject(Value objectInstance, IDebugMemberInfo memberInfo)
{
if (!memberInfo.IsStatic) {
if (objectInstance == null) {
throw new DebuggerException("No target object specified");
}
if (objectInstance.IsNull) {
throw new GetValueException("Null reference");
}
//if (!objectInstance.IsObject) // eg Array.Length can be called
if (!memberInfo.DeclaringType.IsInstanceOfType(objectInstance)) {
throw new GetValueException("Object is not of type " + memberInfo.DeclaringType.FullName);
}
}
}
#region Convenience overload methods
/// <summary> Get the value of given member. </summary>
public Value GetMemberValue(MemberInfo memberInfo, params Value[] arguments)
{
return GetMemberValue(this, memberInfo, arguments);
}
#endregion
/// <summary> Get the value of given member. </summary>
/// <param name="objectInstance">null if member is static</param>
public static Value GetMemberValue(Value objectInstance, MemberInfo memberInfo, params Value[] arguments)
{
if (memberInfo is DebugFieldInfo) {
if (arguments.Length > 0) throw new GetValueException("Arguments can not be used for a field");
return GetFieldValue(objectInstance, (DebugFieldInfo)memberInfo);
} else if (memberInfo is DebugPropertyInfo) {
return GetPropertyValue(objectInstance, (DebugPropertyInfo)memberInfo, arguments);
} else if (memberInfo is DebugMethodInfo) {
return InvokeMethod(objectInstance, (DebugMethodInfo)memberInfo, arguments);
}
throw new DebuggerException("Unknown member type: " + memberInfo.GetType());
}
#region Convenience overload methods
/// <summary> Get the value of given field. </summary>
public Value GetFieldValue(DebugFieldInfo fieldInfo)
{
return Value.GetFieldValue(this, fieldInfo);
}
#endregion
/// <summary> Get the value of given field. </summary>
/// <param name="objectInstance">null if field is static</param>
public static Value GetFieldValue(Value objectInstance, DebugFieldInfo fieldInfo)
{
return new Value(
fieldInfo.AppDomain,
GetFieldCorValue(objectInstance, fieldInfo)
);
}
public static Value SetFieldValue(Value objectInstance, DebugFieldInfo fieldInfo, Value newValue)
{
// TODO
throw new NotImplementedException();
}
static ICorDebugValue GetFieldCorValue(Value objectInstance, DebugFieldInfo fieldInfo)
{
CheckObject(objectInstance, fieldInfo);
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
ICorDebugFrame curFrame = null;
if (fieldInfo.Process.IsPaused &&
fieldInfo.Process.SelectedThread != null &&
fieldInfo.Process.SelectedThread.MostRecentStackFrame != null &&
fieldInfo.Process.SelectedThread.MostRecentStackFrame.CorILFrame != null) {
curFrame = fieldInfo.Process.SelectedThread.MostRecentStackFrame.CorILFrame.CastTo<ICorDebugFrame>();
}
try {
if (fieldInfo.IsStatic) {
return ((DebugType)fieldInfo.DeclaringType).CorType.GetStaticFieldValue((uint)fieldInfo.MetadataToken, curFrame);
} else {
return objectInstance.CorObjectValue.GetFieldValue(((DebugType)fieldInfo.DeclaringType).CorType.Class, (uint)fieldInfo.MetadataToken);
}
} catch {
throw new GetValueException("Can not get value of field");
}
}
#region Convenience overload methods
/// <summary> Get the value of the property using the get accessor </summary>
public Value GetPropertyValue(DebugPropertyInfo propertyInfo, params Value[] arguments)
{
return GetPropertyValue(this, propertyInfo, arguments);
}
#endregion
/// <summary> Get the value of the property using the get accessor </summary>
public static Value GetPropertyValue(Value objectInstance, DebugPropertyInfo propertyInfo, params Value[] arguments)
{
CheckObject(objectInstance, propertyInfo);
if (propertyInfo.GetGetMethod() == null) throw new GetValueException("Property does not have a get method");
Value val = Value.InvokeMethod(objectInstance, (DebugMethodInfo)propertyInfo.GetGetMethod(), arguments);
return val;
}
#region Convenience overload methods
/// <summary> Set the value of the property using the set accessor </summary>
public Value SetPropertyValue(DebugPropertyInfo propertyInfo, Value newValue)
{
return SetPropertyValue(this, propertyInfo, null, newValue);
}
/// <summary> Set the value of the property using the set accessor </summary>
public Value SetPropertyValue(DebugPropertyInfo propertyInfo, Value[] arguments, Value newValue)
{
return SetPropertyValue(this, propertyInfo, arguments, newValue);
}
/// <summary> Set the value of the property using the set accessor </summary>
public static Value SetPropertyValue(Value objectInstance, DebugPropertyInfo propertyInfo, Value newValue)
{
return SetPropertyValue(objectInstance, propertyInfo, null, newValue);
}
#endregion
/// <summary> Set the value of the property using the set accessor </summary>
public static Value SetPropertyValue(Value objectInstance, DebugPropertyInfo propertyInfo, Value[] arguments, Value newValue)
{
CheckObject(objectInstance, propertyInfo);
if (propertyInfo.GetSetMethod() == null) throw new GetValueException("Property does not have a set method");
arguments = arguments ?? new Value[0];
Value[] allParams = new Value[1 + arguments.Length];
allParams[0] = newValue;
arguments.CopyTo(allParams, 1);
return Value.InvokeMethod(objectInstance, (DebugMethodInfo)propertyInfo.GetSetMethod(), allParams);
}
#region Convenience overload methods
/// <summary> Synchronously invoke the method </summary>
public Value InvokeMethod(DebugMethodInfo methodInfo, params Value[] arguments)
{
return InvokeMethod(this, methodInfo, arguments);
}
#endregion
/// <summary> Synchronously invoke the method </summary>
public static Value InvokeMethod(Value objectInstance, DebugMethodInfo methodInfo, params Value[] arguments)
{
CheckObject(objectInstance, methodInfo);
return Eval.InvokeMethod(
methodInfo,
methodInfo.IsStatic ? null : objectInstance,
arguments ?? new Value[0]
);
}
/// <summary> Invoke the ToString() method </summary>
public string InvokeToString()
{
if (this.Type.IsPrimitive) return AsString;
if (this.Type.IsPointer) return "0x" + this.PointerAddress.ToString("X");
// if (!IsObject) // Can invoke on primitives
DebugMethodInfo methodInfo = (DebugMethodInfo)DebugType.CreateFromType(this.AppDomain, typeof(object)).GetMethod("ToString", new DebugType[] {});
return Eval.InvokeMethod(methodInfo, this, new Value[] {}).AsString;
}
#region Convenience overload methods
/// <summary> Asynchronously invoke the method </summary>
public Eval AsyncInvokeMethod(DebugMethodInfo methodInfo, params Value[] arguments)
{
return AsyncInvokeMethod(this, methodInfo, arguments);
}
#endregion
/// <summary> Asynchronously invoke the method </summary>
public static Eval AsyncInvokeMethod(Value objectInstance, DebugMethodInfo methodInfo, params Value[] arguments)
{
CheckObject(objectInstance, methodInfo);
return Eval.AsyncInvokeMethod(
methodInfo,
methodInfo.IsStatic ? null : objectInstance,
arguments ?? new Value[0]
);
}
/// <summary> Get a field or property of an object with a given name. </summary>
/// <returns> Null if not found </returns>
public Value GetMemberValue(string name)
{
DebugType currentType = this.Type;
while (currentType != null) {
MemberInfo memberInfo = currentType.GetMember<MemberInfo>(name, DebugType.BindingFlagsAll, null);
if (memberInfo != null) {
if (memberInfo is DebugFieldInfo) {
return this.GetFieldValue((DebugFieldInfo)memberInfo);
}
if (memberInfo is DebugPropertyInfo) {
return this.GetPropertyValue((DebugPropertyInfo)memberInfo);
}
}
currentType = (DebugType)currentType.BaseType;
}
return null;
}
}
}

66
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.Primitive.cs

@ -1,66 +0,0 @@ @@ -1,66 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.ComponentModel;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
// This part of the class provides support for primitive types
// eg int, bool, string
public partial class Value
{
internal ICorDebugGenericValue CorGenericValue {
get {
if (IsNull) throw new GetValueException("Value is null");
ICorDebugValue corValue = this.CorValue;
// Dereference and unbox if necessary
if (corValue.Is<ICorDebugReferenceValue>())
corValue = corValue.CastTo<ICorDebugReferenceValue>().Dereference();
if (corValue.Is<ICorDebugBoxValue>())
corValue = corValue.CastTo<ICorDebugBoxValue>().Object.CastTo<ICorDebugValue>();
if (!corValue.Is<ICorDebugGenericValue>())
throw new DebuggerException("Value is not an generic value");
return corValue.CastTo<ICorDebugGenericValue>();
}
}
/// <summary>
/// Gets or sets the value of a primitive type.
///
/// If setting of a value fails, NotSupportedException is thrown.
/// </summary>
public object PrimitiveValue {
get {
if (this.Type.PrimitiveType == null) throw new DebuggerException("Value is not a primitive type");
if (this.Type.FullName == typeof(string).FullName) {
if (this.IsNull) return null;
return this.CorReferenceValue.Dereference().CastTo<ICorDebugStringValue>().String;
} else {
return CorGenericValue.GetValue(this.Type.PrimitiveType);
}
}
set {
if (this.Type.PrimitiveType == null) throw new DebuggerException("Value is not a primitive type");
if (this.Type.FullName == typeof(string).FullName) {
this.SetValue(Eval.NewString(this.AppDomain, value.ToString()));
} else {
if (value == null) throw new DebuggerException("Can not set primitive value to null");
object newValue;
try {
newValue = Convert.ChangeType(value, this.Type.PrimitiveType);
} catch {
throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + this.Type.PrimitiveType.ToString());
}
CorGenericValue.SetValue(this.Type.PrimitiveType, newValue);
}
}
}
}
}

538
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Values/Value.cs

@ -5,11 +5,12 @@ @@ -5,11 +5,12 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.NRefactory.Ast;
using System;
using System.Collections.Generic;
using Debugger.MetaData;
using Debugger.Wrappers.CorDebug;
using ICSharpCode.NRefactory.Ast;
using System.Reflection;
namespace Debugger
{
@ -21,37 +22,83 @@ namespace Debugger @@ -21,37 +22,83 @@ namespace Debugger
/// resumed (this includes method invocation and property evaluation).
/// You can use Expressions to reobtain the value.
/// </summary>
public partial class Value: DebuggerObject
public class Value: DebuggerObject
{
AppDomain appDomain;
ICorDebugValue corValue;
PauseSession corValue_pauseSession;
DebugType type;
/// <summary> Returns true if the value is null </summary>
public bool IsNull {
/// <summary> The appdomain that owns the value </summary>
public AppDomain AppDomain {
get { return appDomain; }
}
public Process Process {
get { return appDomain.Process; }
}
[Debugger.Tests.Ignore]
public ICorDebugValue CorValue {
get {
return this.CorValue.Is<ICorDebugReferenceValue>() &&
this.CorValue.CastTo<ICorDebugReferenceValue>().IsNull != 0;
if (this.IsInvalid)
throw new GetValueException("Value is no longer valid");
return corValue;
}
}
/// <summary> Gets a string representation of the value </summary>
public string AsString {
ICorDebugReferenceValue CorReferenceValue {
get {
if (this.IsNull) return "null";
if (this.Type.IsPrimitive) return PrimitiveValue.ToString();
return "{" + this.Type.FullName + "}";
if (!this.CorValue.Is<ICorDebugReferenceValue>())
throw new DebuggerException("Reference value expected");
return this.CorValue.CastTo<ICorDebugReferenceValue>();
}
}
/// <summary> The appdomain that owns the value </summary>
public AppDomain AppDomain {
get { return appDomain; }
internal ICorDebugGenericValue CorGenericValue {
get {
if (IsNull) throw new GetValueException("Value is null");
ICorDebugValue corValue = this.CorValue;
// Dereference and unbox if necessary
if (corValue.Is<ICorDebugReferenceValue>())
corValue = corValue.CastTo<ICorDebugReferenceValue>().Dereference();
if (corValue.Is<ICorDebugBoxValue>())
corValue = corValue.CastTo<ICorDebugBoxValue>().Object.CastTo<ICorDebugValue>();
if (!corValue.Is<ICorDebugGenericValue>())
throw new DebuggerException("Value is not an generic value");
return corValue.CastTo<ICorDebugGenericValue>();
}
}
public Process Process {
get { return appDomain.Process; }
ICorDebugArrayValue CorArrayValue {
get {
if (IsNull) throw new GetValueException("Value is null");
if (!this.Type.IsArray) throw new DebuggerException("Value is not an array");
return this.CorReferenceValue.Dereference().CastTo<ICorDebugArrayValue>();
}
}
internal ICorDebugObjectValue CorObjectValue {
get {
if (IsNull) throw new GetValueException("Value is null");
ICorDebugValue corValue = this.CorValue;
// Dereference and unbox if necessary
if (corValue.Is<ICorDebugReferenceValue>())
corValue = corValue.CastTo<ICorDebugReferenceValue>().Dereference();
if (corValue.Is<ICorDebugBoxValue>())
return corValue.CastTo<ICorDebugBoxValue>().Object;
if (!corValue.Is<ICorDebugObjectValue>())
throw new DebuggerException("Value is not an object");
return corValue.CastTo<ICorDebugObjectValue>();
}
}
/// <summary> Returns the <see cref="Debugger.DebugType"/> of the value </summary>
public DebugType Type {
get { return type; }
}
/// <summary> Returns true if the Value can not be used anymore.
@ -63,20 +110,19 @@ namespace Debugger @@ -63,20 +110,19 @@ namespace Debugger
}
}
[Debugger.Tests.Ignore]
public ICorDebugValue CorValue {
/// <summary> Gets value indication whether the value is a reference </summary>
/// <remarks> Value types also return true if they are boxed </remarks>
public bool IsReference {
get {
if (this.IsInvalid)
throw new GetValueException("Value is no longer valid");
return corValue;
return this.CorValue.Is<ICorDebugReferenceValue>();
}
}
ICorDebugReferenceValue CorReferenceValue {
/// <summary> Returns true if the value is null </summary>
public bool IsNull {
get {
if (!this.CorValue.Is<ICorDebugReferenceValue>())
throw new DebuggerException("Reference value expected");
return this.CorValue.CastTo<ICorDebugReferenceValue>();
return this.CorValue.Is<ICorDebugReferenceValue>() &&
this.CorValue.CastTo<ICorDebugReferenceValue>().IsNull != 0;
}
}
@ -88,11 +134,41 @@ namespace Debugger @@ -88,11 +134,41 @@ namespace Debugger
get { return corValue.Address; }
}
/// <summary> Gets value indication whether the value is a reference </summary>
/// <remarks> Value types also return true if they are boxed </remarks>
public bool IsReference {
[Debugger.Tests.Ignore]
public ulong PointerAddress {
get {
return this.CorValue.Is<ICorDebugReferenceValue>();
if (!this.Type.IsPointer) throw new DebuggerException("Not a pointer");
return this.CorValue.CastTo<ICorDebugReferenceValue>().Value;
}
}
/// <summary> Gets a string representation of the value </summary>
public string AsString {
get {
if (this.IsNull) return "null";
if (this.Type.IsPrimitive) return PrimitiveValue.ToString();
return "{" + this.Type.FullName + "}";
}
}
internal Value(AppDomain appDomain, ICorDebugValue corValue)
{
if (corValue == null)
throw new ArgumentNullException("corValue");
this.appDomain = appDomain;
this.corValue = corValue;
this.corValue_pauseSession = this.Process.PauseSession;
if (corValue.Is<ICorDebugReferenceValue>() &&
corValue.CastTo<ICorDebugReferenceValue>().Value == 0 &&
corValue.CastTo<ICorDebugValue2>().ExactType == null)
{
// We were passed null reference and no metadata description
// (happens during CreateThread callback for the thread object)
this.type = DebugType.CreateFromType(appDomain, typeof(object));
} else {
ICorDebugType exactType = this.CorValue.CastTo<ICorDebugValue2>().ExactType;
this.type = DebugType.CreateFromCorType(appDomain, exactType);
}
}
@ -128,40 +204,6 @@ namespace Debugger @@ -128,40 +204,6 @@ namespace Debugger
}
}
internal Value(AppDomain appDomain, ICorDebugValue corValue)
{
if (corValue == null)
throw new ArgumentNullException("corValue");
this.appDomain = appDomain;
this.corValue = corValue;
this.corValue_pauseSession = this.Process.PauseSession;
if (corValue.Is<ICorDebugReferenceValue>() &&
corValue.CastTo<ICorDebugReferenceValue>().Value == 0 &&
corValue.CastTo<ICorDebugValue2>().ExactType == null)
{
// We were passed null reference and no metadata description
// (happens during CreateThread callback for the thread object)
this.type = DebugType.CreateFromType(appDomain, typeof(object));
} else {
ICorDebugType exactType = this.CorValue.CastTo<ICorDebugValue2>().ExactType;
this.type = DebugType.CreateFromCorType(appDomain, exactType);
}
}
/// <summary> Returns the <see cref="Debugger.DebugType"/> of the value </summary>
public DebugType Type {
get { return type; }
}
[Debugger.Tests.Ignore]
public ulong PointerAddress {
get {
if (!this.Type.IsPointer) throw new DebuggerException("Not a pointer");
return this.CorValue.CastTo<ICorDebugReferenceValue>().Value;
}
}
/// <summary> Dereferences a pointer type </summary>
/// <returns> Returns null for a null pointer </returns>
public Value Dereference()
@ -189,46 +231,368 @@ namespace Debugger @@ -189,46 +231,368 @@ namespace Debugger
}
}
public override string ToString()
{
return this.AsString;
#region Primitive
/// <summary>
/// Gets or sets the value of a primitive type.
///
/// If setting of a value fails, NotSupportedException is thrown.
/// </summary>
public object PrimitiveValue {
get {
if (this.Type.PrimitiveType == null) throw new DebuggerException("Value is not a primitive type");
if (this.Type.FullName == typeof(string).FullName) {
if (this.IsNull) return null;
return this.CorReferenceValue.Dereference().CastTo<ICorDebugStringValue>().String;
} else {
return CorGenericValue.GetValue(this.Type.PrimitiveType);
}
}
set {
if (this.Type.PrimitiveType == null) throw new DebuggerException("Value is not a primitive type");
if (this.Type.FullName == typeof(string).FullName) {
this.SetValue(Eval.NewString(this.AppDomain, value.ToString()));
} else {
if (value == null) throw new DebuggerException("Can not set primitive value to null");
object newValue;
try {
newValue = Convert.ChangeType(value, this.Type.PrimitiveType);
} catch {
throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + this.Type.PrimitiveType.ToString());
}
CorGenericValue.SetValue(this.Type.PrimitiveType, newValue);
}
}
}
}
public class GetValueException: DebuggerException
{
INode expression;
string error;
/// <summary> Expression that has caused this exception to occur </summary>
public INode Expression {
get { return expression; }
set { expression = value; }
#endregion
#region Array
// TODO: Test non-zero LowerBound
/// <summary>
/// Gets the number of elements in the array.
/// eg new object[4,5] returns 20
/// </summary>
/// <returns> 0 for non-arrays </returns>
public int ArrayLength {
get {
if (!this.Type.IsArray) return 0;
return (int)CorArrayValue.Count;
}
}
public string Error {
get { return error; }
/// <summary>
/// Gets the number of dimensions of the array.
/// eg new object[4,5] returns 2
/// </summary>
/// <returns> 0 for non-arrays </returns>
public int ArrayRank {
get {
if (!this.Type.IsArray) return 0;
return (int)CorArrayValue.Rank;
}
}
public override string Message {
/// <summary> Gets the dimensions of the array </summary>
/// <returns> null for non-arrays </returns>
public ArrayDimensions ArrayDimensions {
get {
if (expression == null) {
return error;
if (!this.Type.IsArray) return null;
int rank = this.ArrayRank;
uint[] baseIndicies;
if (CorArrayValue.HasBaseIndicies() == 1) {
baseIndicies = CorArrayValue.BaseIndicies;
} else {
baseIndicies = new uint[this.ArrayRank];
}
uint[] dimensionCounts = CorArrayValue.Dimensions;
List<ArrayDimension> dimensions = new List<ArrayDimension>();
for(int i = 0; i < rank; i++) {
dimensions.Add(new ArrayDimension((int)baseIndicies[i], (int)baseIndicies[i] + (int)dimensionCounts[i] - 1));
}
return new ArrayDimensions(dimensions);
}
}
/// <summary> Returns an element of a single-dimensional array </summary>
public Value GetArrayElement(int index)
{
return GetArrayElement(new int[] {index});
}
/// <summary> Returns an element of an array </summary>
public Value GetArrayElement(int[] elementIndices)
{
int[] indices = (int[])elementIndices.Clone();
return new Value(this.AppDomain, GetCorValueOfArrayElement(indices));
}
// May be called later
ICorDebugValue GetCorValueOfArrayElement(int[] indices)
{
if (indices.Length != ArrayRank) {
throw new GetValueException("Given indicies do not have the same dimension as array.");
}
if (!this.ArrayDimensions.IsIndexValid(indices)) {
throw new GetValueException("Given indices are out of range of the array");
}
return CorArrayValue.GetElement(indices);
}
/// <summary> Returns all elements in the array </summary>
public Value[] GetArrayElements()
{
if (!this.Type.IsArray) return null;
List<Value> values = new List<Value>();
foreach(int[] indices in this.ArrayDimensions.Indices) {
values.Add(GetArrayElement(indices));
}
return values.ToArray();
}
#endregion
#region Object
static void CheckObject(Value objectInstance, IDebugMemberInfo memberInfo)
{
if (!memberInfo.IsStatic) {
if (objectInstance == null) {
throw new DebuggerException("No target object specified");
}
if (objectInstance.IsNull) {
throw new GetValueException("Null reference");
}
//if (!objectInstance.IsObject) // eg Array.Length can be called
if (!memberInfo.DeclaringType.IsInstanceOfType(objectInstance)) {
throw new GetValueException("Object is not of type " + memberInfo.DeclaringType.FullName);
}
}
}
#region Convenience overload methods
/// <summary> Get the value of given member. </summary>
public Value GetMemberValue(MemberInfo memberInfo, params Value[] arguments)
{
return GetMemberValue(this, memberInfo, arguments);
}
#endregion
/// <summary> Get the value of given member. </summary>
/// <param name="objectInstance">null if member is static</param>
public static Value GetMemberValue(Value objectInstance, MemberInfo memberInfo, params Value[] arguments)
{
if (memberInfo is DebugFieldInfo) {
if (arguments.Length > 0) throw new GetValueException("Arguments can not be used for a field");
return GetFieldValue(objectInstance, (DebugFieldInfo)memberInfo);
} else if (memberInfo is DebugPropertyInfo) {
return GetPropertyValue(objectInstance, (DebugPropertyInfo)memberInfo, arguments);
} else if (memberInfo is DebugMethodInfo) {
return InvokeMethod(objectInstance, (DebugMethodInfo)memberInfo, arguments);
}
throw new DebuggerException("Unknown member type: " + memberInfo.GetType());
}
#region Convenience overload methods
/// <summary> Get the value of given field. </summary>
public Value GetFieldValue(DebugFieldInfo fieldInfo)
{
return Value.GetFieldValue(this, fieldInfo);
}
#endregion
/// <summary> Get the value of given field. </summary>
/// <param name="objectInstance">null if field is static</param>
public static Value GetFieldValue(Value objectInstance, DebugFieldInfo fieldInfo)
{
return new Value(
fieldInfo.AppDomain,
GetFieldCorValue(objectInstance, fieldInfo)
);
}
public static Value SetFieldValue(Value objectInstance, DebugFieldInfo fieldInfo, Value newValue)
{
// TODO
throw new NotImplementedException();
}
static ICorDebugValue GetFieldCorValue(Value objectInstance, DebugFieldInfo fieldInfo)
{
CheckObject(objectInstance, fieldInfo);
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
ICorDebugFrame curFrame = null;
if (fieldInfo.Process.IsPaused &&
fieldInfo.Process.SelectedThread != null &&
fieldInfo.Process.SelectedThread.MostRecentStackFrame != null &&
fieldInfo.Process.SelectedThread.MostRecentStackFrame.CorILFrame != null) {
curFrame = fieldInfo.Process.SelectedThread.MostRecentStackFrame.CorILFrame.CastTo<ICorDebugFrame>();
}
try {
if (fieldInfo.IsStatic) {
return ((DebugType)fieldInfo.DeclaringType).CorType.GetStaticFieldValue((uint)fieldInfo.MetadataToken, curFrame);
} else {
return String.Format("Error evaluating \"{0}\": {1}", expression.PrettyPrint(), error);
return objectInstance.CorObjectValue.GetFieldValue(((DebugType)fieldInfo.DeclaringType).CorType.Class, (uint)fieldInfo.MetadataToken);
}
} catch {
throw new GetValueException("Can not get value of field");
}
}
public GetValueException(INode expression, string error):base(error)
#region Convenience overload methods
/// <summary> Get the value of the property using the get accessor </summary>
public Value GetPropertyValue(DebugPropertyInfo propertyInfo, params Value[] arguments)
{
this.expression = expression;
this.error = error;
return GetPropertyValue(this, propertyInfo, arguments);
}
public GetValueException(string error):base(error)
#endregion
/// <summary> Get the value of the property using the get accessor </summary>
public static Value GetPropertyValue(Value objectInstance, DebugPropertyInfo propertyInfo, params Value[] arguments)
{
this.error = error;
CheckObject(objectInstance, propertyInfo);
if (propertyInfo.GetGetMethod() == null) throw new GetValueException("Property does not have a get method");
Value val = Value.InvokeMethod(objectInstance, (DebugMethodInfo)propertyInfo.GetGetMethod(), arguments);
return val;
}
#region Convenience overload methods
/// <summary> Set the value of the property using the set accessor </summary>
public Value SetPropertyValue(DebugPropertyInfo propertyInfo, Value newValue)
{
return SetPropertyValue(this, propertyInfo, null, newValue);
}
/// <summary> Set the value of the property using the set accessor </summary>
public Value SetPropertyValue(DebugPropertyInfo propertyInfo, Value[] arguments, Value newValue)
{
return SetPropertyValue(this, propertyInfo, arguments, newValue);
}
/// <summary> Set the value of the property using the set accessor </summary>
public static Value SetPropertyValue(Value objectInstance, DebugPropertyInfo propertyInfo, Value newValue)
{
return SetPropertyValue(objectInstance, propertyInfo, null, newValue);
}
#endregion
/// <summary> Set the value of the property using the set accessor </summary>
public static Value SetPropertyValue(Value objectInstance, DebugPropertyInfo propertyInfo, Value[] arguments, Value newValue)
{
CheckObject(objectInstance, propertyInfo);
if (propertyInfo.GetSetMethod() == null) throw new GetValueException("Property does not have a set method");
arguments = arguments ?? new Value[0];
Value[] allParams = new Value[1 + arguments.Length];
allParams[0] = newValue;
arguments.CopyTo(allParams, 1);
return Value.InvokeMethod(objectInstance, (DebugMethodInfo)propertyInfo.GetSetMethod(), allParams);
}
#region Convenience overload methods
/// <summary> Synchronously invoke the method </summary>
public Value InvokeMethod(DebugMethodInfo methodInfo, params Value[] arguments)
{
return InvokeMethod(this, methodInfo, arguments);
}
#endregion
/// <summary> Synchronously invoke the method </summary>
public static Value InvokeMethod(Value objectInstance, DebugMethodInfo methodInfo, params Value[] arguments)
{
CheckObject(objectInstance, methodInfo);
return Eval.InvokeMethod(
methodInfo,
methodInfo.IsStatic ? null : objectInstance,
arguments ?? new Value[0]
);
}
/// <summary> Invoke the ToString() method </summary>
public string InvokeToString()
{
if (this.Type.IsPrimitive) return AsString;
if (this.Type.IsPointer) return "0x" + this.PointerAddress.ToString("X");
// if (!IsObject) // Can invoke on primitives
DebugMethodInfo methodInfo = (DebugMethodInfo)DebugType.CreateFromType(this.AppDomain, typeof(object)).GetMethod("ToString", new DebugType[] {});
return Eval.InvokeMethod(methodInfo, this, new Value[] {}).AsString;
}
#region Convenience overload methods
/// <summary> Asynchronously invoke the method </summary>
public Eval AsyncInvokeMethod(DebugMethodInfo methodInfo, params Value[] arguments)
{
return AsyncInvokeMethod(this, methodInfo, arguments);
}
#endregion
/// <summary> Asynchronously invoke the method </summary>
public static Eval AsyncInvokeMethod(Value objectInstance, DebugMethodInfo methodInfo, params Value[] arguments)
{
CheckObject(objectInstance, methodInfo);
return Eval.AsyncInvokeMethod(
methodInfo,
methodInfo.IsStatic ? null : objectInstance,
arguments ?? new Value[0]
);
}
/// <summary> Get a field or property of an object with a given name. </summary>
/// <returns> Null if not found </returns>
public Value GetMemberValue(string name)
{
DebugType currentType = this.Type;
while (currentType != null) {
MemberInfo memberInfo = currentType.GetMember<MemberInfo>(name, DebugType.BindingFlagsAll, null);
if (memberInfo != null) {
if (memberInfo is DebugFieldInfo) {
return this.GetFieldValue((DebugFieldInfo)memberInfo);
}
if (memberInfo is DebugPropertyInfo) {
return this.GetPropertyValue((DebugPropertyInfo)memberInfo);
}
}
currentType = (DebugType)currentType.BaseType;
}
return null;
}
#endregion
public override string ToString()
{
return this.AsString;
}
}
}

Loading…
Cancel
Save