DebugService.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using ILRuntime.CLR.Method;
  7. using ILRuntime.Runtime.Intepreter;
  8. using ILRuntime.Runtime.Stack;
  9. using ILRuntime.CLR.Utils;
  10. namespace ILRuntime.Runtime.Debugger
  11. {
  12. public class DebugService
  13. {
  14. BreakPointContext curBreakpoint;
  15. DebuggerServer server;
  16. Runtime.Enviorment.AppDomain domain;
  17. Dictionary<int, LinkedList<BreakpointInfo>> activeBreakpoints = new Dictionary<int, LinkedList<BreakpointInfo>>();
  18. Dictionary<int, BreakpointInfo> breakpointMapping = new Dictionary<int, BreakpointInfo>();
  19. AutoResetEvent evt = new AutoResetEvent(false);
  20. public Action<string> OnBreakPoint;
  21. public Enviorment.AppDomain AppDomain { get { return domain; } }
  22. public AutoResetEvent BlockEvent { get { return evt; } }
  23. public bool IsDebuggerAttached
  24. {
  25. get
  26. {
  27. #if DEBUG
  28. return (server != null && server.IsAttached);
  29. #else
  30. return false;
  31. #endif
  32. }
  33. }
  34. public DebugService(Runtime.Enviorment.AppDomain domain)
  35. {
  36. this.domain = domain;
  37. }
  38. /// <summary>
  39. /// Start Debugger Server
  40. /// </summary>
  41. /// <param name="port">Port to listen on</param>
  42. public void StartDebugService(int port)
  43. {
  44. #if DEBUG
  45. server = new Debugger.DebuggerServer(this);
  46. server.Port = port;
  47. server.Start();
  48. #endif
  49. }
  50. /// <summary>
  51. /// Stop Debugger Server
  52. /// </summary>
  53. public void StopDebugService()
  54. {
  55. #if DEBUG
  56. server.Stop();
  57. server = null;
  58. #endif
  59. }
  60. /// <summary>
  61. /// 中断运行
  62. /// </summary>
  63. /// <param name="intpreter"></param>
  64. /// <param name="ex"></param>
  65. /// <returns>如果挂的有调试器则返回true</returns>
  66. internal bool Break(ILIntepreter intpreter, Exception ex = null)
  67. {
  68. BreakPointContext ctx = new BreakPointContext();
  69. ctx.Interpreter = intpreter;
  70. ctx.Exception = ex;
  71. curBreakpoint = ctx;
  72. if (OnBreakPoint != null)
  73. {
  74. OnBreakPoint(ctx.DumpContext());
  75. return true;
  76. }
  77. return false;
  78. }
  79. public string GetStackTrance(ILIntepreter intepreper)
  80. {
  81. StringBuilder sb = new StringBuilder();
  82. ILRuntime.CLR.Method.ILMethod m;
  83. StackFrame[] frames = intepreper.Stack.Frames.ToArray();
  84. Mono.Cecil.Cil.Instruction ins = null;
  85. if (frames[0].Address != null)
  86. {
  87. ins = frames[0].Method.Definition.Body.Instructions[frames[0].Address.Value];
  88. sb.AppendLine(ins.ToString());
  89. }
  90. for (int i = 0; i < frames.Length; i++)
  91. {
  92. var f = frames[i];
  93. m = f.Method;
  94. string document = "";
  95. if (f.Address != null)
  96. {
  97. ins = m.Definition.Body.Instructions[f.Address.Value];
  98. var seq = FindSequencePoint(ins);
  99. if (seq != null)
  100. {
  101. document = string.Format("{0}:Line {1}", seq.Document.Url, seq.StartLine);
  102. }
  103. }
  104. sb.AppendFormat("at {0} {1}\r\n", m, document);
  105. }
  106. return sb.ToString();
  107. }
  108. public unsafe string GetThisInfo(ILIntepreter intepreter)
  109. {
  110. var topFrame = intepreter.Stack.Frames.Peek();
  111. var arg = Minus(topFrame.LocalVarPointer, topFrame.Method.ParameterCount);
  112. if (topFrame.Method.HasThis)
  113. arg--;
  114. if (arg->ObjectType == ObjectTypes.StackObjectReference)
  115. {
  116. arg = *(StackObject**)&arg->Value;
  117. }
  118. ILTypeInstance instance = arg->ObjectType != ObjectTypes.Null ? intepreter.Stack.ManagedStack[arg->Value] as ILTypeInstance : null;
  119. if (instance == null)
  120. return "null";
  121. var fields = instance.Type.TypeDefinition.Fields;
  122. int idx = 0;
  123. StringBuilder sb = new StringBuilder();
  124. for (int i = 0; i < fields.Count; i++)
  125. {
  126. var f = fields[i];
  127. if (f.IsStatic)
  128. continue;
  129. var field = instance.Fields[idx];
  130. var v = StackObject.ToObject(&field, intepreter.AppDomain, instance.ManagedObjects);
  131. if (v == null)
  132. v = "null";
  133. string name = f.Name;
  134. sb.AppendFormat("{0} {1} = {2}", f.FieldType.Name, name, v);
  135. if ((idx % 3 == 0 && idx != 0) || idx == instance.Fields.Length - 1)
  136. sb.AppendLine();
  137. else
  138. sb.Append(", ");
  139. idx++;
  140. }
  141. return sb.ToString();
  142. }
  143. public unsafe string GetLocalVariableInfo(ILIntepreter intepreter)
  144. {
  145. StackFrame topFrame = intepreter.Stack.Frames.Peek();
  146. var m = topFrame.Method;
  147. StringBuilder sb = new StringBuilder();
  148. for (int i = 0; i < m.LocalVariableCount; i++)
  149. {
  150. var lv = m.Definition.Body.Variables[i];
  151. var val = Add(topFrame.LocalVarPointer, i);
  152. var v = StackObject.ToObject(val, intepreter.AppDomain, intepreter.Stack.ManagedStack);
  153. if (v == null)
  154. v = "null";
  155. string name = string.IsNullOrEmpty(lv.Name) ? "v" + lv.Index : lv.Name;
  156. sb.AppendFormat("{0} {1} = {2}", lv.VariableType.Name, name, v);
  157. if ((i % 3 == 0 && i != 0) || i == m.LocalVariableCount - 1)
  158. sb.AppendLine();
  159. else
  160. sb.Append(", ");
  161. }
  162. return sb.ToString();
  163. }
  164. internal static Mono.Cecil.Cil.SequencePoint FindSequencePoint(Mono.Cecil.Cil.Instruction ins)
  165. {
  166. Mono.Cecil.Cil.Instruction cur = ins;
  167. while (cur.SequencePoint == null && cur.Previous != null)
  168. cur = cur.Previous;
  169. return cur.SequencePoint;
  170. }
  171. unsafe StackObject* Add(StackObject* a, int b)
  172. {
  173. return (StackObject*)((long)a + sizeof(StackObject) * b);
  174. }
  175. unsafe StackObject* Minus(StackObject* a, int b)
  176. {
  177. return (StackObject*)((long)a - sizeof(StackObject) * b);
  178. }
  179. internal void NotifyModuleLoaded(string moduleName)
  180. {
  181. if (server != null && server.IsAttached)
  182. server.NotifyModuleLoaded(moduleName);
  183. }
  184. internal void SetBreakPoint(int methodHash, int bpHash, int startLine)
  185. {
  186. lock (activeBreakpoints)
  187. {
  188. LinkedList<BreakpointInfo> lst;
  189. if(!activeBreakpoints.TryGetValue(methodHash, out lst))
  190. {
  191. lst = new LinkedList<Debugger.BreakpointInfo>();
  192. activeBreakpoints[methodHash] = lst;
  193. }
  194. BreakpointInfo bpInfo = new BreakpointInfo();
  195. bpInfo.BreakpointHashCode = bpHash;
  196. bpInfo.MethodHashCode = methodHash;
  197. bpInfo.StartLine = startLine;
  198. lst.AddLast(bpInfo);
  199. breakpointMapping[bpHash] = bpInfo;
  200. }
  201. }
  202. internal void DeleteBreakpoint(int bpHash)
  203. {
  204. lock (activeBreakpoints)
  205. {
  206. BreakpointInfo bpInfo;
  207. if (breakpointMapping.TryGetValue(bpHash, out bpInfo))
  208. {
  209. LinkedList<BreakpointInfo> lst;
  210. if(activeBreakpoints.TryGetValue(bpInfo.MethodHashCode, out lst))
  211. {
  212. lst.Remove(bpInfo);
  213. }
  214. breakpointMapping.Remove(bpHash);
  215. }
  216. }
  217. }
  218. internal void ExecuteThread(int threadHash)
  219. {
  220. lock (AppDomain.FreeIntepreters)
  221. {
  222. foreach(var i in AppDomain.Intepreters)
  223. {
  224. //We should resume all threads on execute
  225. i.Value.ClearDebugState();
  226. i.Value.Resume();
  227. }
  228. }
  229. }
  230. internal unsafe void StepThread(int threadHash, StepTypes type)
  231. {
  232. lock (AppDomain.FreeIntepreters)
  233. {
  234. ILIntepreter intp;
  235. if(AppDomain.Intepreters.TryGetValue(threadHash, out intp))
  236. {
  237. intp.ClearDebugState();
  238. intp.CurrentStepType = type;
  239. intp.LastStepFrameBase = intp.Stack.Frames.Count > 0 ? intp.Stack.Frames.Peek().BasePointer : (StackObject*)0;
  240. intp.LastStepInstructionIndex = intp.Stack.Frames.Count > 0 ? intp.Stack.Frames.Peek().Address.Value : 0;
  241. intp.Resume();
  242. }
  243. }
  244. }
  245. unsafe internal void CheckShouldBreak(ILMethod method, ILIntepreter intp, int ip)
  246. {
  247. if (server != null && server.IsAttached)
  248. {
  249. int methodHash = method.GetHashCode();
  250. lock (activeBreakpoints)
  251. {
  252. LinkedList<BreakpointInfo> lst;
  253. bool bpHit = false;
  254. if (activeBreakpoints.TryGetValue(methodHash, out lst))
  255. {
  256. var sp = method.Definition.Body.Instructions[ip].SequencePoint;
  257. if (sp != null)
  258. {
  259. foreach (var i in lst)
  260. {
  261. if ((i.StartLine + 1) == sp.StartLine)
  262. {
  263. DoBreak(intp, i.BreakpointHashCode, false);
  264. bpHit = true;
  265. break;
  266. }
  267. }
  268. }
  269. }
  270. if (!bpHit)
  271. {
  272. var sp = method.Definition.Body.Instructions[ip].SequencePoint;
  273. if (sp != null && IsSequenceValid(sp))
  274. {
  275. switch (intp.CurrentStepType)
  276. {
  277. case StepTypes.Into:
  278. DoBreak(intp, 0, true);
  279. break;
  280. case StepTypes.Over:
  281. if (intp.Stack.Frames.Peek().BasePointer <= intp.LastStepFrameBase && ip != intp.LastStepInstructionIndex)
  282. {
  283. DoBreak(intp, 0, true);
  284. }
  285. break;
  286. case StepTypes.Out:
  287. {
  288. if (intp.Stack.Frames.Count > 0 && intp.Stack.Frames.Peek().BasePointer < intp.LastStepFrameBase)
  289. {
  290. DoBreak(intp, 0, true);
  291. }
  292. }
  293. break;
  294. }
  295. }
  296. }
  297. }
  298. }
  299. }
  300. bool IsSequenceValid(Mono.Cecil.Cil.SequencePoint sp)
  301. {
  302. return sp.StartLine != sp.EndLine || sp.StartColumn != sp.EndColumn;
  303. }
  304. void DoBreak(ILIntepreter intp, int bpHash, bool isStep)
  305. {
  306. KeyValuePair<int, StackFrameInfo[]>[] frames = new KeyValuePair<int, StackFrameInfo[]>[AppDomain.Intepreters.Count];
  307. frames[0] = new KeyValuePair<int, StackFrameInfo[]>(intp.GetHashCode(), GetStackFrameInfo(intp));
  308. int idx = 1;
  309. foreach (var j in AppDomain.Intepreters)
  310. {
  311. if (j.Value != intp)
  312. {
  313. j.Value.ShouldBreak = true;
  314. frames[idx++] = new KeyValuePair<int, Debugger.StackFrameInfo[]>(j.Value.GetHashCode(), GetStackFrameInfo(j.Value));
  315. }
  316. }
  317. if (!isStep)
  318. server.SendSCBreakpointHit(intp.GetHashCode(), bpHash, frames);
  319. else
  320. server.SendSCStepComplete(intp.GetHashCode(), frames);
  321. //Breakpoint hit
  322. intp.Break();
  323. }
  324. unsafe StackFrameInfo[] GetStackFrameInfo(ILIntepreter intp)
  325. {
  326. StackFrame[] frames = intp.Stack.Frames.ToArray();
  327. Mono.Cecil.Cil.Instruction ins = null;
  328. ILMethod m;
  329. StackFrameInfo[] frameInfos = new StackFrameInfo[frames.Length];
  330. for (int j = 0; j < frames.Length; j++)
  331. {
  332. StackFrameInfo info = new Debugger.StackFrameInfo();
  333. var f = frames[j];
  334. m = f.Method;
  335. info.MethodName = m.ToString();
  336. if (f.Address != null)
  337. {
  338. ins = m.Definition.Body.Instructions[f.Address.Value];
  339. var seq = FindSequencePoint(ins);
  340. if (seq != null)
  341. {
  342. info.DocumentName = seq.Document.Url;
  343. info.StartLine = seq.StartLine - 1;
  344. info.StartColumn = seq.StartColumn - 1;
  345. info.EndLine = seq.EndLine - 1;
  346. info.EndColumn = seq.EndColumn - 1;
  347. }
  348. }
  349. StackFrame topFrame = f;
  350. m = topFrame.Method;
  351. int argumentCount = m.ParameterCount;
  352. if (m.HasThis)
  353. argumentCount++;
  354. info.LocalVariables = new VariableInfo[argumentCount + m.LocalVariableCount];
  355. for(int i = 0; i < argumentCount; i++)
  356. {
  357. int argIdx = m.HasThis ? i - 1 : i;
  358. var arg = Minus(topFrame.LocalVarPointer, argumentCount);
  359. string name = null;
  360. object v = null;
  361. string typeName = null;
  362. var val = Add(arg, i);
  363. v = StackObject.ToObject(val, intp.AppDomain, intp.Stack.ManagedStack);
  364. if (v == null)
  365. v = "null";
  366. if (argIdx >= 0)
  367. {
  368. var lv = m.Definition.Parameters[argIdx];
  369. name = string.IsNullOrEmpty(lv.Name) ? "arg" + lv.Index : lv.Name;
  370. typeName = lv.ParameterType.FullName;
  371. if (v != null)
  372. v = m.Parameters[argIdx].TypeForCLR.CheckCLRTypes(v);
  373. }
  374. else
  375. {
  376. name = "this";
  377. typeName = m.DeclearingType.FullName;
  378. }
  379. VariableInfo vinfo = new Debugger.VariableInfo();
  380. vinfo.Address = (long)val;
  381. vinfo.Name = name;
  382. vinfo.Value = v.ToString();
  383. vinfo.TypeName = typeName;
  384. vinfo.Expandable = GetValueExpandable(val, intp.Stack.ManagedStack);
  385. info.LocalVariables[i] = vinfo;
  386. }
  387. for (int i = argumentCount; i < info.LocalVariables.Length; i++)
  388. {
  389. var locIdx = i - argumentCount;
  390. var lv = m.Definition.Body.Variables[locIdx];
  391. var val = Add(topFrame.LocalVarPointer, locIdx);
  392. var v = StackObject.ToObject(val, intp.AppDomain, intp.Stack.ManagedStack);
  393. if (v == null)
  394. v = "null";
  395. else
  396. v = intp.AppDomain.GetType(lv.VariableType, m.DeclearingType, m).TypeForCLR.CheckCLRTypes(v);
  397. string name = string.IsNullOrEmpty(lv.Name) ? "v" + lv.Index : lv.Name;
  398. VariableInfo vinfo = new Debugger.VariableInfo();
  399. vinfo.Address = (long)val;
  400. vinfo.Name = name;
  401. vinfo.Value = v.ToString();
  402. vinfo.TypeName = lv.VariableType.FullName;
  403. vinfo.Expandable = GetValueExpandable(val, intp.Stack.ManagedStack);
  404. info.LocalVariables[i] = vinfo;
  405. }
  406. frameInfos[j] = info;
  407. }
  408. return frameInfos;
  409. }
  410. internal VariableInfo ResolveVariable(VariableReference parent, string name)
  411. {
  412. return null;
  413. }
  414. unsafe bool GetValueExpandable(StackObject* esp, List<object> mStack)
  415. {
  416. if (esp->ObjectType < ObjectTypes.Object)
  417. return false;
  418. else
  419. {
  420. var obj = mStack[esp->Value];
  421. if (obj == null)
  422. return false;
  423. if (obj is ILTypeInstance)
  424. return true;
  425. else if (obj.GetType().IsPrimitive)
  426. return false;
  427. else
  428. return true;
  429. }
  430. }
  431. internal void ThreadStarted(ILIntepreter intp)
  432. {
  433. if (server != null && server.IsAttached)
  434. {
  435. server.SendSCThreadStarted(intp.GetHashCode());
  436. }
  437. }
  438. internal void ThreadEnded(ILIntepreter intp)
  439. {
  440. if (server != null && server.IsAttached)
  441. {
  442. server.SendSCThreadEnded(intp.GetHashCode());
  443. }
  444. }
  445. internal void Detach()
  446. {
  447. activeBreakpoints.Clear();
  448. breakpointMapping.Clear();
  449. foreach (var j in AppDomain.Intepreters)
  450. {
  451. j.Value.ClearDebugState();
  452. j.Value.Resume();
  453. }
  454. }
  455. }
  456. }