/* * Erstellt mit SharpDevelop. * Benutzer: Pavel * Datum: 16.07.2008 * Zeit: 14:31 * * Sie können diese Vorlage unter Extras > Optionen > Codeerstellung > Standardheader ändern. */ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Debugger; using Debugger.Wrappers.CorDebug; using Debugger.Wrappers.CorSym; using Debugger.Wrappers.MetaData; namespace Debugger { /// /// A stack frame which is being executed on some thread. /// Use to obtain arguments or local variables. /// /*public class StackFrame: DebuggerObject { Process process; Thread thread; ICorDebugILFrame corILFrame; object corILFramePauseSession; ICorDebugFunction corFunction; MethodInfo methodInfo; uint chainIndex; uint frameIndex; /// The process in which this stack frame is executed [Debugger.Tests.Ignore] public Process Process { get { return process; } } /// Get the method which this stack frame is executing public MethodInfo MethodInfo { get { return methodInfo; } } /// A thread in which the stack frame is executed [Debugger.Tests.Ignore] public Thread Thread { get { return thread; } } /// Internal index of the stack chain. The value is increasing with age. public uint ChainIndex { get { return chainIndex; } } /// Internal index of the stack frame. The value is increasing with age. public uint FrameIndex { get { return frameIndex; } } /// True if the stack frame has symbols defined. /// (That is has accesss to the .pdb file) public bool HasSymbols { get { return GetSegmentForOffet(0) != null; } } /// Returns true is this incance can not be used any more. /// Stack frame is valid only until the debugee is resumed. public bool IsInvalid { get { return this.corILFramePauseSession != process.PauseSession; } } internal StackFrame(Thread thread, ICorDebugILFrame corILFrame, uint chainIndex, uint frameIndex) { this.process = thread.Process; this.thread = thread; this.corILFrame = corILFrame; this.corILFramePauseSession = process.PauseSession; this.corFunction = corILFrame.Function; this.chainIndex = chainIndex; this.frameIndex = frameIndex; DebugType debugType = DebugType.Create( this.Process, corFunction.Class, corILFrame.CastTo().EnumerateTypeParameters().ToList().ToArray() ); this.methodInfo = debugType.GetMethod(corFunction.Token); } /// Returns diagnostic description of the frame public override string ToString() { return this.MethodInfo.FullName; } internal ICorDebugILFrame CorILFrame { get { if (this.IsInvalid) throw new DebuggerException("StackFrame is not valid anymore"); return corILFrame; } } internal uint CorInstructionPtr { get { uint corInstructionPtr; CorILFrame.GetIP(out corInstructionPtr); return corInstructionPtr; } } internal StackFrame Reobtain() { StackFrame stackFrame = this.Thread.GetStackFrameAt(chainIndex, frameIndex); if (stackFrame.MethodInfo != this.MethodInfo) throw new DebuggerException("The stack frame on the thread does not represent the same method anymore"); return stackFrame; } SourcecodeSegment GetSegmentForOffet(uint offset) { return SourcecodeSegment.Resolve(this.MethodInfo.Module, corFunction, offset); } /// Step into next instruction public void StepInto() { AsyncStepInto(); this.Process.WaitForPause(); } /// Step over next instruction public void StepOver() { AsyncStepOver(); this.Process.WaitForPause(); } /// Step out of the stack frame public void StepOut() { AsyncStepOut(); this.Process.WaitForPause(); } /// Step into next instruction public void AsyncStepInto() { AsyncStep(true); } /// Step over next instruction public void AsyncStepOver() { AsyncStep(false); } /// Step out of the stack frame public void AsyncStepOut() { Stepper.StepOut(this, "normal"); process.AsyncContinue(DebuggeeStateAction.Clear); } void AsyncStep(bool stepIn) { if (this.MethodInfo.Module.HasSymbols == false) { throw new DebuggerException("Unable to step. No symbols loaded."); } SourcecodeSegment nextSt = NextStatement; if (nextSt == null) { throw new DebuggerException("Unable to step. Next statement not aviable"); } if (stepIn) { Stepper stepInStepper = Stepper.StepIn(this, nextSt.StepRanges, "normal"); this.Thread.CurrentStepIn = stepInStepper; Stepper clearCurrentStepIn = Stepper.StepOut(this, "clear current step in"); clearCurrentStepIn.StepComplete += delegate { if (this.Thread.CurrentStepIn == stepInStepper) { this.Thread.CurrentStepIn = null; } }; clearCurrentStepIn.Ignore = true; } else { Stepper.StepOver(this, nextSt.StepRanges, "normal"); } process.AsyncContinue(DebuggeeStateAction.Clear); } /// /// Get the information about the next statement to be executed. /// /// Returns null on error. /// public SourcecodeSegment NextStatement { get { return GetSegmentForOffet(CorInstructionPtr); } } /// /// Determine whether the instrustion pointer can be set to given location /// /// Best possible location. Null is not possible. public SourcecodeSegment CanSetIP(string filename, int line, int column) { return SetIP(true, filename, line, column); } /// /// Set the instrustion pointer to given location /// /// Best possible location. Null is not possible. public SourcecodeSegment SetIP(string filename, int line, int column) { return SetIP(false, filename, line, column); } SourcecodeSegment SetIP(bool simulate, string filename, int line, int column) { process.AssertPaused(); SourcecodeSegment segment = SourcecodeSegment.Resolve(this.MethodInfo.Module, filename, null, line, column); if (segment != null && segment.CorFunction.Token == this.MethodInfo.MetadataToken) { try { if (simulate) { CorILFrame.CanSetIP((uint)segment.ILStart); } else { // Invalidates all frames and chains for the current thread CorILFrame.SetIP((uint)segment.ILStart); process.NotifyResumed(DebuggeeStateAction.Keep); process.NotifyPaused(PausedReason.SetIP); process.RaisePausedEvents(); } } catch { return null; } return segment; } return null; } /// /// Gets the instance of the class asociated with the current frame. /// That is, 'this' in C#. /// public Value GetThisValue() { return new Value(process, new ThisReferenceExpression(), GetThisCorValue()); } ICorDebugValue GetThisCorValue() { if (this.MethodInfo.IsStatic) throw new GetValueException("Static method does not have 'this'."); ICorDebugValue corValue; try { corValue = CorILFrame.GetArgument(0); } catch (COMException e) { // System.Runtime.InteropServices.COMException (0x80131304): An IL variable is not available at the current native IP. (See Forum-8640) if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Not available in the current state"); throw; } // This can be 'by ref' for value types if (corValue.Type == (uint)CorElementType.BYREF) { corValue = corValue.CastTo().Dereference(); } return corValue; } /// Total number of arguments (excluding implicit 'this' argument) public int ArgumentCount { get { ICorDebugValueEnum argumentEnum = CorILFrame.EnumerateArguments(); uint argCount = argumentEnum.Count; if (!this.MethodInfo.IsStatic) { argCount--; // Remove 'this' from count } return (int)argCount; } } /// Gets argument with a given index /// Zero-based index public Value GetArgumentValue(int index) { return new Value(process, new ParameterIdentifierExpression(this.MethodInfo, index), GetArgumentCorValue(index)); } ICorDebugValue GetArgumentCorValue(int index) { ICorDebugValue corValue; try { // Non-static methods include 'this' as first argument corValue = CorILFrame.GetArgument((uint)(this.MethodInfo.IsStatic? index : (index + 1))); } catch (COMException e) { if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); throw; } // Method arguments can be passed 'by ref' if (corValue.Type == (uint)CorElementType.BYREF) { corValue = corValue.CastTo().Dereference(); } return corValue; } #region Convenience methods /// Gets argument with a given name /// Null if not found public Value GetArgumentValue(string name) { for(int i = 0; i < this.ArgumentCount; i++) { if (this.MethodInfo.GetParameterName(i) == name) { return GetArgumentValue(i); } } return null; } /// Gets all arguments of the stack frame. public List GetArgumentValues() { List values = new List(); for (int i = 0; i < ArgumentCount; i++) { values.Add(GetArgumentValue(i)); } return values; } #endregion /// Returns value of give local variable public Value GetLocalVariableValue(ISymUnmanagedVariable symVar) { return new Value(this.Process, new LocalVariableIdentifierExpression(MethodInfo, symVar), GetLocalVariableCorValue(symVar)); } ICorDebugValue GetLocalVariableCorValue(ISymUnmanagedVariable symVar) { try { return CorILFrame.GetLocalVariable((uint)symVar.AddressField1); } catch (COMException e) { if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); throw; } } #region Convenience methods /// Get local variable with given name /// Null if not found public Value GetLocalVariableValue(string name) { foreach(ISymUnmanagedVariable symVar in this.MethodInfo.LocalVariables) { if (symVar.Name == name) { return GetLocalVariableValue(symVar); } } return null; } /// Returns all local variables of the stack frame. public List GetLocalVariableValues() { List values = new List(); foreach(ISymUnmanagedVariable symVar in this.MethodInfo.LocalVariables) { values.Add(GetLocalVariableValue(symVar)); } return values; } #endregion public override bool Equals(object obj) { StackFrame other = obj as StackFrame; return other != null && other.Thread == this.Thread && other.ChainIndex == this.ChainIndex && other.FrameIndex == this.FrameIndex && other.MethodInfo == this.methodInfo; } public override int GetHashCode() { int hashCode = 0; unchecked { if (thread != null) hashCode += 1000000009 * thread.GetHashCode(); if (methodInfo != null) hashCode += 1000000093 * methodInfo.GetHashCode(); hashCode += 1000000097 * chainIndex.GetHashCode(); hashCode += 1000000103 * frameIndex.GetHashCode(); } return hashCode; } }*/ }