From 4777358437c1a47ea4c1a23e76dfaeac7018cc00 Mon Sep 17 00:00:00 2001 From: Sour Date: Sun, 19 May 2019 14:58:26 -0400 Subject: [PATCH] Debugger: Added right-click actions to disassembly view (add to watch, edit label, edit in hex edtior, go to location) --- UI/Debugger/Breakpoints/BreakpointManager.cs | 4 +- UI/Debugger/Code/CpuDisassemblyManager.cs | 191 +++++++------- UI/Debugger/Code/IDisassemblyManager.cs | 16 +- UI/Debugger/Code/SpcDisassemblyManager.cs | 1 + .../Controls/ctrlDisassemblyView.Designer.cs | 36 +-- UI/Debugger/Controls/ctrlDisassemblyView.cs | 238 +++++++++++++++++- UI/Debugger/frmDebugger.cs | 8 +- 7 files changed, 376 insertions(+), 118 deletions(-) diff --git a/UI/Debugger/Breakpoints/BreakpointManager.cs b/UI/Debugger/Breakpoints/BreakpointManager.cs index 6b63267..7004146 100644 --- a/UI/Debugger/Breakpoints/BreakpointManager.cs +++ b/UI/Debugger/Breakpoints/BreakpointManager.cs @@ -81,12 +81,14 @@ namespace Mesen.GUI.Debugger ).FirstOrDefault(); } - public static void EnableDisableBreakpoint(AddressInfo info) + public static bool EnableDisableBreakpoint(AddressInfo info) { Breakpoint breakpoint = BreakpointManager.GetMatchingBreakpoint(info); if(breakpoint != null) { breakpoint.SetEnabled(!breakpoint.Enabled); + return true; } + return false; } public static void ToggleBreakpoint(AddressInfo info) diff --git a/UI/Debugger/Code/CpuDisassemblyManager.cs b/UI/Debugger/Code/CpuDisassemblyManager.cs index ed69ca0..f398419 100644 --- a/UI/Debugger/Code/CpuDisassemblyManager.cs +++ b/UI/Debugger/Code/CpuDisassemblyManager.cs @@ -17,6 +17,7 @@ namespace Mesen.GUI.Debugger.Code public ICodeDataProvider Provider { get { return this._provider; } } + public virtual CpuType CpuType { get { return CpuType.Cpu; } } public virtual SnesMemoryType RelativeMemoryType { get { return SnesMemoryType.CpuMemory; } } public virtual int AddressSize { get { return 6; } } public virtual int ByteCodeSize { get { return 4; } } @@ -32,43 +33,15 @@ namespace Mesen.GUI.Debugger.Code } } - public void ToggleBreakpoint(int lineIndex) + public LocationInfo GetLocationInfo(string word, int lineIndex) { - int address = this._provider.GetLineAddress(lineIndex); - if(address >= 0) { - AddressInfo relAddress = new AddressInfo() { - Address = address, - Type = RelativeMemoryType - }; + LocationInfo location = new LocationInfo(); - AddressInfo absAddress = DebugApi.GetAbsoluteAddress(relAddress); - if(absAddress.Address < 0) { - BreakpointManager.ToggleBreakpoint(relAddress); - } else { - BreakpointManager.ToggleBreakpoint(absAddress); - } - } - } - - public void EnableDisableBreakpoint(int lineIndex) - { - int address = this._provider.GetLineAddress(lineIndex); - if(address >= 0) { - BreakpointManager.EnableDisableBreakpoint(new AddressInfo() { - Address = address, - Type = RelativeMemoryType - }); - } - } - - public Dictionary GetTooltipData(string word, int lineIndex) - { - int? arrayIndex = null; int arraySeparatorIndex = word.IndexOf("+"); if(arraySeparatorIndex >= 0) { int index; if(int.TryParse(word.Substring(arraySeparatorIndex + 1), out index)) { - arrayIndex = index; + location.ArrayIndex = index; } word = word.Substring(0, arraySeparatorIndex); } @@ -76,77 +49,127 @@ namespace Mesen.GUI.Debugger.Code if(_provider is DbgCodeDataProvider && _symbolProvider != null) { int rangeStart, rangeEnd; GetSymbolByteRange(lineIndex, out rangeStart, out rangeEnd); - SymbolInfo symbol = _symbolProvider.GetSymbol(word, rangeStart, rangeEnd); - if(symbol != null) { - AddressInfo? symbolAddress = _symbolProvider.GetSymbolAddressInfo(symbol); + location.Symbol = _symbolProvider.GetSymbol(word, rangeStart, rangeEnd); + } - if(symbolAddress != null && symbolAddress.Value.Address >= 0) { - int relativeAddress = DebugApi.GetRelativeAddress(symbolAddress.Value).Address; - byte byteValue = relativeAddress >= 0 ? DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress) : (byte)0; - UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0; + location.Label = LabelManager.GetLabel(word); - var values = new Dictionary() { - { "Symbol", symbol.Name + (arrayIndex != null ? $"+{arrayIndex.Value}" : "") } - }; - - if(relativeAddress >= 0) { - values["CPU Address"] = "$" + relativeAddress.ToString("X4"); - } else { - values["CPU Address"] = ""; + int address; + if(location.Label != null) { + address = location.Label.GetRelativeAddress().Address; + if(address >= 0) { + location.Address = location.Label.GetRelativeAddress().Address + (location.ArrayIndex ?? 0); + } else { + location.Address = -1; + } + } else if(word.StartsWith("$")) { + word = word.Replace("$", ""); + if(Int32.TryParse(word, System.Globalization.NumberStyles.HexNumber, null, out address)) { + location.Address = address; + if(word.Length <= 4) { + CpuState state = DebugApi.GetState().Cpu; + if(word.Length == 4) { + //Append current DB register to 2-byte addresses + location.Address = (state.DBR << 16) | address; + } else if(word.Length == 2) { + //Add direct register to 1-byte addresses + location.Address = (state.D + address); } - - if(symbolAddress.Value.Type == SnesMemoryType.PrgRom) { - values["PRG Offset"] = "$" + (symbolAddress.Value.Address + (arrayIndex ?? 0)).ToString("X4"); - } - - values["Value"] = (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a"); - return values; - } else { - return new Dictionary() { - { "Symbol", symbol.Name }, - { "Constant", symbol.Address.HasValue ? ("$" + symbol.Address.Value.ToString("X2")) : "" } - }; } } + } else if(Int32.TryParse(word, out address)) { + location.Address = (int)address; } else { - CodeLabel label = LabelManager.GetLabel(word); - if(label != null) { - AddressInfo absAddress = label.GetAbsoluteAddress(); - int relativeAddress; - if(absAddress.Type == SnesMemoryType.Register) { - relativeAddress = absAddress.Address; - } else { - relativeAddress = label.GetRelativeAddress().Address; - } + location.Address = -1; + } + if(location.Label == null && location.Address >= 0) { + AddressInfo relAddress = new AddressInfo() { Address = location.Address, Type = RelativeMemoryType }; + CodeLabel label = LabelManager.GetLabel(relAddress); + if(label != null && !string.IsNullOrWhiteSpace(label.Label)) { + //ignore comment-only labels + location.Label = label; + } + } + + if(location.Label != null && location.Address >= 0) { + AddressInfo absAddress = location.Label.GetAbsoluteAddress(); + AddressInfo absIndexedAddress = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = location.Address, Type = RelativeMemoryType }); + if(absIndexedAddress.Address > absAddress.Address) { + location.ArrayIndex = absIndexedAddress.Address - absAddress.Address; + } + } + + return location; + } + + public Dictionary GetTooltipData(string word, int lineIndex) + { + LocationInfo location = GetLocationInfo(word, lineIndex); + + if(location.Symbol != null) { + AddressInfo? symbolAddress = _symbolProvider.GetSymbolAddressInfo(location.Symbol); + + if(symbolAddress != null && symbolAddress.Value.Address >= 0) { + int relativeAddress = DebugApi.GetRelativeAddress(symbolAddress.Value).Address; byte byteValue = relativeAddress >= 0 ? DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress) : (byte)0; UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0; var values = new Dictionary() { - { "Label", label.Label + (arrayIndex != null ? $"+{arrayIndex.Value}" : "") }, - { "Address", (relativeAddress >= 0 ? "$" + relativeAddress.ToString("X4") : "n/a") }, - { "Value", (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a") }, + { "Symbol", location.Symbol.Name + (location.ArrayIndex != null ? $"+{location.ArrayIndex.Value}" : "") } }; - if(!string.IsNullOrWhiteSpace(label.Comment)) { - values["Comment"] = label.Comment; + if(relativeAddress >= 0) { + values["CPU Address"] = "$" + relativeAddress.ToString("X4"); + } else { + values["CPU Address"] = ""; } + + if(symbolAddress.Value.Type == SnesMemoryType.PrgRom) { + values["PRG Offset"] = "$" + (symbolAddress.Value.Address + (location.ArrayIndex ?? 0)).ToString("X4"); + } + + values["Value"] = (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a"); return values; - } - } + } else { + return new Dictionary() { + { "Symbol", location.Symbol.Name }, + { "Constant", location.Symbol.Address.HasValue ? ("$" + location.Symbol.Address.Value.ToString("X2")) : "" } + }; + } + } else if(location.Label != null) { + AddressInfo absAddress = location.Label.GetAbsoluteAddress(); + int relativeAddress; + if(location.Address >= 0) { + relativeAddress = location.Address; + AddressInfo absIndexedAddress = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = location.Address, Type = RelativeMemoryType }); + if(absIndexedAddress.Address > absAddress.Address) { + location.ArrayIndex = absIndexedAddress.Address - absAddress.Address; + } + } else if(absAddress.Type == SnesMemoryType.Register) { + relativeAddress = absAddress.Address; + } else { + relativeAddress = location.Label.GetRelativeAddress().Address + (location.ArrayIndex ?? 0); + } - System.Globalization.NumberStyles style = System.Globalization.NumberStyles.None; - if(word.StartsWith("$")) { - style = System.Globalization.NumberStyles.HexNumber; - word = word.Replace("$", ""); - } + byte byteValue = relativeAddress >= 0 ? DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress) : (byte)0; + UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0; - uint address; - if(UInt32.TryParse(word, style, null, out address)) { - byte byteValue = DebugApi.GetMemoryValue(this.RelativeMemoryType, address); - UInt16 wordValue = (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, address + 1) << 8)); + var values = new Dictionary() { + { "Label", location.Label.Label + (location.ArrayIndex != null ? $"+{location.ArrayIndex.Value}" : "") }, + { "Address", (relativeAddress >= 0 ? "$" + relativeAddress.ToString("X4") : "n/a") }, + { "Value", (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a") }, + }; + + if(!string.IsNullOrWhiteSpace(location.Label.Comment)) { + values["Comment"] = location.Label.Comment; + } + return values; + } else if(location.Address >= 0) { + byte byteValue = DebugApi.GetMemoryValue(this.RelativeMemoryType, (uint)location.Address); + UInt16 wordValue = (UInt16)(byteValue | (DebugApi.GetMemoryValue(this.RelativeMemoryType, (uint)location.Address + 1) << 8)); return new Dictionary() { - { "Address", "$" + address.ToString("X4") }, + { "Address", "$" + location.Address.ToString("X4") }, { "Value", $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" } }; } diff --git a/UI/Debugger/Code/IDisassemblyManager.cs b/UI/Debugger/Code/IDisassemblyManager.cs index 30ecc41..54df791 100644 --- a/UI/Debugger/Code/IDisassemblyManager.cs +++ b/UI/Debugger/Code/IDisassemblyManager.cs @@ -1,10 +1,12 @@ using Mesen.GUI.Debugger.Controls; using Mesen.GUI.Debugger.Integration; +using Mesen.GUI.Debugger.Labels; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using static Mesen.GUI.Debugger.Integration.DbgImporter; namespace Mesen.GUI.Debugger.Code { @@ -12,14 +14,24 @@ namespace Mesen.GUI.Debugger.Code { ICodeDataProvider Provider { get; } + CpuType CpuType { get; } + SnesMemoryType RelativeMemoryType { get; } int AddressSize { get; } int ByteCodeSize { get; } bool AllowSourceView { get; } void RefreshCode(DbgImporter symbolProvider, DbgImporter.FileInfo file); - void ToggleBreakpoint(int lineIndex); - void EnableDisableBreakpoint(int lineIndex); Dictionary GetTooltipData(string word, int lineIndex); + LocationInfo GetLocationInfo(string lastWord, int lineIndex); + } + + public class LocationInfo + { + public int Address; + public CodeLabel Label; + public SymbolInfo Symbol; + + public int? ArrayIndex = null; } } diff --git a/UI/Debugger/Code/SpcDisassemblyManager.cs b/UI/Debugger/Code/SpcDisassemblyManager.cs index 027ab69..d7a631e 100644 --- a/UI/Debugger/Code/SpcDisassemblyManager.cs +++ b/UI/Debugger/Code/SpcDisassemblyManager.cs @@ -10,6 +10,7 @@ namespace Mesen.GUI.Debugger.Code { public class SpcDisassemblyManager : CpuDisassemblyManager { + public override CpuType CpuType { get { return CpuType.Spc; } } public override SnesMemoryType RelativeMemoryType { get { return SnesMemoryType.SpcMemory; } } public override int AddressSize { get { return 4; } } public override int ByteCodeSize { get { return 3; } } diff --git a/UI/Debugger/Controls/ctrlDisassemblyView.Designer.cs b/UI/Debugger/Controls/ctrlDisassemblyView.Designer.cs index 6cd015a..3b2ae3a 100644 --- a/UI/Debugger/Controls/ctrlDisassemblyView.Designer.cs +++ b/UI/Debugger/Controls/ctrlDisassemblyView.Designer.cs @@ -69,6 +69,7 @@ this.ctrlCode.TabIndex = 0; this.ctrlCode.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlCode_MouseMove); this.ctrlCode.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ctrlCode_MouseDown); + this.ctrlCode.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ctrlCode_MouseDoubleClick); this.ctrlCode.MouseLeave += new System.EventHandler(this.ctrlCode_MouseLeave); this.ctrlCode.TextZoomChanged += new System.EventHandler(this.ctrlCode_TextZoomChanged); // @@ -86,74 +87,79 @@ this.sepSwitchView, this.mnuSwitchView}); this.ctxMenu.Name = "ctxMenu"; - this.ctxMenu.Size = new System.Drawing.Size(191, 176); + this.ctxMenu.Size = new System.Drawing.Size(227, 198); + this.ctxMenu.Closing += new System.Windows.Forms.ToolStripDropDownClosingEventHandler(this.ctxMenu_Closing); + this.ctxMenu.Opening += new System.ComponentModel.CancelEventHandler(this.ctxMenu_Opening); // // mnuToggleBreakpoint // this.mnuToggleBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Breakpoint; this.mnuToggleBreakpoint.Name = "mnuToggleBreakpoint"; - this.mnuToggleBreakpoint.Size = new System.Drawing.Size(190, 22); + this.mnuToggleBreakpoint.Size = new System.Drawing.Size(206, 22); this.mnuToggleBreakpoint.Text = "Toggle Breakpoint"; this.mnuToggleBreakpoint.Click += new System.EventHandler(this.mnuToggleBreakpoint_Click); // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(187, 6); + this.toolStripMenuItem1.Size = new System.Drawing.Size(203, 6); // // mnuAddToWatch // - this.mnuAddToWatch.Enabled = false; + this.mnuAddToWatch.Image = global::Mesen.GUI.Properties.Resources.Add; this.mnuAddToWatch.Name = "mnuAddToWatch"; - this.mnuAddToWatch.Size = new System.Drawing.Size(190, 22); + this.mnuAddToWatch.Size = new System.Drawing.Size(206, 22); this.mnuAddToWatch.Text = "Add to Watch"; + this.mnuAddToWatch.Click += new System.EventHandler(this.mnuAddToWatch_Click); // // mnuEditLabel // - this.mnuEditLabel.Enabled = false; this.mnuEditLabel.Image = global::Mesen.GUI.Properties.Resources.EditLabel; this.mnuEditLabel.Name = "mnuEditLabel"; - this.mnuEditLabel.Size = new System.Drawing.Size(190, 22); + this.mnuEditLabel.Size = new System.Drawing.Size(206, 22); this.mnuEditLabel.Text = "Edit Label"; + this.mnuEditLabel.Click += new System.EventHandler(this.mnuEditLabel_Click); // // mnuEditInMemoryTools // - this.mnuEditInMemoryTools.Enabled = false; this.mnuEditInMemoryTools.Image = global::Mesen.GUI.Properties.Resources.CheatCode; this.mnuEditInMemoryTools.Name = "mnuEditInMemoryTools"; - this.mnuEditInMemoryTools.Size = new System.Drawing.Size(190, 22); + this.mnuEditInMemoryTools.Size = new System.Drawing.Size(206, 22); this.mnuEditInMemoryTools.Text = "Edit in Memory Tools"; + this.mnuEditInMemoryTools.Click += new System.EventHandler(this.mnuEditInMemoryTools_Click); // // toolStripMenuItem2 // this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - this.toolStripMenuItem2.Size = new System.Drawing.Size(187, 6); + this.toolStripMenuItem2.Size = new System.Drawing.Size(203, 6); // // mnuGoToLocation // - this.mnuGoToLocation.Enabled = false; this.mnuGoToLocation.Name = "mnuGoToLocation"; - this.mnuGoToLocation.Size = new System.Drawing.Size(190, 22); + this.mnuGoToLocation.ShortcutKeyDisplayString = "Double Click"; + this.mnuGoToLocation.Size = new System.Drawing.Size(226, 22); this.mnuGoToLocation.Text = "Go to Location"; + this.mnuGoToLocation.Click += new System.EventHandler(this.mnuGoToLocation_Click); // // mnuFindOccurrences // this.mnuFindOccurrences.Enabled = false; this.mnuFindOccurrences.Image = global::Mesen.GUI.Properties.Resources.Find; this.mnuFindOccurrences.Name = "mnuFindOccurrences"; - this.mnuFindOccurrences.Size = new System.Drawing.Size(190, 22); + this.mnuFindOccurrences.Size = new System.Drawing.Size(206, 22); this.mnuFindOccurrences.Text = "Find Occurrences"; + this.mnuFindOccurrences.Visible = false; // // sepSwitchView // this.sepSwitchView.Name = "sepSwitchView"; - this.sepSwitchView.Size = new System.Drawing.Size(187, 6); + this.sepSwitchView.Size = new System.Drawing.Size(203, 6); // // mnuSwitchView // this.mnuSwitchView.Image = global::Mesen.GUI.Properties.Resources.SwitchView; this.mnuSwitchView.Name = "mnuSwitchView"; - this.mnuSwitchView.Size = new System.Drawing.Size(190, 22); + this.mnuSwitchView.Size = new System.Drawing.Size(206, 22); this.mnuSwitchView.Text = "Switch to Source View"; // // cboSourceFile diff --git a/UI/Debugger/Controls/ctrlDisassemblyView.cs b/UI/Debugger/Controls/ctrlDisassemblyView.cs index 068a9bb..d757aeb 100644 --- a/UI/Debugger/Controls/ctrlDisassemblyView.cs +++ b/UI/Debugger/Controls/ctrlDisassemblyView.cs @@ -127,6 +127,11 @@ namespace Mesen.GUI.Debugger.Controls private void InitShortcuts() { mnuToggleBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint)); + + mnuEditLabel.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditLabel)); + mnuEditInMemoryTools.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditInMemoryViewer)); + mnuAddToWatch.InitShortcut(this, nameof(DebuggerShortcutsConfig.LabelList_AddToWatch)); + mnuSwitchView.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_SwitchView)); mnuSwitchView.Click += (s, e) => { ToggleView(); }; @@ -153,6 +158,24 @@ namespace Mesen.GUI.Debugger.Controls ctrlCode.Invalidate(); } + public void ScrollToSymbol(SymbolInfo symbol) + { + if(!_inSourceView) { + ToggleView(); + } + + ReferenceInfo definition = _symbolProvider?.GetSymbolDefinition(symbol); + if(definition != null) { + foreach(DbgImporter.FileInfo fileInfo in cboSourceFile.Items) { + if(fileInfo.Name == definition.FileName) { + cboSourceFile.SelectedItem = fileInfo; + ctrlCode.ScrollToLineIndex(definition.LineNumber); + return; + } + } + } + } + public void ScrollToAddress(uint address) { if(_inSourceView) { @@ -198,11 +221,6 @@ namespace Mesen.GUI.Debugger.Controls public ctrlScrollableTextbox CodeViewer { get { return ctrlCode; } } - public void GoToAddress(int address) - { - ScrollToAddress((uint)address); - } - public void GoToActiveAddress() { if(_styleProvider.ActiveAddress.HasValue) { @@ -212,47 +230,195 @@ namespace Mesen.GUI.Debugger.Controls public void ToggleBreakpoint() { - _manager.ToggleBreakpoint(ctrlCode.SelectedLine); + ToggleBreakpoint(_manager.Provider.GetLineAddress(ctrlCode.SelectedLine)); } public void EnableDisableBreakpoint() { - _manager.EnableDisableBreakpoint(ctrlCode.SelectedLine); + EnableDisableBreakpoint(_manager.Provider.GetLineAddress(ctrlCode.SelectedLine)); + } + + private void ToggleBreakpoint(int address) + { + if(address >= 0) { + AddressInfo relAddress = new AddressInfo() { + Address = address, + Type = _manager.RelativeMemoryType + }; + + AddressInfo absAddress = DebugApi.GetAbsoluteAddress(relAddress); + if(absAddress.Address < 0) { + BreakpointManager.ToggleBreakpoint(relAddress); + } else { + BreakpointManager.ToggleBreakpoint(absAddress); + } + } + } + + private void EnableDisableBreakpoint(int address) + { + if(address >= 0) { + AddressInfo relAddress = new AddressInfo() { + Address = address, + Type = _manager.RelativeMemoryType + }; + + if(!BreakpointManager.EnableDisableBreakpoint(relAddress)) { + AddressInfo absAddress = DebugApi.GetAbsoluteAddress(relAddress); + BreakpointManager.EnableDisableBreakpoint(absAddress); + } + } + } + + private void EditLabel(LocationInfo location) + { + if(location.Symbol != null) { + //Don't allow edit label on symbols + return; + } + + if(location.Label != null) { + using(frmEditLabel frm = new frmEditLabel(location.Label)) { + frm.ShowDialog(); + } + } else if(location.Address >= 0) { + AddressInfo relAddress = new AddressInfo() { + Address = location.Address, + Type = _manager.RelativeMemoryType + }; + + AddressInfo absAddress = DebugApi.GetAbsoluteAddress(relAddress); + if(absAddress.Address >= 0) { + CodeLabel label = LabelManager.GetLabel((uint)absAddress.Address, absAddress.Type); + if(label == null) { + label = new CodeLabel() { + Address = (uint)absAddress.Address, + MemoryType = absAddress.Type + }; + } + + using(frmEditLabel frm = new frmEditLabel(label)) { + frm.ShowDialog(); + } + } + } + } + + private void EditInMemoryTools(LocationInfo location) + { + if(location.Symbol != null) { + AddressInfo? address = _symbolProvider.GetSymbolAddressInfo(location.Symbol); + if(address.HasValue) { + DebugWindowManager.OpenMemoryViewer(address.Value); + } + } else if(location.Address >= 0) { + AddressInfo relAddress = new AddressInfo() { + Address = location.Address, + Type = _manager.RelativeMemoryType + }; + + AddressInfo absAddress = DebugApi.GetAbsoluteAddress(relAddress); + if(absAddress.Address >= 0) { + DebugWindowManager.OpenMemoryViewer(absAddress); + } else { + DebugWindowManager.OpenMemoryViewer(relAddress); + } + } else if(location.Label != null) { + DebugWindowManager.OpenMemoryViewer(location.Label.GetAbsoluteAddress()); + } + } + + private void GoToLocation(LocationInfo location) + { + if(location.Symbol != null) { + ScrollToSymbol(location.Symbol); + } else if(location.Address >= 0) { + ScrollToAddress((uint)location.Address); + } + } + + private LocationInfo GetActionTarget() + { + string word = _lastWord; + int lineIndex; + if(string.IsNullOrWhiteSpace(word)) { + word = "$" + _manager.Provider.GetLineAddress(ctrlCode.SelectedLine).ToString("X6"); + lineIndex = ctrlCode.SelectedLine; + } else { + lineIndex = ctrlCode.GetLineIndexAtPosition(_lastLocation.Y); + } + + return _manager.GetLocationInfo(word, lineIndex); } private void mnuToggleBreakpoint_Click(object sender, EventArgs e) { ToggleBreakpoint(); } + + private void mnuEditLabel_Click(object sender, EventArgs e) + { + EditLabel(GetActionTarget()); + } + + private void mnuEditInMemoryTools_Click(object sender, EventArgs e) + { + EditInMemoryTools(GetActionTarget()); + } + + private void mnuGoToLocation_Click(object sender, EventArgs e) + { + GoToLocation(GetActionTarget()); + } + + private void mnuAddToWatch_Click(object sender, EventArgs e) + { + LocationInfo location = GetActionTarget(); + + if(location.Symbol != null) { + WatchManager.GetWatchManager(_manager.CpuType).AddWatch("[" + location.Symbol.Name + "]"); + } else if(location.Label != null) { + string label = location.Label.Label; + if(location.ArrayIndex.HasValue) { + label += "+" + location.ArrayIndex.Value.ToString(); + } + WatchManager.GetWatchManager(_manager.CpuType).AddWatch("[" + label + "]"); + } else if(location.Address >= 0) { + WatchManager.GetWatchManager(_manager.CpuType).AddWatch("[$" + location.Address.ToString("X" + _manager.AddressSize.ToString()) + "]"); + } + } private void ctrlCode_MouseDown(object sender, MouseEventArgs e) { - if(e.X < 20) { + if(e.X < 20 && e.Button == MouseButtons.Left) { int lineIndex = ctrlCode.GetLineIndexAtPosition(e.Y); - _manager.ToggleBreakpoint(lineIndex); + ToggleBreakpoint(_manager.Provider.GetLineAddress(lineIndex)); } BaseForm.GetPopupTooltip(this.FindForm()).Hide(); } private string _lastWord = null; + private Point _lastLocation = Point.Empty; private void ctrlCode_MouseMove(object sender, MouseEventArgs e) { + _lastLocation = e.Location; + string word = ctrlCode.GetWordUnderLocation(e.Location).Trim(); if(word == _lastWord) { return; } + Form form = this.FindForm(); if(word.Length > 0) { Dictionary values = _manager.GetTooltipData(word, ctrlCode.GetLineIndexAtPosition(e.Y)); if(values != null) { - Form form = this.FindForm(); Point tooltipLocation = ctrlCode.GetWordEndPosition(e.Location); BaseForm.GetPopupTooltip(form).SetTooltip(form.PointToClient(ctrlCode.PointToScreen(tooltipLocation)), values); } else { - BaseForm.GetPopupTooltip(this.FindForm()).Hide(); + BaseForm.GetPopupTooltip(form).Hide(); } } else { - BaseForm.GetPopupTooltip(this.FindForm()).Hide(); + BaseForm.GetPopupTooltip(form).Hide(); } _lastWord = word; @@ -280,5 +446,53 @@ namespace Mesen.GUI.Debugger.Controls { ctrlCode.SetMessage(msg); } + + private void ctxMenu_Opening(object sender, CancelEventArgs e) + { + LocationInfo location = GetActionTarget(); + bool active = location.Address >= 0 || location.Label != null || location.Symbol != null; + + string suffix = location.Symbol?.Name ?? location.Label?.Label; + if(string.IsNullOrWhiteSpace(suffix)) { + suffix = (location.Address >= 0 ? ("$" + location.Address.ToString("X6")) : ""); + } + + string labelName = ""; + if(suffix.Length > 0) { + labelName = " (" + suffix + ")"; + if(location.ArrayIndex.HasValue) { + suffix += "+" + location.ArrayIndex.Value.ToString(); + } + suffix = " (" + suffix + ")"; + } else if(!active || location.Symbol != null) { + suffix = ""; + labelName = ""; + } + + bool enableGoToLocation = (location.Address != _manager.Provider.GetLineAddress(ctrlCode.SelectedLine)); + + mnuAddToWatch.Text = "Add to Watch" + suffix; + mnuEditInMemoryTools.Text = "Edit in Memory Tools" + suffix; + mnuEditLabel.Text = "Edit Label" + labelName; + mnuGoToLocation.Text = "Go to Location" + (enableGoToLocation ? suffix : ""); + + mnuAddToWatch.Enabled = active; + mnuEditInMemoryTools.Enabled = active; + mnuEditLabel.Enabled = active && location.Symbol == null; + mnuGoToLocation.Enabled = active && enableGoToLocation; + } + + private void ctxMenu_Closing(object sender, ToolStripDropDownClosingEventArgs e) + { + mnuAddToWatch.Enabled = true; + mnuEditInMemoryTools.Enabled = true; + mnuEditLabel.Enabled = true; + mnuGoToLocation.Enabled = true; + } + + private void ctrlCode_MouseDoubleClick(object sender, MouseEventArgs e) + { + GoToLocation(GetActionTarget()); + } } } diff --git a/UI/Debugger/frmDebugger.cs b/UI/Debugger/frmDebugger.cs index 1d2aeeb..b728384 100644 --- a/UI/Debugger/frmDebugger.cs +++ b/UI/Debugger/frmDebugger.cs @@ -249,7 +249,7 @@ namespace Mesen.GUI.Debugger public void GoToAddress(int address) { - ctrlDisassemblyView.GoToAddress((int)address); + ctrlDisassemblyView.ScrollToAddress((uint)address); } private void GoToAddress() @@ -258,7 +258,7 @@ namespace Mesen.GUI.Debugger using(frmGoToLine frm = new frmGoToLine(address, _cpuType == CpuType.Spc ? 4 : 6)) { frm.StartPosition = FormStartPosition.CenterParent; if(frm.ShowDialog(ctrlDisassemblyView) == DialogResult.OK) { - ctrlDisassemblyView.GoToAddress((int)address.Address); + ctrlDisassemblyView.ScrollToAddress(address.Address); } } } @@ -273,7 +273,7 @@ namespace Mesen.GUI.Debugger private void GoToVector(CpuVector vector) { - ctrlDisassemblyView.GoToAddress(GetVectorAddress(vector)); + ctrlDisassemblyView.ScrollToAddress((uint)GetVectorAddress(vector)); } private void UpdateDebugger(DebugState state, int? activeAddress) @@ -380,7 +380,7 @@ namespace Mesen.GUI.Debugger private void ctrlBreakpoints_BreakpointNavigation(Breakpoint bp) { - ctrlDisassemblyView.GoToAddress(bp.GetRelativeAddress()); + ctrlDisassemblyView.ScrollToAddress((uint)bp.GetRelativeAddress()); } private void mnuGoTo_DropDownOpening(object sender, EventArgs e)