Debugger - Added callstack

This commit is contained in:
Souryo 2015-08-09 14:47:27 -04:00
parent 955fd88a36
commit cb8ec83408
12 changed files with 414 additions and 48 deletions

View file

@ -474,14 +474,15 @@ class BaseMapper : public IMemoryHandler, public Snapshotable, public INotificat
int32_t FromAbsoluteAddress(uint32_t addr)
{
/*uint32_t page = addr / GetPRGPageSize();
for(int i = 0, len = GetPRGSlotCount(); i < len; i++) {
if((_prgSlotPages[i] % GetPRGPageCount()) == page) {
uint32_t offset = addr - (page * GetPRGPageSize());
return GetPRGPageSize() * i + offset + 0x8000;
uint8_t* ptrAddress = _prgRom + addr;
for(int i = 0; i < 256; i++) {
uint8_t* pageAddress = _prgPages[i];
if(pageAddress != nullptr && ptrAddress >= pageAddress && ptrAddress <= pageAddress + 0xFF) {
return (i << 8) + (ptrAddress - pageAddress);
}
}
*/
//Address is currently not mapped
return -1;
}

View file

@ -112,6 +112,24 @@ void Debugger::PrivateCheckBreakpoint(BreakpointType type, uint32_t addr)
bool breakDone = false;
if(type == BreakpointType::Execute) {
_lastInstruction = _memoryManager->DebugRead(addr);
//Update callstack
if(_lastInstruction == 0x60 && !_callstackRelative.empty()) {
//RTS
_callstackRelative.pop_back();
_callstackRelative.pop_back();
_callstackAbsolute.pop_back();
_callstackAbsolute.pop_back();
} else if(_lastInstruction == 0x20 && _callstackRelative.size() < 1022) {
//JSR
uint16_t targetAddr = _memoryManager->DebugRead(addr + 1) | (_memoryManager->DebugRead(addr + 2) << 8);
_callstackRelative.push_back(addr);
_callstackRelative.push_back(targetAddr);
_callstackAbsolute.push_back(_mapper->ToAbsoluteAddress(addr));
_callstackAbsolute.push_back(_mapper->ToAbsoluteAddress(targetAddr));
}
if(_stepOut && _lastInstruction == 0x60) {
//RTS found, set StepCount to 2 to break on the following instruction
Step(2);
@ -435,4 +453,20 @@ void Debugger::GetPalette(uint32_t* frameBuffer)
}
VideoDecoder::GetInstance()->DebugDecodeFrame(screenBuffer, frameBuffer, 4*8);
delete[] screenBuffer;
}
void Debugger::GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelative)
{
for(size_t i = 0, len = _callstackRelative.size(); i < len; i++) {
callstackAbsolute[i] = _callstackAbsolute[i];
int32_t relativeAddr = _callstackRelative[i];
if(_mapper->FromAbsoluteAddress(_callstackAbsolute[i]) == -1) {
//Mark address as an unmapped memory addr
relativeAddr |= 0x10000;
}
callstackRelative[i] = relativeAddr;
}
callstackAbsolute[_callstackRelative.size()] = -2;
callstackRelative[_callstackRelative.size()] = -2;
}

View file

@ -2,7 +2,9 @@
#include "stdafx.h"
#include <atomic>
#include <deque>
using std::atomic;
using std::deque;
#include "CPU.h"
#include "PPU.h"
@ -44,6 +46,8 @@ private:
vector<shared_ptr<Breakpoint>> _readBreakpoints;
vector<shared_ptr<Breakpoint>> _writeBreakpoints;
vector<shared_ptr<Breakpoint>> _execBreakpoints;
deque<uint32_t> _callstackAbsolute;
deque<uint32_t> _callstackRelative;
SimpleLock _bpLock;
SimpleLock _breakLock;
@ -75,6 +79,8 @@ public:
void GetSprites(uint32_t* frameBuffer);
void GetPalette(uint32_t* frameBuffer);
void GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelative);
void GetState(DebugState *state);
void Step(uint32_t count = 1);

View file

