Debugger: Added option to display why the debugger breaks (breakpoint, break options, etc.)

This commit is contained in:
Sour 2018-12-23 00:10:00 -05:00
parent 7814165bb8
commit 4459b18fa3
17 changed files with 274 additions and 90 deletions

View file

@ -1041,11 +1041,11 @@ void Console::BreakIfDebugging()
{
shared_ptr<Debugger> debugger = _debugger;
if(debugger) {
debugger->BreakImmediately();
debugger->BreakImmediately(BreakSource::BreakOnCpuCrash);
} else if(_settings->CheckFlag(EmulationFlags::BreakOnCrash)) {
//When "Break on Crash" is enabled, open the debugger and break immediately if a crash occurs
debugger = GetDebugger(true);
debugger->BreakImmediately();
debugger->BreakImmediately(BreakSource::BreakOnCpuCrash);
}
}

View file

@ -64,6 +64,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
_breakRequested = false;
_pausedForDebugHelper = false;
_breakOnScanline = -2;
_breakSource = BreakSource::Unspecified;
_preventResume = 0;
_stopFlag = false;
@ -329,14 +330,18 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
bool needMark = false;
bool needState = true;
uint32_t markBreakpointId = 0;
uint32_t breakpointId = 0;
EvalResultType resultType;
auto processBreakpoint = [&needMark, &needBreak, &markBreakpointId](Breakpoint &bp) {
auto processBreakpoint = [&needMark, &needBreak, &markBreakpointId, &breakpointId](Breakpoint &bp) {
if(bp.IsMarked()) {
needMark = true;
markBreakpointId = bp.GetId();
}
needBreak |= bp.IsEnabled();
if(bp.IsEnabled()) {
needBreak = true;
breakpointId = bp.GetId();
}
};
for(size_t i = 0, len = breakpoints.size(); i < len; i++) {
@ -372,7 +377,7 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
if(needBreak && allowBreak) {
//Found a matching breakpoint, stop execution
Step(1);
SleepUntilResume();
SleepUntilResume(BreakSource::Breakpoint, breakpointId, type, operationInfo.Address);
}
}
@ -510,7 +515,7 @@ void Debugger::ProcessPpuCycle()
_ppuStepCount--;
if(_ppuStepCount == 0) {
Step(1);
SleepUntilResume();
SleepUntilResume(BreakSource::PpuStep);
}
}
}
@ -587,7 +592,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
if(_enableBreakOnUninitRead && CheckFlag(DebuggerFlags::BreakOnUninitMemoryRead)) {
//Break on uninit memory read
Step(1);
breakDone = SleepUntilResume();
breakDone = SleepUntilResume(BreakSource::BreakOnUninitMemoryRead);
}
}
}
@ -627,11 +632,14 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
_profiler->ProcessInstructionStart(absoluteAddr);
BreakSource breakSource = BreakSource::Unspecified;
if(value == 0 && CheckFlag(DebuggerFlags::BreakOnBrk)) {
Step(1);
breakSource = BreakSource::BreakOnBrk;
} else if(CheckFlag(DebuggerFlags::BreakOnUnofficialOpCode) && _disassembler->IsUnofficialOpCode(value)) {
Step(1);
}
breakSource = BreakSource::BreakOnUnofficialOpCode;
}
if(_runToCycle != 0) {
if(_cpu->GetCycleCount() >= _runToCycle) {
@ -647,7 +655,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
}
_lastInstruction = value;
breakDone = SleepUntilResume();
breakDone = SleepUntilResume(breakSource);
if(_codeRunner && !_codeRunner->IsRunning()) {
_codeRunner.reset();
@ -711,7 +719,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
return true;
}
bool Debugger::SleepUntilResume(BreakSource source)
bool Debugger::SleepUntilResume(BreakSource source, uint32_t breakpointId, BreakpointType bpType, uint16_t bpAddress)
{
int32_t stepCount = _stepCount.load();
if(stepCount > 0) {
@ -733,7 +741,14 @@ bool Debugger::SleepUntilResume(BreakSource source)
if(preventResume == 0) {
_console->GetSoundMixer()->StopAudio();
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)source);
if(source == BreakSource::Unspecified) {
source = _breakSource;
}
_breakSource = BreakSource::Unspecified;
uint64_t param = ((uint64_t)breakpointId << 32) | ((uint64_t)(bpAddress & 0xFFFF) << 16) | ((uint64_t)(bpType & 0xFF) << 8) | ((uint64_t)source & 0xFF);
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)param);
ProcessEvent(EventType::CodeBreak);
_stepOverAddr = -1;
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
@ -832,7 +847,7 @@ void Debugger::PpuStep(uint32_t count)
_stepOut = false;
}
void Debugger::Step(uint32_t count)
void Debugger::Step(uint32_t count, BreakSource source)
{
//Run CPU for [count] INSTRUCTIONS before breaking again
_stepOut = false;
@ -841,6 +856,7 @@ void Debugger::Step(uint32_t count)
_ppuStepCount = -1;
_stepCount = count;
_breakOnScanline = -2;
_breakSource = source;
}
void Debugger::StepCycles(uint32_t count)
@ -893,10 +909,10 @@ void Debugger::Run()
_stepOut = false;
}
void Debugger::BreakImmediately()
void Debugger::BreakImmediately(BreakSource source)
{
Step(1);
SleepUntilResume();
SleepUntilResume(source);
}
void Debugger::BreakOnScanline(int16_t scanline)

