[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH] gdbstub user mode : canonical -gdb dev option + unix sockets,
Philippe Waille <=