From cd7ecb4ef46e97e76126c7dec2c6c800c187c81f Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Thu, 21 Sep 2023 16:15:25 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86stub=E5=92=8C?= =?UTF-8?q?=E9=83=A8=E5=88=86ptrace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- src/arch/riscv64/include/gdbstub.h | 12 + src/arch/riscv64/include/ptrace.h | 11 + src/arch/riscv64/kernel/gdbstub.c | 1784 ++++++++++++++++++++++++++++ src/arch/riscv64/kernel/ptrac.c | 313 +++++ src/arch/riscv64/kernel/trap.c | 5 + src/include/base/process.h | 2 + src/include/base/ptrace.h | 87 ++ src/include/base/thread.h | 1 + src/ipc/signal.c | 4 + src/kernel/Kconfig | 4 + src/process/process.c | 2 + src/process/syscall.c | 7 + src/sched/thread.c | 2 + 14 files changed, 2236 insertions(+), 1 deletion(-) create mode 100644 src/arch/riscv64/include/gdbstub.h create mode 100644 src/arch/riscv64/include/ptrace.h create mode 100644 src/arch/riscv64/kernel/gdbstub.c create mode 100644 src/arch/riscv64/kernel/ptrac.c create mode 100644 src/include/base/ptrace.h diff --git a/.gitignore b/.gitignore index 0bb6e87..27f3b4d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ src/platform/Kconfig src/include/nx_configure.h platform.mk rootfs.cpio -rootfs.img \ No newline at end of file +rootfs.img +build \ No newline at end of file diff --git a/src/arch/riscv64/include/gdbstub.h b/src/arch/riscv64/include/gdbstub.h new file mode 100644 index 0000000..d4e4d03 --- /dev/null +++ b/src/arch/riscv64/include/gdbstub.h @@ -0,0 +1,12 @@ + + +#ifndef RISCV_GDB_STUB +#define RISCV_GDB_STUB + + +#include +#include + +void GdbStubTrapHandler(NX_HalTrapFrame *frame); + +#endif \ No newline at end of file diff --git a/src/arch/riscv64/include/ptrace.h b/src/arch/riscv64/include/ptrace.h new file mode 100644 index 0000000..fc72109 --- /dev/null +++ b/src/arch/riscv64/include/ptrace.h @@ -0,0 +1,11 @@ +#ifndef __PTRACE_RISCV_H__ +#define __PTRACE_RISCV_H__ +#include "base/error.h" +#include "base/ptrace.h" + +#define gdb_c_ebreak_instruction 0x9002 +#define gdb_ebreak_instruction 0x00100073 + +NX_Error Ptrace(enum __ptrace_requese request, NX_I32 tid, void * addr, void * data); + +#endif \ No newline at end of file diff --git a/src/arch/riscv64/kernel/gdbstub.c b/src/arch/riscv64/kernel/gdbstub.c new file mode 100644 index 0000000..7500743 --- /dev/null +++ b/src/arch/riscv64/kernel/gdbstub.c @@ -0,0 +1,1784 @@ +#include +#include +#include +#include +#include + + +#define GDB_EOF -1 +#define GDB_PRINT(...) +#define PKT_BUF_LEN 4096 + +#ifndef __GDB_MAX_BREAKPOINTS_NUM_ +#define __GDB_MAX_BREAKPOINTS_NUM_ 100 +#endif + +#ifndef __GDB_MAX_WATCHPOINTS_NUM_ +#define __GDB_MAX_WATCHPOINTS_NUM_ 100 +#endif + +#define insert_break_or_watchpoint_software_breakpoint 0 +#define insert_break_or_watchpoint_hardware_breakpoint 1 +#define insert_break_or_watchpoint_write_watchpoint 2 +#define insert_break_or_watchpoint_read_watchpoint 3 +#define insert_break_or_watchpoint_access_watchpoint 4 + +#define gdb_c_ebreak_instruction 0x9002 +#define gdb_ebreak_instruction 0x00100073 + +typedef NX_U64 reg; +typedef NX_Addr address; + +enum GDB_REGISTER { + GDB_CPU_RISCV_REG_X0 = 0, + GDB_CPU_RISCV_REG_RA = 1, + GDB_CPU_RISCV_REG_SP = 2, + GDB_CPU_RISCV_REG_GP = 3, + GDB_CPU_RISCV_REG_TP = 4, + GDB_CPU_RISCV_REG_T0 = 5, + GDB_CPU_RISCV_REG_T1 = 6, + GDB_CPU_RISCV_REG_T2 = 7, + GDB_CPU_RISCV_REG_S0 = 8, + GDB_CPU_RISCV_REG_S1 = 9, + GDB_CPU_RISCV_REG_A0 = 10, + GDB_CPU_RISCV_REG_A1 = 11, + GDB_CPU_RISCV_REG_A2 = 12, + GDB_CPU_RISCV_REG_A3 = 13, + GDB_CPU_RISCV_REG_A4 = 14, + GDB_CPU_RISCV_REG_A5 = 15, + GDB_CPU_RISCV_REG_A6 = 16, + GDB_CPU_RISCV_REG_A7 = 17, + GDB_CPU_RISCV_REG_S2 = 18, + GDB_CPU_RISCV_REG_S3 = 19, + GDB_CPU_RISCV_REG_S4 = 20, + GDB_CPU_RISCV_REG_S5 = 21, + GDB_CPU_RISCV_REG_S6 = 22, + GDB_CPU_RISCV_REG_S7 = 23, + GDB_CPU_RISCV_REG_S8 = 24, + GDB_CPU_RISCV_REG_S9 = 25, + GDB_CPU_RISCV_REG_S10 = 26, + GDB_CPU_RISCV_REG_S11 = 27, + GDB_CPU_RISCV_REG_T3 = 28, + GDB_CPU_RISCV_REG_T4 = 29, + GDB_CPU_RISCV_REG_T5 = 30, + GDB_CPU_RISCV_REG_T6 = 31, + GDB_CPU_RISCV_REG_PC = 32, + GDB_CPU_NUM_REGISTERS = 33 +}; + +typedef struct GdbState { + int signum; + // lastbp >=0 means the last 'step' command's instruction is a breakpoint + // lastbp == -1 means the last 'step' command's instruction is not a + // breakpoint lastbp == -2 means there is no step command + int lastbp; + NX_U32 tmp_instruction; + reg registers[GDB_CPU_NUM_REGISTERS]; +} GdbState; + +typedef struct { + volatile NX_U64 en; + volatile NX_U8 type; + volatile NX_U64 addr; + volatile NX_U64 len; + volatile NX_U32 instruction; +} gdb_bkp_or_watch_t; + + +void gdb_sys_init(void); +static int gdb_sys_getc(struct GdbState *state); +static int gdb_sys_putchar(struct GdbState *state, int ch); +static int gdb_sys_mem_readb(struct GdbState *state, address addr, char *val); +static int gdb_sys_mem_writeb(struct GdbState *state, address addr, char val); + +/***************************************************************************** + * Types + ****************************************************************************/ + +typedef int (*gdb_enc_func)(char *buf, unsigned int buf_len, const char *data, + unsigned int data_len); +typedef int (*gdb_dec_func)(const char *buf, unsigned int buf_len, char *data, + unsigned int data_len); + +/***************************************************************************** + * Const Data + ****************************************************************************/ + +const char digits[17] = "0123456789abcdef"; + +/***************************************************************************** + * Prototypes + ****************************************************************************/ + +/* Communication functions */ +static int gdb_write(struct GdbState *state, const char *buf, + unsigned int len); +static int gdb_read(struct GdbState *state, char *buf, unsigned int buf_len, + unsigned int len); + +/* String processing helper functions */ +static int gdb_strlen(const char *ch); +#if DEBUG +static int gdb_is_printable_char(char ch); +#endif +static char gdb_get_digit(int val); +static int gdb_get_val(char digit, int base); +static int gdb_strtoi(const char *str, unsigned int len, int base, + const char **endptr); +static long gdb_strtol(const char *str, unsigned int len, int base, + const char **endptr); + +/* Packet functions */ +static int gdb_send_packet(struct GdbState *state, const char *pkt, + unsigned int pkt_len); +static int gdb_recv_packet(struct GdbState *state, char *pkt_buf, + unsigned int pkt_buf_len, unsigned int *pkt_len); +static int gdb_checksum(const char *buf, unsigned int len); +static int gdb_recv_ack(struct GdbState *state); + +/* Data encoding/decoding */ +static int gdb_enc_hex(char *buf, unsigned int buf_len, const char *data, + unsigned int data_len); +static int gdb_dec_hex(const char *buf, unsigned int buf_len, char *data, + unsigned int data_len); +static int gdb_enc_bin(char *buf, unsigned int buf_len, const char *data, + unsigned int data_len); +static int gdb_dec_bin(const char *buf, unsigned int buf_len, char *data, + unsigned int data_len); + +/* Packet creation helpers */ +static int gdb_send_ok_packet(struct GdbState *state, char *buf, + unsigned int buf_len); +static int gdb_send_conmsg_packet(struct GdbState *state, char *buf, + unsigned int buf_len, const char *msg); +static int gdb_send_signal_packet(struct GdbState *state, char *buf, + unsigned int buf_len, char signal); +static int gdb_send_error_packet(struct GdbState *state, char *buf, + unsigned int buf_len, char error); + +/* Command functions */ +static int gdb_mem_read(struct GdbState *state, char *buf, + unsigned int buf_len, address addr, unsigned int len, + gdb_enc_func enc); +static int gdb_mem_write(struct GdbState *state, const char *buf, + unsigned int buf_len, address addr, unsigned int len, + gdb_dec_func dec); +static int gdb_continue(struct GdbState *state); +static int gdb_step(struct GdbState *state); + + + +static GdbState gdbStateGlobal; +static int isStartEbreakExectued; +static gdb_bkp_or_watch_t gdb_bkp_buf[__GDB_MAX_BREAKPOINTS_NUM_]; +static gdb_bkp_or_watch_t gdb_watch_buf[__GDB_MAX_WATCHPOINTS_NUM_]; + +/* + * Write one character to the debugging stream. + */ +static int gdb_sys_putchar(struct GdbState *state, int ch) { + // tode + return ch; +} + +/* + * Read one character from the debugging stream. + */ +static int gdb_sys_getc(struct GdbState *state) { + // todo + return 0; +} + +/* + * Read one byte from memory. + */ +static int gdb_sys_mem_readb(struct GdbState *state, address addr, char *val) { + *val = *(volatile char *)addr; + return 0; +} + +static int gdb_sys_mem_read2b(struct GdbState *state, address addr, + NX_U16 *val) { + *val = *(volatile NX_U16 *)addr; + return 0; +} + +static int gdb_sys_mem_read4b(struct GdbState *state, address addr, + NX_U32 *val) { + *val = *(volatile NX_U32 *)addr; + return 0; +} + +/* + * Write one byte to memory. + */ +static int gdb_sys_mem_writeb(struct GdbState *state, address addr, char val) { + *(volatile char *)addr = val; + return 0; +} + +static int gdb_sys_mem_write2b(struct GdbState *state, address addr, + NX_U16 val) { + *(volatile NX_U16 *)addr = val; + return 0; +} + +static int gdb_sys_mem_write4b(struct GdbState *state, address addr, + NX_U32 val) { + *(volatile NX_U32 *)addr = val; + return 0; +} + + + +/* + * Write a sequence of bytes. + * + * Returns: + * 0 if successful + * GDB_EOF if failed to write all bytes + */ +static int gdb_write(struct GdbState *state, const char *buf, + unsigned int len) { + while (len--) { + if (gdb_sys_putchar(state, *buf++) == GDB_EOF) { + return GDB_EOF; + } + } + + return 0; +} + +/* + * Read a sequence of bytes. + * + * Returns: + * 0 if successfully read len bytes + * GDB_EOF if failed to read all bytes + */ +static int gdb_read(struct GdbState *state, char *buf, unsigned int buf_len, + unsigned int len) { + char c; + + if (buf_len < len) { + /* Buffer too small */ + return GDB_EOF; + } + + while (len--) { + if ((c = gdb_sys_getc(state)) == GDB_EOF) { + return GDB_EOF; + } + *buf++ = c; + } + + return 0; +} + + +/***************************************************************************** + * String Processing Helper Functions + ****************************************************************************/ + +/* + * Get null-terminated string length. + */ +static int gdb_strlen(const char *ch) { + int len; + + len = 0; + while (*ch++) { + len += 1; + } + + return len; +} + +/* + * Get integer value for a string representation. + * + * If the string starts with + or -, it will be signed accordingly. + * + * If base == 0, the base will be determined: + * base 16 if the string starts with 0x or 0X, + * base 10 otherwise + * + * If endptr is specified, it will point to the last non-digit in the + * string. If there are no digits in the string, it will be set to NX_NULL. + */ +static int gdb_strtoi(const char *str, unsigned int len, int base, + const char **endptr) { + unsigned int pos; + int sign, tmp, value, valid; + + value = 0; + pos = 0; + sign = 1; + valid = 0; + + if (endptr) { + *endptr = NX_NULL; + } + + if (len < 1) { + return 0; + } + + /* Detect negative numbers */ + if (str[pos] == '-') { + sign = -1; + pos += 1; + } else if (str[pos] == '+') { + sign = 1; + pos += 1; + } + + /* Detect '0x' hex prefix */ + if ((pos + 2 < len) && (str[pos] == '0') && + ((str[pos + 1] == 'x') || (str[pos + 1] == 'X'))) { + base = 16; + pos += 2; + } + + if (base == 0) { + base = 10; + } + + for (; (pos < len) && (str[pos] != '\x00'); pos++) { + tmp = gdb_get_val(str[pos], base); + if (tmp == GDB_EOF) { + break; + } + + value = value * base + tmp; + valid = 1; /* At least one digit is valid */ + } + + if (!valid) { + return 0; + } + + if (endptr) { + *endptr = str + pos; + } + + value *= sign; + + return value; +} + +/* + * Get long(64bit) value for a string representation. + * + * If the string starts with + or -, it will be signed accordingly. + * + * If base == 0, the base will be determined: + * base 16 if the string starts with 0x or 0X, + * base 10 otherwise + * + * If endptr is specified, it will point to the last non-digit in the + * string. If there are no digits in the string, it will be set to NX_NULL. + */ +static long gdb_strtol(const char *str, unsigned int len, int base, + const char **endptr) { + unsigned int pos; + int sign, tmp, valid; + long value; + value = 0; + pos = 0; + sign = 1; + valid = 0; + + if (endptr) { + *endptr = NX_NULL; + } + + if (len < 1) { + return 0; + } + + /* Detect negative numbers */ + if (str[pos] == '-') { + sign = -1; + pos += 1; + } else if (str[pos] == '+') { + sign = 1; + pos += 1; + } + + /* Detect '0x' hex prefix */ + if ((pos + 2 < len) && (str[pos] == '0') && + ((str[pos + 1] == 'x') || (str[pos + 1] == 'X'))) { + base = 16; + pos += 2; + } + + if (base == 0) { + base = 10; + } + + for (; (pos < len) && (str[pos] != '\x00'); pos++) { + tmp = gdb_get_val(str[pos], base); + if (tmp == GDB_EOF) { + break; + } + + value = value * base + tmp; + valid = 1; /* At least one digit is valid */ + } + + if (!valid) { + return 0; + } + + if (endptr) { + *endptr = str + pos; + } + + value *= sign; + + return value; +} + +/* + * Get the corresponding ASCII hex digit character for a value. + */ +static char gdb_get_digit(int val) { + if ((val >= 0) && (val <= 0xf)) { + return digits[val]; + } else { + return GDB_EOF; + } +} + +/* + * Get the corresponding value for a ASCII digit character. + * + * Supports bases 2-16. + */ +static int gdb_get_val(char digit, int base) { + int value; + + if ((digit >= '0') && (digit <= '9')) { + value = digit - '0'; + } else if ((digit >= 'a') && (digit <= 'f')) { + value = digit - 'a' + 0xa; + } else if ((digit >= 'A') && (digit <= 'F')) { + value = digit - 'A' + 0xa; + } else { + return GDB_EOF; + } + + return (value < base) ? value : GDB_EOF; +} + +/* + * Compare two strings. + * + * Returns: + * 0 if the strings are equal + * 1 if the strings are not equal + */ +static int gdb_strncmp(const char *s1, const char *s2, NX_U32 n) { + while (n) { + if (*s1 != *s2 || !*s1 || !*s2) { + return *(unsigned char *)s1 - *(unsigned char *)s2; + } + s1++; + s2++; + n--; + } + return 0; +} + +/***************************************************************************** + * Packet Functions + ****************************************************************************/ + +/* + * Receive a packet acknowledgment + * + * Returns: + * 0 if an ACK (+) was received + * 1 if a NACK (-) was received + * GDB_EOF otherwise + */ +static int gdb_recv_ack(struct GdbState *state) { + int response; + + /* Wait for packet ack */ + switch (response = gdb_sys_getc(state)) { + case '+': + /* Packet acknowledged */ + return 0; + case '-': + /* Packet negative acknowledged */ + return 1; + default: + /* Bad response! */ + GDB_PRINT("received bad packet response: 0x%2x\n", response); + return GDB_EOF; + } +} + +/* + * Calculate 8-bit checksum of a buffer. + * + * Returns: + * 8-bit checksum. + */ +static int gdb_checksum(const char *buf, unsigned int len) { + unsigned char csum; + + csum = 0; + + while (len--) { + csum += *buf++; + } + + return csum; +} + +/* + * Transmits a packet of data. + * Packets are of the form: $# + * + * Returns: + * 0 if the packet was transmitted and acknowledged + * 1 if the packet was transmitted but not acknowledged + * GDB_EOF otherwise + */ +static int gdb_send_packet(struct GdbState *state, const char *pkt_data, + unsigned int pkt_len) { + char buf[3]; + char csum; + + /* Send packet start */ + if (gdb_sys_putchar(state, '$') == GDB_EOF) { + return GDB_EOF; + } + +#if DEBUG + { + unsigned int p; + GDB_PRINT("-> "); + for (p = 0; p < pkt_len; p++) { + if (gdb_is_printable_char(pkt_data[p])) { + GDB_PRINT("%c", pkt_data[p]); + } else { + GDB_PRINT("\\x%02x", pkt_data[p] & 0xff); + } + } + GDB_PRINT("\n"); + } +#endif + + /* Send packet data */ + if (gdb_write(state, pkt_data, pkt_len) == GDB_EOF) { + return GDB_EOF; + } + + /* Send the checksum */ + buf[0] = '#'; + csum = gdb_checksum(pkt_data, pkt_len); + if ((gdb_enc_hex(buf + 1, sizeof(buf) - 1, &csum, 1) == GDB_EOF) || + (gdb_write(state, buf, sizeof(buf)) == GDB_EOF)) { + return GDB_EOF; + } + + return gdb_recv_ack(state); +} + +/* + * Receives a packet of data, assuming a 7-bit clean connection. + * + * Returns: + * 0 if the packet was received + * GDB_EOF otherwise + */ +static int gdb_recv_packet(struct GdbState *state, char *pkt_buf, + unsigned int pkt_buf_len, unsigned int *pkt_len) { + int data; + char expected_csum, actual_csum; + char buf[2]; + + /* Wait for packet start */ + actual_csum = 0; + + while (1) { + data = gdb_sys_getc(state); + if (data == GDB_EOF) { + return GDB_EOF; + } else if (data == '$') { + /* Detected start of packet. */ + break; + } + } + + /* Read until checksum */ + *pkt_len = 0; + while (1) { + data = gdb_sys_getc(state); + + if (data == GDB_EOF) { + /* Error receiving character */ + return GDB_EOF; + } else if (data == '#') { + /* End of packet */ + break; + } else { + /* Check for space */ + if (*pkt_len >= pkt_buf_len) { + GDB_PRINT("packet buffer overflow\n"); + return GDB_EOF; + } + + /* Store character and update checksum */ + pkt_buf[(*pkt_len)++] = (char)data; + } + } + +#if DEBUG + { + unsigned int p; + GDB_PRINT("<- "); + for (p = 0; p < *pkt_len; p++) { + if (gdb_is_printable_char(pkt_buf[p])) { + GDB_PRINT("%c", pkt_buf[p]); + } else { + GDB_PRINT("\\x%02x", pkt_buf[p] & 0xff); + } + } + GDB_PRINT("\n"); + } +#endif + + /* Receive the checksum */ + if ((gdb_read(state, buf, sizeof(buf), 2) == GDB_EOF) || + (gdb_dec_hex(buf, 2, &expected_csum, 1) == GDB_EOF)) { + return GDB_EOF; + } + + /* Verify checksum */ + actual_csum = gdb_checksum(pkt_buf, *pkt_len); + if (actual_csum != expected_csum) { + /* Send packet nack */ + GDB_PRINT("received packet with bad checksum\n"); + gdb_sys_putchar(state, '-'); + return GDB_EOF; + } + + /* Send packet ack */ + gdb_sys_putchar(state, '+'); + return 0; +} + +/***************************************************************************** + * Data Encoding/Decoding + ****************************************************************************/ + +/* + * Encode data to its hex-value representation in a buffer. + * + * Returns: + * 0+ number of bytes written to buf + * GDB_EOF if the buffer is too small + */ +static int gdb_enc_hex(char *buf, unsigned int buf_len, const char *data, + unsigned int data_len) { + unsigned int pos; + + if (buf_len < data_len * 2) { + /* Buffer too small */ + return GDB_EOF; + } + + for (pos = 0; pos < data_len; pos++) { + *buf++ = gdb_get_digit((data[pos] >> 4) & 0xf); + *buf++ = gdb_get_digit((data[pos]) & 0xf); + } + + return data_len * 2; +} + +/* + * Decode data from its hex-value representation to a buffer. + * + * Returns: + * 0 if successful + * GDB_EOF if the buffer is too small + */ +static int gdb_dec_hex(const char *buf, unsigned int buf_len, char *data, + unsigned int data_len) { + unsigned int pos; + int tmp; + + if (buf_len != data_len * 2) { + /* Buffer too small */ + return GDB_EOF; + } + + for (pos = 0; pos < data_len; pos++) { + /* Decode high nibble */ + tmp = gdb_get_val(*buf++, 16); + if (tmp == GDB_EOF) { + /* Buffer contained junk. */ + GDB_ASSERT(0); + return GDB_EOF; + } + + data[pos] = tmp << 4; + + /* Decode low nibble */ + tmp = gdb_get_val(*buf++, 16); + if (tmp == GDB_EOF) { + /* Buffer contained junk. */ + GDB_ASSERT(0); + return GDB_EOF; + } + data[pos] |= tmp; + } + + return 0; +} + +/* + * Encode data to its binary representation in a buffer. + * + * Returns: + * 0+ number of bytes written to buf + * GDB_EOF if the buffer is too small + */ +static int gdb_enc_bin(char *buf, unsigned int buf_len, const char *data, + unsigned int data_len) { + unsigned int buf_pos, data_pos; + + for (buf_pos = 0, data_pos = 0; data_pos < data_len; data_pos++) { + if (data[data_pos] == '$' || data[data_pos] == '#' || + data[data_pos] == '}' || data[data_pos] == '*') { + if (buf_pos + 1 >= buf_len) { + GDB_ASSERT(0); + return GDB_EOF; + } + buf[buf_pos++] = '}'; + buf[buf_pos++] = data[data_pos] ^ 0x20; + } else { + if (buf_pos >= buf_len) { + GDB_ASSERT(0); + return GDB_EOF; + } + buf[buf_pos++] = data[data_pos]; + } + } + + return buf_pos; +} + +/* + * Decode data from its bin-value representation to a buffer. + * + * Returns: + * 0+ if successful, number of bytes decoded + * GDB_EOF if the buffer is too small + */ +static int gdb_dec_bin(const char *buf, unsigned int buf_len, char *data, + unsigned int data_len) { + unsigned int buf_pos, data_pos; + + for (buf_pos = 0, data_pos = 0; buf_pos < buf_len; buf_pos++) { + if (data_pos >= data_len) { + /* Output buffer overflow */ + GDB_ASSERT(0); + return GDB_EOF; + } + if (buf[buf_pos] == '}') { + /* The next byte is escaped! */ + if (buf_pos + 1 >= buf_len) { + /* There's an escape character, but no escaped character + * following the escape character. */ + GDB_ASSERT(0); + return GDB_EOF; + } + buf_pos += 1; + data[data_pos++] = buf[buf_pos] ^ 0x20; + } else { + data[data_pos++] = buf[buf_pos]; + } + } + + return data_pos; +} + +/***************************************************************************** + * Command Functions + ****************************************************************************/ + +/* + * Read from memory and encode into buf. + * + * Returns: + * 0+ number of bytes written to buf + * GDB_EOF if the buffer is too small + */ +static int gdb_mem_read(struct GdbState *state, char *buf, + unsigned int buf_len, address addr, unsigned int len, + gdb_enc_func enc) { + char data[4096]; + unsigned int pos; + + if (len > sizeof(data)) { + return GDB_EOF; + } + + /* Read from system memory */ + for (pos = 0; pos < len; pos++) { + if (gdb_sys_mem_readb(state, addr + pos, &data[pos])) { + /* Failed to read */ + return GDB_EOF; + } + } + + /* Encode data */ + return enc(buf, buf_len, data, len); +} + +/* + * Write to memory from encoded buf. + */ +static int gdb_mem_write(struct GdbState *state, const char *buf, + unsigned int buf_len, address addr, unsigned int len, + gdb_dec_func dec) { + char data[4096]; + unsigned int pos; + + if (len > sizeof(data)) { + return GDB_EOF; + } + + /* Decode data */ + if (dec(buf, buf_len, data, len) == GDB_EOF) { + return GDB_EOF; + } + + /* Write to system memory */ + for (pos = 0; pos < len; pos++) { + if (gdb_sys_mem_writeb(state, addr + pos, data[pos])) { + /* Failed to write */ + return GDB_EOF; + } + } + + return 0; +} + +static int find_pc_bp_num(struct GdbState *state) { + int bp_num = -1; + for (bp_num = 0; bp_num < __GDB_MAX_BREAKPOINTS_NUM_; bp_num++) { + if (gdb_bkp_buf[bp_num].en && + gdb_bkp_buf[bp_num].addr == state->registers[GDB_CPU_RISCV_REG_PC]) { + return bp_num; + } + } + return -1; +} + +/* + * Continue program execution at PC. + * Returns: + * 1 go to run debug program + * -1 error + */ +int gdb_continue(struct GdbState *state) { + // continue不需要考虑当前pc处是不是ebreak + return 1; +} + +/* + * Step one instruction. + */ +int gdb_step(struct GdbState *state) { + NX_U32 instruction = 0; + gdb_sys_mem_read4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC], + &instruction); + if ((instruction & 0x3) != 0x3) { + // compressed instruction 16 bits + int bp_num = -1; + if (instruction == gdb_c_ebreak_instruction) { + // ebreak instruction + bp_num = find_pc_bp_num(state); + if (bp_num == -1) { + return -1; + } + } + if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0xa000) { + // c.j + int offset = 0; + offset |= ((instruction & 0x1000) >> 1) | ((instruction & 0x800) >> 7) | + ((instruction & 0x600) >> 1) | ((instruction & 0x100) << 2) | + ((instruction & 0x80) >> 1) | ((instruction & 0x40) << 1) | + ((instruction & 0x38) >> 2) | ((instruction & 0x4) << 3); + if (instruction & 0x1000) { + offset |= 0xfffff000; + } + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + return 0; + } else if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0x2000) { + // c.jal + int offset = 0; + offset |= ((instruction & 0x1000) >> 1) | ((instruction & 0x800) >> 7) | + ((instruction & 0x600) >> 1) | ((instruction & 0x100) << 2) | + ((instruction & 0x80) >> 1) | ((instruction & 0x40) << 1) | + ((instruction & 0x38) >> 2) | ((instruction & 0x4) << 3); + if (instruction & 0x1000) { + offset |= 0xfffff000; + } + state->registers[GDB_CPU_RISCV_REG_RA] = + state->registers[GDB_CPU_RISCV_REG_PC] + 2; + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + return 0; + } else if ((instruction & 0x7f) == 2 && (instruction & 0xf000) == 0x9000) { + // c.jalr + int tmp = state->registers[GDB_CPU_RISCV_REG_PC] + 2; + state->registers[GDB_CPU_RISCV_REG_PC] = + state->registers[(instruction & 0xf80) >> 7]; + state->registers[GDB_CPU_RISCV_REG_RA] = tmp; + return 0; + } else if ((instruction & 0x7f) == 2 && (instruction & 0xf000) == 0x8000) { + // c.jr + state->registers[GDB_CPU_RISCV_REG_PC] = + state->registers[(instruction & 0xf80) >> 7]; + return 0; + } else if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0xc000) { + // c.beqz + int rs1 = (instruction & 0x380) >> 7; + if (state->registers[rs1 + 8] == 0) { + int offset = 0; + offset |= ((instruction & 0x1000) >> 4) | ((instruction & 0xc) >> 7) | + ((instruction & 0x60) << 1) | ((instruction & 0x18) >> 2) | + ((instruction & 0x4) << 3); + if (instruction & 0x100) { + offset |= 0xffffff00; + } + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0xe000) { + // c.bnez + int rs1 = (instruction & 0x380) >> 7; + if (state->registers[rs1 + 8] != 0) { + int offset = 0; + offset |= ((instruction & 0x1000) >> 4) | ((instruction & 0xc) >> 7) | + ((instruction & 0x60) << 1) | ((instruction & 0x18) >> 2) | + ((instruction & 0x4) << 3); + if (instruction & 0x100) { + offset |= 0xffffff00; + } + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else { + // not control transfer instruction + gdb_sys_mem_write2b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC], + instruction); + if (bp_num != -1) + state->lastbp = bp_num; + else + state->lastbp = -1; + gdb_sys_mem_read4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC] + 2, + &instruction); + state->tmp_instruction = instruction; + gdb_sys_mem_write4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC] + 2, + gdb_ebreak_instruction); + return 1; + } + } else if ((instruction & 0x3) == 0x3 && (instruction & 0x1c) != 0x1c) { + // 32 bits instruction only consider isa set g(imafd) + int bp_num = -1; + if (instruction == gdb_ebreak_instruction) { + bp_num = find_pc_bp_num(state); + if (bp_num == -1) { + return -1; + } + } + + if ((instruction & 0x7f) == 0x6f) { + // jal + int rd = (instruction & 0xf80) >> 7; + state->registers[rd] = state->registers[GDB_CPU_RISCV_REG_PC] + 4; + int offset = 0; + offset |= ((instruction & 0x80000000) >> 11) | + ((instruction & 0x7fe00000) >> 20) | + ((instruction & 0x100000) >> 9) | (instruction & 0xff000); + if (instruction & 0x80000000) { + offset |= 0xfff00000; + } + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + return 0; + } else if ((instruction & 0x7f) == 0x67 && (instruction & 0x7000) == 0) { + // jalr + int rd = (instruction & 0xf80) >> 7; + int rs1 = (instruction & 0xf8000) >> 15; + state->registers[rd] = state->registers[GDB_CPU_RISCV_REG_PC] + 4; + int offset = 0; + offset |= ((instruction & 0xfff00000) >> 20); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + state->registers[GDB_CPU_RISCV_REG_PC] = state->registers[rs1] + offset; + state->registers[GDB_CPU_RISCV_REG_PC] &= ~1; + return 0; + } else if ((instruction & 0x7f) == 0x63 && (instruction & 0x7000) == 0) { + // beq + int rs1 = (instruction & 0xf8000) >> 15; + int rs2 = (instruction & 0x1f00000) >> 20; + int offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (state->registers[rs1] == state->registers[rs2]) { + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x1000) { + // bne + int rs1 = (instruction & 0xf8000) >> 15; + int rs2 = (instruction & 0x1f00000) >> 20; + int offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (state->registers[rs1] != state->registers[rs2]) { + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x4000) { + // blt + int rs1 = (instruction & 0xf8000) >> 15; + int rs2 = (instruction & 0x1f00000) >> 20; + int offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if ((long)state->registers[rs1] < (long)state->registers[rs2]) { + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x5000) { + // bge + int rs1 = (instruction & 0xf8000) >> 15; + int rs2 = (instruction & 0x1f00000) >> 20; + int offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if ((long)state->registers[rs1] >= (long)state->registers[rs2]) { + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x6000) { + // bltu + int rs1 = (instruction & 0xf8000) >> 15; + int rs2 = (instruction & 0x1f00000) >> 20; + int offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (state->registers[rs1] < state->registers[rs2]) { + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x7000) { + // bgeu + int rs1 = (instruction & 0xf8000) >> 15; + int rs2 = (instruction & 0x1f00000) >> 20; + int offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (state->registers[rs1] >= state->registers[rs2]) { + state->registers[GDB_CPU_RISCV_REG_PC] += offset; + } + return 0; + } else { + // not control transfer instruction + gdb_sys_mem_write4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC], + instruction); + if (bp_num != -1) + state->lastbp = bp_num; + else + state->lastbp = -1; + gdb_sys_mem_read4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC] + 4, + &instruction); + state->tmp_instruction = instruction; + gdb_sys_mem_write4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC] + 4, + gdb_ebreak_instruction); + return 1; + } + } else { + return -1; + } + return 0; +} + +/***************************************************************************** + * Packet Creation Helpers + ****************************************************************************/ + +/* + * Send OK packet + */ +static int gdb_send_ok_packet(struct GdbState *state, char *buf, + unsigned int buf_len) { + return gdb_send_packet(state, "OK", 2); +} + +/* + * Send a message to the debugging console (via O XX... packet) + */ +static int gdb_send_conmsg_packet(struct GdbState *state, char *buf, + unsigned int buf_len, const char *msg) { + unsigned int size; + int status; + + if (buf_len < 2) { + /* Buffer too small */ + return GDB_EOF; + } + + buf[0] = 'O'; + status = gdb_enc_hex(&buf[1], buf_len - 1, msg, gdb_strlen(msg)); + if (status == GDB_EOF) { + return GDB_EOF; + } + size = 1 + status; + return gdb_send_packet(state, buf, size); +} + +/* + * Send a signal packet (S AA). + */ +static int gdb_send_signal_packet(struct GdbState *state, char *buf, + unsigned int buf_len, char signal) { + unsigned int size; + int status; + + if (buf_len < 4) { + /* Buffer too small */ + return GDB_EOF; + } + + buf[0] = 'S'; + status = gdb_enc_hex(&buf[1], buf_len - 1, &signal, 1); + if (status == GDB_EOF) { + return GDB_EOF; + } + size = 1 + status; + return gdb_send_packet(state, buf, size); +} + +/* + * Send a error packet (E AA). + */ +static int gdb_send_error_packet(struct GdbState *state, char *buf, + unsigned int buf_len, char error) { + unsigned int size; + int status; + + if (buf_len < 4) { + /* Buffer too small */ + return GDB_EOF; + } + + buf[0] = 'E'; + status = gdb_enc_hex(&buf[1], buf_len - 1, &error, 1); + if (status == GDB_EOF) { + return GDB_EOF; + } + size = 1 + status; + return gdb_send_packet(state, buf, size); +} + +/* + * 目前支持部分查询,并返回固定特性字符串 + */ +static int gdb_handle_query(GdbState *state, char pkt_buf[PKT_BUF_LEN], + NX_U32 pkt_len) { + const char *ptrNext; + ptrNext = pkt_buf + 1; + if (gdb_strncmp(ptrNext, "Supported", 9) == 0) { + return gdb_send_packet(state, "swbreak+;vContSupported+;", 25); + } else if (gdb_strncmp(ptrNext, "TStatus", 7) == 0) { + return gdb_send_packet(state, NX_NULL, 0); + } else if (gdb_strncmp(ptrNext, "fThreadInfo", 11) == 0) { + return gdb_send_packet(state, "m1", 2); + } else if (gdb_strncmp(ptrNext, "sThreadInfo", 11) == 0) { + return gdb_send_packet(state, "l", 1); + } else if (gdb_strncmp(ptrNext, "Attached", 8) == 0) { + return gdb_send_packet(state, "1", 1); + } else if (gdb_strncmp(ptrNext, "C", 1) == 0) { + return gdb_send_packet(state, "QC1", 3); + } else if (gdb_strncmp(ptrNext, "Offsets", 7) == 0) { + return gdb_send_packet(state, NX_NULL, 0); + } else if (gdb_strncmp(ptrNext, "Symbol::", 8) == 0) { + return gdb_send_packet(state, "OK", 2); + } else { + return GDB_EOF; + } +} + +static int gdb_add_break_point(NX_U32 type, NX_U64 addr, NX_U32 length) { + NX_U16 i; + for (i = 0; i < __GDB_MAX_BREAKPOINTS_NUM_; i++) { + if (!gdb_bkp_buf[i].en) { + gdb_bkp_buf[i].en = 1; + gdb_bkp_buf[i].type = type; + gdb_bkp_buf[i].addr = addr; + gdb_bkp_buf[i].len = length; + if (length == 2) { + gdb_sys_mem_read2b(NX_NULL, addr, (NX_U16 *)&gdb_bkp_buf[i].instruction); + // insert c.ebreak instruction + gdb_sys_mem_write2b(NX_NULL, addr, gdb_c_ebreak_instruction); + } else if (length == 4) { + gdb_sys_mem_read4b(NX_NULL, addr, (NX_U32 *)&gdb_bkp_buf[i].instruction); + // insert ebreak instruction + gdb_sys_mem_write4b(NX_NULL, addr, gdb_ebreak_instruction); + } else { + return -1; + } + return 1; + } + } + return 0; +} + +static int gdb_handle_point(GdbState *state, NX_U32 type, NX_U64 addr, + NX_U32 length) { + // insert break or watchpoint (draft) + // Zt,addr,length + // t is type: `0' - software breakpoint, `1' - hardware breakpoint, `2' - + // write watchpoint, `3' - read watchpoint, `4' - access watchpoint; addr is + // address; length is in bytes. For a software breakpoint, length specifies + // the size of the instruction to be patched. For hardware breakpoints and + // watchpoints length specifies the memory region to be monitored. To avoid + // potential problems with duplicate packets, the operations should be + // implemented in an idempotent way. + // reply ENN for an error reply OK for success + // `' If not supported. + switch (type) { + case 0: + // software breakpoint + case 1: + // hardware breakpoint + if (gdb_add_break_point(type, addr, length) == 0) { + return -1; + } else { + return 0; + } + break; + case 2: + // write watchpoint + break; + case 3: + // read watchpoint + break; + case 4: + // access watchpoint + break; + default: + return -1; + } + return -1; +} + +static int gdb_remove_break_point(NX_U32 type, NX_U64 addr, NX_U32 length) { + NX_U16 i; + for (i = 0; i < __GDB_MAX_BREAKPOINTS_NUM_; i++) { + if (gdb_bkp_buf[i].en && gdb_bkp_buf[i].type == type && + gdb_bkp_buf[i].addr == addr && gdb_bkp_buf[i].len == length) { + gdb_bkp_buf[i].en = 0; + if (length == 2) { + gdb_sys_mem_write2b(NX_NULL, addr, gdb_bkp_buf[i].instruction); + } else if (length == 4) { + gdb_sys_mem_write4b(NX_NULL, addr, gdb_bkp_buf[i].instruction); + } else { + return -1; + } + return 1; + } + } + return 0; +} + +static int gdb_remove_point(GdbState *state, NX_U32 type, NX_U64 addr, + NX_U32 length) { + // remove break or watchpoint + switch (type) { + case 0: + // software breakpoint + case 1: + // hardware breakpoint + if (gdb_remove_break_point(type, addr, length) == 0) { + return -1; + } else { + return 0; + } + break; + case 2: + // write watchpoint + break; + case 3: + // read watchpoint + break; + case 4: + // access watchpoint + break; + default: + return -1; + } + return -1; +} + +/* + * Main debug loop. Handles commands. + */ +static int gdb_main(struct GdbState *state) { + address addr; + char pktBuf[PKT_BUF_LEN]; + int status; + NX_U32 length; + NX_U32 pktLen; + const char *ptrNext; + NX_U32 type; + + if (isStartEbreakExectued == 0) { + // 第一次通过ebreak,与gdb进行初始化的一些信息发送 + isStartEbreakExectued = 1; + state->registers[GDB_CPU_RISCV_REG_PC] += 2; + } else { + // 不是第一次控制权交给stub, 故而要告诉gdb为什么程序停下来了 + gdb_send_signal_packet(state, pktBuf, sizeof(pktBuf), state->signum); + } + + if (state->lastbp != -2) { + // step command end + if (state->lastbp >= 0) { + if (gdb_bkp_buf[state->lastbp].len == 2) { + gdb_sys_mem_write2b(NX_NULL, gdb_bkp_buf[state->lastbp].addr, + gdb_c_ebreak_instruction); + } else if (gdb_bkp_buf[state->lastbp].len == 4) { + gdb_sys_mem_write4b(NX_NULL, gdb_bkp_buf[state->lastbp].addr, + gdb_ebreak_instruction); + } else { + goto error; + } + state->lastbp = -2; + } + gdb_sys_mem_write4b(NX_NULL, state->registers[GDB_CPU_RISCV_REG_PC], + state->tmp_instruction); + } + + while (1) { + /* Receive the next packet */ + status = gdb_recv_packet(state, pktBuf, sizeof(pktBuf), &pktLen); + if (status == GDB_EOF) { + break; + } + + if (pktLen == 0) { + /* Received empty packet.. */ + continue; + } + + ptrNext = pktBuf; + + /* + * Handle one letter commands + */ + switch (pktBuf[0]) { + +/* Calculate remaining space in packet from ptrNext position. */ +#define token_remaining_buf (pktLen - (ptrNext - pktBuf)) + +/* Expecting a seperator. If not present, go to error */ +#define token_expect_seperator(c) \ + { \ + if (!ptrNext || *ptrNext != c) { \ + goto error; \ + } else { \ + ptrNext += 1; \ + } \ + } + +/* Expecting an unsigned integer argument. If not present, go to error */ +#define token_expect_uinteger_arg(arg) \ + { \ + arg = (NX_U32)gdb_strtoi(ptrNext, token_remaining_buf, 16, &ptrNext); \ + if (!ptrNext) { \ + goto error; \ + } \ + } + +/* Expecting an long argument. If not present, go to error */ +#define token_expect_ulong_arg(arg) \ + { \ + arg = (NX_U64)gdb_strtol(ptrNext, token_remaining_buf, 16, &ptrNext); \ + if (!ptrNext) { \ + goto error; \ + } \ + } + + /* + * Read Registers + * Command Format: g + */ + case 'g': + /* Encode registers */ + status = + gdb_enc_hex(pktBuf, sizeof(pktBuf), (char *)&(state->registers), + sizeof(state->registers)); + if (status == GDB_EOF) { + goto error; + } + pktLen = status; + gdb_send_packet(state, pktBuf, pktLen); + break; + + /* + * Write Registers + * Command Format: G XX... + */ + case 'G': + status = + gdb_dec_hex(pktBuf + 1, pktLen - 1, (char *)&(state->registers), + sizeof(state->registers)); + if (status == GDB_EOF) { + goto error; + } + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + break; + + /* + * Read a Register + * Command Format: p n + */ + case 'p': + ptrNext += 1; + token_expect_uinteger_arg(addr); + + if (addr >= GDB_CPU_NUM_REGISTERS) { + goto error; + } + + /* Read Register */ + status = gdb_enc_hex(pktBuf, sizeof(pktBuf), + (char *)&(state->registers[addr]), + sizeof(state->registers[addr])); + if (status == GDB_EOF) { + goto error; + } + gdb_send_packet(state, pktBuf, status); + break; + + /* + * Write a Register + * Command Format: P n...=r... + */ + case 'P': + ptrNext += 1; + token_expect_uinteger_arg(addr); + token_expect_seperator('='); + + if (addr < GDB_CPU_NUM_REGISTERS) { + status = gdb_dec_hex(ptrNext, token_remaining_buf, + (char *)&(state->registers[addr]), + sizeof(state->registers[addr])); + if (status == GDB_EOF) { + goto error; + } + } + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + break; + + /* + * Read Memory + * Command Format: m addr,length + */ + case 'm': + ptrNext += 1; + token_expect_uinteger_arg(addr); + token_expect_seperator(','); + token_expect_uinteger_arg(length); + /* Read Memory */ + status = gdb_mem_read(state, pktBuf, sizeof(pktBuf), addr, length, + gdb_enc_hex); + if (status == GDB_EOF) { + goto error; + } + gdb_send_packet(state, pktBuf, status); + break; + + /* + * Write Memory + * Command Format: M addr,length:XX.. + */ + case 'M': + ptrNext += 1; + token_expect_uinteger_arg(addr); + token_expect_seperator(','); + token_expect_uinteger_arg(length); + token_expect_seperator(':'); + + /* Write Memory */ + status = gdb_mem_write(state, ptrNext, token_remaining_buf, addr, length, + gdb_dec_hex); + if (status == GDB_EOF) { + goto error; + } + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + break; + + /* + * Write Memory (Binary) + * Command Format: X addr,length:XX.. + */ + case 'X': + ptrNext += 1; + token_expect_uinteger_arg(addr); + token_expect_seperator(','); + token_expect_uinteger_arg(length); + token_expect_seperator(':'); + + /* Write Memory */ + status = gdb_mem_write(state, ptrNext, token_remaining_buf, addr, length, + gdb_dec_bin); + if (status == GDB_EOF) { + goto error; + } + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + break; + + /* + * Continue + * Command Format: c [addr] + */ + case 'c': + status = gdb_continue(state); + if (status == 1) { + return 0; + } else if (status == 0) { + break; + } else { + goto error; + } + + /* + * Single-step + * Command Format: s [addr] + */ + case 's': + status = gdb_step(state); + if (status == 1) { + return 0; + } else if (status == 0) { + gdb_send_signal_packet(state, pktBuf, sizeof(pktBuf), state->signum); + break; + } else { + goto error; + } + + case '?': + gdb_send_signal_packet(state, pktBuf, sizeof(pktBuf), state->signum); + break; + + /* + * Query + * Command Format: q + */ + case 'q': + status = gdb_handle_query(state, pktBuf, pktLen); + if (status == GDB_EOF) + goto error; + break; + + case 'H': + // 只针对单线程,默认返回OK + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + break; + + case 'z': + // 删除断点 + ptrNext += 1; + token_expect_uinteger_arg(type); + token_expect_seperator(','); + token_expect_ulong_arg(addr); + token_expect_seperator(','); + token_expect_uinteger_arg(length); + if (gdb_remove_point(state, type, addr, length) == 0) { + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + } else { + goto error; + } + break; + + case 'Z': + // 插入断点 + ptrNext += 1; + token_expect_uinteger_arg(type); + token_expect_seperator(','); + token_expect_ulong_arg(addr); + token_expect_seperator(','); + token_expect_uinteger_arg(length); + if (gdb_handle_point(state, type, addr, length) == 0) { + gdb_send_ok_packet(state, pktBuf, sizeof(pktBuf)); + } else { + goto error; + } + break; + + case 'v': + ptrNext += 1; + if (gdb_strncmp(ptrNext, "Cont?", 5) == 0) { + gdb_send_packet(state, "vCont;c;s", 9); + } else if (gdb_strncmp(ptrNext, "MustReplyEmpty", 14) == 0) { + gdb_send_packet(state, "", 0); + } + break; + /* + * Unsupported Command + */ + default: + gdb_send_packet(state, NX_NULL, 0); + } + + continue; + + error: + gdb_send_error_packet(state, pktBuf, sizeof(pktBuf), 0x00); + +#undef token_remaining_buf +#undef token_expect_seperator +#undef token_expect_uinteger_arg +#undef token_expect_ulong_arg + } + + return 0; +} + +void GdbStubTrapHandler(NX_HalTrapFrame *frame) +{ + /* Load Registers */ + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_X0] = 0; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_RA] = frame->ra; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_SP] = frame->sp; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_GP] = frame->gp; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_TP] = frame->tp; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T0] = frame->t0; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T1] = frame->t1; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T2] = frame->t2; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S0] = frame->s0; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S1] = frame->s1; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A0] = frame->a0; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A1] = frame->a1; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A2] = frame->a2; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A3] = frame->a3; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A4] = frame->a4; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A5] = frame->a5; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A6] = frame->a6; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A7] = frame->a7; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S2] = frame->s2; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S3] = frame->s3; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S4] = frame->s4; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S5] = frame->s5; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S6] = frame->s6; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S7] = frame->s7; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S8] = frame->s8; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S9] = frame->s9; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S10] = frame->s10; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S11] = frame->s11; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T3] = frame->t3; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T4] = frame->t4; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T5] = frame->t5; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T6] = frame->t6; + gdbStateGlobal.registers[GDB_CPU_RISCV_REG_PC] = frame->epc; + + gdb_main(&gdbStateGlobal); + + /* Store Registers */ + frame->ra = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_RA]; + frame->sp = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_SP]; + frame->gp = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_GP]; + frame->tp = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_TP]; + frame->t0 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T0]; + frame->t1 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T1]; + frame->t2 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T2]; + frame->s0 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S0]; + frame->s1 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S1]; + frame->a0 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A0]; + frame->a1 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A1]; + frame->a2 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A2]; + frame->a3 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A3]; + frame->a4 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A4]; + frame->a5 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A5]; + frame->a6 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A6]; + frame->a7 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_A7]; + frame->s2 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S2]; + frame->s3 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S3]; + frame->s4 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S4]; + frame->s5 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S5]; + frame->s6 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S6]; + frame->s7 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S7]; + frame->s8 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S8]; + frame->s9 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S9]; + frame->s10 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S10]; + frame->s11 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_S11]; + frame->t3 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T3]; + frame->t4 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T4]; + frame->t5 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T5]; + frame->t6 = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_T6]; + frame->epc = gdbStateGlobal.registers[GDB_CPU_RISCV_REG_PC]; +} + + + +void gdb_sys_init(void) { + NX_LOG_I("gdb stub init"); + for (int i = 0; i < __GDB_MAX_BREAKPOINTS_NUM_; i++) { + gdb_bkp_buf[i].en = 0; + } + + // receive init '+' + if (gdb_sys_getc(NX_NULL) != '+') { + gdb_sys_putchar(NX_NULL, '-'); + gdb_sys_putchar(NX_NULL, '1'); + + } + gdbStateGlobal.signum = 5; + gdbStateGlobal.lastbp = -2; + isStartEbreakExectued = 0; + // __asm__ volatile("ebreak"); +} + +NX_INITCALL(gdb_sys_init); diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c new file mode 100644 index 0000000..420cfb1 --- /dev/null +++ b/src/arch/riscv64/kernel/ptrac.c @@ -0,0 +1,313 @@ +#include "base/thread.h" +#include "base/process.h" + +#include "ptrace.h" +#include "irq.h" + +NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) +{ + NX_U32 instruction = 0; + NX_VmspaceRead(&thread->resource.process->vmspace, (char*)trapFrame->epc, (char*)&instruction, sizeof(NX_U32)); + if ((instruction & 0x3) != 0x3) { + // compressed instruction 16 bits + if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0xa000) { + // c.j + NX_I32 offset = 0; + offset |= ((instruction & 0x1000) >> 1) | ((instruction & 0x800) >> 7) | + ((instruction & 0x600) >> 1) | ((instruction & 0x100) << 2) | + ((instruction & 0x80) >> 1) | ((instruction & 0x40) << 1) | + ((instruction & 0x38) >> 2) | ((instruction & 0x4) << 3); + if (instruction & 0x1000) { + offset |= 0xfffff000; + } + trapFrame->epc += offset; + return 0; + } else if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0x2000) { + // c.jal + NX_I32 offset = 0; + offset |= ((instruction & 0x1000) >> 1) | ((instruction & 0x800) >> 7) | + ((instruction & 0x600) >> 1) | ((instruction & 0x100) << 2) | + ((instruction & 0x80) >> 1) | ((instruction & 0x40) << 1) | + ((instruction & 0x38) >> 2) | ((instruction & 0x4) << 3); + if (instruction & 0x1000) { + offset |= 0xfffff000; + } + trapFrame->ra = trapFrame->epc + 2; + trapFrame->epc += offset; + return 0; + } else if ((instruction & 0x7f) == 2 && (instruction & 0xf000) == 0x9000) { + // c.jalr + NX_I32 tmp = trapFrame->epc + 2; + NX_I32 rs1 = (instruction & 0xf80) >> 7; + if(rs1 == 0){ + return -NX_EINVAL; + } + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + trapFrame->epc = *(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)); + trapFrame->ra = tmp; + return 0; + } else if ((instruction & 0x7f) == 2 && (instruction & 0xf000) == 0x8000) { + // c.jr + NX_I32 rs1 = (instruction & 0xf80) >> 7; + if(rs1 == 0){ + return -NX_EINVAL; + } + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + trapFrame->epc = *(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)); + return 0; + } else if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0xc000) { + // c.beqz + NX_I32 rs1 = (instruction & 0x380) >> 7; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + if (*(NX_UArch*)(tmpTrapFrame + (rs1 + 8) * sizeof(NX_UArch)) == 0) { + NX_I32 offset = 0; + offset |= ((instruction & 0x1000) >> 4) | ((instruction & 0xc) >> 7) | + ((instruction & 0x60) << 1) | ((instruction & 0x18) >> 2) | + ((instruction & 0x4) << 3); + if (instruction & 0x100) { + offset |= 0xffffff00; + } + trapFrame->epc += offset; + } + return 0; + } else if ((instruction & 0x3) == 1 && (instruction & 0xe000) == 0xe000) { + // c.bnez + NX_I32 rs1 = (instruction & 0x380) >> 7; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + if (*(NX_UArch*)(tmpTrapFrame + (rs1 + 8) * sizeof(NX_UArch)) == 0) { + NX_I32 offset = 0; + offset |= ((instruction & 0x1000) >> 4) | ((instruction & 0xc) >> 7) | + ((instruction & 0x60) << 1) | ((instruction & 0x18) >> 2) | + ((instruction & 0x4) << 3); + if (instruction & 0x100) { + offset |= 0xffffff00; + } + trapFrame->epc += offset; + } + return 0; + } else { + // not control transfer instruction + NX_VmspaceRead(&thread->resource.process->vmspace, (char*)trapFrame->epc + 2, (char*)&instruction, sizeof(NX_U32)); + thread->singleStepNextInstruction = instruction; + NX_U32 ebreak = gdb_ebreak_instruction; + NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)trapFrame->epc + 2, (char*)&ebreak, sizeof(NX_U32)); + return 1; + } + }else if ((instruction & 0x3) == 0x3 && (instruction & 0x1c) != 0x1c) { + // 32 bits instruction only consider isa set g(imafd) + if ((instruction & 0x7f) == 0x6f) { + // jal + NX_I32 rd = (instruction & 0xf80) >> 7; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + *(NX_UArch*)(tmpTrapFrame + rd * sizeof(NX_UArch)) = trapFrame->epc + 4; + NX_I32 offset = 0; + offset |= ((instruction & 0x80000000) >> 11) | + ((instruction & 0x7fe00000) >> 20) | + ((instruction & 0x100000) >> 9) | (instruction & 0xff000); + if (instruction & 0x80000000) { + offset |= 0xfff00000; + } + trapFrame->epc += offset; + return 0; + } else if ((instruction & 0x7f) == 0x67 && (instruction & 0x7000) == 0) { + // jalr + NX_I32 rd = (instruction & 0xf80) >> 7; + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + *(NX_UArch*)(tmpTrapFrame + rd * sizeof(NX_UArch)) = trapFrame->epc + 4; + + NX_I32 offset = 0; + offset |= ((instruction & 0xfff00000) >> 20); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + trapFrame->epc = *(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) + offset; + trapFrame->epc &= ~1; + return 0; + } else if ((instruction & 0x7f) == 0x63 && (instruction & 0x7000) == 0) { + // beq + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_I32 rs2 = (instruction & 0x1f00000) >> 20; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + NX_I32 offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (*(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) == + *(NX_UArch*)(tmpTrapFrame + rs2 * sizeof(NX_UArch))) { + trapFrame->epc += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x1000) { + // bne + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_I32 rs2 = (instruction & 0x1f00000) >> 20; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + NX_I32 offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (*(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) != + *(NX_UArch*)(tmpTrapFrame + rs2 * sizeof(NX_UArch))) { + trapFrame->epc += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x4000) { + // blt + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_I32 rs2 = (instruction & 0x1f00000) >> 20; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + NX_I32 offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (*(NX_I64*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) < + *(NX_I64*)(tmpTrapFrame + rs2 * sizeof(NX_UArch))) { + trapFrame->epc += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x5000) { + // bge + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_I32 rs2 = (instruction & 0x1f00000) >> 20; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + NX_I32 offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (*(NX_I64*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) >= + *(NX_I64*)(tmpTrapFrame + rs2 * sizeof(NX_UArch))) { + trapFrame->epc += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x6000) { + // bltu + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_I32 rs2 = (instruction & 0x1f00000) >> 20; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + NX_I32 offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (*(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) < + *(NX_UArch*)(tmpTrapFrame + rs2 * sizeof(NX_UArch))) { + trapFrame->epc += offset; + } + return 0; + } else if ((instruction & 0x7f) == 0x63 && + (instruction & 0x7000) == 0x7000) { + // bgeu + NX_I32 rs1 = (instruction & 0xf8000) >> 15; + NX_I32 rs2 = (instruction & 0x1f00000) >> 20; + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; + NX_I32 offset = 0; + offset |= + ((instruction & 0xf00) >> 7) | ((instruction & 0x80000000) >> 19) | + ((instruction & 0x7e000000) >> 20) | ((instruction & 0x80) << 4); + if (instruction & 0x80000000) { + offset |= 0xfffff000; + } + if (*(NX_UArch*)(tmpTrapFrame + rs1 * sizeof(NX_UArch)) >= + *(NX_UArch*)(tmpTrapFrame + rs2 * sizeof(NX_UArch))) { + trapFrame->epc += offset; + } + return 0; + } else { + // not control transfer instruction + NX_VmspaceRead(&thread->resource.process->vmspace, (char*)trapFrame->epc + 4, (char*)&instruction, sizeof(NX_U32)); + thread->singleStepNextInstruction = instruction; + NX_U32 ebreak = gdb_ebreak_instruction; + NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)trapFrame->epc + 4, (char*)&ebreak, sizeof(NX_U32)); + return 1; + } + } else { + return -1; + } + return 0; +} + +NX_Error Ptrace(enum __ptrace_requese request, NX_I32 tid, void * addr, void * data) +{ + NX_Process * process; + process = NX_ProcessCurrent(); + NX_U64 buf; + NX_Thread * target = NX_ThreadFindById(tid); + if(!target){ + return -NX_EINVAL; + } + NX_HalTrapFrame * trapFrame; + trapFrame = (NX_HalTrapFrame*)target->stackBase + target->stackSize - sizeof(NX_HalTrapFrame); + + switch (request) { + case PTRACE_TRACEME: + if(process->ptrace & PT_PTRACED){ + return -1; + }else{ + process->ptrace |= PT_PTRACED; + } + break; + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + NX_VmspaceRead(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U64)); + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U64)); + break; + case PTRACE_PEEKUSER: + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)trapFrame, sizeof(NX_HalTrapFrame)); + break; + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U64)); + NX_VmspaceWrite(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U64)); + break; + case PTRACE_POKEUSER: + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)trapFrame, sizeof(NX_HalTrapFrame)); + break; + case PTRACE_CONT: + NX_ThreadUnblock(target); + break; + case PTRACE_KILL: + NX_SignalSend(target->tid, NX_SIGNAL_KILL, NX_NULL, NX_NULL); + break; + case PTRACE_SINGLESTEP: + SingleStep(target, trapFrame); + break; + case PTRACE_GETREGS: + break; + case PTRACE_SETREGS: + break; + case PTRACE_GETFPREGS: + break; + case PTRACE_SETFPREGS: + break; + case PTRACE_ATTACH: + break; + case PTRACE_DETACH: + break; + case PTRACE_GETFPXREGS: + break; + case PTRACE_SETFPXREGS: + break; + case PTRACE_SYSCALL: + break; + } + return NX_EOK; +} \ No newline at end of file diff --git a/src/arch/riscv64/kernel/trap.c b/src/arch/riscv64/kernel/trap.c index ce02889..143461b 100644 --- a/src/arch/riscv64/kernel/trap.c +++ b/src/arch/riscv64/kernel/trap.c @@ -15,6 +15,7 @@ #include #include #include +#include #define NX_LOG_NAME "Trap" #define NX_LOG_LEVEL NX_LOG_INFO @@ -280,7 +281,11 @@ void TrapDispatch(NX_HalTrapFrame *frame) return; case RISCV_BREAKPOINT: NX_LOG_E("riscv exception %s occur", msg); +#ifdef NX_DEBUG_STUB + GdbStubTrapHandler(frame); +#else NX_SignalSend(self->tid, NX_SIGNAL_TRAP, NX_NULL, NX_NULL); +#endif return; case RISCV_INS_ADDR_MISALIGNED: case RISCV_INS_ACCESS_FAULT: diff --git a/src/include/base/process.h b/src/include/base/process.h index 8a19a58..5695b52 100644 --- a/src/include/base/process.h +++ b/src/include/base/process.h @@ -52,6 +52,8 @@ struct NX_Process char cwd[NX_FILE_MAX_PATH]; /* current work diretory */ char exePath[NX_FILE_MAX_PATH]; /* execute path */ NX_ExposedObjectTable exobjTable; + + NX_U32 ptrace; }; typedef struct NX_Process NX_Process; diff --git a/src/include/base/ptrace.h b/src/include/base/ptrace.h new file mode 100644 index 0000000..f7568a2 --- /dev/null +++ b/src/include/base/ptrace.h @@ -0,0 +1,87 @@ +#ifndef __PTRACE_H__ +#define __PTRACE_H__ + +#define PT_PTRACED 0x00000001 + + +enum __ptrace_requese{ + /* Indicate that the process making this request should be traced. + All signals received by this process can be intercepted by its + parent, and its parent can use the other `ptrace' requests. */ + PTRACE_TRACEME = 0, +#define PT_TRACE_ME PTRACE_TRACEME + + /* Return the word in the process's text space at address ADDR. */ + PTRACE_PEEKTEXT = 1, +#define PT_READ_I PTRACE_PEEKTEXT + + /* Return the word in the process's data space at address ADDR. */ + PTRACE_PEEKDATA = 2, +#define PT_READ_D PTRACE_PEEKDATA + + /* Return the word in the process's user area at offset ADDR. */ + PTRACE_PEEKUSER = 3, +#define PT_READ_U PTRACE_PEEKUSER + + /* Write the word DATA into the process's text space at address ADDR. */ + PTRACE_POKETEXT = 4, +#define PT_WRITE_I PTRACE_POKETEXT + + /* Write the word DATA into the process's data space at address ADDR. */ + PTRACE_POKEDATA = 5, +#define PT_WRITE_D PTRACE_POKEDATA + + /* Write the word DATA into the process's user area at offset ADDR. */ + PTRACE_POKEUSER = 6, +#define PT_WRITE_U PTRACE_POKEUSER + + /* Continue the process. */ + PTRACE_CONT = 7, +#define PT_CONTINUE PTRACE_CONT + + /* Kill the process. */ + PTRACE_KILL = 8, +#define PT_KILL PTRACE_KILL + + /* Single step the process. */ + PTRACE_SINGLESTEP = 9, +#define PT_STEP PTRACE_SINGLESTEP + + /* Get all general purpose registers used by a processes. */ + PTRACE_GETREGS = 12, +#define PT_GETREGS PTRACE_GETREGS + + /* Set all general purpose registers used by a processes. */ + PTRACE_SETREGS = 13, +#define PT_SETREGS PTRACE_SETREGS + + /* Get all floating point registers used by a processes. */ + PTRACE_GETFPREGS = 14, +#define PT_GETFPREGS PTRACE_GETFPREGS + + /* Set all floating point registers used by a processes. */ + PTRACE_SETFPREGS = 15, +#define PT_SETFPREGS PTRACE_SETFPREGS + + /* Attach to a process that is already running. */ + PTRACE_ATTACH = 16, +#define PT_ATTACH PTRACE_ATTACH + + /* Detach from a process attached to with PTRACE_ATTACH. */ + PTRACE_DETACH = 17, +#define PT_DETACH PTRACE_DETACH + + /* Get all extended floating point registers used by a processes. */ + PTRACE_GETFPXREGS = 18, +#define PT_GETFPXREGS PTRACE_GETFPXREGS + + /* Set all extended floating point registers used by a processes. */ + PTRACE_SETFPXREGS = 19, +#define PT_SETFPXREGS PTRACE_SETFPXREGS + + /* Continue and stop at the next entry to or return from syscall. */ + PTRACE_SYSCALL = 24, +#define PT_SYSCALL PTRACE_SYSCALL +}; + +#endif \ No newline at end of file diff --git a/src/include/base/thread.h b/src/include/base/thread.h index 1801c77..43e97f6 100644 --- a/src/include/base/thread.h +++ b/src/include/base/thread.h @@ -125,6 +125,7 @@ struct NX_Thread NX_UArch onCore; /* thread on which core */ NX_UArch coreAffinity; /* thread would like to run on the core */ + NX_U32 singleStepNextInstruction; /* next single step instruction */ /* thread resource */ NX_ThreadResource resource; }; diff --git a/src/ipc/signal.c b/src/ipc/signal.c index e196fda..d84a0d0 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -350,6 +350,10 @@ NX_PRIVATE NX_Bool HandleUserSignal(NX_Thread * thread, NX_SignalTable * signalT NX_LOG_D("STOP thread %d with signal %d", thread->tid, info->signal); NX_ThreadBlock(thread); break; + case NX_SIGNAL_TRAP: + NX_LOG_D("TRAP thread %d with signal %d", thread->tid, info->signal); + NX_ThreadBlock(thread); + break; default: /* kill thread */ NX_LOG_D("KILL thread %d with signal %d", thread->tid, info->signal); NX_ThreadExit(0); diff --git a/src/kernel/Kconfig b/src/kernel/Kconfig index 780453c..986633d 100644 --- a/src/kernel/Kconfig +++ b/src/kernel/Kconfig @@ -22,6 +22,10 @@ if NX_DEBUG endif +config NX_DEBUG_STUB + bool "Stub for debug" + default n + endmenu menu "Hook system" diff --git a/src/process/process.c b/src/process/process.c index d472018..54d1a77 100644 --- a/src/process/process.c +++ b/src/process/process.c @@ -128,6 +128,8 @@ NX_PRIVATE NX_Process *NX_ProcessCreateObject(NX_U32 flags) NX_MemZero(process->cwd, sizeof(process->cwd)); NX_StrCopy(process->cwd, NX_PROCESS_CWD_DEFAULT); + process->ptrace = 0; + return process; } diff --git a/src/process/syscall.c b/src/process/syscall.c index 37fb420..cf49594 100644 --- a/src/process/syscall.c +++ b/src/process/syscall.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "process_impl.h" @@ -2813,6 +2814,11 @@ NX_Error SysSoltCopy(NX_Solt dest, NX_Solt solt, NX_Solt * outSolt) return err; } +NX_Error SysPtrace(enum __ptrace_requese request, NX_I32 tid, void * addr, void * data) +{ + return Ptrace(request, tid, addr, data); +} + /* xbook env syscall table */ NX_PRIVATE const NX_SyscallHandler NX_SyscallTable[] = { @@ -2912,6 +2918,7 @@ NX_PRIVATE const NX_SyscallHandler NX_SyscallTable[] = SysFifoWrite, SysFifoLength, /* 95 */ SysSoltCopy, + SysPtrace, }; /* posix env syscall table */ diff --git a/src/sched/thread.c b/src/sched/thread.c index 232d4d5..2cb6c2e 100644 --- a/src/sched/thread.c +++ b/src/sched/thread.c @@ -76,6 +76,8 @@ NX_PRIVATE NX_Error ThreadInit(NX_Thread *thread, thread->onCore = NX_MULTI_CORES_NR; /* not on any core */ thread->coreAffinity = NX_MULTI_CORES_NR; /* no core affinity */ + thread->singleStepNextInstruction = 0; + thread->resource.sleepTimer = NX_NULL; thread->resource.process = NX_NULL; thread->resource.fileTable = NX_FileTableGetDefault(); -- Gitee From a14a469c852114fbf277a447b42ad19e0abdec93 Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Thu, 21 Sep 2023 21:33:08 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86ptrace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/arch/riscv64/include/ptrace.h | 2 +- src/arch/riscv64/kernel/ptrac.c | 2 +- src/include/base/ptrace.h | 2 +- src/include/base/signal.h | 1 + src/process/syscall.c | 4 ++-- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/arch/riscv64/include/ptrace.h b/src/arch/riscv64/include/ptrace.h index fc72109..92d8b64 100644 --- a/src/arch/riscv64/include/ptrace.h +++ b/src/arch/riscv64/include/ptrace.h @@ -6,6 +6,6 @@ #define gdb_c_ebreak_instruction 0x9002 #define gdb_ebreak_instruction 0x00100073 -NX_Error Ptrace(enum __ptrace_requese request, NX_I32 tid, void * addr, void * data); +NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * data); #endif \ No newline at end of file diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index 420cfb1..8d8a09f 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -245,7 +245,7 @@ NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) return 0; } -NX_Error Ptrace(enum __ptrace_requese request, NX_I32 tid, void * addr, void * data) +NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * data) { NX_Process * process; process = NX_ProcessCurrent(); diff --git a/src/include/base/ptrace.h b/src/include/base/ptrace.h index f7568a2..715193d 100644 --- a/src/include/base/ptrace.h +++ b/src/include/base/ptrace.h @@ -4,7 +4,7 @@ #define PT_PTRACED 0x00000001 -enum __ptrace_requese{ +enum __ptrace_request{ /* Indicate that the process making this request should be traced. All signals received by this process can be intercepted by its parent, and its parent can use the other `ptrace' requests. */ diff --git a/src/include/base/signal.h b/src/include/base/signal.h index 565aeca..6085e8d 100644 --- a/src/include/base/signal.h +++ b/src/include/base/signal.h @@ -34,6 +34,7 @@ #define NX_SIGNAL_SEGV 14 /* segment fault */ #define NX_SIGNAL_ILLEGAL 15 /* illegal instruction */ #define NX_SIGNAL_INST 16 /* instruction aceesss */ +#define NX_SIGNAL_CHILD 17 /* child process */ /* ...-31 RESERVED */ #define NX_SIGNAL_ANONYMOUS 32 /* anonymous signal */ diff --git a/src/process/syscall.c b/src/process/syscall.c index cf49594..2017746 100644 --- a/src/process/syscall.c +++ b/src/process/syscall.c @@ -36,7 +36,7 @@ #include #include #include - +#include "ptrace.h" #include "process_impl.h" NX_PRIVATE int SysInvalidCall(void) @@ -2814,7 +2814,7 @@ NX_Error SysSoltCopy(NX_Solt dest, NX_Solt solt, NX_Solt * outSolt) return err; } -NX_Error SysPtrace(enum __ptrace_requese request, NX_I32 tid, void * addr, void * data) +NX_Error SysPtrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * data) { return Ptrace(request, tid, addr, data); } -- Gitee From b06d1465bd4f77a2aecd3cda75ce00ca348deeae Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Thu, 21 Sep 2023 23:01:16 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ptrace=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/arch/riscv64/include/ptrace.h | 10 ++++++++++ src/arch/riscv64/kernel/ptrac.c | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/src/arch/riscv64/include/ptrace.h b/src/arch/riscv64/include/ptrace.h index 92d8b64..52f5222 100644 --- a/src/arch/riscv64/include/ptrace.h +++ b/src/arch/riscv64/include/ptrace.h @@ -3,6 +3,16 @@ #include "base/error.h" #include "base/ptrace.h" +struct Registers{ + NX_UArch reg[32]; +}NX_PACKED; +typedef struct Registers Registers; + +struct FpRegisters{ + NX_UArch fp[32]; +}NX_PACKED; +typedef struct FpRegisters FpRegisters; + #define gdb_c_ebreak_instruction 0x9002 #define gdb_ebreak_instruction 0x00100073 diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index 8d8a09f..94484b0 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -1,5 +1,6 @@ #include "base/thread.h" #include "base/process.h" +#include "base/uaccess.h" #include "ptrace.h" #include "irq.h" @@ -256,6 +257,7 @@ NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * d } NX_HalTrapFrame * trapFrame; trapFrame = (NX_HalTrapFrame*)target->stackBase + target->stackSize - sizeof(NX_HalTrapFrame); + NX_U64 tmpTrapFrame = (NX_U64)trapFrame; switch (request) { case PTRACE_TRACEME: @@ -291,12 +293,16 @@ NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * d SingleStep(target, trapFrame); break; case PTRACE_GETREGS: + NX_CopyToUser((char*)data, (char*)trapFrame, sizeof(Registers)); break; case PTRACE_SETREGS: + NX_CopyFromUser((char*)trapFrame, (char*)data, sizeof(Registers)); break; case PTRACE_GETFPREGS: + NX_CopyToUser((char*)data, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), sizeof(FpRegisters)); break; case PTRACE_SETFPREGS: + NX_CopyFromUser((char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), (char*)data, sizeof(FpRegisters)); break; case PTRACE_ATTACH: break; -- Gitee From 15638965b0999845642253f92c830bf36f011c1b Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Fri, 22 Sep 2023 20:31:47 +0800 Subject: [PATCH 4/9] fix:Modify the incorrect use of ptrace soldt and the copying error of the address space. use nx_solt to find child thread, ptrace_getregs should use NX_VmspaceRead instead of NX_MemCopy --- src/arch/riscv64/include/ptrace.h | 3 ++- src/arch/riscv64/kernel/ptrac.c | 14 +++++--------- src/process/syscall.c | 25 +++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/arch/riscv64/include/ptrace.h b/src/arch/riscv64/include/ptrace.h index 52f5222..589d191 100644 --- a/src/arch/riscv64/include/ptrace.h +++ b/src/arch/riscv64/include/ptrace.h @@ -2,6 +2,7 @@ #define __PTRACE_RISCV_H__ #include "base/error.h" #include "base/ptrace.h" +#include "base/thread.h" struct Registers{ NX_UArch reg[32]; @@ -16,6 +17,6 @@ typedef struct FpRegisters FpRegisters; #define gdb_c_ebreak_instruction 0x9002 #define gdb_ebreak_instruction 0x00100073 -NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * data); +NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, void * data); #endif \ No newline at end of file diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index 94484b0..cd2ac52 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -246,15 +246,11 @@ NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) return 0; } -NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * data) +NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, void * data) { NX_Process * process; process = NX_ProcessCurrent(); NX_U64 buf; - NX_Thread * target = NX_ThreadFindById(tid); - if(!target){ - return -NX_EINVAL; - } NX_HalTrapFrame * trapFrame; trapFrame = (NX_HalTrapFrame*)target->stackBase + target->stackSize - sizeof(NX_HalTrapFrame); NX_U64 tmpTrapFrame = (NX_U64)trapFrame; @@ -293,16 +289,16 @@ NX_Error Ptrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * d SingleStep(target, trapFrame); break; case PTRACE_GETREGS: - NX_CopyToUser((char*)data, (char*)trapFrame, sizeof(Registers)); + NX_VmspaceRead(&target->resource.process->vmspace, (char*)trapFrame, (char*)data, sizeof(Registers)); break; case PTRACE_SETREGS: - NX_CopyFromUser((char*)trapFrame, (char*)data, sizeof(Registers)); + NX_VmspaceWrite(&target->resource.process->vmspace, (char*)trapFrame, (char*)data, sizeof(Registers)); break; case PTRACE_GETFPREGS: - NX_CopyToUser((char*)data, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), sizeof(FpRegisters)); + NX_VmspaceRead(&target->resource.process->vmspace, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), (char*)data, sizeof(FpRegisters)); break; case PTRACE_SETFPREGS: - NX_CopyFromUser((char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), (char*)data, sizeof(FpRegisters)); + NX_VmspaceWrite(&target->resource.process->vmspace, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), (char*)data, sizeof(FpRegisters)); break; case PTRACE_ATTACH: break; diff --git a/src/process/syscall.c b/src/process/syscall.c index 2017746..da67933 100644 --- a/src/process/syscall.c +++ b/src/process/syscall.c @@ -2814,9 +2814,30 @@ NX_Error SysSoltCopy(NX_Solt dest, NX_Solt solt, NX_Solt * outSolt) return err; } -NX_Error SysPtrace(enum __ptrace_request request, NX_I32 tid, void * addr, void * data) +NX_Error SysPtrace(enum __ptrace_request request, NX_Solt solt, void * addr, void * data) { - return Ptrace(request, tid, addr, data); + NX_ExposedObject * exobj; + NX_Thread * thread; + + if (solt == NX_SOLT_INVALID_VALUE) + { + return NX_EINVAL; + } + + exobj = NX_ProcessGetSolt(NX_ProcessCurrent(), solt); + if (exobj == NX_NULL) + { + return NX_ENOSRCH; + } + + if (exobj->type != NX_EXOBJ_THREAD) + { + return NX_ENORES; + } + thread = (NX_Thread *)exobj->object; + NX_ASSERT(thread); + NX_Printf("ptrace: target thread:%s\n", thread->name); + return Ptrace(request, thread, addr, data); } /* xbook env syscall table */ -- Gitee From f1fe946a28c2843badd82772a7881f31162eb0c1 Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Tue, 26 Sep 2023 22:41:55 +0800 Subject: [PATCH 5/9] fix:fix ptrace singlestep command --- src/arch/riscv64/include/ptrace.h | 2 ++ src/arch/riscv64/kernel/ptrac.c | 6 ++++++ src/ipc/signal.c | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/src/arch/riscv64/include/ptrace.h b/src/arch/riscv64/include/ptrace.h index 589d191..866d10e 100644 --- a/src/arch/riscv64/include/ptrace.h +++ b/src/arch/riscv64/include/ptrace.h @@ -3,6 +3,7 @@ #include "base/error.h" #include "base/ptrace.h" #include "base/thread.h" +#include "irq.h" struct Registers{ NX_UArch reg[32]; @@ -18,5 +19,6 @@ typedef struct FpRegisters FpRegisters; #define gdb_ebreak_instruction 0x00100073 NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, void * data); +NX_I32 SingleStepCallBack(NX_Thread * thread, NX_HalTrapFrame * trapFrame); #endif \ No newline at end of file diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index cd2ac52..f9f9844 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -5,6 +5,12 @@ #include "ptrace.h" #include "irq.h" +NX_I32 SingleStepCallBack(NX_Thread * thread, NX_HalTrapFrame * trapFrame) +{ + NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)trapFrame->epc, (char*)&thread->singleStepNextInstruction, sizeof(NX_U32)); + return 0; +} + NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) { NX_U32 instruction = 0; diff --git a/src/ipc/signal.c b/src/ipc/signal.c index d84a0d0..5c3f5ff 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -17,6 +17,7 @@ #define NX_LOG_LEVEL NX_LOG_INFO #include #include +#include "ptrace.h" NX_Error NX_SignalTableInit(NX_SignalTable * table) { @@ -353,6 +354,10 @@ NX_PRIVATE NX_Bool HandleUserSignal(NX_Thread * thread, NX_SignalTable * signalT case NX_SIGNAL_TRAP: NX_LOG_D("TRAP thread %d with signal %d", thread->tid, info->signal); NX_ThreadBlock(thread); + NX_SignalSend(thread->resource.process->parentPid, NX_SIGNAL_CHILD, NX_NULL, NX_NULL); + if(thread->singleStepNextInstruction != 0){ + SingleStepCallBack(thread, trapframe); + } break; default: /* kill thread */ NX_LOG_D("KILL thread %d with signal %d", thread->tid, info->signal); -- Gitee From c581953028932565b20c587debd0402018cfa837 Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Sat, 30 Sep 2023 10:28:50 +0800 Subject: [PATCH 6/9] fix:ptrace, Modified the initial state of the debugged program. The debugged program should set the first statement to ebreak at the beginning to correctly initialize the relevant registers, otherwise the contents of the kernel structure will be exposed to the outside world. --- src/arch/riscv64/include/ptrace.h | 2 +- src/arch/riscv64/kernel/gdbstub.c | 12 +++++++----- src/arch/riscv64/kernel/ptrac.c | 11 +++++++++++ src/include/base/thread.h | 1 + src/ipc/signal.c | 7 +++++-- src/process/process.c | 4 ++++ src/process/syscall.c | 1 - 7 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/arch/riscv64/include/ptrace.h b/src/arch/riscv64/include/ptrace.h index 866d10e..a94b2d3 100644 --- a/src/arch/riscv64/include/ptrace.h +++ b/src/arch/riscv64/include/ptrace.h @@ -20,5 +20,5 @@ typedef struct FpRegisters FpRegisters; NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, void * data); NX_I32 SingleStepCallBack(NX_Thread * thread, NX_HalTrapFrame * trapFrame); - +NX_I32 StartSingleStep(NX_Thread * thread); #endif \ No newline at end of file diff --git a/src/arch/riscv64/kernel/gdbstub.c b/src/arch/riscv64/kernel/gdbstub.c index 7500743..bbc3539 100644 --- a/src/arch/riscv64/kernel/gdbstub.c +++ b/src/arch/riscv64/kernel/gdbstub.c @@ -7,6 +7,9 @@ #define GDB_EOF -1 #define GDB_PRINT(...) +#define GDB_ASSERT(x) \ + do { \ + } while (0) #define PKT_BUF_LEN 4096 #ifndef __GDB_MAX_BREAKPOINTS_NUM_ @@ -1770,15 +1773,14 @@ void gdb_sys_init(void) { } // receive init '+' - if (gdb_sys_getc(NX_NULL) != '+') { - gdb_sys_putchar(NX_NULL, '-'); - gdb_sys_putchar(NX_NULL, '1'); - + while(gdb_sys_getc(NX_NULL) != '+') { + } gdbStateGlobal.signum = 5; gdbStateGlobal.lastbp = -2; isStartEbreakExectued = 0; // __asm__ volatile("ebreak"); } - +#ifdef NX_DEBUG_STUB NX_INITCALL(gdb_sys_init); +#endif \ No newline at end of file diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index f9f9844..cef8b3f 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -1,9 +1,11 @@ +#include "base/console.h" #include "base/thread.h" #include "base/process.h" #include "base/uaccess.h" #include "ptrace.h" #include "irq.h" +#include "arch/process.h" NX_I32 SingleStepCallBack(NX_Thread * thread, NX_HalTrapFrame * trapFrame) { @@ -11,6 +13,15 @@ NX_I32 SingleStepCallBack(NX_Thread * thread, NX_HalTrapFrame * trapFrame) return 0; } +NX_I32 StartSingleStep(NX_Thread * thread){ + NX_U32 instruction; + NX_VmspaceRead(&thread->resource.process->vmspace, (char*)NX_USER_IMAGE_VADDR, (char*)&instruction, sizeof(NX_U32)); + thread->singleStepNextInstruction = instruction; + NX_U32 ebreak = gdb_ebreak_instruction; + NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)NX_USER_IMAGE_VADDR, (char*)&ebreak, sizeof(NX_U32)); + return 0; +} + NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) { NX_U32 instruction = 0; diff --git a/src/include/base/thread.h b/src/include/base/thread.h index 43e97f6..d8141de 100644 --- a/src/include/base/thread.h +++ b/src/include/base/thread.h @@ -46,6 +46,7 @@ #define NX_THREAD_CREATE_NORMAL 0x00 /* thread create with normal flag(no wait, no suspend, running) */ #define NX_THREAD_CREATE_SUSPEND 0x01 /* thread create with suspend flag(no running) */ #define NX_THREAD_CREATE_WAIT 0x02 /* thread create with wait thread exit(no return, must wait exit) */ +#define NX_THREAD_CREATE_DEBUG 0x04 /* thread create to be debugged by gdb */ #define NX_THREAD_FLAG_SIGNAL_INTR 0x01 /* thread was interrupted by signal */ #define NX_THREAD_FLAG_UNINTERRUPTABLE 0x02 /* thread was uninterrupted by signal */ diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 5c3f5ff..1b04c83 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -353,11 +353,14 @@ NX_PRIVATE NX_Bool HandleUserSignal(NX_Thread * thread, NX_SignalTable * signalT break; case NX_SIGNAL_TRAP: NX_LOG_D("TRAP thread %d with signal %d", thread->tid, info->signal); - NX_ThreadBlock(thread); - NX_SignalSend(thread->resource.process->parentPid, NX_SIGNAL_CHILD, NX_NULL, NX_NULL); + if(NX_SignalSend(thread->resource.process->parentPid, NX_SIGNAL_CHILD, NX_NULL, NX_NULL) != 0){ + NX_Printf("send signal error\n"); + } if(thread->singleStepNextInstruction != 0){ SingleStepCallBack(thread, trapframe); + thread->singleStepNextInstruction = 0; } + NX_ThreadBlock(thread); break; default: /* kill thread */ NX_LOG_D("KILL thread %d with signal %d", thread->tid, info->signal); diff --git a/src/process/process.c b/src/process/process.c index 54d1a77..519f5cd 100644 --- a/src/process/process.c +++ b/src/process/process.c @@ -31,6 +31,7 @@ #include #include #include +#include "ptrace.h" NX_PRIVATE NX_Error NX_ProcessWait(NX_Process * process, NX_U32 *exitCode); @@ -836,6 +837,9 @@ NX_Error NX_ProcessLaunch(char *path, NX_U32 flags, NX_U32 *exitCode, if (!(flags & NX_THREAD_CREATE_SUSPEND)) { + if(flags & NX_THREAD_CREATE_DEBUG){ + StartSingleStep(thread); + } if (NX_ThreadStart(thread) != NX_EOK) { if (self->resource.process) diff --git a/src/process/syscall.c b/src/process/syscall.c index da67933..2abc0c3 100644 --- a/src/process/syscall.c +++ b/src/process/syscall.c @@ -2836,7 +2836,6 @@ NX_Error SysPtrace(enum __ptrace_request request, NX_Solt solt, void * addr, voi } thread = (NX_Thread *)exobj->object; NX_ASSERT(thread); - NX_Printf("ptrace: target thread:%s\n", thread->name); return Ptrace(request, thread, addr, data); } -- Gitee From e754794b635ffa9a30c88db1d7fe32fa4a473820 Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Sun, 8 Oct 2023 11:57:59 +0800 Subject: [PATCH 7/9] fix:fix some riscv ptrace bug --- src/arch/riscv64/kernel/ptrac.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index cef8b3f..35aace0 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -21,7 +21,11 @@ NX_I32 StartSingleStep(NX_Thread * thread){ NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)NX_USER_IMAGE_VADDR, (char*)&ebreak, sizeof(NX_U32)); return 0; } - +/** +* return value: +* 0: single step success +* 1: the instruction is not control transfer instruction, so gdb should wait for child process stop +*/ NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) { NX_U32 instruction = 0; @@ -109,6 +113,7 @@ NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) thread->singleStepNextInstruction = instruction; NX_U32 ebreak = gdb_ebreak_instruction; NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)trapFrame->epc + 2, (char*)&ebreak, sizeof(NX_U32)); + NX_ThreadUnblock(thread); return 1; } }else if ((instruction & 0x3) == 0x3 && (instruction & 0x1c) != 0x1c) { @@ -255,6 +260,7 @@ NX_I32 SingleStep(NX_Thread * thread, NX_HalTrapFrame * trapFrame) thread->singleStepNextInstruction = instruction; NX_U32 ebreak = gdb_ebreak_instruction; NX_VmspaceWrite(&thread->resource.process->vmspace, (char*)trapFrame->epc + 4, (char*)&ebreak, sizeof(NX_U32)); + NX_ThreadUnblock(thread); return 1; } } else { @@ -269,7 +275,7 @@ NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, v process = NX_ProcessCurrent(); NX_U64 buf; NX_HalTrapFrame * trapFrame; - trapFrame = (NX_HalTrapFrame*)target->stackBase + target->stackSize - sizeof(NX_HalTrapFrame); + trapFrame = (NX_HalTrapFrame*)(target->stackBase + target->stackSize - sizeof(NX_HalTrapFrame)); NX_U64 tmpTrapFrame = (NX_U64)trapFrame; switch (request) { @@ -303,19 +309,19 @@ NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, v NX_SignalSend(target->tid, NX_SIGNAL_KILL, NX_NULL, NX_NULL); break; case PTRACE_SINGLESTEP: - SingleStep(target, trapFrame); + return SingleStep(target, trapFrame); break; case PTRACE_GETREGS: - NX_VmspaceRead(&target->resource.process->vmspace, (char*)trapFrame, (char*)data, sizeof(Registers)); + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)trapFrame, sizeof(Registers)); break; case PTRACE_SETREGS: - NX_VmspaceWrite(&target->resource.process->vmspace, (char*)trapFrame, (char*)data, sizeof(Registers)); + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)trapFrame, sizeof(Registers)); break; case PTRACE_GETFPREGS: - NX_VmspaceRead(&target->resource.process->vmspace, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), (char*)data, sizeof(FpRegisters)); + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), sizeof(FpRegisters)); break; case PTRACE_SETFPREGS: - NX_VmspaceWrite(&target->resource.process->vmspace, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), (char*)data, sizeof(FpRegisters)); + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), sizeof(FpRegisters)); break; case PTRACE_ATTACH: break; -- Gitee From d2cf3fceeb6507cf599a3dc51d7a9fd41f966b5f Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Tue, 17 Oct 2023 17:33:33 +0800 Subject: [PATCH 8/9] refactor: change some ptrace request definition --- src/arch/riscv64/kernel/ptrac.c | 49 +++++++++++---------- src/include/base/ptrace.h | 75 ++++++++------------------------- 2 files changed, 41 insertions(+), 83 deletions(-) diff --git a/src/arch/riscv64/kernel/ptrac.c b/src/arch/riscv64/kernel/ptrac.c index 35aace0..116bb64 100644 --- a/src/arch/riscv64/kernel/ptrac.c +++ b/src/arch/riscv64/kernel/ptrac.c @@ -279,29 +279,38 @@ NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, v NX_U64 tmpTrapFrame = (NX_U64)trapFrame; switch (request) { - case PTRACE_TRACEME: - if(process->ptrace & PT_PTRACED){ - return -1; - }else{ - process->ptrace |= PT_PTRACED; - } + case PTRACE_PEEKINT8: + NX_VmspaceRead(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U8)); + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U8)); + break; + case PTRACE_PEEKINT16: + NX_VmspaceRead(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U16)); + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U16)); + break; + case PTRACE_PEEKINT32: + NX_VmspaceRead(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U32)); + NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U32)); break; - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: + case PTRACE_PEEKINT64: NX_VmspaceRead(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U64)); NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U64)); break; - case PTRACE_PEEKUSER: - NX_VmspaceWrite(&process->vmspace, (char*)data, (char*)trapFrame, sizeof(NX_HalTrapFrame)); + case PTRACE_POKEINT8: + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U8)); + NX_VmspaceWrite(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U8)); break; - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: + case PTRACE_POKEINT16: + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U16)); + NX_VmspaceWrite(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U16)); + break; + case PTRACE_POKEINT32: + NX_VmspaceRead(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U32)); + NX_VmspaceWrite(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U32)); + break; + case PTRACE_POKEINT64: NX_VmspaceRead(&process->vmspace, (char*)data, (char*)&buf, sizeof(NX_U64)); NX_VmspaceWrite(&target->resource.process->vmspace, (char*)addr, (char*)&buf, sizeof(NX_U64)); break; - case PTRACE_POKEUSER: - NX_VmspaceRead(&process->vmspace, (char*)data, (char*)trapFrame, sizeof(NX_HalTrapFrame)); - break; case PTRACE_CONT: NX_ThreadUnblock(target); break; @@ -323,16 +332,6 @@ NX_Error Ptrace(enum __ptrace_request request, NX_Thread* target, void * addr, v case PTRACE_SETFPREGS: NX_VmspaceRead(&process->vmspace, (char*)data, (char*)(tmpTrapFrame + sizeof(Registers) + sizeof(NX_UArch)), sizeof(FpRegisters)); break; - case PTRACE_ATTACH: - break; - case PTRACE_DETACH: - break; - case PTRACE_GETFPXREGS: - break; - case PTRACE_SETFPXREGS: - break; - case PTRACE_SYSCALL: - break; } return NX_EOK; } \ No newline at end of file diff --git a/src/include/base/ptrace.h b/src/include/base/ptrace.h index 715193d..831a5b3 100644 --- a/src/include/base/ptrace.h +++ b/src/include/base/ptrace.h @@ -1,87 +1,46 @@ #ifndef __PTRACE_H__ #define __PTRACE_H__ -#define PT_PTRACED 0x00000001 - enum __ptrace_request{ - /* Indicate that the process making this request should be traced. - All signals received by this process can be intercepted by its - parent, and its parent can use the other `ptrace' requests. */ - PTRACE_TRACEME = 0, -#define PT_TRACE_ME PTRACE_TRACEME - /* Return the word in the process's text space at address ADDR. */ - PTRACE_PEEKTEXT = 1, -#define PT_READ_I PTRACE_PEEKTEXT + PTRACE_PEEKINT8 = 0, + + PTRACE_PEEKINT16 = 1, - /* Return the word in the process's data space at address ADDR. */ - PTRACE_PEEKDATA = 2, -#define PT_READ_D PTRACE_PEEKDATA + PTRACE_PEEKINT32 = 2, - /* Return the word in the process's user area at offset ADDR. */ - PTRACE_PEEKUSER = 3, -#define PT_READ_U PTRACE_PEEKUSER + PTRACE_PEEKINT64 = 3, - /* Write the word DATA into the process's text space at address ADDR. */ - PTRACE_POKETEXT = 4, -#define PT_WRITE_I PTRACE_POKETEXT + PTRACE_POKEINT8 = 4, - /* Write the word DATA into the process's data space at address ADDR. */ - PTRACE_POKEDATA = 5, -#define PT_WRITE_D PTRACE_POKEDATA + PTRACE_POKEINT16 = 5, - /* Write the word DATA into the process's user area at offset ADDR. */ - PTRACE_POKEUSER = 6, -#define PT_WRITE_U PTRACE_POKEUSER + PTRACE_POKEINT32 = 6, + + PTRACE_POKEINT64 = 7, /* Continue the process. */ - PTRACE_CONT = 7, -#define PT_CONTINUE PTRACE_CONT + PTRACE_CONT = 8, /* Kill the process. */ - PTRACE_KILL = 8, -#define PT_KILL PTRACE_KILL + PTRACE_KILL = 9, /* Single step the process. */ - PTRACE_SINGLESTEP = 9, -#define PT_STEP PTRACE_SINGLESTEP + PTRACE_SINGLESTEP = 10, /* Get all general purpose registers used by a processes. */ - PTRACE_GETREGS = 12, -#define PT_GETREGS PTRACE_GETREGS + PTRACE_GETREGS = 11, /* Set all general purpose registers used by a processes. */ - PTRACE_SETREGS = 13, -#define PT_SETREGS PTRACE_SETREGS + PTRACE_SETREGS = 12, /* Get all floating point registers used by a processes. */ - PTRACE_GETFPREGS = 14, -#define PT_GETFPREGS PTRACE_GETFPREGS + PTRACE_GETFPREGS = 13, /* Set all floating point registers used by a processes. */ - PTRACE_SETFPREGS = 15, -#define PT_SETFPREGS PTRACE_SETFPREGS - - /* Attach to a process that is already running. */ - PTRACE_ATTACH = 16, -#define PT_ATTACH PTRACE_ATTACH - - /* Detach from a process attached to with PTRACE_ATTACH. */ - PTRACE_DETACH = 17, -#define PT_DETACH PTRACE_DETACH - - /* Get all extended floating point registers used by a processes. */ - PTRACE_GETFPXREGS = 18, -#define PT_GETFPXREGS PTRACE_GETFPXREGS - - /* Set all extended floating point registers used by a processes. */ - PTRACE_SETFPXREGS = 19, -#define PT_SETFPXREGS PTRACE_SETFPXREGS + PTRACE_SETFPREGS = 14, - /* Continue and stop at the next entry to or return from syscall. */ - PTRACE_SYSCALL = 24, -#define PT_SYSCALL PTRACE_SYSCALL }; #endif \ No newline at end of file -- Gitee From 1d328bbeff26fe2db52525ae3afb27d33a7f2bb0 Mon Sep 17 00:00:00 2001 From: zxt <1163862613@qq.com> Date: Sat, 28 Oct 2023 23:22:28 +0800 Subject: [PATCH 9/9] fix: fix ebreak processing method --- src/arch/riscv64/kernel/trap.c | 10 +++++++++- src/ipc/signal.c | 12 ------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/arch/riscv64/kernel/trap.c b/src/arch/riscv64/kernel/trap.c index b719664..bad31d8 100644 --- a/src/arch/riscv64/kernel/trap.c +++ b/src/arch/riscv64/kernel/trap.c @@ -27,6 +27,7 @@ #include #include #include +#include "ptrace.h" #define RISCV_INS_ADDR_MISALIGNED 0 #define RISCV_INS_ACCESS_FAULT 1 @@ -286,7 +287,14 @@ void TrapDispatch(NX_HalTrapFrame *frame) #ifdef NX_DEBUG_STUB GdbStubTrapHandler(frame); #else - NX_SignalSend(self->tid, NX_SIGNAL_TRAP, NX_NULL, NX_NULL); + if(NX_SignalSend(self->resource.process->parentPid, NX_SIGNAL_CHILD, NX_NULL, NX_NULL) != 0){ + NX_Printf("send signal error\n"); + } + if(self->singleStepNextInstruction != 0){ + SingleStepCallBack(self, frame); + self->singleStepNextInstruction = 0; + } + NX_ThreadBlock(self); #endif return; case RISCV_INS_ADDR_MISALIGNED: diff --git a/src/ipc/signal.c b/src/ipc/signal.c index 7b8cbbc..597d6a4 100644 --- a/src/ipc/signal.c +++ b/src/ipc/signal.c @@ -17,7 +17,6 @@ #define NX_LOG_LEVEL NX_LOG_INFO #include #include -#include "ptrace.h" NX_Error NX_SignalTableInit(NX_SignalTable * table) { @@ -351,17 +350,6 @@ NX_PRIVATE NX_Bool HandleUserSignal(NX_Thread * thread, NX_SignalTable * signalT NX_LOG_D("STOP thread %d with signal %d", thread->tid, info->signal); NX_ThreadBlock(thread); break; - case NX_SIGNAL_TRAP: - NX_LOG_D("TRAP thread %d with signal %d", thread->tid, info->signal); - if(NX_SignalSend(thread->resource.process->parentPid, NX_SIGNAL_CHILD, NX_NULL, NX_NULL) != 0){ - NX_Printf("send signal error\n"); - } - if(thread->singleStepNextInstruction != 0){ - SingleStepCallBack(thread, trapframe); - thread->singleStepNextInstruction = 0; - } - NX_ThreadBlock(thread); - break; default: /* kill thread */ NX_LOG_D("KILL thread %d with signal %d", thread->tid, info->signal); NX_ThreadExit(0); -- Gitee