Implement untested breakpoints
This commit is contained in:
parent
ef1a572d65
commit
c2fd5d1bb2
13
src/breakpoints/bit.h
Normal file
13
src/breakpoints/bit.h
Normal 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
|
87
src/breakpoints/breakpoints.h
Normal file
87
src/breakpoints/breakpoints.h
Normal 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
|
8
src/breakpoints/stringify.h
Normal file
8
src/breakpoints/stringify.h
Normal 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
|
@ -1,4 +1,3 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "dynamic_libs/os_functions.h"
|
#include "dynamic_libs/os_functions.h"
|
||||||
#include "dynamic_libs/gx2_functions.h"
|
#include "dynamic_libs/gx2_functions.h"
|
||||||
#include "dynamic_libs/socket_functions.h"
|
#include "dynamic_libs/socket_functions.h"
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
bool isCodeHandlerInstalled;
|
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); }
|
#define PRINT_TEXT2(x, y, ...) { snprintf(messageBuffer, 80, __VA_ARGS__); OSScreenPutFontEx(0, x, y, messageBuffer); OSScreenPutFontEx(1, x, y, messageBuffer); }
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "system/exception_handler.h"
|
#include "system/exception_handler.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include "system/memory.h"
|
#include "system/memory.h"
|
||||||
|
#include "breakpoints/breakpoints.h"
|
||||||
|
|
||||||
void *client;
|
void *client;
|
||||||
void *commandBlock;
|
void *commandBlock;
|
||||||
@ -58,7 +59,11 @@ struct pygecko_bss_t {
|
|||||||
#define COMMAND_RESUME_CONSOLE 0x83
|
#define COMMAND_RESUME_CONSOLE 0x83
|
||||||
#define COMMAND_IS_CONSOLE_PAUSED 0x84
|
#define COMMAND_IS_CONSOLE_PAUSED 0x84
|
||||||
#define COMMAND_SERVER_VERSION 0x99
|
#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_RUN_KERNEL_COPY_SERVICE 0xCD
|
||||||
#define COMMAND_IOSUHAX_READ_FILE 0xD0
|
#define COMMAND_IOSUHAX_READ_FILE 0xD0
|
||||||
#define COMMAND_GET_VERSION_HASH 0xE0
|
#define COMMAND_GET_VERSION_HASH 0xE0
|
||||||
@ -1420,18 +1425,63 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
strcpy(versionBuffer, SERVER_VERSION);
|
strcpy(versionBuffer, SERVER_VERSION);
|
||||||
int versionLength = strlen(versionBuffer);
|
int versionLength = strlen(versionBuffer);
|
||||||
((int *) buffer)[0] = versionLength;
|
((int *) buffer)[0] = versionLength;
|
||||||
memcpy(buffer + 4, versionBuffer, versionLength);
|
memcpy(buffer + sizeof(int), versionBuffer, versionLength);
|
||||||
|
|
||||||
// Send the length and the version string
|
// 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)");
|
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (server version)");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_OS_VERSION: {
|
case COMMAND_GET_OS_VERSION: {
|
||||||
((int *) buffer)[0] = (int) OS_FIRMWARE;
|
((int *) buffer)[0] = (int) OS_FIRMWARE;
|
||||||
ret = sendwait(bss, clientfd, buffer, 4);
|
ret = sendwait(bss, clientfd, buffer, sizeof(int));
|
||||||
CHECK_ERROR(ret < 0)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@ -1443,10 +1493,11 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
reportIllegalCommandByte(ret);
|
reportIllegalCommandByte(ret);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
tcpgecko.elf
BIN
tcpgecko.elf
Binary file not shown.
Loading…
Reference in New Issue
Block a user