DebuggerServer.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Net.Sockets;
  7. using ILRuntime.CLR.TypeSystem;
  8. using ILRuntime.CLR.Method;
  9. using ILRuntime.Runtime.Debugger.Protocol;
  10. namespace ILRuntime.Runtime.Debugger
  11. {
  12. #pragma warning disable
  13. public class DebuggerServer
  14. {
  15. public const int Version = 2;
  16. TcpListener listener;
  17. //HashSet<Session<T>> clients = new HashSet<Session<T>>();
  18. bool isUp = false;
  19. bool shutdown = false;
  20. int maxNewConnections = 1;
  21. int port;
  22. Thread mainLoop;
  23. DebugSocket clientSocket;
  24. System.IO.MemoryStream sendStream = new System.IO.MemoryStream(64 * 1024);
  25. System.IO.BinaryWriter bw;
  26. DebugService ds;
  27. /// <summary>
  28. /// 服务器监听的端口
  29. /// </summary>
  30. public int Port { get { return port; } set { this.port = value; } }
  31. public DebugSocket Client { get { return clientSocket; } }
  32. public bool IsAttached { get { return clientSocket != null && !clientSocket.Disconnected; } }
  33. public DebuggerServer(DebugService ds)
  34. {
  35. this.ds = ds;
  36. bw = new System.IO.BinaryWriter(sendStream);
  37. }
  38. public virtual bool Start()
  39. {
  40. shutdown = false;
  41. mainLoop = new Thread(new ThreadStart(this.NetworkLoop));
  42. mainLoop.Start();
  43. this.listener = new TcpListener(port);
  44. try { listener.Start(); }
  45. catch
  46. {
  47. return false;
  48. }
  49. isUp = true;
  50. return true;
  51. }
  52. public virtual void Stop()
  53. {
  54. isUp = false;
  55. shutdown = true;
  56. if (this.listener != null)
  57. this.listener.Stop();
  58. mainLoop = null;
  59. if (clientSocket != null)
  60. clientSocket.Close();
  61. }
  62. void NetworkLoop()
  63. {
  64. while (!shutdown)
  65. {
  66. try
  67. {
  68. // let new clients (max 10) connect
  69. if (isUp && clientSocket == null)
  70. {
  71. for (int i = 0; listener.Pending() && i < maxNewConnections; i++)
  72. {
  73. CreateNewSession(listener);
  74. }
  75. }
  76. System.Threading.Thread.Sleep(1);
  77. }
  78. catch (ThreadAbortException)
  79. {
  80. }
  81. catch (Exception)
  82. {
  83. }
  84. }
  85. }
  86. void CreateNewSession(TcpListener listener)
  87. {
  88. Socket sock = listener.AcceptSocket();
  89. clientSocket = new DebugSocket(sock);
  90. clientSocket.OnReciveMessage = OnReceive;
  91. clientSocket.OnClose = OnClose;
  92. ClientConnected();
  93. }
  94. void ClientConnected()
  95. {
  96. }
  97. void OnClose()
  98. {
  99. ds.Detach();
  100. clientSocket = null;
  101. }
  102. void OnReceive(DebugMessageType type, byte[] buffer)
  103. {
  104. if (clientSocket == null || clientSocket.Disconnected)
  105. return;
  106. System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
  107. System.IO.BinaryReader br = new System.IO.BinaryReader(ms);
  108. switch (type)
  109. {
  110. case DebugMessageType.CSAttach:
  111. {
  112. SendAttachResult();
  113. }
  114. break;
  115. case DebugMessageType.CSBindBreakpoint:
  116. {
  117. CSBindBreakpoint msg = new Protocol.CSBindBreakpoint();
  118. msg.BreakpointHashCode = br.ReadInt32();
  119. msg.IsLambda = br.ReadBoolean();
  120. msg.TypeName = br.ReadString();
  121. msg.MethodName = br.ReadString();
  122. msg.StartLine = br.ReadInt32();
  123. msg.EndLine = br.ReadInt32();
  124. TryBindBreakpoint(msg);
  125. }
  126. break;
  127. case DebugMessageType.CSDeleteBreakpoint:
  128. {
  129. CSDeleteBreakpoint msg = new Protocol.CSDeleteBreakpoint();
  130. msg.BreakpointHashCode = br.ReadInt32();
  131. ds.DeleteBreakpoint(msg.BreakpointHashCode);
  132. }
  133. break;
  134. case DebugMessageType.CSExecute:
  135. {
  136. CSExecute msg = new Protocol.CSExecute();
  137. msg.ThreadHashCode = br.ReadInt32();
  138. ds.ExecuteThread(msg.ThreadHashCode);
  139. }
  140. break;
  141. case DebugMessageType.CSStep:
  142. {
  143. CSStep msg = new CSStep();
  144. msg.ThreadHashCode = br.ReadInt32();
  145. msg.StepType = (StepTypes)br.ReadByte();
  146. ds.StepThread(msg.ThreadHashCode, msg.StepType);
  147. }
  148. break;
  149. case DebugMessageType.CSResolveVariable:
  150. {
  151. CSResolveVariable msg = new CSResolveVariable();
  152. msg.ThreadHashCode = br.ReadInt32();
  153. msg.Variable = ReadVariableReference(br);
  154. VariableInfo info;
  155. try
  156. {
  157. object res;
  158. info = ds.ResolveVariable(msg.ThreadHashCode, msg.Variable, out res);
  159. }
  160. catch (Exception ex)
  161. {
  162. info = VariableInfo.GetException(ex);
  163. }
  164. if (info.Type != VariableTypes.Pending)
  165. SendSCResolveVariableResult(info);
  166. }
  167. break;
  168. case DebugMessageType.CSResolveIndexAccess:
  169. {
  170. CSResolveIndexer msg = new CSResolveIndexer();
  171. msg.ThreadHashCode = br.ReadInt32();
  172. msg.Body = ReadVariableReference(br);
  173. msg.Index = ReadVariableReference(br);
  174. VariableInfo info;
  175. try
  176. {
  177. object res;
  178. info = ds.ResolveIndexAccess(msg.ThreadHashCode, msg.Body, msg.Index, out res);
  179. }
  180. catch(Exception ex)
  181. {
  182. info = VariableInfo.GetException(ex);
  183. }
  184. if (info.Type != VariableTypes.Pending)
  185. SendSCResolveVariableResult(info);
  186. }
  187. break;
  188. case DebugMessageType.CSEnumChildren:
  189. {
  190. int thId = br.ReadInt32();
  191. var parent = ReadVariableReference(br);
  192. VariableInfo[] info = null;
  193. try
  194. {
  195. info = ds.EnumChildren(thId, parent);
  196. }
  197. catch(Exception ex)
  198. {
  199. info = new VariableInfo[] { VariableInfo.GetException(ex) };
  200. }
  201. if (info != null)
  202. SendSCEnumChildrenResult(info);
  203. }
  204. break;
  205. }
  206. }
  207. VariableReference ReadVariableReference(System.IO.BinaryReader br)
  208. {
  209. VariableReference res = null;
  210. if (br.ReadBoolean())
  211. {
  212. res = new Debugger.VariableReference();
  213. res.Address = br.ReadInt64();
  214. res.Type = (VariableTypes)br.ReadByte();
  215. res.Offset = br.ReadInt32();
  216. res.Name = br.ReadString();
  217. res.Parent = ReadVariableReference(br);
  218. int cnt = br.ReadInt32();
  219. res.Parameters = new VariableReference[cnt];
  220. for(int i = 0; i < cnt; i++)
  221. {
  222. res.Parameters[i] = ReadVariableReference(br);
  223. }
  224. }
  225. return res;
  226. }
  227. void SendAttachResult()
  228. {
  229. sendStream.Position = 0;
  230. bw.Write((byte)AttachResults.OK);
  231. bw.Write(Version);
  232. DoSend(DebugMessageType.SCAttachResult);
  233. lock (ds.AppDomain.FreeIntepreters)
  234. {
  235. foreach (var i in ds.AppDomain.Intepreters)
  236. {
  237. SendSCThreadStarted(i.Key);
  238. }
  239. }
  240. }
  241. void DoSend(DebugMessageType type)
  242. {
  243. if (clientSocket != null && !clientSocket.Disconnected)
  244. clientSocket.Send(type, sendStream.GetBuffer(), (int)sendStream.Position);
  245. }
  246. bool CheckCompilerGeneratedStateMachine(ILMethod ilm, Enviorment.AppDomain domain,int startLine, out ILMethod found)
  247. {
  248. var mDef = ilm.Definition;
  249. Mono.Cecil.CustomAttribute ca = null;
  250. found = null;
  251. foreach (var attr in mDef.CustomAttributes)
  252. {
  253. switch (attr.AttributeType.FullName)
  254. {
  255. case "System.Runtime.CompilerServices.AsyncStateMachineAttribute":
  256. case "System.Runtime.CompilerServices.IteratorStateMachineAttribute":
  257. ca = attr;
  258. break;
  259. }
  260. }
  261. if (ca != null)
  262. {
  263. if (ca.ConstructorArguments.Count > 0)
  264. {
  265. var smType = domain.GetType(ca.ConstructorArguments[0].Value, null, null);
  266. if (smType != null)
  267. {
  268. ilm = smType.GetMethod("MoveNext", 0, true) as ILMethod;
  269. if (ilm != null && ilm.StartLine <= (startLine + 1) && ilm.EndLine >= (startLine + 1))
  270. {
  271. found = ilm;
  272. return true;
  273. }
  274. }
  275. }
  276. }
  277. return false;
  278. }
  279. void TryBindBreakpoint(CSBindBreakpoint msg)
  280. {
  281. var domain = ds.AppDomain;
  282. SCBindBreakpointResult res = new Protocol.SCBindBreakpointResult();
  283. res.BreakpointHashCode = msg.BreakpointHashCode;
  284. IType type;
  285. if (msg.IsLambda)
  286. {
  287. ILMethod found = null;
  288. foreach (var i in domain.LoadedTypes.ToArray())
  289. {
  290. var vt = i.Value as ILType;
  291. if (vt != null)
  292. {
  293. if (vt.FullName.Contains(msg.TypeName))
  294. {
  295. foreach (var j in vt.GetMethods())
  296. {
  297. if (j.Name.Contains(string.Format("<{0}>", msg.MethodName)))
  298. {
  299. ILMethod ilm = (ILMethod)j;
  300. if (ilm.StartLine <= (msg.StartLine + 1) && ilm.EndLine >= (msg.StartLine + 1))
  301. {
  302. found = ilm;
  303. break;
  304. }
  305. else if (CheckCompilerGeneratedStateMachine(ilm, domain, msg.StartLine, out found))
  306. {
  307. break;
  308. }
  309. }
  310. }
  311. }
  312. }
  313. if (found != null)
  314. break;
  315. }
  316. if (found != null)
  317. {
  318. ds.SetBreakPoint(found.GetHashCode(), msg.BreakpointHashCode, msg.StartLine);
  319. res.Result = BindBreakpointResults.OK;
  320. }
  321. else
  322. {
  323. res.Result = BindBreakpointResults.CodeNotFound;
  324. }
  325. }
  326. else
  327. {
  328. if (domain.LoadedTypes.TryGetValue(msg.TypeName, out type))
  329. {
  330. if (type is ILType)
  331. {
  332. ILType it = (ILType)type;
  333. ILMethod found = null;
  334. if (msg.MethodName == ".ctor")
  335. {
  336. foreach (var i in it.GetConstructors())
  337. {
  338. ILMethod ilm = (ILMethod)i;
  339. if (ilm.StartLine <= (msg.StartLine + 1) && ilm.EndLine >= (msg.StartLine + 1))
  340. {
  341. found = ilm;
  342. break;
  343. }
  344. }
  345. }
  346. else if (msg.MethodName == ".cctor")
  347. {
  348. ILMethod ilm = it.GetStaticConstroctor() as ILMethod;
  349. if (ilm.StartLine <= (msg.StartLine + 1) && ilm.EndLine >= (msg.StartLine + 1))
  350. {
  351. found = ilm;
  352. }
  353. }
  354. else
  355. {
  356. foreach (var i in it.GetMethods())
  357. {
  358. if (i.Name == msg.MethodName)
  359. {
  360. ILMethod ilm = (ILMethod)i;
  361. if (ilm.StartLine <= (msg.StartLine + 1) && ilm.EndLine >= (msg.StartLine + 1))
  362. {
  363. found = ilm;
  364. break;
  365. }
  366. else if(CheckCompilerGeneratedStateMachine(ilm, domain, msg.StartLine, out found))
  367. {
  368. break;
  369. }
  370. }
  371. }
  372. }
  373. if (found != null)
  374. {
  375. ds.SetBreakPoint(found.GetHashCode(), msg.BreakpointHashCode, msg.StartLine);
  376. res.Result = BindBreakpointResults.OK;
  377. }
  378. else
  379. {
  380. res.Result = BindBreakpointResults.CodeNotFound;
  381. }
  382. }
  383. else
  384. {
  385. res.Result = BindBreakpointResults.TypeNotFound;
  386. }
  387. }
  388. else
  389. {
  390. res.Result = BindBreakpointResults.TypeNotFound;
  391. }
  392. }
  393. SendSCBindBreakpointResult(res);
  394. }
  395. void SendSCBindBreakpointResult(SCBindBreakpointResult msg)
  396. {
  397. sendStream.Position = 0;
  398. bw.Write(msg.BreakpointHashCode);
  399. bw.Write((byte)msg.Result);
  400. DoSend(DebugMessageType.SCBindBreakpointResult);
  401. }
  402. internal void SendSCBreakpointHit(int intpHash, int bpHash, KeyValuePair<int, StackFrameInfo[]>[] info)
  403. {
  404. sendStream.Position = 0;
  405. bw.Write(bpHash);
  406. bw.Write(intpHash);
  407. WriteStackFrames(info);
  408. DoSend(DebugMessageType.SCBreakpointHit);
  409. }
  410. internal void SendSCStepComplete(int intpHash, KeyValuePair<int, StackFrameInfo[]>[] info)
  411. {
  412. sendStream.Position = 0;
  413. bw.Write(intpHash);
  414. WriteStackFrames(info);
  415. DoSend(DebugMessageType.SCStepComplete);
  416. }
  417. internal void SendSCResolveVariableResult(VariableInfo info)
  418. {
  419. lock (this)
  420. {
  421. sendStream.Position = 0;
  422. WriteVariableInfo(info);
  423. DoSend(DebugMessageType.SCResolveVariableResult);
  424. }
  425. }
  426. internal void SendSCEnumChildrenResult(VariableInfo[] info)
  427. {
  428. lock (this)
  429. {
  430. sendStream.Position = 0;
  431. if (info != null)
  432. {
  433. bw.Write(info.Length);
  434. for (int i = 0; i < info.Length; i++)
  435. {
  436. WriteVariableInfo(info[i]);
  437. }
  438. }
  439. else
  440. bw.Write(0);
  441. DoSend(DebugMessageType.SCEnumChildrenResult);
  442. }
  443. }
  444. void WriteStackFrames(KeyValuePair<int, StackFrameInfo[]>[] info)
  445. {
  446. bw.Write(info.Length);
  447. foreach (var i in info)
  448. {
  449. bw.Write(i.Key);
  450. bw.Write(i.Value.Length);
  451. foreach (var j in i.Value)
  452. {
  453. bw.Write(j.MethodName);
  454. bw.Write(j.DocumentName);
  455. bw.Write(j.StartLine);
  456. bw.Write(j.StartColumn);
  457. bw.Write(j.EndLine);
  458. bw.Write(j.EndColumn);
  459. bw.Write(j.LocalVariables.Length);
  460. foreach (var k in j.LocalVariables)
  461. {
  462. WriteVariableInfo(k);
  463. }
  464. }
  465. }
  466. }
  467. void WriteVariableInfo(VariableInfo k)
  468. {
  469. bw.Write(k.Address);
  470. bw.Write((byte)k.Type);
  471. bw.Write(k.Offset);
  472. bw.Write(k.Name);
  473. bw.Write(k.Value);
  474. bw.Write((byte)k.ValueType);
  475. bw.Write(k.TypeName);
  476. bw.Write(k.Expandable);
  477. bw.Write(k.IsPrivate);
  478. bw.Write(k.IsProtected);
  479. }
  480. internal void SendSCThreadStarted(int threadHash)
  481. {
  482. sendStream.Position = 0;
  483. bw.Write(threadHash);
  484. DoSend(DebugMessageType.SCThreadStarted);
  485. }
  486. internal void SendSCThreadEnded(int threadHash)
  487. {
  488. sendStream.Position = 0;
  489. bw.Write(threadHash);
  490. DoSend(DebugMessageType.SCThreadEnded);
  491. }
  492. public void NotifyModuleLoaded(string modulename)
  493. {
  494. sendStream.Position = 0;
  495. bw.Write(modulename);
  496. DoSend(DebugMessageType.SCModuleLoaded);
  497. }
  498. }
  499. }