Cosmos/source2/Debug/Cosmos.Debug.GDB/FormMain.cs
Trivalik_cp 612ef94eb0 update gdb to 7.3
add break to Cosmos.Debug.GDB client and update it for current gdb version
2011-08-11 23:11:34 +00:00

417 lines
No EOL
14 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Cosmos.Debug.GDB {
public partial class FormMain : Form {
protected class AsmLine {
public readonly UInt32 mAddr;
public readonly string mLabel;
public readonly string mOp;
public readonly string mData = string.Empty;
public readonly bool mEIPHere;
public AsmLine(string aInput) {
//"0x0056d2b9 <_end_data+0>:\tmov DWORD PTR ds:0x550020,ebx\n"
var s = GDB.Unescape(aInput);
var xSplit1 = s.Split(Global.TabSeparator, StringSplitOptions.RemoveEmptyEntries);
var xSplit2 = xSplit1[0].Split(Global.SpaceSeparator, StringSplitOptions.RemoveEmptyEntries);
int xIndex = 0;
//newer gdb above 6.6 or higher versions
if (xSplit2[0] == "=>")
{
mEIPHere = true;
xIndex = 1;
}
mAddr = Global.FromHexWithLeadingZeroX(xSplit2[xIndex]);
string xLabel;
if (xSplit2.Length > xIndex + 1) {
xLabel = xSplit2[xIndex + 1];
}
xSplit2 = xSplit1[1].Split(Global.SpaceSeparator, StringSplitOptions.RemoveEmptyEntries);
mOp = xSplit2[0];
if (xSplit2.Length > 1) {
for (int j = 1; j < xSplit2.Length; j++) {
mData += xSplit2[j] + " ";
}
mData = mData.TrimEnd();
}
}
public override string ToString() {
// First char reserved for breakpoint (*)
return " " + mAddr.ToString("X8") + ": " + mOp + " " + mData.TrimEnd();
}
}
const int MAX_RETRY = 3;
protected string mFuncName;
protected bool mCreated;
protected int mConnectRetry;
protected void OnGDBResponse(GDB.Response aResponse) {
try {
Windows.mLogForm.Log(aResponse);
var xCmdLine = aResponse.Command.ToLower();
if (xCmdLine == "info registers") {
Windows.mRegistersForm.UpdateRegisters(aResponse);
Windows.UpdateAfterRegisterUpdate();
}else if(xCmdLine.Length == 0) {
if (aResponse.Text.Count == 2 && aResponse.Text[0] == "Breakpoint")
{
// program breaks on aResponse.Text[1]
}
else
{
// contains address where we are
}
} else {
var xCmdParts = xCmdLine.Split(Global.SpaceSeparator);
var xCmd = xCmdParts[0];
bool asyncCmd = false;
if (xCmd.EndsWith("&"))
{
asyncCmd = true;
xCmd = xCmd.Substring(0, xCmd.Length - 1);
}
if (xCmd == "disassemble") {
OnDisassemble(aResponse);
} else if (xCmd == "symbol-file") { // nothing
} else if (xCmd == "set") { // nothing
} else if (xCmd == "target") {
if (Global.GDB.Connected)
{
lablConnected.Visible = true;
lablRunning.Visible = true;
mitmConnect.Enabled = true;
butnConnect.Enabled = true;
mitmConnect.Text = "&Disconnect";
butnConnect.Text = "&Disconnect";
Settings.InitWindows();
}
else
{
if (mConnectRetry < MAX_RETRY + 1)
{
Connect();
}
else
{
mitmConnect.Enabled = true;
butnConnect.Enabled = true;
mitmConnect.Text = "&Connect";
butnConnect.Text = "&Connect";
}
}
} else if (xCmd == "detach") {
if (false == Global.GDB.Connected)
{
mitmConnect.Text = "&Connect";
butnConnect.Text = "&Connect";
mitmContinue.Enabled = false;
butnContinue.Enabled = false;
mitmStepInto.Enabled = false;
mitmStepOver.Enabled = false;
lboxDisassemble.Items.Clear();
lablConnected.Visible = false;
lablRunning.Visible = false;
textCurrentFunction.Visible = false;
}
} else if (xCmd == "delete") {
Windows.mBreakpointsForm.OnDelete(aResponse);
} else if ((xCmd == "stepi") || (xCmd == "nexti")) {
} else if (xCmd == "continue" || xCmd== "fg") {
lboxDisassemble.Items.Clear();
} else if (xCmd == "where") {
Windows.mCallStackForm.OnWhere(aResponse);
} else if (xCmd == "break") {
Windows.mBreakpointsForm.OnBreak(aResponse);
} else if (xCmd.StartsWith("x/")) {
Windows.mWatchesForm.OnWatchUpdate(aResponse);
} else {
throw new Exception("Unrecognized command response: " + aResponse.Command);
}
}
} catch (Exception e) {
MessageBox.Show("Exception: " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
}
public void Disassemble(string aLabel) {
textCurrentFunction.Text = string.Empty;
textCurrentFunction.Visible = true;
// force space free at end
var xDisAsmCmd = "disassemble";
var xLabelTrimed = aLabel.TrimEnd();
if (xLabelTrimed.Length > 0)
xDisAsmCmd += " " + xLabelTrimed;
Global.GDB.SendCmd(xDisAsmCmd);
}
protected void OnDisassemble(GDB.Response xResponse) {
var xResult = xResponse.Text;
lboxDisassemble.BeginUpdate();
try {
lboxDisassemble.Items.Clear();
// In some cases GDB might return no results. This is common when no symbols are loaded.
if (xResult.Count > 0) {
// Get function name
var xSplit = GDB.Unescape(xResult[0]).Split(Global.SpaceSeparator, StringSplitOptions.RemoveEmptyEntries);
mFuncName = xSplit[xSplit.Length - 1];
textCurrentFunction.Text = mFuncName;
// 1 and -2 to eliminate header and footer line
for (int i = 1; i <= xResult.Count - 2; i++) {
lboxDisassemble.Items.Add(new AsmLine(xResult[i]));
}
}
} finally {
lboxDisassemble.EndUpdate();
}
}
public void SetEIP(UInt32 aAddr) {
foreach (AsmLine x in lboxDisassemble.Items) {
if (x.mAddr == aAddr) {
lboxDisassemble.SelectedItem = x;
break;
}
}
}
public FormMain() {
InitializeComponent();
}
// TODO
// watches
// View stack
// If close without connect, it wipes out the settings file
private void mitmExit_Click(object sender, EventArgs e) {
Close();
}
private void mitmStepInto_Click(object sender, EventArgs e) {
Global.GDB.SendCmd("stepi");
}
private void mitmStepOver_Click(object sender, EventArgs e) {
Global.GDB.SendCmd("nexti");
}
protected void Connect() {
mitmConnect.Enabled = false;
butnConnect.Enabled = false;
mitmConnect.Text = "Try " + mConnectRetry;
butnConnect.Text = "Try " + mConnectRetry++;
if (false == mCreated)
{
Windows.CreateForms();
Global.AsmSource = new AsmFile(Path.Combine(Settings.OutputPath, Settings.AsmFile));
Global.GDB = new GDB(OnGDBResponse, OnRunStateChanged);
mCreated = true;
}
Global.GDB.Connect();
}
private void OnRunStateChanged(bool stopped)
{
if (InvokeRequired)
{
Invoke((MethodInvoker) delegate{OnRunStateChanged(stopped);});
return;
}
if (stopped)
{
lablRunning.Text = "Stopped";
mitmContinue.Enabled = true;
butnContinue.Enabled = true;
mitmBreak.Enabled = false;
butnBreak.Enabled = false;
mitmConnect.Enabled = true;
butnConnect.Enabled = true;
mitmStepInto.Enabled = true;
mitmStepOver.Enabled = true;
Windows.UpdateAllWindows();
}
else
{
lablRunning.Text = "Running";
mitmContinue.Enabled = false;
butnContinue.Enabled = false;
mitmBreak.Enabled = true;
butnBreak.Enabled = true;
mitmConnect.Enabled = false;
butnConnect.Enabled = false;
mitmStepInto.Enabled = false;
mitmStepOver.Enabled = false;
}
}
private void mitmConnect_Click(object sender, EventArgs e) {
if (!mitmConnect.Enabled)
return;
if (mCreated && Global.GDB.Connected)
{
Global.GDB.Disconnect();
}
else
{
mConnectRetry = 1;
Connect();
}
}
private void mitmRefresh_Click(object sender, EventArgs e) {
Windows.UpdateAllWindows();
}
private void mitmContinue_Click(object sender, EventArgs e) {
Global.GDB.SendCmd("continue&");
}
private void mitmMainViewCallStack_Click(object sender, EventArgs e) {
Windows.Show(Windows.mCallStackForm);
}
private void mitmMainViewWatches_Click(object sender, EventArgs e) {
Windows.Show(Windows.mWatchesForm);
}
protected FormWindowState mLastWindowState = FormWindowState.Normal;
private void FormMain_Resize(object sender, EventArgs e) {
if (WindowState == FormWindowState.Minimized) {
// Window is being minimized
Windows.Hide();
} else if ((mLastWindowState == FormWindowState.Minimized) && (WindowState != FormWindowState.Minimized)) {
// Window is being restored
Windows.Reshow();
}
mLastWindowState = WindowState;
}
private void mitmViewLog_Click(object sender, EventArgs e) {
Windows.Show(Windows.mLogForm);
}
private void FormMain_Load(object sender, EventArgs e) {
Windows.mMainForm = this;
}
private void mitmViewBreakpoints_Click(object sender, EventArgs e) {
Windows.Show(Windows.mBreakpointsForm);
}
private void mitmRegisters_Click(object sender, EventArgs e) {
Windows.Show(Windows.mRegistersForm);
}
private void FormMain_Shown(object sender, EventArgs e) {
mitmContinue.Enabled = false;
butnContinue.Enabled = false;
mitmBreak.Enabled = false;
butnBreak.Enabled = false;
mitmStepInto.Enabled = false;
mitmStepOver.Enabled = false;
// Dont put this in load. Load happens in main call from Main.cs and on exceptions just
// goes out, no message.
// Also we want to show other forms after main form, not before.
// We also only want to run this once, not on each possible show.
if (mitmConnect.Enabled) {
if (Settings.AutoConnect) {
mConnectRetry = 1;
Connect();
}
}
}
private void BringWindowsToTop() {
mIgnoreNextActivate = true;
foreach (var xWindow in Windows.mForms) {
if (xWindow == this) {
continue;
}
if (xWindow.Visible) {
xWindow.Activate();
}
}
this.Activate();
}
private void mitmWindowsToForeground_Click(object sender, EventArgs e) {
BringWindowsToTop();
}
private bool mIgnoreNextActivate = false;
private void FormMain_Activated(object sender, EventArgs e) {
// Necessary else we get looping becuase BringWindowsToTop reactivates this.
if (mIgnoreNextActivate) {
mIgnoreNextActivate = false;
} else {
BringWindowsToTop();
}
}
private void mitmSave_Click(object sender, EventArgs e) {
Windows.SavePositions();
Settings.Save();
}
private void mitemDisassemblyAddBreakpoint_Click(object sender, EventArgs e) {
var x = (AsmLine)lboxDisassemble.SelectedItem;
if (x != null) {
Windows.mBreakpointsForm.AddBreakpoint("*0x" + x.mAddr.ToString("X8"));
}
}
private void mitmCopyToClipboard_Click(object sender, EventArgs e) {
var x = (AsmLine)lboxDisassemble.SelectedItem;
Clipboard.SetText(x.ToString());
}
private void butnBreakpoints_Click(object sender, EventArgs e) {
mitmViewBreakpoints.PerformClick();
}
private void textCurrentFunction_TextChanged(object sender, EventArgs e) {
base.OnTextChanged(e);
using (Graphics g = textCurrentFunction.CreateGraphics()) {
SizeF size = g.MeasureString(textCurrentFunction.Text, textCurrentFunction.Font);
textCurrentFunction.Width = (int)size.Width + textCurrentFunction.Padding.Horizontal;
}
}
private void mitmBreak_Click(object sender, EventArgs e) {
Global.GDB.SendCmd("-exec-interrupt");
}
private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
{
if (mCreated && Global.GDB.Connected)
{
Global.GDB.Disconnect();
Global.GDB.SendCmd("quit");
}
}
}
}