@ -43,6 +43,11 @@ namespace Mesen.GUI.Debugger.Controls
this.ScrollableTextbox.GoToAddress();
}
public void ScrollToLineNumber(int lineNumber)
{
this.ScrollableTextbox.ScrollToLineNumber(lineNumber);
}
public int GetCurrentLine()
{
return this.ScrollableTextbox.CurrentLine;

View file

@ -0,0 +1,71 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlCallstack
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lstCallstack = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SuspendLayout();
//
// lstCallstack
//
this.lstCallstack.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1});
this.lstCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
this.lstCallstack.Font = new System.Drawing.Font("Consolas", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lstCallstack.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
this.lstCallstack.Location = new System.Drawing.Point(0, 0);
this.lstCallstack.MultiSelect = false;
this.lstCallstack.Name = "lstCallstack";
this.lstCallstack.Size = new System.Drawing.Size(324, 125);
this.lstCallstack.TabIndex = 1;
this.lstCallstack.UseCompatibleStateImageBehavior = false;
this.lstCallstack.View = System.Windows.Forms.View.Details;
this.lstCallstack.DoubleClick += new System.EventHandler(this.lstCallstack_DoubleClick);
//
// columnHeader1
//
this.columnHeader1.Width = 256;
//
// ctrlCallstack
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.lstCallstack);
this.Name = "ctrlCallstack";
this.Size = new System.Drawing.Size(324, 125);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListView lstCallstack;
private System.Windows.Forms.ColumnHeader columnHeader1;
}
}

View file

