CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/Debugger/DisassemblyManager.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "ppsspp_config.h"1819#include <string>20#include <algorithm>21#include <map>2223#include "ext/xxhash.h"2425#include "Common/CommonTypes.h"26#include "Common/Data/Encoding/Utf8.h"27#include "Common/StringUtils.h"28#include "Core/MemMap.h"29#include "Core/System.h"30#include "Core/MIPS/MIPSCodeUtils.h"31#include "Core/MIPS/MIPSTables.h"32#include "Core/Debugger/DebugInterface.h"33#include "Core/Debugger/SymbolMap.h"34#include "Core/Debugger/DisassemblyManager.h"3536std::map<u32, DisassemblyEntry*> DisassemblyManager::entries;37std::recursive_mutex DisassemblyManager::entriesLock_;38DebugInterface* DisassemblyManager::cpu;39int DisassemblyManager::maxParamChars = 29;4041bool isInInterval(u32 start, u32 size, u32 value)42{43return start <= value && value <= (start+size-1);44}4546bool IsLikelyStringAt(uint32_t addr) {47uint32_t maxLen = Memory::ValidSize(addr, 128);48if (maxLen <= 1)49return false;50const char *p = Memory::GetCharPointer(addr);51// If there's no terminator nearby, let's say no.52if (memchr(p, 0, maxLen) == nullptr)53return false;5455// Allow tabs and newlines.56static constexpr bool validControl[] = {57false, false, false, false, false, false, false, false,58false, true, true, true, false, true, false, false,59false, false, false, false, false, false, false, false,60false, false, false, false, false, false, false, false,61};6263// Check that there's some bytes before the terminator that look like a string.64UTF8 utf(p);65if (utf.end())66return false;6768char verify[4];69while (!utf.end()) {70if (utf.invalid())71return false;7273int pos = utf.byteIndex();74uint32_t c = utf.next();75int len = UTF8::encode(verify, c);76// Our decoder is a bit lax, so let's verify this is a normal encoding.77// This prevents us from trying to output invalid encodings in the debugger.78if (memcmp(p + pos, verify, len) != 0 || pos + len != utf.byteIndex())79return false;8081if (c < ARRAY_SIZE(validControl) && !validControl[c])82return false;83if (c > 0x0010FFFF)84return false;85}8687return true;88}8990static HashType computeHash(u32 address, u32 size)91{92if (!Memory::IsValidAddress(address))93return 0;9495size = Memory::ValidSize(address, size);96#if PPSSPP_ARCH(AMD64)97return XXH3_64bits(Memory::GetPointerUnchecked(address), size);98#else99return XXH3_64bits(Memory::GetPointerUnchecked(address), size) & 0xFFFFFFFF;100#endif101}102103104static void parseDisasm(const char *disasm, char *opcode, size_t opcodeSize, char *arguments, size_t argumentsSize, bool insertSymbols) {105// copy opcode106size_t opcodePos = 0;107while (*disasm != 0 && *disasm != '\t' && opcodePos + 1 < opcodeSize) {108opcode[opcodePos++] = *disasm++;109}110opcode[opcodePos] = 0;111112// Otherwise it's a tab, and we skip intentionally.113if (*disasm++ == 0) {114*arguments = 0;115return;116}117118const char* jumpAddress = strstr(disasm,"->$");119const char* jumpRegister = strstr(disasm,"->");120size_t argumentsPos = 0;121while (*disasm != 0 && argumentsPos + 1 < argumentsSize) {122// parse symbol123if (disasm == jumpAddress) {124u32 branchTarget = 0;125sscanf(disasm+3, "%08x", &branchTarget);126const std::string addressSymbol = g_symbolMap->GetLabelString(branchTarget);127if (!addressSymbol.empty() && insertSymbols) {128argumentsPos += snprintf(&arguments[argumentsPos], argumentsSize - argumentsPos, "%s", addressSymbol.c_str());129} else {130argumentsPos += snprintf(&arguments[argumentsPos], argumentsSize - argumentsPos, "0x%08X", branchTarget);131}132133disasm += 3+8;134continue;135}136137if (disasm == jumpRegister)138disasm += 2;139140if (*disasm == ' ') {141disasm++;142continue;143}144arguments[argumentsPos++] = *disasm++;145}146147arguments[argumentsPos] = 0;148}149150std::map<u32,DisassemblyEntry*>::iterator findDisassemblyEntry(std::map<u32,DisassemblyEntry*>& entries, u32 address, bool exact)151{152if (exact)153return entries.find(address);154155if (entries.size() == 0)156return entries.end();157158// find first elem that's >= address159auto it = entries.lower_bound(address);160if (it != entries.end())161{162// it may be an exact match163if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))164return it;165166// otherwise it may point to the next167if (it != entries.begin())168{169it--;170if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))171return it;172}173}174175// check last entry manually176auto rit = entries.rbegin();177if (isInInterval(rit->second->getLineAddress(0),rit->second->getTotalSize(),address))178{179return (++rit).base();180}181182// no match otherwise183return entries.end();184}185186void DisassemblyManager::analyze(u32 address, u32 size = 1024)187{188u32 end = address+size;189190address &= ~3;191u32 start = address;192193while (address < end && start <= address)194{195if (!PSP_IsInited())196return;197198auto memLock = Memory::Lock();199std::lock_guard<std::recursive_mutex> guard(entriesLock_);200auto it = findDisassemblyEntry(entries, address, false);201if (it != entries.end())202{203DisassemblyEntry* entry = it->second;204entry->recheck();205address = entry->getLineAddress(0)+entry->getTotalSize();206continue;207}208209SymbolInfo info;210if (!g_symbolMap->GetSymbolInfo(&info,address,ST_ALL))211{212if (address % 4)213{214u32 next = std::min<u32>((address+3) & ~3,g_symbolMap->GetNextSymbolAddress(address,ST_ALL));215DisassemblyData* data = new DisassemblyData(address,next-address,DATATYPE_BYTE);216entries[address] = data;217address = next;218continue;219}220221u32 next = g_symbolMap->GetNextSymbolAddress(address,ST_ALL);222223if ((next % 4) && next != (u32)-1)224{225u32 alignedNext = next & ~3;226227if (alignedNext != address)228{229DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(alignedNext-address)/4);230entries[address] = opcode;231}232233DisassemblyData* data = new DisassemblyData(address,next-alignedNext,DATATYPE_BYTE);234entries[alignedNext] = data;235} else {236DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(next-address)/4);237entries[address] = opcode;238}239240address = next;241continue;242}243244switch (info.type)245{246case ST_FUNCTION:247{248DisassemblyFunction* function = new DisassemblyFunction(info.address,info.size);249entries[info.address] = function;250address = info.address+info.size;251}252break;253case ST_DATA:254{255DisassemblyData* data = new DisassemblyData(info.address,info.size,g_symbolMap->GetDataType(info.address));256entries[info.address] = data;257address = info.address+info.size;258}259break;260default:261break;262}263}264265}266267std::vector<BranchLine> DisassemblyManager::getBranchLines(u32 start, u32 size)268{269std::vector<BranchLine> result;270271std::lock_guard<std::recursive_mutex> guard(entriesLock_);272auto it = findDisassemblyEntry(entries,start,false);273if (it != entries.end())274{275do276{277it->second->getBranchLines(start,size,result);278it++;279} while (it != entries.end() && start+size > it->second->getLineAddress(0));280}281282return result;283}284285void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo &dest, DebugInterface *cpuDebug)286{287// This is here really to avoid lock ordering issues.288auto memLock = Memory::Lock();289std::lock_guard<std::recursive_mutex> guard(entriesLock_);290auto it = findDisassemblyEntry(entries,address,false);291if (it == entries.end())292{293analyze(address);294it = findDisassemblyEntry(entries,address,false);295}296297if (it != entries.end()) {298DisassemblyEntry *entry = it->second;299if (entry->disassemble(address, dest, insertSymbols, cpuDebug))300return;301}302303dest.type = DISTYPE_OTHER;304memset(&dest.info, 0, sizeof(dest.info));305dest.info.opcodeAddress = address;306if (address % 4)307dest.totalSize = ((address+3) & ~3)-address;308else309dest.totalSize = 4;310if (Memory::IsValidRange(address, 4)) {311dest.name = "ERROR";312dest.params = "Disassembly failure";313} else {314dest.name = "-";315dest.params.clear();316}317}318319u32 DisassemblyManager::getStartAddress(u32 address)320{321auto memLock = Memory::Lock();322std::lock_guard<std::recursive_mutex> guard(entriesLock_);323auto it = findDisassemblyEntry(entries,address,false);324if (it == entries.end())325{326analyze(address);327it = findDisassemblyEntry(entries,address,false);328if (it == entries.end())329return address;330}331332DisassemblyEntry* entry = it->second;333int line = entry->getLineNum(address,true);334return entry->getLineAddress(line);335}336337u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n)338{339auto memLock = Memory::Lock();340std::lock_guard<std::recursive_mutex> guard(entriesLock_);341while (Memory::IsValidAddress(address))342{343auto it = findDisassemblyEntry(entries,address,false);344if (it == entries.end())345break;346while (it != entries.end())347{348DisassemblyEntry* entry = it->second;349int oldLineNum = entry->getLineNum(address,true);350if (n <= oldLineNum)351{352return entry->getLineAddress(oldLineNum-n);353}354355address = entry->getLineAddress(0)-1;356n -= oldLineNum+1;357it = findDisassemblyEntry(entries,address,false);358}359360analyze(address-127,128);361}362363return (address - n * 4) & ~3;364}365366u32 DisassemblyManager::getNthNextAddress(u32 address, int n)367{368auto memLock = Memory::Lock();369std::lock_guard<std::recursive_mutex> guard(entriesLock_);370while (Memory::IsValidAddress(address))371{372auto it = findDisassemblyEntry(entries,address,false);373if (it == entries.end()) {374break;375}376377while (it != entries.end())378{379DisassemblyEntry* entry = it->second;380int oldLineNum = entry->getLineNum(address,true);381int oldNumLines = entry->getNumLines();382if (oldLineNum+n < oldNumLines)383{384return entry->getLineAddress(oldLineNum+n);385}386387address = entry->getLineAddress(0)+entry->getTotalSize();388n -= (oldNumLines-oldLineNum);389it = findDisassemblyEntry(entries,address,false);390}391392analyze(address);393}394395return (address + n * 4) & ~3;396}397398DisassemblyManager::~DisassemblyManager() {399}400401void DisassemblyManager::clear()402{403auto memLock = Memory::Lock();404std::lock_guard<std::recursive_mutex> guard(entriesLock_);405for (auto it = entries.begin(); it != entries.end(); it++)406{407delete it->second;408}409entries.clear();410}411412DisassemblyFunction::DisassemblyFunction(u32 _address, u32 _size): address(_address), size(_size)413{414auto memLock = Memory::Lock();415if (!PSP_IsInited())416return;417418hash = computeHash(address,size);419load();420}421422DisassemblyFunction::~DisassemblyFunction() {423clear();424}425426void DisassemblyFunction::recheck()427{428auto memLock = Memory::Lock();429if (!PSP_IsInited())430return;431432HashType newHash = computeHash(address,size);433if (hash != newHash)434{435hash = newHash;436clear();437load();438}439}440441int DisassemblyFunction::getNumLines()442{443std::lock_guard<std::recursive_mutex> guard(lock_);444return (int) lineAddresses.size();445}446447int DisassemblyFunction::getLineNum(u32 address, bool findStart)448{449std::lock_guard<std::recursive_mutex> guard(lock_);450if (findStart)451{452int last = (int)lineAddresses.size() - 1;453for (int i = 0; i < last; i++)454{455u32 next = lineAddresses[i + 1];456if (lineAddresses[i] <= address && next > address)457return i;458}459if (lineAddresses[last] <= address && this->address + this->size > address)460return last;461}462else463{464int last = (int)lineAddresses.size() - 1;465for (int i = 0; i < last; i++)466{467if (lineAddresses[i] == address)468return i;469}470if (lineAddresses[last] == address)471return last;472}473474return 0;475}476477u32 DisassemblyFunction::getLineAddress(int line)478{479std::lock_guard<std::recursive_mutex> guard(lock_);480return lineAddresses[line];481}482483bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)484{485std::lock_guard<std::recursive_mutex> guard(lock_);486auto it = findDisassemblyEntry(entries,address,false);487if (it == entries.end())488return false;489490return it->second->disassemble(address, dest, insertSymbols, cpuDebug);491}492493void DisassemblyFunction::getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest)494{495u32 end = start+size;496497std::lock_guard<std::recursive_mutex> guard(lock_);498for (size_t i = 0; i < lines.size(); i++)499{500BranchLine& line = lines[i];501502u32 first = line.first;503u32 second = line.second;504505// skip branches that are entirely before or entirely after the window506if ((first < start && second < start) ||507(first > end && second > end))508continue;509510dest.push_back(line);511}512}513514#define NUM_LANES 16515516void DisassemblyFunction::generateBranchLines()517{518struct LaneInfo519{520bool used;521u32 end;522};523524LaneInfo lanes[NUM_LANES];525for (int i = 0; i < NUM_LANES; i++)526lanes[i].used = false;527528u32 end = address+size;529530std::lock_guard<std::recursive_mutex> guard(lock_);531DebugInterface* cpu = DisassemblyManager::getCpu();532for (u32 funcPos = address; funcPos < end; funcPos += 4)533{534MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);535536bool inFunction = (opInfo.branchTarget >= address && opInfo.branchTarget < end);537if (opInfo.isBranch && !opInfo.isBranchToRegister && !opInfo.isLinkedBranch && inFunction) {538if (!Memory::IsValidAddress(opInfo.branchTarget))539continue;540541BranchLine line;542if (opInfo.branchTarget < funcPos) {543line.first = opInfo.branchTarget;544line.second = funcPos;545line.type = LINE_UP;546} else {547line.first = funcPos;548line.second = opInfo.branchTarget;549line.type = LINE_DOWN;550}551552lines.push_back(line);553}554}555556std::sort(lines.begin(),lines.end());557for (size_t i = 0; i < lines.size(); i++)558{559for (int l = 0; l < NUM_LANES; l++)560{561if (lines[i].first > lanes[l].end)562lanes[l].used = false;563}564565int lane = -1;566for (int l = 0; l < NUM_LANES; l++)567{568if (lanes[l].used == false)569{570lane = l;571break;572}573}574575if (lane == -1)576{577// Let's just pile on.578lines[i].laneIndex = 15;579continue;580}581582lanes[lane].end = lines[i].second;583lanes[lane].used = true;584lines[i].laneIndex = lane;585}586}587588void DisassemblyFunction::addOpcodeSequence(u32 start, u32 end)589{590DisassemblyOpcode* opcode = new DisassemblyOpcode(start,(end-start)/4);591std::lock_guard<std::recursive_mutex> guard(lock_);592entries[start] = opcode;593lineAddresses.reserve((end - start) / 4);594for (u32 pos = start; pos < end; pos += 4)595{596lineAddresses.push_back(pos);597}598}599600void DisassemblyFunction::load()601{602generateBranchLines();603604// gather all branch targets605std::set<u32> branchTargets;606{607std::lock_guard<std::recursive_mutex> guard(lock_);608for (size_t i = 0; i < lines.size(); i++)609{610switch (lines[i].type)611{612case LINE_DOWN:613branchTargets.insert(lines[i].second);614break;615case LINE_UP:616branchTargets.insert(lines[i].first);617break;618default:619break;620}621}622}623624DebugInterface* cpu = DisassemblyManager::getCpu();625u32 funcPos = address;626u32 funcEnd = address+size;627628u32 nextData = g_symbolMap->GetNextSymbolAddress(funcPos-1,ST_DATA);629u32 opcodeSequenceStart = funcPos;630while (funcPos < funcEnd)631{632if (funcPos == nextData)633{634if (opcodeSequenceStart != funcPos)635addOpcodeSequence(opcodeSequenceStart,funcPos);636637DisassemblyData* data = new DisassemblyData(funcPos,g_symbolMap->GetDataSize(funcPos),g_symbolMap->GetDataType(funcPos));638std::lock_guard<std::recursive_mutex> guard(lock_);639entries[funcPos] = data;640lineAddresses.push_back(funcPos);641funcPos += data->getTotalSize();642643nextData = g_symbolMap->GetNextSymbolAddress(funcPos-1,ST_DATA);644opcodeSequenceStart = funcPos;645continue;646}647648// force align649if (funcPos % 4)650{651u32 nextPos = (funcPos+3) & ~3;652653DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4");654std::lock_guard<std::recursive_mutex> guard(lock_);655entries[funcPos] = comment;656lineAddresses.push_back(funcPos);657658funcPos = nextPos;659opcodeSequenceStart = funcPos;660continue;661}662663MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);664u32 opAddress = funcPos;665funcPos += 4;666667// skip branches and their delay slots668if (opInfo.isBranch)669{670funcPos += 4;671continue;672}673674// lui675if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)676{677MIPSOpcode next = Memory::Read_Instruction(funcPos);678MIPSInfo nextInfo = MIPSGetInfo(next);679680u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next.encoding & 0xFFFF);681int rt = MIPS_GET_RT(opInfo.encodedOpcode);682683int nextRs = MIPS_GET_RS(next.encoding);684int nextRt = MIPS_GET_RT(next.encoding);685686// both rs and rt of the second op have to match rt of the first,687// otherwise there may be hidden consequences if the macro is displayed.688// also, don't create a macro if something branches into the middle of it689if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())690{691DisassemblyMacro* macro = NULL;692switch (MIPS_GET_OP(next.encoding))693{694case 0x09: // addiu695macro = new DisassemblyMacro(opAddress);696macro->setMacroLi(immediate,rt);697funcPos += 4;698break;699case 0x20: // lb700case 0x21: // lh701case 0x23: // lw702case 0x24: // lbu703case 0x25: // lhu704case 0x28: // sb705case 0x29: // sh706case 0x2B: // sw707macro = new DisassemblyMacro(opAddress);708709int dataSize = MIPSGetMemoryAccessSize(next);710if (dataSize == 0) {711delete macro;712return;713}714715macro->setMacroMemory(MIPSGetName(next),immediate,rt,dataSize);716funcPos += 4;717break;718}719720if (macro != NULL)721{722if (opcodeSequenceStart != opAddress)723addOpcodeSequence(opcodeSequenceStart,opAddress);724725std::lock_guard<std::recursive_mutex> guard(lock_);726entries[opAddress] = macro;727for (int i = 0; i < macro->getNumLines(); i++)728{729lineAddresses.push_back(macro->getLineAddress(i));730}731732opcodeSequenceStart = funcPos;733continue;734}735}736}737738// just a normal opcode739}740741if (opcodeSequenceStart != funcPos)742addOpcodeSequence(opcodeSequenceStart,funcPos);743}744745void DisassemblyFunction::clear()746{747std::lock_guard<std::recursive_mutex> guard(lock_);748for (auto it = entries.begin(); it != entries.end(); it++)749{750delete it->second;751}752753entries.clear();754lines.clear();755lineAddresses.clear();756hash = 0;757}758759bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)760{761if (!cpuDebug)762cpuDebug = DisassemblyManager::getCpu();763764char opcode[64],arguments[256];765char dizz[512];766cpuDebug->DisAsm(address, dizz, sizeof(dizz));767parseDisasm(dizz, opcode, sizeof(opcode), arguments, sizeof(arguments), insertSymbols);768dest.type = DISTYPE_OPCODE;769dest.name = opcode;770dest.params = arguments;771dest.totalSize = 4;772dest.info = MIPSAnalyst::GetOpcodeInfo(cpuDebug, address);773return true;774}775776void DisassemblyOpcode::getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest)777{778if (start < address)779{780size = start+size-address;781start = address;782}783784if (start+size > address+num*4)785size = address+num*4-start;786787int lane = 0;788for (u32 pos = start; pos < start+size; pos += 4)789{790MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),pos);791if (info.isBranch && !info.isBranchToRegister && !info.isLinkedBranch) {792if (!Memory::IsValidAddress(info.branchTarget))793continue;794795BranchLine line;796line.laneIndex = lane++;797798if (info.branchTarget < pos) {799line.first = info.branchTarget;800line.second = pos;801line.type = LINE_UP;802} else {803line.first = pos;804line.second = info.branchTarget;805line.type = LINE_DOWN;806}807808dest.push_back(line);809}810}811}812813814void DisassemblyMacro::setMacroLi(u32 _immediate, u8 _rt)815{816type = MACRO_LI;817name = "li";818immediate = _immediate;819rt = _rt;820numOpcodes = 2;821}822823void DisassemblyMacro::setMacroMemory(const std::string &_name, u32 _immediate, u8 _rt, int _dataSize)824{825type = MACRO_MEMORYIMM;826name = _name;827immediate = _immediate;828rt = _rt;829dataSize = _dataSize;830numOpcodes = 2;831}832833bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)834{835if (!cpuDebug)836cpuDebug = DisassemblyManager::getCpu();837838char buffer[64];839dest.type = DISTYPE_MACRO;840dest.info = MIPSAnalyst::GetOpcodeInfo(cpuDebug, address);841842std::string addressSymbol;843switch (type)844{845case MACRO_LI:846dest.name = name;847848addressSymbol = g_symbolMap->GetLabelString(immediate);849if (!addressSymbol.empty() && insertSymbols) {850snprintf(buffer, sizeof(buffer), "%s,%s", cpuDebug->GetRegName(0, rt).c_str(), addressSymbol.c_str());851} else {852snprintf(buffer, sizeof(buffer), "%s,0x%08X", cpuDebug->GetRegName(0, rt).c_str(), immediate);853}854855dest.params = buffer;856857dest.info.hasRelevantAddress = true;858dest.info.relevantAddress = immediate;859break;860case MACRO_MEMORYIMM:861dest.name = name;862863addressSymbol = g_symbolMap->GetLabelString(immediate);864if (!addressSymbol.empty() && insertSymbols) {865snprintf(buffer, sizeof(buffer), "%s,%s", cpuDebug->GetRegName(0, rt).c_str(), addressSymbol.c_str());866} else {867snprintf(buffer, sizeof(buffer), "%s,0x%08X", cpuDebug->GetRegName(0, rt).c_str(), immediate);868}869870dest.params = buffer;871872dest.info.isDataAccess = true;873dest.info.dataAddress = immediate;874dest.info.dataSize = dataSize;875876dest.info.hasRelevantAddress = true;877dest.info.relevantAddress = immediate;878break;879default:880return false;881}882883dest.totalSize = getTotalSize();884return true;885}886887888DisassemblyData::DisassemblyData(u32 _address, u32 _size, DataType _type): address(_address), size(_size), type(_type)889{890auto memLock = Memory::Lock();891if (!PSP_IsInited())892return;893894hash = computeHash(address,size);895createLines();896}897898void DisassemblyData::recheck()899{900auto memLock = Memory::Lock();901if (!PSP_IsInited())902return;903904HashType newHash = computeHash(address,size);905if (newHash != hash)906{907hash = newHash;908createLines();909}910}911912bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)913{914dest.type = DISTYPE_DATA;915916switch (type)917{918case DATATYPE_BYTE:919dest.name = ".byte";920break;921case DATATYPE_HALFWORD:922dest.name = ".half";923break;924case DATATYPE_WORD:925dest.name = ".word";926break;927case DATATYPE_ASCII:928dest.name = ".ascii";929break;930default:931return false;932}933934std::lock_guard<std::recursive_mutex> guard(lock_);935auto it = lines.find(address);936if (it == lines.end())937return false;938939dest.params = it->second.text;940dest.totalSize = it->second.size;941return true;942}943944int DisassemblyData::getLineNum(u32 address, bool findStart)945{946std::lock_guard<std::recursive_mutex> guard(lock_);947auto it = lines.upper_bound(address);948if (it != lines.end())949{950if (it == lines.begin())951return 0;952it--;953return it->second.lineNum;954}955956return lines.rbegin()->second.lineNum;957}958959void DisassemblyData::createLines()960{961std::lock_guard<std::recursive_mutex> guard(lock_);962lines.clear();963lineAddresses.clear();964965u32 pos = address;966u32 end = address+size;967u32 maxChars = DisassemblyManager::getMaxParamChars();968969std::string currentLine;970u32 currentLineStart = pos;971972int lineCount = 0;973if (type == DATATYPE_ASCII)974{975bool inString = false;976while (pos < end)977{978u8 b = Memory::Read_U8(pos++);979if (b >= 0x20 && b <= 0x7F)980{981if (currentLine.size()+1 >= maxChars)982{983if (inString == true)984currentLine += "\"";985986DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};987lines[currentLineStart] = entry;988lineAddresses.push_back(currentLineStart);989990currentLine.clear();991currentLineStart = pos-1;992inString = false;993}994995if (inString == false)996currentLine += "\"";997currentLine += (char)b;998inString = true;999} else {1000char buffer[64];1001if (pos == end && b == 0)1002truncate_cpy(buffer, "0");1003else1004snprintf(buffer, sizeof(buffer), "0x%02X", b);10051006if (currentLine.size()+strlen(buffer) >= maxChars)1007{1008if (inString == true)1009currentLine += "\"";10101011DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};1012lines[currentLineStart] = entry;1013lineAddresses.push_back(currentLineStart);10141015currentLine.clear();1016currentLineStart = pos-1;1017inString = false;1018}10191020bool comma = false;1021if (currentLine.size() != 0)1022comma = true;10231024if (inString)1025currentLine += "\"";10261027if (comma)1028currentLine += ",";10291030currentLine += buffer;1031inString = false;1032}1033}10341035if (inString == true)1036currentLine += "\"";10371038if (currentLine.size() != 0)1039{1040DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};1041lines[currentLineStart] = entry;1042lineAddresses.push_back(currentLineStart);1043}1044} else {1045while (pos < end)1046{1047char buffer[256];1048u32 value;10491050u32 currentPos = pos;10511052switch (type)1053{1054case DATATYPE_BYTE:1055value = Memory::Read_U8(pos);1056snprintf(buffer, sizeof(buffer), "0x%02X", value);1057pos++;1058break;1059case DATATYPE_HALFWORD:1060value = Memory::Read_U16(pos);1061snprintf(buffer, sizeof(buffer), "0x%04X", value);1062pos += 2;1063break;1064case DATATYPE_WORD:1065{1066value = Memory::Read_U32(pos);1067const std::string label = g_symbolMap->GetLabelString(value);1068if (!label.empty())1069snprintf(buffer, sizeof(buffer), "%s", label.c_str());1070else1071snprintf(buffer, sizeof(buffer), "0x%08X", value);1072pos += 4;1073}1074break;1075default:1076break;1077}10781079size_t len = strlen(buffer);1080if (currentLine.size() != 0 && currentLine.size()+len >= maxChars)1081{1082DataEntry entry = {currentLine,currentPos-currentLineStart,lineCount++};1083lines[currentLineStart] = entry;1084lineAddresses.push_back(currentLineStart);10851086currentLine.clear();1087currentLineStart = currentPos;1088}10891090if (currentLine.size() != 0)1091currentLine += ",";1092currentLine += buffer;1093}10941095if (currentLine.size() != 0) {1096DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};1097lines[currentLineStart] = entry;1098lineAddresses.push_back(currentLineStart);1099}1100}1101}110211031104DisassemblyComment::DisassemblyComment(u32 _address, u32 _size, std::string _name, std::string _param)1105: address(_address), size(_size), name(_name), param(_param)1106{11071108}11091110bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)1111{1112dest.type = DISTYPE_OTHER;1113dest.name = name;1114dest.params = param;1115dest.totalSize = size;1116return true;1117}111811191120