Merge "Fix media on W/T"
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/adb/OWNERS b/adb/OWNERS
new file mode 100644
index 0000000..643b448
--- /dev/null
+++ b/adb/OWNERS
@@ -0,0 +1,2 @@
+jmgao@google.com
+yabinc@google.com
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 2e999ee..b15d28a 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -305,6 +305,7 @@
         handle->devpath = devpath;
         usb_handle* handle_p = handle.get();
         VLOG(USB) << "Add usb device " << serial;
+        LOG(INFO) << "reported max packet size for " << serial << " is " << handle->max_packet_size;
         AddDevice(std::move(handle));
         register_usb_transport(reinterpret_cast<::usb_handle*>(handle_p), serial, devpath.c_str(),
                                1);
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index fdecccf..a00ed5e 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -27,11 +27,18 @@
 
 #if ADB_HOST
 
+#if defined(__APPLE__)
+#define CHECK_PACKET_OVERFLOW 0
+#else
+#define CHECK_PACKET_OVERFLOW 1
+#endif
+
 // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
 // to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
 static int UsbReadMessage(usb_handle* h, amessage* msg) {
     D("UsbReadMessage");
 
+#if CHECK_PACKET_OVERFLOW
     size_t usb_packet_size = usb_get_max_packet_size(h);
     CHECK_GE(usb_packet_size, sizeof(*msg));
     CHECK_LT(usb_packet_size, 4096ULL);
@@ -44,6 +51,9 @@
     }
     memcpy(msg, buffer, sizeof(*msg));
     return n;
+#else
+    return usb_read(h, msg, sizeof(*msg));
+#endif
 }
 
 // Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
@@ -51,6 +61,7 @@
 static int UsbReadPayload(usb_handle* h, apacket* p) {
     D("UsbReadPayload(%d)", p->msg.data_length);
 
+#if CHECK_PACKET_OVERFLOW
     size_t usb_packet_size = usb_get_max_packet_size(h);
     CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
 
@@ -64,6 +75,9 @@
     }
     CHECK_LE(len, sizeof(p->data));
     return usb_read(h, &p->data, len);
+#else
+    return usb_read(h, &p->data, p->msg.data_length);
+#endif
 }
 
 static int remote_read(apacket* p, atransport* t) {
diff --git a/adf/OWNERS b/adf/OWNERS
new file mode 100644
index 0000000..72b8b5a
--- /dev/null
+++ b/adf/OWNERS
@@ -0,0 +1,2 @@
+ghackmann@google.com
+marissaw@google.com
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 0000000..97777f7
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,3 @@
+enh@google.com
+jmgao@google.com
+tomcherry@google.com
diff --git a/bootstat/OWNERS b/bootstat/OWNERS
new file mode 100644
index 0000000..7fe0443
--- /dev/null
+++ b/bootstat/OWNERS
@@ -0,0 +1 @@
+jhawkins@google.com
diff --git a/debuggerd/OWNERS b/debuggerd/OWNERS
new file mode 100644
index 0000000..bfeedca
--- /dev/null
+++ b/debuggerd/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+jmgao@google.com
diff --git a/demangle/OWNERS b/demangle/OWNERS
new file mode 100644
index 0000000..6f7e4a3
--- /dev/null
+++ b/demangle/OWNERS
@@ -0,0 +1 @@
+cferris@google.com
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e0f702d..10ef356 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs sload_f2fs
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -79,6 +79,7 @@
 my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
 my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
 my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs$(HOST_EXECUTABLE_SUFFIX)
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
 ifdef HOST_CROSS_OS
 # Archive fastboot.exe for win_sdk build.
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
new file mode 100644
index 0000000..2d12d50
--- /dev/null
+++ b/fastboot/OWNERS
@@ -0,0 +1,3 @@
+dpursell@google.com
+enh@google.com
+jmgao@google.com
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 9949eae..a1e1677 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -28,7 +28,7 @@
 using android::base::unique_fd;
 
 #ifdef WIN32
-static int exec_e2fs_cmd(const char* /*path*/, const char** argv, const char** envp) {
+static int exec_cmd(const char* path, const char** argv, const char** envp) {
     std::string cmd;
     int i = 0;
     while (argv[i] != nullptr) {
@@ -76,10 +76,14 @@
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
 
-    return exit_code != 0;
+    if (exit_code != 0) {
+        fprintf(stderr, "%s failed: %lu\n", path, exit_code);
+        return -1;
+    }
+    return 0;
 }
 #else
-static int exec_e2fs_cmd(const char* path, const char** argv, const char** envp) {
+static int exec_cmd(const char* path, const char** argv, const char** envp) {
     int status;
     pid_t child;
     if ((child = fork()) == 0) {
@@ -97,11 +101,13 @@
     int ret = -1;
     if (WIFEXITED(status)) {
         ret = WEXITSTATUS(status);
-        if (ret != 0) {
-            fprintf(stderr, "%s failed with status %d\n", path, ret);
-        }
     }
-    return ret;
+
+    if (ret != 0) {
+        fprintf(stderr, "%s failed with status %d\n", path, ret);
+        return -1;
+    }
+    return 0;
 }
 #endif
 
@@ -140,9 +146,8 @@
     const std::string mke2fs_env = "MKE2FS_CONFIG=" + GetExecutableDirectory() + "/mke2fs.conf";
     std::vector<const char*> mke2fs_envp = {mke2fs_env.c_str(), nullptr};
 
-    int ret = exec_e2fs_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
+    int ret = exec_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
     if (ret != 0) {
-        fprintf(stderr, "mke2fs failed: %d\n", ret);
         return -1;
     }
 
@@ -154,19 +159,12 @@
     std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
                                                fileName, nullptr};
 
-    ret = exec_e2fs_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
-    if (ret != 0) {
-        fprintf(stderr, "e2fsdroid failed: %d\n", ret);
-        return -1;
-    }
-
-    return 0;
+    return exec_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
 }
 
 static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
                                unsigned /* unused */, unsigned /* unused */)
 {
-#ifndef WIN32
     const std::string exec_dir = android::base::GetExecutableDirectory();
     const std::string mkf2fs_path = exec_dir + "/make_f2fs";
     std::vector<const char*> mkf2fs_args = {mkf2fs_path.c_str()};
@@ -182,22 +180,20 @@
     mkf2fs_args.push_back(fileName);
     mkf2fs_args.push_back(nullptr);
 
-    int ret = exec_e2fs_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
+    int ret = exec_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
     if (ret != 0) {
-        fprintf(stderr, "mkf2fs failed: %d\n", ret);
         return -1;
     }
 
-    if (!initial_dir.empty()) {
-        fprintf(stderr, "sload.f2s not supported yet\n");
+    if (initial_dir.empty()) {
         return 0;
     }
-    return 0;
-#else
-    UNUSED(fileName, partSize, initial_dir);
-    fprintf(stderr, "make_f2fs not supported on Windows\n");
-    return -1;
-#endif
+
+    const std::string sload_path = exec_dir + "/sload_f2fs";
+    std::vector<const char*> sload_args = {sload_path.c_str(), "-S",
+                                       "-f", initial_dir.c_str(), fileName, nullptr};
+
+    return exec_cmd(sload_args[0], sload_args.data(), nullptr);
 }
 
 static const struct fs_generator {
diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS
new file mode 100644
index 0000000..817a0b8
--- /dev/null
+++ b/fs_mgr/OWNERS
@@ -0,0 +1,2 @@
+bowgotsai@google.com
+tomcherry@google.com
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index fc88217..85a593f 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -34,23 +34,35 @@
 #include "fs_mgr_priv.h"
 #include "cryptfs.h"
 
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+static int get_dev_sz(char *fs_blkdev, uint64_t *dev_sz)
 {
-    uint64_t dev_sz;
-    int fd, rc = 0;
+    int fd;
 
-    if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
+    if ((fd = open(fs_blkdev, O_RDONLY)) < 0) {
         PERROR << "Cannot open block device";
         return -1;
     }
 
-    if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
+    if ((ioctl(fd, BLKGETSIZE64, dev_sz)) == -1) {
         PERROR << "Cannot get block device size";
         close(fd);
         return -1;
     }
 
     close(fd);
+    return 0;
+}
+
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+{
+    uint64_t dev_sz;
+    int rc = 0;
+    int status;
+
+    rc = get_dev_sz(fs_blkdev, &dev_sz);
+    if (rc) {
+        return rc;
+    }
 
     /* Format the partition using the calculated length */
     if (crypt_footer) {
@@ -85,9 +97,25 @@
     return rc;
 }
 
-static int format_f2fs(char *fs_blkdev)
+static int format_f2fs(char *fs_blkdev, uint64_t dev_sz, bool crypt_footer)
 {
-    const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
+    int status;
+
+    if (!dev_sz) {
+        int rc = get_dev_sz(fs_blkdev, &dev_sz);
+        if (rc) {
+            return rc;
+        }
+    }
+
+    /* Format the partition using the calculated length */
+    if (crypt_footer) {
+        dev_sz -= CRYPT_FOOTER_OFFSET;
+    }
+
+    std::string size_str = std::to_string(dev_sz / 4096);
+    const char* const args[] = {
+        "/system/bin/make_f2fs", "-f", "-O", "encrypt", fs_blkdev, size_str.c_str(), nullptr};
 
     return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
                                    LOG_KLOG, true, nullptr, nullptr, 0);
@@ -101,7 +129,7 @@
            << " as '" << fstab->fs_type << "'";
 
     if (!strncmp(fstab->fs_type, "f2fs", 4)) {
-        rc = format_f2fs(fstab->blk_device);
+        rc = format_f2fs(fstab->blk_device, fstab->length, crypt_footer);
     } else if (!strncmp(fstab->fs_type, "ext4", 4)) {
         rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
     } else {
diff --git a/healthd/OWNERS b/healthd/OWNERS
new file mode 100644
index 0000000..2375f7c
--- /dev/null
+++ b/healthd/OWNERS
@@ -0,0 +1 @@
+toddpoynor@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 45ee754..0ec348c 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -118,6 +118,8 @@
     required: [
         "e2fsdroid",
         "mke2fs",
+        "sload_f2fs",
+        "make_f2fs",
     ],
     static_executable: true,
     srcs: [
diff --git a/init/Android.mk b/init/Android.mk
index 44300f6..516f1b3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -88,6 +88,8 @@
 LOCAL_REQUIRED_MODULES := \
     e2fsdroid \
     mke2fs \
+    sload_f2fs \
+    make_f2fs \
 
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/OWNERS b/init/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/init/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 21010b0..1febccd 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -436,6 +436,9 @@
 
     selinux_android_restorecon("/sbin/mke2fs_static", 0);
     selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
+
+    selinux_android_restorecon("/sbin/mkfs.f2fs", 0);
+    selinux_android_restorecon("/sbin/sload.f2fs", 0);
 }
 
 // This function sets up SELinux logging to be written to kmsg, to match init's logging.
diff --git a/libappfuse/OWNERS b/libappfuse/OWNERS
new file mode 100644
index 0000000..cd7cb74
--- /dev/null
+++ b/libappfuse/OWNERS
@@ -0,0 +1 @@
+hirono@google.com
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 0b2ce1d..9eaeae8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -229,6 +229,7 @@
 
     srcs: [
         "backtrace_benchmarks.cpp",
+        "backtrace_read_benchmarks.cpp",
     ],
 
     shared_libs: [
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
index 760817b..d110b48 100644
--- a/libbacktrace/BacktracePtrace.h
+++ b/libbacktrace/BacktracePtrace.h
@@ -29,9 +29,9 @@
   BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
   virtual ~BacktracePtrace() {}
 
-  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
 
-  bool ReadWord(uintptr_t ptr, word_t* out_value);
+  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
 };
 
 #endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/OWNERS b/libbacktrace/OWNERS
new file mode 100644
index 0000000..bfeedca
--- /dev/null
+++ b/libbacktrace/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+jmgao@google.com
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 3a38839..56a6c68 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -99,8 +99,7 @@
     // one extra function call appearing in the unwind.
     unwindstack::RegsGetLocal(regs.get());
   } else {
-    regs.reset(
-        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext));
+    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
   }
 
   error_ = BACKTRACE_UNWIND_NO_ERROR;
@@ -109,7 +108,7 @@
 }
 
 UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
-    : BacktracePtrace(pid, tid, map) {}
+    : BacktracePtrace(pid, tid, map), memory_(pid) {}
 
 std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
   return GetMap()->GetFunctionName(pc, offset);
@@ -120,10 +119,13 @@
   if (context == nullptr) {
     regs.reset(unwindstack::Regs::RemoteGet(Tid()));
   } else {
-    regs.reset(
-        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context));
+    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context));
   }
 
   error_ = BACKTRACE_UNWIND_NO_ERROR;
   return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
 }
+
+size_t UnwindStackPtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+  return memory_.Read(addr, buffer, bytes);
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index be9ef63..ee2a706 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -45,6 +45,11 @@
   bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
 
   std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+
+ private:
+  unwindstack::MemoryRemote memory_;
 };
 
 #endif  // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/backtrace_read_benchmarks.cpp b/libbacktrace/backtrace_read_benchmarks.cpp