@ -0,0 +1,74 @@
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()
{
InteropEmu.DebugGetCallstack(out _absoluteCallstack, out _relativeCallstack);
DebugState state = new DebugState();
InteropEmu.DebugGetState(ref state);
_programCounter = state.CPU.DebugPC;
this.lstCallstack.Items.Clear();
int subStartAddr = -1;
for(int i = 0, len = _relativeCallstack.Length; i < len; i+=2) {
int jsrAddr = _relativeCallstack[i];
bool unmappedAddress = false;
if(subStartAddr >= 0) {
unmappedAddress = ((subStartAddr & 0x10000) == 0x10000);
if(unmappedAddress) {
subStartAddr &= 0xFFFF;
jsrAddr &= 0xFFFF;
}
}
string startAddr = subStartAddr >= 0 ? subStartAddr.ToString("X4") : "----";
if(_relativeCallstack[i] == -2) {
break;
}
subStartAddr = _relativeCallstack[i+1];
ListViewItem item = this.lstCallstack.Items.Insert(0, "$" + startAddr + " @ $" + jsrAddr.ToString("X4") + " [$" + _absoluteCallstack[i].ToString("X4") + "]");
if(unmappedAddress) {
item.ForeColor = Color.Gray;
item.Font = new Font(item.Font, FontStyle.Italic);
}
}
this.lstCallstack.Items.Insert(0, "$" + subStartAddr.ToString("X4") + " @ $" + _programCounter.ToString("X4"));
}
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(this.FunctionSelected != null) {
this.FunctionSelected(address, null);
}
}
}
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -41,10 +41,11 @@
this.ctrlConsoleStatus = new Mesen.GUI.Debugger.ctrlConsoleStatus();
this.ctrlDebuggerCodeSplit = new Mesen.GUI.Debugger.ctrlDebuggerCode();
this.tableLayoutPanel10 = new System.Windows.Forms.TableLayoutPanel();
this.grpBreakpoints = new System.Windows.Forms.GroupBox();
this.ctrlBreakpoints = new Mesen.GUI.Debugger.Controls.ctrlBreakpoints();
this.grpWatch = new System.Windows.Forms.GroupBox();
this.ctrlWatch = new Mesen.GUI.Debugger.ctrlWatch();
this.grpBreakpoints = new System.Windows.Forms.GroupBox();
this.ctrlBreakpoints = new Mesen.GUI.Debugger.Controls.ctrlBreakpoints();
this.grpCallstack = new System.Windows.Forms.GroupBox();
this.menuStrip = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuClose = new System.Windows.Forms.ToolStripMenuItem();
@ -72,6 +73,7 @@
this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPpuViewer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMemoryViewer = new System.Windows.Forms.ToolStripMenuItem();
this.ctrlCallstack = new Mesen.GUI.Debugger.Controls.ctrlCallstack();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout();
this.splitContainer.Panel2.SuspendLayout();
@ -79,8 +81,9 @@
this.tlpTop.SuspendLayout();
this.contextMenuCode.SuspendLayout();
this.tableLayoutPanel10.SuspendLayout();
this.grpBreakpoints.SuspendLayout();
this.grpWatch.SuspendLayout();
this.grpBreakpoints.SuspendLayout();
this.grpCallstack.SuspendLayout();
this.menuStrip.SuspendLayout();
this.SuspendLayout();
//
@ -181,52 +184,28 @@
//
// tableLayoutPanel10
//
this.tableLayoutPanel10.ColumnCount = 2;
this.tableLayoutPanel10.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel10.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel10.Controls.Add(this.grpBreakpoints, 0, 0);
this.tableLayoutPanel10.ColumnCount = 3;
this.tableLayoutPanel10.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel10.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel10.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel10.Controls.Add(this.grpWatch, 0, 0);
this.tableLayoutPanel10.Controls.Add(this.grpBreakpoints, 1, 0);
this.tableLayoutPanel10.Controls.Add(this.grpCallstack, 2, 0);
this.tableLayoutPanel10.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel10.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel10.Name = "tableLayoutPanel10";
this.tableLayoutPanel10.RowCount = 1;
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 162F));
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 162F));
this.tableLayoutPanel10.Size = new System.Drawing.Size(984, 162);
this.tableLayoutPanel10.TabIndex = 0;
//
// grpBreakpoints
//
this.grpBreakpoints.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.grpBreakpoints.Controls.Add(this.ctrlBreakpoints);
this.grpBreakpoints.Location = new System.Drawing.Point(495, 3);
this.grpBreakpoints.Name = "grpBreakpoints";
this.grpBreakpoints.Size = new System.Drawing.Size(486, 156);
this.grpBreakpoints.TabIndex = 3;
this.grpBreakpoints.TabStop = false;
this.grpBreakpoints.Text = "Breakpoints";
//
// ctrlBreakpoints
//
this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16);
this.ctrlBreakpoints.Name = "ctrlBreakpoints";
this.ctrlBreakpoints.Size = new System.Drawing.Size(480, 137);
this.ctrlBreakpoints.TabIndex = 0;
this.ctrlBreakpoints.BreakpointChanged += new System.EventHandler(this.ctrlBreakpoints_BreakpointChanged);
//
// grpWatch
//
this.grpWatch.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.grpWatch.Controls.Add(this.ctrlWatch);
this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpWatch.Location = new System.Drawing.Point(3, 3);
this.grpWatch.Name = "grpWatch";
this.grpWatch.Size = new System.Drawing.Size(486, 156);
this.grpWatch.Size = new System.Drawing.Size(322, 156);
this.grpWatch.TabIndex = 2;
this.grpWatch.TabStop = false;
this.grpWatch.Text = "Watch";
@ -236,9 +215,40 @@
this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlWatch.Location = new System.Drawing.Point(3, 16);
this.ctrlWatch.Name = "ctrlWatch";
this.ctrlWatch.Size = new System.Drawing.Size(480, 137);
this.ctrlWatch.Size = new System.Drawing.Size(316, 137);
this.ctrlWatch.TabIndex = 0;
//
// grpBreakpoints
//
this.grpBreakpoints.Controls.Add(this.ctrlBreakpoints);
this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpBreakpoints.Location = new System.Drawing.Point(331, 3);
this.grpBreakpoints.Name = "grpBreakpoints";
this.grpBreakpoints.Size = new System.Drawing.Size(322, 156);
this.grpBreakpoints.TabIndex = 3;
this.grpBreakpoints.TabStop = false;
this.grpBreakpoints.Text = "Breakpoints";
//
// ctrlBreakpoints
//
this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16);
this.ctrlBreakpoints.Name = "ctrlBreakpoints";
this.ctrlBreakpoints.Size = new System.Drawing.Size(316, 137);
this.ctrlBreakpoints.TabIndex = 0;
this.ctrlBreakpoints.BreakpointChanged += new System.EventHandler(this.ctrlBreakpoints_BreakpointChanged);
//
// grpCallstack
//
this.grpCallstack.Controls.Add(this.ctrlCallstack);
this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpCallstack.Location = new System.Drawing.Point(659, 3);
this.grpCallstack.Name = "grpCallstack";
this.grpCallstack.Size = new System.Drawing.Size(322, 156);
this.grpCallstack.TabIndex = 4;
this.grpCallstack.TabStop = false;
this.grpCallstack.Text = "Callstack";
//
// menuStrip
//
this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -472,6 +482,15 @@
this.mnuMemoryViewer.Text = "Memory Viewer";
this.mnuMemoryViewer.Click += new System.EventHandler(this.mnuMemoryViewer_Click);
//
// ctrlCallstack
//
this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlCallstack.Location = new System.Drawing.Point(3, 16);
this.ctrlCallstack.Name = "ctrlCallstack";
this.ctrlCallstack.Size = new System.Drawing.Size(316, 137);
this.ctrlCallstack.TabIndex = 0;
this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected);
//
// frmDebugger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -491,8 +510,9 @@
this.tlpTop.ResumeLayout(false);
this.contextMenuCode.ResumeLayout(false);
this.tableLayoutPanel10.ResumeLayout(false);
this.grpBreakpoints.ResumeLayout(false);
this.grpWatch.ResumeLayout(false);
this.grpBreakpoints.ResumeLayout(false);
this.grpCallstack.ResumeLayout(false);
this.menuStrip.ResumeLayout(false);
this.menuStrip.PerformLayout();
this.ResumeLayout(false);
@ -542,5 +562,7 @@
private System.Windows.Forms.ToolStripMenuItem mnuIncreaseFontSize;
private System.Windows.Forms.ToolStripMenuItem mnuDecreaseFontSize;
private System.Windows.Forms.ToolStripMenuItem mnuResetFontSize;
private System.Windows.Forms.GroupBox grpCallstack;
private Controls.ctrlCallstack ctrlCallstack;
}
}

