core: Implement debug interface and expression parser

This commit is contained in:
Kingcom 2015-01-13 11:24:19 +01:00
parent 3e255d7b98
commit a46371329d
6 changed files with 230 additions and 41 deletions

View File

@ -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

View File

@ -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,7 +175,8 @@ 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)
{
@ -188,5 +188,5 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr,
}
if (Break)
debug_interface->breakNow();
}
}*/
}

View File

@ -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;
};

View File

@ -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

View 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;
}
}

View 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;