View file

@ -102,6 +102,7 @@ private:
atomic<uint8_t> _lastInstruction;
atomic<bool> _stepOut;
atomic<int32_t> _stepOverAddr;
BreakSource _breakSource;
atomic<bool> _released;
SimpleLock _releaseLock;
@ -140,7 +141,7 @@ private:
void UpdateCallstack(uint8_t currentInstruction, uint32_t addr);
void ProcessStepConditions(uint16_t addr);
bool SleepUntilResume(BreakSource source = BreakSource::Break);
bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0);
void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1);
@ -178,14 +179,14 @@ public:
void ResumeFromBreak();
void PpuStep(uint32_t count = 1);
void Step(uint32_t count = 1);
void Step(uint32_t count = 1, BreakSource source = BreakSource::CpuStep);
void StepCycles(uint32_t cycleCount = 1);
void StepOver();
void StepOut();
void StepBack();
void Run();
void BreakImmediately();
void BreakImmediately(BreakSource source);
void BreakOnScanline(int16_t scanline);
bool LoadCdlFile(string cdlFilepath);

View file

@ -40,9 +40,19 @@ enum class DebuggerFlags
enum class BreakSource
{
Break = 0,
Pause = 1,
BreakAfterSuspend = 2,
Unspecified = -1,
Breakpoint = 0,
CpuStep = 1,
PpuStep = 2,
BreakOnBrk = 3,
BreakOnUnofficialOpCode = 4,
BreakOnReset = 5,
BreakOnFocus = 6,
BreakOnUninitMemoryRead = 7,
BreakOnDecayedOamRead = 8,
BreakOnCpuCrash = 9,
Pause = 10,
BreakAfterSuspend = 11,
};
enum class AddressType

View file

@ -1026,7 +1026,7 @@ uint8_t PPU::ReadSpriteRam(uint8_t addr)
//If this 8-byte row hasn't been read/written to in over 3000 cpu cycles (~1.7ms), return 0xFF to simulate decay
shared_ptr<Debugger> debugger = _console->GetDebugger(false);
if(debugger && debugger->CheckFlag(DebuggerFlags::BreakOnDecayedOamRead)) {
debugger->BreakImmediately();
debugger->BreakImmediately(BreakSource::BreakOnDecayedOamRead);
}
return 0x10;
}

View file

@ -140,6 +140,7 @@ namespace Mesen.GUI.Config
public bool ShowCommentsInLabelList = false;
public bool ShowBreakNotifications = true;
public bool AlwaysScrollToCenter = false;
public bool SplitView = false;
public bool VerticalLayout = false;

View file

