Debugger: Added call stack
This commit is contained in:
parent
77afd87815
commit
75361b4bce
16 changed files with 563 additions and 12 deletions
68
Core/CallstackManager.cpp
Normal file
68
Core/CallstackManager.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "stdafx.h"
|
||||
#include "CallstackManager.h"
|
||||
#include "Debugger.h"
|
||||
#include "DebugBreakHelper.h"
|
||||
|
||||
CallstackManager::CallstackManager(Debugger* debugger)
|
||||
{
|
||||
_debugger = debugger;
|
||||
}
|
||||
|
||||
void CallstackManager::Push(uint32_t srcAddr, uint32_t destAddr, uint32_t returnAddress, StackFrameFlags flags)
|
||||
{
|
||||
if(_callstack.size() >= 511) {
|
||||
//Ensure callstack stays below 512 entries - games can use various tricks that could keep making the callstack grow
|
||||
_callstack.pop_front();
|
||||
}
|
||||
|
||||
StackFrameInfo stackFrame;
|
||||
stackFrame.Source = srcAddr;
|
||||
stackFrame.Target = destAddr;
|
||||
|
||||
stackFrame.Return = returnAddress;
|
||||
|
||||
stackFrame.Flags = flags;
|
||||
|
||||
_callstack.push_back(stackFrame);
|
||||
}
|
||||
|
||||
void CallstackManager::Pop(uint32_t destAddress)
|
||||
{
|
||||
if(_callstack.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t returnAddr = _callstack.back().Return;
|
||||
_callstack.pop_back();
|
||||
|
||||
if(!_callstack.empty() && destAddress != returnAddr) {
|
||||
//Mismatch, pop that stack frame and add the new one
|
||||
bool foundMatch = false;
|
||||
for(int i = (int)_callstack.size() - 1; i >= 0; i--) {
|
||||
if(destAddress == _callstack[i].Return) {
|
||||
//Found a matching stack frame, unstack until that point
|
||||
foundMatch = true;
|
||||
for(int j = (int)_callstack.size() - i - 1; j >= 0; j--) {
|
||||
_callstack.pop_back();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundMatch) {
|
||||
//Couldn't find a matching frame, replace the current one
|
||||
Push(returnAddr, destAddress, returnAddr, StackFrameFlags::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallstackManager::GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize)
|
||||
{
|
||||
DebugBreakHelper helper(_debugger);
|
||||
int i = 0;
|
||||
for(StackFrameInfo &info : _callstack) {
|
||||
callstackArray[i] = info;
|
||||
i++;
|
||||
}
|
||||
callstackSize = i;
|
||||
}
|
20
Core/CallstackManager.h
Normal file
20
Core/CallstackManager.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DebugTypes.h"
|
||||
|
||||
class Debugger;
|
||||
|
||||
class CallstackManager
|
||||
{
|
||||
private:
|
||||
Debugger* _debugger;
|
||||
deque<StackFrameInfo> _callstack;
|
||||
|
||||
public:
|
||||
CallstackManager(Debugger* debugger);
|
||||
|
||||
void Push(uint32_t srcAddr, uint32_t destAddr, uint32_t returnAddress, StackFrameFlags flags);
|
||||
void Pop(uint32_t destAddr);
|
||||
|
||||
void GetCallstack(StackFrameInfo* callstackArray, uint32_t &callstackSize);
|
||||
};
|
|
@ -55,6 +55,7 @@
|
|||
<ClInclude Include="blargg_source.h" />
|
||||
<ClInclude Include="Breakpoint.h" />
|
||||
<ClInclude Include="BreakpointManager.h" />
|
||||
<ClInclude Include="CallstackManager.h" />
|
||||
<ClInclude Include="CartTypes.h" />
|
||||
<ClInclude Include="CodeDataLogger.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
|
@ -137,6 +138,7 @@
|
|||
<ClCompile Include="BaseVideoFilter.cpp" />
|
||||
<ClCompile Include="Breakpoint.cpp" />
|
||||
<ClCompile Include="BreakpointManager.cpp" />
|
||||
<ClCompile Include="CallstackManager.cpp" />
|
||||
<ClCompile Include="CodeDataLogger.cpp" />
|
||||
<ClCompile Include="Console.cpp" />
|
||||
<ClCompile Include="ConsoleLock.cpp" />
|
||||
|
|
|
@ -251,6 +251,9 @@
|
|||
<ClInclude Include="SpcTimer.h">
|
||||
<Filter>SNES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CallstackManager.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
@ -399,6 +402,9 @@
|
|||
<ClCompile Include="Spc.Instructions.cpp">
|
||||
<Filter>SNES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CallstackManager.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="SNES">
|
||||
|
|
|
@ -189,4 +189,19 @@ struct GetTileViewOptions
|
|||
int32_t AddressOffset;
|
||||
|
||||
bool ShowTileGrid;
|
||||
};
|
||||
|
||||
enum class StackFrameFlags
|
||||
{
|
||||
None = 0,
|
||||
Nmi = 1,
|
||||
Irq = 2
|
||||
};
|
||||
|
||||
struct StackFrameInfo
|
||||
{
|
||||
uint32_t Source;
|
||||
uint32_t Target;
|
||||
uint32_t Return;
|
||||
StackFrameFlags Flags;
|
||||
};
|
|
@ -18,6 +18,7 @@
|
|||
#include "PpuTools.h"
|
||||
#include "EventManager.h"
|
||||
#include "EventType.h"
|
||||
#include "CallstackManager.h"
|
||||
#include "ExpressionEvaluator.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
|
@ -37,6 +38,7 @@ Debugger::Debugger(shared_ptr<Console> console)
|
|||
_breakpointManager.reset(new BreakpointManager(this));
|
||||
_ppuTools.reset(new PpuTools(_console.get(), _ppu.get()));
|
||||
_eventManager.reset(new EventManager(this, _cpu.get(), _ppu.get()));
|
||||
_callstackManager.reset(new CallstackManager(this));
|
||||
|
||||
_cpuStepCount = -1;
|
||||
_executionStopped = false;
|
||||
|
@ -96,7 +98,19 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
|
||||
_traceLogger->Log(debugState, disInfo);
|
||||
|
||||
uint32_t pc = (state.K << 16) | state.PC;
|
||||
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
|
||||
//JSR, JSL
|
||||
uint8_t opSize = DisassemblyInfo::GetOperandSize(_prevOpCode, 0) + 1;
|
||||
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
|
||||
_callstackManager->Push(_prevProgramCounter, pc, returnPc, StackFrameFlags::None);
|
||||
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) {
|
||||
//RTS, RTL, RTI
|
||||
_callstackManager->Pop(pc);
|
||||
}
|
||||
|
||||
_prevOpCode = value;
|
||||
_prevProgramCounter = pc;
|
||||
|
||||
if(_cpuStepCount > 0) {
|
||||
_cpuStepCount--;
|
||||
|
@ -194,11 +208,19 @@ void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInf
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::ProcessInterrupt(bool forNmi)
|
||||
{
|
||||
CpuState state = _cpu->GetState();
|
||||
_callstackManager->Push(_prevProgramCounter, (state.K << 16) | state.PC, _prevProgramCounter, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
|
||||
_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
|
||||
}
|
||||
|
||||
void Debugger::ProcessEvent(EventType type)
|
||||
{
|
||||
switch(type) {
|
||||
case EventType::Nmi: _eventManager->AddEvent(DebugEventType::Nmi); break;
|
||||
case EventType::Irq: _eventManager->AddEvent(DebugEventType::Irq); break;
|
||||
case EventType::Nmi: ProcessInterrupt(true); break;
|
||||
case EventType::Irq: ProcessInterrupt(false); break;
|
||||
|
||||
case EventType::StartFrame:
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh);
|
||||
_eventManager->ClearFrameEvents();
|
||||
|
@ -279,6 +301,11 @@ shared_ptr<EventManager> Debugger::GetEventManager()
|
|||
return _eventManager;
|
||||
}
|
||||
|
||||
shared_ptr<CallstackManager> Debugger::GetCallstackManager()
|
||||
{
|
||||
return _callstackManager;
|
||||
}
|
||||
|
||||
shared_ptr<Console> Debugger::GetConsole()
|
||||
{
|
||||
return _console;
|
||||
|
|
|
@ -17,6 +17,7 @@ class BreakpointManager;
|
|||
class PpuTools;
|
||||
class CodeDataLogger;
|
||||
class EventManager;
|
||||
class CallstackManager;
|
||||
|
||||
enum class EventType;
|
||||
enum class SnesMemoryType;
|
||||
|
@ -44,6 +45,7 @@ private:
|
|||
shared_ptr<BreakpointManager> _breakpointManager;
|
||||
shared_ptr<PpuTools> _ppuTools;
|
||||
shared_ptr<EventManager> _eventManager;
|
||||
shared_ptr<CallstackManager> _callstackManager;
|
||||
|
||||
unique_ptr<ExpressionEvaluator> _watchExpEval;
|
||||
|
||||
|
@ -51,7 +53,12 @@ private:
|
|||
atomic<uint32_t> _breakRequestCount;
|
||||
|
||||
atomic<int32_t> _cpuStepCount;
|
||||
|
||||
uint8_t _prevOpCode = 0;
|
||||
uint32_t _prevProgramCounter = 0;
|
||||
|
||||
void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo);
|
||||
void ProcessInterrupt(bool forNmi);
|
||||
|
||||
public:
|
||||
Debugger(shared_ptr<Console> console);
|
||||
|
@ -68,7 +75,6 @@ public:
|
|||
void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
|
||||
void ProcessPpuCycle();
|
||||
|
||||
void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo);
|
||||
void ProcessEvent(EventType type);
|
||||
|
||||
int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache);
|
||||
|
@ -87,5 +93,6 @@ public:
|
|||
shared_ptr<BreakpointManager> GetBreakpointManager();
|
||||
shared_ptr<PpuTools> GetPpuTools();
|
||||
shared_ptr<EventManager> GetEventManager();
|
||||
shared_ptr<CallstackManager> GetCallstackManager();
|
||||
shared_ptr<Console> GetConsole();
|
||||
};
|
|
@ -9,6 +9,7 @@
|
|||
#include "../Core/BreakpointManager.h"
|
||||
#include "../Core/PpuTools.h"
|
||||
#include "../Core/EventManager.h"
|
||||
#include "../Core/CallstackManager.h"
|
||||
|
||||
extern shared_ptr<Console> _console;
|
||||
|
||||
|
@ -51,6 +52,7 @@ extern "C"
|
|||
|
||||
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->GetBreakpointManager()->SetBreakpoints(breakpoints, length); }
|
||||
DllExport int32_t __stdcall EvaluateExpression(char* expression, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, *resultType, useCache); }
|
||||
DllExport void __stdcall GetCallstack(StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager()->GetCallstack(callstackArray, callstackSize); }
|
||||
|
||||
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state); }
|
||||
|
||||
|
|
127
UI/Debugger/Controls/ctrlCallstack.cs
Normal file
127
UI/Debugger/Controls/ctrlCallstack.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
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;
|
||||
using Mesen.GUI.Controls;
|
||||
|
||||
namespace Mesen.GUI.Debugger.Controls
|
||||
{
|
||||
public partial class ctrlCallstack : BaseControl
|
||||
{
|
||||
public delegate void NavigateToAddressHandler(UInt32 address);
|
||||
public event NavigateToAddressHandler FunctionSelected;
|
||||
|
||||
private StackFrameInfo[] _stackFrames;
|
||||
private UInt32 _programCounter;
|
||||
|
||||
public ctrlCallstack()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void UpdateCallstack()
|
||||
{
|
||||
List<StackInfo> stack = GetStackInfo();
|
||||
this.UpdateList(stack);
|
||||
}
|
||||
|
||||
private List<StackInfo> GetStackInfo()
|
||||
{
|
||||
_stackFrames = DebugApi.GetCallstack();
|
||||
DebugState state = DebugApi.GetState();
|
||||
_programCounter = (uint)(state.Cpu.K << 16) | state.Cpu.PC;
|
||||
|
||||
int relDestinationAddr = -1;
|
||||
|
||||
List<StackInfo> stack = new List<StackInfo>();
|
||||
for(int i = 0, len = _stackFrames.Length; i < len; i++) {
|
||||
int relSubEntryAddr = i == 0 ? -1 : (int)_stackFrames[i-1].Target;
|
||||
|
||||
stack.Add(new StackInfo() {
|
||||
SubName = this.GetFunctionName(relSubEntryAddr, i == 0 ? StackFrameFlags.None : _stackFrames[i - 1].Flags),
|
||||
Address = _stackFrames[i].Source,
|
||||
});
|
||||
|
||||
relDestinationAddr = (int)_stackFrames[i].Target;
|
||||
}
|
||||
|
||||
//Add current location
|
||||
stack.Add(new StackInfo() {
|
||||
SubName = this.GetFunctionName(relDestinationAddr, _stackFrames.Length == 0 ? StackFrameFlags.None : _stackFrames[_stackFrames.Length - 1].Flags),
|
||||
Address = _programCounter,
|
||||
});
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private void UpdateList(List<StackInfo> stack)
|
||||
{
|
||||
this.lstCallstack.BeginUpdate();
|
||||
while(this.lstCallstack.Items.Count > stack.Count) {
|
||||
this.lstCallstack.Items.RemoveAt(this.lstCallstack.Items.Count - 1);
|
||||
}
|
||||
while(this.lstCallstack.Items.Count < stack.Count) {
|
||||
this.lstCallstack.Items.Add("").SubItems.AddRange(new string[] { "", "" });
|
||||
}
|
||||
|
||||
for(int i = 0, len = stack.Count; i < len; i++) {
|
||||
StackInfo stackInfo = stack[i];
|
||||
ListViewItem item = this.lstCallstack.Items[len - i - 1];
|
||||
|
||||
item.Text = stackInfo.SubName;
|
||||
item.SubItems[1].Text = "@ $" + stackInfo.Address.ToString("X6");
|
||||
item.Font = new Font(item.Font, FontStyle.Regular);
|
||||
}
|
||||
this.lstCallstack.EndUpdate();
|
||||
}
|
||||
|
||||
private string GetFunctionName(int relSubEntryAddr, StackFrameFlags flags)
|
||||
{
|
||||
if(relSubEntryAddr < 0) {
|
||||
return "[bottom of stack]";
|
||||
}
|
||||
|
||||
string funcName = "";
|
||||
|
||||
//TODO LABELS
|
||||
/*CodeLabel label = absSubEntryAddr >= 0 ? LabelManager.GetLabel((UInt32)absSubEntryAddr, AddressType.PrgRom) : null;
|
||||
if(label != null) {
|
||||
funcName = label.Label + (relSubEntryAddr >= 0 ? (" ($" + relSubEntryAddr.ToString("X6") + ")") : "");
|
||||
} else {
|
||||
funcName = (relSubEntryAddr >= 0 ? ("$" + relSubEntryAddr.ToString("X6")) : "n/a");
|
||||
}*/
|
||||
|
||||
if(flags == StackFrameFlags.Nmi) {
|
||||
funcName = "[nmi] ";
|
||||
} else if(flags == StackFrameFlags.Irq) {
|
||||
funcName = "[irq] ";
|
||||
}
|
||||
funcName += "$" + relSubEntryAddr.ToString("X6");
|
||||
|
||||
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);
|
||||
} else {
|
||||
StackFrameInfo stackFrameInfo = _stackFrames[(this.lstCallstack.Items.Count - 1 - this.lstCallstack.SelectedIndices[0])];
|
||||
this.FunctionSelected?.Invoke((UInt32)stackFrameInfo.Source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StackInfo
|
||||
{
|
||||
public string SubName;
|
||||
public UInt32 Address;
|
||||
}
|
||||
}
|
||||
}
|
82
UI/Debugger/Controls/ctrlCallstack.designer.cs
generated
Normal file
82
UI/Debugger/Controls/ctrlCallstack.designer.cs
generated
Normal file
|
@ -0,0 +1,82 @@
|
|||
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 Mesen.GUI.Controls.DoubleBufferedListView();
|
||||
this.colFunctionAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.colStackAddr = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lstCallstack
|
||||
//
|
||||
this.lstCallstack.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.colFunctionAddress,
|
||||
this.colStackAddr});
|
||||
this.lstCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lstCallstack.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lstCallstack.FullRowSelect = true;
|
||||
this.lstCallstack.GridLines = true;
|
||||
this.lstCallstack.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
|
||||
this.lstCallstack.HideSelection = false;
|
||||
this.lstCallstack.Location = new System.Drawing.Point(0, 0);
|
||||
this.lstCallstack.MultiSelect = false;
|
||||
this.lstCallstack.Name = "lstCallstack";
|
||||
this.lstCallstack.Size = new System.Drawing.Size(330, 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);
|
||||
//
|
||||
// colFunctionAddress
|
||||
//
|
||||
this.colFunctionAddress.Text = "Function (Entry Address)";
|
||||
this.colFunctionAddress.Width = 174;
|
||||
//
|
||||
// colStackAddr
|
||||
//
|
||||
this.colStackAddr.Text = "PC Address";
|
||||
this.colStackAddr.Width = 88;
|
||||
//
|
||||
// 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(330, 125);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Mesen.GUI.Controls.DoubleBufferedListView lstCallstack;
|
||||
private System.Windows.Forms.ColumnHeader colFunctionAddress;
|
||||
private System.Windows.Forms.ColumnHeader colStackAddr;
|
||||
}
|
||||
}
|
120
UI/Debugger/Controls/ctrlCallstack.resx
Normal file
120
UI/Debugger/Controls/ctrlCallstack.resx
Normal 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>
|
|
@ -65,6 +65,11 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
}
|
||||
}
|
||||
|
||||
public void ScrollToAddress(uint address)
|
||||
{
|
||||
ctrlCode.ScrollToAddress((int)address);
|
||||
}
|
||||
|
||||
private void UpdateCode()
|
||||
{
|
||||
int centerLineIndex = ctrlCode.GetLineIndexAtPosition(0) + ctrlCode.GetNumberVisibleLines() / 2;
|
||||
|
|
44
UI/Debugger/frmDebugger.Designer.cs
generated
44
UI/Debugger/frmDebugger.Designer.cs
generated
|
@ -63,6 +63,8 @@
|
|||
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.ctrlCallstack = new Mesen.GUI.Debugger.Controls.ctrlCallstack();
|
||||
this.tsToolbar = new Mesen.GUI.Controls.ctrlMesenToolStrip();
|
||||
this.ctrlMesenMenuStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.ctrlSplitContainer)).BeginInit();
|
||||
|
@ -72,6 +74,7 @@
|
|||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.grpWatch.SuspendLayout();
|
||||
this.grpBreakpoints.SuspendLayout();
|
||||
this.grpCallstack.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// ctrlDisassemblyView
|
||||
|
@ -298,11 +301,13 @@
|
|||
//
|
||||
// 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.ColumnCount = 3;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.grpWatch, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.grpBreakpoints, 1, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.grpCallstack, 2, 0);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
|
@ -317,7 +322,7 @@
|
|||
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(410, 164);
|
||||
this.grpWatch.Size = new System.Drawing.Size(271, 164);
|
||||
this.grpWatch.TabIndex = 1;
|
||||
this.grpWatch.TabStop = false;
|
||||
this.grpWatch.Text = "Watch";
|
||||
|
@ -327,16 +332,16 @@
|
|||
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(404, 145);
|
||||
this.ctrlWatch.Size = new System.Drawing.Size(265, 145);
|
||||
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(419, 3);
|
||||
this.grpBreakpoints.Location = new System.Drawing.Point(280, 3);
|
||||
this.grpBreakpoints.Name = "grpBreakpoints";
|
||||
this.grpBreakpoints.Size = new System.Drawing.Size(410, 164);
|
||||
this.grpBreakpoints.Size = new System.Drawing.Size(271, 164);
|
||||
this.grpBreakpoints.TabIndex = 2;
|
||||
this.grpBreakpoints.TabStop = false;
|
||||
this.grpBreakpoints.Text = "Breakpoints";
|
||||
|
@ -346,9 +351,29 @@
|
|||
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(404, 145);
|
||||
this.ctrlBreakpoints.Size = new System.Drawing.Size(265, 145);
|
||||
this.ctrlBreakpoints.TabIndex = 0;
|
||||
//
|
||||
// grpCallstack
|
||||
//
|
||||
this.grpCallstack.Controls.Add(this.ctrlCallstack);
|
||||
this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpCallstack.Location = new System.Drawing.Point(557, 3);
|
||||
this.grpCallstack.Name = "grpCallstack";
|
||||
this.grpCallstack.Size = new System.Drawing.Size(272, 164);
|
||||
this.grpCallstack.TabIndex = 3;
|
||||
this.grpCallstack.TabStop = false;
|
||||
this.grpCallstack.Text = "Call Stack";
|
||||
//
|
||||
// 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(266, 145);
|
||||
this.ctrlCallstack.TabIndex = 0;
|
||||
this.ctrlCallstack.FunctionSelected += new Mesen.GUI.Debugger.Controls.ctrlCallstack.NavigateToAddressHandler(this.ctrlCallstack_FunctionSelected);
|
||||
//
|
||||
// tsToolbar
|
||||
//
|
||||
this.tsToolbar.Location = new System.Drawing.Point(0, 24);
|
||||
|
@ -376,6 +401,7 @@
|
|||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.grpWatch.ResumeLayout(false);
|
||||
this.grpBreakpoints.ResumeLayout(false);
|
||||
this.grpCallstack.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
@ -416,5 +442,7 @@
|
|||
private Controls.ctrlConsoleStatus ctrlStatus;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuRun1000Cycles;
|
||||
private GUI.Controls.ctrlMesenToolStrip tsToolbar;
|
||||
private System.Windows.Forms.GroupBox grpCallstack;
|
||||
private Controls.ctrlCallstack ctrlCallstack;
|
||||
}
|
||||
}
|
|
@ -91,6 +91,7 @@ namespace Mesen.GUI.Debugger
|
|||
ctrlStatus.UpdateStatus(state);
|
||||
ctrlDisassemblyView.SetActiveAddress(activeAddress);
|
||||
ctrlWatch.UpdateWatch(true);
|
||||
ctrlCallstack.UpdateCallstack();
|
||||
}));
|
||||
break;
|
||||
}
|
||||
|
@ -110,5 +111,10 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
DebugApi.Step(1000);
|
||||
}
|
||||
|
||||
private void ctrlCallstack_FunctionSelected(uint address)
|
||||
{
|
||||
ctrlDisassemblyView.ScrollToAddress(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,19 @@ namespace Mesen.GUI
|
|||
byte[] buffer = new byte[340*2 * 262*2 * 4];
|
||||
DebugApi.GetEventViewerOutputWrapper(buffer, options);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(DllPath, EntryPoint = "GetCallstack")] private static extern void DebugGetCallstackWrapper([In, Out]StackFrameInfo[] callstackArray, ref UInt32 callstackSize);
|
||||
public static StackFrameInfo[] GetCallstack()
|
||||
{
|
||||
StackFrameInfo[] callstack = new StackFrameInfo[512];
|
||||
UInt32 callstackSize = 0;
|
||||
|
||||
DebugApi.DebugGetCallstackWrapper(callstack, ref callstackSize);
|
||||
Array.Resize(ref callstack, (int)callstackSize);
|
||||
|
||||
return callstack;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SnesMemoryType
|
||||
|
@ -348,4 +360,19 @@ namespace Mesen.GUI
|
|||
DivideBy0 = 3,
|
||||
OutOfScope = 4
|
||||
}
|
||||
|
||||
public struct StackFrameInfo
|
||||
{
|
||||
public UInt32 Source;
|
||||
public UInt32 Target;
|
||||
public UInt32 Return;
|
||||
public StackFrameFlags Flags;
|
||||
};
|
||||
|
||||
public enum StackFrameFlags
|
||||
{
|
||||
None = 0,
|
||||
Nmi = 1,
|
||||
Irq = 2
|
||||
}
|
||||
}
|
||||
|
|
|
@ -320,6 +320,12 @@
|
|||
<Compile Include="Debugger\Controls\ComboBoxWithSeparator.cs">
|
||||
<SubType>Component</SubType>
|
||||
</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\ctrlColorPicker.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
|
@ -686,6 +692,9 @@
|
|||
<EmbeddedResource Include="Debugger\Breakpoints\frmBreakpoint.resx">
|
||||
<DependentUpon>frmBreakpoint.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\Controls\ctrlCallstack.resx">
|
||||
<DependentUpon>ctrlCallstack.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\Controls\ctrlConsoleStatus.resx">
|
||||
<DependentUpon>ctrlConsoleStatus.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
Loading…
Add table
Reference in a new issue