xref: /openbmc/qemu/gdbstub/internals.h (revision f2cb4026fccfe073f84a4b440e41d3ed0c3134f6)
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