Debugger: Added option to highlight disassembled but not yet executed code (e.g unused branches)

This commit is contained in:
Souryo 2016-11-27 19:43:17 -05:00
parent 76fa3338a9
commit 28899e3e18
10 changed files with 141 additions and 48 deletions

View File

@ -25,7 +25,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
_mapper = mapper;
_labelManager.reset(new LabelManager(_mapper));
_disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), mapper->GetPrgRom(), mapper->GetPrgSize(), mapper->GetWorkRam(), mapper->GetPrgSize(true)));
_disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), mapper->GetPrgRom(), mapper->GetPrgSize(), mapper->GetWorkRam(), mapper->GetPrgSize(true), this));
_codeDataLogger.reset(new CodeDataLogger(mapper->GetPrgSize(), mapper->GetChrSize()));
_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, _mapper, _codeDataLogger));
@ -117,6 +117,17 @@ bool Debugger::LoadCdlFile(string cdlFilepath)
return false;
}
bool Debugger::IsMarkedAsCode(uint16_t relativeAddress)
{
AddressTypeInfo info;
GetAbsoluteAddressAndType(relativeAddress, &info);
if(info.Address >= 0 && info.Type == AddressType::PrgRom) {
return _codeDataLogger->IsCode(info.Address);
} else {
return false;
}
}
bool Debugger::SaveCdlFile(string cdlFilepath)
{
return _codeDataLogger->SaveCdlFile(cdlFilepath);
@ -655,6 +666,9 @@ void Debugger::GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo*
info->Type = AddressType::SaveRam;
return;
}
info->Address = -1;
info->Type = AddressType::InternalRam;
}
void Debugger::SetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle)

View File

@ -125,6 +125,7 @@ public:
bool SaveCdlFile(string cdlFilepath);
CdlRatios GetCdlRatios();
void ResetCdlLog();
bool IsMarkedAsCode(uint16_t relativeAddress);
void SetNextStatement(uint16_t addr);
void SetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle);

View File