View file

@ -91,6 +91,7 @@ namespace Mesen.GUI.Debugger
ctrlConsoleStatus.UpdateStatus(ref state);
ctrlWatch.UpdateWatch();
ctrlCallstack.UpdateCallstack();
}
private void ClearActiveStatement()
@ -242,5 +243,10 @@ namespace Mesen.GUI.Debugger
{
OpenChildForm(new frmPpuViewer());
}
private void ctrlCallstack_FunctionSelected(object sender, EventArgs e)
{
_lastCodeWindow.ScrollToLineNumber((int)sender);
}
}
}

View file

@ -109,6 +109,12 @@
<Compile Include="Debugger\Controls\ctrlBreakpoints.Designer.cs">
<DependentUpon>ctrlBreakpoints.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlCallstack.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlCallstack.Designer.cs">
<DependentUpon>ctrlCallstack.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlPaletteViewer.cs">
<SubType>UserControl</SubType>
</Compile>
@ -289,6 +295,9 @@
<EmbeddedResource Include="Debugger\Controls\ctrlBreakpoints.resx">
<DependentUpon>ctrlBreakpoints.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlCallstack.resx">
<DependentUpon>ctrlCallstack.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlPaletteViewer.resx">
<DependentUpon>ctrlPaletteViewer.cs</DependentUpon>
</EmbeddedResource>

View file