new file mode 100644
index 0000000..6a688b0
--- /dev/null
+++ b/libbacktrace/backtrace_read_benchmarks.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+
+#include <backtrace/Backtrace.h>
+
+#define AT_COMMON_SIZES Arg(1)->Arg(4)->Arg(8)->Arg(16)->Arg(100)->Arg(200)->Arg(500)->Arg(1024)
+
+static void Attach(pid_t pid) {
+  if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+    perror("Failed to attach");
+    abort();
+  }
+
+  siginfo_t si;
+  // Wait for up to 5 seconds.
+  for (size_t i = 0; i < 5000; i++) {
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+      return;
+    }
+    usleep(1000);
+  }
+  printf("Remote process failed to stop in five seconds.\n");
+  abort();
+}
+
+class ScopedPidReaper {
+ public:
+  ScopedPidReaper(pid_t pid) : pid_(pid) {}
+  ~ScopedPidReaper() {
+    kill(pid_, SIGKILL);
+    waitpid(pid_, nullptr, 0);
+  }
+
+ private:
+  pid_t pid_;
+};
+
+static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
+  struct iovec dst_iov = {
+      .iov_base = dst, .iov_len = len,
+  };
+
+  struct iovec src_iov = {
+      .iov_base = reinterpret_cast<void*>(remote_src), .iov_len = len,
+  };
+
+  ssize_t rc = process_vm_readv(pid, &dst_iov, 1, &src_iov, 1, 0);
+  return rc == -1 ? 0 : rc;
+}
+
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+  if (*value == -1 && errno) {
+    return false;
+  }
+  return true;
+}
+
+static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+  size_t bytes_read = 0;
+  long data;
+  for (size_t i = 0; i < bytes / sizeof(long); i++) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, sizeof(long));
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+    addr += sizeof(long);
+    bytes_read += sizeof(long);
+  }
+
+  size_t left_over = bytes & (sizeof(long) - 1);
+  if (left_over) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+}
+
+static void CreateRemoteProcess(size_t size, void** map, pid_t* pid) {
+  *map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (*map == MAP_FAILED) {
+    perror("Can't allocate memory");
+    abort();
+  }
+  memset(*map, 0xaa, size);
+
+  if ((*pid = fork()) == 0) {
+    for (volatile int i = 0;; i++)
+      ;
+    exit(1);
+  }
+  if (*pid < 0) {
+    perror("Failed to fork");
+    abort();
+  }
+  Attach(*pid);
+  // Don't need this map in the current process any more.
+  munmap(*map, size);
+}
+
+static void BM_read_with_ptrace(benchmark::State& state) {
+  void* map;
+  pid_t pid;
+  CreateRemoteProcess(state.range(0), &map, &pid);
+  ScopedPidReaper reap(pid);
+
+  std::vector<uint8_t> read_buffer(state.range(0));
+  uint64_t addr = reinterpret_cast<uint64_t>(map);
+  while (state.KeepRunning()) {
+    if (PtraceRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+      printf("Unexpected bad read.\n");
+      abort();
+    }
+  }
+  ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_ptrace)->AT_COMMON_SIZES;
+
+static void BM_read_with_process_vm_read(benchmark::State& state) {
+  void* map;
+  pid_t pid;
+  CreateRemoteProcess(state.range(0), &map, &pid);
+  ScopedPidReaper reap(pid);
+
+  std::vector<uint8_t> read_buffer(state.range(0));
+  uint64_t addr = reinterpret_cast<uint64_t>(map);
+  while (state.KeepRunning()) {
+    if (ProcessVmRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+      printf("Unexpected bad read.\n");
+      abort();
+    }
+  }
+  ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_process_vm_read)->AT_COMMON_SIZES;
+
+static void BM_read_with_backtrace_object(benchmark::State& state) {
+  void* map;
+  pid_t pid;
+  CreateRemoteProcess(state.range(0), &map, &pid);
+  ScopedPidReaper reap(pid);
+
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+  if (backtrace.get() == nullptr) {
+    printf("Failed to create backtrace.\n");
+    abort();
+  }
+
+  uint64_t addr = reinterpret_cast<uint64_t>(map);
+  std::vector<uint8_t> read_buffer(state.range(0));
+  while (state.KeepRunning()) {
+    if (backtrace->Read(addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+      printf("Unexpected bad read.\n");
+      abort();
+    }
+  }
+  ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_backtrace_object)->AT_COMMON_SIZES;
diff --git a/liblog/OWNERS b/liblog/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/liblog/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/libmemtrack/OWNERS b/libmemtrack/OWNERS
new file mode 100644
index 0000000..70b375f
--- /dev/null
+++ b/libmemtrack/OWNERS
@@ -0,0 +1 @@
+ccross@google.com
diff --git a/libmemunreachable/OWNERS b/libmemunreachable/OWNERS
new file mode 100644
index 0000000..9127a93
--- /dev/null
+++ b/libmemunreachable/OWNERS
@@ -0,0 +1,2 @@
+ccross@google.com
+cferris@google.com
diff --git a/libmetricslogger/OWNERS b/libmetricslogger/OWNERS
new file mode 100644
index 0000000..7fe0443
--- /dev/null
+++ b/libmetricslogger/OWNERS
@@ -0,0 +1 @@
+jhawkins@google.com
diff --git a/libnativebridge/OWNERS b/libnativebridge/OWNERS
new file mode 100644
index 0000000..f2cc942
--- /dev/null
+++ b/libnativebridge/OWNERS
@@ -0,0 +1 @@
+dimitry@google.com
diff --git a/libnativeloader/OWNERS b/libnativeloader/OWNERS
new file mode 100644
index 0000000..f2cc942
--- /dev/null
+++ b/libnativeloader/OWNERS
@@ -0,0 +1 @@
+dimitry@google.com
diff --git a/libnetutils/OWNERS b/libnetutils/OWNERS
new file mode 100644
index 0000000..e3ec950
--- /dev/null
+++ b/libnetutils/OWNERS
@@ -0,0 +1,3 @@
+# TODO: should this be in system/netd?
+ek@google.com
+lorenzo@google.com
diff --git a/libprocinfo/OWNERS b/libprocinfo/OWNERS
new file mode 100644
index 0000000..a70cc57
--- /dev/null
+++ b/libprocinfo/OWNERS
@@ -0,0 +1 @@
+jmgao@google.com
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 74930d6..4125b12 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -60,6 +60,10 @@
         "Maps.cpp",
         "Memory.cpp",
         "Regs.cpp",
+        "RegsArm.cpp",
+        "RegsArm64.cpp",
+        "RegsX86.cpp",
+        "RegsX86_64.cpp",
         "Unwinder.cpp",
         "Symbols.cpp",
     ],
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index fed3e0e..6b0646f 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -23,11 +23,11 @@
 
 #include <unwindstack/Log.h>
 #include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 #include "Check.h"
-#include "Machine.h"
+#include "MachineArm.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 5f307ed..025429f 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -31,7 +31,6 @@
 #include <unwindstack/Regs.h>
 
 #include "ElfInterfaceArm.h"
-#include "Machine.h"
 #include "Symbols.h"
 
 namespace unwindstack {
@@ -183,18 +182,15 @@
       return nullptr;
     }
 
-    if (e_machine != EM_ARM && e_machine != EM_386) {
-      // Unsupported.
-      ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
-      return nullptr;
-    }
-
     machine_type_ = e_machine;
     if (e_machine == EM_ARM) {
+      arch_ = ARCH_ARM;
       interface.reset(new ElfInterfaceArm(memory));
     } else if (e_machine == EM_386) {
+      arch_ = ARCH_X86;
       interface.reset(new ElfInterface32(memory));
     } else {
+      // Unsupported.
       ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
       return nullptr;
     }
@@ -203,12 +199,17 @@
     if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
       return nullptr;
     }
-    if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
+
+    machine_type_ = e_machine;
+    if (e_machine == EM_AARCH64) {
+      arch_ = ARCH_ARM64;
+    } else if (e_machine == EM_X86_64) {
+      arch_ = ARCH_X86_64;
+    } else {
       // Unsupported.
       ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
       return nullptr;
     }
-    machine_type_ = e_machine;
     interface.reset(new ElfInterface64(memory));
   }
 
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 170a5cd..9841e24 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -18,11 +18,11 @@
 #include <stdint.h>
 
 #include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 #include "ElfInterfaceArm.h"
