Debugger: Add support for assert expressions
This commit is contained in:
parent
e4441b5237
commit
479e91c5f2
5 changed files with 109 additions and 11 deletions
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue