1ae7467b1SAlex Bennée /*
2ae7467b1SAlex Bennée * gdbstub internals
3ae7467b1SAlex Bennée *
4ae7467b1SAlex Bennée * Copyright (c) 2022 Linaro Ltd
5ae7467b1SAlex Bennée *
6ae7467b1SAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later
7ae7467b1SAlex Bennée */
8ae7467b1SAlex Bennée
997748558SAlex Bennée #ifndef GDBSTUB_INTERNALS_H
1097748558SAlex Bennée #define GDBSTUB_INTERNALS_H
11ae7467b1SAlex Bennée
1255b5b8e9SPhilippe Mathieu-Daudé #include "exec/cpu-common.h"
1355b5b8e9SPhilippe Mathieu-Daudé
149f56787cSAlex Bennée #define MAX_PACKET_LENGTH 4096
159f56787cSAlex Bennée
169f56787cSAlex Bennée /*
179f56787cSAlex Bennée * Shared structures and definitions
189f56787cSAlex Bennée */
199f56787cSAlex Bennée
20b6fa2ec2SAlex Bennée enum {
21b6fa2ec2SAlex Bennée GDB_SIGNAL_0 = 0,
22b6fa2ec2SAlex Bennée GDB_SIGNAL_INT = 2,
23b6fa2ec2SAlex Bennée GDB_SIGNAL_QUIT = 3,
24b6fa2ec2SAlex Bennée GDB_SIGNAL_TRAP = 5,
25b6fa2ec2SAlex Bennée GDB_SIGNAL_ABRT = 6,
26b6fa2ec2SAlex Bennée GDB_SIGNAL_ALRM = 14,
275dcf6334SAlex Bennée GDB_SIGNAL_STOP = 17,
28b6fa2ec2SAlex Bennée GDB_SIGNAL_IO = 23,
29b6fa2ec2SAlex Bennée GDB_SIGNAL_XCPU = 24,
30b6fa2ec2SAlex Bennée GDB_SIGNAL_UNKNOWN = 143
31b6fa2ec2SAlex Bennée };
32b6fa2ec2SAlex Bennée
339f56787cSAlex Bennée typedef struct GDBProcess {
349f56787cSAlex Bennée uint32_t pid;
359f56787cSAlex Bennée bool attached;
3656e534bdSAlex Bennée char *target_xml;
379f56787cSAlex Bennée } GDBProcess;
389f56787cSAlex Bennée
399f56787cSAlex Bennée enum RSState {
409f56787cSAlex Bennée RS_INACTIVE,
419f56787cSAlex Bennée RS_IDLE,
429f56787cSAlex Bennée RS_GETLINE,
439f56787cSAlex Bennée RS_GETLINE_ESC,
449f56787cSAlex Bennée RS_GETLINE_RLE,
459f56787cSAlex Bennée RS_CHKSUM1,
469f56787cSAlex Bennée RS_CHKSUM2,
479f56787cSAlex Bennée };
489f56787cSAlex Bennée
499f56787cSAlex Bennée typedef struct GDBState {
509f56787cSAlex Bennée bool init; /* have we been initialised? */
519f56787cSAlex Bennée CPUState *c_cpu; /* current CPU for step/continue ops */
529f56787cSAlex Bennée CPUState *g_cpu; /* current CPU for other ops */
539f56787cSAlex Bennée CPUState *query_cpu; /* for q{f|s}ThreadInfo */
549f56787cSAlex Bennée enum RSState state; /* parsing state */
559f56787cSAlex Bennée char line_buf[MAX_PACKET_LENGTH];
569f56787cSAlex Bennée int line_buf_index;
579f56787cSAlex Bennée int line_sum; /* running checksum */
589f56787cSAlex Bennée int line_csum; /* checksum at the end of the packet */
599f56787cSAlex Bennée GByteArray *last_packet;
609f56787cSAlex Bennée int signal;
619f56787cSAlex Bennée bool multiprocess;
629f56787cSAlex Bennée GDBProcess *processes;
639f56787cSAlex Bennée int process_num;
649f56787cSAlex Bennée GString *str_buf;
659f56787cSAlex Bennée GByteArray *mem_buf;
669f56787cSAlex Bennée int sstep_flags;
679f56787cSAlex Bennée int supported_sstep_flags;
6875837005SMatheus Tavares Bernardino /*
6975837005SMatheus Tavares Bernardino * Whether we are allowed to send a stop reply packet at this moment.
7075837005SMatheus Tavares Bernardino * Must be set off after sending the stop reply itself.
7175837005SMatheus Tavares Bernardino */
7275837005SMatheus Tavares Bernardino bool allow_stop_reply;
739f56787cSAlex Bennée } GDBState;
749f56787cSAlex Bennée
75b6fa2ec2SAlex Bennée /* lives in main gdbstub.c */
76b6fa2ec2SAlex Bennée extern GDBState gdbserver_state;
771678ea04SAlex Bennée
781678ea04SAlex Bennée /*
791678ea04SAlex Bennée * Inline utility function, convert from int to hex and back
801678ea04SAlex Bennée */
811678ea04SAlex Bennée
fromhex(int v)821678ea04SAlex Bennée static inline int fromhex(int v)
831678ea04SAlex Bennée {
841678ea04SAlex Bennée if (v >= '0' && v <= '9') {
851678ea04SAlex Bennée return v - '0';
861678ea04SAlex Bennée } else if (v >= 'A' && v <= 'F') {
871678ea04SAlex Bennée return v - 'A' + 10;
881678ea04SAlex Bennée } else if (v >= 'a' && v <= 'f') {
891678ea04SAlex Bennée return v - 'a' + 10;
901678ea04SAlex Bennée } else {
911678ea04SAlex Bennée return 0;
921678ea04SAlex Bennée }
931678ea04SAlex Bennée }
941678ea04SAlex Bennée
tohex(int v)951678ea04SAlex Bennée static inline int tohex(int v)
961678ea04SAlex Bennée {
971678ea04SAlex Bennée if (v < 10) {
981678ea04SAlex Bennée return v + '0';
991678ea04SAlex Bennée } else {
1001678ea04SAlex Bennée return v - 10 + 'a';
1011678ea04SAlex Bennée }
1021678ea04SAlex Bennée }
1031678ea04SAlex Bennée
1049f56787cSAlex Bennée /*
1053f7d1bdaSPhilippe Mathieu-Daudé * Connection helpers for both system and user backends
10636e067b2SAlex Bennée */
10736e067b2SAlex Bennée
10836e067b2SAlex Bennée void gdb_put_strbuf(void);
10936e067b2SAlex Bennée int gdb_put_packet_binary(const char *buf, int len, bool dump);
11036e067b2SAlex Bennée void gdb_memtohex(GString *buf, const uint8_t *mem, int len);
11136e067b2SAlex Bennée void gdb_memtox(GString *buf, const char *mem, int len);
11236e067b2SAlex Bennée void gdb_read_byte(uint8_t ch);
11336e067b2SAlex Bennée
114a7e0f9bdSAlex Bennée /*
115a7e0f9bdSAlex Bennée * Packet acknowledgement - we handle this slightly differently
11625f34eb7SPhilippe Mathieu-Daudé * between user and system mode, mainly to deal with the differences
117a7e0f9bdSAlex Bennée * between the flexible chardev and the direct fd approaches.
118a7e0f9bdSAlex Bennée *
119a7e0f9bdSAlex Bennée * We currently don't support a negotiated QStartNoAckMode
120a7e0f9bdSAlex Bennée */
121a7e0f9bdSAlex Bennée
122a7e0f9bdSAlex Bennée /**
123a7e0f9bdSAlex Bennée * gdb_got_immediate_ack() - check ok to continue
124a7e0f9bdSAlex Bennée *
125a7e0f9bdSAlex Bennée * Returns true to continue, false to re-transmit for user only, the
12625f34eb7SPhilippe Mathieu-Daudé * system stub always returns true.
127a7e0f9bdSAlex Bennée */
128a7e0f9bdSAlex Bennée bool gdb_got_immediate_ack(void);
12936e067b2SAlex Bennée /* utility helpers */
130a3fcc111SIlya Leoshkevich GDBProcess *gdb_get_process(uint32_t pid);
131a3fcc111SIlya Leoshkevich CPUState *gdb_get_first_cpu_in_process(GDBProcess *process);
13236e067b2SAlex Bennée CPUState *gdb_first_attached_cpu(void);
13336e067b2SAlex Bennée void gdb_append_thread_id(CPUState *cpu, GString *buf);
13436e067b2SAlex Bennée int gdb_get_cpu_index(CPUState *cpu);
1357ea0c33dSAlex Bennée unsigned int gdb_get_max_cpus(void); /* both */
13625f34eb7SPhilippe Mathieu-Daudé bool gdb_can_reverse(void); /* system emulation, stub for user */
1374aad0965SIlya Leoshkevich int gdb_target_sigtrap(void); /* user */
13836e067b2SAlex Bennée
13936e067b2SAlex Bennée void gdb_create_default_process(GDBState *s);
14036e067b2SAlex Bennée
14125f34eb7SPhilippe Mathieu-Daudé /* signal mapping, common for system, specialised for user-mode */
142d96bf49bSAlex Bennée int gdb_signal_to_target(int sig);
143d96bf49bSAlex Bennée int gdb_target_signal_to_gdb(int sig);
144d96bf49bSAlex Bennée
145d96bf49bSAlex Bennée int gdb_get_char(void); /* user only */
146d96bf49bSAlex Bennée
147d96bf49bSAlex Bennée /**
148d96bf49bSAlex Bennée * gdb_continue() - handle continue in mode specific way.
149d96bf49bSAlex Bennée */
150d96bf49bSAlex Bennée void gdb_continue(void);
151d96bf49bSAlex Bennée
152d96bf49bSAlex Bennée /**
153d96bf49bSAlex Bennée * gdb_continue_partial() - handle partial continue in mode specific way.
154d96bf49bSAlex Bennée */
155d96bf49bSAlex Bennée int gdb_continue_partial(char *newstates);
156d96bf49bSAlex Bennée
15736e067b2SAlex Bennée /*
15825f34eb7SPhilippe Mathieu-Daudé * Helpers with separate system and user implementations
15936e067b2SAlex Bennée */
16036e067b2SAlex Bennée void gdb_put_buffer(const uint8_t *buf, int len);
16136e067b2SAlex Bennée
16236e067b2SAlex Bennée /*
16325f34eb7SPhilippe Mathieu-Daudé * Command handlers - either specialised or system or user only
164b6fa2ec2SAlex Bennée */
165b6fa2ec2SAlex Bennée void gdb_init_gdbserver_state(void);
166b6fa2ec2SAlex Bennée
167*0eaf7fb9SPhilippe Mathieu-Daudé void gdb_handle_query_rcmd(GArray *params, void *ctx); /* system */
168d96bf49bSAlex Bennée void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
169d96bf49bSAlex Bennée void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
1709ae5801dSGustavo Romero void gdb_handle_query_xfer_siginfo(GArray *params, void *user_ctx); /*user */
171e282010bSIlya Leoshkevich void gdb_handle_v_file_open(GArray *params, void *user_ctx); /* user */
172e282010bSIlya Leoshkevich void gdb_handle_v_file_close(GArray *params, void *user_ctx); /* user */
173e282010bSIlya Leoshkevich void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
174e282010bSIlya Leoshkevich void gdb_handle_v_file_readlink(GArray *params, void *user_ctx); /* user */
175e282010bSIlya Leoshkevich void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
176046f143cSIlya Leoshkevich void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx); /* user */
1776d923112SIlya Leoshkevich void gdb_handle_query_supported_user(const char *gdb_supported); /* user */
178e454f2feSIlya Leoshkevich bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid); /* user */
179539cb4ecSIlya Leoshkevich bool gdb_handle_detach_user(uint32_t pid); /* user */
180b6fa2ec2SAlex Bennée
181*0eaf7fb9SPhilippe Mathieu-Daudé void gdb_handle_query_attached(GArray *params, void *ctx); /* both */
1828a2025b3SAlex Bennée
18325f34eb7SPhilippe Mathieu-Daudé /* system only */
184*0eaf7fb9SPhilippe Mathieu-Daudé void gdb_handle_query_qemu_phy_mem_mode(GArray *params, void *ctx);
185*0eaf7fb9SPhilippe Mathieu-Daudé void gdb_handle_set_qemu_phy_mem_mode(GArray *params, void *ctx);
186589a5867SAlex Bennée
187c566080cSAlex Bennée /* sycall handling */
188c566080cSAlex Bennée void gdb_handle_file_io(GArray *params, void *user_ctx);
189c566080cSAlex Bennée bool gdb_handled_syscall(void);
190c566080cSAlex Bennée void gdb_disable_syscalls(void);
191c566080cSAlex Bennée void gdb_syscall_reset(void);
192c566080cSAlex Bennée
19325f34eb7SPhilippe Mathieu-Daudé /* user/system specific syscall handling */
194131f387dSAlex Bennée void gdb_syscall_handling(const char *syscall_packet);
195131f387dSAlex Bennée
196b6fa2ec2SAlex Bennée /*
19725f34eb7SPhilippe Mathieu-Daudé * Break/Watch point support - there is an implementation for system
1989f56787cSAlex Bennée * and user mode.
1999f56787cSAlex Bennée */
200a48e7d9eSAlex Bennée bool gdb_supports_guest_debug(void);
20155b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len);
20255b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len);
203ae7467b1SAlex Bennée void gdb_breakpoint_remove_all(CPUState *cs);
204ae7467b1SAlex Bennée
205589a5867SAlex Bennée /**
206589a5867SAlex Bennée * gdb_target_memory_rw_debug() - handle debug access to memory
207589a5867SAlex Bennée * @cs: CPUState
208589a5867SAlex Bennée * @addr: nominal address, could be an entire physical address
209589a5867SAlex Bennée * @buf: data
210589a5867SAlex Bennée * @len: length of access
211589a5867SAlex Bennée * @is_write: is it a write operation
212589a5867SAlex Bennée *
213589a5867SAlex Bennée * This function is specialised depending on the mode we are running
2143f7d1bdaSPhilippe Mathieu-Daudé * in. For system guests we can switch the interpretation of the
215589a5867SAlex Bennée * address to a physical address.
216589a5867SAlex Bennée */
217589a5867SAlex Bennée int gdb_target_memory_rw_debug(CPUState *cs, hwaddr addr,
218589a5867SAlex Bennée uint8_t *buf, int len, bool is_write);
219589a5867SAlex Bennée
22097748558SAlex Bennée #endif /* GDBSTUB_INTERNALS_H */
221