/
StackFrame.cs
202 lines (174 loc) · 6 KB
/
StackFrame.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
using System;
using System.Collections.Generic;
using System.Linq;
namespace Mono.Debugger.Soft
{
public class StackFrame : Mirror
{
ThreadMirror thread;
MethodMirror method;
int il_offset;
Location location;
StackFrameFlags flags;
/*
* FIXME: Decide on the way to request/handle debugging information:
* - request the info in bulk for all frames/on demand for individual frames
* - request the info from the runtime/request only the il offset, and compute
* everything else based on this info using the method debug info.
*/
internal StackFrame (VirtualMachine vm, long id, ThreadMirror thread, MethodMirror method, int il_offset, StackFrameFlags flags) : base (vm, id) {
this.thread = thread;
this.method = method;
this.il_offset = il_offset;
this.flags = flags;
}
public ThreadMirror Thread {
get {
return thread;
}
}
public MethodMirror Method {
get {
return method;
}
}
public Location Location {
get {
if (location == null) {
int line_number;
string src_file = null;
byte[] hash = null;
int column_number = 0;
if (il_offset == -1)
line_number = -1;
else
line_number = method.il_offset_to_line_number (il_offset, out src_file, out hash, out column_number);
location = new Location (vm, Method, 0, il_offset, src_file != null ? src_file : method.SourceFile, line_number, column_number, hash);
}
return location;
}
}
public string FileName {
get {
return Location.SourceFile;
}
}
public int ILOffset {
get {
return Location.ILOffset;
}
}
public int LineNumber {
get {
return Location.LineNumber;
}
}
public bool IsDebuggerInvoke {
get {
return (flags & StackFrameFlags.DEBUGGER_INVOKE) != 0;
}
}
/*
* Whenever this frame transitions to native code. The method associated
* with the frame is either an InternalCall or a pinvoke method.
*/
public bool IsNativeTransition {
get {
return (flags & StackFrameFlags.NATIVE_TRANSITION) != 0;
}
}
public Value GetValue (ParameterInfoMirror param) {
if (param == null)
throw new ArgumentNullException ("param");
if (param.Method != Method)
throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
if (param.IsRetval)
throw new ArgumentException ("Parameter represents the method return value.");
// FIXME: Liveness
// FIXME: Allow returning the frame return value if possible
return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { (- param.Position) - 1 })[0]);
}
public Value GetValue (LocalVariable var) {
if (var == null)
throw new ArgumentNullException ("var");
if (var.Method != Method)
throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
// FIXME: Liveness
// FIXME: Check for return value
// FIXME: Allow returning the frame return value if possible
return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { var.GetValueIndex } )[0]);
}
public Value[] GetValues (LocalVariable[] vars) {
if (vars == null)
throw new ArgumentNullException ("vars");
for (int i = 0; i < vars.Length; ++i) {
if (vars [i] == null)
throw new ArgumentNullException ("vars");
if (vars [i].Method != Method)
throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
}
int[] pos = new int [vars.Length];
for (int i = 0; i < vars.Length; ++i)
pos [i] = vars [i].GetValueIndex;
return vm.DecodeValues (vm.conn.StackFrame_GetValues (thread.Id, Id, pos));
}
public Value GetArgument (int pos) {
return GetValue (Method.GetParameters () [pos]);
}
public Value GetThis () {
return vm.DecodeValue (vm.conn.StackFrame_GetThis (thread.Id, Id));
}
public void SetValue (LocalVariable var, Value value) {
if (var == null)
throw new ArgumentNullException ("var");
if (var.Method != Method)
throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
if (value == null)
throw new ArgumentNullException ("value");
CheckMirror (value);
// FIXME: Liveness
// FIXME: Check for return value
try {
vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { var.GetValueIndex }, new ValueImpl [] { vm.EncodeValue (value) });
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
throw new ArgumentException ("Value does not match the type of the local variable.");
else
throw;
}
}
public void SetValue (ParameterInfoMirror param, Value value) {
if (param == null)
throw new ArgumentNullException ("param");
if (param.Method != Method)
throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
if (param.IsRetval)
throw new ArgumentException ("Parameter represents the method return value.");
if (value == null)
throw new ArgumentNullException ("value");
CheckMirror (value);
// FIXME: Liveness
// FIXME: Allow setting the frame return value if possible
try {
vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { (- param.Position) - 1 }, new ValueImpl [] { vm.EncodeValue (value) });
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
throw new ArgumentException ("Value does not match the type of the variable.");
else
throw;
}
}
public IList<LocalVariable> GetVisibleVariables () {
if (Location.ILOffset == -1)
throw new AbsentInformationException ();
return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset).ToList ();
}
public LocalVariable GetVisibleVariableByName (string name) {
if (name == null)
throw new ArgumentNullException ("name");
if (Location.ILOffset == -1)
throw new AbsentInformationException ();
return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset && l.Name == name).FirstOrDefault ();
}
}
}