mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 03:31:04 +00:00
core: Implement debug interface and expression parser
This commit is contained in:
parent
3e255d7b98
commit
a46371329d
@ -36,7 +36,6 @@ set(HEADERS
|
|||||||
common_types.h
|
common_types.h
|
||||||
concurrent_ring_buffer.h
|
concurrent_ring_buffer.h
|
||||||
cpu_detect.h
|
cpu_detect.h
|
||||||
debug_interface.h
|
|
||||||
emu_window.h
|
emu_window.h
|
||||||
expression_parser.h
|
expression_parser.h
|
||||||
extended_trace.h
|
extended_trace.h
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "common/debug_interface.h"
|
|
||||||
#include "common/break_points.h"
|
#include "common/break_points.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -176,11 +175,12 @@ TMemCheck *MemChecks::GetMemCheck(u32 address)
|
|||||||
void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr,
|
void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr,
|
||||||
bool write, int size, u32 pc)
|
bool write, int size, u32 pc)
|
||||||
{
|
{
|
||||||
if ((write && OnWrite) || (!write && OnRead))
|
// it's unused for now anyway
|
||||||
|
/* if ((write && OnWrite) || (!write && OnRead))
|
||||||
{
|
{
|
||||||
if (Log)
|
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(),
|
pc, debug_interface->getDescription(pc).c_str(),
|
||||||
write ? "Write" : "Read", size*8, size*2, iValue, addr,
|
write ? "Write" : "Read", size*8, size*2, iValue, addr,
|
||||||
debug_interface->getDescription(addr).c_str()
|
debug_interface->getDescription(addr).c_str()
|
||||||
@ -188,5 +188,5 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr,
|
|||||||
}
|
}
|
||||||
if (Break)
|
if (Break)
|
||||||
debug_interface->breakNow();
|
debug_interface->breakNow();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
@ -17,6 +17,7 @@ set(SRCS
|
|||||||
arm/skyeye_common/vfp/vfpdouble.cpp
|
arm/skyeye_common/vfp/vfpdouble.cpp
|
||||||
arm/skyeye_common/vfp/vfpinstr.cpp
|
arm/skyeye_common/vfp/vfpinstr.cpp
|
||||||
arm/skyeye_common/vfp/vfpsingle.cpp
|
arm/skyeye_common/vfp/vfpsingle.cpp
|
||||||
|
debugger/debug_interface.cpp
|
||||||
file_sys/archive_extsavedata.cpp
|
file_sys/archive_extsavedata.cpp
|
||||||
file_sys/archive_romfs.cpp
|
file_sys/archive_romfs.cpp
|
||||||
file_sys/archive_savedata.cpp
|
file_sys/archive_savedata.cpp
|
||||||
@ -106,6 +107,7 @@ set(HEADERS
|
|||||||
arm/skyeye_common/vfp/vfp.h
|
arm/skyeye_common/vfp/vfp.h
|
||||||
arm/skyeye_common/vfp/vfp_helper.h
|
arm/skyeye_common/vfp/vfp_helper.h
|
||||||
arm/arm_interface.h
|
arm/arm_interface.h
|
||||||
|
debugger/debug_interface.h
|
||||||
file_sys/archive_backend.h
|
file_sys/archive_backend.h
|
||||||
file_sys/archive_extsavedata.h
|
file_sys/archive_extsavedata.h
|
||||||
file_sys/archive_romfs.h
|
file_sys/archive_romfs.h
|
||||||
|
194
src/core/debugger/debug_interface.cpp
Normal file
194
src/core/debugger/debug_interface.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
30
src/core/debugger/debug_interface.h
Normal file
30
src/core/debugger/debug_interface.h
Normal file
@ -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 <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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;
|
Loading…
Reference in New Issue
Block a user