From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Lu2vW-0001Lt-4w for qemu-devel@nongnu.org; Wed, 15 Apr 2009 07:05:10 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lu2vQ-0001Lf-6E for qemu-devel@nongnu.org; Wed, 15 Apr 2009 07:05:08 -0400 Received: from [199.232.76.173] (port=57979 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lu2vQ-0001La-2c for qemu-devel@nongnu.org; Wed, 15 Apr 2009 07:05:04 -0400 Received: from gecko.sbs.de ([194.138.37.40]:16235) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Lu2vO-00018n-SL for qemu-devel@nongnu.org; Wed, 15 Apr 2009 07:05:03 -0400 Received: from mail1.sbs.de (localhost [127.0.0.1]) by gecko.sbs.de (8.12.11.20060308/8.12.11) with ESMTP id n3FB4xei012019 for ; Wed, 15 Apr 2009 13:04:59 +0200 Received: from [139.25.109.167] (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail1.sbs.de (8.12.11.20060308/8.12.11) with ESMTP id n3FB4xdu007988 for ; Wed, 15 Apr 2009 13:04:59 +0200 Message-ID: <49E5BF5B.8070902@siemens.com> Date: Wed, 15 Apr 2009 13:04:59 +0200 From: Jan Kiszka MIME-Version: 1.0 References: <20090415092542.GA31193@otto.imag.fr> In-Reply-To: <20090415092542.GA31193@otto.imag.fr> Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] Re: [PATCH] Gdbstub user mode -gdb dev option : add unix sockets 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 Philippe Waille wrote: > This patch removes the -g portnumber option in user mode. > Adds a -gdb device option as in the system mode. >=20 > -gdb tcp:host:port or -gdb tcp::port > -gdb unix:socketname[,unlink] >=20 > Missing tests : > + system mode regression test (I don't have a "hello world" example > for system mode) > + _WIN32 mode >=20 >=20 > Philippe Waille > -----------------------------------------------------------------------= -- >=20 > Index: linux-user/main.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- linux-user/main.c (r=E9vision 7105) > +++ linux-user/main.c (copie de travail) > @@ -2202,40 +2202,37 @@ > =20 > static void usage(void) > { > - printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSIO= N ", Copyright (c) 2003-2008 Fabrice Bellard\n" > - "usage: qemu-" TARGET_ARCH " [options] program [arguments..= .]\n" > - "Linux CPU emulator (compiled for %s emulation)\n" > - "\n" > - "Standard options:\n" > - "-h print this help\n" > - "-g port wait gdb connection to port\n" > - "-L path set the elf interpreter prefix (default=3D= %s)\n" > - "-s size set the stack size in bytes (default=3D%= ld)\n" > - "-cpu model select CPU (-cpu ? for list)\n" > - "-drop-ld-preload drop LD_PRELOAD for target process\n" > - "-E var=3Dvalue sets/modifies targets environment vari= able(s)\n" > - "-U var unsets targets environment variable(s)\n= " > - "\n" > - "Debug options:\n" > - "-d options activate log (logfile=3D%s)\n" > - "-p pagesize set the host page size to 'pagesize'\n" > - "-singlestep always run in singlestep mode\n" > - "-strace log system calls\n" > - "\n" > - "Environment variables:\n" > - "QEMU_STRACE Print system calls and arguments similar= to the\n" > - " 'strace' program. Enable by setting to = any value.\n" > - "You can use -E and -U options to set/unset environment var= iables\n" > - "for target process. It is possible to provide several var= iables\n" > - "by repeating the option. For example:\n" > - " -E var1=3Dval2 -E var2=3Dval2 -U LD_PRELOAD -U LD_DEBU= G\n" > - "Note that if you provide several changes to single variabl= e\n" > - "last change will stay in effect.\n" > - , > - TARGET_ARCH, > - interp_prefix, > - x86_stack_size, > - DEBUG_LOGFILE); > + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (= c) 2003-2008 Fabrice Bellard\n"); > + printf("usage: qemu-" TARGET_ARCH " [options] program [arguments..= .]\n"); > + printf("Linux CPU emulator (compiled for %s emulation)\n", > + TARGET_ARCH); > + printf("\n"); > + printf("Standard options:\n"); > + printf("-h print this help\n"); > + gdbstub_usage(); > + printf("-L path set the elf interpreter prefix (default=3D= %s)\n", > + interp_prefix); > + printf("-s size set the stack size in bytes (default=3D%= ld)\n", > + x86_stack_size); > + printf("-cpu model select CPU (-cpu ? for list)\n"); > + printf("-drop-ld-preload drop LD_PRELOAD for target process\n"); > + printf("-E var=3Dvalue sets/modifies targets environment vari= able(s)\n"); > + printf("-U var unsets targets environment variable(s)\n= "); > + printf("\n"); > + printf("Debug options:\n"); > + printf("-d options activate log (logfile=3D%s)\n", DEBUG_LOGFILE= ); > + printf("-p pagesize set the host page size to 'pagesize'\n"); > + printf("-strace log system calls\n"); > + printf("\n"); > + printf("Environment variables:\n"); > + printf("QEMU_STRACE Print system calls and arguments similar= to the\n"); > + printf(" 'strace' program. Enable by setting to = any value.\n"); > + printf("You can use -E and -U options to set/unset environment var= iables\n"); > + printf("for target process. It is possible to provide several var= iables\n"); > + printf("by repeating the option. For example:\n"); > + printf(" -E var1=3Dval2 -E var2=3Dval2 -U LD_PRELOAD -U LD_DEBU= G\n"); > + printf("Note that if you provide several changes to single variabl= e\n"); > + printf("last change will stay in effect.\n"); Please drop this conversion single -> multiple printf, just change the string related to this patch. Also, I think factoring out gdbstub_usage() is a bit overkill. > exit(1); > } > =20 > @@ -2264,7 +2261,6 @@ > CPUState *env; > int optind; > const char *r; > - int gdbstub_port =3D 0; > char **target_environ, **wrk; > envlist_t *envlist =3D NULL; > =20 > @@ -2345,10 +2341,15 @@ > fprintf(stderr, "page size must be a power of two\n"); > exit(1); > } > - } else if (!strcmp(r, "g")) { > - if (optind >=3D argc) > + } else if (!strcmp(r, "gdb")) { > + if (optind >=3D argc) { > break; > - gdbstub_port =3D atoi(argv[optind++]); > + } > + if (gdbserver_start(argv[optind++]) < 0) { > + /* stop command line analysis */ > + optind =3D argc; > + break; Shouldn't you rather fail with some error message and exit()? > + } > } else if (!strcmp(r, "r")) { > qemu_uname_release =3D argv[optind++]; > } else if (!strcmp(r, "cpu")) { > @@ -2706,8 +2707,10 @@ > ts->heap_limit =3D 0; > #endif > =20 > - if (gdbstub_port) { > - gdbserver_start (gdbstub_port); > + if (gdbstub_accept !=3D NULL) { > + if ((*gdbstub_accept)() < 0) { > + return -1; > + } Rather introduce gdbstub_accept() and keep the function point private (static) to gdbstub.c. gdbstub_accept() could then also check for the pointer being non-NULL and do the inital handlesig. > gdb_handlesig(env, 0); > } > cpu_loop(env); > Index: gdbstub.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gdbstub.c (r=E9vision 7105) > +++ gdbstub.c (copie de travail) > @@ -19,23 +19,19 @@ > */ > #include "config.h" > #include "qemu-common.h" > + > #ifdef CONFIG_USER_ONLY > -#include > -#include > -#include > -#include > -#include > -#include > -#include > +#include "qemu.h" > +#include "gdbstub.h" > =20 > -#include "qemu.h" > -#else > +#else /* CONFIG_USER_ONLY */ Minor remark: I prefer comment on this with "!CONFIG_USER_ONLY" as the following code handles the !defined case. > #include "monitor.h" > #include "qemu-char.h" > #include "sysemu.h" > #include "gdbstub.h" > -#endif > +#endif /* CONFIG_USER_ONLY */ same here > =20 > + > #define MAX_PACKET_LENGTH 4096 > =20 > #include "qemu_socket.h" > @@ -215,7 +211,7 @@ > -1 > #endif > }; > -#else > +#else /* CONFIG_USER_ONLY */ and here > /* In system mode we only need SIGINT and SIGTRAP; other signals > are not yet supported. */ > =20 > @@ -232,7 +228,7 @@ > -1, > TARGET_SIGTRAP > }; > -#endif > +#endif /* CONFIG_USER_ONLY */ and here. > =20 > #ifdef CONFIG_USER_ONLY > static int target_signal_to_gdb (int sig) > @@ -243,7 +239,7 @@ > return i; > return GDB_SIGNAL_UNKNOWN; > } > -#endif > +#endif /* CONFIG_USER_ONLY */ > =20 > static int gdb_signal_to_target (int sig) > { > @@ -307,31 +303,13 @@ > #ifdef CONFIG_USER_ONLY > /* XXX: This is not thread safe. Do we care? */ > static int gdbserver_fd =3D -1; > +gdbstub_func gdbstub_accept =3D NULL; > =20 > -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 */ > =20 > - for(;;) { > - ret =3D recv(s->fd, &ch, 1, 0); > - if (ret < 0) { > - if (errno =3D=3D ECONNRESET) > - s->fd =3D -1; > - if (errno !=3D EINTR && errno !=3D EAGAIN) > - return -1; > - } else if (ret =3D=3D 0) { > - close(s->fd); > - s->fd =3D -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; > =20 > enum { > @@ -361,26 +339,6 @@ > #endif > } > =20 > -static void put_buffer(GDBState *s, const uint8_t *buf, int len) > -{ > -#ifdef CONFIG_USER_ONLY > - int ret; > - > - while (len > 0) { > - ret =3D send(s->fd, buf, len, 0); > - if (ret < 0) { > - if (errno !=3D EINTR && errno !=3D EAGAIN) > - return; > - } else { > - buf +=3D ret; > - len -=3D ret; > - } > - } > -#else > - qemu_chr_write(s->chr, buf, len); > -#endif > -} > - > static inline int fromhex(int v) > { > if (v >=3D '0' && v <=3D '9') > @@ -1280,7 +1238,7 @@ > return 0; > } > =20 > -#endif > +#endif /* TARGET */ That comment is misleading. Just leave it alone for this patch. > =20 > static int num_g_regs =3D NUM_CORE_REGS; > =20 > @@ -2091,8 +2049,7 @@ > } > =20 > #ifdef CONFIG_USER_ONLY > -int > -gdb_queuesig (void) > +int gdb_queuesig (void) If you are at it already: no space between function name and parameter list. Applies to many other functions in this patch, too. Please adjust. > { > GDBState *s; > =20 > @@ -2104,16 +2061,41 @@ > return 1; > } > =20 > -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 =3D gdbserver_state; > + if (gdbserver_fd < 0 || s->fd < 0) > + return; > + > + snprintf(buf, sizeof(buf), "W%02x", code); > + put_packet(s, buf); > +} > + > +void gdb_signalled(CPUState *env, int sig) > +{ > + GDBState *s; > + char buf[4]; > + > + s =3D 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); > +} > + > +int gdb_handlesig (CPUState *env, int sig) > +{ > + GDBState *s; > char buf[256]; > int n; > =20 > s =3D gdbserver_state; > - if (gdbserver_fd < 0 || s->fd < 0) > - return sig; > + if (gdb_disconnected (s)) return sig; Separate line (with brackets), please. > =20 > /* disable single step if it was enabled */ > cpu_single_step(env, 0); > @@ -2126,9 +2108,9 @@ > } > /* put_packet() might have detected that the peer terminated the=20 > connection. */ > - if (s->fd < 0) > - return sig; > =20 > + if (gdb_disconnected (s)) return sig; > + Same here. > sig =3D 0; > s->state =3D RS_IDLE; > s->running_state =3D 0; > @@ -2138,10 +2120,11 @@ > { > int i; > =20 > - for (i =3D 0; i < n; i++) > + for (i =3D 0; i < n; i++) { > gdb_read_byte (s, buf[i]); > + } > } > - else if (n =3D=3D 0 || errno !=3D EAGAIN) > + else if (n =3D=3D 0 || errno !=3D EAGAIN)=20 Trailing whitespace. > { > /* XXX: Connection closed. Should probably wait for annothe= r > connection before continuing. */ > @@ -2153,108 +2136,294 @@ > return sig; > } > =20 > -/* 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; > =20 > - s =3D gdbserver_state; > - if (gdbserver_fd < 0 || s->fd < 0) > - return; > + for(;;) { > + ret =3D recv(s->fd, &ch, 1, 0); > + if (ret < 0) { > + if (errno =3D=3D ECONNRESET) > + s->fd =3D -1; > + if (errno !=3D EINTR && errno !=3D EAGAIN) > + return -1; > + } else if (ret =3D=3D 0) { > + close(s->fd); > + s->fd =3D -1; > + return -1; > + } else { > + break; > + } > + } > + return ch; > +} > =20 > - snprintf(buf, sizeof(buf), "W%02x", code); > - put_packet(s, buf); > + > +static void put_buffer(GDBState *s, const uint8_t *buf, int len) > +{ > + int ret; > + while (len > 0) { > + ret =3D send(s->fd, buf, len, 0); > + if (ret < 0) { > + if (errno !=3D EINTR && errno !=3D EAGAIN) > + return; > + } else { > + buf +=3D ret; > + len -=3D ret; > + } > + } > } > =20 > -/* Tell the remote gdb that the process has exited due to SIG. */ > -void gdb_signalled(CPUState *env, int sig) > +static int gdb_disconnected (GDBState *s)=20 > { > - GDBState *s; > - char buf[4]; > + return (gdbserver_fd < 0) || (s->fd < 0); > +} > =20 > - s =3D gdbserver_state; > - if (gdbserver_fd < 0 || s->fd < 0) > - return; > +static GDBState *gdbserver_create_gdbstate (void) > +{ > + GDBState *s; > =20 > - snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig)); > - put_packet(s, buf); > + s =3D qemu_mallocz(sizeof(GDBState)); > + s->c_cpu =3D first_cpu; > + s->g_cpu =3D first_cpu; > + gdb_has_xml =3D 0; > + gdbserver_state =3D s; > + return s; > } > =20 > -static void gdb_accept(void) > +static int gdbserver_tcp_accept (void) > { > + int fd,res; > GDBState *s; > - struct sockaddr_in sockaddr; > - socklen_t len; > - int val, fd; > =20 > - for(;;) { > - len =3D sizeof(sockaddr); > - fd =3D accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len= ); > - if (fd < 0 && errno !=3D EINTR) { > - perror("accept"); > - return; > - } else if (fd >=3D 0) { > - break; > + for (;;) { > + fd =3D accept (gdbserver_fd,=20 > + (struct sockaddr *) NULL, (socklen_t *) NULL); > + if (fd < 0) { > + if (errno !=3D EINTR) { > + perror("accept"); > + return -1; > + } > + } else { > + break; > } > } > - > /* set short latency */ > - val =3D 1; > - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)= ); > + res =3D 1; > + res =3D setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&res, siz= eof (res)); > + if (res < 0) { > + fprintf (stderr, "gdbserver ERROR : set nodelay\n"); > + return -1; > + }=20 > + res =3D fcntl(fd, F_SETFL, O_NONBLOCK); > + if (res < 0) { > + fprintf (stderr, "gdbserver ERROR : set nonblock\n"); > + return -1; > + } > + s =3D gdbserver_create_gdbstate (); > + s -> fd =3D fd; > + return 0; > +} > =20 > - s =3D qemu_mallocz(sizeof(GDBState)); > - s->c_cpu =3D first_cpu; > - s->g_cpu =3D first_cpu; > - s->fd =3D fd; > - gdb_has_xml =3D 0; > =20 > - gdbserver_state =3D s; > +static int gdbserver_tcp_start (const char *host, const char *port, > + gdbstub_func faccept) > +{ > + struct addrinfo info_in, *info_out; > + struct sockaddr_in addrin, *addr; > + int res; > =20 > - fcntl(fd, F_SETFL, O_NONBLOCK); > + memset (&info_in, 0, sizeof(struct addrinfo)); > + info_in.ai_flags=3DAI_PASSIVE; /* force INADDR_ANY if host =3D=3D= NULL */ > + info_in.ai_family=3D AF_INET; > + info_in.ai_socktype=3DSOCK_STREAM; > + info_in.ai_protocol=3DIPPROTO_TCP; > + > + if (getaddrinfo(host, port, &info_in, &info_out) < 0) { > + perror ("hostname/portname name conversion error"); > + return -1; > + } > + addr =3D (struct sockaddr_in *) info_out -> ai_addr; > + gdbserver_fd =3D 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 */=20 > + res =3D 1; > + res =3D setsockopt(gdbserver_fd, SOL_SOCKET, SO_REUSEADDR, > + (char *) &res, sizeof(res)); > + if (res <0) { > + perror("gdb socket : set fast reuse\n"); > + return -1; > + } > + res =3D bind (gdbserver_fd, (struct sockaddr *) addr, sizeof (addr= in)); > + if (res <0) { > + perror("gdb socket bind\n"); > + return -1; > + } > + res =3D listen (gdbserver_fd,0); > + if (res <0) { > + perror("listen\n"); > + return -1; > + } > + gdbstub_accept =3D faccept; > + return 0; > +}=20 > + > +#ifndef _WIN32 > +static int gdbserver_unix_unlink (void) > +{ > + struct sockaddr_un sock; > + socklen_t len; > + int res; > + > + len =3D sizeof (sock.sun_path); > + res =3D getsockname (gdbserver_fd, &sock, &len); > + if (res < 0 ) { > + fprintf (stderr,"gdb accept/unlink : cannot get socket name\n")= ; > + return -1; > + } > + res =3D unlink (sock.sun_path); > + if (res < 0) { > + fprintf (stderr,"gdb accept/unlink : cannot unlink %s\n",sock.s= un_path); > + return -1; > + }=20 > + return 0; > } > =20 > -static int gdbserver_open(int port) > +static int gdbserver_unix_accept (void) > { > - struct sockaddr_in sockaddr; > - int fd, val, ret; > + int fd,res; > + GDBState *s; > + for (;;) { > + fd =3D accept (gdbserver_fd,=20 > + (struct sockaddr *) NULL, ( socklen_t *) NULL); > + if (fd < 0) { > + if (errno !=3D EINTR) { > + perror("accept"); > + return -1; > + } > + } else { > + break; > + } > + } > =20 > - fd =3D socket(PF_INET, SOCK_STREAM, 0); > - if (fd < 0) { > - perror("socket"); > - return -1; > + res =3D fcntl(fd, F_SETFL, O_NONBLOCK); > + if (res < 0) { > + fprintf (stderr, "gdbserver ERROR : set nonblock\n"); > + return -1; > } > + s =3D gdbserver_create_gdbstate (); > + s -> fd =3D fd; > + return 0; > +} > =20 > - /* allow fast reuse */ > - val =3D 1; > - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)= ); > +static int gdbserver_unix_accept_unlink (void) > +{ > + return (gdbserver_unix_accept () + gdbserver_unix_unlink ()); > +} > =20 > - sockaddr.sin_family =3D AF_INET; > - sockaddr.sin_port =3D htons(port); > - sockaddr.sin_addr.s_addr =3D 0; > - ret =3D bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); > - if (ret < 0) { > - perror("bind"); > +static int gdbserver_unix_start (const char *filename,=20 > + gdbstub_func faccept) > +{ > + struct sockaddr_un addr; > + int res; > + > + if (strlen(filename) =3D=3D 0) { > + fprintf (stderr, "gdbserver ERROR : missing unix socket name\n"= ); > + return -1; > + } > + > + memset (&addr, 0, sizeof(struct sockaddr_un)); > + addr.sun_family =3D AF_UNIX; > + strcpy (addr.sun_path, filename); > + > + gdbserver_fd =3D socket (AF_UNIX,SOCK_STREAM,0); > + if (gdbserver_fd < 0) { > + perror ("gsbserver socket"); > return -1; > } > - ret =3D listen(fd, 0); > - if (ret < 0) { > - perror("listen"); > + res =3D bind (gdbserver_fd, (struct sockaddr *) &addr,=20 > + sizeof(struct sockaddr_un)); > + if (res < 0) { > + perror ("gdbserver bind\n"); > return -1; > } > - return fd; > -} > + res =3D listen (gdbserver_fd,0); > + if (res <0) { > + perror("listen\n"); > + return -1; > + } > + gdbstub_accept =3D faccept; > + return 0; > +}=20 > =20 > -int gdbserver_start(int port) > +#endif /* _WIN32 */ =20 > + > +void gdbstub_usage (void)=20 > { > - gdbserver_fd =3D gdbserver_open(port); > - if (gdbserver_fd < 0) > - return -1; > - /* accept connections */ > - gdb_accept(); > + printf("-gdb device /* use gdb> target command */\n"); > + printf(" tcp:host:port target remote host:port \n"); > +#ifndef _WIN32 > + printf(" unix:name target remote | socat stdio unix:na= me\n"); > + printf(" unix:name,unlink : unlink remove name from filesyste= m after connection\n"); > +#endif /* _WIN32 */ > +} =20 > + > +int gdbserver_start (const char *device) > +{ > + const char *p; > + char *name, *devicename,*opt; > + > + name =3D malloc (strlen(device)+1); > + /* Light memory leak : will never be freed */ > + > + if (strstart (device, "tcp:",&p)) { > + if ((p =3D=3D NULL) || (strlen(p) =3D=3D 0)) { > + perror ("tcp socket syntax error"); > + return -1; > + } > + strcpy (name,p); > + devicename =3D strrchr (name,':'); > + if (devicename =3D=3D NULL) { > + return -1; > + } > + *devicename++ =3D 0; > + if (*devicename =3D=3D 0) { > + return -1; > + } > + if (*name =3D=3D 0) { > + name =3D NULL; > + } > + return gdbserver_tcp_start (name,devicename, > + gdbserver_tcp_accept); > +#ifndef _WIN32 > + } else if (strstart (device, "unix:",&p)) { > + strcpy (name,p); > + opt =3D strrchr(name,','); > + if (opt =3D=3D NULL) { > + return gdbserver_unix_start(name,gdbserver_unix_accept); > + } else { > + *opt++ =3D 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; > + } > + }=20 > +#endif /* _WIN32 */ > + } else { > + return -1; > + } > return 0; > } > =20 > +/* Tell the remote gdb that the process has exited due to SIG. */ > /* Disable gdb stub for child processes. */ > void gdbserver_fork(CPUState *env) > { Does that new comment really belong here? > @@ -2266,7 +2435,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. > @@ -2330,7 +2506,7 @@ > if (vm_running) > vm_stop(EXCP_INTERRUPT); > } > -#endif > +#endif /* _WIN32 */ Skip such not directly related changes. > =20 > int gdbserver_start(const char *device) > { > @@ -2356,7 +2532,7 @@ > act.sa_handler =3D gdb_sigterm_handler; > sigaction(SIGINT, &act, NULL); > } > -#endif > +#endif /* _WIN32 */ > chr =3D qemu_chr_open("gdb", device, NULL); > if (!chr) > return -1; > @@ -2390,4 +2566,4 @@ > =20 > return 0; > } > -#endif > +#endif /* CONFIG_USER_ONLY */ > Index: gdbstub.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gdbstub.h (r=E9vision 7105) > +++ gdbstub.h (copie de travail) > @@ -16,20 +16,25 @@ > 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 > +typedef int (*gdbstub_func) (void); > +extern gdbstub_func gdbstub_accept; > + > 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); > -#endif > +void gdbstub_usage (void); > +#endif /* CONFIG_USER_ONLY */ > + > +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, > gdb_reg_cb get_reg, gdb_reg_cb set_reg, > int num_regs, const char *xml, int g_pos= ); > =20 > -#endif > +#endif /* GDBSTUB_H */ I still think you are on the right track, just minor issues, some coding style cleanups and the gdbstub_accept refactoring. Thanks so far! Jan --=20 Siemens AG, Corporate Technology, CT SE 2 Corporate Competence Center Embedded Linux