@ -99,19 +99,19 @@ namespace Mesen.GUI.Debugger
public bool IsCpuBreakpoint { get { return this._isCpuBreakpoint; } }
private BreakpointType Type
private BreakpointTypeFlags Type
{
get
{
BreakpointType type = BreakpointType.Global;
BreakpointTypeFlags type = BreakpointTypeFlags.Global;
if(BreakOnRead) {
type |= IsCpuBreakpoint ? BreakpointType.Read : BreakpointType.ReadVram;
type |= IsCpuBreakpoint ? BreakpointTypeFlags.Read : BreakpointTypeFlags.ReadVram;
}
if(BreakOnWrite) {
type |= IsCpuBreakpoint ? BreakpointType.Write : BreakpointType.WriteVram;
type |= IsCpuBreakpoint ? BreakpointTypeFlags.Write : BreakpointTypeFlags.WriteVram;
}
if(BreakOnExec && IsCpuBreakpoint) {
type |= BreakpointType.Execute;
type |= BreakpointTypeFlags.Execute;
}
return type;
}

View file

@ -19,6 +19,8 @@ namespace Mesen.GUI.Debugger.Controls
void EditSubroutine();
void EditSelectedCode();
void SetMessage(TextboxMessageInfo message);
CodeViewerActions CodeViewerActions { get; }
ctrlScrollableTextbox CodeViewer { get; }
Ld65DbgImporter SymbolProvider { get; set; }

View file

@ -53,6 +53,11 @@ namespace Mesen.GUI.Debugger
}
}
public void SetMessage(TextboxMessageInfo message)
{
this.ctrlCodeViewer.SetMessage(message);
}
protected override ctrlScrollableTextbox ScrollableTextbox
{
get { return this.ctrlCodeViewer; }

View file

@ -213,6 +213,11 @@ namespace Mesen.GUI.Debugger
{
this.ctrlTextbox.CopySelection(copyLineNumbers, copyContentNotes, copyComments);
}
public void SetMessage(TextboxMessageInfo message)
{
this.ctrlTextbox.SetMessage(message);
}
public int CurrentLine
{

View file

@ -53,6 +53,11 @@ namespace Mesen.GUI.Debugger.Controls
}
}
public void SetMessage(TextboxMessageInfo message)
{
this.ctrlCodeViewer.SetMessage(message);
}
private List<string> _lineNumberNotes = new List<string>();
private void UpdateCode()
{

View file

@ -14,34 +14,6 @@ using System.Windows.Forms;
namespace Mesen.GUI.Debugger
{
[Flags]
public enum LineSymbol
{
None = 0,
Circle = 1,
CircleOutline = 2,
Arrow = 4,
Mark = 8,
Plus = 16
}
public enum eHistoryType
{
Always,
OnScroll,
None
}
public class LineProperties
{
public Color? LineBgColor;
public Color? TextBgColor;
public Color? FgColor;
public Color? OutlineColor;
public Color? AddressColor;
public LineSymbol Symbol;
}
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);
@ -78,6 +50,7 @@ namespace Mesen.GUI.Debugger
private int _extendedMarginWidth = 13;
private float _maxLineWidth = 0;
private int _maxLineWidthIndex = 0;
private TextboxMessageInfo _message;
public ctrlTextbox()
{
@ -760,6 +733,10 @@ namespace Mesen.GUI.Debugger
if(!_disableScrollPositionChangedEvent && this.ScrollPositionChanged != null) {
ScrollPositionChanged(this, null);
}
//Clear message if scroll position changes
this.SetMessage(null);
this.Invalidate();
}
}
@ -795,6 +772,14 @@ namespace Mesen.GUI.Debugger
}
}
public void SetMessage(TextboxMessageInfo message)
{
if(_message != message) {
_message = message;
Invalidate();
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
@ -827,12 +812,23 @@ namespace Mesen.GUI.Debugger
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
//Clear message if a key is pressed
this.SetMessage(null);
return base.ProcessCmdKey(ref msg, keyData);
}
int _clickedLine;
bool _mouseDragging;
protected override void OnMouseDown(MouseEventArgs e)
{
this.Focus();
//Clear message if a mouse button is clicked
this.SetMessage(null);
if(e.Button == MouseButtons.XButton1) {
this.NavigateBackward();
} else if(e.Button == MouseButtons.XButton2) {
@ -1362,6 +1358,50 @@ namespace Mesen.GUI.Debugger
positionY += lineHeight;
currentLine++;
}
if(this._message != null && !string.IsNullOrWhiteSpace(this._message.Message)) {
//Display message if one is active
SizeF textSize = pe.Graphics.MeasureString(this._message.Message, this.Font, int.MaxValue, StringFormat.GenericTypographic);
using(SolidBrush brush = new SolidBrush(Color.FromArgb(255, 246, 168))) {
pe.Graphics.FillRectangle(brush, ClientRectangle.Width - textSize.Width - 20, ClientRectangle.Bottom - textSize.Height - 20, textSize.Width + 6, textSize.Height + 6);
}
pe.Graphics.DrawRectangle(Pens.Black, ClientRectangle.Width - textSize.Width - 20, ClientRectangle.Bottom - textSize.Height - 20, textSize.Width + 6, textSize.Height + 6);
pe.Graphics.DrawString(this._message.Message, this.Font, Brushes.Black, ClientRectangle.Width - textSize.Width - 17, ClientRectangle.Bottom - textSize.Height - 17, StringFormat.GenericTypographic);
}
}
}
[Flags]
public enum LineSymbol
{
None = 0,
Circle = 1,
CircleOutline = 2,
Arrow = 4,
Mark = 8,
Plus = 16
}
public enum eHistoryType
{
Always,
OnScroll,
None
}
public class LineProperties
{
public Color? LineBgColor;
public Color? TextBgColor;
public Color? FgColor;
public Color? OutlineColor;
public Color? AddressColor;
public LineSymbol Symbol;
}
public class TextboxMessageInfo
{
public string Message;
}
}

