qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] gdbstub user mode : canonical -gdb dev option + uni


From: Philippe Waille
Subject: [Qemu-devel] [PATCH] gdbstub user mode : canonical -gdb dev option + unix sockets
Date: Tue, 28 Apr 2009 00:22:09 +0200
User-agent: Mutt/1.5.18 (2008-05-17)

Extend -gdb dev system mode canonical configuration to user mode.
Allow tcp sockets (existing code) and unix sockets (addition).

Sign-off-by: Philippe Waille <address@hidden>

---
 gdbstub.c         |  307 +++++++++++++++++++++++++++++++++++++++++------------
 gdbstub.h         |    5 +-
 linux-user/main.c |   24 +++--
 3 files changed, 253 insertions(+), 83 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 3c34741..6b788d5 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -19,22 +19,14 @@
  */
 #include "config.h"
 #include "qemu-common.h"
+#include "gdbstub.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
 
@@ -305,8 +297,16 @@ static GDBState *gdbserver_state;
 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 gdb_disconnected(GDBState *s)
+{
+    return  (gdbserver_fd < 0) || (s->fd < 0);
+}
 
 static int get_char(GDBState *s)
 {
@@ -332,6 +332,7 @@ static int get_char(GDBState *s)
 }
 #endif
 
+
 static gdb_syscall_complete_cb gdb_current_syscall_cb;
 
 static enum {
@@ -2098,10 +2099,11 @@ gdb_queuesig (void)
 
     s = gdbserver_state;
 
-    if (gdbserver_fd < 0 || s->fd < 0)
+    if (gdb_disconnected(s)) {
         return 0;
-    else
+    } else {
         return 1;
+    }
 }
 
 int
@@ -2112,8 +2114,9 @@ gdb_handlesig (CPUState *env, int sig)
   int n;
 
   s = gdbserver_state;
-  if (gdbserver_fd < 0 || s->fd < 0)
+  if (gdb_disconnected(s)) {
     return sig;
+  }
 
   /* disable single step if it was enabled */
   cpu_single_step(env, 0);
@@ -2126,8 +2129,9 @@ gdb_handlesig (CPUState *env, int sig)
     }
   /* 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;
@@ -2160,8 +2164,9 @@ void gdb_exit(CPUState *env, int code)
   char buf[4];
 
   s = gdbserver_state;
-  if (gdbserver_fd < 0 || s->fd < 0)
+  if (gdb_disconnected(s)) {
     return;
+  }
 
   snprintf(buf, sizeof(buf), "W%02x", code);
   put_packet(s, buf);
@@ -2174,84 +2179,245 @@ void gdb_signalled(CPUState *env, int sig)
   char buf[4];
 
   s = gdbserver_state;
-  if (gdbserver_fd < 0 || s->fd < 0)
+  if (gdb_disconnected(s)) {
     return;
+  }
 
   snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
   put_packet(s, buf);
 }
 
-static void gdb_accept(void)
+static GDBState *gdbserver_create_gdbstate(void)
+ {
+     GDBState *s;
+
+     s = qemu_mallocz(sizeof(GDBState));
+     s->c_cpu = first_cpu;
+     s->g_cpu = first_cpu;
+     gdb_has_xml = 0;
+     gdbserver_state = s;
+     return s;
+}
+
+static int gdbserver_tcp_accept(void)
 {
+    int fd,res;
     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;
+    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 */
-    val = 1;
-    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+    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;
+}
 
-    s = qemu_mallocz(sizeof(GDBState));
-    s->c_cpu = first_cpu;
-    s->g_cpu = first_cpu;
-    s->fd = fd;
-    gdb_has_xml = 0;
+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;
+
+    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;
+} 
+
+#ifndef  _WIN32
+static int gdbserver_unix_unlink(void)
+{
+    struct sockaddr_un sock;
+    socklen_t len;
+    int res;
+    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;
+}
 
-    gdbserver_state = s;
+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;
+}
 
-    fcntl(fd, F_SETFL, O_NONBLOCK);
+static int gdbserver_unix_accept_unlink(void)
+{
+    return (gdbserver_unix_accept() || gdbserver_unix_unlink());
 }
 
-static int gdbserver_open(int port)
+static int gdbserver_unix_start(const char *filename, gdbstub_func faccept)
 {
-    struct sockaddr_in sockaddr;
-    int fd, val, ret;
+    struct sockaddr_un addr;
+    int res;
 
-    fd = socket(PF_INET, SOCK_STREAM, 0);
-    if (fd < 0) {
-        perror("socket");
-        return -1;
+    if (strlen(filename) == 0) {
+       fprintf(stderr, "gdbserver ERROR : missing unix socket name\n");
+       return -1;
     }
 
-    /* allow fast reuse */
-    val = 1;
-    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+    memset(&addr, 0, sizeof(struct sockaddr_un));
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, filename);
 
-    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");
-        return -1;
+    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");
+    }
+    res = listen (gdbserver_fd,0);
+    if (res <0) {
+        perror("listen\n");
         return -1;
     }
-    return fd;
+    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;
 }
 
@@ -2259,14 +2425,15 @@ int gdbserver_start(int port)
 void gdbserver_fork(CPUState *env)
 {
     GDBState *s = gdbserver_state;
-    if (gdbserver_fd < 0 || s->fd < 0)
-      return;
+    if (gdb_disconnected(s)) {
+        return;
+    }
     close(s->fd);
     s->fd = -1;
     cpu_breakpoint_remove_all(env, BP_GDB);
     cpu_watchpoint_remove_all(env, BP_GDB);
 }
-#else
+#else /* !CONFIG_USER_ONLY */
 static int gdb_chr_can_receive(void *opaque)
 {
   /* We can handle an arbitrarily large amount of data.
@@ -2390,4 +2557,4 @@ int gdbserver_start(const char *device)
 
     return 0;
 }
-#endif
+#endif /* !CONFIG_USER_ONLY */
diff --git a/gdbstub.h b/gdbstub.h
index 5740041..513965c 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -21,11 +21,10 @@ 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,
diff --git a/linux-user/main.c b/linux-user/main.c
index dc39b05..9e54f62 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2220,7 +2220,12 @@ static void usage(void)
            "\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"
@@ -2277,7 +2282,6 @@ int main(int argc, char **argv, char **envp)
     CPUState *env;
     int optind;
     const char *r;
-    int gdbstub_port = 0;
     char **target_environ, **wrk;
     char **target_argv;
     int target_argc;
@@ -2365,10 +2369,13 @@ int main(int argc, char **argv, char **envp)
                 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")) {
@@ -2754,10 +2761,7 @@ int main(int argc, char **argv, char **envp)
     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;
-- 
1.6.2.1

-- 
-----------------------------------------------------------------------------
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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]