|
@@ -11,6 +11,10 @@
|
|
|
#include "exec/gdbstub.h"
|
|
|
#include "qemu.h"
|
|
|
#include "internals.h"
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
+#include "linux-user/loader.h"
|
|
|
+#include "linux-user/qemu.h"
|
|
|
+#endif
|
|
|
|
|
|
/*
|
|
|
* Map target signal numbers to GDB protocol signal numbers and vice
|
|
@@ -281,3 +285,136 @@ void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
|
|
|
gdbserver_state.str_buf->len, true);
|
|
|
}
|
|
|
#endif
|
|
|
+
|
|
|
+static const char *get_filename_param(GArray *params, int i)
|
|
|
+{
|
|
|
+ const char *hex_filename = get_param(params, i)->data;
|
|
|
+ gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
|
|
|
+ strlen(hex_filename) / 2);
|
|
|
+ g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
|
|
|
+ return (const char *)gdbserver_state.mem_buf->data;
|
|
|
+}
|
|
|
+
|
|
|
+static void hostio_reply_with_data(const void *buf, size_t n)
|
|
|
+{
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
|
|
|
+ gdb_memtox(gdbserver_state.str_buf, buf, n);
|
|
|
+ gdb_put_packet_binary(gdbserver_state.str_buf->str,
|
|
|
+ gdbserver_state.str_buf->len, true);
|
|
|
+}
|
|
|
+
|
|
|
+void gdb_handle_v_file_open(GArray *params, void *user_ctx)
|
|
|
+{
|
|
|
+ const char *filename = get_filename_param(params, 0);
|
|
|
+ uint64_t flags = get_param(params, 1)->val_ull;
|
|
|
+ uint64_t mode = get_param(params, 2)->val_ull;
|
|
|
+
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
+ int fd = do_guest_openat(gdbserver_state.g_cpu->env_ptr, 0, filename,
|
|
|
+ flags, mode, false);
|
|
|
+#else
|
|
|
+ int fd = open(filename, flags, mode);
|
|
|
+#endif
|
|
|
+ if (fd < 0) {
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
|
|
+ } else {
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "F%d", fd);
|
|
|
+ }
|
|
|
+ gdb_put_strbuf();
|
|
|
+}
|
|
|
+
|
|
|
+void gdb_handle_v_file_close(GArray *params, void *user_ctx)
|
|
|
+{
|
|
|
+ int fd = get_param(params, 0)->val_ul;
|
|
|
+
|
|
|
+ if (close(fd) == -1) {
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
|
|
+ gdb_put_strbuf();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ gdb_put_packet("F00");
|
|
|
+}
|
|
|
+
|
|
|
+void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
|
|
|
+{
|
|
|
+ int fd = get_param(params, 0)->val_ul;
|
|
|
+ size_t count = get_param(params, 1)->val_ull;
|
|
|
+ off_t offset = get_param(params, 2)->val_ull;
|
|
|
+
|
|
|
+ size_t bufsiz = MIN(count, BUFSIZ);
|
|
|
+ g_autofree char *buf = g_try_malloc(bufsiz);
|
|
|
+ if (buf == NULL) {
|
|
|
+ gdb_put_packet("E12");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ssize_t n = pread(fd, buf, bufsiz, offset);
|
|
|
+ if (n < 0) {
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
|
|
+ gdb_put_strbuf();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ hostio_reply_with_data(buf, n);
|
|
|
+}
|
|
|
+
|
|
|
+void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
|
|
|
+{
|
|
|
+ const char *filename = get_filename_param(params, 0);
|
|
|
+
|
|
|
+ g_autofree char *buf = g_try_malloc(BUFSIZ);
|
|
|
+ if (buf == NULL) {
|
|
|
+ gdb_put_packet("E12");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
+ ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
|
|
|
+#else
|
|
|
+ ssize_t n = readlink(filename, buf, BUFSIZ);
|
|
|
+#endif
|
|
|
+ if (n < 0) {
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
|
|
+ gdb_put_strbuf();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ hostio_reply_with_data(buf, n);
|
|
|
+}
|
|
|
+
|
|
|
+void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
|
|
|
+{
|
|
|
+ uint32_t pid = get_param(params, 0)->val_ul;
|
|
|
+ uint32_t offset = get_param(params, 1)->val_ul;
|
|
|
+ uint32_t length = get_param(params, 2)->val_ul;
|
|
|
+
|
|
|
+ GDBProcess *process = gdb_get_process(pid);
|
|
|
+ if (!process) {
|
|
|
+ gdb_put_packet("E00");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
|
|
+ if (!cpu) {
|
|
|
+ gdb_put_packet("E00");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ TaskState *ts = cpu->opaque;
|
|
|
+ if (!ts || !ts->bprm || !ts->bprm->filename) {
|
|
|
+ gdb_put_packet("E00");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t total_length = strlen(ts->bprm->filename);
|
|
|
+ if (offset > total_length) {
|
|
|
+ gdb_put_packet("E00");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (offset + length > total_length) {
|
|
|
+ length = total_length - offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
|
|
|
+ ts->bprm->filename + offset);
|
|
|
+ gdb_put_strbuf();
|
|
|
+}
|