Message ID | 20181115094207.22846-11-luc.michel@greensocs.com |
---|---|
State | New |
Headers | show |
Series | gdbstub: support for the multiprocess extension | expand |
On Thu, Nov 15, 2018 at 10:42:01AM +0100, Luc Michel wrote: > 'D' packets are used by GDB to detach from a process. In multiprocess > mode, the PID to detach from is sent in the request. > > Signed-off-by: Luc Michel <luc.michel@greensocs.com> > Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> > --- > gdbstub.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 53 insertions(+), 7 deletions(-) > > diff --git a/gdbstub.c b/gdbstub.c > index 5df9929f92..eec1cf0d09 100644 > --- a/gdbstub.c > +++ b/gdbstub.c > @@ -1039,24 +1039,39 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) > default: > return -ENOSYS; > } > } > > +static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu) > +{ > + cpu_breakpoint_remove_all(cpu, BP_GDB); > +#ifndef CONFIG_USER_ONLY > + cpu_watchpoint_remove_all(cpu, BP_GDB); > +#endif > +} > + > +static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p) > +{ > + CPUState *cpu = get_first_cpu_in_process(s, p); > + > + while (cpu) { > + gdb_cpu_breakpoint_remove_all(cpu); > + cpu = gdb_next_cpu_in_process(s, cpu); > + } > +} > + > static void gdb_breakpoint_remove_all(void) > { > CPUState *cpu; > > if (kvm_enabled()) { > kvm_remove_all_breakpoints(gdbserver_state->c_cpu); > return; > } > > CPU_FOREACH(cpu) { > - cpu_breakpoint_remove_all(cpu, BP_GDB); > -#ifndef CONFIG_USER_ONLY > - cpu_watchpoint_remove_all(cpu, BP_GDB); > -#endif > + gdb_cpu_breakpoint_remove_all(cpu); > } > } > > static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) > { > @@ -1331,13 +1346,44 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) > /* Kill the target */ > error_report("QEMU: Terminated via GDBstub"); > exit(0); > case 'D': > /* Detach packet */ > - gdb_breakpoint_remove_all(); > - gdb_syscall_mode = GDB_SYS_DISABLED; > - gdb_continue(s); > + pid = 1; > + > + if (s->multiprocess) { > + unsigned long lpid; > + if (*p != ';') { > + put_packet(s, "E22"); > + break; > + } > + > + if (qemu_strtoul(p + 1, &p, 16, &lpid)) { > + put_packet(s, "E22"); > + break; > + } > + > + pid = lpid; > + } > + > + process = gdb_get_process(s, pid); > + gdb_process_breakpoint_remove_all(s, process); > + process->attached = false; > + > + if (pid == gdb_get_cpu_pid(s, s->c_cpu)) { > + s->c_cpu = gdb_first_cpu(s); > + } > + > + if (pid == gdb_get_cpu_pid(s, s->g_cpu)) { > + s->g_cpu = gdb_first_cpu(s); > + } > + > + if (s->c_cpu == NULL) { > + /* No more process attached */ > + gdb_syscall_mode = GDB_SYS_DISABLED; > + gdb_continue(s); > + } > put_packet(s, "OK"); > break; > case 's': > if (*p != '\0') { > addr = strtoull(p, (char **)&p, 16); > -- > 2.19.1 >
On 15/11/2018 1:42 am, Luc Michel wrote: > 'D' packets are used by GDB to detach from a process. In multiprocess > mode, the PID to detach from is sent in the request. > > Signed-off-by: Luc Michel <luc.michel@greensocs.com> > Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Acked-by: Alistair Francis <alistair.francis@wdc.com> Alistair > --- > gdbstub.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 53 insertions(+), 7 deletions(-) > > diff --git a/gdbstub.c b/gdbstub.c > index 5df9929f92..eec1cf0d09 100644 > --- a/gdbstub.c > +++ b/gdbstub.c > @@ -1039,24 +1039,39 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) > default: > return -ENOSYS; > } > } > > +static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu) > +{ > + cpu_breakpoint_remove_all(cpu, BP_GDB); > +#ifndef CONFIG_USER_ONLY > + cpu_watchpoint_remove_all(cpu, BP_GDB); > +#endif > +} > + > +static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p) > +{ > + CPUState *cpu = get_first_cpu_in_process(s, p); > + > + while (cpu) { > + gdb_cpu_breakpoint_remove_all(cpu); > + cpu = gdb_next_cpu_in_process(s, cpu); > + } > +} > + > static void gdb_breakpoint_remove_all(void) > { > CPUState *cpu; > > if (kvm_enabled()) { > kvm_remove_all_breakpoints(gdbserver_state->c_cpu); > return; > } > > CPU_FOREACH(cpu) { > - cpu_breakpoint_remove_all(cpu, BP_GDB); > -#ifndef CONFIG_USER_ONLY > - cpu_watchpoint_remove_all(cpu, BP_GDB); > -#endif > + gdb_cpu_breakpoint_remove_all(cpu); > } > } > > static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) > { > @@ -1331,13 +1346,44 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) > /* Kill the target */ > error_report("QEMU: Terminated via GDBstub"); > exit(0); > case 'D': > /* Detach packet */ > - gdb_breakpoint_remove_all(); > - gdb_syscall_mode = GDB_SYS_DISABLED; > - gdb_continue(s); > + pid = 1; > + > + if (s->multiprocess) { > + unsigned long lpid; > + if (*p != ';') { > + put_packet(s, "E22"); > + break; > + } > + > + if (qemu_strtoul(p + 1, &p, 16, &lpid)) { > + put_packet(s, "E22"); > + break; > + } > + > + pid = lpid; > + } > + > + process = gdb_get_process(s, pid); > + gdb_process_breakpoint_remove_all(s, process); > + process->attached = false; > + > + if (pid == gdb_get_cpu_pid(s, s->c_cpu)) { > + s->c_cpu = gdb_first_cpu(s); > + } > + > + if (pid == gdb_get_cpu_pid(s, s->g_cpu)) { > + s->g_cpu = gdb_first_cpu(s); > + } > + > + if (s->c_cpu == NULL) { > + /* No more process attached */ > + gdb_syscall_mode = GDB_SYS_DISABLED; > + gdb_continue(s); > + } > put_packet(s, "OK"); > break; > case 's': > if (*p != '\0') { > addr = strtoull(p, (char **)&p, 16); >
diff --git a/gdbstub.c b/gdbstub.c index 5df9929f92..eec1cf0d09 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1039,24 +1039,39 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) default: return -ENOSYS; } } +static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu) +{ + cpu_breakpoint_remove_all(cpu, BP_GDB); +#ifndef CONFIG_USER_ONLY + cpu_watchpoint_remove_all(cpu, BP_GDB); +#endif +} + +static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p) +{ + CPUState *cpu = get_first_cpu_in_process(s, p); + + while (cpu) { + gdb_cpu_breakpoint_remove_all(cpu); + cpu = gdb_next_cpu_in_process(s, cpu); + } +} + static void gdb_breakpoint_remove_all(void) { CPUState *cpu; if (kvm_enabled()) { kvm_remove_all_breakpoints(gdbserver_state->c_cpu); return; } CPU_FOREACH(cpu) { - cpu_breakpoint_remove_all(cpu, BP_GDB); -#ifndef CONFIG_USER_ONLY - cpu_watchpoint_remove_all(cpu, BP_GDB); -#endif + gdb_cpu_breakpoint_remove_all(cpu); } } static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) { @@ -1331,13 +1346,44 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) /* Kill the target */ error_report("QEMU: Terminated via GDBstub"); exit(0); case 'D': /* Detach packet */ - gdb_breakpoint_remove_all(); - gdb_syscall_mode = GDB_SYS_DISABLED; - gdb_continue(s); + pid = 1; + + if (s->multiprocess) { + unsigned long lpid; + if (*p != ';') { + put_packet(s, "E22"); + break; + } + + if (qemu_strtoul(p + 1, &p, 16, &lpid)) { + put_packet(s, "E22"); + break; + } + + pid = lpid; + } + + process = gdb_get_process(s, pid); + gdb_process_breakpoint_remove_all(s, process); + process->attached = false; + + if (pid == gdb_get_cpu_pid(s, s->c_cpu)) { + s->c_cpu = gdb_first_cpu(s); + } + + if (pid == gdb_get_cpu_pid(s, s->g_cpu)) { + s->g_cpu = gdb_first_cpu(s); + } + + if (s->c_cpu == NULL) { + /* No more process attached */ + gdb_syscall_mode = GDB_SYS_DISABLED; + gdb_continue(s); + } put_packet(s, "OK"); break; case 's': if (*p != '\0') { addr = strtoull(p, (char **)&p, 16);