@ -6,9 +6,11 @@
#include "CPU.h"
#include "LabelManager.h"
#include "../Utilities/HexUtilities.h"
#include "Debugger.h"
Disassembler::Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize)
Disassembler::Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize, Debugger* debugger)
{
_debugger = debugger;
_internalRam = internalRam;
_prgRom = prgRom;
_prgRam = prgRam;
@ -193,7 +195,10 @@ string Disassembler::GetLine(string code, string comment, int32_t cpuAddress, in
string out;
out.reserve(100);
if(cpuAddress >= 0) {
out += HexUtilities::ToHex((uint16_t)cpuAddress);
out += (_debugger->IsMarkedAsCode(cpuAddress) || absoluteAddress == -1) ? "1\x1" : "0\x1";
out += HexUtilities::ToHex((uint16_t)cpuAddress);
} else {
out += "1\x1";
}
out += "\x1";
if(absoluteAddress >= 0) {

View File

@ -6,10 +6,12 @@ struct State;
class MemoryManager;
class DisassemblyInfo;
class LabelManager;
class Debugger;
class Disassembler
{
private:
Debugger* _debugger;
vector<shared_ptr<DisassemblyInfo>> _disassembleCache;
vector<shared_ptr<DisassemblyInfo>> _disassembleRamCache;
vector<shared_ptr<DisassemblyInfo>> _disassembleMemoryCache;
@ -24,7 +26,7 @@ private:
string GetSubHeader(DisassemblyInfo *info, string &label, uint16_t relativeAddr, uint16_t resetVector, uint16_t nmiVector, uint16_t irqVector);
public:
Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize);
Disassembler(uint8_t* internalRam, uint8_t* prgRom, uint32_t prgSize, uint8_t* prgRam, uint32_t prgRamSize, Debugger* debugger);
~Disassembler();
uint32_t BuildCache(int32_t absoluteAddr, int32_t absoluteRamAddr, uint16_t memoryAddr, bool isSubEntryPoint);

View File

@ -21,26 +21,18 @@ string DisassemblyInfo::ToString(uint32_t memoryAddr, shared_ptr<MemoryManager>
out = DisassemblyInfo::OPName[opCode];
}
if(_opSize == 2) {
_opAddr = *(_opPointer + 1);
} else if(_opSize == 3) {
_opAddr = *(_opPointer + 1) | (*(_opPointer + 2) << 8);
}
if(_opMode == AddrMode::Rel) {
_opAddr = (int8_t)_opAddr + memoryAddr + 2;
}
uint16_t opAddr = GetOpAddr(memoryAddr);
string operandValue;
if(labelManager && _opMode != AddrMode::Imm) {
operandValue = labelManager->GetLabel(_opAddr, true);
operandValue = labelManager->GetLabel(opAddr, true);
}
if(operandValue.empty()) {
if(_opSize == 2 && _opMode != AddrMode::Rel) {
operandValue += "$" + HexUtilities::ToHex((uint8_t)_opAddr);
operandValue += "$" + HexUtilities::ToHex((uint8_t)opAddr);
} else {
operandValue += "$" + HexUtilities::ToHex((uint16_t)_opAddr);
operandValue += "$" + HexUtilities::ToHex((uint16_t)opAddr);
}
}
@ -81,6 +73,22 @@ string DisassemblyInfo::ToString(uint32_t memoryAddr, shared_ptr<MemoryManager>
return out;
}
uint16_t DisassemblyInfo::GetOpAddr(uint16_t memoryAddr)
{
uint16_t opAddr;
if(_opSize == 2) {
opAddr = *(_opPointer + 1);
} else if(_opSize == 3) {
opAddr = *(_opPointer + 1) | (*(_opPointer + 2) << 8);
}
if(_opMode == AddrMode::Rel) {
opAddr = (int8_t)opAddr + memoryAddr + 2;
}
return opAddr;
}
DisassemblyInfo::DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint)
{
_opPointer = opPointer;

View File

@ -20,8 +20,6 @@ private:
uint32_t _opSize = 0;
AddrMode _opMode;
uint16_t _opAddr;
public:
DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint);
@ -33,6 +31,7 @@ public:
string ToString(uint32_t memoryAddr, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager);
string GetByteCode();
uint32_t GetSize();
uint16_t GetOpAddr(uint16_t memoryAddr);
bool IsSubEntryPoint();
bool IsSubExitPoint();

View File

@ -92,6 +92,8 @@ namespace Mesen.GUI.Config
public int WindowHeight = -1;
public int BottomPanelHeight = -1;
public bool HighlightUnexecutedCode = true;
public DebugInfo()
{
LeftView = new DebugViewInfo();

View File

@ -19,6 +19,7 @@ namespace Mesen.GUI.Debugger
public event WatchEventHandler OnWatchAdded;
public event AddressEventHandler OnSetNextStatement;
private DebugViewInfo _config;
HashSet<int> _unexecutedAddresses = new HashSet<int>();
private frmCodeTooltip _codeTooltip = null;
@ -82,9 +83,6 @@ namespace Mesen.GUI.Debugger
public void SetActiveAddress(UInt32 address)
{
//Set line background to yellow
this.ctrlCodeViewer.ClearLineStyles();
this.ctrlCodeViewer.SetLineColor((int)address, Color.Black, Color.Yellow, null, LineSymbol.Arrow);
_currentActiveAddress = address;
}
@ -93,15 +91,31 @@ namespace Mesen.GUI.Debugger
_currentActiveAddress = null;
}
public void UpdateLineColors()
{
this.ctrlCodeViewer.ClearLineStyles();
if(_currentActiveAddress.HasValue) {
this.ctrlCodeViewer.SetLineColor((int)_currentActiveAddress, Color.Black, Color.Yellow, null, LineSymbol.Arrow);
}
if(ConfigManager.Config.DebugInfo.HighlightUnexecutedCode) {
foreach(int relativeAddress in _unexecutedAddresses) {
this.ctrlCodeViewer.SetLineColor(relativeAddress, null, Color.FromArgb(183, 229, 190));
}
}
this.HighlightBreakpoints();
}
public bool UpdateCode(bool forceUpdate = false)
{
if(_codeChanged || forceUpdate) {
this.ctrlCodeViewer.ClearLineStyles();
List<int> lineNumbers = new List<int>();
List<string> lineNumberNotes = new List<string>();
List<string> codeNotes = new List<string>();
List<string> codeLines = new List<string>();
_unexecutedAddresses = new HashSet<int>();
int index = -1;
int previousIndex = -1;
@ -109,11 +123,17 @@ namespace Mesen.GUI.Debugger
string line = _code.Substring(previousIndex + 1, index - previousIndex - 1);
string[] lineParts = line.Split('\x1');
if(lineParts.Length >= 4) {
lineNumbers.Add(ParseHexAddress(lineParts[0]));
lineNumberNotes.Add(lineParts[1].Trim('0'));
codeNotes.Add(lineParts[2]);
codeLines.Add(lineParts[3]);
if(lineParts.Length >= 5) {
int relativeAddress = ParseHexAddress(lineParts[1]);
if(lineParts[0] == "0" && lineParts[4].StartsWith(" ")) {
_unexecutedAddresses.Add(relativeAddress);
}
lineNumbers.Add(relativeAddress);
lineNumberNotes.Add(lineParts[2].Trim('0'));
codeNotes.Add(lineParts[3]);
codeLines.Add(lineParts[4]);
}
previousIndex = index;
@ -123,9 +143,12 @@ namespace Mesen.GUI.Debugger
ctrlCodeViewer.LineNumbers = lineNumbers.ToArray();
ctrlCodeViewer.TextLineNotes = codeNotes.ToArray();
ctrlCodeViewer.LineNumberNotes = lineNumberNotes.ToArray();
_codeChanged = false;
UpdateLineColors();
return true;
}
UpdateLineColors();
return false;
}
@ -140,10 +163,6 @@ namespace Mesen.GUI.Debugger
public void HighlightBreakpoints()
{
ctrlCodeViewer.ClearLineStyles();
if(_currentActiveAddress.HasValue) {
SetActiveAddress(_currentActiveAddress.Value);
}
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
Color? fgColor = Color.White;
Color? bgColor = null;
@ -156,10 +175,14 @@ namespace Mesen.GUI.Debugger
fgColor = Color.Black;
symbol = LineSymbol.CircleOutline;
}
if(breakpoint.Address == (UInt32)(_currentActiveAddress.HasValue ? (int)_currentActiveAddress.Value : -1)) {
fgColor = Color.Black;
bgColor = Color.Yellow;
symbol |= LineSymbol.Arrow;
} else if(_unexecutedAddresses.Contains((Int32)breakpoint.Address)) {
fgColor = Color.Black;
bgColor = Color.FromArgb(183, 229, 190);
}
ctrlCodeViewer.SetLineColor((int)breakpoint.Address, fgColor, bgColor, outlineColor, symbol);

View File

@ -99,6 +99,7 @@
this.mnuPpuPartialDraw = new System.Windows.Forms.ToolStripMenuItem();
this.mnuShowEffectiveAddresses = new System.Windows.Forms.ToolStripMenuItem();
this.mnuShowOnlyDisassembledCode = new System.Windows.Forms.ToolStripMenuItem();
this.mnuHighlightUnexecutedCode = new System.Windows.Forms.ToolStripMenuItem();
this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPpuViewer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMemoryViewer = new System.Windows.Forms.ToolStripMenuItem();
@ -119,6 +120,7 @@
this.lblChrAnalysisResult = new System.Windows.Forms.ToolStripStatusLabel();
this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping();
this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
this.contextMenuCode.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout();
@ -420,40 +422,43 @@
this.mnuSaveWorkspace,
this.mnuResetWorkspace});
this.mnuWorkspace.Name = "mnuWorkspace";
this.mnuWorkspace.Size = new System.Drawing.Size(132, 22);
this.mnuWorkspace.Size = new System.Drawing.Size(152, 22);
this.mnuWorkspace.Text = "Workspace";
//
// mnuImportLabels
//
this.mnuImportLabels.Image = global::Mesen.GUI.Properties.Resources.Import;
this.mnuImportLabels.Name = "mnuImportLabels";
this.mnuImportLabels.Size = new System.Drawing.Size(146, 22);
this.mnuImportLabels.Size = new System.Drawing.Size(152, 22);
this.mnuImportLabels.Text = "Import Labels";
this.mnuImportLabels.Click += new System.EventHandler(this.mnuImportLabels_Click);
//
// mnuSaveWorkspace
//
this.mnuSaveWorkspace.Image = global::Mesen.GUI.Properties.Resources.Floppy;
this.mnuSaveWorkspace.Name = "mnuSaveWorkspace";
this.mnuSaveWorkspace.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S)));
this.mnuSaveWorkspace.Size = new System.Drawing.Size(146, 22);
this.mnuSaveWorkspace.Size = new System.Drawing.Size(152, 22);
this.mnuSaveWorkspace.Text = "Save";
this.mnuSaveWorkspace.Click += new System.EventHandler(this.mnuSaveWorkspace_Click);
//
// mnuResetWorkspace
//
this.mnuResetWorkspace.Image = global::Mesen.GUI.Properties.Resources.Reset;
this.mnuResetWorkspace.Name = "mnuResetWorkspace";
this.mnuResetWorkspace.Size = new System.Drawing.Size(146, 22);
this.mnuResetWorkspace.Size = new System.Drawing.Size(152, 22);
this.mnuResetWorkspace.Text = "Reset";
this.mnuResetWorkspace.Click += new System.EventHandler(this.mnuResetWorkspace_Click);
//
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(129, 6);
this.toolStripMenuItem3.Size = new System.Drawing.Size(149, 6);
//
// mnuClose
//
this.mnuClose.Name = "mnuClose";
this.mnuClose.Size = new System.Drawing.Size(132, 22);
this.mnuClose.Size = new System.Drawing.Size(152, 22);
this.mnuClose.Text = "Close";
this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
//
@ -478,6 +483,7 @@
//
// mnuContinue
//
this.mnuContinue.Image = global::Mesen.GUI.Properties.Resources.Play;
this.mnuContinue.Name = "mnuContinue";
this.mnuContinue.ShortcutKeys = System.Windows.Forms.Keys.F5;
this.mnuContinue.Size = new System.Drawing.Size(258, 22);
@ -486,6 +492,7 @@
//
// mnuBreak
//
this.mnuBreak.Image = global::Mesen.GUI.Properties.Resources.Pause;
this.mnuBreak.Name = "mnuBreak";
this.mnuBreak.ShortcutKeyDisplayString = "Ctrl+Alt+Break";
this.mnuBreak.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt)
@ -653,9 +660,11 @@
this.mnuShowPpuMemoryMapping,
this.mnuShowFunctionLabelLists,
this.toolStripMenuItem6,
this.mnuPpuPartialDraw,
this.mnuHighlightUnexecutedCode,
this.mnuShowEffectiveAddresses,
this.mnuShowOnlyDisassembledCode});
this.mnuShowOnlyDisassembledCode,
this.toolStripMenuItem7,
this.mnuPpuPartialDraw});
this.mnuOptions.Name = "mnuOptions";
this.mnuOptions.Size = new System.Drawing.Size(61, 20);
this.mnuOptions.Text = "Options";
@ -763,6 +772,14 @@
this.mnuShowOnlyDisassembledCode.Text = "Show Only Disassembled Code";
this.mnuShowOnlyDisassembledCode.CheckedChanged += new System.EventHandler(this.mnuShowOnlyDisassembledCode_CheckedChanged);
//
// mnuHighlightUnexecutedCode
//
this.mnuHighlightUnexecutedCode.CheckOnClick = true;
this.mnuHighlightUnexecutedCode.Name = "mnuHighlightUnexecutedCode";
this.mnuHighlightUnexecutedCode.Size = new System.Drawing.Size(237, 22);
this.mnuHighlightUnexecutedCode.Text = "Highlight Unexecuted Code";
this.mnuHighlightUnexecutedCode.Click += new System.EventHandler(this.mnuHighlightUnexecutedCode_Click);
//
// toolsToolStripMenuItem
//
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -925,6 +942,11 @@
this.ctrlCpuMemoryMapping.Text = "ctrlMemoryMapping1";
this.ctrlCpuMemoryMapping.Visible = false;
//
// toolStripMenuItem7
//
this.toolStripMenuItem7.Name = "toolStripMenuItem7";
this.toolStripMenuItem7.Size = new System.Drawing.Size(234, 6);
//
// frmDebugger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1052,5 +1074,7 @@
private System.Windows.Forms.ToolStripMenuItem mnuSaveWorkspace;
private System.Windows.Forms.ToolStripMenuItem mnuResetWorkspace;
private System.Windows.Forms.ToolStripMenuItem mnuImportLabels;
private System.Windows.Forms.ToolStripMenuItem mnuHighlightUnexecutedCode;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7;
}
}

