1 #include "QtDebugger.h"
2 #include "ui_QtDebugger.h"
3 
4 #include <QApplication>
5 #include <QInputDialog>
6 #include <QMessageBox>
7 
8 #include <iostream>
9 #include "AppConfig.h"
10 #include "MIPSAssembler.h"
11 #include "Ps2Const.h"
12 #include "ee/PS2OS.h"
13 #include "MipsFunctionPatternDb.h"
14 #include "StdStream.h"
15 #include "StdStreamUtils.h"
16 #include "xml/Parser.h"
17 #include "xml/Utils.h"
18 #include "string_cast.h"
19 #include "string_format.h"
20 #include "PathUtils.h"
21 
22 #define PREF_DEBUGGER_MEMORYVIEW_BYTEWIDTH "debugger.memoryview.bytewidth"
23 
24 #define FIND_MAX_ADDRESS 0x02000000
25 
QtDebugger(CPS2VM & virtualMachine)26 QtDebugger::QtDebugger(CPS2VM& virtualMachine)
27     : ui(new Ui::QtDebugger)
28     , m_virtualMachine(virtualMachine)
29 {
30 	ui->setupUi(this);
31 
32 	// Setup QT Stuff
33 	RegisterPreferences();
34 
35 	//ELF View Initialization
36 	m_pELFView = new CELFView(ui->mdiArea);
37 
38 	//Functions View Initialization
39 	m_pFunctionsView = new CFunctionsView(ui->mdiArea);
40 	m_pFunctionsView->hide();
41 	m_OnFunctionDblClickConnection = m_pFunctionsView->OnFunctionDblClick.Connect(std::bind(&QtDebugger::OnFunctionsViewFunctionDblClick, this, std::placeholders::_1));
42 	m_OnFunctionsStateChangeConnection = m_pFunctionsView->OnFunctionsStateChange.Connect(std::bind(&QtDebugger::OnFunctionsViewFunctionsStateChange, this));
43 
44 	//Threads View Initialization
45 	auto threadsView = new CThreadsViewWnd(ui->mdiArea);
46 	m_threadsView = new QMdiSubWindow(ui->mdiArea);
47 	m_threadsView->setWidget(threadsView);
48 	m_threadsView->setWindowTitle("Threads");
49 
50 	m_threadsView->hide();
51 	m_OnGotoAddressConnection = threadsView->OnGotoAddress.Connect(std::bind(&QtDebugger::OnThreadsViewAddressDblClick, this, std::placeholders::_1));
52 
53 	//Address List View Initialization
54 	m_addressListView = new CAddressListViewWnd(ui->mdiArea);
55 	m_addressListView->hide();
56 	m_AddressSelectedConnection = m_addressListView->AddressSelected.Connect([&](uint32 address) { OnFindCallersAddressDblClick(address); });
57 
58 	//Debug Views Initialization
59 	m_nCurrentView = -1;
60 
61 	m_pView[DEBUGVIEW_EE] = new CDebugView(this, ui->mdiArea, m_virtualMachine, &m_virtualMachine.m_ee->m_EE,
62 	                                       std::bind(&CPS2VM::StepEe, &m_virtualMachine), m_virtualMachine.m_ee->m_os, "EmotionEngine", PS2::EE_RAM_SIZE + PS2::EE_BIOS_SIZE);
63 	m_pView[DEBUGVIEW_VU0] = new CDebugView(this, ui->mdiArea, m_virtualMachine, &m_virtualMachine.m_ee->m_VU0,
64 	                                        std::bind(&CPS2VM::StepVu0, &m_virtualMachine), nullptr, "Vector Unit 0", PS2::VUMEM0SIZE, CQtDisAsmTableModel::DISASM_VU);
65 	m_pView[DEBUGVIEW_VU1] = new CDebugView(this, ui->mdiArea, m_virtualMachine, &m_virtualMachine.m_ee->m_VU1,
66 	                                        std::bind(&CPS2VM::StepVu1, &m_virtualMachine), nullptr, "Vector Unit 1", PS2::VUMEM1SIZE, CQtDisAsmTableModel::DISASM_VU);
67 	m_pView[DEBUGVIEW_IOP] = new CDebugView(this, ui->mdiArea, m_virtualMachine, &m_virtualMachine.m_iop->m_cpu,
68 	                                        std::bind(&CPS2VM::StepIop, &m_virtualMachine), m_virtualMachine.m_iop->m_bios.get(), "IO Processor", PS2::IOP_RAM_SIZE);
69 
70 	m_OnExecutableChangeConnection = m_virtualMachine.m_ee->m_os->OnExecutableChange.Connect(std::bind(&QtDebugger::OnExecutableChange, this));
71 	m_OnExecutableUnloadingConnection = m_virtualMachine.m_ee->m_os->OnExecutableUnloading.Connect(std::bind(&QtDebugger::OnExecutableUnloading, this));
72 
73 	m_OnMachineStateChangeConnection = m_virtualMachine.OnMachineStateChange.Connect(std::bind(&QtDebugger::OnMachineStateChange, this));
74 	m_OnRunningStateChangeConnection = m_virtualMachine.OnRunningStateChange.Connect(std::bind(&QtDebugger::OnRunningStateChange, this));
75 
76 	ActivateView(DEBUGVIEW_EE);
77 	LoadSettings();
78 
79 	if(GetDisassemblyWindow()->isVisible())
80 	{
81 		GetDisassemblyWindow()->setFocus(Qt::ActiveWindowFocusReason);
82 	}
83 
84 	connect(this, &QtDebugger::OnMachineStateChange, this, &QtDebugger::OnMachineStateChangeMsg);
85 	connect(this, &QtDebugger::OnRunningStateChange, this, &QtDebugger::OnRunningStateChangeMsg);
86 	connect(this, &QtDebugger::OnExecutableChange, this, &QtDebugger::OnExecutableChangeMsg);
87 	connect(this, &QtDebugger::OnExecutableUnloading, this, &QtDebugger::OnExecutableUnloadingMsg);
88 }
89 
~QtDebugger()90 QtDebugger::~QtDebugger()
91 {
92 	delete ui;
93 
94 	OnExecutableUnloading();
95 
96 	for(unsigned int i = 0; i < DEBUGVIEW_MAX; i++)
97 	{
98 		delete m_pView[i];
99 	}
100 
101 	delete m_pELFView;
102 	delete m_pFunctionsView;
103 }
104 
closeEvent(QCloseEvent * event)105 void QtDebugger::closeEvent(QCloseEvent* event)
106 {
107 	if(isVisible())
108 		SaveSettings();
109 
110 	event->accept();
111 }
112 
RegisterPreferences()113 void QtDebugger::RegisterPreferences()
114 {
115 	CAppConfig& config(CAppConfig::GetInstance());
116 
117 	config.RegisterPreferenceInteger("debugger.disasm.posx", 0);
118 	config.RegisterPreferenceInteger("debugger.disasm.posy", 0);
119 	config.RegisterPreferenceInteger("debugger.disasm.sizex", 0);
120 	config.RegisterPreferenceInteger("debugger.disasm.sizey", 0);
121 	config.RegisterPreferenceBoolean("debugger.disasm.visible", true);
122 
123 	config.RegisterPreferenceInteger("debugger.regview.posx", 0);
124 	config.RegisterPreferenceInteger("debugger.regview.posy", 0);
125 	config.RegisterPreferenceInteger("debugger.regview.sizex", 0);
126 	config.RegisterPreferenceInteger("debugger.regview.sizey", 0);
127 	config.RegisterPreferenceBoolean("debugger.regview.visible", true);
128 
129 	config.RegisterPreferenceInteger("debugger.memoryview.posx", 0);
130 	config.RegisterPreferenceInteger("debugger.memoryview.posy", 0);
131 	config.RegisterPreferenceInteger("debugger.memoryview.sizex", 0);
132 	config.RegisterPreferenceInteger("debugger.memoryview.sizey", 0);
133 	config.RegisterPreferenceBoolean("debugger.memoryview.visible", true);
134 	config.RegisterPreferenceInteger(PREF_DEBUGGER_MEMORYVIEW_BYTEWIDTH, 0);
135 
136 	config.RegisterPreferenceInteger("debugger.callstack.posx", 0);
137 	config.RegisterPreferenceInteger("debugger.callstack.posy", 0);
138 	config.RegisterPreferenceInteger("debugger.callstack.sizex", 0);
139 	config.RegisterPreferenceInteger("debugger.callstack.sizey", 0);
140 	config.RegisterPreferenceBoolean("debugger.callstack.visible", true);
141 }
142 
UpdateTitle()143 void QtDebugger::UpdateTitle()
144 {
145 	std::string sTitle("Play! - Debugger");
146 
147 	if(GetCurrentView() != NULL)
148 	{
149 		sTitle += (" - [ ");
150 		sTitle += GetCurrentView()->GetName();
151 		sTitle += (" ]");
152 	}
153 
154 	setWindowTitle(sTitle.c_str());
155 }
156 
LoadSettings()157 void QtDebugger::LoadSettings()
158 {
159 	LoadViewLayout();
160 	LoadBytesPerLine();
161 }
162 
SaveSettings()163 void QtDebugger::SaveSettings()
164 {
165 	SaveViewLayout();
166 	SaveBytesPerLine();
167 }
168 
SerializeWindowGeometry(QWidget * pWindow,const char * sPosX,const char * sPosY,const char * sSizeX,const char * sSizeY,const char * sVisible)169 void QtDebugger::SerializeWindowGeometry(QWidget* pWindow, const char* sPosX, const char* sPosY, const char* sSizeX, const char* sSizeY, const char* sVisible)
170 {
171 	CAppConfig& config(CAppConfig::GetInstance());
172 
173 	auto geometry = pWindow->geometry();
174 
175 	config.SetPreferenceInteger(sPosX, geometry.x());
176 	config.SetPreferenceInteger(sPosY, geometry.y());
177 
178 	config.SetPreferenceInteger(sSizeX, geometry.width());
179 	config.SetPreferenceInteger(sSizeY, geometry.height());
180 
181 	config.SetPreferenceBoolean(sVisible, pWindow->isVisible());
182 }
183 
UnserializeWindowGeometry(QWidget * pWindow,const char * sPosX,const char * sPosY,const char * sSizeX,const char * sSizeY,const char * sVisible)184 void QtDebugger::UnserializeWindowGeometry(QWidget* pWindow, const char* sPosX, const char* sPosY, const char* sSizeX, const char* sSizeY, const char* sVisible)
185 {
186 	CAppConfig& config(CAppConfig::GetInstance());
187 
188 	pWindow->setGeometry(config.GetPreferenceInteger(sPosX), config.GetPreferenceInteger(sPosY),
189 	                     config.GetPreferenceInteger(sSizeX), config.GetPreferenceInteger(sSizeY));
190 
191 	if(!config.GetPreferenceBoolean(sVisible))
192 	{
193 		pWindow->hide();
194 	}
195 	else
196 	{
197 		pWindow->show();
198 	}
199 }
200 
Resume()201 void QtDebugger::Resume()
202 {
203 	m_virtualMachine.Resume();
204 }
205 
StepCPU()206 void QtDebugger::StepCPU()
207 {
208 	if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
209 	{
210 		QApplication::beep();
211 		return;
212 	}
213 
214 	if(!GetDisassemblyWindow()->hasFocus())
215 	{
216 		GetDisassemblyWindow()->setFocus(Qt::ActiveWindowFocusReason);
217 	}
218 
219 	GetCurrentView()->Step();
220 }
221 
FindWordValue(uint32 mask)222 void QtDebugger::FindWordValue(uint32 mask)
223 {
224 	uint32 targetValue = 0;
225 	{
226 		bool ok;
227 		QString res = QInputDialog::getText(this, tr("Find Value in Memory"),
228 		                                    tr("Enter value to find:"), QLineEdit::Normal,
229 		                                    tr("00000000"), &ok);
230 		if(!ok || res.isEmpty())
231 			return;
232 
233 		if(sscanf(res.toStdString().c_str(), "%x", &targetValue) <= 0)
234 		{
235 			QMessageBox msgBox;
236 			msgBox.setText("Invalid hex value.");
237 			msgBox.exec();
238 			return;
239 		}
240 	}
241 	auto context = GetCurrentView()->GetContext();
242 	auto title = string_format("Search results for 0x%08X", targetValue);
243 	auto refs = FindWordValueRefs(context, targetValue & mask, mask);
244 
245 	m_addressListView->SetTitle(std::move(title));
246 	m_addressListView->SetAddressList(std::move(refs));
247 	m_addressListView->show();
248 	m_addressListView->setFocus(Qt::ActiveWindowFocusReason);
249 }
250 
AssembleJAL()251 void QtDebugger::AssembleJAL()
252 {
253 	uint32 nValueTarget = 0, nValueAssemble = 0;
254 	auto getAddress =
255 	    [this](const char* prompt, uint32& address) {
256 		    bool ok;
257 		    QString res = QInputDialog::getText(this, tr("Assemble JAL"),
258 		                                        tr(prompt), QLineEdit::Normal,
259 		                                        tr("00000000"), &ok);
260 		    if(!ok || res.isEmpty())
261 			    return false;
262 		    uint32 addrValueTemp = 0;
263 		    if(sscanf(res.toStdString().c_str(), "%x", &address) <= 0)
264 		    {
265 			    QMessageBox msgBox;
266 			    msgBox.setText("Invalid value.");
267 			    msgBox.exec();
268 			    return false;
269 		    }
270 		    return true;
271 	    };
272 	if(!getAddress("Enter jump target:", nValueTarget)) return;
273 	if(!getAddress("Enter address to assemble JAL to:", nValueAssemble)) return;
274 
275 	*(uint32*)&m_virtualMachine.m_ee->m_ram[nValueAssemble] = 0x0C000000 | (nValueTarget / 4);
276 }
277 
ReanalyzeEe()278 void QtDebugger::ReanalyzeEe()
279 {
280 	if(m_virtualMachine.m_ee->m_os->GetELF() == nullptr) return;
281 
282 	auto executableRange = m_virtualMachine.m_ee->m_os->GetExecutableRange();
283 	uint32 minAddr = executableRange.first;
284 	uint32 maxAddr = executableRange.second & ~0x03;
285 
286 	auto getAddress =
287 	    [this](const char* prompt, uint32& address) {
288 		    bool ok;
289 		    QString res = QInputDialog::getText(this, tr("Analyze EE"),
290 		                                        tr(prompt), QLineEdit::Normal,
291 		                                        tr(string_format("0x%08X", address).c_str()), &ok);
292 		    if(!ok || res.isEmpty())
293 			    return false;
294 		    uint32 addrValueTemp = 0;
295 		    if(sscanf(res.toStdString().c_str(), "%x", &addrValueTemp) <= 0)
296 		    {
297 			    QMessageBox msgBox;
298 			    msgBox.setText("Invalid value.");
299 			    msgBox.exec();
300 			    return false;
301 		    }
302 		    if(addrValueTemp != 0)
303 		    {
304 			    address = addrValueTemp & ~0x3;
305 		    }
306 		    return true;
307 	    };
308 
309 	if(!getAddress("Start Address:", minAddr)) return;
310 	if(!getAddress("End Address:", maxAddr)) return;
311 
312 	if(minAddr > maxAddr)
313 	{
314 		QMessageBox msgBox;
315 		msgBox.setText("Start address is larger than end address.");
316 		msgBox.exec();
317 		return;
318 	}
319 
320 	minAddr = std::min<uint32>(minAddr, PS2::EE_RAM_SIZE);
321 	maxAddr = std::min<uint32>(maxAddr, PS2::EE_RAM_SIZE);
322 
323 	m_virtualMachine.m_ee->m_EE.m_analysis->Clear();
324 	m_virtualMachine.m_ee->m_EE.m_analysis->Analyse(minAddr, maxAddr);
325 }
326 
FindEeFunctions()327 void QtDebugger::FindEeFunctions()
328 {
329 	if(m_virtualMachine.m_ee->m_os->GetELF() == nullptr) return;
330 
331 	auto executableRange = m_virtualMachine.m_ee->m_os->GetExecutableRange();
332 	uint32 minAddr = executableRange.first;
333 	uint32 maxAddr = executableRange.second & ~0x03;
334 
335 	auto functionsPath = Framework::PathUtils::GetAppResourcesPath() / "ee_functions.xml";
336 	auto functionsStream = Framework::CreateInputStdStream(functionsPath.native());
337 	auto functionsDocument = std::unique_ptr<Framework::Xml::CNode>(Framework::Xml::CParser::ParseDocument(functionsStream));
338 	auto functionsNode = functionsDocument->Select("Functions");
339 
340 	//Check function patterns
341 	{
342 		CMipsFunctionPatternDb patternDb(functionsNode);
343 
344 		for(auto patternIterator(std::begin(patternDb.GetPatterns()));
345 		    patternIterator != std::end(patternDb.GetPatterns()); ++patternIterator)
346 		{
347 			auto pattern = *patternIterator;
348 			for(uint32 address = minAddr; address <= maxAddr; address += 4)
349 			{
350 				uint32* text = reinterpret_cast<uint32*>(m_virtualMachine.m_ee->m_ram + address);
351 				uint32 textSize = (maxAddr - address);
352 				if(pattern.Matches(text, textSize))
353 				{
354 					m_virtualMachine.m_ee->m_EE.m_Functions.InsertTag(address, pattern.name.c_str());
355 					break;
356 				}
357 			}
358 		}
359 	}
360 
361 	//Check function comments
362 	{
363 		std::map<std::string, std::string> stringFuncs;
364 		auto commentNodes = functionsNode->SelectNodes("FunctionComments/FunctionComment");
365 		for(const auto& commentNode : commentNodes)
366 		{
367 			auto comment = Framework::Xml::GetAttributeStringValue(commentNode, "Comment");
368 			auto functionName = Framework::Xml::GetAttributeStringValue(commentNode, "Function");
369 			stringFuncs.insert(std::make_pair(comment, functionName));
370 		}
371 
372 		//Identify functions that reference special string literals
373 		{
374 			auto& eeFunctions = m_virtualMachine.m_ee->m_EE.m_Functions;
375 			const auto& eeComments = m_virtualMachine.m_ee->m_EE.m_Comments;
376 			const auto& eeAnalysis = m_virtualMachine.m_ee->m_EE.m_analysis;
377 			for(auto tagIterator = eeComments.GetTagsBegin();
378 			    tagIterator != eeComments.GetTagsEnd(); tagIterator++)
379 			{
380 				const auto& tag = *tagIterator;
381 				auto subroutine = eeAnalysis->FindSubroutine(tag.first);
382 				if(subroutine == nullptr) continue;
383 				auto stringFunc = stringFuncs.find(tag.second);
384 				if(stringFunc == std::end(stringFuncs)) continue;
385 				eeFunctions.InsertTag(subroutine->start, stringFunc->second.c_str());
386 			}
387 		}
388 	}
389 
390 	m_virtualMachine.m_ee->m_EE.m_Functions.OnTagListChange();
391 }
392 
Layout1024()393 void QtDebugger::Layout1024()
394 {
395 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->setGeometry(0, 0, 700, 435);
396 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->show();
397 	GetDisassemblyWindow()->show();
398 
399 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->setGeometry(700, 0, 324, 572);
400 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->show();
401 	GetRegisterViewWindow()->show();
402 
403 	static_cast<QWidget*>(GetMemoryViewWindow()->parent())->setGeometry(0, 435, 700, 265);
404 	static_cast<QWidget*>(GetMemoryViewWindow()->parent())->show();
405 	GetMemoryViewWindow()->show();
406 
407 	static_cast<QWidget*>(GetCallStackWindow()->parent())->setGeometry(700, 572, 324, 128);
408 	static_cast<QWidget*>(GetCallStackWindow()->parent())->show();
409 	GetCallStackWindow()->show();
410 }
411 
Layout1280()412 void QtDebugger::Layout1280()
413 {
414 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->setGeometry(0, 0, 900, 540);
415 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->show();
416 	GetDisassemblyWindow()->show();
417 
418 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->setGeometry(900, 0, 380, 784);
419 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->show();
420 	GetRegisterViewWindow()->show();
421 
422 	static_cast<QWidget*>(GetMemoryViewWindow()->parent())->setGeometry(0, 540, 900, 416);
423 	static_cast<QWidget*>(GetMemoryViewWindow()->parent())->show();
424 	GetMemoryViewWindow()->show();
425 
426 	static_cast<QWidget*>(GetCallStackWindow()->parent())->setGeometry(900, 784, 380, 172);
427 	static_cast<QWidget*>(GetCallStackWindow()->parent())->show();
428 	GetCallStackWindow()->show();
429 }
430 
Layout1600()431 void QtDebugger::Layout1600()
432 {
433 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->setGeometry(0, 0, 1094, 725);
434 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->show();
435 	GetDisassemblyWindow()->show();
436 
437 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->setGeometry(1094, 0, 506, 725);
438 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->show();
439 	GetRegisterViewWindow()->show();
440 
441 	static_cast<QWidget*>(GetMemoryViewWindow()->parent())->setGeometry(0, 725, 1094, 407);
442 	static_cast<QWidget*>(GetMemoryViewWindow()->parent())->show();
443 	GetMemoryViewWindow()->show();
444 
445 	static_cast<QWidget*>(GetCallStackWindow()->parent())->setGeometry(1094, 725, 506, 407);
446 	static_cast<QWidget*>(GetCallStackWindow()->parent())->show();
447 	GetCallStackWindow()->show();
448 }
449 
ActivateView(unsigned int nView)450 void QtDebugger::ActivateView(unsigned int nView)
451 {
452 	if(m_nCurrentView == nView) return;
453 
454 	if(m_nCurrentView != -1)
455 	{
456 		SaveBytesPerLine();
457 		SaveViewLayout();
458 		GetCurrentView()->Hide();
459 	}
460 
461 	m_findCallersRequestConnection.reset();
462 
463 	m_nCurrentView = nView;
464 	LoadViewLayout();
465 	LoadBytesPerLine();
466 	UpdateTitle();
467 
468 	{
469 		auto biosDebugInfoProvider = GetCurrentView()->GetBiosDebugInfoProvider();
470 		m_pFunctionsView->SetContext(GetCurrentView()->GetContext(), biosDebugInfoProvider);
471 		static_cast<CThreadsViewWnd*>(m_threadsView->widget())->SetContext(GetCurrentView()->GetContext(), biosDebugInfoProvider);
472 	}
473 
474 	if(GetDisassemblyWindow()->isVisible())
475 	{
476 		GetDisassemblyWindow()->setFocus(Qt::ActiveWindowFocusReason);
477 	}
478 
479 	m_findCallersRequestConnection = GetCurrentView()->GetDisassemblyWindow()->FindCallersRequested.Connect(
480 	    [&](uint32 address) { OnFindCallersRequested(address); });
481 }
482 
SaveViewLayout()483 void QtDebugger::SaveViewLayout()
484 {
485 	SerializeWindowGeometry(static_cast<QWidget*>(GetDisassemblyWindow()->parent()),
486 	                        "debugger.disasm.posx",
487 	                        "debugger.disasm.posy",
488 	                        "debugger.disasm.sizex",
489 	                        "debugger.disasm.sizey",
490 	                        "debugger.disasm.visible");
491 
492 	SerializeWindowGeometry(static_cast<QWidget*>(GetRegisterViewWindow()->parent()),
493 	                        "debugger.regview.posx",
494 	                        "debugger.regview.posy",
495 	                        "debugger.regview.sizex",
496 	                        "debugger.regview.sizey",
497 	                        "debugger.regview.visible");
498 
499 	SerializeWindowGeometry(static_cast<QWidget*>(GetMemoryViewWindow()->parent()),
500 	                        "debugger.memoryview.posx",
501 	                        "debugger.memoryview.posy",
502 	                        "debugger.memoryview.sizex",
503 	                        "debugger.memoryview.sizey",
504 	                        "debugger.memoryview.visible");
505 
506 	SerializeWindowGeometry(static_cast<QWidget*>(GetCallStackWindow()->parent()),
507 	                        "debugger.callstack.posx",
508 	                        "debugger.callstack.posy",
509 	                        "debugger.callstack.sizex",
510 	                        "debugger.callstack.sizey",
511 	                        "debugger.callstack.visible");
512 }
513 
LoadViewLayout()514 void QtDebugger::LoadViewLayout()
515 {
516 	UnserializeWindowGeometry(static_cast<QWidget*>(GetDisassemblyWindow()->parent()),
517 	                          "debugger.disasm.posx",
518 	                          "debugger.disasm.posy",
519 	                          "debugger.disasm.sizex",
520 	                          "debugger.disasm.sizey",
521 	                          "debugger.disasm.visible");
522 
523 	UnserializeWindowGeometry(static_cast<QWidget*>(GetRegisterViewWindow()->parent()),
524 	                          "debugger.regview.posx",
525 	                          "debugger.regview.posy",
526 	                          "debugger.regview.sizex",
527 	                          "debugger.regview.sizey",
528 	                          "debugger.regview.visible");
529 
530 	UnserializeWindowGeometry(static_cast<QWidget*>(GetMemoryViewWindow()->parent()),
531 	                          "debugger.memoryview.posx",
532 	                          "debugger.memoryview.posy",
533 	                          "debugger.memoryview.sizex",
534 	                          "debugger.memoryview.sizey",
535 	                          "debugger.memoryview.visible");
536 
537 	UnserializeWindowGeometry(static_cast<QWidget*>(GetCallStackWindow()->parent()),
538 	                          "debugger.callstack.posx",
539 	                          "debugger.callstack.posy",
540 	                          "debugger.callstack.sizex",
541 	                          "debugger.callstack.sizey",
542 	                          "debugger.callstack.visible");
543 }
544 
SaveBytesPerLine()545 void QtDebugger::SaveBytesPerLine()
546 {
547 	auto memoryView = GetMemoryViewWindow();
548 	auto bytesPerLine = GetMemoryViewWindow()->GetBytesPerLine();
549 	CAppConfig::GetInstance().SetPreferenceInteger(PREF_DEBUGGER_MEMORYVIEW_BYTEWIDTH, bytesPerLine);
550 }
551 
LoadBytesPerLine()552 void QtDebugger::LoadBytesPerLine()
553 {
554 	auto bytesPerLine = CAppConfig::GetInstance().GetPreferenceInteger(PREF_DEBUGGER_MEMORYVIEW_BYTEWIDTH);
555 	auto memoryView = GetMemoryViewWindow();
556 	memoryView->SetBytesPerLine(bytesPerLine);
557 }
558 
GetCurrentView()559 CDebugView* QtDebugger::GetCurrentView()
560 {
561 	if(m_nCurrentView == -1) return NULL;
562 	return m_pView[m_nCurrentView];
563 }
564 
GetContext()565 CMIPS* QtDebugger::GetContext()
566 {
567 	return nullptr;
568 	return GetCurrentView()->GetContext();
569 }
570 
GetDisassemblyWindow()571 CDisAsmWnd* QtDebugger::GetDisassemblyWindow()
572 {
573 	return GetCurrentView()->GetDisassemblyWindow();
574 }
575 
GetMemoryViewWindow()576 CMemoryViewMIPSWnd* QtDebugger::GetMemoryViewWindow()
577 {
578 	return GetCurrentView()->GetMemoryViewWindow();
579 }
580 
GetRegisterViewWindow()581 CRegViewWnd* QtDebugger::GetRegisterViewWindow()
582 {
583 	return GetCurrentView()->GetRegisterViewWindow();
584 }
585 
GetCallStackWindow()586 CCallStackWnd* QtDebugger::GetCallStackWindow()
587 {
588 	return GetCurrentView()->GetCallStackWindow();
589 }
590 
FindCallers(CMIPS * context,uint32 address)591 std::vector<uint32> QtDebugger::FindCallers(CMIPS* context, uint32 address)
592 {
593 	std::vector<uint32> callers;
594 	for(uint32 i = 0; i < FIND_MAX_ADDRESS; i += 4)
595 	{
596 		uint32 opcode = context->m_pMemoryMap->GetInstruction(i);
597 		uint32 ea = context->m_pArch->GetInstructionEffectiveAddress(context, i, opcode);
598 		if(ea == address)
599 		{
600 			callers.push_back(i);
601 		}
602 	}
603 	return callers;
604 }
605 
FindWordValueRefs(CMIPS * context,uint32 targetValue,uint32 valueMask)606 std::vector<uint32> QtDebugger::FindWordValueRefs(CMIPS* context, uint32 targetValue, uint32 valueMask)
607 {
608 	std::vector<uint32> refs;
609 	for(uint32 i = 0; i < FIND_MAX_ADDRESS; i += 4)
610 	{
611 		uint32 valueAtAddress = context->m_pMemoryMap->GetWord(i);
612 		if((valueAtAddress & valueMask) == targetValue)
613 		{
614 			refs.push_back(i);
615 		}
616 	}
617 	return refs;
618 }
619 
OnFunctionsViewFunctionDblClick(uint32 address)620 void QtDebugger::OnFunctionsViewFunctionDblClick(uint32 address)
621 {
622 	GetDisassemblyWindow()->SetAddress(address);
623 }
624 
OnFunctionsViewFunctionsStateChange()625 void QtDebugger::OnFunctionsViewFunctionsStateChange()
626 {
627 	GetDisassemblyWindow()->HandleMachineStateChange();
628 	GetCallStackWindow()->HandleMachineStateChange();
629 }
630 
OnThreadsViewAddressDblClick(uint32 address)631 void QtDebugger::OnThreadsViewAddressDblClick(uint32 address)
632 {
633 	auto disAsm = GetDisassemblyWindow();
634 	disAsm->SetCenterAtAddress(address);
635 	disAsm->SetSelectedAddress(address);
636 }
637 
OnFindCallersRequested(uint32 address)638 void QtDebugger::OnFindCallersRequested(uint32 address)
639 {
640 	auto context = GetCurrentView()->GetContext();
641 	auto callers = FindCallers(context, address);
642 	auto title =
643 	    [&]() {
644 		    auto functionName = context->m_Functions.Find(address);
645 		    if(functionName)
646 		    {
647 			    return string_format("Find Callers For '%s' (0x%08X)",
648 			                         functionName, address);
649 		    }
650 		    else
651 		    {
652 			    return string_format("Find Callers For 0x%08X", address);
653 		    }
654 	    }();
655 
656 	m_addressListView->SetAddressList(std::move(callers));
657 	m_addressListView->SetTitle(std::move(title));
658 	m_addressListView->show();
659 	m_addressListView->setFocus(Qt::ActiveWindowFocusReason);
660 }
661 
OnFindCallersAddressDblClick(uint32 address)662 void QtDebugger::OnFindCallersAddressDblClick(uint32 address)
663 {
664 	auto disAsm = GetDisassemblyWindow();
665 	disAsm->SetCenterAtAddress(address);
666 	disAsm->SetSelectedAddress(address);
667 }
668 
OnExecutableChangeMsg()669 void QtDebugger::OnExecutableChangeMsg()
670 {
671 	m_pELFView->SetELF(m_virtualMachine.m_ee->m_os->GetELF());
672 
673 	LoadDebugTags();
674 
675 	GetDisassemblyWindow()->HandleMachineStateChange();
676 	GetCallStackWindow()->HandleMachineStateChange();
677 	m_pFunctionsView->Refresh();
678 }
679 
OnExecutableUnloadingMsg()680 void QtDebugger::OnExecutableUnloadingMsg()
681 {
682 	SaveDebugTags();
683 	m_pELFView->SetELF(NULL);
684 }
685 
OnMachineStateChangeMsg()686 void QtDebugger::OnMachineStateChangeMsg()
687 {
688 	for(auto& view : m_pView)
689 	{
690 		view->HandleMachineStateChange();
691 	}
692 	static_cast<CThreadsViewWnd*>(m_threadsView->widget())->HandleMachineStateChange();
693 }
694 
OnRunningStateChangeMsg()695 void QtDebugger::OnRunningStateChangeMsg()
696 {
697 	auto newState = m_virtualMachine.GetStatus();
698 	for(auto& view : m_pView)
699 	{
700 		view->HandleRunningStateChange(newState);
701 	}
702 	static_cast<CThreadsViewWnd*>(m_threadsView->widget())->HandleRunningStateChange(newState);
703 }
704 
LoadDebugTags()705 void QtDebugger::LoadDebugTags()
706 {
707 #ifdef DEBUGGER_INCLUDED
708 	m_virtualMachine.LoadDebugTags(m_virtualMachine.m_ee->m_os->GetExecutableName());
709 #endif
710 }
711 
SaveDebugTags()712 void QtDebugger::SaveDebugTags()
713 {
714 #ifdef DEBUGGER_INCLUDED
715 	if(m_virtualMachine.m_ee != nullptr)
716 	{
717 		if(m_virtualMachine.m_ee->m_os->GetELF() != nullptr)
718 		{
719 			m_virtualMachine.SaveDebugTags(m_virtualMachine.m_ee->m_os->GetExecutableName());
720 		}
721 	}
722 #endif
723 }
724 
on_actionResume_triggered()725 void QtDebugger::on_actionResume_triggered()
726 {
727 	Resume();
728 }
729 
on_actionStep_CPU_triggered()730 void QtDebugger::on_actionStep_CPU_triggered()
731 {
732 	StepCPU();
733 }
734 
on_actionDump_INTC_Handlers_triggered()735 void QtDebugger::on_actionDump_INTC_Handlers_triggered()
736 {
737 	m_virtualMachine.DumpEEIntcHandlers();
738 }
739 
on_actionDump_DMAC_Handlers_triggered()740 void QtDebugger::on_actionDump_DMAC_Handlers_triggered()
741 {
742 	m_virtualMachine.DumpEEDmacHandlers();
743 }
744 
on_actionAssemble_JAL_triggered()745 void QtDebugger::on_actionAssemble_JAL_triggered()
746 {
747 	AssembleJAL();
748 }
749 
on_actionReanalyse_ee_triggered()750 void QtDebugger::on_actionReanalyse_ee_triggered()
751 {
752 	ReanalyzeEe();
753 }
754 
on_actionFind_Functions_triggered()755 void QtDebugger::on_actionFind_Functions_triggered()
756 {
757 	FindEeFunctions();
758 }
759 
on_actionCascade_triggered()760 void QtDebugger::on_actionCascade_triggered()
761 {
762 	ui->mdiArea->cascadeSubWindows();
763 }
764 
on_actionTile_triggered()765 void QtDebugger::on_actionTile_triggered()
766 {
767 	ui->mdiArea->tileSubWindows();
768 }
769 
on_actionLayout_1024x768_triggered()770 void QtDebugger::on_actionLayout_1024x768_triggered()
771 {
772 	Layout1024();
773 }
774 
on_actionLayout_1280x1024_triggered()775 void QtDebugger::on_actionLayout_1280x1024_triggered()
776 {
777 	Layout1280();
778 }
779 
on_actionLayout_1600x1200_triggered()780 void QtDebugger::on_actionLayout_1600x1200_triggered()
781 {
782 	Layout1600();
783 }
784 
on_actionfind_word_value_triggered()785 void QtDebugger::on_actionfind_word_value_triggered()
786 {
787 	FindWordValue(~0);
788 }
789 
on_actionFind_Word_Half_Value_triggered()790 void QtDebugger::on_actionFind_Word_Half_Value_triggered()
791 {
792 	FindWordValue(0xFFFF);
793 }
794 
on_actionCall_Stack_triggered()795 void QtDebugger::on_actionCall_Stack_triggered()
796 {
797 	GetCallStackWindow()->show();
798 	static_cast<QWidget*>(GetCallStackWindow()->parent())->show();
799 	static_cast<QWidget*>(GetCallStackWindow()->parent())->setFocus(Qt::ActiveWindowFocusReason);
800 }
801 
on_actionFunctions_triggered()802 void QtDebugger::on_actionFunctions_triggered()
803 {
804 	m_pFunctionsView->show();
805 	m_pFunctionsView->setFocus(Qt::ActiveWindowFocusReason);
806 }
807 
on_actionThreads_triggered()808 void QtDebugger::on_actionThreads_triggered()
809 {
810 	static_cast<CThreadsViewWnd*>(m_threadsView->widget())->show();
811 	m_threadsView->show();
812 	m_threadsView->setFocus(Qt::ActiveWindowFocusReason);
813 }
814 
on_actionView_Disassmebly_triggered()815 void QtDebugger::on_actionView_Disassmebly_triggered()
816 {
817 	GetDisassemblyWindow()->show();
818 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->show();
819 	static_cast<QWidget*>(GetDisassemblyWindow()->parent())->setFocus(Qt::ActiveWindowFocusReason);
820 }
821 
on_actionView_Registers_triggered()822 void QtDebugger::on_actionView_Registers_triggered()
823 {
824 	GetRegisterViewWindow()->show();
825 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->show();
826 	static_cast<QWidget*>(GetRegisterViewWindow()->parent())->setFocus(Qt::ActiveWindowFocusReason);
827 }
828 
on_actionMemory_triggered()829 void QtDebugger::on_actionMemory_triggered()
830 {
831 	GetMemoryViewWindow()->show();
832 	GetMemoryViewWindow()->setFocus(Qt::ActiveWindowFocusReason);
833 }
834 
on_actionEmotionEngine_View_triggered()835 void QtDebugger::on_actionEmotionEngine_View_triggered()
836 {
837 	ActivateView(DEBUGVIEW_EE);
838 }
839 
on_actionVector_Unit_0_triggered()840 void QtDebugger::on_actionVector_Unit_0_triggered()
841 {
842 	ActivateView(DEBUGVIEW_VU0);
843 }
844 
on_actionVector_Unit_1_triggered()845 void QtDebugger::on_actionVector_Unit_1_triggered()
846 {
847 	ActivateView(DEBUGVIEW_VU1);
848 }
849 
on_actionIOP_View_triggered()850 void QtDebugger::on_actionIOP_View_triggered()
851 {
852 	ActivateView(DEBUGVIEW_IOP);
853 }
854