mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-10-08 03:13:25 +00:00
ARM64 disassembler improvements (show many kinds of branch targets properly)
This commit is contained in:
parent
4c4e95743a
commit
8914cd9914
@ -18,6 +18,17 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "StringUtils.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 parseHexLong(std::string s) {
|
||||||
long value = 0;
|
long value = 0;
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
|
||||||
|
void truncate_cpy(char *dest, size_t destSize, const char *src);
|
||||||
|
|
||||||
long parseHexLong(std::string s);
|
long parseHexLong(std::string s);
|
||||||
long parseLong(std::string s);
|
long parseLong(std::string s);
|
||||||
std::string StringFromFormat(const char* format, ...);
|
std::string StringFromFormat(const char* format, ...);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "profiler/profiler.h"
|
#include "profiler/profiler.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CPUDetect.h"
|
#include "Common/CPUDetect.h"
|
||||||
|
#include "Common/StringUtils.h"
|
||||||
|
|
||||||
#include "Core/Reporting.h"
|
#include "Core/Reporting.h"
|
||||||
#include "Core/Config.h"
|
#include "Core/Config.h"
|
||||||
@ -350,8 +351,39 @@ void Arm64Jit::AddContinuedBlock(u32 dest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Arm64Jit::DescribeCodePtr(const u8 *ptr, std::string &name) {
|
bool Arm64Jit::DescribeCodePtr(const u8 *ptr, std::string &name) {
|
||||||
// TODO: Not used by anything yet (except the modified VerySleepy on Windows)
|
// Used in disassembly viewer.
|
||||||
return false;
|
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<int> 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) {
|
void Arm64Jit::Comp_RunBlock(MIPSOpcode op) {
|
||||||
@ -385,7 +417,7 @@ bool Arm64Jit::ReplaceJalTo(u32 dest) {
|
|||||||
QuickCallFunction(SCRATCH1_64, (const void *)(entry->replaceFunc));
|
QuickCallFunction(SCRATCH1_64, (const void *)(entry->replaceFunc));
|
||||||
ApplyRoundingMode();
|
ApplyRoundingMode();
|
||||||
LoadStaticRegisters();
|
LoadStaticRegisters();
|
||||||
WriteDownCountR(W0);
|
WriteDownCountR(W0); // W0 is the return value from entry->replaceFunc. Neither LoadStaticRegisters nor ApplyRoundingMode can trash it.
|
||||||
}
|
}
|
||||||
|
|
||||||
js.compilerPC += 4;
|
js.compilerPC += 4;
|
||||||
|
@ -94,6 +94,18 @@ std::string AddAddress(const std::string &buf, uint64_t addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ARM64) || defined(DISASM_ALL)
|
#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<std::string> DisassembleArm64(const u8 *data, int size) {
|
std::vector<std::string> DisassembleArm64(const u8 *data, int size) {
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
@ -118,7 +130,7 @@ std::vector<std::string> DisassembleArm64(const u8 *data, int size) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Arm64Dis((intptr_t)codePtr, inst, temp, sizeof(temp), false);
|
Arm64Dis((intptr_t)codePtr, inst, temp, sizeof(temp), false, Arm64SymbolCallback);
|
||||||
std::string buf = temp;
|
std::string buf = temp;
|
||||||
if (buf == "BKPT 1") {
|
if (buf == "BKPT 1") {
|
||||||
bkpt_count++;
|
bkpt_count++;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "Common/Arm64Emitter.h"
|
#include "Common/Arm64Emitter.h"
|
||||||
#include "Common/StringUtils.h"
|
#include "Common/StringUtils.h"
|
||||||
|
#include "Core/Util/DisArm64.h"
|
||||||
|
|
||||||
struct Instruction {
|
struct Instruction {
|
||||||
char text[128];
|
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 Rt = w & 0x1f;
|
||||||
int Rn = (w >> 5) & 0x1f;
|
int Rn = (w >> 5) & 0x1f;
|
||||||
if (((w >> 26) & 0x1F) == 5) {
|
if (((w >> 26) & 0x1F) == 5) {
|
||||||
// Unconditional branch / branch+link
|
// Unconditional branch / branch+link
|
||||||
int offset = SignExtend26(w) << 2;
|
int offset = SignExtend26(w) << 2;
|
||||||
uint64_t target = addr + offset;
|
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) {
|
} else if (((w >> 25) & 0x3F) == 0x1A) {
|
||||||
// Compare and branch
|
// Compare and branch
|
||||||
int op = (w >> 24) & 1;
|
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));
|
memset(instr, 0, sizeof(*instr));
|
||||||
|
|
||||||
// Identify the main encoding groups. See C3.1 A64 instruction index by encoding
|
// 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);
|
DataProcessingImmediate(w, addr, instr);
|
||||||
break;
|
break;
|
||||||
case 0xA: case 0xB:
|
case 0xA: case 0xB:
|
||||||
BranchExceptionAndSystem(w, addr, instr);
|
BranchExceptionAndSystem(w, addr, instr, symbolCallback);
|
||||||
break;
|
break;
|
||||||
case 4: case 6: case 0xC: case 0xE:
|
case 4: case 6: case 0xC: case 0xE:
|
||||||
LoadStore(w, addr, instr);
|
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;
|
Instruction instr;
|
||||||
DisassembleInstruction(w, addr, &instr);
|
DisassembleInstruction(w, addr, &instr, symbolCallback);
|
||||||
char temp[256];
|
char temp[256];
|
||||||
if (includeWord) {
|
if (includeWord) {
|
||||||
snprintf(output, bufsize, "%08x\t%s", w, instr.text);
|
snprintf(output, bufsize, "%08x\t%s", w, instr.text);
|
||||||
|
@ -20,5 +20,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user