-#include "Machine.h"
+#include "MachineArm.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/Machine.h b/libunwindstack/Machine.h
deleted file mode 100644
index 1fb9309..0000000
--- a/libunwindstack/Machine.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_MACHINE_H
-#define _LIBUNWINDSTACK_MACHINE_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum ArmReg : uint16_t {
-  ARM_REG_R0 = 0,
-  ARM_REG_R1,
-  ARM_REG_R2,
-  ARM_REG_R3,
-  ARM_REG_R4,
-  ARM_REG_R5,
-  ARM_REG_R6,
-  ARM_REG_R7,
-  ARM_REG_R8,
-  ARM_REG_R9,
-  ARM_REG_R10,
-  ARM_REG_R11,
-  ARM_REG_R12,
-  ARM_REG_R13,
-  ARM_REG_R14,
-  ARM_REG_R15,
-  ARM_REG_LAST,
-
-  ARM_REG_SP = ARM_REG_R13,
-  ARM_REG_LR = ARM_REG_R14,
-  ARM_REG_PC = ARM_REG_R15,
-};
-
-enum Arm64Reg : uint16_t {
-  ARM64_REG_R0 = 0,
-  ARM64_REG_R1,
-  ARM64_REG_R2,
-  ARM64_REG_R3,
-  ARM64_REG_R4,
-  ARM64_REG_R5,
-  ARM64_REG_R6,
-  ARM64_REG_R7,
-  ARM64_REG_R8,
-  ARM64_REG_R9,
-  ARM64_REG_R10,
-  ARM64_REG_R11,
-  ARM64_REG_R12,
-  ARM64_REG_R13,
-  ARM64_REG_R14,
-  ARM64_REG_R15,
-  ARM64_REG_R16,
-  ARM64_REG_R17,
-  ARM64_REG_R18,
-  ARM64_REG_R19,
-  ARM64_REG_R20,
-  ARM64_REG_R21,
-  ARM64_REG_R22,
-  ARM64_REG_R23,
-  ARM64_REG_R24,
-  ARM64_REG_R25,
-  ARM64_REG_R26,
-  ARM64_REG_R27,
-  ARM64_REG_R28,
-  ARM64_REG_R29,
-  ARM64_REG_R30,
-  ARM64_REG_R31,
-  ARM64_REG_PC,
-  ARM64_REG_LAST,
-
-  ARM64_REG_SP = ARM64_REG_R31,
-  ARM64_REG_LR = ARM64_REG_R30,
-};
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86Reg : uint16_t {
-  X86_REG_EAX = 0,
-  X86_REG_ECX = 1,
-  X86_REG_EDX = 2,
-  X86_REG_EBX = 3,
-  X86_REG_ESP = 4,
-  X86_REG_EBP = 5,
-  X86_REG_ESI = 6,
-  X86_REG_EDI = 7,
-  X86_REG_EIP = 8,
-  X86_REG_EFL = 9,
-  X86_REG_CS = 10,
-  X86_REG_SS = 11,
-  X86_REG_DS = 12,
-  X86_REG_ES = 13,
-  X86_REG_FS = 14,
-  X86_REG_GS = 15,
-  X86_REG_LAST,
-
-  X86_REG_SP = X86_REG_ESP,
-  X86_REG_PC = X86_REG_EIP,
-};
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86_64Reg : uint16_t {
-  X86_64_REG_RAX = 0,
-  X86_64_REG_RDX = 1,
-  X86_64_REG_RCX = 2,
-  X86_64_REG_RBX = 3,
-  X86_64_REG_RSI = 4,
-  X86_64_REG_RDI = 5,
-  X86_64_REG_RBP = 6,
-  X86_64_REG_RSP = 7,
-  X86_64_REG_R8 = 8,
-  X86_64_REG_R9 = 9,
-  X86_64_REG_R10 = 10,
-  X86_64_REG_R11 = 11,
-  X86_64_REG_R12 = 12,
-  X86_64_REG_R13 = 13,
-  X86_64_REG_R14 = 14,
-  X86_64_REG_R15 = 15,
-  X86_64_REG_RIP = 16,
-  X86_64_REG_LAST,
-
-  X86_64_REG_SP = X86_64_REG_RSP,
-  X86_64_REG_PC = X86_64_REG_RIP,
-};
-
-}  // namespace unwindstack
-
-#endif  // _LIBUNWINDSTACK_MACHINE_H
diff --git a/libunwindstack/MachineArm.h b/libunwindstack/MachineArm.h
new file mode 100644
index 0000000..3f902b1
--- /dev/null
+++ b/libunwindstack/MachineArm.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_ARM_H
+#define _LIBUNWINDSTACK_MACHINE_ARM_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum ArmReg : uint16_t {
+  ARM_REG_R0 = 0,
+  ARM_REG_R1,
+  ARM_REG_R2,
+  ARM_REG_R3,
+  ARM_REG_R4,
+  ARM_REG_R5,
+  ARM_REG_R6,
+  ARM_REG_R7,
+  ARM_REG_R8,
+  ARM_REG_R9,
+  ARM_REG_R10,
+  ARM_REG_R11,
+  ARM_REG_R12,
+  ARM_REG_R13,
+  ARM_REG_R14,
+  ARM_REG_R15,
+  ARM_REG_LAST,
+
+  ARM_REG_SP = ARM_REG_R13,
+  ARM_REG_LR = ARM_REG_R14,
+  ARM_REG_PC = ARM_REG_R15,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_ARM_H
diff --git a/libunwindstack/MachineArm64.h b/libunwindstack/MachineArm64.h
new file mode 100644
index 0000000..e8b778b
--- /dev/null
+++ b/libunwindstack/MachineArm64.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_ARM64_H
+#define _LIBUNWINDSTACK_MACHINE_ARM64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum Arm64Reg : uint16_t {
+  ARM64_REG_R0 = 0,
+  ARM64_REG_R1,
+  ARM64_REG_R2,
+  ARM64_REG_R3,
+  ARM64_REG_R4,
+  ARM64_REG_R5,
+  ARM64_REG_R6,
+  ARM64_REG_R7,
+  ARM64_REG_R8,
+  ARM64_REG_R9,
+  ARM64_REG_R10,
+  ARM64_REG_R11,
+  ARM64_REG_R12,
+  ARM64_REG_R13,
+  ARM64_REG_R14,
+  ARM64_REG_R15,
+  ARM64_REG_R16,
+  ARM64_REG_R17,
+  ARM64_REG_R18,
+  ARM64_REG_R19,
+  ARM64_REG_R20,
+  ARM64_REG_R21,
+  ARM64_REG_R22,
+  ARM64_REG_R23,
+  ARM64_REG_R24,
+  ARM64_REG_R25,
+  ARM64_REG_R26,
+  ARM64_REG_R27,
+  ARM64_REG_R28,
+  ARM64_REG_R29,
+  ARM64_REG_R30,
+  ARM64_REG_R31,
+  ARM64_REG_PC,
+  ARM64_REG_LAST,
+
+  ARM64_REG_SP = ARM64_REG_R31,
+  ARM64_REG_LR = ARM64_REG_R30,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_ARM64_H
diff --git a/libunwindstack/MachineX86.h b/libunwindstack/MachineX86.h
new file mode 100644
index 0000000..02adb98
--- /dev/null
+++ b/libunwindstack/MachineX86.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_X86_H
+#define _LIBUNWINDSTACK_MACHINE_X86_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
+enum X86Reg : uint16_t {
+  X86_REG_EAX = 0,
+  X86_REG_ECX = 1,
+  X86_REG_EDX = 2,
+  X86_REG_EBX = 3,
+  X86_REG_ESP = 4,
+  X86_REG_EBP = 5,
+  X86_REG_ESI = 6,
+  X86_REG_EDI = 7,
+  X86_REG_EIP = 8,
+  X86_REG_EFL = 9,
+  X86_REG_CS = 10,
+  X86_REG_SS = 11,
+  X86_REG_DS = 12,
+  X86_REG_ES = 13,
+  X86_REG_FS = 14,
+  X86_REG_GS = 15,
+  X86_REG_LAST,
+
+  X86_REG_SP = X86_REG_ESP,
+  X86_REG_PC = X86_REG_EIP,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_X86_H
diff --git a/libunwindstack/MachineX86_64.h b/libunwindstack/MachineX86_64.h
new file mode 100644
index 0000000..af33fea
--- /dev/null
+++ b/libunwindstack/MachineX86_64.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_X86_64_H
+#define _LIBUNWINDSTACK_MACHINE_X86_64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
+enum X86_64Reg : uint16_t {
+  X86_64_REG_RAX = 0,
+  X86_64_REG_RDX = 1,
+  X86_64_REG_RCX = 2,
+  X86_64_REG_RBX = 3,
+  X86_64_REG_RSI = 4,
+  X86_64_REG_RDI = 5,
+  X86_64_REG_RBP = 6,
+  X86_64_REG_RSP = 7,
+  X86_64_REG_R8 = 8,
+  X86_64_REG_R9 = 9,
+  X86_64_REG_R10 = 10,
+  X86_64_REG_R11 = 11,
+  X86_64_REG_R12 = 12,
+  X86_64_REG_R13 = 13,
+  X86_64_REG_R14 = 14,
+  X86_64_REG_R15 = 15,
+  X86_64_REG_RIP = 16,
+  X86_64_REG_LAST,
+
+  X86_64_REG_SP = X86_64_REG_RSP,
+  X86_64_REG_PC = X86_64_REG_RIP,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_X86_64_H
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index b1b39a0..1f3c6c3 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -32,7 +32,9 @@
 
 #include "Check.h"
 
-static size_t ProcessVmRead(pid_t pid, void* dst, uint64_t remote_src, size_t len) {
+namespace unwindstack {
+
+static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
   struct iovec dst_iov = {
       .iov_base = dst,
       .iov_len = len,
@@ -82,7 +84,59 @@
   return rc == -1 ? 0 : rc;
 }
 
-namespace unwindstack {
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+  if (*value == -1 && errno) {
+    return false;
+  }
+  return true;
+}
+
+static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+  // Make sure that there is no overflow.
+  uint64_t max_size;
+  if (__builtin_add_overflow(addr, bytes, &max_size)) {
+    return 0;
+  }
+
+  size_t bytes_read = 0;
+  long data;
+  size_t align_bytes = addr & (sizeof(long) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
+      return 0;
+    }
+    size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
+    memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
+  }
+
+  for (size_t i = 0; i < bytes / sizeof(long); i++) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, sizeof(long));
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+    addr += sizeof(long);
+    bytes_read += sizeof(long);
+  }
+
+  size_t left_over = bytes & (sizeof(long) - 1);
+  if (left_over) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+}
 
 bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
   size_t rc = Read(addr, dst, size);
@@ -198,72 +252,39 @@
   return actual_len;
 }
 
-static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
-  // ptrace() returns -1 and sets errno when the operation fails.
-  // To disambiguate -1 from a valid result, we clear errno beforehand.
-  errno = 0;
-  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
-  if (*value == -1 && errno) {
-    return false;
-  }
-  return true;
-}
-
-static size_t ReadWithPtrace(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
-  // Make sure that there is no overflow.
-  uint64_t max_size;
-  if (__builtin_add_overflow(addr, bytes, &max_size)) {
-    return 0;
-  }
-
-  size_t bytes_read = 0;
-  long data;
-  size_t align_bytes = addr & (sizeof(long) - 1);
-  if (align_bytes != 0) {
-    if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
-      return 0;
-    }
-    size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
-    memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
-    addr += copy_bytes;
-    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
-    bytes -= copy_bytes;
-    bytes_read += copy_bytes;
-  }
-
-  for (size_t i = 0; i < bytes / sizeof(long); i++) {
-    if (!PtraceReadLong(pid, addr, &data)) {
-      return bytes_read;
-    }
-    memcpy(dst, &data, sizeof(long));
-    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
-    addr += sizeof(long);
-    bytes_read += sizeof(long);
-  }
-
-  size_t left_over = bytes & (sizeof(long) - 1);
-  if (left_over) {
-    if (!PtraceReadLong(pid, addr, &data)) {
-      return bytes_read;
-    }
-    memcpy(dst, &data, left_over);
-    bytes_read += left_over;
-  }
-  return bytes_read;
-}
-
 size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
 #if !defined(__LP64__)
-  // Cannot read an address greater than 32 bits.
+  // Cannot read an address greater than 32 bits in a 32 bit context.
   if (addr > UINT32_MAX) {
     return 0;
   }
 #endif
-  return ReadWithPtrace(pid_, addr, dst, size);
+
+  size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
+      reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
+  if (read_func != nullptr) {
+    return read_func(pid_, addr, dst, size);
+  } else {
+    // Prefer process_vm_read, try it first. If it doesn't work, use the
+    // ptrace function. If at least one of them returns at least some data,
+    // set that as the permanent function to use.
+    // This assumes that if process_vm_read works once, it will continue
+    // to work.
+    size_t bytes = ProcessVmRead(pid_, addr, dst, size);
+    if (bytes > 0) {
+      read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
+      return bytes;
+    }
+    bytes = PtraceRead(pid_, addr, dst, size);
+    if (bytes > 0) {
+      read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
+    }
+    return bytes;
+  }
 }
 
 size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
-  return ProcessVmRead(getpid(), dst, addr, size);
+  return ProcessVmRead(getpid(), addr, dst, size);
 }
 
 MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
diff --git a/libunwindstack/OWNERS b/libunwindstack/OWNERS
new file mode 100644
index 0000000..6f7e4a3
--- /dev/null
+++ b/libunwindstack/OWNERS
@@ -0,0 +1 @@
+cferris@google.com
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 28a77dc..29dbf9d 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <elf.h>
 #include <stdint.h>
 #include <sys/ptrace.h>
 #include <sys/uio.h>
