PageRenderTime 54ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/source2/Debug/Cosmos.Debug.GDB/FormMain.cs

https://bitbucket.org/mvptracker/cosmos
C# | 473 lines | 389 code | 60 blank | 24 comment | 102 complexity | 558f35f1458b0ec9211134d3e0d94489 MD5 | raw file
Possible License(s): BSD-2-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Globalization;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Windows.Forms;
  11. using System.Runtime.InteropServices;
  12. namespace Cosmos.Debug.GDB {
  13. public partial class FormMain : Form {
  14. protected class GdbAsmLine {
  15. public readonly UInt32 mAddr;
  16. public readonly string mLabel;
  17. public readonly string mOp;
  18. public readonly string mData = string.Empty;
  19. public readonly bool mEIPHere;
  20. public GdbAsmLine(string aInput) {
  21. //"0x0056d2b9 <_end_data+0>:\tmov DWORD PTR ds:0x550020,ebx\n"
  22. var s = GDB.Unescape(aInput);
  23. var xSplit1 = s.Split(Global.TabSeparator, StringSplitOptions.RemoveEmptyEntries);
  24. var xSplit2 = xSplit1[0].Split(Global.SpaceSeparator, StringSplitOptions.RemoveEmptyEntries);
  25. int xIndex = 0;
  26. //newer gdb above 6.6 or higher versions
  27. if (xSplit2[0] == "=>")
  28. {
  29. mEIPHere = true;
  30. xIndex = 1;
  31. }
  32. mAddr = Global.FromHexWithLeadingZeroX(xSplit2[xIndex]);
  33. string xLabel;
  34. if (xSplit2.Length > xIndex + 1) {
  35. xLabel = xSplit2[xIndex + 1];
  36. }
  37. xSplit2 = xSplit1[1].Split(Global.SpaceSeparator, StringSplitOptions.RemoveEmptyEntries);
  38. mOp = xSplit2[0];
  39. if (xSplit2.Length > 1) {
  40. for (int j = 1; j < xSplit2.Length; j++) {
  41. mData += xSplit2[j] + " ";
  42. }
  43. mData = mData.TrimEnd();
  44. }
  45. }
  46. public override string ToString() {
  47. // First char reserved for breakpoint (*)
  48. return " " + mAddr.ToString("X8") + ": " + mOp + " " + mData.TrimEnd();
  49. }
  50. }
  51. const int MAX_RETRY = 3;
  52. protected string mFuncName;
  53. protected bool mCreated;
  54. protected int mConnectRetry;
  55. protected void OnGDBResponse(GDB.Response aResponse) {
  56. try {
  57. Windows.mLogForm.Log(aResponse);
  58. var xCmdLine = aResponse.Command.ToLower();
  59. if (xCmdLine == "info registers") {
  60. Windows.mRegistersForm.UpdateRegisters(aResponse);
  61. Windows.UpdateAfterRegisterUpdate();
  62. }else if(xCmdLine.Length == 0) {
  63. if (aResponse.Text.Count == 2 && aResponse.Text[0] == "Breakpoint")
  64. {
  65. // program breaks on aResponse.Text[1]
  66. }
  67. else
  68. {
  69. // contains address where we are
  70. }
  71. } else {
  72. var xCmdParts = xCmdLine.Split(Global.SpaceSeparator);
  73. var xCmd = xCmdParts[0];
  74. if (xCmd.EndsWith("&")) {
  75. xCmd = xCmd.Substring(0, xCmd.Length - 1);
  76. }
  77. if (xCmd == "disassemble") {
  78. OnDisassemble(aResponse);
  79. } else if (xCmd == "symbol-file") { // nothing
  80. } else if (xCmd == "set") { // nothing
  81. } else if (xCmd == "target") {
  82. if (Global.GDB.Connected)
  83. {
  84. mitmRefresh.Enabled = true;
  85. lablConnected.Visible = true;
  86. lablRunning.Visible = true;
  87. mitmConnect.Enabled = true;
  88. butnConnect.Enabled = true;
  89. mitmConnect.Text = "&Disconnect";
  90. butnConnect.Text = "&Disconnect";
  91. Settings.InitWindows();
  92. lboxDisassemble.SetItems(Global.AsmSource.Lines);
  93. }
  94. else
  95. {
  96. if (mConnectRetry < MAX_RETRY + 1)
  97. {
  98. Connect();
  99. }
  100. else
  101. {
  102. mitmConnect.Enabled = true;
  103. butnConnect.Enabled = true;
  104. mitmConnect.Text = "&Connect";
  105. butnConnect.Text = "&Connect";
  106. lboxDisassemble.Items.Clear();
  107. }
  108. }
  109. } else if (xCmd == "detach") {
  110. if (false == Global.GDB.Connected)
  111. {
  112. mitmConnect.Text = "&Connect";
  113. butnConnect.Text = "&Connect";
  114. mitmRefresh.Enabled = false;
  115. mitmContinue.Enabled = false;
  116. butnContinue.Enabled = false;
  117. mitmStepInto.Enabled = false;
  118. mitmStepOver.Enabled = false;
  119. lboxDisassemble.Items.Clear();
  120. lablConnected.Visible = false;
  121. lablRunning.Visible = false;
  122. textCurrentFunction.Visible = false;
  123. }
  124. } else if (xCmd == "delete") {
  125. Windows.mBreakpointsForm.OnDelete(aResponse);
  126. } else if ((xCmd == "stepi") || (xCmd == "nexti")) {
  127. } else if (xCmd == "continue" || xCmd== "fg") {
  128. //lboxDisassemble.Items.Clear();
  129. } else if (xCmd == "where") {
  130. Windows.mCallStackForm.OnWhere(aResponse);
  131. } else if (xCmd == "break") {
  132. Windows.mBreakpointsForm.OnBreak(aResponse);
  133. } else if (xCmd.StartsWith("x/")) {
  134. Windows.mWatchesForm.OnWatchUpdate(aResponse);
  135. } else {
  136. throw new Exception("Unrecognized command response: " + aResponse.Command);
  137. }
  138. }
  139. } catch (Exception e) {
  140. MessageBox.Show("Exception: " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
  141. }
  142. }
  143. public void Disassemble(string aLabel) {
  144. textCurrentFunction.Text = string.Empty;
  145. textCurrentFunction.Visible = true;
  146. // force space free at end
  147. var xDisAsmCmd = "disassemble";
  148. var xLabelTrimed = aLabel.TrimEnd();
  149. if (xLabelTrimed.Length > 0)
  150. xDisAsmCmd += " " + xLabelTrimed;
  151. Global.GDB.SendCmd(xDisAsmCmd);
  152. }
  153. protected void OnDisassemble(GDB.Response xResponse)
  154. {
  155. var xResult = xResponse.Text;
  156. // In some cases GDB might return no results. This is common when no symbols are loaded.
  157. if (xResult.Count == 0)
  158. return;
  159. // Get function name
  160. var xSplit = GDB.Unescape(xResult[0]).Split(Global.SpaceSeparator, StringSplitOptions.RemoveEmptyEntries);
  161. mFuncName = xSplit[xSplit.Length - 1];
  162. textCurrentFunction.Text = mFuncName;
  163. // remove ':'
  164. mFuncName = mFuncName.Substring(0, mFuncName.Length - 1);
  165. int labelLine = Global.AsmSource.GetLineOfLabel(mFuncName);
  166. labelLine++;
  167. // 1 and -2 to eliminate header and footer line
  168. for (int i = 1; i <= xResult.Count - 2; i++, labelLine++)
  169. {
  170. var asmLine = Global.AsmSource.Lines[labelLine];
  171. while (asmLine.IsLabel ||
  172. (asmLine.FirstToken != null && (asmLine.FirstToken == "global" || asmLine.FirstToken.StartsWith(";"))))
  173. {
  174. labelLine++;
  175. asmLine = Global.AsmSource.Lines[labelLine];
  176. }
  177. var gdbLine = new GdbAsmLine(xResult[i]);
  178. asmLine.Address = gdbLine.mAddr;
  179. // check if line different, if so, we set a line for tooltip
  180. string strGdbLine = gdbLine.ToString();
  181. string gdbLineWithoutAddress = strGdbLine.Substring(strGdbLine.IndexOf(":") + 3);
  182. string gdbLineWithoutAddressLower = gdbLineWithoutAddress.Replace(" ", string.Empty).ToLower().Replace("dwordptr",string.Empty);
  183. string asmlineFromFile = asmLine.OrignalLine.TrimStart('\t', ' ').ToLower().Replace("dword", string.Empty);
  184. string asmlineFromFileWithoutspace = asmlineFromFile.Replace(" ", string.Empty);
  185. if (gdbLineWithoutAddressLower != asmlineFromFileWithoutspace)
  186. {
  187. asmLine.GDBLine = gdbLineWithoutAddress;
  188. }
  189. }
  190. }
  191. public void SetEIP(UInt32 aAddr) {
  192. lboxDisassemble.SelectedAddress = aAddr;
  193. }
  194. public FormMain() {
  195. InitializeComponent();
  196. }
  197. // TODO
  198. // watches
  199. // View stack
  200. // If close without connect, it wipes out the settings file
  201. private void mitmExit_Click(object sender, EventArgs e) {
  202. Close();
  203. }
  204. private void mitmStepInto_Click(object sender, EventArgs e) {
  205. Global.GDB.SendCmd("stepi&");
  206. }
  207. private void mitmStepOver_Click(object sender, EventArgs e) {
  208. Global.GDB.SendCmd("nexti&");
  209. }
  210. protected void Connect() {
  211. if (Settings.OutputPath == null)
  212. {
  213. // path of asm, obj and cgdb
  214. using(var xDialog = new OpenFileDialog())
  215. {
  216. xDialog.Filter = "Symbols (*.asm;*.obj;*.mdf)|*.asm;*.obj;*.mdf";
  217. xDialog.ShowHelp = true;
  218. xDialog.HelpRequest += new EventHandler(xDialog_HelpRequest);
  219. if (xDialog.ShowDialog(this) != System.Windows.Forms.DialogResult.OK)
  220. return;
  221. if (false == Settings.LoadOnFly(xDialog.FileName))
  222. {
  223. MessageBox.Show("Error on loading selection!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
  224. return;
  225. }
  226. mitmSave.Enabled = true;
  227. }
  228. }
  229. mitmConnect.Enabled = false;
  230. butnConnect.Enabled = false;
  231. mitmConnect.Text = "Try " + mConnectRetry;
  232. butnConnect.Text = "Try " + mConnectRetry++;
  233. if (false == mCreated)
  234. {
  235. Windows.CreateForms();
  236. Global.AsmSource = new AsmFile(Path.Combine(Settings.OutputPath, Settings.AsmFile));
  237. Global.GDB = new GDB(OnGDBResponse, OnRunStateChanged);
  238. mCreated = true;
  239. }
  240. Global.GDB.Connect();
  241. }
  242. void xDialog_HelpRequest(object sender, EventArgs e)
  243. {
  244. MessageBox.Show("Select a folder which contain files of type asm, obj and mdf with same name.", "Help", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
  245. }
  246. private void OnRunStateChanged(bool stopped)
  247. {
  248. if (InvokeRequired)
  249. {
  250. Invoke((MethodInvoker) delegate{OnRunStateChanged(stopped);});
  251. return;
  252. }
  253. if (stopped)
  254. {
  255. lablRunning.Text = "Stopped";
  256. mitmContinue.Enabled = true;
  257. butnContinue.Enabled = true;
  258. mitmBreak.Enabled = false;
  259. butnBreak.Enabled = false;
  260. mitmConnect.Enabled = true;
  261. butnConnect.Enabled = true;
  262. mitmStepInto.Enabled = true;
  263. mitmStepOver.Enabled = true;
  264. Windows.UpdateAllWindows();
  265. }
  266. else
  267. {
  268. lablRunning.Text = "Running";
  269. mitmContinue.Enabled = false;
  270. butnContinue.Enabled = false;
  271. mitmBreak.Enabled = true;
  272. butnBreak.Enabled = true;
  273. mitmConnect.Enabled = false;
  274. butnConnect.Enabled = false;
  275. mitmStepInto.Enabled = false;
  276. mitmStepOver.Enabled = false;
  277. }
  278. }
  279. private void mitmConnect_Click(object sender, EventArgs e) {
  280. if (!mitmConnect.Enabled)
  281. return;
  282. if (mCreated && Global.GDB.Connected)
  283. {
  284. Global.GDB.Disconnect();
  285. }
  286. else
  287. {
  288. mConnectRetry = 1;
  289. Connect();
  290. }
  291. }
  292. private void mitmRefresh_Click(object sender, EventArgs e) {
  293. Windows.UpdateAllWindows();
  294. }
  295. private void mitmContinue_Click(object sender, EventArgs e) {
  296. Global.GDB.SendCmd("continue&");
  297. }
  298. private void mitmMainViewCallStack_Click(object sender, EventArgs e) {
  299. Windows.Show(Windows.mCallStackForm);
  300. }
  301. private void mitmMainViewWatches_Click(object sender, EventArgs e) {
  302. Windows.Show(Windows.mWatchesForm);
  303. }
  304. protected FormWindowState mLastWindowState = FormWindowState.Normal;
  305. private void FormMain_Resize(object sender, EventArgs e) {
  306. if (WindowState == FormWindowState.Minimized) {
  307. // Window is being minimized
  308. Windows.Hide();
  309. } else if ((mLastWindowState == FormWindowState.Minimized) && (WindowState != FormWindowState.Minimized)) {
  310. // Window is being restored
  311. Windows.Reshow();
  312. }
  313. mLastWindowState = WindowState;
  314. }
  315. private void mitmViewLog_Click(object sender, EventArgs e) {
  316. Windows.Show(Windows.mLogForm);
  317. }
  318. private void FormMain_Load(object sender, EventArgs e) {
  319. Windows.mMainForm = this;
  320. }
  321. private void mitmViewBreakpoints_Click(object sender, EventArgs e) {
  322. Windows.Show(Windows.mBreakpointsForm);
  323. }
  324. private void mitmRegisters_Click(object sender, EventArgs e) {
  325. Windows.Show(Windows.mRegistersForm);
  326. }
  327. private void FormMain_Shown(object sender, EventArgs e) {
  328. mitmContinue.Enabled = false;
  329. butnContinue.Enabled = false;
  330. mitmBreak.Enabled = false;
  331. butnBreak.Enabled = false;
  332. mitmStepInto.Enabled = false;
  333. mitmStepOver.Enabled = false;
  334. mitmRefresh.Enabled = false;
  335. if (Settings.OutputPath == null)
  336. {
  337. mitmSave.Enabled = false;
  338. }
  339. // Dont put this in load. Load happens in main call from Main.cs and on exceptions just
  340. // goes out, no message.
  341. // Also we want to show other forms after main form, not before.
  342. // We also only want to run this once, not on each possible show.
  343. if (mitmConnect.Enabled) {
  344. if (Settings.AutoConnect) {
  345. mConnectRetry = 1;
  346. Connect();
  347. }
  348. }
  349. }
  350. private void BringWindowsToTop() {
  351. mIgnoreNextActivate = true;
  352. foreach (var xWindow in Windows.mForms) {
  353. if (xWindow == this) {
  354. continue;
  355. }
  356. if (xWindow.Visible) {
  357. xWindow.Activate();
  358. }
  359. }
  360. this.Activate();
  361. }
  362. private void mitmWindowsToForeground_Click(object sender, EventArgs e) {
  363. BringWindowsToTop();
  364. }
  365. private bool mIgnoreNextActivate = false;
  366. private void FormMain_Activated(object sender, EventArgs e) {
  367. // Necessary else we get looping becuase BringWindowsToTop reactivates this.
  368. if (mIgnoreNextActivate) {
  369. mIgnoreNextActivate = false;
  370. } else {
  371. BringWindowsToTop();
  372. }
  373. }
  374. private void mitmSave_Click(object sender, EventArgs e) {
  375. Settings.Save();
  376. }
  377. private void mitemDisassemblyAddBreakpoint_Click(object sender, EventArgs e) {
  378. if (lboxDisassemble.SelectedIndices.Count == 0)
  379. return;
  380. var x = Global.AsmSource.Lines[lboxDisassemble.SelectedIndices[0]];
  381. if (x.Address != 0) {
  382. Windows.mBreakpointsForm.AddBreakpoint("*0x" + x.Address.ToString("X8"));
  383. }
  384. }
  385. private void mitmCopyToClipboard_Click(object sender, EventArgs e) {
  386. if (lboxDisassemble.SelectedIndices.Count == 0)
  387. return;
  388. var x = Global.AsmSource.Lines[lboxDisassemble.SelectedIndices[0]];
  389. Clipboard.SetText(x.ToString());
  390. }
  391. private void butnBreakpoints_Click(object sender, EventArgs e) {
  392. mitmViewBreakpoints.PerformClick();
  393. }
  394. private void textCurrentFunction_TextChanged(object sender, EventArgs e) {
  395. base.OnTextChanged(e);
  396. using (Graphics g = textCurrentFunction.CreateGraphics()) {
  397. SizeF size = g.MeasureString(textCurrentFunction.Text, textCurrentFunction.Font);
  398. textCurrentFunction.Width = (int)size.Width + textCurrentFunction.Padding.Horizontal;
  399. }
  400. }
  401. private void mitmBreak_Click(object sender, EventArgs e) {
  402. Global.GDB.SendCmd("-exec-interrupt");
  403. }
  404. private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
  405. {
  406. if (mCreated && Global.GDB.Connected)
  407. {
  408. Global.GDB.Disconnect();
  409. Global.GDB.SendCmd("quit");
  410. }
  411. }
  412. }
  413. }