Mesen-X/GUI.NET/Debugger/Controls/ctrlCallstack.cs

111 lines
3.7 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlCallstack : UserControl
{
public event EventHandler FunctionSelected;
private Int32[] _absoluteCallstack;
private Int32[] _relativeCallstack;
private Int32 _programCounter;
public ctrlCallstack()
{
InitializeComponent();
}
public void UpdateCallstack()
{
int nmiHandler = InteropEmu.DebugGetMemoryValue(0xFFFA) | (InteropEmu.DebugGetMemoryValue(0xFFFB) << 8);
int irqHandler = InteropEmu.DebugGetMemoryValue(0xFFFE) | (InteropEmu.DebugGetMemoryValue(0xFFFF) << 8);
InteropEmu.DebugGetCallstack(out _absoluteCallstack, out _relativeCallstack);
DebugState state = new DebugState();
InteropEmu.DebugGetState(ref state);
_programCounter = state.CPU.DebugPC;
this.lstCallstack.BeginUpdate();
this.lstCallstack.Items.Clear();
int relSubEntryAddr = -1, absSubEntryAddr = -1, relCurrentAddr = -1, relDestinationAddr = -1, absCurrentAddr = -1, absDestinationAddr = -1;
ListViewItem item;
for(int i = 0, len = _relativeCallstack.Length; i < len; i+=2) {
if(_relativeCallstack[i] == -2) {
break;
}
relSubEntryAddr = i == 0 ? -1 : _relativeCallstack[i-1] & 0xFFFF;
absSubEntryAddr = i == 0 ? -1 : _absoluteCallstack[i-1] & 0xFFFF;
bool currentAddrUnmapped = (_relativeCallstack[i] & 0x10000) == 0x10000;
relCurrentAddr = _relativeCallstack[i] & 0xFFFF;
relDestinationAddr = _relativeCallstack[i+1] & 0xFFFF;
absCurrentAddr = _absoluteCallstack[i];
absDestinationAddr = _absoluteCallstack[i+1];
item = this.lstCallstack.Items.Insert(0, this.GetFunctionName(relSubEntryAddr, absSubEntryAddr, nmiHandler, irqHandler));
item.SubItems.Add("@ $" + relCurrentAddr.ToString("X4"));
item.SubItems.Add("[$" + absCurrentAddr.ToString("X4") + "]");
if(currentAddrUnmapped) {
item.ForeColor = Color.Gray;
item.Font = new Font(item.Font, FontStyle.Italic);
}
}
item = this.lstCallstack.Items.Insert(0, this.GetFunctionName(relDestinationAddr, absDestinationAddr, nmiHandler, irqHandler));
item.SubItems.Add("@ $" + _programCounter.ToString("X4"));
item.SubItems.Add("[$" + InteropEmu.DebugGetAbsoluteAddress((UInt32)_programCounter).ToString("X4") + "]");
if((relDestinationAddr & 0x10000) == 0x10000) {
item.ForeColor = Color.Gray;
item.Font = new Font(item.Font, FontStyle.Italic);
}
this.lstCallstack.EndUpdate();
}
private string GetFunctionName(int relSubEntryAddr, int absSubEntryAddr, int nmiHandler, int irqHandler)
{
if(relSubEntryAddr < 0) {
return "[bottom of stack]";
}
string funcName;
CodeLabel label = LabelManager.GetLabel((UInt32)absSubEntryAddr);
if(label != null) {
funcName = label.Label + (relSubEntryAddr >= 0 ? (" ($" + relSubEntryAddr.ToString("X4") + ")") : "");
} else {
funcName = (relSubEntryAddr >= 0 ? ("$" + relSubEntryAddr.ToString("X4")) : "n/a");
}
if(relSubEntryAddr == nmiHandler) {
funcName = "[nmi] " + funcName;
} else if(relSubEntryAddr == irqHandler) {
funcName = "[irq] " + funcName;
}
return funcName;
}
private void lstCallstack_DoubleClick(object sender, EventArgs e)
{
if(this.lstCallstack.SelectedIndices.Count > 0) {
if(this.lstCallstack.SelectedIndices[0] == 0) {
this.FunctionSelected(_programCounter, null);
} else {
Int32 address = _relativeCallstack[(this.lstCallstack.Items.Count - 1 - this.lstCallstack.SelectedIndices[0]) * 2];
if((address & 0x10000) == 0) {
this.FunctionSelected?.Invoke(address & 0xFFFF, null);
}
}
}
}
}
}