[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH v2] Gdbstub user mode -gdb dev option/unix socke
From: |
Philippe Waille |
Subject: |
[Qemu-devel] Re: [PATCH v2] Gdbstub user mode -gdb dev option/unix sockets |
Date: |
Wed, 15 Apr 2009 20:59:01 +0200 |
User-agent: |
Mutt/1.5.18 (2008-05-17) |
New patch release, takes Jan comments into account.
Philippe
This patch removes the -g portnumber option in user mode.
Adds a -gdb device option as in the system mode.
-gdb tcp:host:port or -gdb tcp::port
-gdb unix:socketname[,unlink]
Missing tests :
+ system mode regression test (I don't have a "hello world" example
for system mode)
+ _WIN32 mode
Index: linux-user/main.c
===================================================================
--- linux-user/main.c (révision 7119)
+++ linux-user/main.c (copie de travail)
@@ -2208,7 +2208,12 @@
"\n"
"Standard options:\n"
"-h print this help\n"
- "-g port wait gdb connection to port\n"
+ "-gdb device wait gdb connection to device\n"
+ " device syntax use gdb target remote command \n"
+ " tcp:host:port remote host:port\n"
+ " tcp::port remote :port\n"
+ " unix:sockname[,unlink] remote | socat stdio unix:sockname\n"
+ " unlink : removes sockname after
connection\n"
"-L path set the elf interpreter prefix (default=%s)\n"
"-s size set the stack size in bytes (default=%ld)\n"
"-cpu model select CPU (-cpu ? for list)\n"
@@ -2265,7 +2270,6 @@
CPUState *env;
int optind;
const char *r;
- int gdbstub_port = 0;
char **target_environ, **wrk;
char **target_argv;
int target_argc;
@@ -2353,10 +2357,13 @@
fprintf(stderr, "page size must be a power of two\n");
exit(1);
}
- } else if (!strcmp(r, "g")) {
- if (optind >= argc)
- break;
- gdbstub_port = atoi(argv[optind++]);
+ } else if (!strcmp(r, "gdb")) {
+ if (optind >= argc) {
+ usage ();
+ }
+ if (gdbserver_start(argv[optind++]) < 0) {
+ usage ();
+ }
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
} else if (!strcmp(r, "cpu")) {
@@ -2742,10 +2749,7 @@
ts->heap_limit = 0;
#endif
- if (gdbstub_port) {
- gdbserver_start (gdbstub_port);
- gdb_handlesig(env, 0);
- }
+ gdbserver_accept (env);
cpu_loop(env);
/* never exits */
return 0;
Index: gdbstub.c
===================================================================
--- gdbstub.c (révision 7119)
+++ gdbstub.c (copie de travail)
@@ -19,22 +19,15 @@
*/
#include "config.h"
#include "qemu-common.h"
+
#ifdef CONFIG_USER_ONLY
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-
#include "qemu.h"
-#else
+#else /* !CONFIG_USER_ONLY */
#include "monitor.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "gdbstub.h"
-#endif
+#endif /* !CONFIG_USER_ONLY */
#define MAX_PACKET_LENGTH 4096
@@ -215,7 +208,7 @@
-1
#endif
};
-#else
+#else /* !CONFIG_USER_ONLY */
/* In system mode we only need SIGINT and SIGTRAP; other signals
are not yet supported. */
@@ -232,8 +225,9 @@
-1,
TARGET_SIGTRAP
};
-#endif
+#endif /* !CONFIG_USER_ONLY */
+
#ifdef CONFIG_USER_ONLY
static int target_signal_to_gdb (int sig)
{
@@ -243,7 +237,7 @@
return i;
return GDB_SIGNAL_UNKNOWN;
}
-#endif
+#endif /* CONFIG_USER_ONLY */
static int gdb_signal_to_target (int sig)
{
@@ -305,33 +299,17 @@
static int gdb_has_xml;
#ifdef CONFIG_USER_ONLY
+typedef int (*gdbstub_func) (void);
+
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
+static gdbstub_func gdbserver_do_accept = NULL;
-static int get_char(GDBState *s)
-{
- uint8_t ch;
- int ret;
+static int gdb_disconnected (GDBState *);
+static int get_char(GDBState *s);
+#endif /* CONFIG_USER_ONLY */
- for(;;) {
- ret = recv(s->fd, &ch, 1, 0);
- if (ret < 0) {
- if (errno == ECONNRESET)
- s->fd = -1;
- if (errno != EINTR && errno != EAGAIN)
- return -1;
- } else if (ret == 0) {
- close(s->fd);
- s->fd = -1;
- return -1;
- } else {
- break;
- }
- }
- return ch;
-}
-#endif
-
+static void put_buffer(GDBState *s, const uint8_t *buf, int len);
static gdb_syscall_complete_cb gdb_current_syscall_cb;
enum {
@@ -342,6 +320,7 @@
/* If gdb is connected when the first semihosting syscall occurs then use
remote gdb syscalls. Otherwise use native file IO. */
+
int use_gdb_syscalls(void)
{
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
@@ -361,26 +340,6 @@
#endif
}
-static void put_buffer(GDBState *s, const uint8_t *buf, int len)
-{
-#ifdef CONFIG_USER_ONLY
- int ret;
-
- while (len > 0) {
- ret = send(s->fd, buf, len, 0);
- if (ret < 0) {
- if (errno != EINTR && errno != EAGAIN)
- return;
- } else {
- buf += ret;
- len -= ret;
- }
- }
-#else
- qemu_chr_write(s->chr, buf, len);
-#endif
-}
-
static inline int fromhex(int v)
{
if (v >= '0' && v <= '9')
@@ -2091,29 +2050,62 @@
}
#ifdef CONFIG_USER_ONLY
-int
-gdb_queuesig (void)
+int gdb_queuesig (void)
{
GDBState *s;
s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
+ if (gdb_disconnected (s)) {
return 0;
- else
+ } else {
return 1;
+ }
}
-int
-gdb_handlesig (CPUState *env, int sig)
+/* Tell the remote gdb that the process has exited. */
+void gdb_exit(CPUState *env, int code)
{
GDBState *s;
+ char buf[4];
+
+ s = gdbserver_state;
+ if (gdb_disconnected (s)) {
+ return;
+ }
+ snprintf(buf, sizeof(buf), "W%02x", code);
+ put_packet(s, buf);
+}
+
+/* Tell the remote gdb that the process has exited due to SIG. */
+void gdb_signalled(CPUState *env, int sig)
+{
+ GDBState *s;
+ char buf[4];
+
+ s = gdbserver_state;
+ if (gdb_disconnected (s)) {
+ return;
+ }
+ snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
+ put_packet(s, buf);
+}
+
+static int gdb_disconnected (GDBState *s)
+{
+ return (gdbserver_fd < 0) || (s->fd < 0);
+}
+
+int gdb_handlesig (CPUState *env, int sig)
+{
+ GDBState *s;
char buf[256];
int n;
s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
- return sig;
+ if (gdb_disconnected (s)) {
+ return sig;
+ }
/* disable single step if it was enabled */
cpu_single_step(env, 0);
@@ -2126,9 +2118,9 @@
}
/* put_packet() might have detected that the peer terminated the
connection. */
- if (s->fd < 0)
+ if (gdb_disconnected (s)) {
return sig;
-
+ }
sig = 0;
s->state = RS_IDLE;
s->running_state = 0;
@@ -2153,106 +2145,285 @@
return sig;
}
-/* Tell the remote gdb that the process has exited. */
-void gdb_exit(CPUState *env, int code)
+static int get_char(GDBState *s)
{
- GDBState *s;
- char buf[4];
+ uint8_t ch;
+ int ret;
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
- return;
-
- snprintf(buf, sizeof(buf), "W%02x", code);
- put_packet(s, buf);
+ for(;;) {
+ ret = recv(s->fd, &ch, 1, 0);
+ if (ret < 0) {
+ if (errno == ECONNRESET)
+ s->fd = -1;
+ if (errno != EINTR && errno != EAGAIN)
+ return -1;
+ } else if (ret == 0) {
+ close(s->fd);
+ s->fd = -1;
+ return -1;
+ } else {
+ break;
+ }
+ }
+ return ch;
}
-/* Tell the remote gdb that the process has exited due to SIG. */
-void gdb_signalled(CPUState *env, int sig)
+static void put_buffer(GDBState *s, const uint8_t *buf, int len)
{
- GDBState *s;
- char buf[4];
+ int ret;
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0)
- return;
-
- snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
- put_packet(s, buf);
+ while (len > 0) {
+ ret = send(s->fd, buf, len, 0);
+ if (ret < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ return;
+ } else {
+ buf += ret;
+ len -= ret;
+ }
+ }
}
-static void gdb_accept(void)
+
+static GDBState *gdbserver_create_gdbstate (void)
{
GDBState *s;
- struct sockaddr_in sockaddr;
- socklen_t len;
- int val, fd;
- for(;;) {
- len = sizeof(sockaddr);
- fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
- if (fd < 0 && errno != EINTR) {
- perror("accept");
- return;
- } else if (fd >= 0) {
- break;
- }
- }
-
- /* set short latency */
- val = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
-
s = qemu_mallocz(sizeof(GDBState));
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
- s->fd = fd;
gdb_has_xml = 0;
-
gdbserver_state = s;
+ return s;
+}
- fcntl(fd, F_SETFL, O_NONBLOCK);
+static int gdbserver_tcp_accept (void)
+{
+ int fd,res;
+ GDBState *s;
+
+ for (;;) {
+ fd = accept (gdbserver_fd,
+ (struct sockaddr *) NULL, (socklen_t *) NULL);
+ if (fd < 0) {
+ if (errno != EINTR) {
+ perror("accept");
+ return -1;
+ }
+ } else {
+ break;
+ }
+ }
+ /* set short latency */
+ res = 1;
+ res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&res, sizeof (res));
+ if (res < 0) {
+ fprintf (stderr, "gdbserver ERROR : set nodelay\n");
+ return -1;
+ }
+ res = fcntl(fd, F_SETFL, O_NONBLOCK);
+ if (res < 0) {
+ fprintf (stderr, "gdbserver ERROR : set nonblock\n");
+ return -1;
+ }
+ s = gdbserver_create_gdbstate ();
+ s -> fd = fd;
+ return 0;
}
-static int gdbserver_open(int port)
+
+static int gdbserver_tcp_start (const char *host, const char *port,
+ gdbstub_func faccept)
{
- struct sockaddr_in sockaddr;
- int fd, val, ret;
+ struct addrinfo info_in, *info_out;
+ struct sockaddr_in addrin, *addr;
+ int res;
- fd = socket(PF_INET, SOCK_STREAM, 0);
- if (fd < 0) {
- perror("socket");
+ memset (&info_in, 0, sizeof(struct addrinfo));
+ info_in.ai_flags=AI_PASSIVE; /* force INADDR_ANY if host == NULL */
+ info_in.ai_family= AF_INET;
+ info_in.ai_socktype=SOCK_STREAM;
+ info_in.ai_protocol=IPPROTO_TCP;
+
+ if (getaddrinfo(host, port, &info_in, &info_out) < 0) {
+ perror ("hostname/portname name conversion error");
return -1;
}
+ addr = (struct sockaddr_in *) info_out -> ai_addr;
+ gdbserver_fd = socket (info_in.ai_family, info_in.ai_socktype,
+ info_in.ai_protocol);
+ if (info_in.ai_protocol < 0) {
+ perror ("gdb socket");
+ return -1;
+ }
+ /* allow fast reuse */
+ res = 1;
+ res = setsockopt(gdbserver_fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &res, sizeof(res));
+ if (res <0) {
+ perror("gdb socket : set fast reuse\n");
+ return -1;
+ }
+ res = bind (gdbserver_fd, (struct sockaddr *) addr, sizeof (addrin));
+ if (res <0) {
+ perror("gdb socket bind\n");
+ return -1;
+ }
+ res = listen (gdbserver_fd,0);
+ if (res <0) {
+ perror("listen\n");
+ return -1;
+ }
+ gdbserver_do_accept = faccept;
+ return 0;
+}
- /* allow fast reuse */
- val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+#ifndef _WIN32
+static int gdbserver_unix_unlink (void)
+{
+ struct sockaddr_un sock;
+ socklen_t len;
+ int res;
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_port = htons(port);
- sockaddr.sin_addr.s_addr = 0;
- ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
- if (ret < 0) {
- perror("bind");
+ len = sizeof (sock.sun_path);
+ res = getsockname (gdbserver_fd, &sock, &len);
+ if (res < 0 ) {
+ fprintf (stderr,"gdb accept/unlink : cannot get socket name\n");
+ return -1;
+ }
+ res = unlink (sock.sun_path);
+ if (res < 0) {
+ fprintf (stderr,"gdb accept/unlink : cannot unlink %s\n",sock.sun_path);
+ return -1;
+ }
+ return 0;
+}
+
+static int gdbserver_unix_accept (void)
+{
+ int fd,res;
+ GDBState *s;
+ for (;;) {
+ fd = accept (gdbserver_fd,
+ (struct sockaddr *) NULL, ( socklen_t *) NULL);
+ if (fd < 0) {
+ if (errno != EINTR) {
+ perror("accept");
+ return -1;
+ }
+ } else {
+ break;
+ }
+ }
+
+ res = fcntl(fd, F_SETFL, O_NONBLOCK);
+ if (res < 0) {
+ fprintf (stderr, "gdbserver ERROR : set nonblock\n");
+ return -1;
+ }
+ s = gdbserver_create_gdbstate ();
+ s -> fd = fd;
+ return 0;
+}
+
+static int gdbserver_unix_accept_unlink (void)
+{
+ return (gdbserver_unix_accept () + gdbserver_unix_unlink ());
+}
+
+static int gdbserver_unix_start (const char *filename,
+ gdbstub_func faccept)
+{
+ struct sockaddr_un addr;
+ int res;
+
+ if (strlen(filename) == 0) {
+ fprintf (stderr, "gdbserver ERROR : missing unix socket name\n");
+ return -1;
+ }
+
+ memset (&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ strcpy (addr.sun_path, filename);
+
+ gdbserver_fd = socket (AF_UNIX,SOCK_STREAM,0);
+ if (gdbserver_fd < 0) {
+ perror ("gsbserver socket");
return -1;
}
- ret = listen(fd, 0);
- if (ret < 0) {
- perror("listen");
+ res = bind (gdbserver_fd, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_un));
+ if (res < 0) {
+ perror ("gdbserver bind\n");
return -1;
}
- return fd;
+ res = listen (gdbserver_fd,0);
+ if (res <0) {
+ perror("listen\n");
+ return -1;
+ }
+ gdbserver_do_accept = faccept;
+ return 0;
+}
+
+#endif /* _WIN32 */
+
+void gdbserver_accept (CPUState *env)
+{
+ if ((gdbserver_do_accept != NULL) && ((*gdbserver_do_accept)() >= 0)) {
+ gdb_handlesig(env, 0);
+ }
}
-int gdbserver_start(int port)
+int gdbserver_start(const char *device)
{
- gdbserver_fd = gdbserver_open(port);
- if (gdbserver_fd < 0)
- return -1;
- /* accept connections */
- gdb_accept();
+ const char *p;
+ char *name, *devicename,*opt;
+
+ name = malloc (strlen(device)+1);
+ /* Light memory leak : will never be freed */
+
+ if (strstart (device, "tcp:",&p)) {
+ if ((p == NULL) || (strlen(p) == 0)) {
+ perror ("tcp socket syntax error");
+ return -1;
+ }
+ strcpy (name,p);
+ devicename = strrchr (name,':');
+ if (devicename == NULL) {
+ return -1;
+ }
+ *devicename++ = 0;
+ if (*devicename == 0) {
+ return -1;
+ }
+ if (*name == 0) {
+ name = NULL;
+ }
+ return gdbserver_tcp_start (name,devicename,
+ gdbserver_tcp_accept);
+#ifndef _WIN32
+ } else if (strstart (device, "unix:",&p)) {
+ strcpy (name,p);
+ opt = strrchr(name,',');
+ if (opt == NULL) {
+ return gdbserver_unix_start(name,gdbserver_unix_accept);
+ } else {
+ *opt++ = 0;
+ if (!strcmp(opt,"unlink")) {
+ return gdbserver_unix_start(name,
+ gdbserver_unix_accept_unlink);
+ } else {
+ fprintf (stderr,"gdb unix socket : unknown %s option\n",opt);
+ return -1;
+ }
+ }
+#endif /* _WIN32 */
+ } else {
+ return -1;
+ }
return 0;
+
}
/* Disable gdb stub for child processes. */
@@ -2266,7 +2437,14 @@
cpu_breakpoint_remove_all(env, BP_GDB);
cpu_watchpoint_remove_all(env, BP_GDB);
}
-#else
+
+#else /* !CONFIG_USER_ONLY */
+
+static void put_buffer(GDBState *s, const uint8_t *buf, int len)
+{
+ qemu_chr_write(s->chr, buf, len);
+}
+
static int gdb_chr_can_receive(void *opaque)
{
/* We can handle an arbitrarily large amount of data.
@@ -2390,4 +2568,4 @@
return 0;
}
-#endif
+#endif /* !CONFIG_USER_ONLY */
Index: gdbstub.h
===================================================================
--- gdbstub.h (révision 7119)
+++ gdbstub.h (copie de travail)
@@ -16,16 +16,17 @@
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
int use_gdb_syscalls(void);
void gdb_set_stop_cpu(CPUState *env);
+
#ifdef CONFIG_USER_ONLY
int gdb_queuesig (void);
int gdb_handlesig (CPUState *, int);
void gdb_exit(CPUState *, int);
void gdb_signalled(CPUState *, int);
-int gdbserver_start(int);
void gdbserver_fork(CPUState *);
-#else
-int gdbserver_start(const char *port);
+void gdbserver_accept (CPUState *);
#endif
+
+int gdbserver_start (const char *device);
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg);
void gdb_register_coprocessor(CPUState *env,
--
-----------------------------------------------------------------------------
Philippe WAILLE email : address@hidden
IMAG ID (Informatique et distribution) Tel : 04 76 61 20 13
ENSIMAG - antenne de Montbonnot Foreign : 33 4 76 61 20 13
INOVALLEE Fax : 04 76 61 20 99
51, avenue Jean Kuntzmann
38330 MONTBONNOT SAINT MARTIN
patch.tar
Description: Unix tar archive
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] Re: [PATCH v2] Gdbstub user mode -gdb dev option/unix sockets,
Philippe Waille <=