qemu-devel
[Top][All Lists]
Advanced

[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

Attachment: patch.tar
Description: Unix tar archive


reply via email to

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