MainForm.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Diagnostics;
  6. using System.Drawing;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Windows.Forms;
  12. using MoonSharp.Interpreter;
  13. using MoonSharp.Interpreter.CoreLib;
  14. using MoonSharp.Interpreter.Debugging;
  15. using MoonSharp.Interpreter.Execution;
  16. using MoonSharp.Interpreter.Execution.VM;
  17. using MoonSharp.Interpreter.Loaders;
  18. namespace MoonSharp.Debugger
  19. {
  20. public partial class MainForm : Form, IDebugger
  21. {
  22. List<DynamicExpression> m_Watches = new List<DynamicExpression>();
  23. public MainForm()
  24. {
  25. InitializeComponent();
  26. }
  27. private void MainForm_Load(object sender, EventArgs e)
  28. {
  29. m_Ctx = SynchronizationContext.Current;
  30. Script.WarmUp();
  31. }
  32. private void openToolStripMenuItem_Click(object sender, EventArgs e)
  33. {
  34. OpenFileDialog ofd = new OpenFileDialog();
  35. ofd.Title = "Load script";
  36. ofd.DefaultExt = "lua";
  37. ofd.Filter = "Lua files (*.lua)|*.lua|All files (*.*)|*.*";
  38. if (ofd.ShowDialog() == DialogResult.OK)
  39. {
  40. DebugScript(ofd.FileName);
  41. openToolStripMenuItem.Enabled = false;
  42. }
  43. }
  44. Script m_Script;
  45. SynchronizationContext m_Ctx;
  46. private void Console_WriteLine(string fmt, params object[] args)
  47. {
  48. fmt = string.Format(fmt, args);
  49. m_Ctx.Post(str =>
  50. {
  51. txtOutput.Text = txtOutput.Text + fmt.ToString().Replace("\n", "\r\n") + "\r\n";
  52. txtOutput.SelectionStart = txtOutput.Text.Length - 1;
  53. txtOutput.SelectionLength = 0;
  54. txtOutput.ScrollToCaret();
  55. }, fmt);
  56. }
  57. private void DebugScript(string filename)
  58. {
  59. m_Script = new Script(CoreModules.Preset_Complete);
  60. m_Script.DebugPrint = s => { Console_WriteLine("{0}", s); };
  61. var L = new ClassicLuaScriptLoader();
  62. L.ModulePaths = L.UnpackStringPaths("Modules/?;Modules/?.lua");
  63. m_Script.ScriptLoader = L;
  64. try
  65. {
  66. m_Script.LoadFile(filename, null, filename.Replace(':', '|'));
  67. }
  68. catch (Exception ex)
  69. {
  70. txtOutput.Text = "";
  71. Console_WriteLine("{0}", ex.Message);
  72. return;
  73. }
  74. m_Script.AttachDebugger(this);
  75. Thread m_Debugger = new Thread(DebugMain);
  76. m_Debugger.Name = "MoonSharp Execution Thread";
  77. m_Debugger.IsBackground = true;
  78. m_Debugger.Start();
  79. }
  80. public void SetSourceCode(SourceCode sourceCode)
  81. {
  82. }
  83. void IDebugger.SetByteCode(string[] byteCode)
  84. {
  85. string[] source = byteCode.Select((s, i) => string.Format("{0:X8} {1}", i, s)).ToArray();
  86. m_Ctx.Send(o =>
  87. {
  88. codeView.SourceCode = source;
  89. }, null);
  90. }
  91. DebuggerAction m_NextAction;
  92. AutoResetEvent m_WaitLock = new AutoResetEvent(false);
  93. AutoResetEvent m_WaitBack = new AutoResetEvent(false);
  94. DebuggerAction IDebugger.GetAction(int ip, SourceRef sourceCodeRef)
  95. {
  96. m_Ctx.Post(o =>
  97. {
  98. codeView.ActiveLine = ip;
  99. RefreshCodeView(sourceCodeRef);
  100. }, null);
  101. m_WaitLock.WaitOne();
  102. DebuggerAction action = m_NextAction;
  103. m_NextAction = null;
  104. m_WaitBack.Set();
  105. return action;
  106. }
  107. SourceRef m_PrevRef = null;
  108. private void RefreshCodeView(SourceRef sourceCodeRef)
  109. {
  110. if (sourceCodeRef == m_PrevRef)
  111. return;
  112. m_PrevRef = sourceCodeRef;
  113. if (sourceCodeRef == null)
  114. {
  115. txtCodeView.Text = "!! NULL !!";
  116. }
  117. else
  118. {
  119. SourceCode sc = m_Script.GetSourceCode(sourceCodeRef.SourceIdx);
  120. //txtCodeView.Text = sc.Lines[sourceCodeRef.FromLine + 1] + "\n" +
  121. // sourceCodeRef.ToString();
  122. txtCodeView.Text = sc.GetCodeSnippet(sourceCodeRef) + "\r\n\r\n" + sourceCodeRef.ToString();
  123. }
  124. }
  125. void DebugAction(DebuggerAction action)
  126. {
  127. bool savedState = timerFollow.Enabled;
  128. timerFollow.Enabled = false;
  129. m_NextAction = action;
  130. m_WaitLock.Set();
  131. if (!m_WaitBack.WaitOne(1000))
  132. {
  133. MessageBox.Show(this, "Operation timed out", "Timeout");
  134. }
  135. else
  136. {
  137. timerFollow.Enabled = savedState;
  138. }
  139. }
  140. void DebugMain()
  141. {
  142. try
  143. {
  144. m_Script.Call(m_Script.GetMainChunk());
  145. }
  146. catch (ScriptRuntimeException ex)
  147. {
  148. timerFollow.Enabled = false;
  149. Console_WriteLine("Guest raised unhandled CLR exception: {0} -@{3:X8} {2}\n{1}\n", ex.GetType(), ex.ToString(), ex.DecoratedMessage, ex.InstructionPtr);
  150. }
  151. catch (Exception ex)
  152. {
  153. timerFollow.Enabled = false;
  154. Console_WriteLine("Guest raised unhandled CLR exception: {0} \n{1}\n", ex.GetType(), ex.ToString());
  155. }
  156. }
  157. private void StepIN()
  158. {
  159. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.ByteCodeStepIn });
  160. }
  161. private void StepOVER()
  162. {
  163. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.ByteCodeStepOver });
  164. }
  165. private void GO()
  166. {
  167. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Run });
  168. }
  169. void IDebugger.Update(WatchType watchType, IEnumerable<WatchItem> items)
  170. {
  171. if (watchType == WatchType.CallStack)
  172. m_Ctx.Post(UpdateCallStack, items);
  173. if (watchType == WatchType.Watches)
  174. m_Ctx.Post(UpdateWatches, items);
  175. if (watchType == WatchType.VStack)
  176. m_Ctx.Post(UpdateVStack, items);
  177. }
  178. void UpdateVStack(object o)
  179. {
  180. IEnumerable<WatchItem> items = (IEnumerable<WatchItem>)o;
  181. lvVStack.BeginUpdate();
  182. lvVStack.Items.Clear();
  183. foreach (var item in items)
  184. {
  185. lvVStack.Add(
  186. item.Address.ToString("X4"),
  187. (item.Value != null) ? item.Value.Type.ToString() : "(undefined)",
  188. (item.Value != null) ? item.Value.ToString() : "(undefined)"
  189. ).Tag = item.Value;
  190. }
  191. lvVStack.EndUpdate();
  192. }
  193. void UpdateWatches(object o)
  194. {
  195. IEnumerable<WatchItem> items = (IEnumerable<WatchItem>)o;
  196. lvWatches.BeginUpdate();
  197. lvWatches.Items.Clear();
  198. foreach (var item in items)
  199. {
  200. lvWatches.Add(
  201. item.Name ?? "(???)",
  202. (item.Value != null) ? item.Value.Type.ToLuaTypeString() : "(undefined)",
  203. (item.Value != null) ? item.Value.ToString() : "(undefined)",
  204. (item.LValue != null) ? item.LValue.ToString() : "(undefined)"
  205. ).Tag = item.Value;
  206. }
  207. lvWatches.EndUpdate();
  208. }
  209. void UpdateCallStack(object o)
  210. {
  211. IEnumerable<WatchItem> items = (IEnumerable<WatchItem>)o;
  212. lvCallStack.BeginUpdate();
  213. lvCallStack.Items.Clear();
  214. foreach (var item in items)
  215. {
  216. lvCallStack.Add(
  217. item.Address.ToString("X8"),
  218. item.Name ?? ((item.RetAddress < 0) ? "<chunk-root>" : "<??unknown??>"),
  219. item.RetAddress.ToString("X8"),
  220. item.BasePtr.ToString("X8")
  221. ).Tag = item.Address;
  222. }
  223. lvCallStack.Add("---", "<CLR>", "---", "---");
  224. lvCallStack.EndUpdate();
  225. }
  226. List<DynamicExpression> IDebugger.GetWatchItems()
  227. {
  228. return m_Watches;
  229. }
  230. private void btnAddWatch_Click(object sender, EventArgs e)
  231. {
  232. string text = WatchInputDialog.GetNewWatchName();
  233. if (!string.IsNullOrEmpty(text))
  234. {
  235. string[] codeToAdd = text.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
  236. m_Watches.AddRange(codeToAdd.Select(code => m_Script.CreateDynamicExpression(code)));
  237. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Refresh });
  238. }
  239. }
  240. private void btnRemoveWatch_Click(object sender, EventArgs e)
  241. {
  242. HashSet<string> itemsToRemove = new HashSet<string>(lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Text));
  243. int i = m_Watches.RemoveAll(w => itemsToRemove.Contains(w.ExpressionCode));
  244. if (i != 0)
  245. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Refresh });
  246. }
  247. private void stepInToolStripMenuItem_Click(object sender, EventArgs e)
  248. {
  249. StepIN();
  250. }
  251. private void btnOpenFile_Click(object sender, EventArgs e)
  252. {
  253. openToolStripMenuItem.PerformClick();
  254. }
  255. private void stepOverToolStripMenuItem_Click(object sender, EventArgs e)
  256. {
  257. StepOVER();
  258. }
  259. private void toolGO_Click(object sender, EventArgs e)
  260. {
  261. GO();
  262. }
  263. private void gOToolStripMenuItem_Click(object sender, EventArgs e)
  264. {
  265. GO();
  266. }
  267. private void toolStripButton1_Click(object sender, EventArgs e)
  268. {
  269. StepIN();
  270. }
  271. private void toolStepOver_Click(object sender, EventArgs e)
  272. {
  273. StepOVER();
  274. }
  275. private void btnViewVStk_Click(object sender, EventArgs e)
  276. {
  277. ValueBrowser.StartBrowse(lvVStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  278. }
  279. private void lvVStack_MouseDoubleClick(object sender, MouseEventArgs e)
  280. {
  281. ValueBrowser.StartBrowse(lvVStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  282. }
  283. private void btnViewWatch_Click(object sender, EventArgs e)
  284. {
  285. ValueBrowser.StartBrowse(lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  286. }
  287. private void lvWatches_MouseDoubleClick(object sender, MouseEventArgs e)
  288. {
  289. ValueBrowser.StartBrowse(lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  290. }
  291. private void toolGoToCodeVStack_Click(object sender, EventArgs e)
  292. {
  293. var v = lvVStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault();
  294. if (v != null && v.Type == DataType.Function)
  295. GotoBytecode(v.Function.EntryPointByteCodeLocation);
  296. }
  297. private void toolGoToCodeWatches_Click(object sender, EventArgs e)
  298. {
  299. var v = lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault();
  300. if (v != null && v.Type == DataType.Function)
  301. GotoBytecode(v.Function.EntryPointByteCodeLocation);
  302. }
  303. private void toolGoToCodeXStack_Click(object sender, EventArgs e)
  304. {
  305. var v = lvCallStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).OfType<int>().FirstOrDefault();
  306. if (v != 0)
  307. GotoBytecode(v);
  308. }
  309. private void GotoBytecode(int code)
  310. {
  311. codeView.CursorLine = code;
  312. }
  313. private void timerFollow_Tick(object sender, EventArgs e)
  314. {
  315. toolStepIN.PerformClick();
  316. }
  317. private void btnFollow_Click(object sender, EventArgs e)
  318. {
  319. timerFollow.Start();
  320. }
  321. private void btnFastHack_Click(object sender, EventArgs e)
  322. {
  323. DebugScript(@"C:\temp\test.lua");
  324. }
  325. void IDebugger.SetSourceCode(SourceCode sourceCode)
  326. {
  327. }
  328. bool IDebugger.IsPauseRequested()
  329. {
  330. return false;
  331. }
  332. public void SignalExecutionEnded()
  333. {
  334. }
  335. public void RefreshBreakpoints(IEnumerable<SourceRef> refs)
  336. {
  337. }
  338. }
  339. }