Implement untested breakpoints

This commit is contained in:
BullyWiiPlaza 2017-05-17 15:45:45 +02:00
parent ef1a572d65
commit c2fd5d1bb2
7 changed files with 166 additions and 10 deletions

13
src/breakpoints/bit.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef TCPGECKO_BIT_UTILITIES_H
#define TCPGECKO_BIT_UTILITIES_H
// http://stackoverflow.com/a/47990/3764804
inline unsigned int setBit(unsigned int value, bool bit, int bitIndex) {
return value | (bit << bitIndex);
}
inline bool getBit(unsigned int value, int bitIndex) {
return ((value >> bitIndex) & 1) == 1;
}
#endif

View File

@ -0,0 +1,87 @@
#include "bit.h"
#include "stringify.h"
#ifndef TCPGECKO_BREAKPOINTS_H
#define TCPGECKO_BREAKPOINTS_H
/* Breakpoint types
#define BREAKPOINT_READ 0x01
#define BREAKPOINT_WRITE 0x02 */
struct DataBreakpoint {
unsigned int value;
bool translate;
bool write;
bool read;
} __attribute__((packed));
// Special purpose registers
#define INSTRUCTION_ADDRESS_BREAKPOINT_REGISTER 0x3F2
#define DATA_ADDRESS_BREAKPOINT_REGISTER 0x3F5
// Data address breakpoint bit indices
#define TRANSLATE_BIT_INDEX 29
#define WRITE_BIT_INDEX 30
#define READ_BIT_INDEX 31
// http://www.ds.ewi.tudelft.nl/vakken/in1006/instruction-set/mtspr.html
#define moveToSpecialPurposeRegister(specialPurposeRegister, value) \
__asm__ __volatile__ ("mtspr %0, %1" : : "K" (specialPurposeRegister), "r" (value)) \
// http://elixir.free-electrons.com/linux/v2.6.24/source/include/asm-powerpc/reg.h#L713
#define moveFromSpecialPurposeRegister(specialPurposeRegister) \
({unsigned int value; \
asm volatile("mfspr %0, " __stringify(specialPurposeRegister) : "=r" (value)); \
value;}) \
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.alangref/idalangref_isync_ics_instrs.htm
static inline void synchronizeInstructions() {
__asm__ __volatile__ ("isync" : : : "memory");
}
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.alangref/idalangref_eieio_instrs.htm
static inline void enforeInOrderExecutionOfIO() {
__asm__ __volatile__ ("eieio" : : : "memory");
}
static inline void setDataAddressBreakpointRegister(struct DataBreakpoint dataBreakpoint) {
unsigned int value = dataBreakpoint.value;
// Breakpoint translation
value = setBit(value, dataBreakpoint.translate, TRANSLATE_BIT_INDEX);
// Write breakpoint
value = setBit(value, dataBreakpoint.write, WRITE_BIT_INDEX);
// Read breakpoint
value = setBit(value, dataBreakpoint.read, READ_BIT_INDEX);
moveToSpecialPurposeRegister(DATA_ADDRESS_BREAKPOINT_REGISTER, value);
synchronizeInstructions();
}
static inline struct DataBreakpoint getDataAddressBreakpointRegisterContents(struct DataBreakpoint dataBreakpoint) {
unsigned int value = moveFromSpecialPurposeRegister(DATA_ADDRESS_BREAKPOINT_REGISTER);
dataBreakpoint.translate = getBit(value, TRANSLATE_BIT_INDEX);
dataBreakpoint.write = getBit(value, WRITE_BIT_INDEX);
dataBreakpoint.read = getBit(value, READ_BIT_INDEX);
value = setBit(value, 0, TRANSLATE_BIT_INDEX);
value = setBit(value, 0, WRITE_BIT_INDEX);
value = setBit(value, 0, READ_BIT_INDEX);
dataBreakpoint.value = value;
return dataBreakpoint;
}
// https://www.manualslib.com/manual/606065/Ibm-Powerpc-750gx.html?page=64
static inline void setInstructionAddressBreakpointRegister(unsigned int address) {
moveToSpecialPurposeRegister(INSTRUCTION_ADDRESS_BREAKPOINT_REGISTER, address);
synchronizeInstructions();
}
static inline int getInstructionAddressBreakpointRegister() {
return moveFromSpecialPurposeRegister(INSTRUCTION_ADDRESS_BREAKPOINT_REGISTER);
}
#endif

View File

@ -0,0 +1,8 @@
#ifndef TCPGECKO_STRING_H
#define TCPGECKO_STRING_H
// http://elixir.free-electrons.com/linux/v2.6.24/source/include/linux/stringify.h#L9
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
#endif

View File

@ -1,4 +1,3 @@
#include <string.h>
#include "dynamic_libs/os_functions.h"
#include "dynamic_libs/gx2_functions.h"
#include "dynamic_libs/socket_functions.h"

View File

@ -19,8 +19,6 @@
bool isCodeHandlerInstalled;
// TODO Make sure accessing the browser does not freeze the console
#define PRINT_TEXT2(x, y, ...) { snprintf(messageBuffer, 80, __VA_ARGS__); OSScreenPutFontEx(0, x, y, messageBuffer); OSScreenPutFontEx(1, x, y, messageBuffer); }
typedef enum {

View File

@ -15,6 +15,7 @@
#include "system/exception_handler.h"
#include "utils/logger.h"
#include "system/memory.h"
#include "breakpoints/breakpoints.h"
void *client;
void *commandBlock;
@ -58,7 +59,11 @@ struct pygecko_bss_t {
#define COMMAND_RESUME_CONSOLE 0x83
#define COMMAND_IS_CONSOLE_PAUSED 0x84
#define COMMAND_SERVER_VERSION 0x99
#define COMMAND_OS_VERSION 0x9A
#define COMMAND_GET_OS_VERSION 0x9A
#define COMMAND_SET_DATA_BREAKPOINT 0xA0
#define COMMAND_GET_DATA_BREAKPOINT 0xA1
#define COMMAND_SET_INSTRUCTION_BREAKPOINT 0xA2
#define COMMAND_GET_INSTRUCTION_BREAKPOINT 0xA3
#define COMMAND_RUN_KERNEL_COPY_SERVICE 0xCD
#define COMMAND_IOSUHAX_READ_FILE 0xD0
#define COMMAND_GET_VERSION_HASH 0xE0
@ -1420,18 +1425,63 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
strcpy(versionBuffer, SERVER_VERSION);
int versionLength = strlen(versionBuffer);
((int *) buffer)[0] = versionLength;
memcpy(buffer + 4, versionBuffer, versionLength);
memcpy(buffer + sizeof(int), versionBuffer, versionLength);
// Send the length and the version string
ret = sendwait(bss, clientfd, buffer, 4 + versionLength);
ret = sendwait(bss, clientfd, buffer, sizeof(int) + versionLength);
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (server version)");
break;
}
case COMMAND_OS_VERSION: {
case COMMAND_GET_OS_VERSION: {
((int *) buffer)[0] = (int) OS_FIRMWARE;
ret = sendwait(bss, clientfd, buffer, 4);
CHECK_ERROR(ret < 0)
ret = sendwait(bss, clientfd, buffer, sizeof(int));
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (OS version)");
break;
}
case COMMAND_SET_DATA_BREAKPOINT: {
ret = recvwait(bss, clientfd, buffer, 4 + 3 * 1);
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (data breakpoint)");
int bufferIndex = 0;
unsigned int address = ((unsigned int *) buffer)[bufferIndex];
bufferIndex += 4;
bool translate = buffer[bufferIndex++];
bool write = buffer[bufferIndex++];
bool read = buffer[bufferIndex];
struct DataBreakpoint dataBreakpoint;
dataBreakpoint.value = address;
dataBreakpoint.translate = translate;
dataBreakpoint.write = write;
dataBreakpoint.read = read;
setDataAddressBreakpointRegister(dataBreakpoint);
break;
}
case COMMAND_GET_DATA_BREAKPOINT: {
struct DataBreakpoint dataBreakpoint;
getDataAddressBreakpointRegisterContents(dataBreakpoint);
int structureSize = sizeof(dataBreakpoint);
memcpy(buffer, (const void *) &dataBreakpoint, structureSize);
ret = sendwait(bss, clientfd, buffer, structureSize);
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (data breakpoint)");
break;
}
case COMMAND_SET_INSTRUCTION_BREAKPOINT: {
// Read the address and set the breakpoint execute
ret = recvwait(bss, clientfd, buffer, sizeof(int));
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (instruction breakpoint)");
unsigned int address = ((unsigned int *) buffer)[0];
setInstructionAddressBreakpointRegister(address);
break;
}
case COMMAND_GET_INSTRUCTION_BREAKPOINT: {
int address = getInstructionAddressBreakpointRegister();
((int *) buffer)[0] = address;
ret = sendwait(bss, clientfd, buffer, sizeof(int));
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (instruction breakpoint)");
break;
}
@ -1443,10 +1493,11 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
break;
}
default:
default: {
reportIllegalCommandByte(ret);
break;
}
}
}

Binary file not shown.