From a46371329d97fdad3e2ad67e661d51e312bc1d02 Mon Sep 17 00:00:00 2001 From: Kingcom Date: Tue, 13 Jan 2015 11:24:19 +0100 Subject: [PATCH] core: Implement debug interface and expression parser --- src/common/CMakeLists.txt | 1 - src/common/break_points.cpp | 8 +- src/common/debug_interface.h | 36 ----- src/core/CMakeLists.txt | 2 + src/core/debugger/debug_interface.cpp | 194 ++++++++++++++++++++++++++ src/core/debugger/debug_interface.h | 30 ++++ 6 files changed, 230 insertions(+), 41 deletions(-) delete mode 100644 src/common/debug_interface.h create mode 100644 src/core/debugger/debug_interface.cpp create mode 100644 src/core/debugger/debug_interface.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7256369f7..15e011829 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -36,7 +36,6 @@ set(HEADERS common_types.h concurrent_ring_buffer.h cpu_detect.h - debug_interface.h emu_window.h expression_parser.h extended_trace.h diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp index 6696935fa..de98cd3c4 100644 --- a/src/common/break_points.cpp +++ b/src/common/break_points.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/common.h" -#include "common/debug_interface.h" #include "common/break_points.h" #include @@ -176,11 +175,12 @@ TMemCheck *MemChecks::GetMemCheck(u32 address) void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, bool write, int size, u32 pc) { - if ((write && OnWrite) || (!write && OnRead)) + // it's unused for now anyway +/* if ((write && OnWrite) || (!write && OnRead)) { if (Log) { - LOG_DEBUG(Debug_Breakpoint, "CHK %08x (%s) %s%i %0*x at %08x (%s)", + LOG_DEBUG(Debug_Breakpoint, "CHK %08x (%s) %s%i %0*x at %08x (%s)", pc, debug_interface->getDescription(pc).c_str(), write ? "Write" : "Read", size*8, size*2, iValue, addr, debug_interface->getDescription(addr).c_str() @@ -188,5 +188,5 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, } if (Break) debug_interface->breakNow(); - } + }*/ } diff --git a/src/common/debug_interface.h b/src/common/debug_interface.h deleted file mode 100644 index 32f55cb59..000000000 --- a/src/common/debug_interface.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include - -class DebugInterface -{ -protected: - virtual ~DebugInterface() {} - -public: - virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual void getRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual int getInstructionSize(int /*instruction*/) {return 1;} - virtual bool isAlive() {return true;} - virtual bool isBreakpoint(unsigned int /*address*/) {return false;} - virtual void setBreakpoint(unsigned int /*address*/){} - virtual void clearBreakpoint(unsigned int /*address*/){} - virtual void clearAllBreakpoints() {} - virtual void toggleBreakpoint(unsigned int /*address*/){} - virtual bool isMemCheck(unsigned int /*address*/) {return false;} - virtual void toggleMemCheck(unsigned int /*address*/){} - virtual unsigned int readMemory(unsigned int /*address*/){return 0;} - virtual void writeExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} - virtual unsigned int readExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;} - virtual unsigned int readInstruction(unsigned int /*address*/){return 0;} - virtual unsigned int getPC() {return 0;} - virtual void setPC(unsigned int /*address*/) {} - virtual void step() {} - virtual void runToBreakpoint() {} - virtual void breakNow() {} - virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {} - virtual void showJitResults(unsigned int /*address*/) {}; - virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;} - virtual std::string getDescription(unsigned int /*address*/) = 0; -}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8723a471f..161f1598c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -17,6 +17,7 @@ set(SRCS arm/skyeye_common/vfp/vfpdouble.cpp arm/skyeye_common/vfp/vfpinstr.cpp arm/skyeye_common/vfp/vfpsingle.cpp + debugger/debug_interface.cpp file_sys/archive_extsavedata.cpp file_sys/archive_romfs.cpp file_sys/archive_savedata.cpp @@ -106,6 +107,7 @@ set(HEADERS arm/skyeye_common/vfp/vfp.h arm/skyeye_common/vfp/vfp_helper.h arm/arm_interface.h + debugger/debug_interface.h file_sys/archive_backend.h file_sys/archive_extsavedata.h file_sys/archive_romfs.h diff --git a/src/core/debugger/debug_interface.cpp b/src/core/debugger/debug_interface.cpp new file mode 100644 index 000000000..0a3a8f6a6 --- /dev/null +++ b/src/core/debugger/debug_interface.cpp @@ -0,0 +1,194 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "debug_interface.h" + +#include "core/core.h" +#include "core/arm/arm_interface.h" + +DebugInterface g_debug_interface; +DebugInterface* g_debug = &g_debug_interface; + +const char* reg_names_cat0[] = { + "r0", "r1", "r2", "r3", "r4", + "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", + "r15", "cpsr" +}; + +const char* reg_names_cat1[] = { + "m", "it", "ge", "dnm", +}; + +const char* reg_names_cat2[] = { + "n", "z", "c", "v", "q", "j", + "e", "a", "i", "f", "t" +}; + +const u8 cat2_regs_cpsr_bit_indices[] = { + 31, 30, 29, 38, 27, 24, + 9, 8, 7, 6, 5 +}; + +class ArmExpressionFunctions: public IExpressionFunctions { + +public: + ArmExpressionFunctions(DebugInterface* debug) { + this->debug = debug; + } + + virtual bool parseReference(char* str, uint32& reference_index) override { + // check if it's a register + int index = 0; + for (int i = 0; i < debug->GetNumCategories(); i++) { + for (int l = 0; l < debug->GetNumRegsInCategory(i); l++) { + if (strcasecmp(str,debug->GetRegName(i,l)) == 0) { + reference_index = index; + return true; + } + index++; + } + } + + return false; + } + + virtual bool parseSymbol(char* str, uint32& value) { + // todo: check labels + return false; + } + + virtual uint32 getReferenceValue(uint32 reference_index) { + // find category the index belongs to and return the register value + for (int i = 0; i < debug->GetNumCategories(); i++) { + if (reference_index < debug->GetNumRegsInCategory(i)) + return debug->GetRegValue(i,reference_index); + + reference_index -= debug->GetNumRegsInCategory(i); + } + + // should never be reached + return 0; + } + + virtual ExpressionType getReferenceType(uint32 referenceIndex) { + return EXPR_TYPE_UINT; + } + + virtual bool getMemoryValue(uint32 address, int size, uint32& dest, char* error) { + // todo: implement + return false; + } + +private: + DebugInterface* debug; +}; + + +bool DebugInterface::InitExpression(const char* exp, PostfixExpression& dest) { + ArmExpressionFunctions funcs(this); + return initPostfixExpression(exp,&funcs,dest); +} + +bool DebugInterface::ParseExpression(PostfixExpression& exp, u32& dest) { + ArmExpressionFunctions funcs(this); + return parsePostfixExpression(exp,&funcs,dest); +} + +int DebugInterface::GetNumCategories() { + return 3; +} + +int DebugInterface::GetNumRegsInCategory(int cat) { + switch (cat) { + case 0: + return ARRAY_SIZE(reg_names_cat0); + case 1: + return ARRAY_SIZE(reg_names_cat1); + case 2: + return ARRAY_SIZE(reg_names_cat2); + } + + return 0; +} + +const char *DebugInterface::GetRegName(int cat, int index) { + switch (cat) { + case 0: + return reg_names_cat0[index]; + case 1: + return reg_names_cat1[index]; + case 2: + return reg_names_cat2[index]; + } + + return nullptr; +} + +u32 DebugInterface::GetRegValue(int cat, int index) { + ARM_Interface* app = Core::g_app_core; + if (app == nullptr) + return 0; + + switch (cat) { + case 0: + if (index < 16) + return app->GetReg(index); + return app->GetCPSR(); + case 1: + switch (index) { + case CAT1_REG_M: + return app->GetCPSR() & 0x1F; + case CAT1_REG_IT: + return (app->GetCPSR() >> 10) & 0x3F; + case CAT1_REG_GE: + return (app->GetCPSR() >> 16) & 0xF; + case CAT1_REG_DNM: + return (app->GetCPSR() >> 20) & 0xF; + } + return 0; + case 2: + return (app->GetCPSR() >> cat2_regs_cpsr_bit_indices[index]) & 1; + } +} + +void DebugInterface::SetRegValue(int cat, int index, u32 value) { + ARM_Interface* app = Core::g_app_core; + if (app == nullptr) + return; + + u32 cpsr = app->GetCPSR(); + + switch (cat) { + case 0: + if (index < 16) + app->SetReg(index,value); + else + app->SetCPSR(value); + break; + case 1: + switch (index) { + case CAT1_REG_M: + cpsr = (cpsr & ~0x1F) | (value & 0x1F); + break; + case CAT1_REG_IT: + cpsr = (cpsr & ~(0x3F << 10)) | ((value & 0x3F) << 10); + break; + case CAT1_REG_GE: + cpsr = (cpsr & ~(0xF << 16)) | ((value & 0xF) << 16); + break; + case CAT1_REG_DNM: + cpsr = (cpsr & ~(0xF << 20)) | ((value & 0xF) << 20); + break; + } + app->SetCPSR(cpsr); + break; + case 2: + cpsr &= ~(1 << cat2_regs_cpsr_bit_indices[index]); + if (value != 0) + cpsr |= 1 << cat2_regs_cpsr_bit_indices[index]; + app->SetCPSR(cpsr); + break; + } +} diff --git a/src/core/debugger/debug_interface.h b/src/core/debugger/debug_interface.h new file mode 100644 index 000000000..5e711bd62 --- /dev/null +++ b/src/core/debugger/debug_interface.h @@ -0,0 +1,30 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/expression_parser.h" + +enum RegisterCategory { REGCAT_GPR = 0, REGCAT_CPSR_FIELDS, REGCAT_CPSR_FLAGS }; +enum Cat1Registers { CAT1_REG_M, CAT1_REG_IT, CAT1_REG_GE, CAT1_REG_DNM }; + +class DebugInterface { +public: + ~DebugInterface() {} + + bool InitExpression(const char* exp, PostfixExpression& dest); + bool ParseExpression(PostfixExpression& exp, u32& dest); + + u32 GetPC() { return GetRegValue(REGCAT_GPR,15); } + int GetNumCategories(); + int GetNumRegsInCategory(int cat); + const char *GetRegName(int cat, int index); + u32 GetRegValue(int cat, int index); + void SetRegValue(int cat, int index, u32 value); +}; + +extern DebugInterface* g_debug;