mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 01:10:09 +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
|
||||
concurrent_ring_buffer.h
|
||||
cpu_detect.h
|
||||
debug_interface.h
|
||||
emu_window.h
|
||||
expression_parser.h
|
||||
extended_trace.h
|
||||
|
@ -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 <sstream>
|
||||
@ -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();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
@ -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/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
|
||||
|
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