DebugService.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  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. internal 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. internal 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. arg = *(StackObject**)&arg->Value;
  116. ILTypeInstance instance = arg->ObjectType != ObjectTypes.Null ? intepreter.Stack.ManagedStack[arg->Value] as ILTypeInstance : null;
  117. if (instance == null)
  118. return "null";
  119. var fields = instance.Type.TypeDefinition.Fields;
  120. int idx = 0;
  121. StringBuilder sb = new StringBuilder();
  122. for (int i = 0; i < fields.Count; i++)
  123. {
  124. var f = fields[i];
  125. if (f.IsStatic)
  126. continue;
  127. var field = instance.Fields[idx];
  128. var v = StackObject.ToObject(&field, intepreter.AppDomain, instance.ManagedObjects);
  129. if (v == null)
  130. v = "null";
  131. string name = f.Name;
  132. sb.AppendFormat("{0} {1} = {2}", f.FieldType.Name, name, v);
  133. if ((idx % 3 == 0 && idx != 0) || idx == instance.Fields.Length - 1)
  134. sb.AppendLine();
  135. else
  136. sb.Append(", ");
  137. idx++;
  138. }
  139. return sb.ToString();
  140. }
  141. internal unsafe string GetLocalVariableInfo(ILIntepreter intepreter)
  142. {
  143. StackFrame topFrame = intepreter.Stack.Frames.Peek();
  144. var m = topFrame.Method;
  145. StringBuilder sb = new StringBuilder();
  146. for (int i = 0; i < m.LocalVariableCount; i++)
  147. {
  148. var lv = m.Definition.Body.Variables[i];
  149. var val = Add(topFrame.LocalVarPointer, i);
  150. var v = StackObject.ToObject(val, intepreter.AppDomain, intepreter.Stack.ManagedStack);
  151. if (v == null)
  152. v = "null";
  153. string name = string.IsNullOrEmpty(lv.Name) ? "v" + lv.Index : lv.Name;
  154. sb.AppendFormat("{0} {1} = {2}", lv.VariableType.Name, name, v);
  155. if ((i % 3 == 0 && i != 0) || i == m.LocalVariableCount - 1)
  156. sb.AppendLine();
  157. else
  158. sb.Append(", ");
  159. }
  160. return sb.ToString();
  161. }
  162. internal static Mono.Cecil.Cil.SequencePoint FindSequencePoint(Mono.Cecil.Cil.Instruction ins)
  163. {
  164. Mono.Cecil.Cil.Instruction cur = ins;
  165. while (cur.SequencePoint == null && cur.Previous != null)
  166. cur = cur.Previous;
  167. return cur.SequencePoint;
  168. }
  169. unsafe StackObject* Add(StackObject* a, int b)
  170. {
  171. return (StackObject*)((long)a + sizeof(StackObject) * b);
  172. }
  173. unsafe StackObject* Minus(StackObject* a, int b)
  174. {
  175. return (StackObject*)((long)a - sizeof(StackObject) * b);
  176. }
  177. internal void NotifyModuleLoaded(string moduleName)
  178. {
  179. if (server != null && server.IsAttached)
  180. server.NotifyModuleLoaded(moduleName);
  181. }
  182. internal void SetBreakPoint(int methodHash, int bpHash, int startLine)
  183. {
  184. lock (activeBreakpoints)
  185. {
  186. LinkedList<BreakpointInfo> lst;
  187. if(!activeBreakpoints.TryGetValue(methodHash, out lst))
  188. {
  189. lst = new LinkedList<Debugger.BreakpointInfo>();
  190. activeBreakpoints[methodHash] = lst;
  191. }
  192. BreakpointInfo bpInfo = new BreakpointInfo();
  193. bpInfo.BreakpointHashCode = bpHash;
  194. bpInfo.MethodHashCode = methodHash;
  195. bpInfo.StartLine = startLine;
  196. lst.AddLast(bpInfo);
  197. breakpointMapping[bpHash] = bpInfo;
  198. }
  199. }
  200. internal void DeleteBreakpoint(int bpHash)
  201. {
  202. lock (activeBreakpoints)
  203. {
  204. BreakpointInfo bpInfo;
  205. if (breakpointMapping.TryGetValue(bpHash, out bpInfo))
  206. {
  207. LinkedList<BreakpointInfo> lst;
  208. if(activeBreakpoints.TryGetValue(bpInfo.MethodHashCode, out lst))
  209. {
  210. lst.Remove(bpInfo);
  211. }
  212. breakpointMapping.Remove(bpHash);
  213. }
  214. }
  215. }
  216. internal void ExecuteThread(int threadHash)
  217. {
  218. lock (AppDomain.FreeIntepreters)
  219. {
  220. foreach(var i in AppDomain.Intepreters)
  221. {
  222. //We should resume all threads on execute
  223. i.Value.ClearDebugState();
  224. i.Value.Resume();
  225. }
  226. }
  227. }
  228. internal unsafe void StepThread(int threadHash, StepTypes type)
  229. {
  230. lock (AppDomain.FreeIntepreters)
  231. {
  232. ILIntepreter intp;
  233. if(AppDomain.Intepreters.TryGetValue(threadHash, out intp))
  234. {
  235. intp.ClearDebugState();
  236. intp.CurrentStepType = type;
  237. intp.LastStepFrameBase = intp.Stack.Frames.Count > 0 ? intp.Stack.Frames.Peek().BasePointer : (StackObject*)0;
  238. intp.LastStepInstructionIndex = intp.Stack.Frames.Count > 0 ? intp.Stack.Frames.Peek().Address.Value : 0;
  239. intp.Resume();
  240. }
  241. }
  242. }
  243. unsafe internal void CheckShouldBreak(ILMethod method, ILIntepreter intp, int ip)
  244. {
  245. if (server != null && server.IsAttached)
  246. {
  247. int methodHash = method.GetHashCode();
  248. lock (activeBreakpoints)
  249. {
  250. LinkedList<BreakpointInfo> lst;
  251. bool bpHit = false;
  252. if (activeBreakpoints.TryGetValue(methodHash, out lst))
  253. {
  254. var sp = method.Definition.Body.Instructions[ip].SequencePoint;
  255. if (sp != null)
  256. {
  257. foreach (var i in lst)
  258. {
  259. if ((i.StartLine + 1) == sp.StartLine)
  260. {
  261. DoBreak(intp, i.BreakpointHashCode, false);
  262. bpHit = true;
  263. break;
  264. }
  265. }
  266. }
  267. }
  268. if (!bpHit)
  269. {
  270. var sp = method.Definition.Body.Instructions[ip].SequencePoint;
  271. if (sp != null && IsSequenceValid(sp))
  272. {
  273. switch (intp.CurrentStepType)
  274. {
  275. case StepTypes.Into:
  276. DoBreak(intp, 0, true);
  277. break;
  278. case StepTypes.Over:
  279. if (intp.Stack.Frames.Peek().BasePointer <= intp.LastStepFrameBase && ip != intp.LastStepInstructionIndex)
  280. {
  281. DoBreak(intp, 0, true);
  282. }
  283. break;
  284. case StepTypes.Out:
  285. {
  286. if (intp.Stack.Frames.Count > 0 && intp.Stack.Frames.Peek().BasePointer < intp.LastStepFrameBase)
  287. {
  288. DoBreak(intp, 0, true);
  289. }
  290. }
  291. break;
  292. }
  293. }
  294. }
  295. }
  296. }
  297. }
  298. bool IsSequenceValid(Mono.Cecil.Cil.SequencePoint sp)
  299. {
  300. return sp.StartLine != sp.EndLine || sp.StartColumn != sp.EndColumn;
  301. }
  302. void DoBreak(ILIntepreter intp, int bpHash, bool isStep)
  303. {
  304. KeyValuePair<int, StackFrameInfo[]>[] frames = new KeyValuePair<int, StackFrameInfo[]>[AppDomain.Intepreters.Count];
  305. frames[0] = new KeyValuePair<int, StackFrameInfo[]>(intp.GetHashCode(), GetStackFrameInfo(intp));
  306. int idx = 1;
  307. foreach (var j in AppDomain.Intepreters)
  308. {
  309. if (j.Value != intp)
  310. {
  311. j.Value.ShouldBreak = true;
  312. frames[idx++] = new KeyValuePair<int, Debugger.StackFrameInfo[]>(j.Value.GetHashCode(), GetStackFrameInfo(j.Value));
  313. }
  314. }
  315. if (!isStep)
  316. server.SendSCBreakpointHit(intp.GetHashCode(), bpHash, frames);
  317. else
  318. server.SendSCStepComplete(intp.GetHashCode(), frames);
  319. //Breakpoint hit
  320. intp.Break();
  321. }
  322. unsafe StackFrameInfo[] GetStackFrameInfo(ILIntepreter intp)
  323. {
  324. StackFrame[] frames = intp.Stack.Frames.ToArray();
  325. Mono.Cecil.Cil.Instruction ins = null;
  326. ILMethod m;
  327. StackFrameInfo[] frameInfos = new StackFrameInfo[frames.Length];
  328. for (int j = 0; j < frames.Length; j++)
  329. {
  330. StackFrameInfo info = new Debugger.StackFrameInfo();
  331. var f = frames[j];
  332. m = f.Method;
  333. info.MethodName = m.ToString();
  334. if (f.Address != null)
  335. {
  336. ins = m.Definition.Body.Instructions[f.Address.Value];
  337. var seq = FindSequencePoint(ins);
  338. if (seq != null)
  339. {
  340. info.DocumentName = seq.Document.Url;
  341. info.StartLine = seq.StartLine - 1;
  342. info.StartColumn = seq.StartColumn - 1;
  343. info.EndLine = seq.EndLine - 1;
  344. info.EndColumn = seq.EndColumn - 1;
  345. }
  346. }
  347. StackFrame topFrame = f;
  348. m = topFrame.Method;
  349. int argumentCount = m.ParameterCount;
  350. if (m.HasThis)
  351. argumentCount++;
  352. info.LocalVariables = new VariableInfo[argumentCount + m.LocalVariableCount];
  353. for(int i = 0; i < argumentCount; i++)
  354. {
  355. int argIdx = m.HasThis ? i - 1 : i;
  356. var arg = Minus(topFrame.LocalVarPointer, argumentCount);
  357. string name = null;
  358. object v = null;
  359. string typeName = null;
  360. var val = Add(arg, i);
  361. v = StackObject.ToObject(val, intp.AppDomain, intp.Stack.ManagedStack);
  362. if (v == null)
  363. v = "null";
  364. if (argIdx >= 0)
  365. {
  366. var lv = m.Definition.Parameters[argIdx];
  367. name = string.IsNullOrEmpty(lv.Name) ? "arg" + lv.Index : lv.Name;
  368. typeName = lv.ParameterType.FullName;
  369. if (v != null)
  370. v = m.Parameters[argIdx].TypeForCLR.CheckCLRTypes(intp.AppDomain, v);
  371. }
  372. else
  373. {
  374. name = "this";
  375. typeName = m.DeclearingType.FullName;
  376. }
  377. VariableInfo vinfo = new Debugger.VariableInfo();
  378. vinfo.Address = (long)val;
  379. vinfo.Name = name;
  380. vinfo.Value = v.ToString();
  381. vinfo.TypeName = typeName;
  382. vinfo.Expandable = GetValueExpandable(val, intp.Stack.ManagedStack);
  383. info.LocalVariables[i] = vinfo;
  384. }
  385. for (int i = argumentCount; i < info.LocalVariables.Length; i++)
  386. {
  387. var locIdx = i - argumentCount;
  388. var lv = m.Definition.Body.Variables[locIdx];
  389. var val = Add(topFrame.LocalVarPointer, locIdx);
  390. var v = StackObject.ToObject(val, intp.AppDomain, intp.Stack.ManagedStack);
  391. if (v == null)
  392. v = "null";
  393. else
  394. v = intp.AppDomain.GetType(lv.VariableType, m.DeclearingType, m).TypeForCLR.CheckCLRTypes(intp.AppDomain, v);
  395. string name = string.IsNullOrEmpty(lv.Name) ? "v" + lv.Index : lv.Name;
  396. VariableInfo vinfo = new Debugger.VariableInfo();
  397. vinfo.Address = (long)val;
  398. vinfo.Name = name;
  399. vinfo.Value = v.ToString();
  400. vinfo.TypeName = lv.VariableType.FullName;
  401. vinfo.Expandable = GetValueExpandable(val, intp.Stack.ManagedStack);
  402. info.LocalVariables[i] = vinfo;
  403. }
  404. frameInfos[j] = info;
  405. }
  406. return frameInfos;
  407. }
  408. internal VariableInfo ResolveVariable(VariableReference parent, string name)
  409. {
  410. return null;
  411. }
  412. unsafe bool GetValueExpandable(StackObject* esp, List<object> mStack)
  413. {
  414. if (esp->ObjectType < ObjectTypes.Object)
  415. return false;
  416. else
  417. {
  418. var obj = mStack[esp->Value];
  419. if (obj == null)
  420. return false;
  421. if (obj is ILTypeInstance)
  422. return true;
  423. else if (obj.GetType().IsPrimitive)
  424. return false;
  425. else
  426. return true;
  427. }
  428. }
  429. internal void ThreadStarted(ILIntepreter intp)
  430. {
  431. if (server != null && server.IsAttached)
  432. {
  433. server.SendSCThreadStarted(intp.GetHashCode());
  434. }
  435. }
  436. internal void ThreadEnded(ILIntepreter intp)
  437. {
  438. if (server != null && server.IsAttached)
  439. {
  440. server.SendSCThreadEnded(intp.GetHashCode());
  441. }
  442. }
  443. internal void Detach()
  444. {
  445. activeBreakpoints.Clear();
  446. breakpointMapping.Clear();
  447. foreach (var j in AppDomain.Intepreters)
  448. {
  449. j.Value.ClearDebugState();
  450. j.Value.Resume();
  451. }
  452. }
  453. }
  454. }