From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JweBC-000666-Ax for qemu-devel@nongnu.org; Thu, 15 May 2008 10:11:34 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JweBA-00064A-5h for qemu-devel@nongnu.org; Thu, 15 May 2008 10:11:33 -0400 Received: from [199.232.76.173] (port=47130 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JweBA-000646-01 for qemu-devel@nongnu.org; Thu, 15 May 2008 10:11:32 -0400 Received: from mail.windriver.com ([147.11.1.11]:50474 helo=mail.wrs.com) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1JweB9-0003TK-1d for qemu-devel@nongnu.org; Thu, 15 May 2008 10:11:31 -0400 Received: from ALA-MAIL03.corp.ad.wrs.com (ala-mail03 [147.11.57.144]) by mail.wrs.com (8.13.6/8.13.6) with ESMTP id m4FEBTg0000016 for ; Thu, 15 May 2008 07:11:29 -0700 (PDT) From: Jason Wessel Date: Thu, 15 May 2008 09:11:30 -0500 Message-Id: <1210860693-22245-3-git-send-email-jason.wessel@windriver.com> In-Reply-To: <1210860693-22245-2-git-send-email-jason.wessel@windriver.com> References: <1210860693-22245-1-git-send-email-jason.wessel@windriver.com> <1210860693-22245-2-git-send-email-jason.wessel@windriver.com> Subject: [Qemu-devel] [PATCH 2/5] gdbstub: gdb pass-through qemu monitor support Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org This patch adds a feature to the gdbstub to allow gdb to issue monitor commands that can pass-through to the qemu monitor. In order to make this work, the MAX_MON (the maximum number of monitor connections) had to get incremented by 1 to support the case when the gdbstub is setup along with all the other connections. A small check was added avoid strange crashes when you allocate too many qemu monitor connections. The monitor_handle_command had to be exported in order to allow gdbstub to pass the strings directly to the monitor. The gdbstub registers as an output device of the qemu monitor such that no further changes were needed to the monitor other than to have a global variable in the gdbstub that controls when to transmit data from a pass through monitor command to an attached debugger. The qemu docs were updated to reflect this change. Signed-off-by: Jason Wessel --- console.h | 1 + gdbstub.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- monitor.c | 8 ++++++-- qemu-doc.texi | 11 +++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/console.h b/console.h index c7f29f5..041b4ef 100644 --- a/console.h +++ b/console.h @@ -159,6 +159,7 @@ extern uint8_t _translate_keycode(const int key); does not need to include console.h */ /* monitor.c */ void monitor_init(CharDriverState *hd, int show_banner); +void monitor_handle_command(const char *cmdline); void term_puts(const char *str); void term_vprintf(const char *fmt, va_list ap); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); diff --git a/gdbstub.c b/gdbstub.c index 4bc7999..833cdd9 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -33,6 +33,7 @@ #include "qemu-char.h" #include "sysemu.h" #include "gdbstub.h" +#include "console.h" #endif #include "qemu_socket.h" @@ -70,6 +71,8 @@ typedef struct GDBState { int running_state; #else CharDriverState *chr; + CharDriverState *mon; + int allow_monitor; #endif } GDBState; @@ -239,10 +242,11 @@ static int put_packet(GDBState *s, char *buf) return 0; } -static void monitor_output(GDBState *s, const char *msg) +static void monitor_output_len(GDBState *s, const char *msg, int len) { char *buf; - int len = strlen(msg); + if (!len) + len = strlen(msg); buf = malloc(len * 2 + 2); buf[0] = 'O'; @@ -251,6 +255,11 @@ static void monitor_output(GDBState *s, const char *msg) free(buf); } +static void monitor_output(GDBState *s, const char *msg) +{ + monitor_output_len(s, msg, 0); +} + static void monitor_help(GDBState *s) { monitor_output(s, "gdbstub specific monitor commands:\n"); @@ -258,6 +267,7 @@ static void monitor_help(GDBState *s) monitor_output(s, "set s_step <0|1> -- Single Stepping enabled\n"); monitor_output(s, "set s_irq <0|1> -- Single Stepping with qemu irq handlers enabled\n"); monitor_output(s, "set s_timer <0|1> -- Single Stepping with qemu timers enabled\n"); + monitor_output(s, "qemu monitor pass-through commands:\n"); } #if defined(TARGET_I386) @@ -994,8 +1004,14 @@ static void gdb_rcmd(GDBState *s, const char *p, char *buf, char *mem_buf) sstep_flags &= ~SSTEP_NOTIMER; } else if (!strcmp(mem_buf, "s_timer 0")) { sstep_flags |= SSTEP_NOTIMER; - } else if (!strcmp(mem_buf, "help") || !strcmp(mem_buf, "?")) { - monitor_help(s); + } else { + if (!strcmp(mem_buf, "help") || !strcmp(mem_buf, "?")) + monitor_help(s); +#ifndef CONFIG_USER_ONLY + s->allow_monitor = 1; + monitor_handle_command(mem_buf); + s->allow_monitor = 0; +#endif } put_packet(s, "OK"); } @@ -1536,6 +1552,26 @@ static void gdb_chr_event(void *opaque, int event) } } +static int gdb_mon_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + GDBState *s = chr->opaque; + if (s->allow_monitor) + monitor_output_len(s, buf, len); + return len; +} + +static CharDriverState *qemu_chr_open_gdb_mon(GDBState *s) +{ + CharDriverState *chr; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + chr->chr_write = gdb_mon_chr_write; + chr->opaque = s; + return chr; +} + int gdbserver_start(const char *port) { GDBState *s; @@ -1568,6 +1604,9 @@ int gdbserver_start(const char *port) qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, gdb_chr_event, s); qemu_add_vm_stop_handler(gdb_vm_stopped, s); + /* Initialize a monitor port for gdb */ + s->mon = qemu_chr_open_gdb_mon(s); + monitor_init(s->mon, 0); return 0; } #endif diff --git a/monitor.c b/monitor.c index 236b827..2d2a110 100644 --- a/monitor.c +++ b/monitor.c @@ -69,7 +69,7 @@ typedef struct term_cmd_t { const char *help; } term_cmd_t; -#define MAX_MON 4 +#define MAX_MON 5 static CharDriverState *monitor_hd[MAX_MON]; static int hide_banner; @@ -2096,7 +2096,7 @@ static int default_fmt_size = 4; #define MAX_ARGS 16 -static void monitor_handle_command(const char *cmdline) +void monitor_handle_command(const char *cmdline) { const char *p, *pstart, *typestr; char *q; @@ -2649,6 +2649,10 @@ void monitor_init(CharDriverState *hd, int show_banner) break; } } + if (i >= MAX_MON) { + fprintf(stderr, "ERROR too many monitor connections requested\n"); + exit(0); + } hide_banner = !show_banner; diff --git a/qemu-doc.texi b/qemu-doc.texi index 11c7058..f981b08 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1976,6 +1976,17 @@ Turn off or on the the irq processing when single stepping, which is defaulted t Turn off or on the the timer processing when single stepping, which is defaulted to off. @end table +You may also use gdb to send pass-through monitor commands to the qemu monitor. It is easiest to start off with using just using @code{monitor help} to display the list of commands in available from the monitor. Then you can prefix the @code{monitor} key word prior to any command. The example below show the use of the qemu monitor's @code{info pci} command. + +@example +(gdb) monitor info pci + Bus 0, device 0, function 0: + Host bridge: PCI device 1057:4801 + Bus 0, device 1, function 0: + VGA controller: PCI device 1234:1111 + BAR0: 32 bit memory at 0xf0000000 [0xf07fffff]. +@end example + @node pcsys_os_specific @section Target OS specific information -- 1.5.5.1