Debugger: Add support for assert expressions

This commit is contained in:
Sour 2020-04-26 22:32:17 -04:00
parent e4441b5237
commit 479e91c5f2
5 changed files with 109 additions and 11 deletions

View file

@ -21,6 +21,7 @@ namespace Mesen.GUI.Debugger
public CpuType CpuType;
public BreakpointAddressType AddressType = BreakpointAddressType.SingleAddress;
public string Condition = "";
public bool IsAssert = false;
public SnesMemoryType MemoryType
{

View file

@ -18,6 +18,8 @@ namespace Mesen.GUI.Debugger
get { return _breakpoints.ToList().AsReadOnly(); }
}
public static List<Breakpoint> Asserts { internal get; set; }
public static void AddCpuType(CpuType cpuType)
{
_activeCpuTypes.Add(cpuType);
@ -121,20 +123,34 @@ namespace Mesen.GUI.Debugger
public static void SetBreakpoints()
{
List<InteropBreakpoint> breakpoints = new List<InteropBreakpoint>();
for(int i = 0; i < Breakpoints.Count; i++) {
if(_activeCpuTypes.Contains(Breakpoints[i].CpuType)) {
breakpoints.Add(Breakpoints[i].ToInteropBreakpoint(i));
ReadOnlyCollection<Breakpoint> userBreakpoints = BreakpointManager.Breakpoints;
for(int i = 0; i < userBreakpoints.Count; i++) {
if(_activeCpuTypes.Contains(userBreakpoints[i].CpuType)) {
breakpoints.Add(userBreakpoints[i].ToInteropBreakpoint(breakpoints.Count));
}
}
List<Breakpoint> assertBreakpoints = BreakpointManager.Asserts;
for(int i = 0; i < assertBreakpoints.Count; i++) {
if(_activeCpuTypes.Contains(assertBreakpoints[i].CpuType)) {
breakpoints.Add(assertBreakpoints[i].ToInteropBreakpoint(breakpoints.Count));
}
}
DebugApi.SetBreakpoints(breakpoints.ToArray(), (UInt32)breakpoints.Count);
}
public static Breakpoint GetBreakpointById(int breakpointId)
{
if(breakpointId < 0 || breakpointId >= _breakpoints.Count) {
if(breakpointId < 0) {
return null;
} else if(breakpointId < _breakpoints.Count) {
return _breakpoints[breakpointId];
} else if(breakpointId < _breakpoints.Count + Asserts.Count) {
return Asserts[breakpointId - _breakpoints.Count];
}
return _breakpoints[breakpointId];
return null;
}
}
}

View file

@ -596,6 +596,7 @@ namespace Mesen.GUI.Debugger.Integration
private void LoadComments()
{
DbgIntegrationConfig config = ConfigManager.Config.Debug.DbgIntegration;
SortedDictionary<string, int> constants = GetConstants();
foreach(KeyValuePair<int, LineInfo> kvp in _lines) {
try {
LineInfo line = kvp.Value;
@ -668,7 +669,7 @@ namespace Mesen.GUI.Debugger.Integration
if(address >= 0 && memoryType != null) {
CodeLabel label = this.CreateLabel(address, memoryType.Value, 1);
if(label != null) {
label.Comment = comment;
label.Comment = ParseAsserts(constants, comment);
}
}
}
@ -678,6 +679,42 @@ namespace Mesen.GUI.Debugger.Integration
}
}
private string[] _splitOnNewLine = { Environment.NewLine };
private string ParseAsserts(SortedDictionary<string, int> constants, string comment)
{
//Parse and replace content of asserts as needed
string[] commentLines = comment.Split(_splitOnNewLine, StringSplitOptions.None);
for(int i = 0; i < commentLines.Length; i++) {
Match m = LabelManager.AssertRegex.Match(commentLines[i]);
if(m.Success) {
foreach(KeyValuePair<string, int> entry in constants) {
commentLines[i] = commentLines[i].Replace(entry.Key, entry.Value.ToString());
}
}
}
return string.Join(Environment.NewLine, commentLines);
}
private SortedDictionary<string, int> GetConstants()
{
SortedDictionary<string, int> constants = new SortedDictionary<string, int>(Comparer<string>.Create((string a, string b) => {
if(a.Length == b.Length) {
return a.CompareTo(b);
}
return b.Length - a.Length;
}));
foreach(SymbolInfo symbol in _symbols.Values) {
AddressInfo? addressInfo = GetSymbolAddressInfo(symbol);
if(!addressInfo.HasValue && symbol.Address.HasValue) {
constants[symbol.Name] = symbol.Address.Value;
}
}
return constants;
}
private void LoadFileData(string path)
{
Dictionary<int, int> maxLineCountByFile = new Dictionary<int, int>();

View file

@ -12,6 +12,7 @@ namespace Mesen.GUI.Debugger.Labels
public class LabelManager
{
public static Regex LabelRegex { get; } = new Regex("^[@_a-zA-Z]+[@_a-zA-Z0-9]*$", RegexOptions.Compiled);
public static Regex AssertRegex { get; } = new Regex(@"assert\((.*)\)", RegexOptions.Compiled);
private static Dictionary<UInt64, CodeLabel> _labelsByKey = new Dictionary<UInt64, CodeLabel>();
private static HashSet<CodeLabel> _labels = new HashSet<CodeLabel>();
@ -54,7 +55,7 @@ namespace Mesen.GUI.Debugger.Labels
SetLabel(label, false);
}
if(raiseEvents) {
OnLabelUpdated?.Invoke(null, null);
ProcessLabelUpdate();
}
}
@ -135,7 +136,7 @@ namespace Mesen.GUI.Debugger.Labels
}
if(raiseEvent) {
OnLabelUpdated?.Invoke(null, null);
ProcessLabelUpdate();
RefreshDisassembly(label);
}
@ -162,7 +163,7 @@ namespace Mesen.GUI.Debugger.Labels
}
if(needEvent) {
OnLabelUpdated?.Invoke(null, null);
ProcessLabelUpdate();
RefreshDisassembly(label);
}
}
@ -200,6 +201,44 @@ namespace Mesen.GUI.Debugger.Labels
LabelManager.SetLabels(new List<CodeLabel>(_labels), true);
}
private static void ProcessLabelUpdate()
{
OnLabelUpdated?.Invoke(null, null);
UpdateAssertBreakpoints();
}
private static void UpdateAssertBreakpoints()
{
List<Breakpoint> asserts = new List<Breakpoint>();
Action<CodeLabel, string, CpuType> addAssert = (CodeLabel label, string condition, CpuType cpuType) => {
asserts.Add(new Breakpoint() {
BreakOnExec = true,
MemoryType = label.MemoryType,
CpuType = cpuType,
Address = label.Address,
Condition = "!(" + condition + ")",
IsAssert = true
});
};
foreach(CodeLabel label in _labels) {
foreach(string commentLine in label.Comment.Split('\n')) {
Match m = LabelManager.AssertRegex.Match(commentLine);
if(m.Success) {
CpuType cpuType = label.MemoryType.ToCpuType();
addAssert(label, m.Groups[1].Value, cpuType);
if(cpuType == CpuType.Cpu) {
addAssert(label, m.Groups[1].Value, CpuType.Sa1);
}
}
}
}
BreakpointManager.Asserts = asserts;
BreakpointManager.SetBreakpoints();
}
public static void SetDefaultLabels()
{
//B-Bus registers

View file

@ -476,8 +476,9 @@ namespace Mesen.GUI.Debugger
void ProcessBreakEvent(BreakEvent evt, DebugState state, int activeAddress)
{
Breakpoint bp = null;
if(ConfigManager.Config.Debug.Debugger.BringToFrontOnBreak) {
Breakpoint bp = BreakpointManager.GetBreakpointById(evt.BreakpointId);
bp = BreakpointManager.GetBreakpointById(evt.BreakpointId);
if(bp?.CpuType == _cpuType || evt.Source > BreakSource.PpuStep) {
DebugWindowManager.BringToFront(this);
}
@ -489,7 +490,11 @@ namespace Mesen.GUI.Debugger
if(evt.Source == BreakSource.Breakpoint || evt.Source > BreakSource.PpuStep) {
string message = ResourceHelper.GetEnumText(evt.Source);
if(evt.Source == BreakSource.Breakpoint) {
message += ": " + ResourceHelper.GetEnumText(evt.Operation.Type) + " ($" + evt.Operation.Address.ToString("X4") + ":$" + evt.Operation.Value.ToString("X2") + ")";
if(bp != null && bp.IsAssert) {
message = "Assert failed: " + bp.Condition.Substring(2, bp.Condition.Length - 3);
} else {
message += ": " + ResourceHelper.GetEnumText(evt.Operation.Type) + " ($" + evt.Operation.Address.ToString("X4") + ":$" + evt.Operation.Value.ToString("X2") + ")";
}
}
ctrlDisassemblyView.SetMessage(new TextboxMessageInfo() { Message = message });
}