@ -82,12 +82,8 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern IntPtr DebugGetCode();
[DllImport(DLLPath)] public static extern Byte DebugGetMemoryValue(UInt32 addr);
[DllImport(DLLPath)] public static extern UInt32 DebugGetRelativeAddress(UInt32 addr);
[DllImport(DLLPath, EntryPoint="DebugGetMemoryState")] private static extern UInt32 DebugGetMemoryStateWrapper(DebugMemoryType type, IntPtr buffer);
[DllImport(DLLPath, EntryPoint="DebugGetNametable")] private static extern void DebugGetNametableWrapper(UInt32 nametableIndex, IntPtr frameBuffer, IntPtr tileData, IntPtr attributeData);
[DllImport(DLLPath, EntryPoint="DebugGetChrBank")] private static extern void DebugGetChrBankWrapper(UInt32 bankIndex, IntPtr frameBuffer, Byte palette);
[DllImport(DLLPath, EntryPoint="DebugGetSprites")] private static extern void DebugGetSpritesWrapper(IntPtr frameBuffer);
[DllImport(DLLPath, EntryPoint="DebugGetPalette")] private static extern void DebugGetPaletteWrapper(IntPtr frameBuffer);
[DllImport(DLLPath, EntryPoint="DebugGetMemoryState")] private static extern UInt32 DebugGetMemoryStateWrapper(DebugMemoryType type, IntPtr buffer);
public static byte[] DebugGetMemoryState(DebugMemoryType type)
{
byte[] buffer = new byte[10485760]; //10mb buffer
@ -101,6 +97,7 @@ namespace Mesen.GUI
return buffer;
}
[DllImport(DLLPath, EntryPoint="DebugGetNametable")] private static extern void DebugGetNametableWrapper(UInt32 nametableIndex, IntPtr frameBuffer, IntPtr tileData, IntPtr attributeData);
public static void DebugGetNametable(int nametableIndex, out byte[] frameData, out byte[] tileData, out byte[] attributeData)
{
frameData = new byte[256*240*4];
@ -119,6 +116,7 @@ namespace Mesen.GUI
}
}
[DllImport(DLLPath, EntryPoint="DebugGetChrBank")] private static extern void DebugGetChrBankWrapper(UInt32 bankIndex, IntPtr frameBuffer, Byte palette);
public static byte[] DebugGetChrBank(int bankIndex, int palette)
{
byte[] frameData = new byte[128*128*4];
@ -133,6 +131,7 @@ namespace Mesen.GUI
return frameData;
}
[DllImport(DLLPath, EntryPoint="DebugGetSprites")] private static extern void DebugGetSpritesWrapper(IntPtr frameBuffer);
public static byte[] DebugGetSprites()
{
byte[] frameData = new byte[64*128*4];
@ -147,6 +146,7 @@ namespace Mesen.GUI
return frameData;
}
[DllImport(DLLPath, EntryPoint="DebugGetPalette")] private static extern void DebugGetPaletteWrapper(IntPtr frameBuffer);
public static byte[] DebugGetPalette()
{
byte[] frameData = new byte[4*8*4];
@ -161,6 +161,22 @@ namespace Mesen.GUI
return frameData;
}
[DllImport(DLLPath, EntryPoint="DebugGetCallstack")] private static extern void DebugGetCallstackWrapper(IntPtr callstackAbsolute, IntPtr callstackRelative);
public static void DebugGetCallstack(out Int32[] callstackAbsolute, out Int32[] callstackRelative)
{
callstackAbsolute = new Int32[1024];
callstackRelative = new Int32[1024];
GCHandle hAbsolute = GCHandle.Alloc(callstackAbsolute, GCHandleType.Pinned);
GCHandle hRelative = GCHandle.Alloc(callstackRelative, GCHandleType.Pinned);
try {
InteropEmu.DebugGetCallstackWrapper(hAbsolute.AddrOfPinnedObject(), hRelative.AddrOfPinnedObject());
} finally {
hAbsolute.Free();
hRelative.Free();
}
}
public static string GetROMPath() { return PtrToStringUtf8(InteropEmu.GetROMPathWrapper()); }
public static string GetKeyName(UInt32 key) { return PtrToStringUtf8(InteropEmu.GetKeyNameWrapper(key)); }

View file

@ -39,6 +39,8 @@ extern "C"
DllExport void __stdcall DebugGetSprites(uint32_t *frameBuffer) { _debugger->GetSprites(frameBuffer); }
DllExport void __stdcall DebugGetPalette(uint32_t *frameBuffer) { _debugger->GetPalette(frameBuffer); }
DllExport void __stdcall DebugGetCallstack(int32_t *callstackAbsolute, int32_t *callstackRelative) { _debugger->GetCallstack(callstackAbsolute, callstackRelative); }
DllExport uint8_t __stdcall DebugGetMemoryValue(uint32_t addr) { return _debugger->GetMemoryValue(addr); }
DllExport uint32_t __stdcall DebugGetRelativeAddress(uint32_t addr) { return _debugger->GetRelativeAddress(addr); }
};