* Makefile.am:
[monodevelop.git] / extras / MonoDevelop.Debugger.Gdb / GdbBacktrace.cs
blob9262247065290256291cf99f3a664cff5cc9826b
1 // GdbBacktrace.cs
2 //
3 // Author:
4 // Lluis Sanchez Gual <lluis@novell.com>
5 //
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 // THE SOFTWARE.
28 using System;
29 using System.Collections.Generic;
30 using System.Globalization;
31 using Mono.Debugging.Client;
32 using Mono.Debugging.Backend;
34 namespace MonoDevelop.Debugger.Gdb
38 class GdbBacktrace: IBacktrace, IObjectValueSource
40 int fcount;
41 StackFrame firstFrame;
42 GdbSession session;
43 DissassemblyBuffer[] disBuffers;
44 int currentFrame = -1;
45 int threadId;
47 public GdbBacktrace (GdbSession session, int threadId, int count, ResultData firstFrame)
49 fcount = count;
50 this.threadId = threadId;
51 if (firstFrame != null)
52 this.firstFrame = CreateFrame (firstFrame);
53 this.session = session;
56 public int FrameCount {
57 get {
58 return fcount;
62 public StackFrame[] GetStackFrames (int firstIndex, int lastIndex)
64 List<StackFrame> frames = new List<StackFrame> ();
65 if (firstIndex == 0 && firstFrame != null) {
66 frames.Add (firstFrame);
67 firstIndex++;
70 if (lastIndex >= fcount)
71 lastIndex = fcount - 1;
73 if (firstIndex > lastIndex)
74 return frames.ToArray ();
76 session.SelectThread (threadId);
77 GdbCommandResult res = session.RunCommand ("-stack-list-frames", firstIndex.ToString (), lastIndex.ToString ());
78 ResultData stack = res.GetObject ("stack");
79 for (int n=0; n<stack.Count; n++) {
80 ResultData frd = stack.GetObject (n);
81 frames.Add (CreateFrame (frd.GetObject ("frame")));
83 return frames.ToArray ();
86 public ObjectValue[] GetLocalVariables (int frameIndex, int timeOut)
88 List<ObjectValue> values = new List<ObjectValue> ();
89 SelectFrame (frameIndex);
91 GdbCommandResult res = session.RunCommand ("-stack-list-locals", "0");
92 foreach (ResultData data in res.GetObject ("locals"))
93 values.Add (CreateVarObject (data.GetValue ("name")));
95 return values.ToArray ();
98 public ObjectValue[] GetParameters (int frameIndex, int timeOut)
100 List<ObjectValue> values = new List<ObjectValue> ();
101 SelectFrame (frameIndex);
102 GdbCommandResult res = session.RunCommand ("-stack-list-arguments", "0", frameIndex.ToString (), frameIndex.ToString ());
103 foreach (ResultData data in res.GetObject ("stack-args").GetObject (0).GetObject ("frame").GetObject ("args"))
104 values.Add (CreateVarObject (data.GetValue ("name")));
106 return values.ToArray ();
109 public ObjectValue GetThisReference (int frameIndex, int timeOut)
111 return null;
114 public ObjectValue[] GetAllLocals (int frameIndex, int timeOut)
116 List<ObjectValue> locals = new List<ObjectValue> ();
117 locals.AddRange (GetParameters (frameIndex, timeOut));
118 locals.AddRange (GetLocalVariables (frameIndex, timeOut));
119 return locals.ToArray ();
122 public ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, bool evaluateMethods, int timeOut)
124 List<ObjectValue> values = new List<ObjectValue> ();
125 SelectFrame (frameIndex);
126 foreach (string exp in expressions)
127 values.Add (CreateVarObject (exp));
128 return values.ToArray ();
131 public CompletionData GetExpressionCompletionData (int frameIndex, string exp)
133 SelectFrame (frameIndex);
135 bool pointer = exp.EndsWith ("->");
136 int i;
138 if (pointer || exp.EndsWith (".")) {
139 exp = exp.Substring (0, exp.Length - (pointer ? 2 : 1));
140 i = 0;
141 while (i < exp.Length) {
142 ObjectValue val = CreateVarObject (exp);
143 if (!val.IsUnknown && !val.IsError) {
144 CompletionData data = new CompletionData ();
145 foreach (ObjectValue cv in val.GetAllChildren ())
146 data.Items.Add (new CompletionItem (cv.Name, cv.Flags));
147 data.ExpressionLenght = 0;
148 return data;
150 i++;
152 return null;
155 i = exp.Length - 1;
156 bool lastWastLetter = false;
157 while (i >= 0) {
158 char c = exp [i--];
159 if (!char.IsLetterOrDigit (c) && c != '_')
160 break;
161 lastWastLetter = !char.IsDigit (c);
164 if (lastWastLetter) {
165 string partialWord = exp.Substring (i+1);
167 CompletionData cdata = new CompletionData ();
168 cdata.ExpressionLenght = partialWord.Length;
170 // Local variables
172 GdbCommandResult res = session.RunCommand ("-stack-list-locals", "0");
173 foreach (ResultData data in res.GetObject ("locals")) {
174 string name = data.GetValue ("name");
175 if (name.StartsWith (partialWord))
176 cdata.Items.Add (new CompletionItem (name, ObjectValueFlags.Variable));
179 // Parameters
181 res = session.RunCommand ("-stack-list-arguments", "0", frameIndex.ToString (), frameIndex.ToString ());
182 foreach (ResultData data in res.GetObject ("stack-args").GetObject (0).GetObject ("frame").GetObject ("args")) {
183 string name = data.GetValue ("name");
184 if (name.StartsWith (partialWord))
185 cdata.Items.Add (new CompletionItem (name, ObjectValueFlags.Parameter));
188 if (cdata.Items.Count > 0)
189 return cdata;
191 return null;
195 ObjectValue CreateVarObject (string exp)
197 try {
198 session.SelectThread (threadId);
199 exp = exp.Replace ("\"", "\\\"");
200 GdbCommandResult res = session.RunCommand ("-var-create", "-", "*", "\"" + exp + "\"");
201 string vname = res.GetValue ("name");
202 session.RegisterTempVariableObject (vname);
203 return CreateObjectValue (exp, res);
204 } catch {
205 return ObjectValue.CreateUnknown (exp);
209 ObjectValue CreateObjectValue (string name, ResultData data)
211 string vname = data.GetValue ("name");
212 string typeName = data.GetValue ("type");
213 string value = data.GetValue ("value");
214 int nchild = data.GetInt ("numchild");
216 ObjectValue val;
217 ObjectValueFlags flags = ObjectValueFlags.Variable;
219 if (typeName.EndsWith ("]")) {
220 val = ObjectValue.CreateArray (this, new ObjectPath (vname), typeName, nchild, flags, null);
221 } else if (value == "{...}" || typeName.EndsWith ("*") || nchild > 0) {
222 val = ObjectValue.CreateObject (this, new ObjectPath (vname), typeName, value, flags, null);
223 } else {
224 val = ObjectValue.CreatePrimitive (this, new ObjectPath (vname), typeName, value, flags);
226 val.Name = name;
227 return val;
230 public ObjectValue[] GetChildren (ObjectPath path, int index, int count)
232 List<ObjectValue> children = new List<ObjectValue> ();
233 session.SelectThread (threadId);
234 GdbCommandResult res = session.RunCommand ("-var-list-children", "2", path.Join ("."));
235 ResultData cdata = res.GetObject ("children");
236 if (index == -1) {
237 index = 0;
238 count = cdata.Count;
241 for (int n=index; n<cdata.Count && n<index+count; n++) {
242 ResultData data = cdata.GetObject (n);
243 ResultData child = data.GetObject ("child");
245 string name = child.GetValue ("exp");
246 if (name.Length > 0 && char.IsNumber (name [0]))
247 name = "[" + name + "]";
249 ObjectValue val = CreateObjectValue (name, child);
250 children.Add (val);
252 return children.ToArray ();
255 public string SetValue (ObjectPath path, string value)
257 session.SelectThread (threadId);
258 session.RunCommand ("-var-assign", path.Join ("."), value);
259 return value;
263 void SelectFrame (int frame)
265 session.SelectThread (threadId);
266 if (frame != currentFrame) {
267 session.RunCommand ("-stack-select-frame", frame.ToString ());
268 currentFrame = frame;
272 StackFrame CreateFrame (ResultData frameData)
274 string lang = "Native";
275 string func = frameData.GetValue ("func");
276 string sadr = frameData.GetValue ("addr");
278 if (func == "??" && session.IsMonoProcess) {
279 // Try to get the managed func name
280 try {
281 ResultData data = session.RunCommand ("-data-evaluate-expression", "mono_pmip(" + sadr + ")");
282 string val = data.GetValue ("value");
283 if (val != null) {
284 int i = val.IndexOf ('"');
285 if (i != -1) {
286 func = val.Substring (i).Trim ('"',' ');
287 lang = "Mono";
290 } catch {
294 int line = -1;
295 string sline = frameData.GetValue ("line");
296 if (sline != null)
297 line = int.Parse (sline);
299 string sfile = frameData.GetValue ("fullname");
300 if (sfile == null)
301 sfile = frameData.GetValue ("file");
302 if (sfile == null)
303 sfile = frameData.GetValue ("from");
304 SourceLocation loc = new SourceLocation (func ?? "?", sfile, line);
306 long addr;
307 if (!string.IsNullOrEmpty (sadr))
308 addr = long.Parse (sadr.Substring (2), NumberStyles.HexNumber);
309 else
310 addr = 0;
312 return new StackFrame (addr, loc, lang);
315 public AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count)
317 SelectFrame (frameIndex);
318 if (disBuffers == null)
319 disBuffers = new DissassemblyBuffer [fcount];
321 DissassemblyBuffer buffer = disBuffers [frameIndex];
322 if (buffer == null) {
323 ResultData data = session.RunCommand ("-stack-info-frame");
324 long addr = long.Parse (data.GetObject ("frame").GetValue ("addr").Substring (2), NumberStyles.HexNumber);
325 buffer = new GdbDissassemblyBuffer (session, addr);
326 disBuffers [frameIndex] = buffer;
329 return buffer.GetLines (firstLine, firstLine + count - 1);
333 class GdbDissassemblyBuffer: DissassemblyBuffer
335 GdbSession session;
337 public GdbDissassemblyBuffer (GdbSession session, long addr): base (addr)
339 this.session = session;
342 public override AssemblyLine[] GetLines (long startAddr, long endAddr)
344 try {
345 ResultData data = session.RunCommand ("-data-disassemble", "-s", startAddr.ToString (), "-e", endAddr.ToString (), "--", "0");
346 ResultData ins = data.GetObject ("asm_insns");
348 AssemblyLine[] alines = new AssemblyLine [ins.Count];
349 for (int n=0; n<ins.Count; n++) {
350 ResultData aline = ins.GetObject (n);
351 long addr = long.Parse (aline.GetValue ("address").Substring (2), NumberStyles.HexNumber);
352 AssemblyLine line = new AssemblyLine (addr, aline.GetValue ("inst"));
353 alines [n] = line;
355 return alines;
356 } catch {
357 return new AssemblyLine [0];