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