4 // Lluis Sanchez Gual <lluis@novell.com>
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
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
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
41 StackFrame firstFrame
;
43 DissassemblyBuffer
[] disBuffers
;
44 int currentFrame
= -1;
47 public GdbBacktrace (GdbSession session
, int threadId
, int count
, ResultData firstFrame
)
50 this.threadId
= threadId
;
51 if (firstFrame
!= null)
52 this.firstFrame
= CreateFrame (firstFrame
);
53 this.session
= session
;
56 public int FrameCount
{
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
);
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
)
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 ("->");
138 if (pointer
|| exp
.EndsWith (".")) {
139 exp
= exp
.Substring (0, exp
.Length
- (pointer
? 2 : 1));
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;
156 bool lastWastLetter
= false;
159 if (!char.IsLetterOrDigit (c
) && c
!= '_')
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
;
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
));
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)
195 ObjectValue
CreateVarObject (string exp
)
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
);
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");
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);
224 val
= ObjectValue
.CreatePrimitive (this, new ObjectPath (vname
), typeName
, value, flags
);
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");
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
);
252 return children
.ToArray ();
255 public string SetValue (ObjectPath path
, string value)
257 session
.SelectThread (threadId
);
258 session
.RunCommand ("-var-assign", path
.Join ("."), 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
281 ResultData data
= session
.RunCommand ("-data-evaluate-expression", "mono_pmip(" + sadr
+ ")");
282 string val
= data
.GetValue ("value");
284 int i
= val
.IndexOf ('"');
286 func
= val
.Substring (i
).Trim ('"',' ');
295 string sline
= frameData
.GetValue ("line");
297 line
= int.Parse (sline
);
299 string sfile
= frameData
.GetValue ("fullname");
301 sfile
= frameData
.GetValue ("file");
303 sfile
= frameData
.GetValue ("from");
304 SourceLocation loc
= new SourceLocation (func
?? "?", sfile
, line
);
307 if (!string.IsNullOrEmpty (sadr
))
308 addr
= long.Parse (sadr
.Substring (2), NumberStyles
.HexNumber
);
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
337 public GdbDissassemblyBuffer (GdbSession session
, long addr
): base (addr
)
339 this.session
= session
;
342 public override AssemblyLine
[] GetLines (long startAddr
, long endAddr
)
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"));
357 return new AssemblyLine
[0];