Files
linux-packaging-mono/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/StackFrame.cs
Xamarin Public Jenkins (auto-signing) 7d05485754 Imported Upstream version 5.8.0.22
Former-commit-id: df344e34b07851d296efb3e6604c8db42b6f7aa3
2017-10-19 20:04:20 +00:00

251 lines
7.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace Mono.Debugger.Soft
{
public class StackFrame : Mirror
{
ThreadMirror thread;
AppDomainMirror domain;
MethodMirror method;
int il_offset;
Location location;
StackFrameFlags flags;
/*
* FIXME: Decide on the way to request/handle debugging information:
* - request the info in bulk for all frames/on demand for individual frames
* - request the info from the runtime/request only the il offset, and compute
* everything else based on this info using the method debug info.
*/
internal StackFrame (VirtualMachine vm, long id, ThreadMirror thread, MethodMirror method, int il_offset, StackFrameFlags flags) : base (vm, id) {
this.thread = thread;
this.method = method;
this.il_offset = il_offset;
this.flags = flags;
}
public ThreadMirror Thread {
get {
return thread;
}
}
public AppDomainMirror Domain {
get {
if (domain == null) {
if (vm.Version.AtLeast (2, 38)) {
try {
domain = vm.GetDomain (vm.conn.StackFrame_GetDomain (thread.Id, Id));
} catch (AbsentInformationException) {
domain = Thread.Domain;
}
} else {
domain = Thread.Domain;
}
}
return domain;
}
}
public MethodMirror Method {
get {
return method;
}
}
public Location Location {
get {
if (location == null) {
int line_number;
string src_file = null;
byte[] hash = null;
int column_number = 0;
int end_line_number = -1;
int end_column_number = -1;
if (il_offset == -1)
line_number = -1;
else
line_number = method.il_offset_to_line_number (il_offset, out src_file, out hash, out column_number, out end_line_number, out end_column_number);
location = new Location (vm, Method, 0, il_offset, src_file != null ? src_file : method.SourceFile, line_number, column_number, end_line_number, end_column_number, hash);
}
return location;
}
}
public string FileName {
get {
return Location.SourceFile;
}
}
public int ILOffset {
get {
return Location.ILOffset;
}
}
public int LineNumber {
get {
return Location.LineNumber;
}
}
public int ColumnNumber {
get {
return Location.ColumnNumber;
}
}
public int EndLineNumber {
get {
return Location.EndLineNumber;
}
}
public int EndColumnNumber {
get {
return Location.EndColumnNumber;
}
}
public bool IsDebuggerInvoke {
get {
return (flags & StackFrameFlags.DEBUGGER_INVOKE) != 0;
}
}
/*
* Whenever this frame transitions to native code. The method associated
* with the frame is either an InternalCall or a pinvoke method.
*/
public bool IsNativeTransition {
get {
return (flags & StackFrameFlags.NATIVE_TRANSITION) != 0;
}
}
public Value GetValue (ParameterInfoMirror param) {
if (param == null)
throw new ArgumentNullException ("param");
if (param.Method != Method)
throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
if (param.IsRetval)
throw new ArgumentException ("Parameter represents the method return value.");
// FIXME: Liveness
// FIXME: Allow returning the frame return value if possible
return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { (- param.Position) - 1 })[0]);
}
public Value GetValue (LocalVariable var) {
if (var == null)
throw new ArgumentNullException ("var");
if (var.Method != Method)
throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
// FIXME: Liveness
// FIXME: Check for return value
// FIXME: Allow returning the frame return value if possible
return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { var.GetValueIndex } )[0]);
}
public Value[] GetValues (LocalVariable[] vars) {
if (vars == null)
throw new ArgumentNullException ("vars");
for (int i = 0; i < vars.Length; ++i) {
if (vars [i] == null)
throw new ArgumentNullException ("vars");
if (vars [i].Method != Method)
throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
}
int[] pos = new int [vars.Length];
for (int i = 0; i < vars.Length; ++i)
pos [i] = vars [i].GetValueIndex;
return vm.DecodeValues (vm.conn.StackFrame_GetValues (thread.Id, Id, pos));
}
public Value GetArgument (int pos) {
return GetValue (Method.GetParameters () [pos]);
}
public Value GetThis () {
return vm.DecodeValue (vm.conn.StackFrame_GetThis (thread.Id, Id));
}
// Since protocol version 2.44
public void SetThis (Value value) {
if (value == null)
throw new ArgumentNullException ("value");
if (Method.IsStatic || !Method.DeclaringType.IsValueType)
throw new InvalidOperationException ("The frame's method needs to be a valuetype instance method.");
vm.conn.StackFrame_SetThis (thread.Id, Id, vm.EncodeValue (value));
}
public void SetValue (LocalVariable var, Value value) {
if (var == null)
throw new ArgumentNullException ("var");
if (var.Method != Method)
throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
if (value == null)
throw new ArgumentNullException ("value");
CheckMirror (value);
// FIXME: Liveness
// FIXME: Check for return value
try {
vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { var.GetValueIndex }, new ValueImpl [] { vm.EncodeValue (value) });
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
throw new ArgumentException ("Value does not match the type of the local variable.");
else
throw;
}
}
public void SetValue (ParameterInfoMirror param, Value value) {
if (param == null)
throw new ArgumentNullException ("param");
if (param.Method != Method)
throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
if (param.IsRetval)
throw new ArgumentException ("Parameter represents the method return value.");
if (value == null)
throw new ArgumentNullException ("value");
CheckMirror (value);
// FIXME: Liveness
// FIXME: Allow setting the frame return value if possible
try {
vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { (- param.Position) - 1 }, new ValueImpl [] { vm.EncodeValue (value) });
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
throw new ArgumentException ("Value does not match the type of the variable.");
else
throw;
}
}
public IList<LocalVariable> GetVisibleVariables () {
if (Location.ILOffset == -1)
throw new AbsentInformationException ();
return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset).ToList ();
}
public LocalVariable GetVisibleVariableByName (string name) {
if (name == null)
throw new ArgumentNullException ("name");
if (Location.ILOffset == -1)
throw new AbsentInformationException ();
return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset && l.Name == name).FirstOrDefault ();
}
}
}