PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/extras/MonoDevelop.Debugger.Gdb/GdbBacktrace.cs

https://bitbucket.org/anicolaspp/monodevelop
C# | 400 lines | 307 code | 59 blank | 34 comment | 61 complexity | d02693be814a54e322ca6b83bebca458 MD5 | raw file
  1. // GdbBacktrace.cs
  2. //
  3. // Authors: Lluis Sanchez Gual <lluis@novell.com>
  4. // Jeffrey Stedfast <jeff@xamarin.com>
  5. //
  6. // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
  7. // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. //
  27. //
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Globalization;
  31. using Mono.Debugging.Client;
  32. using Mono.Debugging.Backend;
  33. namespace MonoDevelop.Debugger.Gdb
  34. {
  35. class GdbBacktrace: IBacktrace, IObjectValueSource
  36. {
  37. int fcount;
  38. StackFrame firstFrame;
  39. GdbSession session;
  40. DissassemblyBuffer[] disBuffers;
  41. int currentFrame = -1;
  42. long threadId;
  43. public GdbBacktrace (GdbSession session, long threadId, int count, ResultData firstFrame)
  44. {
  45. fcount = count;
  46. this.threadId = threadId;
  47. if (firstFrame != null)
  48. this.firstFrame = CreateFrame (firstFrame);
  49. this.session = session;
  50. }
  51. public int FrameCount {
  52. get {
  53. return fcount;
  54. }
  55. }
  56. public StackFrame[] GetStackFrames (int firstIndex, int lastIndex)
  57. {
  58. List<StackFrame> frames = new List<StackFrame> ();
  59. if (firstIndex == 0 && firstFrame != null) {
  60. frames.Add (firstFrame);
  61. firstIndex++;
  62. }
  63. if (lastIndex >= fcount)
  64. lastIndex = fcount - 1;
  65. if (firstIndex > lastIndex)
  66. return frames.ToArray ();
  67. session.SelectThread (threadId);
  68. GdbCommandResult res = session.RunCommand ("-stack-list-frames", firstIndex.ToString (), lastIndex.ToString ());
  69. ResultData stack = res.GetObject ("stack");
  70. for (int n=0; n<stack.Count; n++) {
  71. ResultData frd = stack.GetObject (n);
  72. frames.Add (CreateFrame (frd.GetObject ("frame")));
  73. }
  74. return frames.ToArray ();
  75. }
  76. public ObjectValue[] GetLocalVariables (int frameIndex, EvaluationOptions options)
  77. {
  78. List<ObjectValue> values = new List<ObjectValue> ();
  79. SelectFrame (frameIndex);
  80. GdbCommandResult res = session.RunCommand ("-stack-list-locals", "0");
  81. foreach (ResultData data in res.GetObject ("locals"))
  82. values.Add (CreateVarObject (data.GetValue ("name")));
  83. return values.ToArray ();
  84. }
  85. public ObjectValue[] GetParameters (int frameIndex, EvaluationOptions options)
  86. {
  87. List<ObjectValue> values = new List<ObjectValue> ();
  88. SelectFrame (frameIndex);
  89. GdbCommandResult res = session.RunCommand ("-stack-list-arguments", "0", frameIndex.ToString (), frameIndex.ToString ());
  90. foreach (ResultData data in res.GetObject ("stack-args").GetObject (0).GetObject ("frame").GetObject ("args"))
  91. values.Add (CreateVarObject (data.GetValue ("name")));
  92. return values.ToArray ();
  93. }
  94. public ObjectValue GetThisReference (int frameIndex, EvaluationOptions options)
  95. {
  96. return null;
  97. }
  98. public ObjectValue[] GetAllLocals (int frameIndex, EvaluationOptions options)
  99. {
  100. List<ObjectValue> locals = new List<ObjectValue> ();
  101. locals.AddRange (GetParameters (frameIndex, options));
  102. locals.AddRange (GetLocalVariables (frameIndex, options));
  103. return locals.ToArray ();
  104. }
  105. public ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, EvaluationOptions options)
  106. {
  107. List<ObjectValue> values = new List<ObjectValue> ();
  108. SelectFrame (frameIndex);
  109. foreach (string exp in expressions)
  110. values.Add (CreateVarObject (exp));
  111. return values.ToArray ();
  112. }
  113. public ExceptionInfo GetException (int frameIndex, EvaluationOptions options)
  114. {
  115. return null;
  116. }
  117. public ValidationResult ValidateExpression (int frameIndex, string expression, EvaluationOptions options)
  118. {
  119. return new ValidationResult (true, null);
  120. }
  121. public CompletionData GetExpressionCompletionData (int frameIndex, string exp)
  122. {
  123. SelectFrame (frameIndex);
  124. bool pointer = exp.EndsWith ("->");
  125. int i;
  126. if (pointer || exp.EndsWith (".")) {
  127. exp = exp.Substring (0, exp.Length - (pointer ? 2 : 1));
  128. i = 0;
  129. while (i < exp.Length) {
  130. ObjectValue val = CreateVarObject (exp);
  131. if (!val.IsUnknown && !val.IsError) {
  132. CompletionData data = new CompletionData ();
  133. foreach (ObjectValue cv in val.GetAllChildren ())
  134. data.Items.Add (new CompletionItem (cv.Name, cv.Flags));
  135. data.ExpressionLength = 0;
  136. return data;
  137. }
  138. i++;
  139. }
  140. return null;
  141. }
  142. i = exp.Length - 1;
  143. bool lastWastLetter = false;
  144. while (i >= 0) {
  145. char c = exp [i--];
  146. if (!char.IsLetterOrDigit (c) && c != '_')
  147. break;
  148. lastWastLetter = !char.IsDigit (c);
  149. }
  150. if (lastWastLetter) {
  151. string partialWord = exp.Substring (i+1);
  152. CompletionData cdata = new CompletionData ();
  153. cdata.ExpressionLength = partialWord.Length;
  154. // Local variables
  155. GdbCommandResult res = session.RunCommand ("-stack-list-locals", "0");
  156. foreach (ResultData data in res.GetObject ("locals")) {
  157. string name = data.GetValue ("name");
  158. if (name.StartsWith (partialWord))
  159. cdata.Items.Add (new CompletionItem (name, ObjectValueFlags.Variable));
  160. }
  161. // Parameters
  162. res = session.RunCommand ("-stack-list-arguments", "0", frameIndex.ToString (), frameIndex.ToString ());
  163. foreach (ResultData data in res.GetObject ("stack-args").GetObject (0).GetObject ("frame").GetObject ("args")) {
  164. string name = data.GetValue ("name");
  165. if (name.StartsWith (partialWord))
  166. cdata.Items.Add (new CompletionItem (name, ObjectValueFlags.Parameter));
  167. }
  168. if (cdata.Items.Count > 0)
  169. return cdata;
  170. }
  171. return null;
  172. }
  173. ObjectValue CreateVarObject (string exp)
  174. {
  175. try {
  176. session.SelectThread (threadId);
  177. exp = exp.Replace ("\"", "\\\"");
  178. GdbCommandResult res = session.RunCommand ("-var-create", "-", "*", "\"" + exp + "\"");
  179. string vname = res.GetValue ("name");
  180. session.RegisterTempVariableObject (vname);
  181. return CreateObjectValue (exp, res);
  182. } catch {
  183. return ObjectValue.CreateUnknown (exp);
  184. }
  185. }
  186. ObjectValue CreateObjectValue (string name, ResultData data)
  187. {
  188. string vname = data.GetValue ("name");
  189. string typeName = data.GetValue ("type");
  190. string value = data.GetValue ("value");
  191. int nchild = data.GetInt ("numchild");
  192. ObjectValue val;
  193. ObjectValueFlags flags = ObjectValueFlags.Variable;
  194. // There can be 'public' et al children for C++ structures
  195. if (typeName == null)
  196. typeName = "none";
  197. if (typeName.EndsWith ("]")) {
  198. val = ObjectValue.CreateArray (this, new ObjectPath (vname), typeName, nchild, flags, null);
  199. } else if (value == "{...}" || typeName.EndsWith ("*") || nchild > 0) {
  200. val = ObjectValue.CreateObject (this, new ObjectPath (vname), typeName, value, flags, null);
  201. } else {
  202. val = ObjectValue.CreatePrimitive (this, new ObjectPath (vname), typeName, new EvaluationResult (value), flags);
  203. }
  204. val.Name = name;
  205. return val;
  206. }
  207. public ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options)
  208. {
  209. List<ObjectValue> children = new List<ObjectValue> ();
  210. session.SelectThread (threadId);
  211. GdbCommandResult res = session.RunCommand ("-var-list-children", "2", path.Join ("."));
  212. ResultData cdata = res.GetObject ("children");
  213. // The response may not contain the "children" list at all.
  214. if (cdata == null)
  215. return children.ToArray ();
  216. if (index == -1) {
  217. index = 0;
  218. count = cdata.Count;
  219. }
  220. for (int n=index; n<cdata.Count && n<index+count; n++) {
  221. ResultData data = cdata.GetObject (n);
  222. ResultData child = data.GetObject ("child");
  223. string name = child.GetValue ("exp");
  224. if (name.Length > 0 && char.IsNumber (name [0]))
  225. name = "[" + name + "]";
  226. // C++ structures may contain typeless children named
  227. // "public", "private" and "protected".
  228. if (child.GetValue("type") == null) {
  229. ObjectPath childPath = new ObjectPath (child.GetValue ("name").Split ('.'));
  230. ObjectValue[] subchildren = GetChildren (childPath, -1, -1, options);
  231. children.AddRange(subchildren);
  232. } else {
  233. ObjectValue val = CreateObjectValue (name, child);
  234. children.Add (val);
  235. }
  236. }
  237. return children.ToArray ();
  238. }
  239. public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)
  240. {
  241. session.SelectThread (threadId);
  242. session.RunCommand ("-var-assign", path.Join ("."), value);
  243. return new EvaluationResult (value);
  244. }
  245. public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)
  246. {
  247. throw new NotSupportedException ();
  248. }
  249. void SelectFrame (int frame)
  250. {
  251. session.SelectThread (threadId);
  252. if (frame != currentFrame) {
  253. session.RunCommand ("-stack-select-frame", frame.ToString ());
  254. currentFrame = frame;
  255. }
  256. }
  257. StackFrame CreateFrame (ResultData frameData)
  258. {
  259. string lang = "Native";
  260. string func = frameData.GetValue ("func");
  261. string sadr = frameData.GetValue ("addr");
  262. if (func == "??" && session.IsMonoProcess) {
  263. // Try to get the managed func name
  264. try {
  265. ResultData data = session.RunCommand ("-data-evaluate-expression", "mono_pmip(" + sadr + ")");
  266. string val = data.GetValue ("value");
  267. if (val != null) {
  268. int i = val.IndexOf ('"');
  269. if (i != -1) {
  270. func = val.Substring (i).Trim ('"',' ');
  271. lang = "Mono";
  272. }
  273. }
  274. } catch {
  275. }
  276. }
  277. int line = -1;
  278. string sline = frameData.GetValue ("line");
  279. if (sline != null)
  280. line = int.Parse (sline);
  281. string sfile = frameData.GetValue ("fullname");
  282. if (sfile == null)
  283. sfile = frameData.GetValue ("file");
  284. if (sfile == null)
  285. sfile = frameData.GetValue ("from");
  286. SourceLocation loc = new SourceLocation (func ?? "?", sfile, line);
  287. long addr;
  288. if (!string.IsNullOrEmpty (sadr))
  289. addr = long.Parse (sadr.Substring (2), NumberStyles.HexNumber);
  290. else
  291. addr = 0;
  292. return new StackFrame (addr, loc, lang);
  293. }
  294. public AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count)
  295. {
  296. SelectFrame (frameIndex);
  297. if (disBuffers == null)
  298. disBuffers = new DissassemblyBuffer [fcount];
  299. DissassemblyBuffer buffer = disBuffers [frameIndex];
  300. if (buffer == null) {
  301. ResultData data = session.RunCommand ("-stack-info-frame");
  302. long addr = long.Parse (data.GetObject ("frame").GetValue ("addr").Substring (2), NumberStyles.HexNumber);
  303. buffer = new GdbDissassemblyBuffer (session, addr);
  304. disBuffers [frameIndex] = buffer;
  305. }
  306. return buffer.GetLines (firstLine, firstLine + count - 1);
  307. }
  308. public object GetRawValue (ObjectPath path, EvaluationOptions options)
  309. {
  310. return null;
  311. }
  312. public void SetRawValue (ObjectPath path, object value, EvaluationOptions options)
  313. {
  314. }
  315. }
  316. class GdbDissassemblyBuffer: DissassemblyBuffer
  317. {
  318. GdbSession session;
  319. public GdbDissassemblyBuffer (GdbSession session, long addr): base (addr)
  320. {
  321. this.session = session;
  322. }
  323. public override AssemblyLine[] GetLines (long startAddr, long endAddr)
  324. {
  325. try {
  326. ResultData data = session.RunCommand ("-data-disassemble", "-s", startAddr.ToString (), "-e", endAddr.ToString (), "--", "0");
  327. ResultData ins = data.GetObject ("asm_insns");
  328. AssemblyLine[] alines = new AssemblyLine [ins.Count];
  329. for (int n=0; n<ins.Count; n++) {
  330. ResultData aline = ins.GetObject (n);
  331. long addr = long.Parse (aline.GetValue ("address").Substring (2), NumberStyles.HexNumber);
  332. AssemblyLine line = new AssemblyLine (addr, aline.GetValue ("inst"));
  333. alines [n] = line;
  334. }
  335. return alines;
  336. } catch {
  337. return new AssemblyLine [0];
  338. }
  339. }
  340. }
  341. }