Debugger: Added support for multi-byte labels

This commit is contained in:
Sour 2019-01-11 00:09:51 -05:00
parent 725ea58562
commit 1a84ef8c4f
13 changed files with 273 additions and 100 deletions

View file

@ -556,6 +556,18 @@ string Disassembler::GetCode(AddressTypeInfo &addressInfo, uint32_t endAddr, uin
} else if(info) {
dataType = DataType::VerifiedCode;
}
if(!label.empty()) {
size_t arrayNotationIndex = label.find_first_of('+');
if(arrayNotationIndex != string::npos && label.size() > arrayNotationIndex + 1) {
if(label[arrayNotationIndex + 1] != '0') {
//Ignore array labels except the +0 variation
label = "";
} else {
label = label.substr(0, label.size() - 2);
}
}
}
if(info && addr + info->GetSize() <= endAddr + 1) {
if(insideDataBlock) {

View file

@ -6,6 +6,7 @@ using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -13,6 +14,8 @@ namespace Mesen.GUI.Debugger
{
class CodeTooltipManager : IDisposable
{
public static Regex LabelArrayFormat = new Regex("(.*)\\+(\\d+)", RegexOptions.Compiled);
private string _hoverLastWord = "";
private int _hoverLastLineAddress = -1;
private Point _previousLocation;
@ -88,14 +91,14 @@ namespace Mesen.GUI.Debugger
this.ShowTooltip(word, values, -1, addressInfo);
}
private void DisplayLabelTooltip(string word, CodeLabel label)
private void DisplayLabelTooltip(string word, CodeLabel label, int? arrayIndex = null)
{
int relativeAddress = InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType);
int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)(label.Address + (arrayIndex ?? 0)), label.AddressType);
byte byteValue = relativeAddress >= 0 ? InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress) : (byte)0;
UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0;
var values = new Dictionary<string, string>() {
{ "Label", label.Label },
{ "Label", label.Label + (arrayIndex != null ? $"+{arrayIndex.Value}" : "") },
{ "Address", "$" + relativeAddress.ToString("X4") },
{ "Value", (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a") },
};
@ -107,17 +110,17 @@ namespace Mesen.GUI.Debugger
ShowTooltip(word, values, -1, new AddressTypeInfo() { Address = (int)label.Address, Type = label.AddressType });
}
private void DisplaySymbolTooltip(Ld65DbgImporter.SymbolInfo symbol)
private void DisplaySymbolTooltip(Ld65DbgImporter.SymbolInfo symbol, int? arrayIndex = null)
{
AddressTypeInfo addressInfo = SymbolProvider.GetSymbolAddressInfo(symbol);
if(addressInfo != null && addressInfo.Address >= 0) {
int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type);
int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)(addressInfo.Address + (arrayIndex ?? 0)), addressInfo.Type);
byte byteValue = relativeAddress >= 0 ? InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress) : (byte)0;
UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0;
var values = new Dictionary<string, string>() {
{ "Symbol", symbol.Name }
{ "Symbol", symbol.Name + (arrayIndex != null ? $"+{arrayIndex.Value}" : "") }
};
if(relativeAddress >= 0) {
@ -127,7 +130,7 @@ namespace Mesen.GUI.Debugger
}
if(addressInfo.Type == AddressType.PrgRom) {
values["PRG Offset"] = "$" + addressInfo.Address.ToString("X4");
values["PRG Offset"] = "$" + (addressInfo.Address + (arrayIndex ?? 0)).ToString("X4");
}
values["Value"] = (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a");
@ -163,7 +166,7 @@ namespace Mesen.GUI.Debugger
DisplayAddressTooltip(word, address);
closeExistingPopup = false;
} else {
DisplayLabelTooltip(word, label);
DisplayLabelTooltip(word, label, 0);
closeExistingPopup = false;
}
} else {
@ -172,20 +175,27 @@ namespace Mesen.GUI.Debugger
}
} catch { }
} else {
Match arrayMatch = LabelArrayFormat.Match(word);
int? arrayIndex = null;
if(arrayMatch.Success) {
word = arrayMatch.Groups[1].Value;
arrayIndex = Int32.Parse(arrayMatch.Groups[2].Value);
}
int address = _codeViewer.GetLineNumberAtPosition(location.Y);
if(SymbolProvider != null) {
int rangeStart, rangeEnd;
if(_codeViewer.GetNoteRangeAtLocation(location.Y, out rangeStart, out rangeEnd)) {
Ld65DbgImporter.SymbolInfo symbol = SymbolProvider.GetSymbol(word, rangeStart, rangeEnd);
if(symbol != null) {
DisplaySymbolTooltip(symbol);
DisplaySymbolTooltip(symbol, arrayIndex);
return;
}
}
} else {
CodeLabel label = LabelManager.GetLabel(word);
if(label != null) {
DisplayLabelTooltip(word, label);
DisplayLabelTooltip(word, label, arrayIndex);
return;
}
}

View file

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using System.Globalization;
using System.Text.RegularExpressions;
namespace Mesen.GUI.Debugger.Controls
{
@ -502,6 +503,11 @@ namespace Mesen.GUI.Debugger.Controls
CodeLabel codeLabel = null;
if(!word.StartsWith("$")) {
Match arrayMatch = CodeTooltipManager.LabelArrayFormat.Match(word);
if(arrayMatch.Success) {
word = arrayMatch.Groups[1].Value;
}
codeLabel = LabelManager.GetLabel(word);
if(Viewer.SymbolProvider != null && IsSourceView) {

View file

@ -55,16 +55,16 @@ namespace Mesen.GUI.Debugger.Controls
public static void EditLabel(UInt32 address, AddressType type)
{
CodeLabel existingLabel = LabelManager.GetLabel(address, type);
CodeLabel newLabel = new CodeLabel() { Address = address, AddressType = type, Label = existingLabel?.Label, Comment = existingLabel?.Comment };
CodeLabel newLabel = new CodeLabel() { Address = address, AddressType = type, Label = existingLabel?.Label, Comment = existingLabel?.Comment, Length = existingLabel?.Length ?? 1 };
frmEditLabel frm = new frmEditLabel(newLabel, existingLabel);
if(frm.ShowDialog() == DialogResult.OK) {
bool empty = string.IsNullOrWhiteSpace(newLabel.Label) && string.IsNullOrWhiteSpace(newLabel.Comment);
if(existingLabel != null) {
LabelManager.DeleteLabel(existingLabel.Address, existingLabel.AddressType, empty);
LabelManager.DeleteLabel(existingLabel, empty);
}
if(!empty) {
LabelManager.SetLabel(newLabel.Address, newLabel.AddressType, newLabel.Label, newLabel.Comment);
LabelManager.SetLabel(newLabel.Address, newLabel.AddressType, newLabel.Label, newLabel.Comment, true, CodeLabelFlags.None, newLabel.Length);
}
}
}
@ -221,7 +221,7 @@ namespace Mesen.GUI.Debugger.Controls
List<int> selectedIndexes = new List<int>(lstLabels.SelectedIndices.Cast<int>().ToList());
for(int i = selectedIndexes.Count - 1; i >= 0; i--) {
CodeLabel label = (CodeLabel)_listItems[selectedIndexes[i]].SubItems[1].Tag;
LabelManager.DeleteLabel(label.Address, label.AddressType, i == 0);
LabelManager.DeleteLabel(label, i == 0);
}
//Reposition scroll bar and selected/focused item
@ -245,7 +245,7 @@ namespace Mesen.GUI.Debugger.Controls
frmEditLabel frm = new frmEditLabel(newLabel);
if(frm.ShowDialog() == DialogResult.OK) {
LabelManager.SetLabel(newLabel.Address, newLabel.AddressType, newLabel.Label, newLabel.Comment);
LabelManager.SetLabel(newLabel.Address, newLabel.AddressType, newLabel.Label, newLabel.Comment, true, CodeLabelFlags.None, newLabel.Length);
}
}

View file

@ -36,23 +36,22 @@
this.lblAbsoluteAddress = new System.Windows.Forms.Label();
this.lblMemoryType = new System.Windows.Forms.Label();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.picWarning = new System.Windows.Forms.PictureBox();
this.lblLabelName = new System.Windows.Forms.Label();
this.picType = new System.Windows.Forms.PictureBox();
this.picWarning = new System.Windows.Forms.PictureBox();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picType)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picWarning)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picType)).BeginInit();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.lblLocation, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 1, 0);
@ -64,7 +63,7 @@
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(251, 36);
this.tableLayoutPanel1.Size = new System.Drawing.Size(274, 36);
this.tableLayoutPanel1.TabIndex = 0;
//
// tableLayoutPanel4
@ -75,7 +74,7 @@
this.tableLayoutPanel4.Controls.Add(this.lblCpu, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.lblRelativeAddress, 1, 0);
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel4.Location = new System.Drawing.Point(125, 17);
this.tableLayoutPanel4.Location = new System.Drawing.Point(148, 17);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
@ -126,7 +125,7 @@
this.tableLayoutPanel2.Controls.Add(this.lblAbsoluteAddress, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.lblMemoryType, 0, 0);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(125, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(148, 0);
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 1;
@ -173,9 +172,19 @@
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.Size = new System.Drawing.Size(125, 17);
this.tableLayoutPanel3.Size = new System.Drawing.Size(148, 17);
this.tableLayoutPanel3.TabIndex = 5;
//
// picWarning
//
this.picWarning.Image = global::Mesen.GUI.Properties.Resources.Warning;
this.picWarning.Location = new System.Drawing.Point(1, 0);
this.picWarning.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0);
this.picWarning.Name = "picWarning";
this.picWarning.Size = new System.Drawing.Size(16, 16);
this.picWarning.TabIndex = 2;
this.picWarning.TabStop = false;
//
// lblLabelName
//
this.lblLabelName.AutoSize = true;
@ -195,16 +204,6 @@
this.picType.TabIndex = 1;
this.picType.TabStop = false;
//
// picWarning
//
this.picWarning.Image = global::Mesen.GUI.Properties.Resources.Warning;
this.picWarning.Location = new System.Drawing.Point(1, 0);
this.picWarning.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0);
this.picWarning.Name = "picWarning";
this.picWarning.Size = new System.Drawing.Size(16, 16);
this.picWarning.TabIndex = 2;
this.picWarning.TabStop = false;
//
// ctrlSearchResult
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -212,7 +211,7 @@
this.Controls.Add(this.tableLayoutPanel1);
this.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.Name = "ctrlSearchResult";
this.Size = new System.Drawing.Size(251, 36);
this.Size = new System.Drawing.Size(274, 36);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel4.ResumeLayout(false);
@ -221,8 +220,8 @@
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel3.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picType)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picWarning)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picType)).EndInit();
this.ResumeLayout(false);
}

