Skip to content

Instantly share code, notes, and snippets.

@YiChenChai
Created July 25, 2019 08:02
Show Gist options
  • Save YiChenChai/06382e49a4dcd49a1d64f240fa8c35df to your computer and use it in GitHub Desktop.
Save YiChenChai/06382e49a4dcd49a1d64f240fa8c35df to your computer and use it in GitHub Desktop.
Small patch to add GDB remote file download capabilities to QEMU
diff --git a/gdbstub.c b/gdbstub.c
index b470aec..54cc026 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1907,6 +1907,91 @@ static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
exit(0);
}
+static void handle_v_file_open(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ const char *hex_name = gdb_ctx->params[0].data;
+ char *p;
+ int len = 0;
+ int fd;
+ unsigned long mask, mode;
+ CPUState *cpu;
+ GDBProcess *process;
+
+ while (hex_name[len] != ',') len++;
+ hextomem(gdb_ctx->mem_buf, hex_name, len);
+ gdb_ctx->mem_buf[len / 2 + 1] = '\0';
+ p = (char *)gdb_ctx->mem_buf;
+ // error_report("Param 1: %s", (char*)(gdb_ctx->mem_buf));
+ // error_report("Param 2: %lu", gdb_ctx->params[1].val_ul);
+ // error_report("Param 3: %lu", gdb_ctx->params[2].val_ul);
+ mask = gdb_ctx->params[1].val_ul;
+ mode = gdb_ctx->params[2].val_ul;
+
+ process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
+ cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+ fd = do_openat(cpu->env_ptr, AT_FDCWD, p, mask, mode);
+ error_report("FD: %d", fd);
+ snprintf(gdb_ctx->str_buf, 1024, "F%d", fd);
+ put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
+
+static void handle_v_file_read(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ unsigned long fd, sz, offset;
+ fd = gdb_ctx->params[0].val_ul;
+ sz = gdb_ctx->params[1].val_ul;
+ offset = gdb_ctx->params[2].val_ul;
+
+ // error_report("Read param 2: %lu", gdb_ctx->params[1].val_ul);
+ // error_report("Read param 3: %lu", gdb_ctx->params[2].val_ul);
+
+ lseek(fd, offset, SEEK_SET);
+ if (sz > 1024) sz = 1024;
+ int ret = -TARGET_ERESTARTSYS;
+ CPUState *cpu;
+ GDBProcess *process;
+ process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
+ cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+ while (ret == -TARGET_ERESTARTSYS) {
+ process_pending_signals(cpu->env_ptr);
+ ret = safe_read_wrap(fd, gdb_ctx->mem_buf, sz);
+ }
+ if (is_error(ret)) {
+ snprintf(gdb_ctx->str_buf, 1024, "F%d,%x", -1, -ret);
+ put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ }
+ else {
+ int idx, j;
+ idx = snprintf(gdb_ctx->str_buf, 4096, "F%x;", ret);
+ // error_report("Debug: %s", (char*)gdb_ctx->mem_buf);
+ j = idx;
+ for (int i = 0; i < ret; i++) {
+ char c;
+ c = gdb_ctx->mem_buf[i];
+ if (c == '}' || c == '#' || c == '$' || c == '*' || c == '\0') {
+ gdb_ctx->str_buf[j++] = '}';
+ gdb_ctx->str_buf[j++] = c ^ ' ';
+ }
+ else { gdb_ctx->str_buf[j++] = c; }
+ }
+ gdb_ctx->str_buf[j++] = '\0';
+ // error_report("String Debug: %s", (char*)gdb_ctx->str_buf);
+ put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ }
+}
+
+static void handle_v_file_close(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+ unsigned long fd;
+ int ret;
+ fd = gdb_ctx->params[0].val_ul;
+ ret = close(fd);
+ if (ret < 0) {
+ snprintf(gdb_ctx->str_buf, 4096, "F%x,%x", -1, -ret);
+ }
+ else snprintf(gdb_ctx->str_buf, 4096, "F%x", ret);
+ put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+}
static GdbCmdParseEntry gdb_v_commands_table[] = {
/* Order is important if has same prefix */
{
@@ -1931,6 +2016,24 @@ static GdbCmdParseEntry gdb_v_commands_table[] = {
.cmd = "Kill;",
.cmd_startswith = 1
},
+ {
+ .handler = handle_v_file_open,
+ .cmd = "File:open:",
+ .cmd_startswith = 1,
+ .schema = "s,l,l0"
+ },
+ {
+ .handler = handle_v_file_read,
+ .cmd = "File:pread:",
+ .cmd_startswith = 1,
+ .schema = "l,l,l0"
+ },
+ {
+ .handler = handle_v_file_close,
+ .cmd = "File:close:",
+ .cmd_startswith = 1,
+ .schema = "l0"
+ },
};
static void handle_v_commands(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2977,7 +3080,11 @@ static void create_default_process(GDBState *s)
/* We need an available PID slot for this process */
assert(max_pid < UINT32_MAX);
+ #ifdef CONFIG_USER_ONLY
+ process->pid = getpid();
+ #else
process->pid = max_pid + 1;
+ #endif
process->attached = false;
process->target_xml[0] = '\0';
}
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 4258e41..5cf255d 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -675,3 +675,6 @@ void preexit_cleanup(CPUArchState *env, int code);
#include "target_structs.h"
#endif /* QEMU_H */
+
+int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode);
+ssize_t safe_read_wrap(int fd, void * buff, size_t count);
\ No newline at end of file
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8367cb1..12ac85c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -769,6 +769,9 @@ safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
int, flags)
safe_syscall2(int, nanosleep, const struct timespec *, req,
struct timespec *, rem)
+abi_long safe_read_wrap(int fd, void * buff, size_t count) {
+ return get_errno(safe_read(fd, buff, count));
+}
#ifdef TARGET_NR_clock_nanosleep
safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
const struct timespec *, req, struct timespec *, rem)
@@ -7061,7 +7064,7 @@ static int open_hardware(void *cpu_env, int fd)
}
#endif
-static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
+int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
{
struct fake_open {
const char *filename;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment