mirror of
https://github.com/mupen64plus/mupen64plus-core.git
synced 2024-06-02 19:27:51 -04:00
gdb stub
This commit is contained in:
parent
fba8a57cf1
commit
83df1b49a5
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,5 @@
|
|||
/projects/unix/_obj*/
|
||||
/projects/unix/libmupen64plus*.so*
|
||||
/.vscode
|
||||
/projects/unix/*.dll
|
||||
/src/asm_defines/*.h
|
|
@ -729,16 +729,17 @@ ifeq ($(DEBUGGER), 1)
|
|||
$(SRCDIR)/debugger/dbg_debugger.c \
|
||||
$(SRCDIR)/debugger/dbg_decoder.c \
|
||||
$(SRCDIR)/debugger/dbg_memory.c \
|
||||
$(SRCDIR)/debugger/dbg_breakpoints.c
|
||||
LDLIBS += -lopcodes -lbfd
|
||||
$(SRCDIR)/debugger/dbg_breakpoints.c \
|
||||
$(SRCDIR)/debugger/gdbstub/gdbstub.cpp
|
||||
LDLIBS += -lopcodes -lbfd -liberty -lintl -liconv -lsframe -lz -lzstd -lSDL2_net
|
||||
|
||||
# UGLY libopcodes/libbfd version check (we check for >= 2.28 and >= 2.39)
|
||||
LIBOPCODES_VERSION := $(shell $(STRINGS) --version | head -n1 | rev | cut -d ' ' -f1 | rev)
|
||||
LIBOPCODES_MAJOR := $(shell echo $(LIBOPCODES_VERSION) | cut -f1 -d.)
|
||||
LIBOPCODES_MINOR := $(shell echo $(LIBOPCODES_VERSION) | cut -f2 -d.)
|
||||
LIBOPCODES_POINT := $(shell echo $(LIBOPCODES_VERSION) | cut -f3 -d.)
|
||||
LIBOPCODES_GE_2_29 := $(shell [ $(LIBOPCODES_MAJOR) -gt 2 -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -ge 29 \) -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -eq 28 -a $(LIBOPCODES_POINT) -ge 1 \) ] && echo true)
|
||||
LIBBFD_GE_2_39 := $(shell [ $(LIBOPCODES_MAJOR) -gt 2 -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -ge 29 \) -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -eq 39 -a $(LIBOPCODES_POINT) -ge 1 \) ] && echo true)
|
||||
LIBOPCODES_POINT := $(shell echo $(LIBOPCODES_VERSION) | cut -f3 -d. | sed 's/^$$/0/')
|
||||
LIBOPCODES_GE_2_29 := $(shell [ $(LIBOPCODES_MAJOR) -gt 2 -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -ge 28 \) -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -eq 28 -a $(LIBOPCODES_POINT) -ge 1 \) ] && echo true)
|
||||
LIBBFD_GE_2_39 := $(shell [ $(LIBOPCODES_MAJOR) -gt 2 -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -ge 39 \) -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -eq 39 -a $(LIBOPCODES_POINT) -ge 1 \) ] && echo true)
|
||||
ifeq ($(LIBOPCODES_GE_2_29),true)
|
||||
CFLAGS += -DUSE_LIBOPCODES_GE_2_29
|
||||
endif
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
#include "m64p_frontend.h"
|
||||
#include "m64p_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos)))
|
||||
#else
|
||||
|
@ -41,5 +46,9 @@ extern m64p_error SetStateCallback(ptr_StateCallback pFunc, void *Context);
|
|||
extern void DebugMessage(int level, const char *message, ...) ATTR_FMT(2,3);
|
||||
extern void StateChanged(m64p_core_param param_type, int new_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* API_CALLBACKS_H */
|
||||
|
||||
|
|
|
@ -447,7 +447,7 @@ EXPORT uint32_t CALL DebugVirtualToPhysical(uint32_t address)
|
|||
struct r4300_core* r4300 = &dev->r4300;
|
||||
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address(r4300, address, 0);
|
||||
address = virtual_to_physical_address_no_tlb_refill_exception(r4300, address, 0);
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "main/netplay.h"
|
||||
#include "plugin/plugin.h"
|
||||
#include "vidext.h"
|
||||
#include "debugger/gdbstub/gdbstub.h"
|
||||
|
||||
/* some local state variables */
|
||||
static int l_CoreInit = 0;
|
||||
|
@ -108,6 +109,10 @@ EXPORT m64p_error CALL CoreStartup(int APIVersion, const char *ConfigPath, const
|
|||
|
||||
workqueue_init();
|
||||
|
||||
#if defined(DBG)
|
||||
gdbstub_init();
|
||||
#endif
|
||||
|
||||
l_CoreInit = 1;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct memory;
|
||||
|
||||
extern int g_NumBreakpoints;
|
||||
|
@ -43,5 +48,9 @@ int lookup_breakpoint(uint32_t address, uint32_t size, uint32_t flags);
|
|||
int log_breakpoint(uint32_t PC, uint32_t Flag, uint32_t Access);
|
||||
void replace_breakpoint_num(struct memory* mem, int, m64p_breakpoint*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BREAKPOINTS_H__ */
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbg_breakpoints.h"
|
||||
#include "dbg_debugger.h"
|
||||
#include "dbg_memory.h"
|
||||
#include "gdbstub/gdbstub.h"
|
||||
|
||||
#ifdef DBG
|
||||
|
||||
|
@ -94,6 +95,7 @@ void update_debugger(uint32_t pc)
|
|||
DebuggerCallback(DEBUG_UI_UPDATE, pc); /* call front-end to notify user interface to update */
|
||||
}
|
||||
if (g_dbg_runstate == M64P_DBG_RUNSTATE_PAUSED) {
|
||||
gdb_try_send_signal_stop();
|
||||
// The emulation thread is blocked until a step call via the API.
|
||||
SDL_SemWait(sem_pending_steps);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
|
||||
#include "api/m64p_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern int g_DebuggerActive; /* True if the debugger is running */
|
||||
|
||||
extern m64p_dbg_runstate g_dbg_runstate;
|
||||
|
@ -39,5 +44,9 @@ void update_debugger(uint32_t pc);
|
|||
void destroy_debugger(void);
|
||||
void debugger_step(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DBG_DEBUGGER_H__ */
|
||||
|
||||
|
|
296
src/debugger/gdbstub/gdbstub.cpp
Normal file
296
src/debugger/gdbstub/gdbstub.cpp
Normal file
|
@ -0,0 +1,296 @@
|
|||
#include <SDL.h>
|
||||
#include <SDL_net.h>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include "gdbstub.h"
|
||||
#include "api/callbacks.h"
|
||||
#include "../dbg_debugger.h"
|
||||
#include "../dbg_breakpoints.h"
|
||||
#include "device/r4300/tlb.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#define BUFFER_SIZE 8192
|
||||
|
||||
char gdb_buffer[BUFFER_SIZE];
|
||||
|
||||
char gdb_send_buffer[BUFFER_SIZE];
|
||||
|
||||
TCPsocket gdb_socket;
|
||||
|
||||
auto sendLength = 0;
|
||||
|
||||
int gdb_loop(void *x);
|
||||
void gdb_send_signal_stop();
|
||||
void set_checksum_and_sendlength(int hash_index);
|
||||
uint32_t DebugVirtualToPhysical(uint32_t address);
|
||||
|
||||
void gdbstub_init() {
|
||||
#if SDL_VERSION_ATLEAST(2,0,0)
|
||||
SDL_CreateThread(gdb_loop, "gdb_loop", NULL);
|
||||
#else
|
||||
SDL_CreateThread(gdb_loop, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
int gdb_loop(void *x) {
|
||||
if(SDL_Init(0) == -1) {
|
||||
DebugMessage(M64MSG_ERROR, "Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
if(SDLNet_Init() == -1) {
|
||||
DebugMessage(M64MSG_ERROR, "Gdb stub: Could not initialize SDL Net library");
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
IPaddress serverIP;
|
||||
SDLNet_ResolveHost(&serverIP, NULL, 5555);
|
||||
auto serverSocket = SDLNet_TCP_Open(&serverIP);
|
||||
if(serverSocket == nullptr) {
|
||||
DebugMessage(M64MSG_ERROR, "Gdb stub: Server socket creation failed");
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
gdb_socket = SDLNet_TCP_Accept(serverSocket);
|
||||
|
||||
while(gdb_socket != nullptr)
|
||||
{
|
||||
auto recvLength = SDLNet_TCP_Recv(gdb_socket, gdb_buffer, BUFFER_SIZE - 1);
|
||||
if(recvLength <= 0) {
|
||||
DebugMessage(M64MSG_ERROR, "Gdb stub: TCP receive error");
|
||||
break;
|
||||
}
|
||||
|
||||
auto& qSupported = "qSupported";
|
||||
if(gdb_buffer[0] == '-') {
|
||||
sendLength = 0;
|
||||
} else if(gdb_buffer[0] == '+') {
|
||||
gdb_send_buffer[0] = '+';
|
||||
sendLength = 1;
|
||||
} else if(gdb_buffer[0] == '\x03') {
|
||||
g_dbg_runstate = M64P_DBG_RUNSTATE_PAUSED;
|
||||
} else if(memcmp(gdb_buffer + 1, qSupported, sizeof(qSupported) - 1) == 0) {
|
||||
auto& supported = "$PacketSize=1400;hwbreak+;";
|
||||
strncpy(gdb_send_buffer, supported, sizeof(supported) - 1);
|
||||
set_checksum_and_sendlength(sizeof(supported) - 1);
|
||||
} else if(gdb_buffer[1] == 'g') {
|
||||
auto regs = r4300_regs(&g_dev.r4300);
|
||||
gdb_send_buffer[0] = '$';
|
||||
for(auto i = 0; i < 32; i++) {
|
||||
snprintf(gdb_send_buffer + 1 + i * 16, 17, "%016" SCNx64, regs[i]);
|
||||
}
|
||||
|
||||
auto cp0reg = r4300_cp0_regs(&g_dev.r4300.cp0);
|
||||
snprintf(gdb_send_buffer + 1 + 32 * 16, 17, "%016" SCNx64, (uint64_t) cp0reg[CP0_STATUS_REG]);
|
||||
snprintf(gdb_send_buffer + 1 + 33 * 16, 17, "%016" SCNx64, (uint64_t) g_dev.r4300.lo);
|
||||
snprintf(gdb_send_buffer + 1 + 34 * 16, 17, "%016" SCNx64, (uint64_t) g_dev.r4300.hi);
|
||||
snprintf(gdb_send_buffer + 1 + 35 * 16, 17, "%016" SCNx64, (uint64_t) cp0reg[CP0_BADVADDR_REG]);
|
||||
snprintf(gdb_send_buffer + 1 + 36 * 16, 17, "%016" SCNx64, (uint64_t) cp0reg[CP0_CAUSE_REG]);
|
||||
snprintf(gdb_send_buffer + 1 + 37 * 16, 17, "%016" SCNx64, (uint64_t) *r4300_pc(&g_dev.r4300));
|
||||
|
||||
const auto reg_len = 8 * 2;
|
||||
const auto non_gen_reg_count = 6;
|
||||
const auto non_gen_reg_total_size = reg_len * non_gen_reg_count;
|
||||
|
||||
const auto gen_reg_count = 32;
|
||||
const auto gen_reg_total_size = reg_len * gen_reg_count;
|
||||
int message_end = 1 + gen_reg_total_size + non_gen_reg_total_size;
|
||||
|
||||
set_checksum_and_sendlength(message_end);
|
||||
} else if(gdb_buffer[1] == 'G') {
|
||||
auto regs = r4300_regs(&g_dev.r4300);
|
||||
|
||||
for(auto i = 0; i < 32; i++) {
|
||||
uint64_t data;
|
||||
char buf[17];
|
||||
strncpy(buf, gdb_buffer + 2 + i * 16, sizeof(buf) - 1);
|
||||
buf[16] = '\0';
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
regs[i] = data;
|
||||
}
|
||||
|
||||
auto cp0reg = r4300_cp0_regs(&g_dev.r4300.cp0);
|
||||
|
||||
uint64_t data;
|
||||
const auto hex16str = sizeof("XXXXXXXXXXXXXXXX");
|
||||
char buf[hex16str];
|
||||
buf[hex16str - 1] = '\0';
|
||||
strncpy(buf, gdb_buffer + 2 + 32 * 16, sizeof(buf) - 1);
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
cp0reg[CP0_STATUS_REG] = data;
|
||||
strncpy(buf, gdb_buffer + 2 + 33 * 16, sizeof(buf) - 1);
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
g_dev.r4300.lo = data;
|
||||
strncpy(buf, gdb_buffer + 2 + 34 * 16, sizeof(buf) - 1);
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
g_dev.r4300.hi = data;
|
||||
strncpy(buf, gdb_buffer + 2 + 35 * 16, sizeof(buf) - 1);
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
cp0reg[CP0_BADVADDR_REG] = data;
|
||||
strncpy(buf, gdb_buffer + 2 + 36 * 16, sizeof(buf) - 1);
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
cp0reg[CP0_CAUSE_REG] = data;
|
||||
strncpy(buf, gdb_buffer + 2 + 37 * 16, sizeof(buf) - 1);
|
||||
sscanf(buf, "%" SCNx64, &data);
|
||||
*r4300_pc(&g_dev.r4300) = data;
|
||||
|
||||
strncpy(gdb_send_buffer, "$OK", sizeof("$OK") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$OK") - 1);
|
||||
} else if(gdb_buffer[1] == '?') {
|
||||
//a ? is sent on connection by gdb
|
||||
if(g_dbg_runstate == M64P_DBG_RUNSTATE_PAUSED) {
|
||||
auto& reply = "$S05";
|
||||
strncpy(gdb_send_buffer, reply, sizeof(reply) - 1);
|
||||
set_checksum_and_sendlength(sizeof(reply) - 1);
|
||||
}
|
||||
else g_dbg_runstate = M64P_DBG_RUNSTATE_PAUSED;
|
||||
} else if(gdb_buffer[1] == 's') {
|
||||
debugger_step();
|
||||
} else if(gdb_buffer[1] == 'c') {
|
||||
g_dbg_runstate = M64P_DBG_RUNSTATE_RUNNING;
|
||||
debugger_step();
|
||||
} else if(gdb_buffer[1] == 'Z' || gdb_buffer[1] == 'z') {
|
||||
unsigned int address;
|
||||
unsigned int kind; //for read/write, this is size bytes to watch at addr
|
||||
sscanf(gdb_buffer + 4, "%x,%x", &address, &kind);
|
||||
|
||||
auto execbk = gdb_buffer[2] == '0' || gdb_buffer[2] == '1';
|
||||
auto writebk = gdb_buffer[2] == '2';
|
||||
auto readbk = gdb_buffer[2] == '3';
|
||||
|
||||
unsigned int flags = M64P_BKP_FLAG_ENABLED | (
|
||||
execbk ? M64P_BKP_FLAG_EXEC :
|
||||
writebk ? M64P_BKP_FLAG_WRITE :
|
||||
readbk ? M64P_BKP_FLAG_READ :
|
||||
M64P_BKP_FLAG_WRITE | M64P_BKP_FLAG_READ);
|
||||
|
||||
if(!execbk) address = DebugVirtualToPhysical(address);
|
||||
|
||||
m64p_breakpoint bkpt = {
|
||||
.address = address,
|
||||
.endaddr = execbk ? address : address + kind,
|
||||
.flags = flags
|
||||
};
|
||||
|
||||
if(gdb_buffer[1] == 'Z') {
|
||||
auto num = add_breakpoint_struct(&g_dev.mem, &bkpt);
|
||||
if(num == -1) {
|
||||
strncpy(gdb_send_buffer, "$E01", sizeof("$E01") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$E01") - 1);
|
||||
} else {
|
||||
enable_breakpoint(&g_dev.mem, num);
|
||||
strncpy(gdb_send_buffer, "$OK", sizeof("$OK") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$OK") - 1);
|
||||
}
|
||||
} else {
|
||||
remove_breakpoint_by_address(&g_dev.mem, address);
|
||||
strncpy(gdb_send_buffer, "$OK", sizeof("$OK") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$OK") - 1);
|
||||
}
|
||||
} else if(gdb_buffer[1] == 'm') {
|
||||
unsigned int address;
|
||||
unsigned int length;
|
||||
sscanf(gdb_buffer + 2, "%x,%x", &address, &length);
|
||||
|
||||
auto start = fast_mem_access_no_tlb_refill_exception(&g_dev.r4300, address);
|
||||
if(start == nullptr) {
|
||||
strncpy(gdb_send_buffer, "$E01", sizeof("$E01") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$E01") - 1);
|
||||
} else {
|
||||
gdb_send_buffer[0] = '$';
|
||||
|
||||
auto initialOffset = address & 0x3;
|
||||
auto wordCount = ((initialOffset + length + 0x3) & ~0x3) >> 2;
|
||||
for(unsigned int wordi = 0; wordi < wordCount; wordi++) {
|
||||
auto word = start[wordi];
|
||||
for(unsigned int bytei = wordi == 0 ? initialOffset : 0, writei = (unsigned int)0; wordi * 4 - initialOffset + bytei < length && bytei < 4; bytei++, writei++) {
|
||||
auto byte = (word >> (3 - bytei) * 8) & 0xFF;
|
||||
snprintf(gdb_send_buffer + 1 + wordi * 4 + writei * 2, 3, "%02x", byte);
|
||||
}
|
||||
}
|
||||
|
||||
set_checksum_and_sendlength(1 + length * 2);
|
||||
}
|
||||
} else if(gdb_buffer[1] == 'M') {
|
||||
unsigned int address;
|
||||
unsigned int length;
|
||||
sscanf(gdb_buffer + 2, "%x,%x", &address, &length);
|
||||
|
||||
auto start = fast_mem_access_no_tlb_refill_exception(&g_dev.r4300, address);
|
||||
if(start == nullptr) {
|
||||
strncpy(gdb_send_buffer, "$E01", sizeof("$E01") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$E01") - 1);
|
||||
} else {
|
||||
auto initialOffset = address & 0x3;
|
||||
auto wordCount = ((initialOffset + length + 0x3) & ~0x3) >> 2;
|
||||
auto bytes = strchr(gdb_buffer, ':');
|
||||
for(unsigned int wordi = 0; wordi < wordCount; wordi++) {
|
||||
auto word = &start[wordi];
|
||||
for(unsigned int bytei = wordi == 0 ? initialOffset : 0, writei = (unsigned int)0; wordi * 4 - initialOffset + bytei < length && bytei < 4; bytei++, writei++) {
|
||||
unsigned int data;
|
||||
char buf[3];
|
||||
buf[2] = '\0';
|
||||
strncpy(buf, bytes + 1 + wordi * 4 + writei * 2, sizeof(buf) - 1);
|
||||
sscanf(buf, "%02x", &data);
|
||||
|
||||
auto mask = 0xFF << (3 - bytei) * 8;
|
||||
*word &= ~mask;
|
||||
*word |= data << (3 - bytei) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(gdb_send_buffer, "$OK", sizeof("$OK") - 1);
|
||||
set_checksum_and_sendlength(sizeof("$OK") - 1);
|
||||
}
|
||||
} else {
|
||||
auto& emptyReply = "$#00";
|
||||
strncpy(gdb_send_buffer, emptyReply, sizeof(emptyReply) - 1);
|
||||
sendLength = sizeof(emptyReply) - 1;
|
||||
}
|
||||
|
||||
SDLNet_TCP_Send(gdb_socket, gdb_send_buffer, sendLength);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gdb_try_send_signal_stop() {
|
||||
if(gdb_socket == nullptr) return;
|
||||
gdb_send_signal_stop();
|
||||
}
|
||||
|
||||
void set_checksum_and_sendlength(int hash_index) {
|
||||
gdb_send_buffer[hash_index] = '#';
|
||||
auto checkSend = std::accumulate(gdb_send_buffer + 1, gdb_send_buffer + hash_index, 0) % 256;
|
||||
snprintf(gdb_send_buffer + hash_index + 1, 3, "%02x", checkSend);
|
||||
sendLength = hash_index + sizeof("#XX") - 1;
|
||||
}
|
||||
|
||||
void gdb_send_signal_stop()
|
||||
{
|
||||
char stopb[7];
|
||||
auto& reply = "$S05#";
|
||||
strncpy(stopb, reply, sizeof(reply) - 1);
|
||||
auto checkSend = std::accumulate(reply + 1, reply + sizeof(reply) - 2, 0) % 256;
|
||||
snprintf(stopb + sizeof(reply) - 1, 3, "%02x", checkSend);
|
||||
auto sendLength = sizeof(reply) - 1 + 2;
|
||||
SDLNet_TCP_Send(gdb_socket, stopb, sendLength);
|
||||
}
|
||||
|
||||
uint32_t DebugVirtualToPhysical(uint32_t address)
|
||||
{
|
||||
struct device* dev = &g_dev;
|
||||
struct r4300_core* r4300 = &dev->r4300;
|
||||
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address_no_tlb_refill_exception(r4300, address, 0);
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
address &= UINT32_C(0x1fffffff);
|
||||
return address;
|
||||
}
|
11
src/debugger/gdbstub/gdbstub.h
Normal file
11
src/debugger/gdbstub/gdbstub.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void gdbstub_init();
|
||||
|
||||
void gdb_try_send_signal_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -297,6 +297,20 @@ uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address)
|
|||
return mem_base_u32(r4300->mem->base, address);
|
||||
}
|
||||
|
||||
uint32_t *fast_mem_access_no_tlb_refill_exception(struct r4300_core* r4300, uint32_t address)
|
||||
{
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address_no_tlb_refill_exception(r4300, address, 2);
|
||||
if (address == 0) // TLB exception
|
||||
return NULL;
|
||||
}
|
||||
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
|
||||
return mem_base_u32(r4300->mem->base, address);
|
||||
}
|
||||
|
||||
|
||||
/* Read aligned word from memory.
|
||||
* address may not be word-aligned for byte or hword accesses.
|
||||
* Alignment is taken care of when calling mem handler.
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef M64P_DEVICE_R4300_R4300_CORE_H
|
||||
#define M64P_DEVICE_R4300_R4300_CORE_H
|
||||
|
||||
|
@ -233,6 +238,7 @@ unsigned int get_r4300_emumode(struct r4300_core* r4300);
|
|||
* Can access RDRAM, SP_DMEM, SP_IMEM and ROM, using TLB if necessary
|
||||
* Useful for getting fast access to a zone with executable code. */
|
||||
uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address);
|
||||
uint32_t *fast_mem_access_no_tlb_refill_exception(struct r4300_core* r4300, uint32_t address);
|
||||
|
||||
int r4300_read_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t* value);
|
||||
int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t* value);
|
||||
|
@ -254,3 +260,7 @@ void generic_jump_to(struct r4300_core* r4300, unsigned int address);
|
|||
void savestates_load_set_pc(struct r4300_core* r4300, uint32_t pc);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -100,7 +100,7 @@ void tlb_map(struct tlb* tlb, size_t entry)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w)
|
||||
uint32_t virtual_to_physical_address_no_tlb_refill_exception(struct r4300_core* r4300, uint32_t address, int w)
|
||||
{
|
||||
const struct tlb* tlb = &r4300->cp0.tlb;
|
||||
unsigned int addr = address >> 12;
|
||||
|
@ -140,8 +140,16 @@ uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address,
|
|||
//printf("tlb exception !!! @ %x, %x, add:%x\n", address, w, r4300->pc->addr);
|
||||
//getchar();
|
||||
|
||||
TLB_refill_exception(r4300, address, w);
|
||||
|
||||
//return 0x80000000;
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w)
|
||||
{
|
||||
uint32_t physicalAddress = virtual_to_physical_address_no_tlb_refill_exception(r4300, address, w);
|
||||
|
||||
TLB_refill_exception(r4300, address, w);
|
||||
|
||||
return physicalAddress;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct r4300_core;
|
||||
|
||||
struct tlb_entry
|
||||
|
@ -65,5 +70,10 @@ void tlb_unmap(struct tlb* tlb, size_t entry);
|
|||
void tlb_map(struct tlb* tlb, size_t entry);
|
||||
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w);
|
||||
uint32_t virtual_to_physical_address_no_tlb_refill_exception(struct r4300_core* r4300, uint32_t address, int w);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* M64P_DEVICE_R4300_TLB_H */
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
#include "device/device.h"
|
||||
#include "osal/preproc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos)))
|
||||
#else
|
||||
|
@ -103,5 +108,9 @@ m64p_error main_reset(int do_hard_reset);
|
|||
|
||||
m64p_error open_pif(const unsigned char* pifimage, unsigned int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAIN_H__ */
|
||||
|
||||
|
|
Loading…
Reference in a new issue