All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] Re: [PATCH v2] Gdbstub user mode -gdb dev option/unix sockets
@ 2009-04-15 18:59 Philippe Waille
  0 siblings, 0 replies; only message in thread
From: Philippe Waille @ 2009-04-15 18:59 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 18518 bytes --]


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 :    Philippe.Waille@imag.fr
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


[-- Attachment #2: patch.tar --]
[-- Type: application/x-tar, Size: 169203 bytes --]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-04-15 19:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-15 18:59 [Qemu-devel] Re: [PATCH v2] Gdbstub user mode -gdb dev option/unix sockets Philippe Waille

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.