Temporarily set current working directory to rr's root directory while the tracee connects to rr's socket
diff --git a/src/AutoRemoteSyscalls.cc b/src/AutoRemoteSyscalls.cc
index 3f55050..ae7428d 100644
--- a/src/AutoRemoteSyscalls.cc
+++ b/src/AutoRemoteSyscalls.cc
@@ -4,6 +4,8 @@
 
 #include "AutoRemoteSyscalls.h"
 
+#include "rr/rr.h"
+
 #include "log.h"
 #include "Session.h"
 #include "task.h"
@@ -214,11 +216,27 @@
                                  AutoRestoreMem& remote_buf,
                                  remote_ptr<socketcall_args<Arch> > sc_args,
                                  remote_ptr<void> buf_end, int child_sock,
-                                 const char* path) {
+                                 const char* path, int* cwd_fd) {
   typename Arch::sockaddr_un addr;
   addr.sun_family = AF_UNIX;
   assert(strlen(path) < sizeof(addr.sun_path));
-  strcpy(addr.sun_path, path);
+  // Skip leading '/' since we're going to access this relative to the root
+  assert(path[0] == '/');
+  strcpy(addr.sun_path, path + 1);
+
+  auto tmp_buf_end = buf_end;
+  auto remote_dot = allocate(&tmp_buf_end, remote_buf, 2);
+  remote.task()->write_mem(remote_dot.cast<char>(), ".", 2);
+  *cwd_fd = remote.syscall(syscall_number_for_open(Arch::arch()), remote_dot,
+                           O_PATH | O_DIRECTORY);
+  if (0 > *cwd_fd) {
+    FATAL() << "Failed to open() cwd in tracee; err=" << *cwd_fd;
+  }
+  int child_syscall_result =
+      remote.syscall(Arch::fchdir, RR_RESERVED_ROOT_DIR_FD);
+  if (0 > child_syscall_result) {
+    FATAL() << "Failed to fchdir() in tracee; err=" << child_syscall_result;
+  }
 
   auto remote_addr = allocate<typename Arch::sockaddr_un>(&buf_end, remote_buf);
   remote.task()->write_mem(remote_addr, addr);
@@ -241,6 +259,20 @@
 }
 
 template <typename Arch>
+static void child_restore_cwd(AutoRemoteSyscalls& remote, int cwd_fd) {
+  // Restore child's cwd
+  int child_syscall_result = remote.syscall(Arch::fchdir, cwd_fd);
+  if (0 > child_syscall_result) {
+    FATAL() << "Failed to fchdir() to old cwd in tracee; err="
+            << child_syscall_result;
+  }
+  child_syscall_result = remote.syscall(Arch::close, cwd_fd);
+  if (0 > child_syscall_result) {
+    FATAL() << "Failed to close() cwd in tracee; err=" << child_syscall_result;
+  }
+}
+
+template <typename Arch>
 static void child_sendmsg(AutoRemoteSyscalls& remote,
                           AutoRestoreMem& remote_buf,
                           remote_ptr<socketcall_args<Arch> > sc_args,
@@ -347,8 +379,9 @@
 
   int listen_sock = create_bind_and_listen_socket(path);
   int child_sock = child_create_socket(*this, sc_args);
+  int cwd_fd;
   child_connect_socket(*this, remote_buf, sc_args, sc_args_end, child_sock,
-                       path);
+                       path, &cwd_fd);
   // Now the child is waiting for us to accept it.
   int sock = accept(listen_sock, nullptr, nullptr);
   if (sock < 0) {
@@ -359,6 +392,8 @@
   if (child_syscall_result) {
     FATAL() << "Failed to connect() in tracee; err=" << child_syscall_result;
   }
+  child_restore_cwd<Arch>(*this, cwd_fd);
+
   // Listening socket not needed anymore
   close(listen_sock);
   unlink(path);