* Makefile.am:
[monodevelop.git] / extras / MonoDevelop.Debugger.Mdb / Mono.Debugging.Server.Mdb / BacktraceWrapper.cs
blob0f54fd6f5c0426514baa25ef659d5ed56549b3b4
1 using System;
2 using System.Text;
3 using System.Collections.Generic;
5 using MD = Mono.Debugger;
6 using DL = Mono.Debugging.Client;
8 using Mono.Debugging.Client;
9 using Mono.Debugging.Backend;
10 using Mono.Debugger.Languages;
12 namespace DebuggerServer
14 class BacktraceWrapper: RemoteFrameObject, IBacktrace, IDisposable
16 MD.StackFrame[] frames;
17 DissassemblyBuffer[] disBuffers;
18 bool disposed;
20 public BacktraceWrapper (MD.StackFrame[] frames)
22 this.frames = frames;
23 Connect ();
26 public void Dispose ()
28 disposed = true;
31 public int FrameCount {
32 get { return frames.Length; }
35 public DL.StackFrame[] GetStackFrames (int firstIndex, int lastIndex)
37 CheckDisposed ();
39 //FIXME: validate indices
41 List<DL.StackFrame> list = new List<DL.StackFrame> ();
42 for (int i = firstIndex; i <= lastIndex && i < frames.Length; i ++) {
43 MD.StackFrame frame = frames [i];
44 string method = null;
45 string filename = null;
46 int line = -1;
48 if (frame.Method != null) {
49 method = frame.Method.Name;
50 if (!method.StartsWith ("<")) {
51 int p = method.IndexOf ('(');
52 if (p != -1)
53 method = method.Substring (0, p).Trim ();
55 } else if (frame.Name != null) {
56 method = frame.Name.Name;
57 } else {
58 method = "?";
61 if (frame.SourceAddress != null) {
62 if (frame.SourceAddress.SourceFile != null)
63 filename = frame.SourceAddress.SourceFile.FileName;
64 line = frame.SourceAddress.Row;
67 string lang = frame.Language != null ? frame.Language.Name : string.Empty;
68 list.Add (new DL.StackFrame (frame.TargetAddress.Address, new DL.SourceLocation (method, filename, line), lang));
71 return list.ToArray ();
74 EvaluationContext GetEvaluationContext (int frameIndex, int timeout)
76 CheckDisposed ();
77 if (timeout == -1)
78 timeout = DebuggerServer.DefaultEvaluationTimeout;
79 MD.StackFrame frame = frames [frameIndex];
80 return new EvaluationContext (frame.Thread, frame, timeout);
83 public ObjectValue[] GetLocalVariables (int frameIndex, int timeout)
85 EvaluationContext ctx = GetEvaluationContext (frameIndex, timeout);
86 List<ObjectValue> vars = new List<ObjectValue> ();
87 foreach (VariableReference vref in Util.GetLocalVariables (ctx))
88 vars.Add (vref.CreateObjectValue (true));
89 return vars.ToArray ();
92 public ObjectValue[] GetParameters (int frameIndex, int timeout)
94 try {
95 EvaluationContext ctx = GetEvaluationContext (frameIndex, timeout);
96 List<ObjectValue> vars = new List<ObjectValue> ();
97 foreach (VariableReference vref in Util.GetParameters (ctx)) {
98 vars.Add (vref.CreateObjectValue (true));
100 return vars.ToArray ();
101 } catch {
102 return new ObjectValue [0];
106 public ObjectValue GetThisReference (int frameIndex, int timeout)
108 EvaluationContext ctx = GetEvaluationContext (frameIndex, timeout);
109 if (ctx.Frame.Method != null && ctx.Frame.Method.HasThis) {
110 ObjectValueFlags flags = ObjectValueFlags.Field | ObjectValueFlags.ReadOnly;
111 TargetVariable var = ctx.Frame.Method.GetThis (ctx.Thread);
112 VariableReference vref = new VariableReference (ctx, var, flags);
113 return vref.CreateObjectValue ();
115 else
116 return null;
119 public ObjectValue[] GetAllLocals (int frameIndex, int timeout)
121 EvaluationContext ctx = GetEvaluationContext (frameIndex, timeout);
123 List<ObjectValue> locals = new List<ObjectValue> ();
125 // 'This' reference, or a reference to the type if the method is static
127 ObjectValue val = GetThisReference (frameIndex, timeout);
128 if (val != null)
129 locals.Add (val);
130 else if (ctx.Frame.Method != null) {
131 TargetType t = ctx.Frame.Method.GetDeclaringType (ctx.Thread);
132 if (t != null) {
133 ValueReference vr = new TypeValueReference (ctx, t);
134 locals.Add (vr.CreateObjectValue (true));
138 // Parameters
139 locals.AddRange (GetParameters (frameIndex, timeout));
141 // Local variables
142 locals.AddRange (GetLocalVariables (frameIndex, timeout));
144 return locals.ToArray ();
147 public ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, bool evaluateMethods, int timeout)
149 EvaluationContext ctx = GetEvaluationContext (frameIndex, timeout);
150 ObjectValue[] values = new ObjectValue [expressions.Length];
151 for (int n=0; n<values.Length; n++) {
152 string exp = expressions[n];
153 values[n] = Server.Instance.AsyncEvaluationTracker.Run (exp, ObjectValueFlags.Literal, delegate {
154 return GetExpressionValue (ctx, exp, evaluateMethods);
157 return values;
160 ObjectValue GetExpressionValue (EvaluationContext ctx, string exp, bool evaluateMethods)
162 try {
163 EvaluationOptions ops = new EvaluationOptions ();
164 ops.CanEvaluateMethods = evaluateMethods;
165 ValueReference var = (ValueReference) Server.Instance.Evaluator.Evaluate (ctx, exp, ops);
166 if (var != null)
167 return var.CreateObjectValue ();
168 else
169 return ObjectValue.CreateUnknown (exp);
170 } catch (NotSupportedExpressionException ex) {
171 return ObjectValue.CreateNotSupported (exp, ex.Message, ObjectValueFlags.None);
172 } catch (EvaluatorException ex) {
173 return ObjectValue.CreateError (exp, ex.Message, ObjectValueFlags.None);
174 } catch (Exception ex) {
175 Server.Instance.WriteDebuggerError (ex);
176 return ObjectValue.CreateUnknown (exp);
180 public CompletionData GetExpressionCompletionData (int frameIndex, string exp)
182 EvaluationContext ctx = GetEvaluationContext (frameIndex, -1);
183 int i;
185 if (exp [exp.Length - 1] == '.') {
186 exp = exp.Substring (0, exp.Length - 1);
187 i = 0;
188 while (i < exp.Length) {
189 ValueReference vr = null;
190 try {
191 vr = Server.Instance.Evaluator.Evaluate (ctx, exp.Substring (i), null);
192 if (vr != null) {
193 DL.CompletionData data = new DL.CompletionData ();
194 foreach (ValueReference cv in vr.GetChildReferences ())
195 data.Items.Add (new CompletionItem (cv.Name, cv.Flags));
196 data.ExpressionLenght = 0;
197 return data;
199 } catch (Exception ex) {
200 Console.WriteLine (ex);
202 i++;
204 return null;
207 i = exp.Length - 1;
208 bool lastWastLetter = false;
209 while (i >= 0) {
210 char c = exp [i--];
211 if (!char.IsLetterOrDigit (c) && c != '_')
212 break;
213 lastWastLetter = !char.IsDigit (c);
215 if (lastWastLetter) {
216 string partialWord = exp.Substring (i+1);
218 DL.CompletionData data = new DL.CompletionData ();
219 data.ExpressionLenght = partialWord.Length;
221 // Local variables
223 foreach (ValueReference vc in Util.GetLocalVariables (ctx))
224 if (vc.Name.StartsWith (partialWord))
225 data.Items.Add (new CompletionItem (vc.Name, vc.Flags));
227 // Parameters
229 foreach (ValueReference vc in Util.GetParameters (ctx))
230 if (vc.Name.StartsWith (partialWord))
231 data.Items.Add (new CompletionItem (vc.Name, vc.Flags));
233 // Members
235 TargetStructObject thisobj = null;
237 if (ctx.Frame.Method.HasThis) {
238 TargetObject ob = ctx.Frame.Method.GetThis (ctx.Thread).GetObject (ctx.Frame);
239 thisobj = ObjectUtil.GetRealObject (ctx, ob) as TargetStructObject;
240 data.Items.Add (new CompletionItem ("this", DL.ObjectValueFlags.Field | DL.ObjectValueFlags.ReadOnly));
243 TargetStructType type = ctx.Frame.Method.GetDeclaringType (ctx.Thread);
245 foreach (ValueReference vc in Util.GetMembers (ctx, type, thisobj))
246 if (vc.Name.StartsWith (partialWord))
247 data.Items.Add (new CompletionItem (vc.Name, vc.Flags));
249 if (data.Items.Count > 0)
250 return data;
252 return null;
255 public AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count)
257 CheckDisposed ();
258 if (disBuffers == null)
259 disBuffers = new MdbDissassemblyBuffer [frames.Length];
261 MD.StackFrame frame = frames [frameIndex];
262 DissassemblyBuffer buffer = disBuffers [frameIndex];
263 if (buffer == null) {
264 buffer = new MdbDissassemblyBuffer (frame.Thread, frame.TargetAddress);
265 disBuffers [frameIndex] = buffer;
268 return buffer.GetLines (firstLine, firstLine + count - 1);
271 void CheckDisposed ()
273 if (disposed)
274 throw new InvalidOperationException ("Invalid stack frame");
278 class MdbDissassemblyBuffer: DissassemblyBuffer
280 MD.Thread thread;
281 MD.TargetAddress baseAddr;
283 public MdbDissassemblyBuffer (MD.Thread thread, MD.TargetAddress addr): base (addr.Address)
285 this.thread = thread;
286 this.baseAddr = addr;
289 public override AssemblyLine[] GetLines (long startAddr, long endAddr)
291 List<AssemblyLine> lines = new List<AssemblyLine> ();
293 MD.TargetAddress addr = baseAddr + (startAddr - baseAddr.Address);
294 while (addr.Address <= endAddr) {
295 try {
296 MD.AssemblerLine line = thread.DisassembleInstruction (null, addr);
297 lines.Add (new AssemblyLine (addr.Address, line.Text));
298 addr += line.InstructionSize;
299 } catch {
300 Console.WriteLine ("failed " + addr.Address);
301 lines.Add (new AssemblyLine (addr.Address, "??"));
302 addr++;
305 return lines.ToArray ();