diff --git a/drake/test1/main b/drake/test1/main
new file mode 100755
index 0000000000000000000000000000000000000000..f184c09488f33bb06aa276cba7bcc7e9ca63bc0a
Binary files /dev/null and b/drake/test1/main differ
diff --git a/drake/test2/Makefile b/drake/test2/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..915290724b2c3bc6af1a5483d87579d93ec409c0
--- /dev/null
+++ b/drake/test2/Makefile
@@ -0,0 +1,3 @@
+
+all:
+	ls /doesntexist
diff --git a/duck/duck.c b/duck/duck.c
index 280eb9e4c44e6698c78d959312d884fe5604bc3a..3f52e8febb65bfc1e47fdc250608a4e312c9808c 100644
--- a/duck/duck.c
+++ b/duck/duck.c
@@ -82,15 +82,12 @@ int main(int argc, char **argv)
 	  } else if (strcmp(argv[i], "nod") == 0) {
 	       if (argv[i+1]) {
 		    int numnods = atoi(argv[i+1]);
-		    shake(MOTOR_2, numnods, -90, 0, 250);
+		    shake(MOTOR_2, numnods, 0, 90, 250);
 		    i++;
 	       }
 	  } else if (strcmp(argv[i], "facepalm") == 0) {
-	       if (argv[i+1]) {
-		    int numnods = atoi(argv[i+1]);
-		    shake(MOTOR_2, numnods, -90, 0, 250);
-		    i++;
-	       }
+	       duck_set_velocity(2, 30, 3000);
+	       duck_delay(3000);
 	  } else if (strcmp(argv[i], "print") == 0) {
 	       if (argv[i+1]) {
 		    duck_write_text(argv[i+1]);
diff --git a/gduckb/Makefile b/gduckb/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7862772b9554e78ccc2bc46cbdb4bfda3df98d3c
--- /dev/null
+++ b/gduckb/Makefile
@@ -0,0 +1,2 @@
+gduckb: gduckb.c ../libduck/libduck.so
+	cc gduckb.c -o gduckb -L ../libduck -l duck -g
diff --git a/gduckb/gdbinit b/gduckb/gdbinit
new file mode 100644
index 0000000000000000000000000000000000000000..1ca4a9c7a12efa12040bd6201940058ed0061def
--- /dev/null
+++ b/gduckb/gdbinit
@@ -0,0 +1,2 @@
+b main
+r a.out
diff --git a/gduckb/gduckb.c b/gduckb/gduckb.c
new file mode 100644
index 0000000000000000000000000000000000000000..8efabd4a1b83b62279c1b7ffe7727fa6f31ca265
--- /dev/null
+++ b/gduckb/gduckb.c
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <err.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "../libduck/libduck.h"
+
+int this_in_gdb_out[2];
+int gdb_in_this_out[2];
+
+void setup_pipes(void)
+{
+     if (pipe(gdb_in_this_out) ||
+       pipe(this_in_gdb_out)) err(EXIT_FAILURE, "Pipe failed");
+     /*this_in_gdb_out[0] = STDIN_FILENO;
+       gdb_in_this_out[1] = STDOUT_FILENO;*/
+}
+
+void launch_gdb(const char *prog)
+{
+     int res = fork();
+     if (res < 0) {
+	  err(EXIT_FAILURE, "fork failed");
+     } else if (res == 0) { /* Child */
+	  dup2(gdb_in_this_out[0], STDIN_FILENO);
+	  dup2(this_in_gdb_out[1], STDOUT_FILENO);
+	  
+	  if (execl("/bin/gdb", "/bin/gdb", "--interpreter=mi3", "-x", "gdbinit", prog, (char *)NULL)) {
+	       err(EXIT_FAILURE, "Failed to launch gdb");
+	  }
+     } else { /* Parent */
+	  return;
+     }
+}
+
+enum {
+     STATE_LINENO, STATE_WHITESPACE, STATE_CODE, STATE_NL
+};
+
+void process_code_line(const char *str)
+{
+     if (str[0] != '~' || str[1] != '"') return;
+
+     int state = STATE_LINENO;
+     static char lineno_buf[20];
+     int lb_ind = 0;
+     int lineno;
+     static char code_buf[200];
+     int code_ind = 0;
+     int esc = 0;
+     
+     for (const char *c=str+2; *c; c++) {
+	  switch (state) {
+	  case STATE_LINENO:
+	       if (isdigit(*c)) {
+		    lineno_buf[lb_ind++] = *c;
+	       } else if (c[0] == '\\' && c[1] == 't') {
+		    lineno_buf[lb_ind] = 0;
+		    lineno = atoi(lineno_buf);
+		    if (lineno <= 0) return;
+		    state = STATE_WHITESPACE;
+		    c += 2;
+	       }
+	       break;
+	  case STATE_WHITESPACE:
+	       if (!isspace(*c)) {
+		    state = STATE_CODE;
+		    code_buf[code_ind++] = *c;
+	       }
+	       break;
+	  case STATE_CODE:
+	       if (esc) {
+		    if (*c == 't') code_buf[code_ind++] = '\t';
+		    if (*c == '\\') code_buf[code_ind++] = '\\';
+		    if (*c == '"') code_buf[code_ind++] = '"';
+		    if (*c == '\'') code_buf[code_ind++] = '\'';
+		    if (*c == 'n') state = STATE_NL;
+		    esc = 0;
+	       } else if (*c == '\\') {
+		    esc = 1;
+	       } else {
+		    code_buf[code_ind++] = *c;
+	       }
+	       break;
+	  case STATE_NL:
+	       code_buf[code_ind] = 0;
+	       duck_write_text(code_buf);
+	       break;
+	  }
+     }
+}
+
+/* Line of code is last ~ line before prompt, matching line pattern */
+
+enum { STATE_PROMPT, STATE_TILDE_LINE, STATE_OTHER_LINE };
+
+void parse_line(const char *line)
+{
+     static int state = STATE_OTHER_LINE;
+     static char codelinebuf[200];
+
+     switch (state) {
+     case STATE_PROMPT:
+	  if (line[0] == '~') {
+	       state = STATE_TILDE_LINE;
+	       strncpy(codelinebuf, line, 199);
+	  }
+	  break;
+     case STATE_TILDE_LINE:
+	  if (line[0] != '~') {
+	       state = STATE_OTHER_LINE;
+	       process_code_line(codelinebuf);
+	  }
+	  break;
+     case STATE_OTHER_LINE:
+	  if (strcmp(line, "(gdb)") == 0) {
+	       state = STATE_PROMPT;
+	  }
+	  if (line[0] == '~') process_code_line(line);
+	  break;
+     }
+}
+	       
+
+char buf[4096];
+int buf_ind = 0;
+
+char linebuf[200];
+int linebuf_ind = 0;
+
+void read_data(void)
+{
+     int n;
+
+     if ((n=read(this_in_gdb_out[0], buf, 4065)) <= 0) {
+	  return;
+     } else {
+	  for (int i=0; i < n; i++) {
+	       if (buf[i] == '\n') {
+		    linebuf[linebuf_ind] = '\0';
+		    parse_line(linebuf);
+		    linebuf_ind = 0;
+	       } else {
+		    linebuf[linebuf_ind++] = buf[i];
+	       }
+	  }
+     }
+}
+
+void sleep_ms(int ms)
+{
+     struct timespec ts = {
+	  .tv_sec=ms/1000, .tv_nsec=(ms % 1000) * 1000000
+     };
+     nanosleep(&ts, NULL);
+}
+
+void shake(int motor, int number, int min, int max, int delay)
+{
+     int delay1 = (delay * (-min)) / (max - min);
+     int delay2 = delay - delay1;
+     
+     duck_set_velocity(motor, 100, 100);
+     duck_delay(100);
+     duck_set_velocity(motor, -100, 200);
+     duck_delay(200);
+     duck_set_velocity(motor, 100, 100);
+     duck_delay(100);
+}
+int interact_gdb(void)
+{
+     FILE *to_gdb = fdopen(gdb_in_this_out[1], "w");
+     if (!to_gdb) err(EXIT_FAILURE, "fdopen failed");
+     setbuf(to_gdb, NULL);
+     
+     struct pollfd fds[] = {
+	  { .fd = this_in_gdb_out[0], POLLIN, 0 },
+	  { .fd = duckfd, POLLIN, 0 },
+     };
+
+     static char tmp[4096];
+
+     /*read(this_in_gdb_out[0], tmp, 4096);
+     fprintf(to_gdb, "b main\n");
+     sleep_ms(300);
+     read(this_in_gdb_out[0], tmp, 4096);
+     fprintf(to_gdb, "r\n");*/
+     sleep_ms(300);
+
+     while (1) {
+	  if (poll(fds, 2, -1)) {
+	       if (fds[0].revents) {
+		    read_data();
+		    fds[0].revents = 0;
+	       }
+	       if (fds[1].revents) {
+		    int c = duck_getc();
+		    fprintf(to_gdb, c == 'a' ? "s\n" : "n\n");
+		    shake(MOTOR_1, 2, -20, 20, 200);
+		    fds[1].revents = 0;
+	       }
+	  }
+     }
+}
+
+
+
+int main(int argc, char **argv)
+{
+     duck_debug_mode = 0;
+     if (argc < 2) {
+	  printf("Usage: gduckb program-name\n");
+	  return -1;
+     }
+     
+     setup_pipes();
+     launch_gdb("a.out");
+     open_duck(DEFAULT_DUCK_FNAME);
+     configure_duck();
+
+     if (interact_gdb()) {
+	  err(EXIT_FAILURE, "gdb interaction failed");
+     }
+     close_duck();
+     return 0;
+     
+}
diff --git a/libduck/libduck.c b/libduck/libduck.c
index d0e210f6dd936bb2ec60e724ba460b765bd612cb..f967f3fb039f1d5bdf7797ae8877c32cc4eb2f85 100644
--- a/libduck/libduck.c
+++ b/libduck/libduck.c
@@ -11,14 +11,14 @@
 # define DUCK_BAUD B115200
 #endif /* DUCK_BAUD */
 
-static int duckfd = 0;
+int duckfd = 0;
 
 int duck_debug_mode = 0;
 
 void open_duck(const char *fname)
 {
      if (duck_debug_mode) {
-	  printf("Opening duck\n");
+	  fprintf(stderr, "Opening duck\n");
      } else {
 	  duckfd = open(fname, O_NOCTTY | O_RDWR);
 	  
@@ -31,7 +31,7 @@ void open_duck(const char *fname)
 void configure_duck(void)
 {
      if (duck_debug_mode) {
-	  printf("Configuring duck\n");
+	  fprintf(stderr, "Configuring duck\n");
      } else {
 	  struct termios tio;
 	  if (tcgetattr(duckfd, &tio)) {
@@ -51,7 +51,7 @@ static int duck_printf(const char *fmt, ...)
      va_list ap;
      va_start(ap, fmt);
      if (duck_debug_mode) {
-	  return vprintf(fmt, ap);
+	  return vfprintf(stderr, fmt, ap);
      } else {
 	  return vdprintf(duckfd, fmt, ap) < 0;
      }
@@ -103,10 +103,17 @@ void read_duck_to_stdout(void)
      }
 }
 
+int duck_getc(void)
+{
+     char c;
+     if (read(duckfd, &c, 1)) return c;
+     else return EOF;
+}
+
 void close_duck(void)
 {
      if (duck_debug_mode) {
-	  printf("Closing duck\n");
+	  fprintf(stderr, "Closing duck\n");
      } else {
 	  close(duckfd);
      }
diff --git a/libduck/libduck.h b/libduck/libduck.h
index 9ce01667bf2b107d35497b1a3b4a7de3b95fa6bf..524c3de95e56a5f2baddeeb07c1af29aa4acbdc8 100644
--- a/libduck/libduck.h
+++ b/libduck/libduck.h
@@ -10,6 +10,7 @@
 #endif /* DEFAULT_DUCK_FNAME */
 
 extern int duck_debug_mode;
+extern int duckfd;
 
 void open_duck(const char *fname);
 void configure_duck(void);
@@ -18,6 +19,7 @@ int duck_delay(int ms);
 int duck_set_velocity(int motor, int deg_per_sec, int ms);
 int duck_write_text(const char *str);
 void read_duck_to_stdout(void);
+int duck_getc(void);
 void close_duck(void);
 
 #endif /* _LIBDUCK_H */