#include "stdafx.h" #include "Debugger/CodeDataLogger.h" #include "Debugger/Disassembler.h" #include "Shared/Emulator.h" #include "Shared/EmuSettings.h" #include "Utilities/VirtualFile.h" #include "Utilities/FolderUtilities.h" CodeDataLogger::CodeDataLogger(MemoryType memType, uint32_t memSize, CpuType cpuType, uint32_t romCrc32) { _memType = memType; _cpuType = cpuType; _memSize = memSize; _romCrc32 = romCrc32; _cdlData = new uint8_t[memSize]; Reset(); } CodeDataLogger::~CodeDataLogger() { delete[] _cdlData; } void CodeDataLogger::Reset() { memset(_cdlData, 0, _memSize); } uint32_t CodeDataLogger::GetSize() { return _memSize; } MemoryType CodeDataLogger::GetMemoryType() { return _memType; } bool CodeDataLogger::LoadCdlFile(string cdlFilepath, bool autoResetCdl) { VirtualFile cdlFile = cdlFilepath; if(cdlFile.IsValid()) { uint32_t fileSize = (uint32_t)cdlFile.GetSize(); vector cdlData; cdlFile.ReadFile(cdlData); if(fileSize >= _memSize) { Reset(); constexpr int headerSize = 9; //"CDLv2" + 4-byte CRC32 value if(memcmp(cdlData.data(), "CDLv2", 5) == 0) { uint32_t savedCrc = cdlData[5] | (cdlData[6] << 8) | (cdlData[7] << 16) | (cdlData[8] << 24); if((autoResetCdl && savedCrc != _romCrc32) || fileSize < _memSize + headerSize) { memset(_cdlData, 0, _memSize); } else { memcpy(_cdlData, cdlData.data() + headerSize, _memSize); } } else { //Older CRC-less CDL file, use as-is without checking CRC to avoid data loss memcpy(_cdlData, cdlData.data(), _memSize); } return true; } } return false; } bool CodeDataLogger::SaveCdlFile(string cdlFilepath) { ofstream cdlFile(cdlFilepath, ios::out | ios::binary); if(cdlFile) { cdlFile.write("CDLv2", 5); cdlFile.put(_romCrc32 & 0xFF); cdlFile.put((_romCrc32 >> 8) & 0xFF); cdlFile.put((_romCrc32 >> 16) & 0xFF); cdlFile.put((_romCrc32 >> 24) & 0xFF); cdlFile.write((char*)_cdlData, _memSize); cdlFile.close(); return true; } return false; } string CodeDataLogger::GetCdlFilePath(string romName) { return FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(romName, false) + ".cdl"); } CdlRatios CodeDataLogger::GetRatios() { uint32_t codeSize = 0; uint32_t dataSize = 0; for(int i = 0, len = _memSize; i < len; i++) { if(IsCode(i)) { codeSize++; } else if(IsData(i)) { dataSize++; } } CdlRatios ratios; ratios.CodeRatio = (float)codeSize / (float)_memSize; ratios.DataRatio = (float)dataSize / (float)_memSize; ratios.PrgRatio = (float)(codeSize + dataSize) / (float)_memSize; return ratios; } bool CodeDataLogger::IsCode(uint32_t absoluteAddr) { return (_cdlData[absoluteAddr] & CdlFlags::Code) != 0; } bool CodeDataLogger::IsJumpTarget(uint32_t absoluteAddr) { return (_cdlData[absoluteAddr] & CdlFlags::JumpTarget) != 0; } bool CodeDataLogger::IsSubEntryPoint(uint32_t absoluteAddr) { return (_cdlData[absoluteAddr] & CdlFlags::SubEntryPoint) != 0; } bool CodeDataLogger::IsData(uint32_t absoluteAddr) { return (_cdlData[absoluteAddr] & CdlFlags::Data) != 0; } void CodeDataLogger::SetCdlData(uint8_t *cdlData, uint32_t length) { if(length <= _memSize) { memcpy(_cdlData, cdlData, length); } } void CodeDataLogger::GetCdlData(uint32_t offset, uint32_t length, uint8_t *cdlData) { memcpy(cdlData, _cdlData + offset, length); } uint8_t CodeDataLogger::GetFlags(uint32_t addr) { return _cdlData[addr]; } void CodeDataLogger::MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags) { for(uint32_t i = start; i <= end; i++) { _cdlData[i] = (_cdlData[i] & 0xFC) | (int)flags; } } void CodeDataLogger::StripData(uint8_t* romBuffer, CdlStripOption flag) { if(flag == CdlStripOption::StripUnused) { for(uint32_t i = 0; i < _memSize; i++) { if(_cdlData[i] == 0) { romBuffer[i] = 0; } } } else if(flag == CdlStripOption::StripUsed) { for(uint32_t i = 0; i < _memSize; i++) { if(_cdlData[i] != 0) { romBuffer[i] = 0; } } } } void CodeDataLogger::RebuildPrgCache(Disassembler* dis) { AddressInfo addrInfo; addrInfo.Type = _memType; for(uint32_t i = 0; i < _memSize; i++) { if(IsCode(i)) { addrInfo.Address = (int32_t)i; i += dis->BuildCache(addrInfo, 0, _cpuType) - 1; } } }