diff options
Diffstat (limited to 'gdbstub/internals.h')
| -rw-r--r-- | gdbstub/internals.h | 212 |
1 files changed, 209 insertions, 3 deletions
diff --git a/gdbstub/internals.h b/gdbstub/internals.h index b23999f951..94ddff4495 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -6,14 +6,220 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _INTERNALS_H_ -#define _INTERNALS_H_ +#ifndef GDBSTUB_INTERNALS_H +#define GDBSTUB_INTERNALS_H #include "exec/cpu-common.h" +#define MAX_PACKET_LENGTH 4096 + +/* + * Shared structures and definitions + */ + +enum { + GDB_SIGNAL_0 = 0, + GDB_SIGNAL_INT = 2, + GDB_SIGNAL_QUIT = 3, + GDB_SIGNAL_TRAP = 5, + GDB_SIGNAL_ABRT = 6, + GDB_SIGNAL_ALRM = 14, + GDB_SIGNAL_IO = 23, + GDB_SIGNAL_XCPU = 24, + GDB_SIGNAL_UNKNOWN = 143 +}; + +typedef struct GDBProcess { + uint32_t pid; + bool attached; + + char target_xml[1024]; +} GDBProcess; + +enum RSState { + RS_INACTIVE, + RS_IDLE, + RS_GETLINE, + RS_GETLINE_ESC, + RS_GETLINE_RLE, + RS_CHKSUM1, + RS_CHKSUM2, +}; + +typedef struct GDBState { + bool init; /* have we been initialised? */ + CPUState *c_cpu; /* current CPU for step/continue ops */ + CPUState *g_cpu; /* current CPU for other ops */ + CPUState *query_cpu; /* for q{f|s}ThreadInfo */ + enum RSState state; /* parsing state */ + char line_buf[MAX_PACKET_LENGTH]; + int line_buf_index; + int line_sum; /* running checksum */ + int line_csum; /* checksum at the end of the packet */ + GByteArray *last_packet; + int signal; + bool multiprocess; + GDBProcess *processes; + int process_num; + GString *str_buf; + GByteArray *mem_buf; + int sstep_flags; + int supported_sstep_flags; +} GDBState; + +/* lives in main gdbstub.c */ +extern GDBState gdbserver_state; + +/* + * Inline utility function, convert from int to hex and back + */ + +static inline int fromhex(int v) +{ + if (v >= '0' && v <= '9') { + return v - '0'; + } else if (v >= 'A' && v <= 'F') { + return v - 'A' + 10; + } else if (v >= 'a' && v <= 'f') { + return v - 'a' + 10; + } else { + return 0; + } +} + +static inline int tohex(int v) +{ + if (v < 10) { + return v + '0'; + } else { + return v - 10 + 'a'; + } +} + +/* + * Connection helpers for both softmmu and user backends + */ + +void gdb_put_strbuf(void); +int gdb_put_packet(const char *buf); +int gdb_put_packet_binary(const char *buf, int len, bool dump); +void gdb_hextomem(GByteArray *mem, const char *buf, int len); +void gdb_memtohex(GString *buf, const uint8_t *mem, int len); +void gdb_memtox(GString *buf, const char *mem, int len); +void gdb_read_byte(uint8_t ch); + +/* + * Packet acknowledgement - we handle this slightly differently + * between user and softmmu mode, mainly to deal with the differences + * between the flexible chardev and the direct fd approaches. + * + * We currently don't support a negotiated QStartNoAckMode + */ + +/** + * gdb_got_immediate_ack() - check ok to continue + * + * Returns true to continue, false to re-transmit for user only, the + * softmmu stub always returns true. + */ +bool gdb_got_immediate_ack(void); +/* utility helpers */ +CPUState *gdb_first_attached_cpu(void); +void gdb_append_thread_id(CPUState *cpu, GString *buf); +int gdb_get_cpu_index(CPUState *cpu); +unsigned int gdb_get_max_cpus(void); /* both */ +bool gdb_can_reverse(void); /* softmmu, stub for user */ + +void gdb_create_default_process(GDBState *s); + +/* signal mapping, common for softmmu, specialised for user-mode */ +int gdb_signal_to_target(int sig); +int gdb_target_signal_to_gdb(int sig); + +int gdb_get_char(void); /* user only */ + +/** + * gdb_continue() - handle continue in mode specific way. + */ +void gdb_continue(void); + +/** + * gdb_continue_partial() - handle partial continue in mode specific way. + */ +int gdb_continue_partial(char *newstates); + +/* + * Helpers with separate softmmu and user implementations + */ +void gdb_put_buffer(const uint8_t *buf, int len); + +/* + * Command handlers - either specialised or softmmu or user only + */ +void gdb_init_gdbserver_state(void); + +typedef enum GDBThreadIdKind { + GDB_ONE_THREAD = 0, + GDB_ALL_THREADS, /* One process, all threads */ + GDB_ALL_PROCESSES, + GDB_READ_THREAD_ERR +} GDBThreadIdKind; + +typedef union GdbCmdVariant { + const char *data; + uint8_t opcode; + unsigned long val_ul; + unsigned long long val_ull; + struct { + GDBThreadIdKind kind; + uint32_t pid; + uint32_t tid; + } thread_id; +} GdbCmdVariant; + +#define get_param(p, i) (&g_array_index(p, GdbCmdVariant, i)) + +void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */ +void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */ +void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */ + +void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */ + +/* softmmu only */ +void gdb_handle_query_qemu_phy_mem_mode(GArray *params, void *user_ctx); +void gdb_handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx); + +/* sycall handling */ +void gdb_handle_file_io(GArray *params, void *user_ctx); +bool gdb_handled_syscall(void); +void gdb_disable_syscalls(void); +void gdb_syscall_reset(void); + +/* user/softmmu specific syscall handling */ +void gdb_syscall_handling(const char *syscall_packet); + +/* + * Break/Watch point support - there is an implementation for softmmu + * and user mode. + */ bool gdb_supports_guest_debug(void); int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len); int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len); void gdb_breakpoint_remove_all(CPUState *cs); -#endif /* _INTERNALS_H_ */ +/** + * gdb_target_memory_rw_debug() - handle debug access to memory + * @cs: CPUState + * @addr: nominal address, could be an entire physical address + * @buf: data + * @len: length of access + * @is_write: is it a write operation + * + * This function is specialised depending on the mode we are running + * in. For softmmu guests we can switch the interpretation of the + * address to a physical address. + */ +int gdb_target_memory_rw_debug(CPUState *cs, hwaddr addr, + uint8_t *buf, int len, bool is_write); + +#endif /* GDBSTUB_INTERNALS_H */ |