View File

@ -17,10 +17,11 @@ namespace Mesen.GUI.Debugger
public partial class frmDebugger : BaseForm
{
private List<Form> _childForms = new List<Form>();
private bool _debuggerInitialized = false;
private InteropEmu.NotificationListener _notifListener;
private ctrlDebuggerCode _lastCodeWindow;
private frmTraceLogger _traceLogger;
private DebugWorkspace _workspace;
public frmDebugger()
@ -45,6 +46,7 @@ namespace Mesen.GUI.Debugger
this.mnuShowPpuMemoryMapping.Checked = ConfigManager.Config.DebugInfo.ShowPpuMemoryMapping;
this.mnuShowOnlyDisassembledCode.Checked = ConfigManager.Config.DebugInfo.ShowOnlyDisassembledCode;
this.mnuShowFunctionLabelLists.Checked = ConfigManager.Config.DebugInfo.ShowFunctionLabelLists;
this.mnuHighlightUnexecutedCode.Checked = ConfigManager.Config.DebugInfo.HighlightUnexecutedCode;
this.Width = ConfigManager.Config.DebugInfo.WindowWidth;
this.Height = ConfigManager.Config.DebugInfo.WindowHeight;
@ -80,8 +82,9 @@ namespace Mesen.GUI.Debugger
_notifListener.OnNotification += _notifListener_OnNotification;
InteropEmu.DebugInitialize();
//Pause a few frames later to give the debugger a chance to disassemble some code
_debuggerInitialized = true;
InteropEmu.DebugStep(30000);
UpdateCdlRatios();
@ -199,6 +202,10 @@ namespace Mesen.GUI.Debugger
string _previousCode = string.Empty;
private void UpdateDebugger(bool updateActiveAddress = true)
{
if(!_debuggerInitialized) {
return;
}
ctrlLabelList.UpdateLabelListAddresses();
ctrlFunctionList.UpdateFunctionList(false);
UpdateDebuggerFlags();
@ -226,7 +233,7 @@ namespace Mesen.GUI.Debugger
_lastCodeWindow.SelectActiveAddress(state.CPU.DebugPC);
}
RefreshBreakpoints();
UpdateLineColors();
ctrlConsoleStatus.UpdateStatus(ref state);
ctrlWatch.UpdateWatch();
@ -242,7 +249,7 @@ namespace Mesen.GUI.Debugger
{
ctrlDebuggerCode.ClearActiveAddress();
ctrlDebuggerCodeSplit.ClearActiveAddress();
RefreshBreakpoints();
UpdateLineColors();
}
private void ToggleBreakpoint(bool toggleEnabled)
@ -250,10 +257,10 @@ namespace Mesen.GUI.Debugger
BreakpointManager.ToggleBreakpoint(_lastCodeWindow.GetCurrentLine(), toggleEnabled);
}
private void RefreshBreakpoints()
private void UpdateLineColors()
{
ctrlDebuggerCodeSplit.HighlightBreakpoints();
ctrlDebuggerCode.HighlightBreakpoints();
ctrlDebuggerCodeSplit.UpdateLineColors();
ctrlDebuggerCode.UpdateLineColors();
}
private void OpenChildForm(Form frm)
@ -364,7 +371,7 @@ namespace Mesen.GUI.Debugger
private void BreakpointManager_BreakpointsChanged(object sender, EventArgs e)
{
RefreshBreakpoints();
UpdateLineColors();
}
private void ctrlDebuggerCode_Enter(object sender, EventArgs e)
@ -547,6 +554,14 @@ namespace Mesen.GUI.Debugger
ConfigManager.ApplyChanges();
}
private void mnuHighlightUnexecutedCode_Click(object sender, EventArgs e)
{
ConfigManager.Config.DebugInfo.HighlightUnexecutedCode = mnuHighlightUnexecutedCode.Checked;
ConfigManager.ApplyChanges();
ctrlDebuggerCode.UpdateLineColors();
ctrlDebuggerCodeSplit.UpdateLineColors();
}
private void frmDebugger_Resize(object sender, EventArgs e)
{
ctrlCpuMemoryMapping.Invalidate();