Mesen-SX/Core/Debugger.cpp

214 lines
6.5 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Debugger.h"
2019-02-27 20:33:56 -05:00
#include "DebugTypes.h"
2019-02-15 21:33:13 -05:00
#include "Console.h"
#include "Cpu.h"
#include "Ppu.h"
#include "BaseCartridge.h"
#include "MemoryManager.h"
#include "NotificationManager.h"
#include "CpuTypes.h"
#include "DisassemblyInfo.h"
#include "TraceLogger.h"
2019-02-15 21:33:13 -05:00
#include "MemoryDumper.h"
#include "CodeDataLogger.h"
#include "Disassembler.h"
2019-03-01 20:27:49 -05:00
#include "BreakpointManager.h"
2019-02-27 20:33:56 -05:00
#include "ExpressionEvaluator.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FolderUtilities.h"
2019-02-15 21:33:13 -05:00
Debugger::Debugger(shared_ptr<Console> console)
{
_console = console;
2019-02-15 21:33:13 -05:00
_cpu = console->GetCpu();
_ppu = console->GetPpu();
_memoryManager = console->GetMemoryManager();
2019-02-27 20:33:56 -05:00
_watchExpEval.reset(new ExpressionEvaluator(this));
_codeDataLogger.reset(new CodeDataLogger(console->GetCartridge()->DebugGetPrgRomSize()));
_disassembler.reset(new Disassembler(console, _codeDataLogger));
2019-02-15 21:33:13 -05:00
_traceLogger.reset(new TraceLogger(this, _memoryManager));
_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, console->GetCartridge()));
2019-03-01 20:27:49 -05:00
_breakpointManager.reset(new BreakpointManager(this));
_cpuStepCount = 0;
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomPath, false) + ".cdl");
_codeDataLogger->LoadCdlFile(cdlFile);
//TODO: Thread safety
uint32_t prgRomSize = console->GetCartridge()->DebugGetPrgRomSize();
AddressInfo addrInfo;
addrInfo.Type = SnesMemoryType::PrgRom;
for(uint32_t i = 0; i < prgRomSize; i++) {
if(_codeDataLogger->IsCode(i)) {
addrInfo.Address = (int32_t)i;
i += _disassembler->BuildCache(addrInfo, _codeDataLogger->GetCpuFlags(i)) - 1;
}
}
}
Debugger::~Debugger()
{
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomPath, false) + ".cdl");
_codeDataLogger->SaveCdlFile(cdlFile);
}
void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr);
2019-03-01 20:27:49 -05:00
MemoryOperationInfo operation = { addr, value, type };
CpuState state = _cpu->GetState();
if(type == MemoryOperationType::ExecOpCode) {
if(addressInfo.Address >= 0) {
if(addressInfo.Type == SnesMemoryType::PrgRom) {
uint8_t flags = CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
if(_prevOpCode == 0x20 || _prevOpCode == 0x5C || _prevOpCode == 0xDC || _prevOpCode == 0xFC) {
flags |= CdlFlags::SubEntryPoint;
}
_codeDataLogger->SetFlags(addressInfo.Address, flags);
}
_disassembler->BuildCache(addressInfo, state.PS);
}
DebugState debugState;
2019-03-01 20:27:49 -05:00
GetState(debugState);
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo);
_traceLogger->Log(debugState, disInfo);
_prevOpCode = value;
if(_cpuStepCount > 0) {
_cpuStepCount--;
2019-03-01 20:27:49 -05:00
}
if(value == 0x00 || value == 0xCB) {
//Break on BRK/WAI
_cpuStepCount = 0;
}
} else if(type == MemoryOperationType::ExecOperand) {
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
}
} else {
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
}
}
2019-03-01 20:27:49 -05:00
ProcessBreakConditions(operation, addressInfo);
}
void Debugger::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr);
2019-03-01 20:27:49 -05:00
MemoryOperationInfo operation = { addr, value, type };
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) {
_disassembler->InvalidateCache(addressInfo);
}
2019-03-01 20:27:49 -05:00
ProcessBreakConditions(operation, addressInfo);
}
void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value)
{
AddressInfo addressInfo(addr, SnesMemoryType::WorkRam);
//TODO Make this more flexible/accurate
MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Read);
ProcessBreakConditions(operation, addressInfo);
}
void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value)
{
AddressInfo addressInfo(addr, SnesMemoryType::WorkRam);
//TODO Make this more flexible/accurate
MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Write);
ProcessBreakConditions(operation, addressInfo);
}
void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
AddressInfo addressInfo(addr, memoryType);
MemoryOperationInfo operation(addr, value, MemoryOperationType::Read);
ProcessBreakConditions(operation, addressInfo);
}
void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType)
{
AddressInfo addressInfo(addr, memoryType);
MemoryOperationInfo operation(addr, value, MemoryOperationType::Write);
ProcessBreakConditions(operation, addressInfo);
}
void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo)
{
if(_breakpointManager->CheckBreakpoint(operation, addressInfo)) {
_cpuStepCount = 0;
}
if(_cpuStepCount == 0) {
_disassembler->Disassemble();
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak);
while(_cpuStepCount == 0) {
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(10));
}
}
}
2019-02-27 20:33:56 -05:00
int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType, bool useCache)
{
2019-03-01 20:27:49 -05:00
MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read };
2019-02-27 20:33:56 -05:00
DebugState state;
2019-03-01 20:27:49 -05:00
GetState(state);
2019-02-27 20:33:56 -05:00
if(useCache) {
return _watchExpEval->Evaluate(expression, state, resultType, operationInfo);
} else {
ExpressionEvaluator expEval(this);
return expEval.Evaluate(expression, state, resultType, operationInfo);
}
}
void Debugger::Run()
{
_cpuStepCount = -1;
}
void Debugger::Step(int32_t stepCount)
{
_cpuStepCount = stepCount;
}
bool Debugger::IsExecutionStopped()
{
//TODO
return false;
}
2019-03-01 20:27:49 -05:00
void Debugger::GetState(DebugState &state)
{
2019-03-01 20:27:49 -05:00
state.Cpu = _cpu->GetState();
state.Ppu = _ppu->GetState();
}
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
{
return _traceLogger;
2019-02-15 21:33:13 -05:00
}
shared_ptr<MemoryDumper> Debugger::GetMemoryDumper()
{
return _memoryDumper;
}
shared_ptr<Disassembler> Debugger::GetDisassembler()
{
return _disassembler;
}
2019-03-01 20:27:49 -05:00
shared_ptr<BreakpointManager> Debugger::GetBreakpointManager()
{
return _breakpointManager;
}