From 8914cd9914745b54c12da960d32d39bc5581805f Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 10 Oct 2015 11:27:28 +0200 Subject: [PATCH] ARM64 disassembler improvements (show many kinds of branch targets properly) --- Common/StringUtils.cpp | 11 +++++++++ Common/StringUtils.h | 2 ++ Core/MIPS/ARM64/Arm64Jit.cpp | 38 ++++++++++++++++++++++++++++--- Core/MIPS/JitCommon/JitCommon.cpp | 14 +++++++++++- Core/Util/DisArm64.cpp | 18 ++++++++++----- Core/Util/DisArm64.h | 4 +++- 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index ff0378e31c..1946d0df92 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -18,6 +18,17 @@ #include "Common.h" #include "StringUtils.h" +void truncate_cpy(char *dest, size_t destSize, const char *src) { + size_t len = strlen(src); + if (len >= destSize - 1) { + memcpy(dest, src, destSize - 1); + dest[destSize - 1] = '\0'; + } else { + memcpy(dest, src, len); + dest[len] = '\0'; + } +} + long parseHexLong(std::string s) { long value = 0; diff --git a/Common/StringUtils.h b/Common/StringUtils.h index d9cdbd9bc9..a7b699962f 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -22,6 +22,8 @@ #include "Common.h" +void truncate_cpy(char *dest, size_t destSize, const char *src); + long parseHexLong(std::string s); long parseLong(std::string s); std::string StringFromFormat(const char* format, ...); diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index a8770bba29..caf882a384 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -19,6 +19,7 @@ #include "profiler/profiler.h" #include "Common/ChunkFile.h" #include "Common/CPUDetect.h" +#include "Common/StringUtils.h" #include "Core/Reporting.h" #include "Core/Config.h" @@ -350,8 +351,39 @@ void Arm64Jit::AddContinuedBlock(u32 dest) { } bool Arm64Jit::DescribeCodePtr(const u8 *ptr, std::string &name) { - // TODO: Not used by anything yet (except the modified VerySleepy on Windows) - return false; + // Used in disassembly viewer. + if (ptr == applyRoundingMode) + name = "applyRoundingMode"; + else if (ptr == updateRoundingMode) + name = "updateRoundingMode"; + else if (ptr == dispatcher) + name = "dispatcher"; + else if (ptr == dispatcherPCInSCRATCH1) + name = "dispatcher (PC in SCRATCH1)"; + else if (ptr == dispatcherNoCheck) + name = "dispatcherNoCheck"; + else if (ptr == enterDispatcher) + name = "enterDispatcher"; + else if (ptr == restoreRoundingMode) + name = "restoreRoundingMode"; + else if (ptr == saveStaticRegisters) + name = "saveStaticRegisters"; + else if (ptr == loadStaticRegisters) + name = "loadStaticRegisters"; + else { + u32 addr = blocks.GetAddressFromBlockPtr(ptr); + std::vector numbers; + blocks.GetBlockNumbersFromAddress(addr, &numbers); + if (!numbers.empty()) { + const JitBlock *block = blocks.GetBlock(numbers[0]); + if (block) { + name = StringFromFormat("(block %d at %08x)", numbers[0], block->originalAddress); + return true; + } + } + return false; + } + return true; } void Arm64Jit::Comp_RunBlock(MIPSOpcode op) { @@ -385,7 +417,7 @@ bool Arm64Jit::ReplaceJalTo(u32 dest) { QuickCallFunction(SCRATCH1_64, (const void *)(entry->replaceFunc)); ApplyRoundingMode(); LoadStaticRegisters(); - WriteDownCountR(W0); + WriteDownCountR(W0); // W0 is the return value from entry->replaceFunc. Neither LoadStaticRegisters nor ApplyRoundingMode can trash it. } js.compilerPC += 4; diff --git a/Core/MIPS/JitCommon/JitCommon.cpp b/Core/MIPS/JitCommon/JitCommon.cpp index 0591f5b286..26c2954a6f 100644 --- a/Core/MIPS/JitCommon/JitCommon.cpp +++ b/Core/MIPS/JitCommon/JitCommon.cpp @@ -94,6 +94,18 @@ std::string AddAddress(const std::string &buf, uint64_t addr) { } #if defined(ARM64) || defined(DISASM_ALL) + +static bool Arm64SymbolCallback(char *buffer, int bufsize, uint8_t *address) { + if (MIPSComp::jit) { + std::string name; + if (MIPSComp::jit->DescribeCodePtr(address, name)) { + truncate_cpy(buffer, bufsize, name.c_str()); + return true; + } + } + return false; +} + std::vector DisassembleArm64(const u8 *data, int size) { std::vector lines; @@ -118,7 +130,7 @@ std::vector DisassembleArm64(const u8 *data, int size) { continue; } } - Arm64Dis((intptr_t)codePtr, inst, temp, sizeof(temp), false); + Arm64Dis((intptr_t)codePtr, inst, temp, sizeof(temp), false, Arm64SymbolCallback); std::string buf = temp; if (buf == "BKPT 1") { bkpt_count++; diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index 3eb5de9e74..dc4ca3e80d 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -25,6 +25,7 @@ #include "Common/Arm64Emitter.h" #include "Common/StringUtils.h" +#include "Core/Util/DisArm64.h" struct Instruction { char text[128]; @@ -200,14 +201,19 @@ static const char *GetSystemRegName(int o0, int op1, int CRn, int CRm, int op2) } } -static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *instr) { +static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *instr, SymbolCallback symbolCallback) { + char buffer[128]; int Rt = w & 0x1f; int Rn = (w >> 5) & 0x1f; if (((w >> 26) & 0x1F) == 5) { // Unconditional branch / branch+link int offset = SignExtend26(w) << 2; uint64_t target = addr + offset; - snprintf(instr->text, sizeof(instr->text), "b%s %04x%08x", (w >> 31) ? "l" : "", (uint32_t)(target >> 32), (uint32_t)(target & 0xFFFFFFFF)); + if (symbolCallback && symbolCallback(buffer, sizeof(buffer), (uint8_t *)(uintptr_t)target)) { + snprintf(instr->text, sizeof(instr->text), "b%s %s", (w >> 31) ? "l" : "", buffer); + } else { + snprintf(instr->text, sizeof(instr->text), "b%s %04x%08x", (w >> 31) ? "l" : "", (uint32_t)(target >> 32), (uint32_t)(target & 0xFFFFFFFF)); + } } else if (((w >> 25) & 0x3F) == 0x1A) { // Compare and branch int op = (w >> 24) & 1; @@ -994,7 +1000,7 @@ static void FPandASIMD2(uint32_t w, uint64_t addr, Instruction *instr) { } } -static void DisassembleInstruction(uint32_t w, uint64_t addr, Instruction *instr) { +static void DisassembleInstruction(uint32_t w, uint64_t addr, Instruction *instr, SymbolCallback symbolCallback) { memset(instr, 0, sizeof(*instr)); // Identify the main encoding groups. See C3.1 A64 instruction index by encoding @@ -1007,7 +1013,7 @@ static void DisassembleInstruction(uint32_t w, uint64_t addr, Instruction *instr DataProcessingImmediate(w, addr, instr); break; case 0xA: case 0xB: - BranchExceptionAndSystem(w, addr, instr); + BranchExceptionAndSystem(w, addr, instr, symbolCallback); break; case 4: case 6: case 0xC: case 0xE: LoadStore(w, addr, instr); @@ -1024,9 +1030,9 @@ static void DisassembleInstruction(uint32_t w, uint64_t addr, Instruction *instr } } -void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord) { +void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord, SymbolCallback symbolCallback) { Instruction instr; - DisassembleInstruction(w, addr, &instr); + DisassembleInstruction(w, addr, &instr, symbolCallback); char temp[256]; if (includeWord) { snprintf(output, bufsize, "%08x\t%s", w, instr.text); diff --git a/Core/Util/DisArm64.h b/Core/Util/DisArm64.h index 0125aa01a2..fc55c6c34b 100644 --- a/Core/Util/DisArm64.h +++ b/Core/Util/DisArm64.h @@ -20,5 +20,7 @@ #include -void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord); +typedef bool (*SymbolCallback)(char *buffer, int bufsize, uint8_t *address); + +void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord, SymbolCallback symbolCallback = nullptr);