View file

@ -52,6 +52,13 @@ namespace Mesen.GUI.Debugger.Controls
public void Initialize(SearchResultInfo info)
{
lblLabelName.Text = info.Caption;
if(info.Length > 1) {
if(info.Length == 2) {
lblLabelName.Text += " (word)";
} else {
lblLabelName.Text += $" ({info.Length} bytes)";
}
}
if(info.AbsoluteAddress >= 0) {
lblAbsoluteAddress.Text = "$" + info.AbsoluteAddress.ToString("X4") + ":$" + info.Value.ToString("X2");
if(info.RelativeAddress >= 0) {
@ -126,6 +133,7 @@ namespace Mesen.GUI.Debugger.Controls
public int AbsoluteAddress;
public int RelativeAddress;
public int Value;
public int Length;
public string Filename;
public int FileLineNumber;
public AddressType MemoryType;

View file

@ -16,7 +16,7 @@ namespace Mesen.GUI.Debugger
{
public partial class ctrlTextbox : Control
{
private Regex _codeRegex = new Regex("^(\\s*)([a-z]{3})([*]{0,1})($|[ ]){1}([(]{0,1})(([$][0-9a-f]*)|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*)){0,1}([)]{0,1})(,X|,Y){0,1}([)]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private Regex _codeRegex = new Regex("^(\\s*)([a-z]{3})([*]{0,1})($|[ ]){1}([(]{0,1})(([$][0-9a-f]*)|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*){0,1}(\\+(\\d+)){0,1}){0,1}([)]{0,1})(,X|,Y){0,1}([)]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public event EventHandler ScrollPositionChanged;
public event EventHandler SelectedLineChanged;
private bool _disableScrollPositionChangedEvent;
@ -502,7 +502,7 @@ namespace Mesen.GUI.Debugger
return false;
}
char[] _wordDelimiters = new char[] { ' ', ',', '|', ';', '(', ')', '.', '-', ':', '+', '<', '>', '#', '*', '/', '&', '[', ']', '~', '%' };
char[] _wordDelimiters = new char[] { ' ', ',', '|', ';', '(', ')', '.', '-', ':', '<', '>', '#', '*', '/', '&', '[', ']', '~', '%' };
public string GetWordUnderLocation(Point position)
{
int charIndex;
@ -1044,10 +1044,11 @@ namespace Mesen.GUI.Debugger
string invalidStar = match.Groups[3].Value;
string paren1 = match.Groups[5].Value;
string operand = match.Groups[6].Value;
string paren2 = match.Groups[11].Value;
string indirect = match.Groups[12].Value;
string paren3 = match.Groups[13].Value;
string rest = match.Groups[14].Value;
string arrayPosition = match.Groups[12].Value;
string paren2 = match.Groups[13].Value;
string indirect = match.Groups[14].Value;
string paren3 = match.Groups[15].Value;
string rest = match.Groups[16].Value;
Color operandColor = operand.Length > 0 ? (operand[0] == '#' ? (Color)info.AssemblerImmediateColor : (operand[0] == '$' ? (Color)info.AssemblerAddressColor : (Color)info.AssemblerLabelDefinitionColor)) : Color.Black;
List<Color> colors = new List<Color>() { defaultColor, info.AssemblerOpcodeColor, defaultColor, defaultColor, defaultColor, operandColor, defaultColor, defaultColor, defaultColor };
int codePartCount = colors.Count;
@ -1068,9 +1069,15 @@ namespace Mesen.GUI.Debugger
Int32.TryParse(memoryAddress.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier, null, out address);
} else {
//Label
UInt32 arrayOffset = 0;
if(!string.IsNullOrWhiteSpace(arrayPosition)) {
memoryAddress = memoryAddress.Substring(0, memoryAddress.Length - arrayPosition.Length - 1);
arrayOffset = UInt32.Parse(arrayPosition);
}
CodeLabel label = LabelManager.GetLabel(memoryAddress);
if(label != null) {
address = label.GetRelativeAddress();
address = InteropEmu.DebugGetRelativeAddress(label.Address + arrayOffset, label.AddressType);
}
}

View file

@ -42,7 +42,7 @@ namespace Mesen.GUI.Debugger
private static Regex _lineRegex = new Regex("^line\tid=([0-9]+),.*file=([0-9]+),.*line=([0-9]+)(,.*type=([0-9]+)){0,1}(,.*span=([0-9+]+)){0,1}", RegexOptions.Compiled);
private static Regex _fileRegex = new Regex("^file\tid=([0-9]+),.*name=\"([^\"]+)\"", RegexOptions.Compiled);
private static Regex _spanRegex = new Regex("^span\tid=([0-9]+),.*seg=([0-9]+),.*start=([0-9]+),.*size=([0-9]+)(,.*type=([0-9]+)){0,1}", RegexOptions.Compiled);
private static Regex _symbolRegex = new Regex("^sym\tid=([0-9]+).*name=\"([0-9a-zA-Z@_-]+)\"(,.*def=([0-9+]+)){0,1}(,.*ref=([0-9+]+)){0,1}(,.*val=0x([0-9a-fA-F]+)){0,1}(,.*seg=([0-9]+)){0,1}(,.*exp=([0-9]+)){0,1}", RegexOptions.Compiled);
private static Regex _symbolRegex = new Regex("^sym\tid=([0-9]+).*name=\"([0-9a-zA-Z@_-]+)\"(,.*size=([0-9]+)){0,1}(,.*def=([0-9+]+)){0,1}(,.*ref=([0-9+]+)){0,1}(,.*val=0x([0-9a-fA-F]+)){0,1}(,.*seg=([0-9]+)){0,1}(,.*exp=([0-9]+)){0,1}", RegexOptions.Compiled);
private static Regex _cSymbolRegex = new Regex("^csym\tid=([0-9]+).*name=\"([0-9a-zA-Z@_-]+)\"(,.*sym=([0-9+]+)){0,1}", RegexOptions.Compiled);
private static Regex _asmFirstLineRegex = new Regex(";(.*)", RegexOptions.Compiled);
@ -160,7 +160,7 @@ namespace Mesen.GUI.Debugger
if(_lines.TryGetValue(definition, out definitionLine)) {
if(_files.TryGetValue(definitionLine.FileID, out file)) {
int lineNumber = definitionLine.LineNumber;
while(!(definitionLine?.SpanIDs.Count > 0) && lineNumber < file.Data.Length - 1) {
while(!(definitionLine?.SpanIDs.Count > 0) && lineNumber < _linesByFile[file.ID].Length - 1) {
//Definition line contains no code, try the next line
lineNumber++;
definitionLine = _linesByFile[file.ID][lineNumber];
@ -392,19 +392,23 @@ namespace Mesen.GUI.Debugger
SymbolInfo symbol = new SymbolInfo() {
ID = Int32.Parse(match.Groups[1].Value),
Name = match.Groups[2].Value,
Address = match.Groups[8].Success ? (int?)Int32.Parse(match.Groups[8].Value, NumberStyles.HexNumber) : null,
SegmentID = match.Groups[10].Success ? (int?)Int32.Parse(match.Groups[10].Value) : null,
ExportSymbolID = match.Groups[12].Success ? (int?)Int32.Parse(match.Groups[12].Value) : null
Address = match.Groups[10].Success ? (int?)Int32.Parse(match.Groups[10].Value, NumberStyles.HexNumber) : null,
SegmentID = match.Groups[12].Success ? (int?)Int32.Parse(match.Groups[12].Value) : null,
ExportSymbolID = match.Groups[14].Success ? (int?)Int32.Parse(match.Groups[14].Value) : null
};
if(match.Groups[4].Success) {
symbol.Definitions = match.Groups[4].Value.Split('+').Select(o => Int32.Parse(o)).ToList();
symbol.Size = Int32.Parse(match.Groups[4].Value);
}
if(match.Groups[6].Success) {
symbol.Definitions = match.Groups[6].Value.Split('+').Select(o => Int32.Parse(o)).ToList();
} else {
symbol.Definitions = new List<int>();
}
if(match.Groups[6].Success) {
symbol.References = match.Groups[6].Value.Split('+').Select(o => Int32.Parse(o)).ToList();
if(match.Groups[8].Success) {
symbol.References = match.Groups[8].Value.Split('+').Select(o => Int32.Parse(o)).ToList();
} else {
symbol.References = new List<int>();
}
@ -418,6 +422,20 @@ namespace Mesen.GUI.Debugger
return false;
}
public int GetSymbolSize(SymbolInfo symbol)
{
if(symbol.SegmentID != null && _segments.ContainsKey(symbol.SegmentID.Value)) {
SegmentInfo segment = _segments[symbol.SegmentID.Value];
SpanInfo defSpan = null;
if(!segment.IsRam) {
defSpan = GetSymbolDefinitionSpan(symbol);
}
return (defSpan == null || defSpan.IsData) ? (symbol.Size ?? 1) : 1;
}
return 1;
}
private void GetRamLabelAddressAndType(int address, out int absoluteAddress, out AddressType? addressType)
{
if(address < 0x2000) {
@ -435,27 +453,27 @@ namespace Mesen.GUI.Debugger
}
}
private CodeLabel CreateLabel(Int32 address, AddressType addressType)
private CodeLabel CreateLabel(Int32 address, AddressType addressType, UInt32 length)
{
CodeLabel label = null;
if(addressType == AddressType.InternalRam) {
if(!_ramLabels.TryGetValue(address, out label)) {
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.InternalRam, Comment = string.Empty, Label = string.Empty };
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.InternalRam, Comment = string.Empty, Label = string.Empty, Length = length };
_ramLabels[address] = label;
}
} else if(addressType == AddressType.WorkRam) {
if(!_workRamLabels.TryGetValue(address, out label)) {
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.WorkRam, Comment = string.Empty, Label = string.Empty };
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.WorkRam, Comment = string.Empty, Label = string.Empty, Length = length };
_workRamLabels[address] = label;
}
} else if(addressType == AddressType.SaveRam) {
if(!_saveRamLabels.TryGetValue(address, out label)) {
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.SaveRam, Comment = string.Empty, Label = string.Empty };
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.SaveRam, Comment = string.Empty, Label = string.Empty, Length = length };
_saveRamLabels[address] = label;
}
} else {
if(!_romLabels.TryGetValue(address, out label)) {
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.PrgRom, Comment = string.Empty, Label = string.Empty };
label = new CodeLabel() { Address = (UInt32)address, AddressType = AddressType.PrgRom, Comment = string.Empty, Label = string.Empty, Length = length };
_romLabels[address] = label;
}
}
@ -487,7 +505,7 @@ namespace Mesen.GUI.Debugger
AddressTypeInfo addressInfo = GetSymbolAddressInfo(symbol);
if(symbol.Address != null) {
int address = addressInfo.Address;
CodeLabel label = this.CreateLabel(addressInfo.Address, addressInfo.Type);
CodeLabel label = this.CreateLabel(addressInfo.Address, addressInfo.Type, (uint)GetSymbolSize(symbol));
if(label != null) {
label.Label = newName;
}
@ -560,7 +578,7 @@ namespace Mesen.GUI.Debugger
}
if(address >= 0 && addressType != null) {
CodeLabel label = this.CreateLabel(address, addressType.Value);
CodeLabel label = this.CreateLabel(address, addressType.Value, 1);
if(label != null) {
label.Comment = comment;
}
@ -859,6 +877,7 @@ namespace Mesen.GUI.Debugger
public int? Address;
public int? SegmentID;
public int? ExportSymbolID;
public int? Size;
public List<int> References;
public List<int> Definitions;
}

View file

@ -15,6 +15,7 @@ namespace Mesen.GUI.Debugger
public string Label;
public string Comment;
public CodeLabelFlags Flags;
public UInt32 Length = 1;
public override string ToString()
{
@ -49,7 +50,8 @@ namespace Mesen.GUI.Debugger
public class LabelManager
{
private static Dictionary<UInt32, CodeLabel> _labels = new Dictionary<UInt32, CodeLabel>();
private static Dictionary<UInt32, CodeLabel> _labelsByKey = new Dictionary<UInt32, CodeLabel>();
private static HashSet<CodeLabel> _labels = new HashSet<CodeLabel>();
private static Dictionary<string, CodeLabel> _reverseLookup = new Dictionary<string, CodeLabel>();
public static event EventHandler OnLabelUpdated;
@ -58,13 +60,14 @@ namespace Mesen.GUI.Debugger
{
InteropEmu.DebugDeleteLabels();
_labels.Clear();
_labelsByKey.Clear();
_reverseLookup.Clear();
}
public static CodeLabel GetLabel(UInt32 address, AddressType type)
{
CodeLabel label;
_labels.TryGetValue(GetKey(address, type), out label);
_labelsByKey.TryGetValue(GetKey(address, type), out label);
return label;
}
@ -86,7 +89,7 @@ namespace Mesen.GUI.Debugger
public static void SetLabels(IEnumerable<CodeLabel> labels, bool raiseEvents = true)
{
foreach(CodeLabel label in labels) {
SetLabel(label.Address, label.AddressType, label.Label, label.Comment, false, label.Flags);
SetLabel(label.Address, label.AddressType, label.Label, label.Comment, false, label.Flags, label.Length);
}
if(raiseEvents) {
OnLabelUpdated?.Invoke(null, null);
@ -95,7 +98,7 @@ namespace Mesen.GUI.Debugger
public static List<CodeLabel> GetLabels()
{
return _labels.Values.ToList<CodeLabel>();
return _labels.ToList<CodeLabel>();
}
private static UInt32 GetKey(UInt32 address, AddressType addressType)
@ -110,25 +113,39 @@ namespace Mesen.GUI.Debugger
throw new Exception("Invalid type");
}
public static bool SetLabel(UInt32 address, AddressType type, string label, string comment, bool raiseEvent = true, CodeLabelFlags flags = CodeLabelFlags.None)
public static bool SetLabel(UInt32 address, AddressType type, string label, string comment, bool raiseEvent = true, CodeLabelFlags flags = CodeLabelFlags.None, UInt32 labelLength = 1)
{
if(_reverseLookup.ContainsKey(label)) {
//Another identical label exists, we need to remove it
CodeLabel existingLabel = _reverseLookup[label];
DeleteLabel(existingLabel.Address, existingLabel.AddressType, false);
DeleteLabel(existingLabel, false);
}
UInt32 key = GetKey(address, type);
if(_labels.ContainsKey(key)) {
_reverseLookup.Remove(_labels[key].Label);
CodeLabel newLabel = new CodeLabel() { Address = address, AddressType = type, Label = label, Comment = comment, Flags = flags, Length = labelLength };
for(UInt32 i = address; i < address + labelLength; i++) {
UInt32 key = GetKey(i, type);
CodeLabel existingLabel;
if(_labelsByKey.TryGetValue(key, out existingLabel)) {
_reverseLookup.Remove(existingLabel.Label);
}
_labelsByKey[key] = newLabel;
if(labelLength == 1) {
InteropEmu.DebugSetLabel(i, type, label, comment.Replace(Environment.NewLine, "\n"));
} else {
InteropEmu.DebugSetLabel(i, type, label + "+" + (i - address).ToString(), comment.Replace(Environment.NewLine, "\n"));
//Only set the comment on the first byte of multi-byte comments
comment = "";
}
}
_labels[key] = new CodeLabel() { Address = address, AddressType = type, Label = label, Comment = comment, Flags = flags };
_labels.Add(newLabel);
if(label.Length > 0) {
_reverseLookup[label] = _labels[key];
_reverseLookup[label] = newLabel;
}
InteropEmu.DebugSetLabel(address, type, label, comment.Replace(Environment.NewLine, "\n"));
if(raiseEvent) {
OnLabelUpdated?.Invoke(null, null);
}
@ -136,17 +153,27 @@ namespace Mesen.GUI.Debugger
return true;
}
public static void DeleteLabel(UInt32 address, AddressType type, bool raiseEvent)
public static void DeleteLabel(CodeLabel label, bool raiseEvent)
{
UInt32 key = GetKey(address, type);
if(_labels.ContainsKey(key)) {
_reverseLookup.Remove(_labels[key].Label);
}
if(_labels.Remove(key)) {
InteropEmu.DebugSetLabel(address, type, string.Empty, string.Empty);
if(raiseEvent) {
OnLabelUpdated?.Invoke(null, null);
bool needEvent = false;
_labels.Remove(label);
for(UInt32 i = label.Address; i < label.Address + label.Length; i++) {
UInt32 key = GetKey(i, label.AddressType);
if(_labelsByKey.ContainsKey(key)) {
_reverseLookup.Remove(_labelsByKey[key].Label);
}
if(_labelsByKey.Remove(key)) {
InteropEmu.DebugSetLabel(i, label.AddressType, string.Empty, string.Empty);
if(raiseEvent) {
needEvent = true;
}
}
}
if(needEvent) {
OnLabelUpdated?.Invoke(null, null);
}
}

View file

@ -39,12 +39,18 @@
this.lblAddressSign = new System.Windows.Forms.Label();
this.txtAddress = new System.Windows.Forms.TextBox();
this.lblRange = new System.Windows.Forms.Label();
this.lblLength = new System.Windows.Forms.Label();
this.nudLength = new Mesen.GUI.Controls.MesenNumericUpDown();
this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel();
this.lblBytes = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
this.flowLayoutPanel3.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 242);
this.baseConfigPanel.Size = new System.Drawing.Size(377, 29);
//
// tableLayoutPanel1
@ -52,6 +58,8 @@
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel3, 1, 4);
this.tableLayoutPanel1.Controls.Add(this.lblLength, 0, 4);
this.tableLayoutPanel1.Controls.Add(this.lblLabel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.lblComment, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.txtComment, 1, 3);
@ -63,12 +71,13 @@
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 4;
this.tableLayoutPanel1.RowCount = 5;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(377, 233);
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(377, 242);
this.tableLayoutPanel1.TabIndex = 2;
//
// lblLabel
@ -85,7 +94,7 @@
//
this.lblComment.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblComment.AutoSize = true;
this.lblComment.Location = new System.Drawing.Point(3, 149);
this.lblComment.Location = new System.Drawing.Point(3, 141);
this.lblComment.Name = "lblComment";
this.lblComment.Size = new System.Drawing.Size(54, 13);
this.lblComment.TabIndex = 1;
@ -99,7 +108,7 @@
this.txtComment.Multiline = true;
this.txtComment.Name = "txtComment";
this.txtComment.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtComment.Size = new System.Drawing.Size(311, 148);
this.txtComment.Size = new System.Drawing.Size(311, 131);
this.txtComment.TabIndex = 3;
//
// txtLabel
@ -180,11 +189,72 @@
this.lblRange.TabIndex = 10;
this.lblRange.Text = "(range)";
//
// lblLength
//
this.lblLength.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblLength.AutoSize = true;
this.lblLength.Location = new System.Drawing.Point(3, 222);
this.lblLength.Name = "lblLength";
this.lblLength.Size = new System.Drawing.Size(43, 13);
this.lblLength.TabIndex = 8;
this.lblLength.Text = "Length:";
//
// nudLength
//
this.nudLength.DecimalPlaces = 0;
this.nudLength.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudLength.Location = new System.Drawing.Point(3, 3);
this.nudLength.Maximum = new decimal(new int[] {
65536,
0,
0,
0});
this.nudLength.MaximumSize = new System.Drawing.Size(10000, 21);
this.nudLength.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.nudLength.MinimumSize = new System.Drawing.Size(0, 21);
this.nudLength.Name = "nudLength";
this.nudLength.Size = new System.Drawing.Size(52, 21);
this.nudLength.TabIndex = 9;
this.nudLength.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// flowLayoutPanel3
//
this.flowLayoutPanel3.Controls.Add(this.nudLength);
this.flowLayoutPanel3.Controls.Add(this.lblBytes);
this.flowLayoutPanel3.ForeColor = System.Drawing.SystemColors.ControlDarkDark;
this.flowLayoutPanel3.Location = new System.Drawing.Point(60, 216);
this.flowLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel3.Name = "flowLayoutPanel3";
this.flowLayoutPanel3.Size = new System.Drawing.Size(200, 26);
this.flowLayoutPanel3.TabIndex = 9;
//
// lblBytes
//
this.lblBytes.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblBytes.AutoSize = true;
this.lblBytes.Location = new System.Drawing.Point(61, 7);
this.lblBytes.Name = "lblBytes";
this.lblBytes.Size = new System.Drawing.Size(84, 13);
this.lblBytes.TabIndex = 10;
this.lblBytes.Text = "bytes (for arrays)";
//
// frmEditLabel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(377, 262);
this.ClientSize = new System.Drawing.Size(377, 271);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "frmEditLabel";
@ -196,6 +266,8 @@
this.tableLayoutPanel1.PerformLayout();
this.flowLayoutPanel2.ResumeLayout(false);
this.flowLayoutPanel2.PerformLayout();
this.flowLayoutPanel3.ResumeLayout(false);
this.flowLayoutPanel3.PerformLayout();
this.ResumeLayout(false);
}
@ -214,5 +286,9 @@
private System.Windows.Forms.Label lblAddressSign;
private System.Windows.Forms.TextBox txtAddress;
private System.Windows.Forms.Label lblRange;
private System.Windows.Forms.Label lblLength;
private GUI.Controls.MesenNumericUpDown nudLength;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel3;
private System.Windows.Forms.Label lblBytes;
}
}

View file

@ -37,6 +37,7 @@ namespace Mesen.GUI.Debugger
AddBinding("Address", txtAddress);
AddBinding("Label", txtLabel);
AddBinding("Comment", txtComment);
AddBinding("Length", nudLength);
}
protected override void OnShown(EventArgs e)
@ -62,6 +63,7 @@ namespace Mesen.GUI.Debugger
UpdateObject();
UInt32 address = ((CodeLabel)Entity).Address;
UInt32 length = ((CodeLabel)Entity).Length;
AddressType type = ((CodeLabel)Entity).AddressType;
CodeLabel sameLabel = LabelManager.GetLabel(txtLabel.Text);
CodeLabel sameAddress = LabelManager.GetLabel(address, type);
@ -75,7 +77,8 @@ namespace Mesen.GUI.Debugger
}
return
address <= maxAddress &&
length >= 1 && length <= 65536 &&
address + (length - 1) <= maxAddress &&
(sameLabel == null || sameLabel == _originalLabel)
&& (sameAddress == null || sameAddress == _originalLabel)
&& (_originalLabel != null || txtLabel.Text.Length > 0 || txtComment.Text.Length > 0)

View file

@ -211,6 +211,7 @@ namespace Mesen.GUI.Debugger
searchResults.Add(new SearchResultInfo() {
Caption = symbol.Name,
AbsoluteAddress = addressInfo?.Address ?? -1,
Length = _symbolProvider.GetSymbolSize(symbol),
MemoryType = addressInfo?.Type ?? AddressType.InternalRam,
SearchResultType = resultType,
Value = value,
@ -236,6 +237,7 @@ namespace Mesen.GUI.Debugger
searchResults.Add(new SearchResultInfo() {
Caption = label.Label,
AbsoluteAddress = (int)label.Address,
Length = (int)label.Length,
Value = label.GetValue(),
MemoryType = label.AddressType,
SearchResultType = resultType,

View file

@ -601,6 +601,7 @@ namespace Mesen.GUI.Debugger
private frmCodeTooltip _tooltip = null;
private CodeLabel _lastLabelTooltip = null;
private int _lastLabelArrayOffset = -1;
private int _lastTooltipAddress = -1;
private void ctrlHexViewer_ByteMouseHover(int address, Point position)
{
@ -608,6 +609,7 @@ namespace Mesen.GUI.Debugger
if(_tooltip != null) {
_tooltip.Close();
_lastLabelTooltip = null;
_lastLabelArrayOffset = -1;
_lastTooltipAddress = -1;
}
return;
@ -620,37 +622,34 @@ namespace Mesen.GUI.Debugger
_lastTooltipAddress = address;
CodeLabel label = null;
int arrayOffset = 0;
switch(_memoryType) {
case DebugMemoryType.CpuMemory:
AddressTypeInfo info = new AddressTypeInfo();
InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)address, info);
if(info.Address >= 0) {
label = LabelManager.GetLabel((UInt32)info.Address, info.Type);
if(label != null) {
arrayOffset = info.Address - (int)label.Address;
} else {
label = LabelManager.GetLabel((UInt32)address, AddressType.Register);
}
}
if(label == null) {
label = LabelManager.GetLabel((UInt32)address, AddressType.Register);
}
break;
case DebugMemoryType.InternalRam:
label = LabelManager.GetLabel((UInt32)address, AddressType.InternalRam);
break;
case DebugMemoryType.WorkRam:
label = LabelManager.GetLabel((UInt32)address, AddressType.WorkRam);
break;
case DebugMemoryType.SaveRam:
label = LabelManager.GetLabel((UInt32)address, AddressType.SaveRam);
break;
case DebugMemoryType.PrgRom:
label = LabelManager.GetLabel((UInt32)address, AddressType.PrgRom);
label = LabelManager.GetLabel((UInt32)address, _memoryType.ToAddressType());
if(label != null) {
arrayOffset = address - (int)label.Address;
}
break;
}
if(label != null) {
if(_lastLabelTooltip != label) {
if(_lastLabelTooltip != label || _lastLabelArrayOffset != arrayOffset) {
if(_tooltip != null) {
_tooltip.Close();
}
@ -658,8 +657,11 @@ namespace Mesen.GUI.Debugger
Dictionary<string, string> values = new Dictionary<string, string>();
if(!string.IsNullOrWhiteSpace(label.Label)) {
values["Label"] = label.Label;
if(label.Length > 1) {
values["Label"] += "+" + arrayOffset.ToString();
}
}
values["Address"] = "$" + label.Address.ToString("X4");
values["Address"] = "$" + (label.Address + arrayOffset).ToString("X4");
values["Address Type"] = label.AddressType.ToString();
if(!string.IsNullOrWhiteSpace(label.Comment)) {
values["Comment"] = label.Comment;
@ -669,11 +671,13 @@ namespace Mesen.GUI.Debugger
_tooltip.FormClosed += (s, evt) => { _tooltip = null; };
_tooltip.SetFormLocation(new Point(position.X, position.Y), ctrlHexViewer);
_lastLabelTooltip = label;
_lastLabelArrayOffset = arrayOffset;
}
} else {
if(_tooltip != null) {
_tooltip.Close();
_lastLabelTooltip = null;
_lastLabelArrayOffset = -1;
_lastTooltipAddress = -1;
}
}