@@ -23,315 +22,21 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
-#include "Check.h"
-#include "Machine.h"
-#include "Ucontext.h"
-#include "User.h"
+#include "UserArm.h"
+#include "UserArm64.h"
+#include "UserX86.h"
+#include "UserX86_64.h"
 
 namespace unwindstack {
 
-RegsArm::RegsArm()
-    : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
-
-uint32_t RegsArm::MachineType() {
-  return EM_ARM;
-}
-
-uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  uint64_t load_bias = elf->GetLoadBias();
-  if (rel_pc < load_bias) {
-    return rel_pc;
-  }
-  uint64_t adjusted_rel_pc = rel_pc - load_bias;
-
-  if (adjusted_rel_pc < 5) {
-    return rel_pc;
-  }
-
-  if (adjusted_rel_pc & 1) {
-    // This is a thumb instruction, it could be 2 or 4 bytes.
-    uint32_t value;
-    if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
-        (value & 0xe000f000) != 0xe000f000) {
-      return rel_pc - 2;
-    }
-  }
-  return rel_pc - 4;
-}
-
-void RegsArm::SetFromRaw() {
-  set_pc(regs_[ARM_REG_PC]);
-  set_sp(regs_[ARM_REG_SP]);
-}
-
-bool RegsArm::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[ARM_REG_LR]) {
-    return false;
-  }
-
-  set_pc(regs_[ARM_REG_LR]);
-  return true;
-}
-
-void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("r0", regs_[ARM_REG_R0]);
-  fn("r1", regs_[ARM_REG_R1]);
-  fn("r2", regs_[ARM_REG_R2]);
-  fn("r3", regs_[ARM_REG_R3]);
-  fn("r4", regs_[ARM_REG_R4]);
-  fn("r5", regs_[ARM_REG_R5]);
-  fn("r6", regs_[ARM_REG_R6]);
-  fn("r7", regs_[ARM_REG_R7]);
-  fn("r8", regs_[ARM_REG_R8]);
-  fn("r9", regs_[ARM_REG_R9]);
-  fn("r10", regs_[ARM_REG_R10]);
-  fn("r11", regs_[ARM_REG_R11]);
-  fn("ip", regs_[ARM_REG_R12]);
-  fn("sp", regs_[ARM_REG_SP]);
-  fn("lr", regs_[ARM_REG_LR]);
-  fn("pc", regs_[ARM_REG_PC]);
-}
-
-RegsArm64::RegsArm64()
-    : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
-
-uint32_t RegsArm64::MachineType() {
-  return EM_AARCH64;
-}
-
-uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc < 4) {
-    return rel_pc;
-  }
-  return rel_pc - 4;
-}
-
-void RegsArm64::SetFromRaw() {
-  set_pc(regs_[ARM64_REG_PC]);
-  set_sp(regs_[ARM64_REG_SP]);
-}
-
-bool RegsArm64::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[ARM64_REG_LR]) {
-    return false;
-  }
-
-  set_pc(regs_[ARM64_REG_LR]);
-  return true;
-}
-
-void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("x0", regs_[ARM64_REG_R0]);
-  fn("x1", regs_[ARM64_REG_R1]);
-  fn("x2", regs_[ARM64_REG_R2]);
-  fn("x3", regs_[ARM64_REG_R3]);
-  fn("x4", regs_[ARM64_REG_R4]);
-  fn("x5", regs_[ARM64_REG_R5]);
-  fn("x6", regs_[ARM64_REG_R6]);
-  fn("x7", regs_[ARM64_REG_R7]);
-  fn("x8", regs_[ARM64_REG_R8]);
-  fn("x9", regs_[ARM64_REG_R9]);
-  fn("x10", regs_[ARM64_REG_R10]);
-  fn("x11", regs_[ARM64_REG_R11]);
-  fn("x12", regs_[ARM64_REG_R12]);
-  fn("x13", regs_[ARM64_REG_R13]);
-  fn("x14", regs_[ARM64_REG_R14]);
-  fn("x15", regs_[ARM64_REG_R15]);
-  fn("x16", regs_[ARM64_REG_R16]);
-  fn("x17", regs_[ARM64_REG_R17]);
-  fn("x18", regs_[ARM64_REG_R18]);
-  fn("x19", regs_[ARM64_REG_R19]);
-  fn("x20", regs_[ARM64_REG_R20]);
-  fn("x21", regs_[ARM64_REG_R21]);
-  fn("x22", regs_[ARM64_REG_R22]);
-  fn("x23", regs_[ARM64_REG_R23]);
-  fn("x24", regs_[ARM64_REG_R24]);
-  fn("x25", regs_[ARM64_REG_R25]);
-  fn("x26", regs_[ARM64_REG_R26]);
-  fn("x27", regs_[ARM64_REG_R27]);
-  fn("x28", regs_[ARM64_REG_R28]);
-  fn("x29", regs_[ARM64_REG_R29]);
-  fn("sp", regs_[ARM64_REG_SP]);
-  fn("lr", regs_[ARM64_REG_LR]);
-  fn("pc", regs_[ARM64_REG_PC]);
-}
-
-RegsX86::RegsX86()
-    : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
-
-uint32_t RegsX86::MachineType() {
-  return EM_386;
-}
-
-uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc == 0) {
-    return 0;
-  }
-  return rel_pc - 1;
-}
-
-void RegsX86::SetFromRaw() {
-  set_pc(regs_[X86_REG_PC]);
-  set_sp(regs_[X86_REG_SP]);
-}
-
-bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
-  // Attempt to get the return address from the top of the stack.
-  uint32_t new_pc;
-  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
-    return false;
-  }
-
-  set_pc(new_pc);
-  return true;
-}
-
-void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("eax", regs_[X86_REG_EAX]);
-  fn("ebx", regs_[X86_REG_EBX]);
-  fn("ecx", regs_[X86_REG_ECX]);
-  fn("edx", regs_[X86_REG_EDX]);
-  fn("ebp", regs_[X86_REG_EBP]);
-  fn("edi", regs_[X86_REG_EDI]);
-  fn("esi", regs_[X86_REG_ESI]);
-  fn("esp", regs_[X86_REG_ESP]);
-  fn("eip", regs_[X86_REG_EIP]);
-}
-
-RegsX86_64::RegsX86_64()
-    : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
-
-uint32_t RegsX86_64::MachineType() {
-  return EM_X86_64;
-}
-
-uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc == 0) {
-    return 0;
-  }
-
-  return rel_pc - 1;
-}
-
-void RegsX86_64::SetFromRaw() {
-  set_pc(regs_[X86_64_REG_PC]);
-  set_sp(regs_[X86_64_REG_SP]);
-}
-
-bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
-  // Attempt to get the return address from the top of the stack.
-  uint64_t new_pc;
-  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
-    return false;
-  }
-
-  set_pc(new_pc);
-  return true;
-}
-
-void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
-  fn("rax", regs_[X86_64_REG_RAX]);
-  fn("rbx", regs_[X86_64_REG_RBX]);
-  fn("rcx", regs_[X86_64_REG_RCX]);
-  fn("rdx", regs_[X86_64_REG_RDX]);
-  fn("r8", regs_[X86_64_REG_R8]);
-  fn("r9", regs_[X86_64_REG_R9]);
-  fn("r10", regs_[X86_64_REG_R10]);
-  fn("r11", regs_[X86_64_REG_R11]);
-  fn("r12", regs_[X86_64_REG_R12]);
-  fn("r13", regs_[X86_64_REG_R13]);
-  fn("r14", regs_[X86_64_REG_R14]);
-  fn("r15", regs_[X86_64_REG_R15]);
-  fn("rdi", regs_[X86_64_REG_RDI]);
-  fn("rsi", regs_[X86_64_REG_RSI]);
-  fn("rbp", regs_[X86_64_REG_RBP]);
-  fn("rsp", regs_[X86_64_REG_RSP]);
-  fn("rip", regs_[X86_64_REG_RIP]);
-}
-
-static Regs* ReadArm(void* remote_data) {
-  arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
-
-  RegsArm* regs = new RegsArm();
-  memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* ReadArm64(void* remote_data) {
-  arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
-
-  RegsArm64* regs = new RegsArm64();
-  memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
-  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
-  reg_data[ARM64_REG_PC] = user->pc;
-  reg_data[ARM64_REG_SP] = user->sp;
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* ReadX86(void* remote_data) {
-  x86_user_regs* user = reinterpret_cast<x86_user_regs*>(remote_data);
-
-  RegsX86* regs = new RegsX86();
-  (*regs)[X86_REG_EAX] = user->eax;
-  (*regs)[X86_REG_EBX] = user->ebx;
-  (*regs)[X86_REG_ECX] = user->ecx;
-  (*regs)[X86_REG_EDX] = user->edx;
-  (*regs)[X86_REG_EBP] = user->ebp;
-  (*regs)[X86_REG_EDI] = user->edi;
-  (*regs)[X86_REG_ESI] = user->esi;
-  (*regs)[X86_REG_ESP] = user->esp;
-  (*regs)[X86_REG_EIP] = user->eip;
-
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* ReadX86_64(void* remote_data) {
-  x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
-
-  RegsX86_64* regs = new RegsX86_64();
-  (*regs)[X86_64_REG_RAX] = user->rax;
-  (*regs)[X86_64_REG_RBX] = user->rbx;
-  (*regs)[X86_64_REG_RCX] = user->rcx;
-  (*regs)[X86_64_REG_RDX] = user->rdx;
-  (*regs)[X86_64_REG_R8] = user->r8;
-  (*regs)[X86_64_REG_R9] = user->r9;
-  (*regs)[X86_64_REG_R10] = user->r10;
-  (*regs)[X86_64_REG_R11] = user->r11;
-  (*regs)[X86_64_REG_R12] = user->r12;
-  (*regs)[X86_64_REG_R13] = user->r13;
-  (*regs)[X86_64_REG_R14] = user->r14;
-  (*regs)[X86_64_REG_R15] = user->r15;
-  (*regs)[X86_64_REG_RDI] = user->rdi;
-  (*regs)[X86_64_REG_RSI] = user->rsi;
-  (*regs)[X86_64_REG_RBP] = user->rbp;
-  (*regs)[X86_64_REG_RSP] = user->rsp;
-  (*regs)[X86_64_REG_RIP] = user->rip;
-
-  regs->SetFromRaw();
-  return regs;
-}
+// The largest user structure.
+constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
 
 // This function assumes that reg_data is already aligned to a 64 bit value.
 // If not this could crash with an unaligned access.
@@ -348,106 +53,42 @@
 
   switch (io.iov_len) {
   case sizeof(x86_user_regs):
-    return ReadX86(buffer.data());
+    return RegsX86::Read(buffer.data());
   case sizeof(x86_64_user_regs):
-    return ReadX86_64(buffer.data());
+    return RegsX86_64::Read(buffer.data());
   case sizeof(arm_user_regs):
-    return ReadArm(buffer.data());
+    return RegsArm::Read(buffer.data());
   case sizeof(arm64_user_regs):
-    return ReadArm64(buffer.data());
+    return RegsArm64::Read(buffer.data());
   }
   return nullptr;
 }
 
-static Regs* CreateFromArmUcontext(void* ucontext) {
-  arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
-
-  RegsArm* regs = new RegsArm();
-  memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
-  regs->SetFromRaw();
-  return regs;
-}
-
-static Regs* CreateFromArm64Ucontext(void* ucontext) {
-  arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
-
-  RegsArm64* regs = new RegsArm64();
-  memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
-  regs->SetFromRaw();
-  return regs;
-}
-
-void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
-  // Put the registers in the expected order.
-  regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
-  regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
-  regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
-  regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
-  regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
-  regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
-  regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
-  regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
-  regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
-  SetFromRaw();
-}
-
-static Regs* CreateFromX86Ucontext(void* ucontext) {
-  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
-
-  RegsX86* regs = new RegsX86();
-  regs->SetFromUcontext(x86_ucontext);
-  return regs;
-}
-
-void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
-  // R8-R15
-  memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
-
-  // Rest of the registers.
-  regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
-  regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
-  regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
-  regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
-  regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
-  regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
-  regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
-  regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
-  regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
-
-  SetFromRaw();
-}
-
-static Regs* CreateFromX86_64Ucontext(void* ucontext) {
-  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
-
-  RegsX86_64* regs = new RegsX86_64();
-  regs->SetFromUcontext(x86_64_ucontext);
-  return regs;
-}
-
-Regs* Regs::CreateFromUcontext(uint32_t machine_type, void* ucontext) {
-  switch (machine_type) {
-    case EM_386:
-      return CreateFromX86Ucontext(ucontext);
-    case EM_X86_64:
-      return CreateFromX86_64Ucontext(ucontext);
-    case EM_ARM:
-      return CreateFromArmUcontext(ucontext);
-    case EM_AARCH64:
-      return CreateFromArm64Ucontext(ucontext);
+Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
+  switch (arch) {
+    case ARCH_X86:
+      return RegsX86::CreateFromUcontext(ucontext);
+    case ARCH_X86_64:
+      return RegsX86_64::CreateFromUcontext(ucontext);
+    case ARCH_ARM:
+      return RegsArm::CreateFromUcontext(ucontext);
+    case ARCH_ARM64:
+      return RegsArm64::CreateFromUcontext(ucontext);
+    case ARCH_UNKNOWN:
+    default:
+      return nullptr;
   }
-  return nullptr;
 }
 
-uint32_t Regs::CurrentMachineType() {
+ArchEnum Regs::CurrentArch() {
 #if defined(__arm__)
-  return EM_ARM;
+  return ARCH_ARM;
 #elif defined(__aarch64__)
-  return EM_AARCH64;
+  return ARCH_ARM64;
 #elif defined(__i386__)
-  return EM_386;
+  return ARCH_X86;
 #elif defined(__x86_64__)
-  return EM_X86_64;
+  return ARCH_X86_64;
 #else
   abort();
 #endif
@@ -469,192 +110,4 @@
   return regs;
 }
 
-bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint32_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
-    return false;
-  }
-
-  uint64_t offset = 0;
-  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
-    // non-RT sigreturn call.
-    // __restore:
-    //
-    // Form 1 (arm):
-    // 0x77 0x70              mov r7, #0x77
-    // 0xa0 0xe3              svc 0x00000000
-    //
-    // Form 2 (arm):
-    // 0x77 0x00 0x90 0xef    svc 0x00900077
-    //
-    // Form 3 (thumb):
-    // 0x77 0x27              movs r7, #77
-    // 0x00 0xdf              svc 0
-    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
-      return false;
-    }
-    if (data == 0x5ac3c35a) {
-      // SP + uc_mcontext offset + r0 offset.
-      offset = sp() + 0x14 + 0xc;
-    } else {
-      // SP + r0 offset
-      offset = sp() + 0xc;
-    }
-  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
-    // RT sigreturn call.
-    // __restore_rt:
-    //
-    // Form 1 (arm):
-    // 0xad 0x70      mov r7, #0xad
-    // 0xa0 0xe3      svc 0x00000000
-    //
-    // Form 2 (arm):
-    // 0xad 0x00 0x90 0xef    svc 0x009000ad
-    //
-    // Form 3 (thumb):
-    // 0xad 0x27              movs r7, #ad
-    // 0x00 0xdf              svc 0
-    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
-      return false;
-    }
-    if (data == sp() + 8) {
-      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
-      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
-    } else {
-      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
-      offset = sp() + 0x80 + 0x14 + 0xc;
-    }
-  }
-  if (offset == 0) {
-    return false;
-  }
-
-  if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
-    return false;
-  }
-  SetFromRaw();
-  return true;
-}
-
-bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint64_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
-    return false;
-  }
-
-  // Look for the kernel sigreturn function.
-  // __kernel_rt_sigreturn:
-  // 0xd2801168     mov x8, #0x8b
-  // 0xd4000001     svc #0x0
-  if (data != 0xd4000001d2801168ULL) {
-    return false;
-  }
-
-  // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
-  if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
-                                 sizeof(uint64_t) * ARM64_REG_LAST)) {
-    return false;
-  }
-
-  SetFromRaw();
-  return true;
-}
-
-bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint64_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
-    return false;
-  }
-
-  if (data == 0x80cd00000077b858ULL) {
-    // Without SA_SIGINFO set, the return sequence is:
-    //
-    //   __restore:
-    //   0x58                            pop %eax
-    //   0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
-    //   0xcd 0x80                       int 0x80
-    //
-    // SP points at arguments:
-    //   int signum
-    //   struct sigcontext (same format as mcontext)
-    struct x86_mcontext_t context;
-    if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
-      return false;
-    }
-    regs_[X86_REG_EBP] = context.ebp;
-    regs_[X86_REG_ESP] = context.esp;
-    regs_[X86_REG_EBX] = context.ebx;
-    regs_[X86_REG_EDX] = context.edx;
-    regs_[X86_REG_ECX] = context.ecx;
-    regs_[X86_REG_EAX] = context.eax;
-    regs_[X86_REG_EIP] = context.eip;
-    SetFromRaw();
-    return true;
-  } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
-    // With SA_SIGINFO set, the return sequence is:
-    //
-    //   __restore_rt:
-    //   0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
-    //   0xcd 0x80                       int 0x80
-    //
-    // SP points at arguments:
-    //   int signum
-    //   siginfo*
-    //   ucontext*
-
-    // Get the location of the sigcontext data.
-    uint32_t ptr;
-    if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
-      return false;
-    }
-    // Only read the portion of the data structure we care about.
-    x86_ucontext_t x86_ucontext;
-    if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
-      return false;
-    }
-    SetFromUcontext(&x86_ucontext);
-    return true;
-  }
-  return false;
-}
-
-bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
-  uint64_t data;
-  Memory* elf_memory = elf->memory();
-  // Read from elf memory since it is usually more expensive to read from
-  // process memory.
-  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
-    return false;
-  }
-
-  uint16_t data2;
-  if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
-    return false;
-  }
-
-  // __restore_rt:
-  // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
-  // 0x0f 0x05                            syscall
-  // 0x0f                                 nopl 0x0($rax)
-
-  // Read the mcontext data from the stack.
-  // sp points to the ucontext data structure, read only the mcontext part.
-  x86_64_ucontext_t x86_64_ucontext;
-  if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
-                                 sizeof(x86_64_mcontext_t))) {
-    return false;
-  }
-  SetFromUcontext(&x86_64_ucontext);
-  return true;
-}
-
 }  // namespace unwindstack
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
new file mode 100644
index 0000000..34f29bd
--- /dev/null
+++ b/libunwindstack/RegsArm.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsArm.h>
+
+#include "MachineArm.h"
+#include "UcontextArm.h"
+#include "UserArm.h"
+
+namespace unwindstack {
+
+RegsArm::RegsArm()
+    : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
+
+ArchEnum RegsArm::Arch() {
+  return ARCH_ARM;
+}
+
+uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  uint64_t load_bias = elf->GetLoadBias();
+  if (rel_pc < load_bias) {
+    return rel_pc;
+  }
+  uint64_t adjusted_rel_pc = rel_pc - load_bias;
+
+  if (adjusted_rel_pc < 5) {
+    return rel_pc;
+  }
+
+  if (adjusted_rel_pc & 1) {
+    // This is a thumb instruction, it could be 2 or 4 bytes.
+    uint32_t value;
+    if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
+        (value & 0xe000f000) != 0xe000f000) {
+      return rel_pc - 2;
+    }
+  }
+  return rel_pc - 4;
+}
+
+void RegsArm::SetFromRaw() {
+  set_pc(regs_[ARM_REG_PC]);
+  set_sp(regs_[ARM_REG_SP]);
+}
+
+bool RegsArm::SetPcFromReturnAddress(Memory*) {
+  if (pc() == regs_[ARM_REG_LR]) {
+    return false;
+  }
+
+  set_pc(regs_[ARM_REG_LR]);
+  return true;
+}
+
+void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("r0", regs_[ARM_REG_R0]);
+  fn("r1", regs_[ARM_REG_R1]);
+  fn("r2", regs_[ARM_REG_R2]);
+  fn("r3", regs_[ARM_REG_R3]);
+  fn("r4", regs_[ARM_REG_R4]);
+  fn("r5", regs_[ARM_REG_R5]);
+  fn("r6", regs_[ARM_REG_R6]);
+  fn("r7", regs_[ARM_REG_R7]);
+  fn("r8", regs_[ARM_REG_R8]);
+  fn("r9", regs_[ARM_REG_R9]);
+  fn("r10", regs_[ARM_REG_R10]);
+  fn("r11", regs_[ARM_REG_R11]);
+  fn("ip", regs_[ARM_REG_R12]);
+  fn("sp", regs_[ARM_REG_SP]);
+  fn("lr", regs_[ARM_REG_LR]);
+  fn("pc", regs_[ARM_REG_PC]);
+}
+
+Regs* RegsArm::Read(void* remote_data) {
+  arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
+
+  RegsArm* regs = new RegsArm();
+  memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+Regs* RegsArm::CreateFromUcontext(void* ucontext) {
+  arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
+
+  RegsArm* regs = new RegsArm();
+  memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint32_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  uint64_t offset = 0;
+  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+    // non-RT sigreturn call.
+    // __restore:
+    //
+    // Form 1 (arm):
+    // 0x77 0x70              mov r7, #0x77
+    // 0xa0 0xe3              svc 0x00000000
+    //
+    // Form 2 (arm):
+    // 0x77 0x00 0x90 0xef    svc 0x00900077
+    //
+    // Form 3 (thumb):
+    // 0x77 0x27              movs r7, #77
+    // 0x00 0xdf              svc 0
+    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+      return false;
+    }
+    if (data == 0x5ac3c35a) {
+      // SP + uc_mcontext offset + r0 offset.
+      offset = sp() + 0x14 + 0xc;
+    } else {
+      // SP + r0 offset
+      offset = sp() + 0xc;
+    }
+  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+    // RT sigreturn call.
+    // __restore_rt:
+    //
+    // Form 1 (arm):
+    // 0xad 0x70      mov r7, #0xad
+    // 0xa0 0xe3      svc 0x00000000
+    //
+    // Form 2 (arm):
+    // 0xad 0x00 0x90 0xef    svc 0x009000ad
+    //
+    // Form 3 (thumb):
+    // 0xad 0x27              movs r7, #ad
+    // 0x00 0xdf              svc 0
+    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+      return false;
+    }
+    if (data == sp() + 8) {
+      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+    } else {
+      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+      offset = sp() + 0x80 + 0x14 + 0xc;
+    }
+  }
+  if (offset == 0) {
+    return false;
+  }
+
+  if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+    return false;
+  }
+  SetFromRaw();
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
new file mode 100644
index 0000000..2077bc5
--- /dev/null
+++ b/libunwindstack/RegsArm64.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsArm64.h>
+
+#include "MachineArm64.h"
+#include "UcontextArm64.h"
+#include "UserArm64.h"
+
+namespace unwindstack {
+
+RegsArm64::RegsArm64()
+    : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
+
+ArchEnum RegsArm64::Arch() {
+  return ARCH_ARM64;
+}
+
+uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  if (rel_pc < 4) {
+    return rel_pc;
+  }
+  return rel_pc - 4;
+}
+
+void RegsArm64::SetFromRaw() {
+  set_pc(regs_[ARM64_REG_PC]);
+  set_sp(regs_[ARM64_REG_SP]);
+}
+
+bool RegsArm64::SetPcFromReturnAddress(Memory*) {
+  if (pc() == regs_[ARM64_REG_LR]) {
+    return false;
+  }
+
+  set_pc(regs_[ARM64_REG_LR]);
+  return true;
+}
+
+void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("x0", regs_[ARM64_REG_R0]);
+  fn("x1", regs_[ARM64_REG_R1]);
+  fn("x2", regs_[ARM64_REG_R2]);
+  fn("x3", regs_[ARM64_REG_R3]);
+  fn("x4", regs_[ARM64_REG_R4]);
+  fn("x5", regs_[ARM64_REG_R5]);
+  fn("x6", regs_[ARM64_REG_R6]);
+  fn("x7", regs_[ARM64_REG_R7]);
+  fn("x8", regs_[ARM64_REG_R8]);
+  fn("x9", regs_[ARM64_REG_R9]);
+  fn("x10", regs_[ARM64_REG_R10]);
+  fn("x11", regs_[ARM64_REG_R11]);
+  fn("x12", regs_[ARM64_REG_R12]);
+  fn("x13", regs_[ARM64_REG_R13]);
+  fn("x14", regs_[ARM64_REG_R14]);
+  fn("x15", regs_[ARM64_REG_R15]);
+  fn("x16", regs_[ARM64_REG_R16]);
+  fn("x17", regs_[ARM64_REG_R17]);
+  fn("x18", regs_[ARM64_REG_R18]);
+  fn("x19", regs_[ARM64_REG_R19]);
+  fn("x20", regs_[ARM64_REG_R20]);
+  fn("x21", regs_[ARM64_REG_R21]);
+  fn("x22", regs_[ARM64_REG_R22]);
+  fn("x23", regs_[ARM64_REG_R23]);
+  fn("x24", regs_[ARM64_REG_R24]);
+  fn("x25", regs_[ARM64_REG_R25]);
+  fn("x26", regs_[ARM64_REG_R26]);
+  fn("x27", regs_[ARM64_REG_R27]);
+  fn("x28", regs_[ARM64_REG_R28]);
+  fn("x29", regs_[ARM64_REG_R29]);
+  fn("sp", regs_[ARM64_REG_SP]);
+  fn("lr", regs_[ARM64_REG_LR]);
+  fn("pc", regs_[ARM64_REG_PC]);
+}
+
+Regs* RegsArm64::Read(void* remote_data) {
+  arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
+
+  RegsArm64* regs = new RegsArm64();
+  memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
+  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+  reg_data[ARM64_REG_PC] = user->pc;
+  reg_data[ARM64_REG_SP] = user->sp;
+  regs->SetFromRaw();
+  return regs;
+}
+
+Regs* RegsArm64::CreateFromUcontext(void* ucontext) {
+  arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
+
+  RegsArm64* regs = new RegsArm64();
+  memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  // Look for the kernel sigreturn function.
+  // __kernel_rt_sigreturn:
+  // 0xd2801168     mov x8, #0x8b
+  // 0xd4000001     svc #0x0
+  if (data != 0xd4000001d2801168ULL) {
+    return false;
+  }
+
+  // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+  if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+                                 sizeof(uint64_t) * ARM64_REG_LAST)) {
+    return false;
+  }
+
+  SetFromRaw();
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
new file mode 100644
index 0000000..ef2f3de
--- /dev/null
+++ b/libunwindstack/RegsX86.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsX86.h>
+
+#include "MachineX86.h"
+#include "UcontextX86.h"
+#include "UserX86.h"
+
+namespace unwindstack {
+
+RegsX86::RegsX86()
+    : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
+
+ArchEnum RegsX86::Arch() {
+  return ARCH_X86;
+}
+
+uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  if (rel_pc == 0) {
+    return 0;
+  }
+  return rel_pc - 1;
+}
+
+void RegsX86::SetFromRaw() {
+  set_pc(regs_[X86_REG_PC]);
+  set_sp(regs_[X86_REG_SP]);
+}
+
+bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
+  // Attempt to get the return address from the top of the stack.
+  uint32_t new_pc;
+  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+    return false;
+  }
+
+  set_pc(new_pc);
+  return true;
+}
+
+void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("eax", regs_[X86_REG_EAX]);
+  fn("ebx", regs_[X86_REG_EBX]);
+  fn("ecx", regs_[X86_REG_ECX]);
+  fn("edx", regs_[X86_REG_EDX]);
+  fn("ebp", regs_[X86_REG_EBP]);
+  fn("edi", regs_[X86_REG_EDI]);
+  fn("esi", regs_[X86_REG_ESI]);
+  fn("esp", regs_[X86_REG_ESP]);
+  fn("eip", regs_[X86_REG_EIP]);
+}
+
+Regs* RegsX86::Read(void* user_data) {
+  x86_user_regs* user = reinterpret_cast<x86_user_regs*>(user_data);
+
+  RegsX86* regs = new RegsX86();
+  (*regs)[X86_REG_EAX] = user->eax;
+  (*regs)[X86_REG_EBX] = user->ebx;
+  (*regs)[X86_REG_ECX] = user->ecx;
+  (*regs)[X86_REG_EDX] = user->edx;
+  (*regs)[X86_REG_EBP] = user->ebp;
+  (*regs)[X86_REG_EDI] = user->edi;
+  (*regs)[X86_REG_ESI] = user->esi;
+  (*regs)[X86_REG_ESP] = user->esp;
+  (*regs)[X86_REG_EIP] = user->eip;
+
+  regs->SetFromRaw();
+  return regs;
+}
+
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+  // Put the registers in the expected order.
+  regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+  regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+  regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+  regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+  regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+  regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+  regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+  regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+  regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+  SetFromRaw();
+}
+
+Regs* RegsX86::CreateFromUcontext(void* ucontext) {
+  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
+
+  RegsX86* regs = new RegsX86();
+  regs->SetFromUcontext(x86_ucontext);
+  return regs;
+}
+
+bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  if (data == 0x80cd00000077b858ULL) {
+    // Without SA_SIGINFO set, the return sequence is:
+    //
+    //   __restore:
+    //   0x58                            pop %eax
+    //   0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
+    //   0xcd 0x80                       int 0x80
+    //
+    // SP points at arguments:
+    //   int signum
+    //   struct sigcontext (same format as mcontext)
+    struct x86_mcontext_t context;
+    if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
+      return false;
+    }
+    regs_[X86_REG_EBP] = context.ebp;
+    regs_[X86_REG_ESP] = context.esp;
+    regs_[X86_REG_EBX] = context.ebx;
+    regs_[X86_REG_EDX] = context.edx;
+    regs_[X86_REG_ECX] = context.ecx;
+    regs_[X86_REG_EAX] = context.eax;
+    regs_[X86_REG_EIP] = context.eip;
+    SetFromRaw();
+    return true;
+  } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+    // With SA_SIGINFO set, the return sequence is:
+    //
+    //   __restore_rt:
+    //   0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
+    //   0xcd 0x80                       int 0x80
+    //
+    // SP points at arguments:
+    //   int signum
+    //   siginfo*
+    //   ucontext*
+
+    // Get the location of the sigcontext data.
+    uint32_t ptr;
+    if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
+      return false;
+    }
+    // Only read the portion of the data structure we care about.
+    x86_ucontext_t x86_ucontext;
+    if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+      return false;
+    }
+    SetFromUcontext(&x86_ucontext);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
new file mode 100644
index 0000000..70921f8
--- /dev/null
+++ b/libunwindstack/RegsX86_64.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsX86_64.h>
+
+#include "MachineX86_64.h"
+#include "UcontextX86_64.h"
+#include "UserX86_64.h"
+
+namespace unwindstack {
+
+RegsX86_64::RegsX86_64()
+    : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
+
+ArchEnum RegsX86_64::Arch() {
+  return ARCH_X86_64;
+}
+
+uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  if (rel_pc == 0) {
+    return 0;
+  }
+
+  return rel_pc - 1;
+}
+
+void RegsX86_64::SetFromRaw() {
+  set_pc(regs_[X86_64_REG_PC]);
+  set_sp(regs_[X86_64_REG_SP]);
+}
+
+bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
+  // Attempt to get the return address from the top of the stack.
+  uint64_t new_pc;
+  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+    return false;
+  }
+
+  set_pc(new_pc);
+  return true;
+}
+
+void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("rax", regs_[X86_64_REG_RAX]);
+  fn("rbx", regs_[X86_64_REG_RBX]);
+  fn("rcx", regs_[X86_64_REG_RCX]);
+  fn("rdx", regs_[X86_64_REG_RDX]);
+  fn("r8", regs_[X86_64_REG_R8]);
+  fn("r9", regs_[X86_64_REG_R9]);
+  fn("r10", regs_[X86_64_REG_R10]);
+  fn("r11", regs_[X86_64_REG_R11]);
+  fn("r12", regs_[X86_64_REG_R12]);
+  fn("r13", regs_[X86_64_REG_R13]);
+  fn("r14", regs_[X86_64_REG_R14]);
+  fn("r15", regs_[X86_64_REG_R15]);
+  fn("rdi", regs_[X86_64_REG_RDI]);
+  fn("rsi", regs_[X86_64_REG_RSI]);
+  fn("rbp", regs_[X86_64_REG_RBP]);
+  fn("rsp", regs_[X86_64_REG_RSP]);
+  fn("rip", regs_[X86_64_REG_RIP]);
+}
+
+Regs* RegsX86_64::Read(void* remote_data) {
+  x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
+
+  RegsX86_64* regs = new RegsX86_64();
+  (*regs)[X86_64_REG_RAX] = user->rax;
+  (*regs)[X86_64_REG_RBX] = user->rbx;
+  (*regs)[X86_64_REG_RCX] = user->rcx;
+  (*regs)[X86_64_REG_RDX] = user->rdx;
+  (*regs)[X86_64_REG_R8] = user->r8;
+  (*regs)[X86_64_REG_R9] = user->r9;
+  (*regs)[X86_64_REG_R10] = user->r10;
+  (*regs)[X86_64_REG_R11] = user->r11;
+  (*regs)[X86_64_REG_R12] = user->r12;
+  (*regs)[X86_64_REG_R13] = user->r13;
+  (*regs)[X86_64_REG_R14] = user->r14;
+  (*regs)[X86_64_REG_R15] = user->r15;
+  (*regs)[X86_64_REG_RDI] = user->rdi;
+  (*regs)[X86_64_REG_RSI] = user->rsi;
+  (*regs)[X86_64_REG_RBP] = user->rbp;
+  (*regs)[X86_64_REG_RSP] = user->rsp;
+  (*regs)[X86_64_REG_RIP] = user->rip;
+
+  regs->SetFromRaw();
+  return regs;
+}
+
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
+  // R8-R15
+  memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+  // Rest of the registers.
+  regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+  regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+  regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+  regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+  regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+  regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+  regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+  regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+  regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+  SetFromRaw();
+}
+
+Regs* RegsX86_64::CreateFromUcontext(void* ucontext) {
+  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
+
+  RegsX86_64* regs = new RegsX86_64();
+  regs->SetFromUcontext(x86_64_ucontext);
+  return regs;
+}
+
+bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+    return false;
+  }
+
+  uint16_t data2;
+  if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+    return false;
+  }
+
+  // __restore_rt:
+  // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
+  // 0x0f 0x05                            syscall
+  // 0x0f                                 nopl 0x0($rax)
+
+  // Read the mcontext data from the stack.
+  // sp points to the ucontext data structure, read only the mcontext part.
+  x86_64_ucontext_t x86_64_ucontext;
+  if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
+                                 sizeof(x86_64_mcontext_t))) {
+    return false;
+  }
+  SetFromUcontext(&x86_64_ucontext);
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
deleted file mode 100644
index 22f6a89..0000000
--- a/libunwindstack/Ucontext.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_H
-#define _LIBUNWINDSTACK_UCONTEXT_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-//-------------------------------------------------------------------
-// ARM ucontext structures
-//-------------------------------------------------------------------
-struct arm_stack_t {
-  uint32_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint32_t ss_size;  // size_t
-};
-
-struct arm_mcontext_t {
-  uint32_t trap_no;             // unsigned long
-  uint32_t error_code;          // unsigned long
-  uint32_t oldmask;             // unsigned long
-  uint32_t regs[ARM_REG_LAST];  // unsigned long
-  uint32_t cpsr;                // unsigned long
-  uint32_t fault_address;       // unsigned long
-};
-
-struct arm_ucontext_t {
-  uint32_t uc_flags;  // unsigned long
-  uint32_t uc_link;   // struct ucontext*
-  arm_stack_t uc_stack;
-  arm_mcontext_t uc_mcontext;
-  // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// ARM64 ucontext structures
-//-------------------------------------------------------------------
-struct arm64_stack_t {
-  uint64_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint64_t ss_size;  // size_t
-};
-
-struct arm64_sigset_t {
-  uint64_t sig;  // unsigned long
-};
-
-struct arm64_mcontext_t {
-  uint64_t fault_address;         // __u64
-  uint64_t regs[ARM64_REG_LAST];  // __u64
-  uint64_t pstate;                // __u64
-  // Nothing else is used, so don't define it.
-};
-
-struct arm64_ucontext_t {
-  uint64_t uc_flags;  // unsigned long
-  uint64_t uc_link;   // struct ucontext*
-  arm64_stack_t uc_stack;
-  arm64_sigset_t uc_sigmask;
-  // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
-  char __padding[128 - sizeof(arm64_sigset_t)];
-  // The full structure requires 16 byte alignment, but our partial structure
-  // doesn't, so force the alignment.
-  arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// X86 ucontext structures
-//-------------------------------------------------------------------
-struct x86_stack_t {
-  uint32_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint32_t ss_size;  // size_t
-};
-
-struct x86_mcontext_t {
-  uint32_t gs;
-  uint32_t fs;
-  uint32_t es;
-  uint32_t ds;
-  uint32_t edi;
-  uint32_t esi;
-  uint32_t ebp;
-  uint32_t esp;
-  uint32_t ebx;
-  uint32_t edx;
-  uint32_t ecx;
-  uint32_t eax;
-  uint32_t trapno;
-  uint32_t err;
-  uint32_t eip;
-  uint32_t cs;
-  uint32_t efl;
-  uint32_t uesp;
-  uint32_t ss;
-  // Only care about the registers, skip everything else.
-};
-
-struct x86_ucontext_t {
-  uint32_t uc_flags;  // unsigned long
-  uint32_t uc_link;   // struct ucontext*
-  x86_stack_t uc_stack;
-  x86_mcontext_t uc_mcontext;
-  // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// X86_64 ucontext structures
-//-------------------------------------------------------------------
-struct x86_64_stack_t {
-  uint64_t ss_sp;    // void __user*
-  int32_t ss_flags;  // int
-  uint64_t ss_size;  // size_t
-};
-
-struct x86_64_mcontext_t {
-  uint64_t r8;
-  uint64_t r9;
-  uint64_t r10;
-  uint64_t r11;
-  uint64_t r12;
-  uint64_t r13;
-  uint64_t r14;
-  uint64_t r15;
-  uint64_t rdi;
-  uint64_t rsi;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t rdx;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rsp;
-  uint64_t rip;
-  uint64_t efl;
-  uint64_t csgsfs;
-  uint64_t err;
-  uint64_t trapno;
-  uint64_t oldmask;
-  uint64_t cr2;
-  // Only care about the registers, skip everything else.
-};
-
-struct x86_64_ucontext_t {
-  uint64_t uc_flags;  // unsigned long
-  uint64_t uc_link;   // struct ucontext*
-  x86_64_stack_t uc_stack;
-  x86_64_mcontext_t uc_mcontext;
-  // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-}  // namespace unwindstack
-
-#endif  // _LIBUNWINDSTACK_UCONTEXT_H
diff --git a/libunwindstack/UcontextArm.h b/libunwindstack/UcontextArm.h
new file mode 100644
index 0000000..8c94166
--- /dev/null
+++ b/libunwindstack/UcontextArm.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM_H
+
+#include <stdint.h>
+
+#include "MachineArm.h"
+
+namespace unwindstack {
+
+struct arm_stack_t {
+  uint32_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint32_t ss_size;  // size_t
+};
+
+struct arm_mcontext_t {
+  uint32_t trap_no;             // unsigned long
+  uint32_t error_code;          // unsigned long
+  uint32_t oldmask;             // unsigned long
+  uint32_t regs[ARM_REG_LAST];  // unsigned long
+  uint32_t cpsr;                // unsigned long
+  uint32_t fault_address;       // unsigned long
+};
+
+struct arm_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  arm_stack_t uc_stack;
+  arm_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_ARM_H
diff --git a/libunwindstack/UcontextArm64.h b/libunwindstack/UcontextArm64.h
new file mode 100644
index 0000000..655719f
--- /dev/null
+++ b/libunwindstack/UcontextArm64.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+
+#include <stdint.h>
+
+#include "MachineArm64.h"
+
+namespace unwindstack {
+
+struct arm64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint64_t ss_size;  // size_t
+};
+
+struct arm64_sigset_t {
+  uint64_t sig;  // unsigned long
+};
+
+struct arm64_mcontext_t {
+  uint64_t fault_address;         // __u64
+  uint64_t regs[ARM64_REG_LAST];  // __u64
+  uint64_t pstate;                // __u64
+  // Nothing else is used, so don't define it.
+};
+
+struct arm64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  arm64_stack_t uc_stack;
+  arm64_sigset_t uc_sigmask;
+  // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
+  char __padding[128 - sizeof(arm64_sigset_t)];
+  // The full structure requires 16 byte alignment, but our partial structure
+  // doesn't, so force the alignment.
+  arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_ARM64_H
diff --git a/libunwindstack/User.h b/libunwindstack/UcontextX86.h
similarity index 62%
copy from libunwindstack/User.h
copy to libunwindstack/UcontextX86.h
index 53f7e50..f79d92b 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UcontextX86.h
@@ -26,75 +26,52 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_H
+
+#include <stdint.h>
+
+#include "MachineX86.h"
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
+struct x86_stack_t {
+  uint32_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint32_t ss_size;  // size_t
+};
+
+struct x86_mcontext_t {
+  uint32_t gs;
+  uint32_t fs;
+  uint32_t es;
+  uint32_t ds;
   uint32_t edi;
+  uint32_t esi;
   uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
   uint32_t esp;
-  uint32_t xss;
+  uint32_t ebx;
+  uint32_t edx;
+  uint32_t ecx;
+  uint32_t eax;
+  uint32_t trapno;
+  uint32_t err;
+  uint32_t eip;
+  uint32_t cs;
+  uint32_t efl;
+  uint32_t uesp;
+  uint32_t ss;
+  // Only care about the registers, skip everything else.
 };
 
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
-  uint64_t r12;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
-  uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
+struct x86_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  x86_stack_t uc_stack;
+  x86_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
 };
 
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_UCONTEXT_X86_H
diff --git a/libunwindstack/User.h b/libunwindstack/UcontextX86_64.h
similarity index 67%
copy from libunwindstack/User.h
copy to libunwindstack/UcontextX86_64.h
index 53f7e50..d689796 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UcontextX86_64.h
@@ -26,75 +26,56 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+
+#include <stdint.h>
+
+#include "MachineX86_64.h"
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
-  uint32_t edi;
-  uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
-  uint32_t esp;
-  uint32_t xss;
+struct x86_64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint64_t ss_size;  // size_t
 };
 
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
+struct x86_64_mcontext_t {
+  uint64_t r8;
+  uint64_t r9;
+  uint64_t r10;
+  uint64_t r11;
   uint64_t r12;
+  uint64_t r13;
+  uint64_t r14;
+  uint64_t r15;
+  uint64_t rdi;
+  uint64_t rsi;
   uint64_t rbp;
   uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
+  uint64_t rdx;
   uint64_t rax;
   uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
   uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
+  uint64_t rip;
+  uint64_t efl;
+  uint64_t csgsfs;
+  uint64_t err;
+  uint64_t trapno;
+  uint64_t oldmask;
+  uint64_t cr2;
+  // Only care about the registers, skip everything else.
 };
 
-struct arm_user_regs {
-  uint32_t regs[18];
+struct x86_64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  x86_64_stack_t uc_stack;
+  x86_64_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
 };
 
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_UCONTEXT_X86_64_H
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 3092a62..4ae365d 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -174,8 +174,7 @@
   if (frame_num >= frames_.size()) {
     return "";
   }
-  return FormatFrame(frames_[frame_num],
-                     regs_->MachineType() == EM_ARM || regs_->MachineType() == EM_386);
+  return FormatFrame(frames_[frame_num], regs_->Arch() == ARCH_ARM || regs_->Arch() == ARCH_X86);
 }
 
 std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) {
diff --git a/libunwindstack/UserArm.h b/libunwindstack/UserArm.h
new file mode 100644
index 0000000..7388c03
--- /dev/null
+++ b/libunwindstack/UserArm.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_USER_ARM_H
+#define _LIBUNWINDSTACK_USER_ARM_H
+
+namespace unwindstack {
+
+struct arm_user_regs {
+  uint32_t regs[18];
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_USER_ARM_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserArm64.h
similarity index 60%
copy from libunwindstack/User.h
copy to libunwindstack/UserArm64.h
index 53f7e50..d74983f 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserArm64.h
@@ -26,65 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_ARM64_H
+#define _LIBUNWINDSTACK_USER_ARM64_H
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
-  uint32_t edi;
-  uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
-  uint32_t esp;
-  uint32_t xss;
-};
-
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
-  uint64_t r12;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
-  uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
-};
-
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
 struct arm64_user_regs {
   uint64_t regs[31];
   uint64_t sp;
@@ -92,9 +38,6 @@
   uint64_t pstate;
 };
 
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_USER_ARM64_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserX86.h
similarity index 68%
copy from libunwindstack/User.h
copy to libunwindstack/UserX86.h
index 53f7e50..a040560 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserX86.h
@@ -26,8 +26,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_X86_H
+#define _LIBUNWINDSTACK_USER_X86_H
 
 namespace unwindstack {
 
@@ -51,50 +51,6 @@
   uint32_t xss;
 };
 
-struct x86_64_user_regs {
-  uint64_t r15;
-  uint64_t r14;
-  uint64_t r13;
-  uint64_t r12;
-  uint64_t rbp;
-  uint64_t rbx;
-  uint64_t r11;
-  uint64_t r10;
-  uint64_t r9;
-  uint64_t r8;
-  uint64_t rax;
-  uint64_t rcx;
-  uint64_t rdx;
-  uint64_t rsi;
-  uint64_t rdi;
-  uint64_t orig_rax;
-  uint64_t rip;
-  uint64_t cs;
-  uint64_t eflags;
-  uint64_t rsp;
-  uint64_t ss;
-  uint64_t fs_base;
-  uint64_t gs_base;
-  uint64_t ds;
-  uint64_t es;
-  uint64_t fs;
-  uint64_t gs;
-};
-
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_USER_X86_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserX86_64.h
similarity index 74%
rename from libunwindstack/User.h
rename to libunwindstack/UserX86_64.h
index 53f7e50..b80d201 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserX86_64.h
@@ -26,31 +26,11 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_X86_64_H
+#define _LIBUNWINDSTACK_USER_X86_64_H
 
 namespace unwindstack {
 
-struct x86_user_regs {
-  uint32_t ebx;
-  uint32_t ecx;
-  uint32_t edx;
-  uint32_t esi;
-  uint32_t edi;
-  uint32_t ebp;
-  uint32_t eax;
-  uint32_t xds;
-  uint32_t xes;
-  uint32_t xfs;
-  uint32_t xgs;
-  uint32_t orig_eax;
-  uint32_t eip;
-  uint32_t xcs;
-  uint32_t eflags;
-  uint32_t esp;
-  uint32_t xss;
-};
-
 struct x86_64_user_regs {
   uint64_t r15;
   uint64_t r14;
@@ -81,20 +61,6 @@
   uint64_t gs;
 };
 
-struct arm_user_regs {
-  uint32_t regs[18];
-};
-
-struct arm64_user_regs {
-  uint64_t regs[31];
-  uint64_t sp;
-  uint64_t pc;
-  uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_USER_H
+#endif  // _LIBUNWINDSTACK_USER_X86_64_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index d9ea9c4..d27727b 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -36,6 +36,14 @@
 struct MapInfo;
 class Regs;
 
+enum ArchEnum : uint8_t {
+  ARCH_UNKNOWN = 0,
+  ARCH_ARM,
+  ARCH_ARM64,
+  ARCH_X86,
+  ARCH_X86_64,
+};
+
 class Elf {
  public:
   Elf(Memory* memory) : memory_(memory) {}
@@ -64,6 +72,8 @@
 
   uint8_t class_type() { return class_type_; }
 
+  ArchEnum arch() { return arch_; }
+
   Memory* memory() { return memory_.get(); }
 
   ElfInterface* interface() { return interface_.get(); }
@@ -83,6 +93,7 @@
   std::unique_ptr<Memory> memory_;
   uint32_t machine_type_;
   uint8_t class_type_;
+  ArchEnum arch_;
   // Protect calls that can modify internal state of the interface object.
   std::mutex lock_;
 
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 8163152..94ceaab 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <atomic>
 #include <memory>
 #include <string>
 #include <vector>
@@ -99,7 +100,7 @@
 
 class MemoryRemote : public Memory {
  public:
-  MemoryRemote(pid_t pid) : pid_(pid) {}
+  MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {}
   virtual ~MemoryRemote() = default;
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
@@ -108,6 +109,7 @@
 
  private:
   pid_t pid_;
+  std::atomic_uintptr_t read_redirect_func_;
 };
 
 class MemoryLocal : public Memory {
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 6576e4c..7025fcf 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -27,10 +27,8 @@
 
 // Forward declarations.
 class Elf;
-struct MapInfo;
+enum ArchEnum : uint8_t;
 class Memory;
-struct x86_ucontext_t;
-struct x86_64_ucontext_t;
 
 class Regs {
  public:
@@ -51,7 +49,7 @@
       : total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {}
   virtual ~Regs() = default;
 
-  virtual uint32_t MachineType() = 0;
+  virtual ArchEnum Arch() = 0;
 
   virtual void* RawData() = 0;
   virtual uint64_t pc() = 0;
@@ -70,9 +68,9 @@
   uint16_t sp_reg() { return sp_reg_; }
   uint16_t total_regs() { return total_regs_; }
 
-  static uint32_t CurrentMachineType();
+  static ArchEnum CurrentArch();
   static Regs* RemoteGet(pid_t pid);
-  static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext);
+  static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext);
   static Regs* CreateFromLocal();
 
  protected:
@@ -110,82 +108,6 @@
   std::vector<AddressType> regs_;
 };
 
-class RegsArm : public RegsImpl<uint32_t> {
- public:
-  RegsArm();
-  virtual ~RegsArm() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsArm64 : public RegsImpl<uint64_t> {
- public:
-  RegsArm64();
-  virtual ~RegsArm64() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsX86 : public RegsImpl<uint32_t> {
- public:
-  RegsX86();
-  virtual ~RegsX86() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  void SetFromUcontext(x86_ucontext_t* ucontext);
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsX86_64 : public RegsImpl<uint64_t> {
- public:
-  RegsX86_64();
-  virtual ~RegsX86_64() = default;
-
-  virtual uint32_t MachineType() override final;
-
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
-
-  void SetFromRaw() override;
-
-  bool SetPcFromReturnAddress(Memory* process_memory) override;
-
-  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
-
-  void SetFromUcontext(x86_64_ucontext_t* ucontext);
-
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
new file mode 100644
index 0000000..b5d344b
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_ARM_H
+#define _LIBUNWINDSTACK_REGS_ARM_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsArm : public RegsImpl<uint32_t> {
+ public:
+  RegsArm();
+  virtual ~RegsArm() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_ARM_H
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
new file mode 100644
index 0000000..30e626c
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_ARM64_H
+#define _LIBUNWINDSTACK_REGS_ARM64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsArm64 : public RegsImpl<uint64_t> {
+ public:
+  RegsArm64();
+  virtual ~RegsArm64() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_ARM64_H
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
new file mode 100644
index 0000000..a695bbf
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_X86_H
+#define _LIBUNWINDSTACK_REGS_X86_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+struct x86_ucontext_t;
+
+class RegsX86 : public RegsImpl<uint32_t> {
+ public:
+  RegsX86();
+  virtual ~RegsX86() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  void SetFromUcontext(x86_ucontext_t* ucontext);
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_X86_H
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
new file mode 100644
index 0000000..23a3f20
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_X86_64_H
+#define _LIBUNWINDSTACK_REGS_X86_64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+struct x86_64_ucontext_t;
+
+class RegsX86_64 : public RegsImpl<uint64_t> {
+ public:
+  RegsX86_64();
+  virtual ~RegsX86_64() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  void SetFromUcontext(x86_64_ucontext_t* ucontext);
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_X86_64_H
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index 94cb493..8d6d00d 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -24,7 +24,7 @@
 #include <gtest/gtest.h>
 
 #include <unwindstack/Log.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 4b621c9..5f7cf60 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,10 +20,10 @@
 
 #include <vector>
 
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ElfInterfaceArm.h"
-#include "Machine.h"
+#include "MachineArm.h"
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index afd113d..00192f1 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -25,6 +25,7 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
+#include <unwindstack/RegsArm.h>
 
 #include "ElfFake.h"
 #include "ElfTestUtils.h"
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 8aa8605..f5492a2 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -225,7 +225,7 @@
 
   MemoryRemote remote(pid);
   std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
-  size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+  size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
   // Some read methods can read PROT_NONE maps, allow that.
   ASSERT_LE(page_size, read_size);
   for (size_t i = 0; i < read_size; ++i) {
@@ -260,7 +260,7 @@
 
   MemoryRemote remote(pid);
   std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
-  size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+  size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
   ASSERT_EQ(page_size, read_size);
   for (size_t i = 0; i < read_size; ++i) {
     ASSERT_EQ(0xFF, dst[i]);
@@ -270,4 +270,55 @@
   }
 }
 
+// Verify that the memory remote object chooses a memory read function
+// properly. Either process_vm_readv or ptrace.
+TEST_F(MemoryRemoteTest, read_choose_correctly) {
+  size_t page_size = getpagesize();
+  void* mapping =
+      mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0xFC, 2 * page_size);
+  ASSERT_EQ(0, mprotect(static_cast<char*>(mapping), page_size, PROT_NONE));
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  ASSERT_EQ(0, munmap(mapping, 2 * page_size));
+
+  ASSERT_TRUE(Attach(pid));
+
+  // We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
+  // Read from the PROT_NONE area first to force the choice of ptrace.
+  MemoryRemote remote_ptrace(pid);
+  uint32_t value;
+  size_t bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+  bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+  bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+
+  // Now verify that choosing process_vm_readv results in failing reads of
+  // the PROT_NONE part of the map. Read from a valid map first which
+  // should prefer process_vm_readv, and keep that as the read function.
+  MemoryRemote remote_readv(pid);
+  bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+  bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+  ASSERT_EQ(0U, bytes);
+  bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+  ASSERT_EQ(sizeof(value), bytes);
+  ASSERT_EQ(0xfcfcfcfcU, value);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index fedaf87..3c5af4a 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <unwindstack/Elf.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 
@@ -30,7 +31,7 @@
       : Regs(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsFake() = default;
 
-  uint32_t MachineType() override { return fake_type_; }
+  ArchEnum Arch() override { return fake_arch_; }
   void* RawData() override { return nullptr; }
   uint64_t pc() override { return fake_pc_; }
   uint64_t sp() override { return fake_sp_; }
@@ -50,14 +51,14 @@
 
   void SetFromRaw() override {}
 
-  void FakeSetMachineType(uint32_t type) { fake_type_ = type; }
+  void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
   void FakeSetPc(uint64_t pc) { fake_pc_ = pc; }
   void FakeSetSp(uint64_t sp) { fake_sp_ = sp; }
   void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; }
   void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; }
 
  private:
-  uint32_t fake_type_ = 0;
+  ArchEnum fake_arch_ = ARCH_UNKNOWN;
   uint64_t fake_pc_ = 0;
   uint64_t fake_sp_ = 0;
   bool fake_return_address_valid_ = false;
@@ -71,7 +72,7 @@
       : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsImplFake() = default;
 
-  uint32_t MachineType() override { return 0; }
+  ArchEnum Arch() override { return ARCH_UNKNOWN; }
 
   uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
   void SetFromRaw() override {}
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index c8d1d98..0cb70ba 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -25,9 +25,15 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/MapInfo.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
+#include "MachineX86.h"
+#include "MachineX86_64.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index 85192d5..ae57caf 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -19,9 +19,15 @@
 #include <gtest/gtest.h>
 
 #include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
+#include "MachineX86.h"
+#include "MachineX86_64.h"
 
 #include "MemoryFake.h"
 
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3320f77..a932973 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -21,7 +21,10 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/MapInfo.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
@@ -212,4 +215,18 @@
   EXPECT_EQ(0x4900000000U, x86_64.pc());
 }
 
+TEST_F(RegsTest, machine_type) {
+  RegsArm arm_regs;
+  EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
+
+  RegsArm64 arm64_regs;
+  EXPECT_EQ(ARCH_ARM64, arm64_regs.Arch());
+
+  RegsX86 x86_regs;
+  EXPECT_EQ(ARCH_X86, x86_regs.Arch());
+
+  RegsX86_64 x86_64_regs;
+  EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index d24abe4..962f744 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -27,10 +27,12 @@
 
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
 #include <unwindstack/Unwinder.h>
 
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
 
 #include "ElfTestUtils.h"
 
@@ -73,7 +75,7 @@
   BufferMaps maps(buffer.data());
   ASSERT_TRUE(maps.Parse());
 
-  ASSERT_EQ(static_cast<uint32_t>(EM_ARM), regs.MachineType());
+  ASSERT_EQ(ARCH_ARM, regs.Arch());
 
   std::shared_ptr<Memory> process_memory(memory);
 
@@ -125,7 +127,7 @@
   BufferMaps maps(buffer.data());
   ASSERT_TRUE(maps.Parse());
 
-  ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
+  ASSERT_EQ(ARCH_ARM64, regs.Arch());
 
   std::shared_ptr<Memory> process_memory(memory);
 
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index b372fd0..242cc6a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -250,7 +250,7 @@
 
   LocalMaps maps;
   ASSERT_TRUE(maps.Parse());
-  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext));
+  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
 
   VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
 
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 098459e..71103b4 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -95,7 +95,7 @@
 
   void SetUp() override {
     ElfInterfaceFake::FakeClear();
-    regs_.FakeSetMachineType(EM_ARM);
+    regs_.FakeSetArch(ARCH_ARM);
     regs_.FakeSetReturnAddressValid(false);
   }
 
@@ -702,14 +702,14 @@
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
-  regs_.FakeSetMachineType(EM_ARM);
+  regs_.FakeSetArch(ARCH_ARM);
   EXPECT_EQ("  #00 pc 00001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
-  regs_.FakeSetMachineType(EM_386);
+  regs_.FakeSetArch(ARCH_X86);
   EXPECT_EQ("  #00 pc 00001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
 
-  regs_.FakeSetMachineType(EM_AARCH64);
+  regs_.FakeSetArch(ARCH_ARM64);
   EXPECT_EQ("  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
-  regs_.FakeSetMachineType(EM_X86_64);
+  regs_.FakeSetArch(ARCH_X86_64);
   EXPECT_EQ("  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
 
   EXPECT_EQ("", unwinder.FormatFrame(1));
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index f2530d7..7896279 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -63,17 +63,17 @@
   }
 
   printf("ABI: ");
-  switch (regs->MachineType()) {
-    case EM_ARM:
+  switch (regs->Arch()) {
+    case unwindstack::ARCH_ARM:
       printf("arm");
       break;
-    case EM_386:
+    case unwindstack::ARCH_X86:
       printf("x86");
       break;
-    case EM_AARCH64:
+    case unwindstack::ARCH_ARM64:
       printf("arm64");
       break;
-    case EM_X86_64:
+    case unwindstack::ARCH_X86_64:
       printf("x86_64");
       break;
     default:
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 44b878d..4d286bf 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -324,29 +324,39 @@
 
 struct usb_device *usb_device_open(const char *dev_name)
 {
-    int fd, did_retry = 0, writeable = 1;
-
+    int fd, attempts, writeable = 1;
+    const int SLEEP_BETWEEN_ATTEMPTS_US = 100000; /* 100 ms */
+    const int64_t MAX_ATTEMPTS = 10;              /* 1s */
     D("usb_device_open %s\n", dev_name);
 
-retry:
-    fd = open(dev_name, O_RDWR);
-    if (fd < 0) {
-        /* if we fail, see if have read-only access */
-        fd = open(dev_name, O_RDONLY);
-        D("usb_device_open open returned %d errno %d\n", fd, errno);
-        if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
-            /* work around race condition between inotify and permissions management */
-            sleep(1);
-            did_retry = 1;
-            goto retry;
+    /* Hack around waiting for permissions to be set on the USB device node.
+     * Should really be a timeout instead of attempt count, and should REALLY
+     * be triggered by the perm change via inotify rather than polling.
+     */
+    for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
+        if (access(dev_name, R_OK | W_OK) == 0) {
+            writeable = 1;
+            break;
+        } else {
+            if (access(dev_name, R_OK) == 0) {
+                /* double check that write permission didn't just come along too! */
+                writeable = (access(dev_name, R_OK | W_OK) == 0);
+                break;
+            }
         }
-
-        if (fd < 0)
-            return NULL;
-        writeable = 0;
-        D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
+        /* not writeable or readable - sleep and try again. */
+        D("usb_device_open no access sleeping\n");
+        usleep(SLEEP_BETWEEN_ATTEMPTS_US);
     }
 
+    if (writeable) {
+        fd = open(dev_name, O_RDWR);
+    } else {
+        fd = open(dev_name, O_RDONLY);
+    }
+    D("usb_device_open open returned %d writeable %d errno %d\n", fd, writeable, errno);
+    if (fd < 0) return NULL;
+
     struct usb_device* result = usb_device_new(dev_name, fd);
     if (result)
         result->writeable = writeable;
diff --git a/libutils/OWNERS b/libutils/OWNERS
new file mode 100644
index 0000000..40164aa
--- /dev/null
+++ b/libutils/OWNERS
@@ -0,0 +1 @@
+smoreland@google.com
diff --git a/libvndksupport/OWNERS b/libvndksupport/OWNERS
new file mode 100644
index 0000000..c7efc16
--- /dev/null
+++ b/libvndksupport/OWNERS
@@ -0,0 +1,2 @@
+jiyong@google.com
+smoreland@google.com
diff --git a/libziparchive/OWNERS b/libziparchive/OWNERS
new file mode 100644
index 0000000..fcc567a
--- /dev/null
+++ b/libziparchive/OWNERS
@@ -0,0 +1 @@
+narayan@google.com
diff --git a/logcat/OWNERS b/logcat/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/logcat/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/logd/OWNERS b/logd/OWNERS
new file mode 100644
index 0000000..2394e32
--- /dev/null
+++ b/logd/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+tomcherry@google.com
diff --git a/logwrapper/OWNERS b/logwrapper/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/logwrapper/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/qemu_pipe/OWNERS b/qemu_pipe/OWNERS
new file mode 100644
index 0000000..dbc1bf6
--- /dev/null
+++ b/qemu_pipe/OWNERS
@@ -0,0 +1 @@
+bohu@google.com
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index aa970d6..777fdb0 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -142,6 +142,7 @@
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
     sbin dev proc sys system data oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
     ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
     ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
@@ -206,16 +207,18 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-vndk_lib_md5 := $(word 1, $(shell echo $(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) | $(MD5SUM)))
-vndk_lib_dep := $(intermediates)/$(vndk_lib_md5).dep
-$(vndk_lib_dep):
-	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
 
-llndk_libraries := $(subst $(space),:,$(addsuffix .so,$(LLNDK_LIBRARIES)))
+llndk_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
 
-vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_SAMEPROCESS_LIBRARIES)))
+private_llndk_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
 
-vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_CORE_LIBRARIES)))
+vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_SAMEPROCESS_LIBRARIES))))
+
+vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES))))
 
 sanitizer_runtime_libraries := $(subst $(space),:,$(addsuffix .so,\
 $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
@@ -226,20 +229,20 @@
 $(2ND_TSAN_RUNTIME_LIBRARY)))
 
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(llndk_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_PRIVATE_LLNDK_LIBRARIES := $(private_llndk_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(vndk_sameprocess_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_PRIVATE_LIBRARIES := $(llndk_private_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(vndk_core_libraries)
 $(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in $(vndk_lib_dep)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in
 	@echo "Generate: $< -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
+	$(hide) sed -i -e 's?%PRIVATE_LLNDK_LIBRARIES%?$(PRIVATE_PRIVATE_LLNDK_LIBRARIES)?g' $@
 	$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $@
 	$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $@
 	$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
 
-vndk_lib_md5 :=
-vndk_lib_dep :=
 llndk_libraries :=
 vndk_sameprocess_libraries :=
 vndk_core_libraries :=
@@ -266,13 +269,8 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-llndk_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-llndk_dep = $(intermediates)/$(llndk_md5).dep
-$(llndk_dep):
-	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(LLNDK_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(llndk_dep)
+$(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
 	$(hide) echo -n > $@
@@ -287,13 +285,8 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-vndksp_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-vndksp_dep = $(intermediates)/$(vndksp_md5).dep
-$(vndksp_dep):
-	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(VNDK_SAMEPROCESS_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(vndksp_dep)
+$(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
 	$(hide) echo -n > $@
diff --git a/rootdir/OWNERS b/rootdir/OWNERS
new file mode 100644
index 0000000..f335715
--- /dev/null
+++ b/rootdir/OWNERS
@@ -0,0 +1,3 @@
+jiyong@google.com
+smoreland@google.com
+tomcherry@google.com
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index cd1bd82..2d05fca 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -51,7 +51,7 @@
 namespace.sphal.isolated = true
 namespace.sphal.visible = true
 namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp${VNDK_VER}/hw
 
 namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -79,14 +79,17 @@
 ###############################################################################
 namespace.rs.isolated = true
 namespace.rs.visible = true
-namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}
 namespace.rs.permitted.paths = /vendor/${LIB}:/data
 
-namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
 
 namespace.rs.links = default,vndk
 namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
 namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
 ###############################################################################
@@ -96,10 +99,10 @@
 ###############################################################################
 namespace.vndk.isolated = true
 namespace.vndk.visible = true
-namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
 
-namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
 
 # When these NDK libs are required inside this namespace, then it is redirected
@@ -120,28 +123,31 @@
 ###############################################################################
 # "default" namespace
 #
-# Vendor-side code runs in this namespace.
+# This is the default linker namespace for a vendor process (a process started
+# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
+# are loaded directly into this namespace. However, other libs under the system
+# partition (VNDK and LLNDK libraries) are not loaded here but from the
+# separate namespace 'system'. The delegation to the system namespace is done
+# via the 'namespace.default.link.system.shared_libs' property below.
 ###############################################################################
 namespace.default.isolated = true
 namespace.default.visible = true
 
-namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}
+namespace.default.permitted.paths = /vendor
 
-namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk${VNDK_VER}:/data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor
 
 namespace.default.links = system
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:%VNDK_SAMEPROCESS_LIBRARIES%:%VNDK_CORE_LIBRARIES%
 
 ###############################################################################
 # "system" namespace
 #
-# This is for vendor process to use LL-NDK in system partition.
+# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
+# a vendor process.
 ###############################################################################
 namespace.system.isolated = false
-namespace.system.search.paths = /system/${LIB}
-namespace.system.permitted.paths = /system/${LIB}
+namespace.system.search.paths = /system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}
 
-namespace.system.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
-namespace.system.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.system.asan.search.paths = /data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 51a8d2b..5fa77d8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -48,8 +48,10 @@
     copy /proc/cmdline /dev/urandom
     copy /default.prop /dev/urandom
 
-    # Backward compatibility.
+    symlink /system/bin /bin
     symlink /system/etc /etc
+
+    # Backward compatibility.
     symlink /sys/kernel/debug /d
 
     # Link /vendor to /system/vendor for devices without a vendor partition.
diff --git a/sdcard/OWNERS b/sdcard/OWNERS
new file mode 100644
index 0000000..199a0f8
--- /dev/null
+++ b/sdcard/OWNERS
@@ -0,0 +1 @@
+drosen@google.com
diff --git a/shell_and_utilities/OWNERS b/shell_and_utilities/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/shell_and_utilities/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/storaged/OWNERS b/storaged/OWNERS
new file mode 100644
index 0000000..7445270
--- /dev/null
+++ b/storaged/OWNERS
@@ -0,0 +1 @@
+jinqian@google.com
diff --git a/toolbox/OWNERS b/toolbox/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/toolbox/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/trusty/OWNERS b/trusty/OWNERS
new file mode 100644
index 0000000..25291fd
--- /dev/null
+++ b/trusty/OWNERS
@@ -0,0 +1 @@
+bohr@google.com