1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7 using Mesen.GUI.Config;
8 
9 namespace Mesen.GUI.Debugger
10 {
11 	public class DebugWorkspaceManager
12 	{
13 		private static DebugWorkspace _workspace;
14 		private static Ld65DbgImporter _symbolProvider;
15 		private static string _romName;
16 		private static object _lock = new object();
17 
SymbolProviderChangedHandler(Ld65DbgImporter provider)18 		public delegate void SymbolProviderChangedHandler(Ld65DbgImporter provider);
19 		public static event SymbolProviderChangedHandler SymbolProviderChanged;
20 
21 		public static Ld65DbgImporter SymbolProvider
22 		{
23 			get { return _symbolProvider; }
24 			private set
25 			{
26 				if(_symbolProvider != value) {
27 					_symbolProvider = value;
28 					SymbolProviderChanged?.Invoke(value);
29 				}
30 			}
31 		}
32 
SaveWorkspace()33 		public static void SaveWorkspace()
34 		{
35 			if(_workspace != null) {
36 				lock(_lock) {
37 					if(_workspace != null) {
38 						_workspace.WatchValues = new List<string>(WatchManager.WatchEntries);
39 						_workspace.Labels = new List<CodeLabel>(LabelManager.GetLabels());
40 						_workspace.Breakpoints = new List<Breakpoint>(BreakpointManager.Breakpoints);
41 						_workspace.Save();
42 					}
43 				}
44 			}
45 		}
46 
Clear()47 		public static void Clear()
48 		{
49 			lock(_lock) {
50 				_workspace = null;
51 				_romName = null;
52 				SymbolProvider = null;
53 			}
54 		}
55 
ResetWorkspace()56 		public static void ResetWorkspace()
57 		{
58 			if(_workspace != null) {
59 				lock(_lock) {
60 					if(_workspace != null) {
61 						_workspace.Breakpoints = new List<Breakpoint>();
62 						_workspace.Labels = new List<CodeLabel>();
63 						_workspace.WatchValues = new List<string>();
64 						LabelManager.ResetLabels();
65 						WatchManager.WatchEntries = _workspace.WatchValues;
66 						BreakpointManager.SetBreakpoints(_workspace.Breakpoints);
67 						_workspace.Save();
68 						Clear();
69 					}
70 				}
71 			}
72 		}
73 
GetWorkspace()74 		public static DebugWorkspace GetWorkspace()
75 		{
76 			string romName = InteropEmu.GetRomInfo().GetRomName();
77 			if(_workspace == null || _romName != romName) {
78 				SymbolProvider = null;
79 				lock(_lock) {
80 					if(_workspace == null || _romName != romName) {
81 						if(_workspace != null) {
82 							SaveWorkspace();
83 						}
84 						_romName = InteropEmu.GetRomInfo().GetRomName();
85 						_workspace = DebugWorkspace.GetWorkspace();
86 
87 						//Load watch entries
88 						WatchManager.WatchEntries = _workspace.WatchValues;
89 
90 						//Load breakpoints
91 						BreakpointManager.SetBreakpoints(_workspace.Breakpoints);
92 
93 						//Setup labels
94 						if(_workspace.Labels.Count == 0) {
95 							LabelManager.ResetLabels();
96 							if(!ConfigManager.Config.DebugInfo.DisableDefaultLabels) {
97 								LabelManager.SetDefaultLabels(InteropEmu.GetRomInfo().MapperId);
98 							}
99 						} else {
100 							LabelManager.ResetLabels();
101 							LabelManager.SetLabels(_workspace.Labels, true);
102 						}
103 					}
104 				}
105 			}
106 			return _workspace;
107 		}
108 
109 		private static DebuggerFlags _flags = DebuggerFlags.None;
SetFlags(DebuggerFlags flags)110 		public static void SetFlags(DebuggerFlags flags)
111 		{
112 			_flags |= flags;
113 			InteropEmu.DebugSetFlags(_flags);
114 		}
115 
ClearFlags(DebuggerFlags flags = DebuggerFlags.None)116 		public static void ClearFlags(DebuggerFlags flags = DebuggerFlags.None)
117 		{
118 			if(flags == DebuggerFlags.None) {
119 				_flags = DebuggerFlags.None;
120 			} else {
121 				_flags &= ~flags;
122 			}
123 			InteropEmu.DebugSetFlags(_flags);
124 		}
125 
ResetLabels()126 		public static void ResetLabels()
127 		{
128 			LabelManager.ResetLabels();
129 			if(!ConfigManager.Config.DebugInfo.DisableDefaultLabels) {
130 				LabelManager.SetDefaultLabels(InteropEmu.GetRomInfo().MapperId);
131 			}
132 			SaveWorkspace();
133 			GetWorkspace();
134 		}
135 
AutoLoadDbgFiles(bool silent)136 		public static void AutoLoadDbgFiles(bool silent)
137 		{
138 			if(ConfigManager.Config.DebugInfo.AutoLoadDbgFiles) {
139 				RomInfo info = InteropEmu.GetRomInfo();
140 				string dbgPath = Path.Combine(info.RomFile.Folder, info.GetRomName() + ".dbg");
141 				if(File.Exists(dbgPath)) {
142 					DateTime lastDbgUpdate = File.GetLastWriteTime(dbgPath);
143 					if(lastDbgUpdate != SymbolProvider?.DbgFileStamp) {
144 						ImportDbgFile(dbgPath, silent);
145 					} else {
146 						//Currently loaded symbol provider is still valid
147 						return;
148 					}
149 				} else {
150 					string mlbPath = Path.Combine(info.RomFile.Folder, info.GetRomName() + ".mlb");
151 					if(File.Exists(mlbPath)) {
152 						ImportMlbFile(mlbPath, silent);
153 					} else {
154 						string fnsPath = Path.Combine(info.RomFile.Folder, info.GetRomName() + ".fns");
155 						if(File.Exists(fnsPath)) {
156 							ImportNesasmFnsFile(fnsPath, silent);
157 						}
158 					}
159 				}
160 			}
161 		}
162 
ImportNesasmFnsFile(string fnsPath, bool silent = false)163 		public static void ImportNesasmFnsFile(string fnsPath, bool silent = false)
164 		{
165 			if(ConfigManager.Config.DebugInfo.ImportConfig.ResetLabelsOnImport) {
166 				ResetLabels();
167 			}
168 			NesasmFnsImporter.Import(fnsPath, silent);
169 		}
170 
ImportMlbFile(string mlbPath, bool silent = false)171 		public static void ImportMlbFile(string mlbPath, bool silent = false)
172 		{
173 			if(ConfigManager.Config.DebugInfo.ImportConfig.ResetLabelsOnImport) {
174 				ResetLabels();
175 			}
176 			MesenLabelFile.Import(mlbPath, silent);
177 		}
178 
ImportDbgFile(string dbgPath, bool silent)179 		public static void ImportDbgFile(string dbgPath, bool silent)
180 		{
181 			if(ConfigManager.Config.DebugInfo.ImportConfig.ResetLabelsOnImport) {
182 				ResetLabels();
183 			}
184 
185 			Ld65DbgImporter dbgImporter = new Ld65DbgImporter();
186 			dbgImporter.Import(dbgPath, silent);
187 
188 			DebugWorkspaceManager.SymbolProvider = dbgImporter;
189 		}
190 	}
191 }
192