View file

@ -173,6 +173,7 @@ namespace Mesen.GUI.Debugger
this.mnuPpuPartialDraw = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPpuShowPreviousFrame = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator();
this.mnuShowBreakNotifications = new System.Windows.Forms.ToolStripMenuItem();
this.mnuAlwaysScrollToCenter = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRefreshWhileRunning = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator();
@ -254,7 +255,7 @@ namespace Mesen.GUI.Debugger
this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10);
this.splitContainer.Panel2MinSize = 100;
this.splitContainer.Size = new System.Drawing.Size(1075, 570);
this.splitContainer.SplitterDistance = 425;
this.splitContainer.SplitterDistance = 419;
this.splitContainer.SplitterWidth = 7;
this.splitContainer.TabIndex = 1;
this.splitContainer.TabStop = false;
@ -278,7 +279,7 @@ namespace Mesen.GUI.Debugger
//
this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists);
this.ctrlSplitContainerTop.Panel2MinSize = 150;
this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 425);
this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 419);
this.ctrlSplitContainerTop.SplitterDistance = 750;
this.ctrlSplitContainerTop.SplitterWidth = 7;
this.ctrlSplitContainerTop.TabIndex = 3;
@ -299,8 +300,8 @@ namespace Mesen.GUI.Debugger
this.tlpTop.Name = "tlpTop";
this.tlpTop.RowCount = 1;
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 408F));
this.tlpTop.Size = new System.Drawing.Size(750, 425);
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 419F));
this.tlpTop.Size = new System.Drawing.Size(750, 419);
this.tlpTop.TabIndex = 2;
//
// panel1
@ -311,7 +312,7 @@ namespace Mesen.GUI.Debugger
this.panel1.Location = new System.Drawing.Point(3, 0);
this.panel1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(286, 425);
this.panel1.Size = new System.Drawing.Size(286, 419);
this.panel1.TabIndex = 5;
//
// ctrlSourceViewer
@ -320,7 +321,7 @@ namespace Mesen.GUI.Debugger
this.ctrlSourceViewer.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlSourceViewer.Location = new System.Drawing.Point(0, 0);
this.ctrlSourceViewer.Name = "ctrlSourceViewer";
this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 425);
this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 419);
this.ctrlSourceViewer.SymbolProvider = null;
this.ctrlSourceViewer.TabIndex = 7;
this.ctrlSourceViewer.Visible = false;
@ -333,7 +334,7 @@ namespace Mesen.GUI.Debugger
this.ctrlDebuggerCode.Location = new System.Drawing.Point(0, 0);
this.ctrlDebuggerCode.Name = "ctrlDebuggerCode";
this.ctrlDebuggerCode.ShowMemoryValues = false;
this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 425);
this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 419);
this.ctrlDebuggerCode.SymbolProvider = null;
this.ctrlDebuggerCode.TabIndex = 2;
this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode);
@ -347,7 +348,7 @@ namespace Mesen.GUI.Debugger
this.panel2.Location = new System.Drawing.Point(292, 0);
this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(1, 425);
this.panel2.Size = new System.Drawing.Size(1, 419);
this.panel2.TabIndex = 6;
//
// ctrlSourceViewerSplit
@ -356,7 +357,7 @@ namespace Mesen.GUI.Debugger
this.ctrlSourceViewerSplit.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlSourceViewerSplit.Location = new System.Drawing.Point(0, 0);
this.ctrlSourceViewerSplit.Name = "ctrlSourceViewerSplit";
this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 425);
this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 419);
this.ctrlSourceViewerSplit.SymbolProvider = null;
this.ctrlSourceViewerSplit.TabIndex = 8;
this.ctrlSourceViewerSplit.Visible = false;
@ -369,7 +370,7 @@ namespace Mesen.GUI.Debugger
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(0, 0);
this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit";
this.ctrlDebuggerCodeSplit.ShowMemoryValues = false;
this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 425);
this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 419);
this.ctrlDebuggerCodeSplit.SymbolProvider = null;
this.ctrlDebuggerCodeSplit.TabIndex = 4;
this.ctrlDebuggerCodeSplit.Visible = false;
@ -389,7 +390,7 @@ namespace Mesen.GUI.Debugger
this.tableLayoutPanel1.RowCount = 2;
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(458, 425);
this.tableLayoutPanel1.Size = new System.Drawing.Size(458, 419);
this.tableLayoutPanel1.TabIndex = 7;
//
// ctrlConsoleStatus
@ -413,7 +414,7 @@ namespace Mesen.GUI.Debugger
this.tlpVerticalLayout.Name = "tlpVerticalLayout";
this.tlpVerticalLayout.RowCount = 1;
this.tlpVerticalLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpVerticalLayout.Size = new System.Drawing.Size(458, 25);
this.tlpVerticalLayout.Size = new System.Drawing.Size(458, 19);
this.tlpVerticalLayout.TabIndex = 4;
//
// tlpFunctionLabelLists
@ -429,16 +430,16 @@ namespace Mesen.GUI.Debugger
this.tlpFunctionLabelLists.RowCount = 2;
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 425);
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 419);
this.tlpFunctionLabelLists.TabIndex = 5;
//
// grpLabels
//
this.grpLabels.Controls.Add(this.ctrlLabelList);
this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpLabels.Location = new System.Drawing.Point(3, 215);
this.grpLabels.Location = new System.Drawing.Point(3, 212);
this.grpLabels.Name = "grpLabels";
this.grpLabels.Size = new System.Drawing.Size(312, 207);
this.grpLabels.Size = new System.Drawing.Size(312, 204);
this.grpLabels.TabIndex = 6;
this.grpLabels.TabStop = false;
this.grpLabels.Text = "Labels";
@ -448,7 +449,7 @@ namespace Mesen.GUI.Debugger
this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlLabelList.Location = new System.Drawing.Point(3, 16);
this.ctrlLabelList.Name = "ctrlLabelList";
this.ctrlLabelList.Size = new System.Drawing.Size(306, 188);
this.ctrlLabelList.Size = new System.Drawing.Size(306, 185);
this.ctrlLabelList.TabIndex = 0;
this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence);
this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected);
@ -459,7 +460,7 @@ namespace Mesen.GUI.Debugger
this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpFunctions.Location = new System.Drawing.Point(3, 3);
this.grpFunctions.Name = "grpFunctions";
this.grpFunctions.Size = new System.Drawing.Size(312, 206);
this.grpFunctions.Size = new System.Drawing.Size(312, 203);
this.grpFunctions.TabIndex = 5;
this.grpFunctions.TabStop = false;
this.grpFunctions.Text = "Functions";
@ -469,7 +470,7 @@ namespace Mesen.GUI.Debugger
this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16);
this.ctrlFunctionList.Name = "ctrlFunctionList";
this.ctrlFunctionList.Size = new System.Drawing.Size(306, 187);
this.ctrlFunctionList.Size = new System.Drawing.Size(306, 184);
this.ctrlFunctionList.TabIndex = 0;
this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence);
this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected);
@ -500,7 +501,7 @@ namespace Mesen.GUI.Debugger
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 138);
this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 144);
this.tableLayoutPanel10.TabIndex = 0;
//
// grpWatch
@ -509,7 +510,7 @@ namespace Mesen.GUI.Debugger
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(352, 132);
this.grpWatch.Size = new System.Drawing.Size(352, 138);
this.grpWatch.TabIndex = 2;
this.grpWatch.TabStop = false;
this.grpWatch.Text = "Watch";
@ -519,7 +520,7 @@ namespace Mesen.GUI.Debugger
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(346, 113);
this.ctrlWatch.Size = new System.Drawing.Size(346, 119);
this.ctrlWatch.TabIndex = 0;
//
// grpBreakpoints
@ -528,7 +529,7 @@ namespace Mesen.GUI.Debugger
this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpBreakpoints.Location = new System.Drawing.Point(361, 3);
this.grpBreakpoints.Name = "grpBreakpoints";
this.grpBreakpoints.Size = new System.Drawing.Size(352, 132);
this.grpBreakpoints.Size = new System.Drawing.Size(352, 138);
this.grpBreakpoints.TabIndex = 3;
this.grpBreakpoints.TabStop = false;
this.grpBreakpoints.Text = "Breakpoints";
@ -538,7 +539,7 @@ namespace Mesen.GUI.Debugger
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(346, 113);
this.ctrlBreakpoints.Size = new System.Drawing.Size(346, 119);
this.ctrlBreakpoints.TabIndex = 0;
this.ctrlBreakpoints.BreakpointNavigation += new System.EventHandler(this.ctrlBreakpoints_BreakpointNavigation);
//
@ -548,7 +549,7 @@ namespace Mesen.GUI.Debugger
this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpCallstack.Location = new System.Drawing.Point(719, 3);
this.grpCallstack.Name = "grpCallstack";
this.grpCallstack.Size = new System.Drawing.Size(353, 132);
this.grpCallstack.Size = new System.Drawing.Size(353, 138);
this.grpCallstack.TabIndex = 4;
this.grpCallstack.TabStop = false;
this.grpCallstack.Text = "Call Stack";
@ -558,7 +559,7 @@ namespace Mesen.GUI.Debugger
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(347, 113);
this.ctrlCallstack.Size = new System.Drawing.Size(347, 119);
this.ctrlCallstack.TabIndex = 0;
this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected);
//
@ -1035,6 +1036,7 @@ namespace Mesen.GUI.Debugger
this.mnuPpuPartialDraw,
this.mnuPpuShowPreviousFrame,
this.toolStripMenuItem19,
this.mnuShowBreakNotifications,
this.mnuAlwaysScrollToCenter,
this.mnuRefreshWhileRunning,
this.toolStripMenuItem6,
@ -1558,6 +1560,14 @@ namespace Mesen.GUI.Debugger
this.toolStripMenuItem19.Name = "toolStripMenuItem19";
this.toolStripMenuItem19.Size = new System.Drawing.Size(263, 6);
//
// mnuShowBreakNotifications
//
this.mnuShowBreakNotifications.CheckOnClick = true;
this.mnuShowBreakNotifications.Name = "mnuShowBreakNotifications";
this.mnuShowBreakNotifications.Size = new System.Drawing.Size(266, 22);
this.mnuShowBreakNotifications.Text = "Show break notifications";
this.mnuShowBreakNotifications.Click += new System.EventHandler(this.mnuShowBreakNotifications_Click);
//
// mnuAlwaysScrollToCenter
//
this.mnuAlwaysScrollToCenter.CheckOnClick = true;
@ -2090,5 +2100,6 @@ namespace Mesen.GUI.Debugger
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem26;
private System.Windows.Forms.ToolStripMenuItem mnuAutoCreateJumpLabels;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem25;
private System.Windows.Forms.ToolStripMenuItem mnuShowBreakNotifications;
}
}

View file

@ -13,6 +13,7 @@ using Mesen.GUI.Config;
using Mesen.GUI.Debugger.Controls;
using Mesen.GUI.Forms;
using Mesen.GUI.Controls;
using System.Collections.ObjectModel;
namespace Mesen.GUI.Debugger
{
@ -121,6 +122,7 @@ namespace Mesen.GUI.Debugger
this.mnuShowVerifiedData.Checked = ConfigManager.Config.DebugInfo.ShowVerifiedData;
this.mnuShowUnidentifiedData.Checked = ConfigManager.Config.DebugInfo.ShowUnidentifiedData;
this.mnuShowBreakNotifications.Checked = ConfigManager.Config.DebugInfo.ShowBreakNotifications;
this.mnuAlwaysScrollToCenter.Checked = ConfigManager.Config.DebugInfo.AlwaysScrollToCenter;
this.mnuRefreshWhileRunning.Checked = ConfigManager.Config.DebugInfo.RefreshWhileRunning;
this.mnuShowMemoryValues.Checked = ConfigManager.Config.DebugInfo.ShowMemoryValuesInCodeWindow;
@ -322,7 +324,7 @@ namespace Mesen.GUI.Debugger
{
base.OnActivated(e);
if(ConfigManager.Config.DebugInfo.BreakOnDebuggerFocus && !InteropEmu.DebugIsExecutionStopped()) {
InteropEmu.DebugStep(1);
InteropEmu.DebugStep(1, BreakSource.BreakOnFocus);
}
}
@ -485,6 +487,37 @@ namespace Mesen.GUI.Debugger
InteropEmu.SetFlag(EmulationFlags.DebuggerWindowEnabled, true);
}
private string GetBreakNotification(Int64 param)
{
BreakSource source = (BreakSource)(byte)param;
string message = null;
if(ConfigManager.Config.DebugInfo.ShowBreakNotifications) {
message = ResourceHelper.GetEnumText(source);
if(source == BreakSource.Breakpoint) {
int breakpointId = (int)(param >> 32);
BreakpointType bpType = (BreakpointType)(byte)(param >> 8);
UInt16 bpAddress = (UInt16)(param >> 16);
ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints;
if(breakpointId >= 0 && breakpointId < breakpoints.Count) {
Breakpoint bp = breakpoints[breakpointId];
if(bpType != BreakpointType.Global) {
message += ": " + ResourceHelper.GetEnumText(bpType) + " ($" + bpAddress.ToString("X4") + ")";
}
if(!string.IsNullOrWhiteSpace(bp.Condition)) {
message += Environment.NewLine + bp.Condition;
}
}
} else if(source == BreakSource.CpuStep || source == BreakSource.PpuStep) {
//Don't display anything when breaking due to stepping
message = null;
}
}
return message;
}
private void _notifListener_OnNotification(InteropEmu.NotificationEventArgs e)
{
switch(e.NotificationType) {
@ -508,12 +541,16 @@ namespace Mesen.GUI.Debugger
case InteropEmu.ConsoleNotificationType.CodeBreak:
this.BeginInvoke((MethodInvoker)(() => {
BreakSource source = (BreakSource)e.Parameter.ToInt32();
BreakSource source = (BreakSource)(byte)e.Parameter.ToInt64();
bool bringToFront = (
source == BreakSource.Break && ConfigManager.Config.DebugInfo.BringToFrontOnBreak ||
source < BreakSource.Pause && ConfigManager.Config.DebugInfo.BringToFrontOnBreak ||
source == BreakSource.Pause && ConfigManager.Config.DebugInfo.BringToFrontOnPause
);
UpdateDebugger(true, bringToFront);
_lastCodeWindow.SetMessage(new TextboxMessageInfo() { Message = GetBreakNotification(e.Parameter.ToInt64()) });
mnuContinue.Enabled = true;
mnuBreak.Enabled = false;
}));
@ -538,7 +575,7 @@ namespace Mesen.GUI.Debugger
}));
if(breakOnReset) {
InteropEmu.DebugStep(1);
InteropEmu.DebugStep(1, BreakSource.BreakOnReset);
}
break;
}
@ -670,6 +707,11 @@ namespace Mesen.GUI.Debugger
ctrlSourceViewer.ClearActiveAddress();
ctrlSourceViewerSplit.ClearActiveAddress();
ctrlDebuggerCode.SetMessage(null);
ctrlDebuggerCodeSplit.SetMessage(null);
ctrlSourceViewer.SetMessage(null);
ctrlSourceViewerSplit.SetMessage(null);
}
public void TogglePause()
@ -1212,6 +1254,12 @@ namespace Mesen.GUI.Debugger
ConfigManager.Config.DebugInfo.BringToFrontOnBreak = mnuBringToFrontOnBreak.Checked;
ConfigManager.ApplyChanges();
}
private void mnuShowBreakNotifications_Click(object sender, EventArgs e)
{
ConfigManager.Config.DebugInfo.ShowBreakNotifications = mnuShowBreakNotifications.Checked;
ConfigManager.ApplyChanges();
}
private void mnuAlwaysScrollToCenter_Click(object sender, EventArgs e)
{

View file

@ -1187,6 +1187,26 @@
<Value ID="Irq">IRQ</Value>
<Value ID="SpriteZeroHit">Sprite 0 Hit</Value>
</Enum>
<Enum ID="BreakpointType">
<Value ID="Global">Global</Value>
<Value ID="Execute">Execute</Value>
<Value ID="ReadRam">CPU Read</Value>
<Value ID="WriteRam">CPU Write</Value>
<Value ID="ReadVram">PPU Read</Value>
<Value ID="WriteVram">PPU Write</Value>
</Enum>
<Enum ID="BreakSource">
<Value ID="Breakpoint">Breakpoint</Value>
<Value ID="CpuStep">CPU Step</Value>
<Value ID="PpuStep">PPU Step</Value>
<Value ID="BreakOnBrk">BRK</Value>
<Value ID="BreakOnUnofficialOpCode">Unofficial OP code</Value>
<Value ID="BreakOnReset">Reset event</Value>
<Value ID="BreakOnFocus">Debugger focused</Value>
<Value ID="BreakOnUninitMemoryRead">Uninitialized memory read</Value>
<Value ID="BreakOnDecayedOamRead">Decayed OAM read</Value>
<Value ID="BreakOnCpuCrash">CPU crashed</Value>
</Enum>
<Enum ID="VsPpuType">
<Value ID="RP2C03B">RP2C03B</Value>
<Value ID="RP2C03G">RP2C03G</Value>

View file

@ -229,7 +229,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void DebugSetBreakpoints([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]InteropBreakpoint[] breakpoints, UInt32 length);
[DllImport(DLLPath)] public static extern void DebugSetLabel(UInt32 address, AddressType addressType, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string label, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string comment);
[DllImport(DLLPath)] public static extern void DebugDeleteLabels();
[DllImport(DLLPath)] public static extern void DebugStep(UInt32 count);
[DllImport(DLLPath)] public static extern void DebugStep(UInt32 count, BreakSource source = BreakSource.CpuStep);
[DllImport(DLLPath)] public static extern void DebugPpuStep(UInt32 count);
[DllImport(DLLPath)] public static extern void DebugStepCycles(UInt32 count);
[DllImport(DLLPath)] public static extern void DebugStepOut();
@ -1945,7 +1945,7 @@ namespace Mesen.GUI
{
public Int32 Id;
public DebugMemoryType MemoryType;
public BreakpointType Type;
public BreakpointTypeFlags Type;
public Int32 StartAddress;
public Int32 EndAddress;
@ -2089,9 +2089,19 @@ namespace Mesen.GUI
public RecordMovieFrom RecordFrom;
}
public enum BreakpointType
{
Global = 0,
Execute = 1,
ReadRam = 2,
WriteRam = 3,
ReadVram = 4,
WriteVram = 5,
}
[Flags]
public enum BreakpointType
public enum BreakpointTypeFlags
{
Global = 0,
Execute = 1,
@ -2265,9 +2275,19 @@ namespace Mesen.GUI
public enum BreakSource
{
Break = 0,
Pause = 1,
BreakAfterSuspend = 2,
Unspecified = -1,
Breakpoint = 0,
CpuStep = 1,
PpuStep = 2,
BreakOnBrk = 3,
BreakOnUnofficialOpCode = 4,
BreakOnReset = 5,
BreakOnFocus = 6,
BreakOnUninitMemoryRead = 7,
BreakOnDecayedOamRead = 8,
BreakOnCpuCrash = 9,
Pause = 10,
BreakAfterSuspend = 11,
}
public enum AddressType

View file

@ -57,7 +57,7 @@ extern "C"
DllExport bool __stdcall DebugIsExecutionStopped() { return GetDebugger()->IsExecutionStopped(); }
DllExport void __stdcall DebugRun() { GetDebugger()->Run(); }
DllExport void __stdcall DebugStep(uint32_t count) { GetDebugger()->Step(count); }
DllExport void __stdcall DebugStep(uint32_t count, BreakSource breakSource) { GetDebugger()->Step(count, breakSource); }
DllExport void __stdcall DebugStepCycles(uint32_t count) { GetDebugger()->StepCycles(count); }
DllExport void __stdcall DebugStepOver() { GetDebugger()->StepOver(); }
DllExport void __stdcall DebugStepOut() { GetDebugger()->StepOut(); }