Merge "Prevent vendors from accessing private VNDK libs"
diff --git a/adb/OVERVIEW.TXT b/adb/OVERVIEW.TXT
index c40695a..29a6992 100644
--- a/adb/OVERVIEW.TXT
+++ b/adb/OVERVIEW.TXT
@@ -7,16 +7,16 @@
 - keep track of all Android devices and emulators instances
   connected to or running on a given host developer machine
 
-- implement various control commands (e.g. "adb shell", "adb pull", etc..)
+- implement various control commands (e.g. "adb shell", "adb pull", etc.)
   for the benefit of clients (command-line users, or helper programs like
-  DDMS). These commands are what is called a 'service' in ADB.
+  DDMS). These commands are called 'services' in ADB.
 
 As a whole, everything works through the following components:
 
   1. The ADB server
 
     This is a background process that runs on the host machine. Its purpose
-    if to sense the USB ports to know when devices are attached/removed,
+    is to sense the USB ports to know when devices are attached/removed,
     as well as when emulator instances start/stop.
 
     It thus maintains a list of "connected devices" and assigns a 'state'
@@ -40,7 +40,7 @@
     meaning that the ADB server detected a new device/emulator, but could not
     connect to the adbd daemon.
 
-    the BOOTLOADER and RECOVERY states correspond to alternate states of
+    The BOOTLOADER and RECOVERY states correspond to alternate states of
     devices when they are in the bootloader or recovery mode.
 
   3. The ADB command-line client
@@ -49,8 +49,7 @@
     or a script. It first tries to locate the ADB server on the host machine,
     and will start one automatically if none is found.
 
-    then, the client sends its service requests to the ADB server. It doesn't
-    need to know.
+    Then, the client sends its service requests to the ADB server.
 
     Currently, a single 'adb' binary is used for both the server and client.
     this makes distribution and starting the server easier.
@@ -61,13 +60,13 @@
     There are essentially two kinds of services that a client can talk to.
 
     Host Services:
-      these services run within the ADB Server and thus do not need to
+      These services run within the ADB Server and thus do not need to
       communicate with a device at all. A typical example is "adb devices"
       which is used to return the list of currently known devices and their
-      state. They are a few couple other services though.
+      states. They are a few other services though.
 
     Local Services:
-      these services either run within the adbd daemon, or are started by
+      These services either run within the adbd daemon, or are started by
       it on the device. The ADB server is used to multiplex streams
       between the client and the service running in adbd. In this case
       its role is to initiate the connection, then of being a pass-through
@@ -109,7 +108,7 @@
 
     Note that the connection is still alive after an OKAY, which allows the
     client to make other requests. But in certain cases, an OKAY will even
-    change the state of the connection. 
+    change the state of the connection.
 
     For example, the case of the 'host:transport:<serialnumber>' request,
     where '<serialnumber>' is used to identify a given device/emulator; after
diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT
index 06d7804..4445a76 100644
--- a/adb/SYNC.TXT
+++ b/adb/SYNC.TXT
@@ -1,4 +1,4 @@
-This file tries to document file related requests a client can make
+This file tries to document file-related requests a client can make
 to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
 to understand what's going on here. See the SERVICES.TXT to learn more
 about the other requests that are possible.
@@ -8,16 +8,16 @@
 
 Requesting the sync service ("sync:") using the protocol as described in
 SERVICES.TXT sets the connection in sync mode. This mode is a binary mode that
-differ from the regular adb protocol. The connection stays in sync mode until
+differs from the regular adb protocol. The connection stays in sync mode until
 explicitly terminated (see below).
 
 After the initial "sync:" command is sent the server must respond with either
-"OKAY" or "FAIL" as per usual. 
+"OKAY" or "FAIL" as per usual.
 
 In sync mode both the server and the client will frequently use eight-byte
-packets to communicate in this document called sync request and sync
-responses. The first four bytes is an id and specifies sync request is
-represented by four utf-8 characters. The last four bytes is a Little-Endian
+packets to communicate. In this document these are called sync requests and sync
+responses. The first four bytes are an id that specifies the sync request. It is
+represented by four utf-8 characters. The last four bytes are a Little-Endian
 integer, with various uses. This number will be called "length" below. In fact
 all binary integers are Little-Endian in the sync mode. Sync mode is
 implicitly exited after each sync request, and normal adb communication
@@ -29,8 +29,8 @@
 SEND - Send a file to device
 STAT - Stat a file
 
-For all of the sync request above the must be followed by length number of
-bytes containing an utf-8 string with a remote filename.
+All of the sync requests above must be followed by "length": the number of
+bytes containing a utf-8 string with a remote filename.
 
 LIST:
 Lists files in the directory specified by the remote filename. The server will
@@ -45,7 +45,7 @@
 6. length number of bytes containing an utf-8 string representing the file
    name.
 
-When an sync response "DONE" is received the listing is done.
+When a sync response "DONE" is received the listing is done.
 
 SEND:
 The remote file name is split into two parts separated by the last
@@ -65,7 +65,7 @@
 
 When the file is transferred a sync request "DONE" is sent, where length is set
 to the last modified time for the file. The server responds to this last
-request (but not to chuck requests) with an "OKAY" sync response (length can
+request (but not to chunk requests) with an "OKAY" sync response (length can
 be ignored).
 
 
@@ -73,9 +73,8 @@
 Retrieves a file from device to a local file. The remote path is the path to
 the file that will be returned. Just as for the SEND sync request the file
 received is split up into chunks. The sync response id is "DATA" and length is
-the chuck size. After follows chunk size number of bytes. This is repeated
-until the file is transferred. Each chuck will not be larger than 64k.
+the chunk size. After follows chunk size number of bytes. This is repeated
+until the file is transferred. Each chunk will not be larger than 64k.
 
 When the file is transferred a sync response "DONE" is retrieved where the
 length can be ignored.
-
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index c6f3e66..9a87931 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -62,7 +62,7 @@
     }
 
     vfs_cap_data cap_data = {};
-    cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+    cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
     cap_data.data[0].permitted = (capabilities & 0xffffffff);
     cap_data.data[0].inheritable = 0;
     cap_data.data[1].permitted = (capabilities >> 32);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0abb680..307be6d 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -31,6 +31,7 @@
 
 // Include this before open/close/unlink are defined as macros below.
 #include <android-base/errors.h>
+#include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 #include <android-base/utf8.h>
 
@@ -38,21 +39,6 @@
 #include "sysdeps/network.h"
 #include "sysdeps/stat.h"
 
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({         \
-    typeof (exp) _rc;                      \
-    do {                                   \
-        _rc = (exp);                       \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc; })
-#endif
-
 // Some printf-like functions are implemented in terms of
 // android::base::StringAppendV, so they should use the same attribute for
 // compile-time format string checking. On Windows, if the mingw version of
diff --git a/base/Android.bp b/base/Android.bp
index 7ff02a0..ad0edf4 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -129,6 +129,7 @@
         },
         windows: {
             srcs: ["utf8_test.cpp"],
+            cflags: ["-Wno-unused-parameter"],
             enabled: true,
         },
     },
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index adb041b..6f05d9b 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -192,6 +192,7 @@
 #undef CHECK_WOULD_LOG_ENABLED
 
 
+#if !defined(_WIN32)
 static std::string make_log_pattern(android::base::LogSeverity severity,
                                     const char* message) {
   static const char log_characters[] = "VDIWEFF";
@@ -203,6 +204,7 @@
       "%c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s:\\d+] %s",
       log_char, basename(&holder[0]), message);
 }
+#endif
 
 static void CheckMessage(const CapturedStderr& cap,
                          android::base::LogSeverity severity, const char* expected) {
diff --git a/base/utf8.cpp b/base/utf8.cpp
index 5984fb0..adb46d0 100644
--- a/base/utf8.cpp
+++ b/base/utf8.cpp
@@ -195,7 +195,7 @@
   return _wfopen(name_utf16.c_str(), mode_utf16.c_str());
 }
 
-int mkdir(const char* name, mode_t mode) {
+int mkdir(const char* name, mode_t) {
   std::wstring name_utf16;
   if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
     return -1;
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 2d34e2d..8db9121 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -228,6 +228,24 @@
     {"reboot,its_just_so_hard", 88},  // produced by boot_reason_test
     {"reboot,Its Just So Hard", 89},  // produced by boot_reason_test
     {"usb", 90},
+    {"charge", 91},
+    {"oem_tz_crash", 92},
+    {"uvlo", 93},
+    {"oem_ps_hold", 94},
+    {"abnormal_reset", 95},
+    {"oemerr_unknown", 96},
+    {"reboot_fastboot_mode", 97},
+    {"watchdog_apps_bite", 98},
+    {"xpu_err", 99},
+    {"power_on_usb", 100},
+    {"watchdog_rpm", 101},
+    {"watchdog_nonsec", 102},
+    {"watchdog_apps_bark", 103},
+    {"reboot_dmverity_corrupted", 104},
+    {"reboot_smpl", 105},
+    {"watchdog_sdi_apps_reset", 106},
+    {"smpl", 107},
+    {"oem_modem_failed_to_powerup", 108},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 7723ec6..b0b2337 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
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid make_f2fs
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -66,8 +66,6 @@
     libcutils \
     libgtest_host \
 
-LOCAL_CFLAGS_linux := -DUSE_F2FS
-
 LOCAL_CXX_STL := libc++_static
 
 # Don't add anything here, we don't want additional shared dependencies
@@ -80,6 +78,7 @@
 my_dist_files := $(LOCAL_BUILT_MODULE)
 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)
 $(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/fs.cpp b/fastboot/fs.cpp
index 8877b09..4bf7af8 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -27,7 +27,7 @@
 using android::base::unique_fd;
 
 #ifdef WIN32
-static int exec_e2fs_cmd(const char* path, char* const argv[]) {
+static int exec_e2fs_cmd(const char* /*path*/, char* const argv[]) {
     std::string cmd;
     int i = 0;
     while (argv[i] != nullptr) {
@@ -154,10 +154,10 @@
     return 0;
 }
 
-#ifdef USE_F2FS
 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()};
@@ -180,12 +180,16 @@
     }
 
     if (!initial_dir.empty()) {
-        fprintf(stderr, "Unable to set initial directory on F2FS filesystem: %s\n", strerror(errno));
-        return -1;
+        fprintf(stderr, "sload.f2s not supported yet\n");
+        return 0;
     }
     return 0;
-}
+#else
+    UNUSED(fileName, partSize, initial_dir);
+    fprintf(stderr, "make_f2fs not supported on Windows\n");
+    return -1;
 #endif
+}
 
 static const struct fs_generator {
     const char* fs_type;  //must match what fastboot reports for partition type
@@ -196,9 +200,7 @@
 
 } generators[] = {
     { "ext4", generate_ext4_image},
-#ifdef USE_F2FS
     { "f2fs", generate_f2fs_image},
-#endif
 };
 
 const struct fs_generator* fs_get_generator(const std::string& fs_type) {
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 28f0b07..6d5d1ea 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -32,6 +32,7 @@
 	libbase \
 	libutils \
 	libcrypto \
+	libkeystore_aidl \
 	libkeystore_binder \
 	libhidlbase \
 	libhidltransport \
diff --git a/healthd/Android.bp b/healthd/Android.bp
index ed1413e..ea59469 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -9,6 +9,7 @@
 cc_library_static {
     name: "libbatterymonitor",
     srcs: ["BatteryMonitor.cpp"],
+    cflags: ["-Wall", "-Werror"],
     vendor_available: true,
     export_include_dirs: ["include"],
     shared_libs: [
@@ -27,7 +28,10 @@
         "healthd_common.cpp",
     ],
 
-    cflags: ["-DHEALTHD_USE_HEALTH_2_0"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     export_include_dirs: ["include"],
 
@@ -58,7 +62,11 @@
         "HealthServiceDefault.cpp",
     ],
 
-    cflags: ["-DHEALTH_INSTANCE_NAME=\"default\""],
+    cflags: [
+        "-DHEALTH_INSTANCE_NAME=\"default\"",
+        "-Wall",
+        "-Werror",
+    ],
 
     static_libs: [
         "android.hardware.health@2.0-impl",
@@ -86,7 +94,11 @@
     ],
     local_include_dirs: ["include"],
 
-    cflags: ["-DHEALTH_INSTANCE_NAME=\"backup\""],
+    cflags: [
+        "-DHEALTH_INSTANCE_NAME=\"backup\"",
+        "-Wall",
+        "-Werror",
+    ],
 
     static_libs: [
         "android.hardware.health@2.0-impl",
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 5f10f1e..63c9d27 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -89,12 +89,6 @@
 ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 LOCAL_CFLAGS += -DCHARGER_NO_UI
 endif
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-endif
-ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
-LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-endif
 
 CHARGER_STATIC_LIBRARIES := \
     android.hardware.health@2.0-impl \
diff --git a/healthd/charger_test.cpp b/healthd/charger_test.cpp
index acc0f5b..a7e2161 100644
--- a/healthd/charger_test.cpp
+++ b/healthd/charger_test.cpp
@@ -27,7 +27,7 @@
 #include <thread>
 #include <vector>
 
-#include <healthd/healthd.h>
+#include <health2/Health.h>
 
 #define LOG_THIS(fmt, ...)     \
     ALOGE(fmt, ##__VA_ARGS__); \
@@ -97,6 +97,16 @@
     return status;
 }
 
+::android::hardware::hidl_handle createHidlHandle(const char* filepath) {
+    int fd = creat(filepath, S_IRUSR | S_IWUSR);
+    if (fd < 0) return {};
+    native_handle_t* nativeHandle = native_handle_create(1, 0);
+    nativeHandle->data[0] = fd;
+    ::android::hardware::hidl_handle handle;
+    handle.setTo(nativeHandle, true /* shouldOwn */);
+    return handle;
+}
+
 void healthd_board_init(struct healthd_config* config) {
     config->periodic_chores_interval_fast = 60;
     config->periodic_chores_interval_slow = 600;
@@ -129,6 +139,8 @@
 extern int healthd_charger_main(int argc, char** argv);
 
 int main(int argc, char** argv) {
+    using android::hardware::health::V2_0::implementation::Health;
+
     const char* dumpFile = "/data/local/tmp/dump.txt";
 
     std::thread bgThread([=] {
@@ -141,12 +153,7 @@
         exit(1);
     }
 
-    int fd = creat(dumpFile, S_IRUSR | S_IWUSR);
-    if (fd < 0) {
-        exit(errno);
-    }
-    healthd_dump_battery_state(fd);
-    close(fd);
+    Health::getImplementation()->debug(createHidlHandle(dumpFile), {} /* options */);
 
     std::string content = openToString(dumpFile);
     int status = expectContains(content, {
diff --git a/healthd/healthd_common.cpp b/healthd/healthd_common.cpp
index 140c49d..3006644 100644
--- a/healthd/healthd_common.cpp
+++ b/healthd/healthd_common.cpp
@@ -33,25 +33,14 @@
 #include <sys/timerfd.h>
 #include <utils/Errors.h>
 
-#ifdef HEALTHD_USE_HEALTH_2_0
 #include <health2/Health.h>
-#endif
 
 using namespace android;
 
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
-  // Periodic chores fast interval in seconds
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-#else
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-#endif
-
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
-  // Periodic chores fast interval in seconds
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
-#else
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-#endif
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
 
 static struct healthd_config healthd_config = {
     .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
@@ -88,11 +77,7 @@
 
 static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
 
-#ifndef HEALTHD_USE_HEALTH_2_0
-static BatteryMonitor* gBatteryMonitor = nullptr;
-#else
 using ::android::hardware::health::V2_0::implementation::Health;
-#endif
 
 struct healthd_mode_ops *healthd_mode_ops = nullptr;
 
@@ -135,81 +120,6 @@
         KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
 }
 
-#ifdef HEALTHD_USE_HEALTH_2_0
-status_t convertStatus(android::hardware::health::V2_0::Result r) {
-    using android::hardware::health::V2_0::Result;
-    switch(r) {
-        case Result::SUCCESS:       return OK;
-        case Result::NOT_SUPPORTED: return BAD_VALUE;
-        case Result::NOT_FOUND:     return NAME_NOT_FOUND;
-        case Result::CALLBACK_DIED: return DEAD_OBJECT;
-        case Result::UNKNOWN: // fallthrough
-        default:
-            return UNKNOWN_ERROR;
-    }
-}
-#endif
-
-status_t healthd_get_property(int id, struct BatteryProperty *val) {
-#ifndef HEALTHD_USE_HEALTH_2_0
-    return gBatteryMonitor->getProperty(id, val);
-#else
-    using android::hardware::health::V1_0::BatteryStatus;
-    using android::hardware::health::V2_0::Result;
-    val->valueInt64 = INT64_MIN;
-    status_t err = UNKNOWN_ERROR;
-    switch (id) {
-        case BATTERY_PROP_CHARGE_COUNTER: {
-            Health::getImplementation()->getChargeCounter([&](Result r, int32_t v) {
-                err = convertStatus(r);
-                val->valueInt64 = v;
-            });
-            break;
-        }
-        case BATTERY_PROP_CURRENT_NOW: {
-            Health::getImplementation()->getCurrentNow([&](Result r, int32_t v) {
-                err = convertStatus(r);
-                val->valueInt64 = v;
-            });
-            break;
-        }
-        case BATTERY_PROP_CURRENT_AVG: {
-            Health::getImplementation()->getCurrentAverage([&](Result r, int32_t v) {
-                err = convertStatus(r);
-                val->valueInt64 = v;
-            });
-            break;
-        }
-        case BATTERY_PROP_CAPACITY: {
-            Health::getImplementation()->getCapacity([&](Result r, int32_t v) {
-                err = convertStatus(r);
-                val->valueInt64 = v;
-            });
-            break;
-        }
-        case BATTERY_PROP_ENERGY_COUNTER: {
-            Health::getImplementation()->getEnergyCounter([&](Result r, int64_t v) {
-                err = convertStatus(r);
-                val->valueInt64 = v;
-            });
-            break;
-        }
-        case BATTERY_PROP_BATTERY_STATUS: {
-            Health::getImplementation()->getChargeStatus([&](Result r, BatteryStatus v) {
-                err = convertStatus(r);
-                val->valueInt64 = static_cast<int64_t>(v);
-            });
-            break;
-        }
-        default: {
-            err = BAD_VALUE;
-            break;
-        }
-    }
-    return err;
-#endif
-}
-
 void healthd_battery_update_internal(bool charger_online) {
     // Fast wake interval when on charger (watch for overheat);
     // slow wake interval when on battery (watch for drained battery).
@@ -233,26 +143,8 @@
                 -1 : healthd_config.periodic_chores_interval_fast * 1000;
 }
 
-void healthd_battery_update(void) {
-#ifndef HEALTHD_USE_HEALTH_2_0
-    healthd_battery_update_internal(gBatteryMonitor->update());
-#else
+static void healthd_battery_update(void) {
     Health::getImplementation()->update();
-#endif
-}
-
-void healthd_dump_battery_state(int fd) {
-#ifndef HEALTHD_USE_HEALTH_2_0
-    gBatteryMonitor->dumpState(fd);
-#else
-    native_handle_t* nativeHandle = native_handle_create(1, 0);
-    nativeHandle->data[0] = fd;
-    ::android::hardware::hidl_handle handle;
-    handle.setTo(nativeHandle, true /* shouldOwn */);
-    Health::getImplementation()->debug(handle, {} /* options */);
-#endif
-
-    fsync(fd);
 }
 
 static void periodic_chores() {
@@ -368,21 +260,10 @@
         return -1;
     }
 
-#ifndef HEALTHD_USE_HEALTH_2_0
-    healthd_board_init(&healthd_config);
-#else
-    // healthd_board_* functions are removed in health@2.0
-#endif
-
     healthd_mode_ops->init(&healthd_config);
     wakealarm_init();
     uevent_init();
 
-#ifndef HEALTHD_USE_HEALTH_2_0
-    gBatteryMonitor = new BatteryMonitor();
-    gBatteryMonitor->init(&healthd_config);
-#endif
-
     return 0;
 }
 
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index 97c7a8c..c01e8d7 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -81,15 +81,6 @@
 // Global helper functions
 
 int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD);
-void healthd_battery_update();
-
-// deprecated.
-// TODO(b/62229583): This function should be removed since it is only used by
-// BatteryPropertiesRegistrar.
-android::status_t healthd_get_property(int id,
-    struct android::BatteryProperty *val);
-
-void healthd_dump_battery_state(int fd);
 
 struct healthd_mode_ops {
     void (*init)(struct healthd_config *config);
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 950a551..f584021 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -65,6 +65,7 @@
 #include "property_service.h"
 #include "reboot.h"
 #include "rlimit_parser.h"
+#include "selinux.h"
 #include "service.h"
 #include "subcontext.h"
 #include "util.h"
@@ -641,8 +642,26 @@
     return Success();
 }
 
+static int MakeSymlink(const std::string& target, const std::string& linkpath) {
+    std::string secontext;
+    // Passing 0 for mode should work.
+    if (SelabelLookupFileContext(linkpath, 0, &secontext) && !secontext.empty()) {
+        setfscreatecon(secontext.c_str());
+    }
+
+    int rc = symlink(target.c_str(), linkpath.c_str());
+
+    if (!secontext.empty()) {
+        int save_errno = errno;
+        setfscreatecon(nullptr);
+        errno = save_errno;
+    }
+
+    return rc;
+}
+
 static Result<Success> do_symlink(const BuiltinArguments& args) {
-    if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
+    if (MakeSymlink(args[1], args[2]) < 0) {
         // The symlink builtin is often used to create symlinks for older devices to be backwards
         // compatible with new paths, therefore we skip reporting this error.
         if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 642a364..50987db 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -194,5 +194,18 @@
     return SetAmbientCaps(to_keep);
 }
 
+bool DropInheritableCaps() {
+    ScopedCaps caps(cap_get_proc());
+    if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) {
+        PLOG(ERROR) << "cap_clear_flag(INHERITABLE) failed";
+        return false;
+    }
+    if (cap_set_proc(caps.get()) != 0) {
+        PLOG(ERROR) << "cap_set_proc() failed";
+        return false;
+    }
+    return true;
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/capabilities.h b/init/capabilities.h
index ede85c3..fc80c98 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -35,6 +35,7 @@
 bool CapAmbientSupported();
 unsigned int GetLastValidCap();
 bool SetCapsForExec(const CapSet& to_keep);
+bool DropInheritableCaps();
 
 }  // namespace init
 }  // namespace android
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 3f9f7f4..21010b0 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -302,18 +302,18 @@
     }
     std::string mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
 
-    // vendor_sepolicy.cil and nonplat_declaration.cil are the new design to replace
+    // vendor_sepolicy.cil and plat_pub_versioned.cil are the new design to replace
     // nonplat_sepolicy.cil.
-    std::string nonplat_declaration_cil_file("/vendor/etc/selinux/nonplat_declaration.cil");
+    std::string plat_pub_versioned_cil_file("/vendor/etc/selinux/plat_pub_versioned.cil");
     std::string vendor_policy_cil_file("/vendor/etc/selinux/vendor_sepolicy.cil");
 
     if (access(vendor_policy_cil_file.c_str(), F_OK) == -1) {
         // For backward compatibility.
         // TODO: remove this after no device is using nonplat_sepolicy.cil.
         vendor_policy_cil_file = "/vendor/etc/selinux/nonplat_sepolicy.cil";
-        nonplat_declaration_cil_file.clear();
-    } else if (access(nonplat_declaration_cil_file.c_str(), F_OK) == -1) {
-        LOG(ERROR) << "Missing " << nonplat_declaration_cil_file;
+        plat_pub_versioned_cil_file.clear();
+    } else if (access(plat_pub_versioned_cil_file.c_str(), F_OK) == -1) {
+        LOG(ERROR) << "Missing " << plat_pub_versioned_cil_file;
         return false;
     }
 
@@ -338,8 +338,8 @@
     };
     // clang-format on
 
-    if (!nonplat_declaration_cil_file.empty()) {
-        compile_args.push_back(nonplat_declaration_cil_file.c_str());
+    if (!plat_pub_versioned_cil_file.empty()) {
+        compile_args.push_back(plat_pub_versioned_cil_file.c_str());
     }
     if (!vendor_policy_cil_file.empty()) {
         compile_args.push_back(vendor_policy_cil_file.c_str());
diff --git a/init/service.cpp b/init/service.cpp
index 481df65..331b859 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -291,6 +291,11 @@
         if (!SetCapsForExec(capabilities_)) {
             LOG(FATAL) << "cannot set capabilities for " << name_;
         }
+    } else if (uid_) {
+        // Inheritable caps can be non-zero when running in a container.
+        if (!DropInheritableCaps()) {
+            LOG(FATAL) << "cannot drop inheritable caps for " << name_;
+        }
     }
 }
 
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 84feeee..068be6e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -23,7 +23,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <selinux/android.h>
 
@@ -32,7 +31,6 @@
 #include "system/core/init/subcontext.pb.h"
 #include "util.h"
 
-using android::base::GetBoolProperty;
 using android::base::GetExecutablePath;
 using android::base::Join;
 using android::base::Socketpair;
@@ -262,13 +260,11 @@
 static std::vector<Subcontext> subcontexts;
 
 std::vector<Subcontext>* InitializeSubcontexts() {
-    if (GetBoolProperty("ro.init.subcontexts_enabled", false)) {
-        static const char* const paths_and_secontexts[][2] = {
-            {"/vendor", kVendorContext.c_str()},
-        };
-        for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
-            subcontexts.emplace_back(path_prefix, secontext);
-        }
+    static const char* const paths_and_secontexts[][2] = {
+        {"/vendor", kVendorContext.c_str()},
+    };
+    for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
+        subcontexts.emplace_back(path_prefix, secontext);
     }
     return &subcontexts;
 }
diff --git a/init/util.cpp b/init/util.cpp
index a19a6f3..d80cb1e 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -178,9 +178,26 @@
     return content;
 }
 
+static int OpenFile(const std::string& path, int flags, mode_t mode) {
+    std::string secontext;
+    if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
+        setfscreatecon(secontext.c_str());
+    }
+
+    int rc = open(path.c_str(), flags, mode);
+
+    if (!secontext.empty()) {
+        int save_errno = errno;
+        setfscreatecon(nullptr);
+        errno = save_errno;
+    }
+
+    return rc;
+}
+
 Result<Success> WriteFile(const std::string& path, const std::string& content) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-        open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
+        OpenFile(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
     if (fd == -1) {
         return ErrnoError() << "open() failed";
     }
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 25e5002..9ac0a0b 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -44,15 +44,15 @@
   }
 
   // Iterate through the maps and fill in the backtrace_map_t structure.
-  for (auto& map_info : *stack_maps_) {
+  for (auto* map_info : *stack_maps_) {
     backtrace_map_t map;
-    map.start = map_info.start;
-    map.end = map_info.end;
-    map.offset = map_info.offset;
+    map.start = map_info->start;
+    map.end = map_info->end;
+    map.offset = map_info->offset;
     // Set to -1 so that it is demand loaded.
     map.load_bias = static_cast<uintptr_t>(-1);
-    map.flags = map_info.flags;
-    map.name = map_info.name;
+    map.flags = map_info->flags;
+    map.name = map_info->name;
 
     maps_.push_back(map);
   }
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 0a60ec4..9911e74 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -77,6 +77,7 @@
 
 struct dump_thread_t {
   thread_t thread;
+  BacktraceMap* map;
   Backtrace* backtrace;
   int32_t* now;
   int32_t done;
@@ -632,7 +633,7 @@
   }
 
   // The status of the actual unwind will be checked elsewhere.
-  dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid);
+  dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid, dump->map);
   dump->backtrace->Unwind(0);
 
   android_atomic_acquire_store(1, &dump->done);
@@ -640,8 +641,8 @@
   return nullptr;
 }
 
-TEST(libbacktrace, thread_multiple_dump) {
-  // Dump NUM_THREADS simultaneously.
+static void MultipleThreadDumpTest(bool share_map) {
+  // Dump NUM_THREADS simultaneously using the same map.
   std::vector<thread_t> runners(NUM_THREADS);
   std::vector<dump_thread_t> dumpers(NUM_THREADS);
 
@@ -662,12 +663,17 @@
 
   // Start all of the dumpers at once, they will spin until they are signalled
   // to begin their dump run.
+  std::unique_ptr<BacktraceMap> map;
+  if (share_map) {
+    map.reset(BacktraceMap::Create(getpid()));
+  }
   int32_t dump_now = 0;
   for (size_t i = 0; i < NUM_THREADS; i++) {
     dumpers[i].thread.tid = runners[i].tid;
     dumpers[i].thread.state = 0;
     dumpers[i].done = 0;
     dumpers[i].now = &dump_now;
+    dumpers[i].map = map.get();
 
     ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
   }
@@ -689,47 +695,12 @@
   }
 }
 
-TEST(libbacktrace, thread_multiple_dump_same_thread) {
-  pthread_attr_t attr;
-  pthread_attr_init(&attr);
-  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  thread_t runner;
-  runner.tid = 0;
-  runner.state = 0;
-  ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
+TEST(libbacktrace, thread_multiple_dump) {
+  MultipleThreadDumpTest(false);
+}
 
-  // Wait for tids to be set.
-  ASSERT_TRUE(WaitForNonZero(&runner.state, 30));
-
-  // Start all of the dumpers at once, they will spin until they are signalled
-  // to begin their dump run.
-  int32_t dump_now = 0;
-  // Dump the same thread NUM_THREADS simultaneously.
-  std::vector<dump_thread_t> dumpers(NUM_THREADS);
-  for (size_t i = 0; i < NUM_THREADS; i++) {
-    dumpers[i].thread.tid = runner.tid;
-    dumpers[i].thread.state = 0;
-    dumpers[i].done = 0;
-    dumpers[i].now = &dump_now;
-
-    ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
-  }
-
-  // Start all of the dumpers going at once.
-  android_atomic_acquire_store(1, &dump_now);
-
-  for (size_t i = 0; i < NUM_THREADS; i++) {
-    ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
-
-    ASSERT_TRUE(dumpers[i].backtrace != nullptr);
-    VerifyMaxDump(dumpers[i].backtrace);
-
-    delete dumpers[i].backtrace;
-    dumpers[i].backtrace = nullptr;
-  }
-
-  // Tell the runner thread to exit its infinite loop.
-  android_atomic_acquire_store(0, &runner.state);
+TEST(libbacktrace, thread_multiple_dump_same_map) {
+  MultipleThreadDumpTest(true);
 }
 
 // This test is for UnwindMaps that should share the same map cursor when
diff --git a/libcutils/android_reboot.cpp b/libcutils/android_reboot.cpp
index 5e864d4..ce41cd3 100644
--- a/libcutils/android_reboot.cpp
+++ b/libcutils/android_reboot.cpp
@@ -23,7 +23,7 @@
 
 #define TAG "android_reboot"
 
-int android_reboot(int cmd, int flags __unused, const char* arg) {
+int android_reboot(int cmd, int /*flags*/, const char* arg) {
     int ret;
     const char* restart_cmd = NULL;
     char* prop_value;
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index d2c28f3..b2bec99 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -35,12 +35,7 @@
 
 #include <utils/Compat.h>
 
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
-int ashmem_create_region(const char *ignored __unused, size_t size)
-{
+int ashmem_create_region(const char* /*ignored*/, size_t size) {
     char pattern[PATH_MAX];
     snprintf(pattern, sizeof(pattern), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid());
     int fd = mkstemp(pattern);
@@ -56,18 +51,15 @@
     return fd;
 }
 
-int ashmem_set_prot_region(int fd __unused, int prot __unused)
-{
+int ashmem_set_prot_region(int /*fd*/, int /*prot*/) {
     return 0;
 }
 
-int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
-{
+int ashmem_pin_region(int /*fd*/, size_t /*offset*/, size_t /*len*/) {
     return 0 /*ASHMEM_NOT_PURGED*/;
 }
 
-int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
-{
+int ashmem_unpin_region(int /*fd*/, size_t /*offset*/, size_t /*len*/) {
     return 0 /*ASHMEM_IS_UNPINNED*/;
 }
 
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 0e6d333..f5ce82f 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -27,8 +27,6 @@
 
 #include <log/log.h>
 
-#define UNUSED __attribute__((__unused__))
-
 /* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
  * Call this any place a SchedPolicy is used as an input parameter.
  * Returns the possibly re-mapped policy.
@@ -445,13 +443,11 @@
 
 /* Stubs for non-Android targets. */
 
-int set_sched_policy(int tid UNUSED, SchedPolicy policy UNUSED)
-{
+int set_sched_policy(int /*tid*/, SchedPolicy /*policy*/) {
     return 0;
 }
 
-int get_sched_policy(int tid UNUSED, SchedPolicy *policy)
-{
+int get_sched_policy(int /*tid*/, SchedPolicy* policy) {
     *policy = SP_SYSTEM_DEFAULT;
     return 0;
 }
diff --git a/libcutils/socket_local_client_unix.cpp b/libcutils/socket_local_client_unix.cpp
index 68b2b0c..d2b4909 100644
--- a/libcutils/socket_local_client_unix.cpp
+++ b/libcutils/socket_local_client_unix.cpp
@@ -39,8 +39,6 @@
 
 #include "socket_local_unix.h"
 
-#define UNUSED __attribute__((unused))
-
 #define LISTEN_BACKLOG 4
 
 /* Documented in header file. */
@@ -123,9 +121,7 @@
  * 
  * Used by AndroidSocketImpl
  */
-int socket_local_client_connect(int fd, const char *name, int namespaceId, 
-        int type UNUSED)
-{
+int socket_local_client_connect(int fd, const char* name, int namespaceId, int /*type*/) {
     struct sockaddr_un addr;
     socklen_t alen;
     int err;
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index 3e49b85..df14712 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -85,6 +85,6 @@
     return -1;
 }
 
-int android_get_control_socket(const char* name) {
+int android_get_control_socket(const char*) {
     return -1;
 }
diff --git a/libcutils/str_parms.cpp b/libcutils/str_parms.cpp
index 139d62f..f5a52a7 100644
--- a/libcutils/str_parms.cpp
+++ b/libcutils/str_parms.cpp
@@ -30,8 +30,6 @@
 #include <cutils/memory.h>
 #include <log/log.h>
 
-#define UNUSED __attribute__((unused))
-
 /* When an object is allocated but not freed in a function,
  * because its ownership is released to other object like a hashmap,
  * call RELEASE_OWNERSHIP to tell the clang analyzer and avoid
@@ -364,8 +362,7 @@
     return str;
 }
 
-static bool dump_entry(void *key, void *value, void *context UNUSED)
-{
+static bool dump_entry(void* key, void* value, void* /*context*/) {
     ALOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
     return true;
 }
diff --git a/libcutils/threads.cpp b/libcutils/threads.cpp
index beea8bd..a7e6b2d 100644
--- a/libcutils/threads.cpp
+++ b/libcutils/threads.cpp
@@ -84,7 +84,7 @@
 
 void   thread_store_set( thread_store_t*          store,
                          void*                    value,
-                         thread_store_destruct_t  destroy )
+                         thread_store_destruct_t  /*destroy*/ )
 {
     /* XXX: can't use destructor on thread exit */
     if (!store->lock_init) {
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index 05842cd..d47cc18 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -16,21 +16,17 @@
 
 #include <cutils/trace.h>
 
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
 atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(true);
 int                     atrace_marker_fd     = -1;
 uint64_t                atrace_enabled_tags  = 0;
 
-void atrace_set_debuggable(bool debuggable __unused) { }
-void atrace_set_tracing_enabled(bool enabled __unused) { }
+void atrace_set_debuggable(bool /*debuggable*/) {}
+void atrace_set_tracing_enabled(bool /*enabled*/) {}
 void atrace_update_tags() { }
 void atrace_setup() { }
-void atrace_begin_body(const char* name __unused) { }
+void atrace_begin_body(const char* /*name*/) {}
 void atrace_end_body() { }
-void atrace_async_begin_body(const char* name __unused, int32_t cookie __unused) { }
-void atrace_async_end_body(const char* name __unused, int32_t cookie __unused) { }
-void atrace_int_body(const char* name __unused, int32_t value __unused) { }
-void atrace_int64_body(const char* name __unused, int64_t value __unused) { }
+void atrace_async_begin_body(const char* /*name*/, int32_t /*cookie*/) {}
+void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
+void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
+void atrace_int64_body(const char* /*name*/, int64_t /*value*/) {}
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 83064fd..2e2bf87 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -25,9 +25,9 @@
 #include <string.h>
 #include <sys/mman.h>
 
-#include <experimental/string_view>
 #include <functional>
 #include <string>
+#include <string_view>
 #include <unordered_map>
 
 #include <log/event_tag_map.h>
@@ -44,10 +44,10 @@
 class MapString {
  private:
   const std::string* alloc;                  // HAS-AN
-  const std::experimental::string_view str;  // HAS-A
+  const std::string_view str;                // HAS-A
 
  public:
-  operator const std::experimental::string_view() const {
+  operator const std::string_view() const {
     return str;
   }
 
@@ -92,8 +92,7 @@
     : public std::unary_function<const MapString&, size_t> {
   size_t operator()(const MapString& __t) const noexcept {
     if (!__t.length()) return 0;
-    return std::hash<std::experimental::string_view>()(
-        std::experimental::string_view(__t));
+    return std::hash<std::string_view>()(std::string_view(__t));
   }
 };
 
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 589ce84..d03a2b6 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -270,7 +270,7 @@
       /* If only we could reset downstream logd counter */
       return -EPERM;
     }
-  } else if (log_id == LOG_ID_EVENTS) {
+  } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
     const char* tag;
     size_t len;
     EventTagMap *m, *f;
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 00b1ee2..7f92904 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -501,6 +501,8 @@
         asprintf(&mParams[0], "INTERFACE=%s", ifname);
         asprintf(&mParams[1], "LIFETIME=%u", lifetime);
         mParams[2] = buf;
+    } else if (opthdr->nd_opt_type == ND_OPT_DNSSL) {
+        // TODO: support DNSSL.
     } else {
         SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
         return false;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 40364fe..75aa427 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -130,6 +130,7 @@
         "tests/RegsStepIfSignalHandlerTest.cpp",
         "tests/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
+        "tests/UnwindOfflineTest.cpp",
         "tests/UnwindTest.cpp",
         "tests/UnwinderTest.cpp",
     ],
@@ -153,6 +154,8 @@
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
+        "tests/files/offline/straddle_arm32/*",
+        "tests/files/offline/straddle_arm64/*",
     ],
 }
 
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 561d23a..2589c89 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -40,7 +40,7 @@
 
   uint64_t AdjustPcFromFde(uint64_t pc) override {
     // The eh_frame uses relative pcs.
-    return pc + this->memory_.cur_offset();
+    return pc + this->memory_.cur_offset() - 4;
   }
 };
 
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index 901f492..6ffdc0d 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -27,7 +27,7 @@
 namespace unwindstack {
 
 bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
-  if (!memory_->Read(cur_offset_, dst, num_bytes)) {
+  if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
     return false;
   }
   cur_offset_ += num_bytes;
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index b3fd0df..3b3d340 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -141,7 +141,7 @@
   // Read the address and dereference it.
   AddressType addr = StackPop();
   AddressType value;
-  if (!regular_memory()->Read(addr, &value, sizeof(value))) {
+  if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) {
     last_error_ = DWARF_ERROR_MEMORY_INVALID;
     return false;
   }
@@ -159,7 +159,7 @@
   // Read the address and dereference it.
   AddressType addr = StackPop();
   AddressType value = 0;
-  if (!regular_memory()->Read(addr, &value, bytes_to_read)) {
+  if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) {
     last_error_ = DWARF_ERROR_MEMORY_INVALID;
     return false;
   }
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 805dcd3..0954187 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -142,7 +142,7 @@
         return false;
       }
       if (loc->type == DWARF_LOCATION_EXPRESSION) {
-        if (!regular_memory->Read(value, &cfa, sizeof(AddressType))) {
+        if (!regular_memory->ReadFully(value, &cfa, sizeof(AddressType))) {
           last_error_ = DWARF_ERROR_MEMORY_INVALID;
           return false;
         }
@@ -175,7 +175,8 @@
     const DwarfLocation* loc = &entry.second;
     switch (loc->type) {
       case DWARF_LOCATION_OFFSET:
-        if (!regular_memory->Read(cfa + loc->values[0], &(*cur_regs)[reg], sizeof(AddressType))) {
+        if (!regular_memory->ReadFully(cfa + loc->values[0], &(*cur_regs)[reg],
+                                       sizeof(AddressType))) {
           last_error_ = DWARF_ERROR_MEMORY_INVALID;
           return false;
         }
@@ -210,7 +211,7 @@
           return false;
         }
         if (loc->type == DWARF_LOCATION_EXPRESSION) {
-          if (!regular_memory->Read(value, &(*cur_regs)[reg], sizeof(AddressType))) {
+          if (!regular_memory->ReadFully(value, &(*cur_regs)[reg], sizeof(AddressType))) {
             last_error_ = DWARF_ERROR_MEMORY_INVALID;
             return false;
           }
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index edf7ac2..97ade56 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -18,6 +18,7 @@
 #include <string.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 
 #define LOG_TAG "unwind"
@@ -87,6 +88,7 @@
 }
 
 bool Elf::GetSoname(std::string* name) {
+  std::lock_guard<std::mutex> guard(lock_);
   return valid_ && interface_->GetSoname(name);
 }
 
@@ -95,14 +97,15 @@
 }
 
 bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
+  std::lock_guard<std::mutex> guard(lock_);
   return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
                     (gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
                                                      addr, load_bias_, name, func_offset)));
 }
 
 // The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
-               bool* finished) {
+bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
+               Memory* process_memory, bool* finished) {
   if (!valid_) {
     return false;
   }
@@ -114,14 +117,16 @@
   }
 
   // Adjust the load bias to get the real relative pc.
-  if (rel_pc < load_bias_) {
+  if (adjusted_rel_pc < load_bias_) {
     return false;
   }
-  rel_pc -= load_bias_;
+  adjusted_rel_pc -= load_bias_;
 
-  return interface_->Step(rel_pc, regs, process_memory, finished) ||
+  // Lock during the step which can update information in the object.
+  std::lock_guard<std::mutex> guard(lock_);
+  return interface_->Step(adjusted_rel_pc, regs, process_memory, finished) ||
          (gnu_debugdata_interface_ &&
-          gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
+          gnu_debugdata_interface_->Step(adjusted_rel_pc, regs, process_memory, finished));
 }
 
 bool Elf::IsValidElf(Memory* memory) {
@@ -131,7 +136,7 @@
 
   // Verify that this is a valid elf file.
   uint8_t e_ident[SELFMAG + 1];
-  if (!memory->Read(0, e_ident, SELFMAG)) {
+  if (!memory->ReadFully(0, e_ident, SELFMAG)) {
     return false;
   }
 
@@ -151,7 +156,7 @@
 
   // Now read the section header information.
   uint8_t class_type;
-  if (!memory->Read(EI_CLASS, &class_type, 1)) {
+  if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
     return;
   }
   if (class_type == ELFCLASS32) {
@@ -169,12 +174,12 @@
   }
 
   std::unique_ptr<ElfInterface> interface;
-  if (!memory->Read(EI_CLASS, &class_type_, 1)) {
+  if (!memory->ReadFully(EI_CLASS, &class_type_, 1)) {
     return nullptr;
   }
   if (class_type_ == ELFCLASS32) {
     Elf32_Half e_machine;
-    if (!memory->Read(EI_NIDENT + sizeof(Elf32_Half), &e_machine, sizeof(e_machine))) {
+    if (!memory->ReadFully(EI_NIDENT + sizeof(Elf32_Half), &e_machine, sizeof(e_machine))) {
       return nullptr;
     }
 
@@ -195,7 +200,7 @@
     }
   } else if (class_type_ == ELFCLASS64) {
     Elf64_Half e_machine;
-    if (!memory->Read(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
+    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) {
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index d5d158f..9bdb094 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -53,7 +53,7 @@
   Crc64GenerateTable();
 
   std::vector<uint8_t> src(gnu_debugdata_size_);
-  if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
+  if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
     gnu_debugdata_offset_ = 0;
     gnu_debugdata_size_ = static_cast<uint64_t>(-1);
     return nullptr;
@@ -131,7 +131,7 @@
 template <typename EhdrType, typename PhdrType, typename ShdrType>
 bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
   EhdrType ehdr;
-  if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
+  if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
     return false;
   }
 
@@ -242,7 +242,7 @@
     }
 
     if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
-      if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
+      if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
         return false;
       }
       // Need to go get the information about the section that contains
@@ -324,7 +324,7 @@
   uint64_t offset = dynamic_offset_;
   uint64_t max_offset = offset + dynamic_size_;
   for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
-    if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
+    if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
       return false;
     }
 
@@ -388,7 +388,7 @@
 template <typename EhdrType>
 void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
   EhdrType ehdr;
-  if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
+  if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
     return;
   }
   if (ehdr.e_shnum == 0) {
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 140d05a..8a7ad9c 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -19,6 +19,7 @@
 #include <unistd.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 
 #include <unwindstack/Elf.h>
@@ -101,10 +102,13 @@
   if (!(flags & PROT_READ)) {
     return nullptr;
   }
-  return new MemoryRange(process_memory, start, end);
+  return new MemoryRange(process_memory, start, end - start, 0);
 }
 
 Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
+  // Make sure no other thread is trying to add the elf to this map.
+  std::lock_guard<std::mutex> guard(mutex_);
+
   if (elf) {
     return elf;
   }
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 5e1c0a2..56370c1 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -44,7 +44,7 @@
   size_t last = maps_.size();
   while (first < last) {
     size_t index = (first + last) / 2;
-    MapInfo* cur = &maps_[index];
+    MapInfo* cur = maps_[index];
     if (pc >= cur->start && pc < cur->end) {
       return cur;
     } else if (pc < cur->start) {
@@ -57,22 +57,22 @@
 }
 
 // Assumes that line does not end in '\n'.
-static bool InternalParseLine(const char* line, MapInfo* map_info) {
+static MapInfo* InternalParseLine(const char* line) {
   // Do not use a sscanf implementation since it is not performant.
 
   // Example linux /proc/<pid>/maps lines:
   // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
   char* str;
   const char* old_str = line;
-  map_info->start = strtoul(old_str, &str, 16);
+  uint64_t start = strtoull(old_str, &str, 16);
   if (old_str == str || *str++ != '-') {
-    return false;
+    return nullptr;
   }
 
   old_str = str;
-  map_info->end = strtoul(old_str, &str, 16);
+  uint64_t end = strtoull(old_str, &str, 16);
   if (old_str == str || !std::isspace(*str++)) {
-    return false;
+    return nullptr;
   }
 
   while (std::isspace(*str)) {
@@ -81,82 +81,81 @@
 
   // Parse permissions data.
   if (*str == '\0') {
-    return false;
+    return nullptr;
   }
-  map_info->flags = 0;
+  uint16_t flags = 0;
   if (*str == 'r') {
-    map_info->flags |= PROT_READ;
+    flags |= PROT_READ;
   } else if (*str != '-') {
-    return false;
+    return nullptr;
   }
   str++;
   if (*str == 'w') {
-    map_info->flags |= PROT_WRITE;
+    flags |= PROT_WRITE;
   } else if (*str != '-') {
-    return false;
+    return nullptr;
   }
   str++;
   if (*str == 'x') {
-    map_info->flags |= PROT_EXEC;
+    flags |= PROT_EXEC;
   } else if (*str != '-') {
-    return false;
+    return nullptr;
   }
   str++;
   if (*str != 'p' && *str != 's') {
-    return false;
+    return nullptr;
   }
   str++;
 
   if (!std::isspace(*str++)) {
-    return false;
+    return nullptr;
   }
 
   old_str = str;
-  map_info->offset = strtoul(old_str, &str, 16);
+  uint64_t offset = strtoull(old_str, &str, 16);
   if (old_str == str || !std::isspace(*str)) {
-    return false;
+    return nullptr;
   }
 
   // Ignore the 00:00 values.
   old_str = str;
-  (void)strtoul(old_str, &str, 16);
+  (void)strtoull(old_str, &str, 16);
   if (old_str == str || *str++ != ':') {
-    return false;
+    return nullptr;
   }
   if (std::isspace(*str)) {
-    return false;
+    return nullptr;
   }
 
   // Skip the inode.
   old_str = str;
-  (void)strtoul(str, &str, 16);
+  (void)strtoull(str, &str, 16);
   if (old_str == str || !std::isspace(*str++)) {
-    return false;
+    return nullptr;
   }
 
   // Skip decimal digit.
   old_str = str;
-  (void)strtoul(old_str, &str, 10);
+  (void)strtoull(old_str, &str, 10);
   if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
-    return false;
+    return nullptr;
   }
 
   while (std::isspace(*str)) {
     str++;
   }
   if (*str == '\0') {
-    map_info->name = str;
-    return true;
+    return new MapInfo(start, end, offset, flags, "");
   }
 
   // Save the name data.
-  map_info->name = str;
+  std::string name(str);
 
   // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
-  if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
-    map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+  if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
+    flags |= MAPS_FLAGS_DEVICE_MAP;
   }
-  return true;
+  return new MapInfo(start, end, offset, flags, name);
 }
 
 bool Maps::Parse() {
@@ -187,8 +186,8 @@
       }
       *newline = '\0';
 
-      MapInfo map_info;
-      if (!InternalParseLine(line, &map_info)) {
+      MapInfo* map_info = InternalParseLine(line);
+      if (map_info == nullptr) {
         return_value = false;
         break;
       }
@@ -205,8 +204,7 @@
 
 Maps::~Maps() {
   for (auto& map : maps_) {
-    delete map.elf;
-    map.elf = nullptr;
+    delete map;
   }
 }
 
@@ -222,8 +220,8 @@
       end_of_line++;
     }
 
-    MapInfo map_info;
-    if (!InternalParseLine(line.c_str(), &map_info)) {
+    MapInfo* map_info = InternalParseLine(line.c_str());
+    if (map_info == nullptr) {
       return false;
     }
     maps_.push_back(map_info);
@@ -252,24 +250,27 @@
 
   std::vector<char> name;
   while (true) {
-    MapInfo map_info;
-    ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
+    uint64_t start;
+    ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &start, sizeof(start)));
     if (bytes == 0) {
       break;
     }
-    if (bytes == -1 || bytes != sizeof(map_info.start)) {
+    if (bytes == -1 || bytes != sizeof(start)) {
       return false;
     }
-    bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
-    if (bytes == -1 || bytes != sizeof(map_info.end)) {
+    uint64_t end;
+    bytes = TEMP_FAILURE_RETRY(read(fd, &end, sizeof(end)));
+    if (bytes == -1 || bytes != sizeof(end)) {
       return false;
     }
-    bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
-    if (bytes == -1 || bytes != sizeof(map_info.offset)) {
+    uint64_t offset;
+    bytes = TEMP_FAILURE_RETRY(read(fd, &offset, sizeof(offset)));
+    if (bytes == -1 || bytes != sizeof(offset)) {
       return false;
     }
-    bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
-    if (bytes == -1 || bytes != sizeof(map_info.flags)) {
+    uint16_t flags;
+    bytes = TEMP_FAILURE_RETRY(read(fd, &flags, sizeof(flags)));
+    if (bytes == -1 || bytes != sizeof(flags)) {
       return false;
     }
     uint16_t len;
@@ -283,9 +284,10 @@
       if (bytes == -1 || bytes != len) {
         return false;
       }
-      map_info.name = std::string(name.data(), len);
+      maps_.push_back(new MapInfo(start, end, offset, flags, std::string(name.data(), len)));
+    } else {
+      maps_.push_back(new MapInfo(start, end, offset, flags, ""));
     }
-    maps_.push_back(map_info);
   }
   return true;
 }
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 32753df..b1b39a0 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -32,14 +32,69 @@
 
 #include "Check.h"
 
+static size_t ProcessVmRead(pid_t pid, void* dst, uint64_t remote_src, size_t len) {
+  struct iovec dst_iov = {
+      .iov_base = dst,
+      .iov_len = len,
+  };
+
+  // Split up the remote read across page boundaries.
+  // From the manpage:
+  //   A partial read/write may result if one of the remote_iov elements points to an invalid
+  //   memory region in the remote process.
+  //
+  //   Partial transfers apply at the granularity of iovec elements.  These system calls won't
+  //   perform a partial transfer that splits a single iovec element.
+  constexpr size_t kMaxIovecs = 64;
+  struct iovec src_iovs[kMaxIovecs];
+  size_t iovecs_used = 0;
+
+  uint64_t cur = remote_src;
+  while (len > 0) {
+    if (iovecs_used == kMaxIovecs) {
+      errno = EINVAL;
+      return 0;
+    }
+
+    // struct iovec uses void* for iov_base.
+    if (cur >= UINTPTR_MAX) {
+      errno = EFAULT;
+      return 0;
+    }
+
+    src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
+
+    uintptr_t misalignment = cur & (getpagesize() - 1);
+    size_t iov_len = getpagesize() - misalignment;
+    iov_len = std::min(iov_len, len);
+
+    len -= iov_len;
+    if (__builtin_add_overflow(cur, iov_len, &cur)) {
+      errno = EFAULT;
+      return 0;
+    }
+
+    src_iovs[iovecs_used].iov_len = iov_len;
+    ++iovecs_used;
+  }
+
+  ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
+  return rc == -1 ? 0 : rc;
+}
+
 namespace unwindstack {
 
+bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
+  size_t rc = Read(addr, dst, size);
+  return rc == size;
+}
+
 bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
   string->clear();
   uint64_t bytes_read = 0;
   while (bytes_read < max_read) {
     uint8_t value;
-    if (!Read(addr, &value, sizeof(value))) {
+    if (!ReadFully(addr, &value, sizeof(value))) {
       return false;
     }
     if (value == '\0') {
@@ -59,16 +114,17 @@
   return std::shared_ptr<Memory>(new MemoryRemote(pid));
 }
 
-bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
-  uint64_t last_read_byte;
-  if (__builtin_add_overflow(size, addr, &last_read_byte)) {
-    return false;
+size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
+  if (addr >= raw_.size()) {
+    return 0;
   }
-  if (last_read_byte > raw_.size()) {
-    return false;
-  }
-  memcpy(dst, &raw_[addr], size);
-  return true;
+
+  size_t bytes_left = raw_.size() - static_cast<size_t>(addr);
+  const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr;
+  size_t actual_len = std::min(bytes_left, size);
+
+  memcpy(dst, actual_base, actual_len);
+  return actual_len;
 }
 
 uint8_t* MemoryBuffer::GetPtr(size_t offset) {
@@ -129,45 +185,43 @@
   return true;
 }
 
-bool MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
-  uint64_t max_size;
-  if (__builtin_add_overflow(addr, size, &max_size) || max_size > size_) {
-    return false;
+size_t MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
+  if (addr >= size_) {
+    return 0;
   }
-  memcpy(dst, &data_[addr], size);
-  return true;
+
+  size_t bytes_left = size_ - static_cast<size_t>(addr);
+  const unsigned char* actual_base = static_cast<const unsigned char*>(data_) + addr;
+  size_t actual_len = std::min(bytes_left, size);
+
+  memcpy(dst, actual_base, actual_len);
+  return actual_len;
 }
 
-bool MemoryRemote::PtraceRead(uint64_t addr, long* value) {
-#if !defined(__LP64__)
-  // Cannot read an address greater than 32 bits.
-  if (addr > UINT32_MAX) {
-    return false;
-  }
-#endif
+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);
+  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
   if (*value == -1 && errno) {
     return false;
   }
   return true;
 }
 
-bool MemoryRemote::Read(uint64_t addr, void* dst, size_t bytes) {
+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 false;
+    return 0;
   }
 
   size_t bytes_read = 0;
   long data;
   size_t align_bytes = addr & (sizeof(long) - 1);
   if (align_bytes != 0) {
-    if (!PtraceRead(addr & ~(sizeof(long) - 1), &data)) {
-      return false;
+    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);
@@ -178,8 +232,8 @@
   }
 
   for (size_t i = 0; i < bytes / sizeof(long); i++) {
-    if (!PtraceRead(addr, &data)) {
-      return false;
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
     }
     memcpy(dst, &data, sizeof(long));
     dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
@@ -189,85 +243,79 @@
 
   size_t left_over = bytes & (sizeof(long) - 1);
   if (left_over) {
-    if (!PtraceRead(addr, &data)) {
-      return false;
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
     }
     memcpy(dst, &data, left_over);
     bytes_read += left_over;
   }
-  return true;
+  return bytes_read;
 }
 
-bool MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
-  // Make sure that there is no overflow.
-  uint64_t max_size;
-  if (__builtin_add_overflow(addr, size, &max_size)) {
-    return false;
+size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
+#if !defined(__LP64__)
+  // Cannot read an address greater than 32 bits.
+  if (addr > UINT32_MAX) {
+    return 0;
+  }
+#endif
+  return ReadWithPtrace(pid_, addr, dst, size);
+}
+
+size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
+  return ProcessVmRead(getpid(), dst, addr, size);
+}
+
+MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
+                         uint64_t offset)
+    : memory_(memory), begin_(begin), length_(length), offset_(offset) {}
+
+size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
+  if (addr < offset_) {
+    return 0;
   }
 
-  // The process_vm_readv call will not always work on remote
-  // processes, so only use it for reads from the current pid.
-  // Use this method to avoid crashes if an address is invalid since
-  // unwind data could try to access any part of the address space.
-  struct iovec local_io;
-  local_io.iov_base = dst;
-  local_io.iov_len = size;
-
-  struct iovec remote_io;
-  remote_io.iov_base = reinterpret_cast<void*>(static_cast<uintptr_t>(addr));
-  remote_io.iov_len = size;
-
-  ssize_t bytes_read = process_vm_readv(getpid(), &local_io, 1, &remote_io, 1, 0);
-  if (bytes_read == -1) {
-    return false;
+  uint64_t read_offset = addr - offset_;
+  if (read_offset >= length_) {
+    return 0;
   }
-  return static_cast<size_t>(bytes_read) == size;
+
+  uint64_t read_length = std::min(static_cast<uint64_t>(size), length_ - read_offset);
+  uint64_t read_addr;
+  if (__builtin_add_overflow(read_offset, begin_, &read_addr)) {
+    return 0;
+  }
+
+  return memory_->Read(read_addr, dst, read_length);
 }
 
 bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
-  if (!MemoryFileAtOffset::Init(file, offset)) {
+  auto memory_file = std::make_shared<MemoryFileAtOffset>();
+  if (!memory_file->Init(file, offset)) {
     return false;
   }
+
   // The first uint64_t value is the start of memory.
-  if (!MemoryFileAtOffset::Read(0, &start_, sizeof(start_))) {
+  uint64_t start;
+  if (!memory_file->ReadFully(0, &start, sizeof(start))) {
     return false;
   }
-  // Subtract the first 64 bit value from the total size.
-  size_ -= sizeof(start_);
+
+  uint64_t size = memory_file->Size();
+  if (__builtin_sub_overflow(size, sizeof(start), &size)) {
+    return false;
+  }
+
+  memory_ = std::make_unique<MemoryRange>(memory_file, sizeof(start), size, start);
   return true;
 }
 
-bool MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
-  uint64_t max_size;
-  if (__builtin_add_overflow(addr, size, &max_size)) {
-    return false;
+size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
+  if (!memory_) {
+    return 0;
   }
 
-  uint64_t real_size;
-  if (__builtin_add_overflow(start_, offset_, &real_size) ||
-      __builtin_add_overflow(real_size, size_, &real_size)) {
-    return false;
-  }
-
-  if (addr < start_ || max_size > real_size) {
-    return false;
-  }
-  memcpy(dst, &data_[addr + offset_ - start_ + sizeof(start_)], size);
-  return true;
-}
-
-MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end)
-    : memory_(memory), begin_(begin), length_(end - begin) {
-  CHECK(end > begin);
-}
-
-bool MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
-  uint64_t max_read;
-  if (__builtin_add_overflow(addr, size, &max_read) || max_read > length_) {
-    return false;
-  }
-  // The check above guarantees that addr + begin_ will not overflow.
-  return memory_->Read(addr + begin_, dst, size);
+  return memory_->Read(addr, dst, size);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 36b8e25..28a77dc 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -58,7 +58,7 @@
   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()->Read(adjusted_rel_pc - 5, &value, sizeof(value)) ||
+    if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
         (value & 0xe000f000) != 0xe000f000) {
       return rel_pc - 2;
     }
@@ -193,7 +193,7 @@
 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->Read(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
     return false;
   }
 
@@ -240,7 +240,7 @@
 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->Read(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
     return false;
   }
 
@@ -474,7 +474,7 @@
   Memory* elf_memory = elf->memory();
   // Read from elf memory since it is usually more expensive to read from
   // process memory.
-  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
     return false;
   }
 
@@ -493,7 +493,7 @@
     // Form 3 (thumb):
     // 0x77 0x27              movs r7, #77
     // 0x00 0xdf              svc 0
-    if (!process_memory->Read(sp(), &data, sizeof(data))) {
+    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
       return false;
     }
     if (data == 0x5ac3c35a) {
@@ -517,7 +517,7 @@
     // Form 3 (thumb):
     // 0xad 0x27              movs r7, #ad
     // 0x00 0xdf              svc 0
-    if (!process_memory->Read(sp(), &data, sizeof(data))) {
+    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
       return false;
     }
     if (data == sp() + 8) {
@@ -532,7 +532,7 @@
     return false;
   }
 
-  if (!process_memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+  if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
     return false;
   }
   SetFromRaw();
@@ -544,7 +544,7 @@
   Memory* elf_memory = elf->memory();
   // Read from elf memory since it is usually more expensive to read from
   // process memory.
-  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
     return false;
   }
 
@@ -557,8 +557,8 @@
   }
 
   // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
-  if (!process_memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
-                            sizeof(uint64_t) * ARM64_REG_LAST)) {
+  if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+                                 sizeof(uint64_t) * ARM64_REG_LAST)) {
     return false;
   }
 
@@ -571,7 +571,7 @@
   Memory* elf_memory = elf->memory();
   // Read from elf memory since it is usually more expensive to read from
   // process memory.
-  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
     return false;
   }
 
@@ -587,7 +587,7 @@
     //   int signum
     //   struct sigcontext (same format as mcontext)
     struct x86_mcontext_t context;
-    if (!process_memory->Read(sp() + 4, &context, sizeof(context))) {
+    if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
       return false;
     }
     regs_[X86_REG_EBP] = context.ebp;
@@ -613,12 +613,12 @@
 
     // Get the location of the sigcontext data.
     uint32_t ptr;
-    if (!process_memory->Read(sp() + 8, &ptr, sizeof(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->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+    if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
       return false;
     }
     SetFromUcontext(&x86_ucontext);
@@ -632,12 +632,12 @@
   Memory* elf_memory = elf->memory();
   // Read from elf memory since it is usually more expensive to read from
   // process memory.
-  if (!elf_memory->Read(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
     return false;
   }
 
   uint16_t data2;
-  if (!elf_memory->Read(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+  if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
     return false;
   }
 
@@ -649,7 +649,8 @@
   // 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->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
+  if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
+                                 sizeof(x86_64_mcontext_t))) {
     return false;
   }
   SetFromUcontext(&x86_64_ucontext);
diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp
index 42d816a..b4b92d6 100644
--- a/libunwindstack/Symbols.cpp
+++ b/libunwindstack/Symbols.cpp
@@ -71,7 +71,7 @@
   bool return_value = false;
   while (cur_offset_ + entry_size_ <= end_) {
     SymType entry;
-    if (!elf_memory->Read(cur_offset_, &entry, sizeof(entry))) {
+    if (!elf_memory->ReadFully(cur_offset_, &entry, sizeof(entry))) {
       // Stop all processing, something looks like it is corrupted.
       cur_offset_ = UINT64_MAX;
       return false;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 2e46a11..3092a62 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -32,27 +32,20 @@
 
 namespace unwindstack {
 
-void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc) {
+void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc) {
   size_t frame_num = frames_.size();
   frames_.resize(frame_num + 1);
   FrameData* frame = &frames_.at(frame_num);
   frame->num = frame_num;
-  frame->pc = regs_->pc();
   frame->sp = regs_->sp();
-  frame->rel_pc = rel_pc;
+  frame->rel_pc = adjusted_rel_pc;
 
   if (map_info == nullptr) {
+    frame->pc = regs_->pc();
     return;
   }
 
-  if (adjust_pc) {
-    // Don't adjust the first frame pc.
-    frame->rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
-
-    // Adjust the original pc.
-    frame->pc -= rel_pc - frame->rel_pc;
-  }
-
+  frame->pc = map_info->start + adjusted_rel_pc;
   frame->map_name = map_info->name;
   frame->map_offset = map_info->offset;
   frame->map_start = map_info->start;
@@ -92,21 +85,29 @@
 
     MapInfo* map_info = maps_->Find(regs_->pc());
     uint64_t rel_pc;
+    uint64_t adjusted_rel_pc;
     Elf* elf;
     if (map_info == nullptr) {
       rel_pc = regs_->pc();
+      adjusted_rel_pc = rel_pc;
     } else {
       if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
         break;
       }
       elf = map_info->GetElf(process_memory_, true);
       rel_pc = elf->GetRelPc(regs_->pc(), map_info);
+      if (adjust_pc) {
+        adjusted_rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
+      } else {
+        adjusted_rel_pc = rel_pc;
+      }
     }
 
     if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
         std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
                   basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
-      FillInFrame(map_info, elf, rel_pc, adjust_pc);
+      FillInFrame(map_info, elf, adjusted_rel_pc);
+
       // Once a frame is added, stop skipping frames.
       initial_map_names_to_skip = nullptr;
     }
@@ -133,7 +134,8 @@
           in_device_map = true;
         } else {
           bool finished;
-          stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
+          stepped = elf->Step(rel_pc, adjusted_rel_pc, map_info->elf_offset, regs_,
+                              process_memory_.get(), &finished);
           if (stepped && finished) {
             break;
           }
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 294d742..da2ddc0 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -20,6 +20,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 
 #include <unwindstack/ElfInterface.h>
@@ -50,8 +51,8 @@
 
   uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
 
-  bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
-            bool* finished);
+  bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
+            Memory* process_memory, bool* finished);
 
   ElfInterface* CreateInterfaceFromMemory(Memory* memory);
 
@@ -80,6 +81,8 @@
   std::unique_ptr<Memory> memory_;
   uint32_t machine_type_;
   uint8_t class_type_;
+  // Protect calls that can modify internal state of the interface object.
+  std::mutex lock_;
 
   std::unique_ptr<Memory> gnu_debugdata_memory_;
   std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index f108766..e54b348 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -19,34 +19,48 @@
 
 #include <stdint.h>
 
+#include <mutex>
 #include <string>
 
+#include <unwindstack/Elf.h>
+
 namespace unwindstack {
 
 // Forward declarations.
-class Elf;
 class Memory;
 
 struct MapInfo {
-  uint64_t start;
-  uint64_t end;
-  uint64_t offset;
-  uint16_t flags;
+  MapInfo() = default;
+  MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
+  MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
+      : start(start), end(end), offset(offset), flags(flags), name(name) {}
+  ~MapInfo() { delete elf; }
+
+  uint64_t start = 0;
+  uint64_t end = 0;
+  uint64_t offset = 0;
+  uint16_t flags = 0;
   std::string name;
   Elf* elf = nullptr;
   // This value is only non-zero if the offset is non-zero but there is
   // no elf signature found at that offset. This indicates that the
   // entire file is represented by the Memory object returned by CreateMemory,
   // instead of a portion of the file.
-  uint64_t elf_offset;
+  uint64_t elf_offset = 0;
 
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
 
  private:
+  MapInfo(const MapInfo&) = delete;
+  void operator=(const MapInfo&) = delete;
+
   Memory* GetFileMemory();
 
   Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
+
+  // Protect the creation of the elf object.
+  std::mutex mutex_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 22122a9..34fef7f 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -42,11 +42,11 @@
 
   virtual const std::string GetMapsFile() const { return ""; }
 
-  typedef std::vector<MapInfo>::iterator iterator;
+  typedef std::vector<MapInfo*>::iterator iterator;
   iterator begin() { return maps_.begin(); }
   iterator end() { return maps_.end(); }
 
-  typedef std::vector<MapInfo>::const_iterator const_iterator;
+  typedef std::vector<MapInfo*>::const_iterator const_iterator;
   const_iterator begin() const { return maps_.begin(); }
   const_iterator end() const { return maps_.end(); }
 
@@ -54,11 +54,11 @@
 
   MapInfo* Get(size_t index) {
     if (index >= maps_.size()) return nullptr;
-    return &maps_[index];
+    return maps_[index];
   }
 
  protected:
-  std::vector<MapInfo> maps_;
+  std::vector<MapInfo*> maps_;
 };
 
 class RemoteMaps : public Maps {
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 183b899..8163152 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -36,7 +36,9 @@
 
   virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
 
-  virtual bool Read(uint64_t addr, void* dst, size_t size) = 0;
+  virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
+
+  bool ReadFully(uint64_t addr, void* dst, size_t size);
 
   inline bool ReadField(uint64_t addr, void* start, void* field, size_t size) {
     if (reinterpret_cast<uintptr_t>(field) < reinterpret_cast<uintptr_t>(start)) {
@@ -47,12 +49,16 @@
       return false;
     }
     // The read will check if offset + size overflows.
-    return Read(offset, field, size);
+    return ReadFully(offset, field, size);
   }
 
-  inline bool Read32(uint64_t addr, uint32_t* dst) { return Read(addr, dst, sizeof(uint32_t)); }
+  inline bool Read32(uint64_t addr, uint32_t* dst) {
+    return ReadFully(addr, dst, sizeof(uint32_t));
+  }
 
-  inline bool Read64(uint64_t addr, uint64_t* dst) { return Read(addr, dst, sizeof(uint64_t)); }
+  inline bool Read64(uint64_t addr, uint64_t* dst) {
+    return ReadFully(addr, dst, sizeof(uint64_t));
+  }
 };
 
 class MemoryBuffer : public Memory {
@@ -60,7 +66,7 @@
   MemoryBuffer() = default;
   virtual ~MemoryBuffer() = default;
 
-  bool Read(uint64_t addr, void* dst, size_t size) override;
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
 
   uint8_t* GetPtr(size_t offset);
 
@@ -79,7 +85,9 @@
 
   bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX);
 
-  bool Read(uint64_t addr, void* dst, size_t size) override;
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  size_t Size() { return size_; }
 
   void Clear();
 
@@ -89,31 +97,15 @@
   uint8_t* data_ = nullptr;
 };
 
-class MemoryOffline : public MemoryFileAtOffset {
- public:
-  MemoryOffline() = default;
-  virtual ~MemoryOffline() = default;
-
-  bool Init(const std::string& file, uint64_t offset);
-
-  bool Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
-  uint64_t start_;
-};
-
 class MemoryRemote : public Memory {
  public:
   MemoryRemote(pid_t pid) : pid_(pid) {}
   virtual ~MemoryRemote() = default;
 
-  bool Read(uint64_t addr, void* dst, size_t size) override;
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
 
   pid_t pid() { return pid_; }
 
- protected:
-  virtual bool PtraceRead(uint64_t addr, long* value);
-
  private:
   pid_t pid_;
 };
@@ -123,20 +115,38 @@
   MemoryLocal() = default;
   virtual ~MemoryLocal() = default;
 
-  bool Read(uint64_t addr, void* dst, size_t size) override;
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
 };
 
+// MemoryRange maps one address range onto another.
+// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset,
+// such that range.read(offset) is equivalent to underlying.read(src_begin).
 class MemoryRange : public Memory {
  public:
-  MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end);
+  MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
+              uint64_t offset);
   virtual ~MemoryRange() = default;
 
-  bool Read(uint64_t addr, void* dst, size_t size) override;
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
 
  private:
   std::shared_ptr<Memory> memory_;
   uint64_t begin_;
   uint64_t length_;
+  uint64_t offset_;
+};
+
+class MemoryOffline : public Memory {
+ public:
+  MemoryOffline() = default;
+  virtual ~MemoryOffline() = default;
+
+  bool Init(const std::string& file, uint64_t offset);
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+  std::unique_ptr<MemoryRange> memory_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index d1461d8..c59e081 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -33,7 +33,7 @@
 
 #if defined(__arm__)
 
-inline void RegsGetLocal(Regs* regs) {
+inline __always_inline void RegsGetLocal(Regs* regs) {
   void* reg_data = regs->RawData();
   asm volatile(
       ".align 2\n"
@@ -57,7 +57,7 @@
 
 #elif defined(__aarch64__)
 
-inline void RegsGetLocal(Regs* regs) {
+inline __always_inline void RegsGetLocal(Regs* regs) {
   void* reg_data = regs->RawData();
   asm volatile(
       "1:\n"
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 37a76b2..b64d460 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -70,7 +70,7 @@
   static std::string FormatFrame(const FrameData& frame, bool bits32);
 
  private:
-  void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc);
+  void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc);
 
   size_t max_frames_;
   Maps* maps_;
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 53ee719..3a629f8 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -109,23 +109,23 @@
 
   this->eh_frame_->TestGetFdeInfo(0, &info);
   EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x660cU, info.start);
-  EXPECT_EQ(0x680cU, info.end);
+  EXPECT_EQ(0x6608U, info.start);
+  EXPECT_EQ(0x6808U, info.end);
 
   this->eh_frame_->TestGetFdeInfo(1, &info);
   EXPECT_EQ(0x5200U, info.offset);
-  EXPECT_EQ(0x770cU, info.start);
-  EXPECT_EQ(0x7a0cU, info.end);
+  EXPECT_EQ(0x7708U, info.start);
+  EXPECT_EQ(0x7a08U, info.end);
 
   this->eh_frame_->TestGetFdeInfo(2, &info);
   EXPECT_EQ(0x5400U, info.offset);
-  EXPECT_EQ(0x890cU, info.start);
-  EXPECT_EQ(0x8d0cU, info.end);
+  EXPECT_EQ(0x8908U, info.start);
+  EXPECT_EQ(0x8d08U, info.end);
 
   this->eh_frame_->TestGetFdeInfo(3, &info);
   EXPECT_EQ(0x5500U, info.offset);
-  EXPECT_EQ(0x9a0cU, info.start);
-  EXPECT_EQ(0x9f0cU, info.end);
+  EXPECT_EQ(0x9a08U, info.start);
+  EXPECT_EQ(0x9f08U, info.end);
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
@@ -193,23 +193,23 @@
 
   this->eh_frame_->TestGetFdeInfo(0, &info);
   EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x661cU, info.start);
-  EXPECT_EQ(0x681cU, info.end);
+  EXPECT_EQ(0x6618U, info.start);
+  EXPECT_EQ(0x6818U, info.end);
 
   this->eh_frame_->TestGetFdeInfo(1, &info);
   EXPECT_EQ(0x5200U, info.offset);
-  EXPECT_EQ(0x771cU, info.start);
-  EXPECT_EQ(0x7a1cU, info.end);
+  EXPECT_EQ(0x7718U, info.start);
+  EXPECT_EQ(0x7a18U, info.end);
 
   this->eh_frame_->TestGetFdeInfo(2, &info);
   EXPECT_EQ(0x5400U, info.offset);
-  EXPECT_EQ(0x891cU, info.start);
-  EXPECT_EQ(0x8d1cU, info.end);
+  EXPECT_EQ(0x8918U, info.start);
+  EXPECT_EQ(0x8d18U, info.end);
 
   this->eh_frame_->TestGetFdeInfo(3, &info);
   EXPECT_EQ(0x5500U, info.offset);
-  EXPECT_EQ(0x9a1cU, info.start);
-  EXPECT_EQ(0x9f1cU, info.end);
+  EXPECT_EQ(0x9a18U, info.start);
+  EXPECT_EQ(0x9f18U, info.end);
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
@@ -261,8 +261,8 @@
   typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
   this->eh_frame_->TestGetFdeInfo(0, &info);
   EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x660aU, info.start);
-  EXPECT_EQ(0x680aU, info.end);
+  EXPECT_EQ(0x6606U, info.start);
+  EXPECT_EQ(0x6806U, info.end);
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
@@ -304,8 +304,8 @@
   typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
   this->eh_frame_->TestGetFdeInfo(0, &info);
   EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x660aU, info.start);
-  EXPECT_EQ(0x680aU, info.end);
+  EXPECT_EQ(0x6606U, info.start);
+  EXPECT_EQ(0x6806U, info.end);
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) {
@@ -384,8 +384,8 @@
   ASSERT_TRUE(fde != nullptr);
   EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
   EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
-  EXPECT_EQ(0x1d00cU, fde->pc_start);
-  EXPECT_EQ(0x1d10cU, fde->pc_end);
+  EXPECT_EQ(0x1d008U, fde->pc_start);
+  EXPECT_EQ(0x1d108U, fde->pc_end);
   EXPECT_EQ(0xf000U, fde->cie_offset);
   EXPECT_EQ(0U, fde->lsda_address);
 
@@ -428,8 +428,8 @@
   ASSERT_TRUE(fde != nullptr);
   EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
   EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
-  EXPECT_EQ(0xd01cU, fde->pc_start);
-  EXPECT_EQ(0xd31cU, fde->pc_end);
+  EXPECT_EQ(0xd018U, fde->pc_start);
+  EXPECT_EQ(0xd318U, fde->pc_end);
   EXPECT_EQ(0x6000U, fde->cie_offset);
   EXPECT_EQ(0U, fde->lsda_address);
 
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 1028ab9..64b325b 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -345,8 +345,8 @@
   ASSERT_TRUE(fde != nullptr);
   EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
   EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
-  EXPECT_EQ(0x1d00cU, fde->pc_start);
-  EXPECT_EQ(0x1d10cU, fde->pc_end);
+  EXPECT_EQ(0x1d008U, fde->pc_start);
+  EXPECT_EQ(0x1d108U, fde->pc_end);
   EXPECT_EQ(0xf000U, fde->cie_offset);
   EXPECT_EQ(0U, fde->lsda_address);
 
@@ -387,8 +387,8 @@
   ASSERT_TRUE(fde != nullptr);
   EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
   EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
-  EXPECT_EQ(0xd01cU, fde->pc_start);
-  EXPECT_EQ(0xd31cU, fde->pc_end);
+  EXPECT_EQ(0xd018U, fde->pc_start);
+  EXPECT_EQ(0xd318U, fde->pc_end);
   EXPECT_EQ(0x6000U, fde->cie_offset);
   EXPECT_EQ(0U, fde->lsda_address);
 
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 4e48fa1..afd113d 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -132,7 +132,7 @@
   ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
 
   bool finished;
-  ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
+  ASSERT_FALSE(elf.Step(0, 0, 0, nullptr, nullptr, &finished));
 }
 
 TEST_F(ElfTest, elf32_invalid_machine) {
@@ -273,7 +273,7 @@
 
   elf.FakeSetValid(true);
   elf.FakeSetLoadBias(0);
-  MapInfo map_info{.start = 0x1000, .end = 0x2000};
+  MapInfo map_info(0x1000, 0x2000);
 
   ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
 
@@ -306,7 +306,7 @@
   elf.FakeSetValid(true);
   elf.FakeSetLoadBias(0);
   bool finished;
-  ASSERT_TRUE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x1000, 0x1000, 0x2000, &regs, &process_memory, &finished));
   EXPECT_FALSE(finished);
   EXPECT_EQ(15U, regs.pc());
   EXPECT_EQ(13U, regs.sp());
@@ -339,7 +339,7 @@
   EXPECT_CALL(*interface, Step(0x1000, &regs, &process_memory, &finished))
       .WillOnce(::testing::Return(true));
 
-  ASSERT_TRUE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x1004, 0x1000, 0x2000, &regs, &process_memory, &finished));
 }
 
 TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
@@ -355,12 +355,12 @@
 
   // Invalid relative pc given load_bias.
   bool finished;
-  ASSERT_FALSE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_FALSE(elf.Step(0x1004, 0x1000, 0x2000, &regs, &process_memory, &finished));
 
   EXPECT_CALL(*interface, Step(0x3300, &regs, &process_memory, &finished))
       .WillOnce(::testing::Return(true));
 
-  ASSERT_TRUE(elf.Step(0x7300, 0x2000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x7304, 0x7300, 0x2000, &regs, &process_memory, &finished));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
index 069386b..69163ac 100644
--- a/libunwindstack/tests/ElfTestUtils.cpp
+++ b/libunwindstack/tests/ElfTestUtils.cpp
@@ -47,7 +47,7 @@
   ehdr->e_ehsize = sizeof(Ehdr);
 }
 
-static std::string GetTestFileDirectory() {
+std::string TestGetFileDirectory() {
   std::string exec(testing::internal::GetArgvs()[0]);
   auto const value = exec.find_last_of('/');
   if (value == std::string::npos) {
@@ -102,7 +102,7 @@
   offset = symtab_offset + 0x100;
   if (init_gnu_debugdata) {
     // Read in the compressed elf data and copy it in.
-    name = GetTestFileDirectory();
+    name = TestGetFileDirectory();
     if (elf_class == ELFCLASS32) {
       name += "elf32.xz";
     } else {
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
index 6ef00e1..62cd59a 100644
--- a/libunwindstack/tests/ElfTestUtils.h
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -18,6 +18,7 @@
 #define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
 
 #include <functional>
+#include <string>
 
 namespace unwindstack {
 
@@ -30,6 +31,8 @@
 void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
                           TestCopyFuncType copy_func);
 
+std::string TestGetFileDirectory();
+
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index d2aad49..866b5b4 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -94,7 +94,7 @@
 TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
 
 TEST_F(MapInfoCreateMemoryTest, end_le_start) {
-  MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
+  MapInfo info(0x100, 0x100, 0, 0, elf_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
@@ -112,7 +112,7 @@
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
-  MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
+  MapInfo info(0x100, 0x200, 0x100, 0, elf_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -120,20 +120,20 @@
 
   // Read the entire file.
   std::vector<uint8_t> buffer(1024);
-  ASSERT_TRUE(memory->Read(0, buffer.data(), 1024));
+  ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 1024));
   ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
   ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]);
   for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_FALSE(memory->Read(1024, buffer.data(), 1));
+  ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
 }
 
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
-  MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
+  MapInfo info(0x100, 0x200, 0x100, 0, elf_at_100_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -141,14 +141,14 @@
 
   // Read the valid part of the file.
   std::vector<uint8_t> buffer(0x100);
-  ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100));
+  ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
   ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
   ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]);
   for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1));
+  ASSERT_FALSE(memory->ReadFully(0x100, buffer.data(), 1));
 }
 
 // Verify that if the offset is non-zero and there is an elf at that
@@ -156,7 +156,7 @@
 // embedded elf is bigger than the initial map, the new object is larger
 // than the original map size. Do this for a 32 bit elf and a 64 bit elf.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
-  MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path};
+  MapInfo info(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -164,15 +164,15 @@
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
-  ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG));
+  ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
   ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
 
   // Read past the end of what would normally be the size of the map.
-  ASSERT_TRUE(memory->Read(0x1000, e_ident, 1));
+  ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
 }
 
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
-  MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path};
+  MapInfo info(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -180,11 +180,11 @@
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
-  ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG));
+  ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
   ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
 
   // Read past the end of what would normally be the size of the map.
-  ASSERT_TRUE(memory->Read(0x1000, e_ident, 1));
+  ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
 }
 
 // Verify that device file names will never result in Memory object creation.
@@ -221,13 +221,13 @@
   ASSERT_TRUE(memory.get() != nullptr);
 
   memset(buffer.data(), 0, buffer.size());
-  ASSERT_TRUE(memory->Read(0, buffer.data(), buffer.size()));
+  ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
   for (size_t i = 0; i < buffer.size(); i++) {
     ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
   }
 
   // Try to read outside of the map size.
-  ASSERT_FALSE(memory->Read(buffer.size(), buffer.data(), 1));
+  ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 0b70d13..948597b 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -23,7 +23,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <atomic>
 #include <memory>
+#include <thread>
 #include <vector>
 
 #include <android-base/file.h>
@@ -67,52 +69,52 @@
 };
 
 TEST_F(MapInfoGetElfTest, invalid) {
-  MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
 
   // The map is empty, but this should still create an invalid elf object.
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 }
 
 TEST_F(MapInfoGetElfTest, valid32) {
-  MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x3000, 0x4000, 0, PROT_READ, "");
 
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
   memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
   EXPECT_EQ(ELFCLASS32, elf->class_type());
 }
 
 TEST_F(MapInfoGetElfTest, valid64) {
-  MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x8000, 0x9000, 0, PROT_READ, "");
 
   Elf64_Ehdr ehdr;
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
   memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
   EXPECT_EQ(ELFCLASS64, elf->class_type());
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
-  MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x4000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x4000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
   EXPECT_EQ(ELFCLASS32, elf->class_type());
@@ -120,15 +122,15 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
-  MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x6000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x6000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
   EXPECT_EQ(ELFCLASS64, elf->class_type());
@@ -136,15 +138,15 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
-  MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x2000, 0x3000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x2000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, true);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
   EXPECT_EQ(ELFCLASS32, elf->class_type());
@@ -152,15 +154,15 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
-  MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x5000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x5000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, true);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
   EXPECT_EQ(ELFCLASS64, elf->class_type());
@@ -168,32 +170,36 @@
 }
 
 TEST_F(MapInfoGetElfTest, end_le_start) {
-  MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x1000, 0x1000, 0, PROT_READ, elf_.path);
 
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
+  delete info.elf;
   info.elf = nullptr;
   info.end = 0xfff;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
   // Make sure this test is valid.
+  delete info.elf;
   info.elf = nullptr;
   info.end = 0x2000;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
 }
 
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
-  MapInfo info{
-      .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x1000);
   memset(buffer.data(), 0, buffer.size());
@@ -202,27 +208,27 @@
   memcpy(buffer.data(), &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0x100U, info.elf_offset);
 
   // Read the entire file.
   memset(buffer.data(), 0, buffer.size());
-  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size()));
+  ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
   for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_FALSE(elf->memory()->Read(buffer.size(), buffer.data(), 1));
+  ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
 }
 
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
-  MapInfo info{
-      .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -231,19 +237,20 @@
   memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
 
   // Read the valid part of the file.
-  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+  ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
   for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_FALSE(elf->memory()->Read(0x1000, buffer.data(), 1));
+  ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
 }
 
 // Verify that if the offset is non-zero and there is an elf at that
@@ -251,8 +258,7 @@
 // embedded elf is bigger than the initial map, the new object is larger
 // than the original map size. Do this for a 32 bit elf and a 64 bit elf.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
-  MapInfo info{
-      .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -264,23 +270,23 @@
   memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
 
   // Verify the memory is a valid elf.
   memset(buffer.data(), 0, buffer.size());
-  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+  ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
 
   // Read past the end of what would normally be the size of the map.
-  ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
+  ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
 }
 
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
-  MapInfo info{
-      .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -292,22 +298,23 @@
   memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
 
   // Verify the memory is a valid elf.
   memset(buffer.data(), 0, buffer.size());
-  ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+  ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
 
   // Read past the end of what would normally be the size of the map.
-  ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
+  ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
 }
 
 TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
-  MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""};
+  MapInfo info(0x9000, 0xa000, 0x1000, 0, "");
 
   // Create valid elf data in process memory only.
   Elf64_Ehdr ehdr;
@@ -317,21 +324,19 @@
   ehdr.e_shnum = 4;
   memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
+  delete info.elf;
   info.elf = nullptr;
   info.flags = PROT_READ;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf->valid());
 }
 
 TEST_F(MapInfoGetElfTest, check_device_maps) {
-  MapInfo info{.start = 0x7000,
-               .end = 0x8000,
-               .offset = 0x1000,
-               .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP,
-               .name = "/dev/something"};
+  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
 
   // Create valid elf data in process memory for this to verify that only
   // the name is causing invalid elf data.
@@ -342,20 +347,68 @@
   ehdr.e_shnum = 4;
   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
   // Set the name to nothing to verify that it still fails.
+  delete info.elf;
   info.elf = nullptr;
   info.name = "";
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
   ASSERT_FALSE(elf->valid());
 
   // Change the flags and verify the elf is valid now.
+  delete info.elf;
   info.elf = nullptr;
   info.flags = PROT_READ;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf->valid());
 }
 
+TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
+  static constexpr size_t kNumConcurrentThreads = 100;
+
+  Elf64_Ehdr ehdr;
+  TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
+  ehdr.e_shoff = 0x2000;
+  ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+  ehdr.e_shnum = 4;
+  memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
+
+  Elf* elf_in_threads[kNumConcurrentThreads];
+  std::vector<std::thread*> threads;
+
+  std::atomic_bool wait;
+  wait = true;
+  // Create all of the threads and have them do the GetElf at the same time
+  // to make it likely that a race will occur.
+  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, "");
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
+      while (wait)
+        ;
+      Elf* elf = info.GetElf(process_memory_, false);
+      elf_in_threads[i] = elf;
+    });
+    threads.push_back(thread);
+  }
+  ASSERT_TRUE(info.elf == nullptr);
+
+  // Set them all going and wait for the threads to finish.
+  wait = false;
+  for (auto thread : threads) {
+    thread->join();
+    delete thread;
+  }
+
+  // Now verify that all of the elf files are exactly the same and valid.
+  Elf* elf = info.elf;
+  ASSERT_TRUE(elf != nullptr);
+  EXPECT_TRUE(elf->valid());
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 2d15a4e..8dc884f 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -35,7 +35,12 @@
     ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
     MapInfo* element = maps.Get(0);
     ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
-    *info = *element;
+    info->start = element->start;
+    info->end = element->end;
+    info->offset = element->offset;
+    info->flags = element->flags;
+    info->name = element->name;
+    info->elf_offset = element->elf_offset;
   }
 }
 
@@ -139,38 +144,48 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(5U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(PROT_NONE, it->flags);
-  ASSERT_EQ(0x1000U, it->start);
-  ASSERT_EQ(0x2000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_READ, it->flags);
-  ASSERT_EQ(0x2000U, it->start);
-  ASSERT_EQ(0x3000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_WRITE, it->flags);
-  ASSERT_EQ(0x3000U, it->start);
-  ASSERT_EQ(0x4000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_EXEC, it->flags);
-  ASSERT_EQ(0x4000U, it->start);
-  ASSERT_EQ(0x5000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, it->flags);
-  ASSERT_EQ(0x5000U, it->start);
-  ASSERT_EQ(0x6000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_NONE, info->flags);
+  EXPECT_EQ(0x1000U, info->start);
+  EXPECT_EQ(0x2000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_READ, info->flags);
+  EXPECT_EQ(0x2000U, info->start);
+  EXPECT_EQ(0x3000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_WRITE, info->flags);
+  EXPECT_EQ(0x3000U, info->start);
+  EXPECT_EQ(0x4000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(3);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_EXEC, info->flags);
+  EXPECT_EQ(0x4000U, info->start);
+  EXPECT_EQ(0x5000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(4);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+  EXPECT_EQ(0x5000U, info->start);
+  EXPECT_EQ(0x6000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  ASSERT_TRUE(maps.Get(5) == nullptr);
 }
 
 TEST(MapsTest, parse_name) {
@@ -181,26 +196,32 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ("", it->name);
-  ASSERT_EQ(0x7b29b000U, it->start);
-  ASSERT_EQ(0x7b29e000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ++it;
-  ASSERT_EQ("/system/lib/fake.so", it->name);
-  ASSERT_EQ(0x7b29e000U, it->start);
-  ASSERT_EQ(0x7b29f000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ++it;
-  ASSERT_EQ("", it->name);
-  ASSERT_EQ(0x7b29f000U, it->start);
-  ASSERT_EQ(0x7b2a0000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ("", info->name);
+  EXPECT_EQ(0x7b29b000U, info->start);
+  EXPECT_EQ(0x7b29e000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ("/system/lib/fake.so", info->name);
+  EXPECT_EQ(0x7b29e000U, info->start);
+  EXPECT_EQ(0x7b29f000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ("", info->name);
+  EXPECT_EQ(0x7b29f000U, info->start);
+  EXPECT_EQ(0x7b2a0000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+  ASSERT_TRUE(maps.Get(3) == nullptr);
 }
 
 TEST(MapsTest, parse_offset) {
@@ -210,20 +231,60 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(2U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(0xa000U, it->start);
-  ASSERT_EQ(0xe000U, it->end);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ASSERT_EQ("/system/lib/fake.so", it->name);
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(0xa000U, info->start);
+  EXPECT_EQ(0xe000U, info->end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake.so", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0xa12345U, info->offset);
+  EXPECT_EQ(0xe000U, info->start);
+  EXPECT_EQ(0xf000U, info->end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake.so", info->name);
+
+  ASSERT_TRUE(maps.Get(2) == nullptr);
+}
+
+TEST(MapsTest, iterate) {
+  BufferMaps maps(
+      "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+      "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+  ASSERT_TRUE(maps.Parse());
+  ASSERT_EQ(2U, maps.Total());
+
+  Maps::iterator it = maps.begin();
+  EXPECT_EQ(0xa000U, (*it)->start);
+  EXPECT_EQ(0xe000U, (*it)->end);
   ++it;
-  ASSERT_EQ(0xa12345U, it->offset);
-  ASSERT_EQ(0xe000U, it->start);
-  ASSERT_EQ(0xf000U, it->end);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ASSERT_EQ("/system/lib/fake.so", it->name);
+  EXPECT_EQ(0xe000U, (*it)->start);
+  EXPECT_EQ(0xf000U, (*it)->end);
   ++it;
-  ASSERT_EQ(maps.end(), it);
+  EXPECT_EQ(maps.end(), it);
+}
+
+TEST(MapsTest, const_iterate) {
+  BufferMaps maps(
+      "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+      "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+  ASSERT_TRUE(maps.Parse());
+  ASSERT_EQ(2U, maps.Total());
+
+  Maps::const_iterator it = maps.begin();
+  EXPECT_EQ(0xa000U, (*it)->start);
+  EXPECT_EQ(0xe000U, (*it)->end);
+  ++it;
+  EXPECT_EQ(0xe000U, (*it)->start);
+  EXPECT_EQ(0xf000U, (*it)->end);
+  ++it;
+  EXPECT_EQ(maps.end(), it);
 }
 
 TEST(MapsTest, device) {
@@ -235,18 +296,23 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(4U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_TRUE(it->flags & 0x8000);
-  ASSERT_EQ("/dev/", it->name);
-  ++it;
-  ASSERT_TRUE(it->flags & 0x8000);
-  ASSERT_EQ("/dev/does_not_exist", it->name);
-  ++it;
-  ASSERT_FALSE(it->flags & 0x8000);
-  ASSERT_EQ("/dev/ashmem/does_not_exist", it->name);
-  ++it;
-  ASSERT_FALSE(it->flags & 0x8000);
-  ASSERT_EQ("/devsomething/does_not_exist", it->name);
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_TRUE(info->flags & 0x8000);
+  EXPECT_EQ("/dev/", info->name);
+
+  info = maps.Get(1);
+  EXPECT_TRUE(info->flags & 0x8000);
+  EXPECT_EQ("/dev/does_not_exist", info->name);
+
+  info = maps.Get(2);
+  EXPECT_FALSE(info->flags & 0x8000);
+  EXPECT_EQ("/dev/ashmem/does_not_exist", info->name);
+
+  info = maps.Get(3);
+  EXPECT_FALSE(info->flags & 0x8000);
+  EXPECT_EQ("/devsomething/does_not_exist", info->name);
 }
 
 TEST(MapsTest, file_smoke) {
@@ -263,26 +329,32 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(0x7b29b000U, it->start);
-  ASSERT_EQ(0x7b29e000U, it->end);
-  ASSERT_EQ(0xa0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake.so", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2b0000U, it->start);
-  ASSERT_EQ(0x7b2e0000U, it->end);
-  ASSERT_EQ(0xb0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake2.so", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2e0000U, it->start);
-  ASSERT_EQ(0x7b2f0000U, it->end);
-  ASSERT_EQ(0xc0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake3.so", it->name);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b29b000U, info->start);
+  EXPECT_EQ(0x7b29e000U, info->end);
+  EXPECT_EQ(0xa0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake.so", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2b0000U, info->start);
+  EXPECT_EQ(0x7b2e0000U, info->end);
+  EXPECT_EQ(0xb0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake2.so", info->name);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2e0000U, info->start);
+  EXPECT_EQ(0x7b2f0000U, info->end);
+  EXPECT_EQ(0xc0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake3.so", info->name);
+
+  ASSERT_TRUE(maps.Get(3) == nullptr);
 }
 
 TEST(MapsTest, file_no_map_name) {
@@ -299,26 +371,32 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(0x7b29b000U, it->start);
-  ASSERT_EQ(0x7b29e000U, it->end);
-  ASSERT_EQ(0xa0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2b0000U, it->start);
-  ASSERT_EQ(0x7b2e0000U, it->end);
-  ASSERT_EQ(0xb0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake2.so", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2e0000U, it->start);
-  ASSERT_EQ(0x7b2f0000U, it->end);
-  ASSERT_EQ(0xc0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b29b000U, info->start);
+  EXPECT_EQ(0x7b29e000U, info->end);
+  EXPECT_EQ(0xa0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2b0000U, info->start);
+  EXPECT_EQ(0x7b2e0000U, info->end);
+  EXPECT_EQ(0xb0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake2.so", info->name);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2e0000U, info->start);
+  EXPECT_EQ(0x7b2f0000U, info->end);
+  EXPECT_EQ(0xc0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("", info->name);
+
+  ASSERT_TRUE(maps.Get(3) == nullptr);
 }
 
 // Verify that a file that crosses a buffer is parsed correctly.
@@ -435,10 +513,10 @@
   ASSERT_EQ(5000U, maps.Total());
   for (size_t i = 0; i < 5000; i++) {
     MapInfo* info = maps.Get(i);
-    ASSERT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
-    ASSERT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
+    EXPECT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
+    EXPECT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
     std::string name = "/fake" + std::to_string(i) + ".so";
-    ASSERT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
+    EXPECT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
   }
 }
 
@@ -452,52 +530,52 @@
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(5U, maps.Total());
 
-  ASSERT_TRUE(maps.Find(0x500) == nullptr);
-  ASSERT_TRUE(maps.Find(0x2000) == nullptr);
-  ASSERT_TRUE(maps.Find(0x5010) == nullptr);
-  ASSERT_TRUE(maps.Find(0x9a00) == nullptr);
-  ASSERT_TRUE(maps.Find(0xf000) == nullptr);
-  ASSERT_TRUE(maps.Find(0xf010) == nullptr);
+  EXPECT_TRUE(maps.Find(0x500) == nullptr);
+  EXPECT_TRUE(maps.Find(0x2000) == nullptr);
+  EXPECT_TRUE(maps.Find(0x5010) == nullptr);
+  EXPECT_TRUE(maps.Find(0x9a00) == nullptr);
+  EXPECT_TRUE(maps.Find(0xf000) == nullptr);
+  EXPECT_TRUE(maps.Find(0xf010) == nullptr);
 
   MapInfo* info = maps.Find(0x1000);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0x1000U, info->start);
-  ASSERT_EQ(0x2000U, info->end);
-  ASSERT_EQ(0x10U, info->offset);
-  ASSERT_EQ(PROT_READ, info->flags);
-  ASSERT_EQ("/system/lib/fake1.so", info->name);
+  EXPECT_EQ(0x1000U, info->start);
+  EXPECT_EQ(0x2000U, info->end);
+  EXPECT_EQ(0x10U, info->offset);
+  EXPECT_EQ(PROT_READ, info->flags);
+  EXPECT_EQ("/system/lib/fake1.so", info->name);
 
   info = maps.Find(0x3020);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0x3000U, info->start);
-  ASSERT_EQ(0x4000U, info->end);
-  ASSERT_EQ(0x20U, info->offset);
-  ASSERT_EQ(PROT_WRITE, info->flags);
-  ASSERT_EQ("/system/lib/fake2.so", info->name);
+  EXPECT_EQ(0x3000U, info->start);
+  EXPECT_EQ(0x4000U, info->end);
+  EXPECT_EQ(0x20U, info->offset);
+  EXPECT_EQ(PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake2.so", info->name);
 
   info = maps.Find(0x6020);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0x6000U, info->start);
-  ASSERT_EQ(0x8000U, info->end);
-  ASSERT_EQ(0x30U, info->offset);
-  ASSERT_EQ(PROT_EXEC, info->flags);
-  ASSERT_EQ("/system/lib/fake3.so", info->name);
+  EXPECT_EQ(0x6000U, info->start);
+  EXPECT_EQ(0x8000U, info->end);
+  EXPECT_EQ(0x30U, info->offset);
+  EXPECT_EQ(PROT_EXEC, info->flags);
+  EXPECT_EQ("/system/lib/fake3.so", info->name);
 
   info = maps.Find(0xafff);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0xa000U, info->start);
-  ASSERT_EQ(0xb000U, info->end);
-  ASSERT_EQ(0x40U, info->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, info->flags);
-  ASSERT_EQ("/system/lib/fake4.so", info->name);
+  EXPECT_EQ(0xa000U, info->start);
+  EXPECT_EQ(0xb000U, info->end);
+  EXPECT_EQ(0x40U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake4.so", info->name);
 
   info = maps.Find(0xe500);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0xe000U, info->start);
-  ASSERT_EQ(0xf000U, info->end);
-  ASSERT_EQ(0x50U, info->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
-  ASSERT_EQ("/system/lib/fake5.so", info->name);
+  EXPECT_EQ(0xe000U, info->start);
+  EXPECT_EQ(0xf000U, info->end);
+  EXPECT_EQ(0x50U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+  EXPECT_EQ("/system/lib/fake5.so", info->name);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
index 50a8a1b..28e0e76 100644
--- a/libunwindstack/tests/MemoryBufferTest.cpp
+++ b/libunwindstack/tests/MemoryBufferTest.cpp
@@ -36,7 +36,7 @@
 TEST_F(MemoryBufferTest, empty) {
   ASSERT_EQ(0U, memory_->Size());
   std::vector<uint8_t> buffer(1024);
-  ASSERT_FALSE(memory_->Read(0, buffer.data(), 1));
+  ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 1));
   ASSERT_EQ(nullptr, memory_->GetPtr(0));
   ASSERT_EQ(nullptr, memory_->GetPtr(1));
 }
@@ -55,7 +55,7 @@
   }
 
   std::vector<uint8_t> buffer(memory_->Size());
-  ASSERT_TRUE(memory_->Read(0, buffer.data(), buffer.size()));
+  ASSERT_TRUE(memory_->ReadFully(0, buffer.data(), buffer.size()));
   for (size_t i = 0; i < buffer.size(); i++) {
     ASSERT_EQ(i, buffer[i]) << "Failed at byte " << i;
   }
@@ -64,18 +64,38 @@
 TEST_F(MemoryBufferTest, read_failures) {
   memory_->Resize(100);
   std::vector<uint8_t> buffer(200);
-  ASSERT_FALSE(memory_->Read(0, buffer.data(), 101));
-  ASSERT_FALSE(memory_->Read(100, buffer.data(), 1));
-  ASSERT_FALSE(memory_->Read(101, buffer.data(), 2));
-  ASSERT_FALSE(memory_->Read(99, buffer.data(), 2));
-  ASSERT_TRUE(memory_->Read(99, buffer.data(), 1));
+  ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 101));
+  ASSERT_FALSE(memory_->ReadFully(100, buffer.data(), 1));
+  ASSERT_FALSE(memory_->ReadFully(101, buffer.data(), 2));
+  ASSERT_FALSE(memory_->ReadFully(99, buffer.data(), 2));
+  ASSERT_TRUE(memory_->ReadFully(99, buffer.data(), 1));
 }
 
 TEST_F(MemoryBufferTest, read_failure_overflow) {
   memory_->Resize(100);
   std::vector<uint8_t> buffer(200);
 
-  ASSERT_FALSE(memory_->Read(UINT64_MAX - 100, buffer.data(), 200));
+  ASSERT_FALSE(memory_->ReadFully(UINT64_MAX - 100, buffer.data(), 200));
+}
+
+TEST_F(MemoryBufferTest, Read) {
+  memory_->Resize(256);
+  ASSERT_EQ(256U, memory_->Size());
+  ASSERT_TRUE(memory_->GetPtr(0) != nullptr);
+  ASSERT_TRUE(memory_->GetPtr(1) != nullptr);
+  ASSERT_TRUE(memory_->GetPtr(255) != nullptr);
+  ASSERT_TRUE(memory_->GetPtr(256) == nullptr);
+
+  uint8_t* data = memory_->GetPtr(0);
+  for (size_t i = 0; i < memory_->Size(); i++) {
+    data[i] = i;
+  }
+
+  std::vector<uint8_t> buffer(memory_->Size());
+  ASSERT_EQ(128U, memory_->Read(128, buffer.data(), buffer.size()));
+  for (size_t i = 0; i < 128; i++) {
+    ASSERT_EQ(128 + i, buffer[i]) << "Failed at byte " << i;
+  }
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp
index 2026acc..60936cd 100644
--- a/libunwindstack/tests/MemoryFake.cpp
+++ b/libunwindstack/tests/MemoryFake.cpp
@@ -35,16 +35,16 @@
   }
 }
 
-bool MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
+size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
   uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
   for (size_t i = 0; i < size; i++, addr++) {
     auto value = data_.find(addr);
     if (value == data_.end()) {
-      return false;
+      return i;
     }
     dst[i] = value->second;
   }
-  return true;
+  return size;
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.h b/libunwindstack/tests/MemoryFake.h
index d374261..764a6c3 100644
--- a/libunwindstack/tests/MemoryFake.h
+++ b/libunwindstack/tests/MemoryFake.h
@@ -32,7 +32,7 @@
   MemoryFake() = default;
   virtual ~MemoryFake() = default;
 
-  bool Read(uint64_t addr, void* buffer, size_t size) override;
+  size_t Read(uint64_t addr, void* buffer, size_t size) override;
 
   void SetMemory(uint64_t addr, const void* memory, size_t length);
 
@@ -71,21 +71,9 @@
   MemoryFakeAlwaysReadZero() = default;
   virtual ~MemoryFakeAlwaysReadZero() = default;
 
-  bool Read(uint64_t, void* buffer, size_t size) override {
+  size_t Read(uint64_t, void* buffer, size_t size) override {
     memset(buffer, 0, size);
-    return true;
-  }
-};
-
-class MemoryFakeRemote : public MemoryRemote {
- public:
-  MemoryFakeRemote() : MemoryRemote(0) {}
-  virtual ~MemoryFakeRemote() = default;
-
- protected:
-  bool PtraceRead(uint64_t, long* value) override {
-    *value = 0;
-    return true;
+    return size;
   }
 };
 
diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp
index a204bae..d7d1ace 100644
--- a/libunwindstack/tests/MemoryFileTest.cpp
+++ b/libunwindstack/tests/MemoryFileTest.cpp
@@ -49,7 +49,7 @@
 
   ASSERT_TRUE(memory_.Init(tf_->path, 0));
   std::vector<char> buffer(11);
-  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
+  ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
   buffer[10] = '\0';
   ASSERT_STREQ("0123456789", buffer.data());
 }
@@ -59,7 +59,7 @@
 
   ASSERT_TRUE(memory_.Init(tf_->path, 10));
   std::vector<char> buffer(11);
-  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
+  ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
   buffer[10] = '\0';
   ASSERT_STREQ("abcdefghij", buffer.data());
 }
@@ -75,7 +75,7 @@
 
   ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 15));
   std::vector<char> buffer(9);
-  ASSERT_TRUE(memory_.Read(0, buffer.data(), 8));
+  ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 8));
   buffer[8] = '\0';
   ASSERT_STREQ("abcdefgh", buffer.data());
 }
@@ -91,7 +91,7 @@
 
   ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize));
   std::vector<char> buffer(11);
-  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
+  ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
   buffer[10] = '\0';
   std::string expected_str;
   for (size_t i = 0; i < 5; i++) {
@@ -112,7 +112,7 @@
 
   ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize + 10));
   std::vector<char> buffer(11);
-  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
+  ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
   buffer[10] = '\0';
   std::string expected_str;
   for (size_t i = 0; i < 5; i++) {
@@ -149,19 +149,19 @@
   std::vector<char> buffer(100);
 
   // Read before init.
-  ASSERT_FALSE(memory_.Read(0, buffer.data(), 10));
+  ASSERT_FALSE(memory_.ReadFully(0, buffer.data(), 10));
 
   ASSERT_TRUE(memory_.Init(tf_->path, 0));
 
-  ASSERT_FALSE(memory_.Read(10000, buffer.data(), 10));
-  ASSERT_FALSE(memory_.Read(5000, buffer.data(), 10));
-  ASSERT_FALSE(memory_.Read(4990, buffer.data(), 11));
-  ASSERT_TRUE(memory_.Read(4990, buffer.data(), 10));
-  ASSERT_FALSE(memory_.Read(4999, buffer.data(), 2));
-  ASSERT_TRUE(memory_.Read(4999, buffer.data(), 1));
+  ASSERT_FALSE(memory_.ReadFully(10000, buffer.data(), 10));
+  ASSERT_FALSE(memory_.ReadFully(5000, buffer.data(), 10));
+  ASSERT_FALSE(memory_.ReadFully(4990, buffer.data(), 11));
+  ASSERT_TRUE(memory_.ReadFully(4990, buffer.data(), 10));
+  ASSERT_FALSE(memory_.ReadFully(4999, buffer.data(), 2));
+  ASSERT_TRUE(memory_.ReadFully(4999, buffer.data(), 1));
 
   // Check that overflow fails properly.
-  ASSERT_FALSE(memory_.Read(UINT64_MAX - 100, buffer.data(), 200));
+  ASSERT_FALSE(memory_.ReadFully(UINT64_MAX - 100, buffer.data(), 200));
 }
 
 TEST_F(MemoryFileTest, read_past_file_within_mapping) {
@@ -178,7 +178,8 @@
 
   for (size_t i = 0; i < 100; i++) {
     uint8_t value;
-    ASSERT_FALSE(memory_.Read(buffer.size() + i, &value, 1)) << "Should have failed at value " << i;
+    ASSERT_FALSE(memory_.ReadFully(buffer.size() + i, &value, 1))
+        << "Should have failed at value " << i;
   }
 }
 
@@ -195,8 +196,8 @@
 
   std::vector<uint8_t> read_buffer(pagesize * 2);
   // Make sure that reading after mapped data is a failure.
-  ASSERT_FALSE(memory_.Read(pagesize * 2, read_buffer.data(), 1));
-  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 2));
+  ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
+  ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
   for (size_t i = 0; i < pagesize; i++) {
     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
   }
@@ -219,8 +220,8 @@
 
   std::vector<uint8_t> read_buffer(pagesize * 2);
   // Make sure that reading after mapped data is a failure.
-  ASSERT_FALSE(memory_.Read(pagesize * 2, read_buffer.data(), 1));
-  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 2));
+  ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
+  ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
   for (size_t i = 0; i < pagesize - 0x100; i++) {
     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
   }
@@ -245,8 +246,8 @@
   ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, UINT64_MAX));
 
   std::vector<uint8_t> read_buffer(pagesize * 10);
-  ASSERT_FALSE(memory_.Read(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
-  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 9 - 0x100));
+  ASSERT_FALSE(memory_.ReadFully(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
+  ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 9 - 0x100));
 }
 
 TEST_F(MemoryFileTest, init_reinit) {
@@ -259,14 +260,14 @@
 
   ASSERT_TRUE(memory_.Init(tf_->path, 0));
   std::vector<uint8_t> read_buffer(buffer.size());
-  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize));
+  ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
   for (size_t i = 0; i < pagesize; i++) {
     ASSERT_EQ(1, read_buffer[i]) << "Failed at byte " << i;
   }
 
   // Now reinit.
   ASSERT_TRUE(memory_.Init(tf_->path, pagesize));
-  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize));
+  ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
   for (size_t i = 0; i < pagesize; i++) {
     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
   }
diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp
index 73eebdd..5a389d0 100644
--- a/libunwindstack/tests/MemoryLocalTest.cpp
+++ b/libunwindstack/tests/MemoryLocalTest.cpp
@@ -16,6 +16,7 @@
 
 #include <stdint.h>
 #include <string.h>
+#include <sys/mman.h>
 
 #include <vector>
 
@@ -32,14 +33,14 @@
   MemoryLocal local;
 
   std::vector<uint8_t> dst(1024);
-  ASSERT_TRUE(local.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
+  ASSERT_TRUE(local.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
   ASSERT_EQ(0, memcmp(src.data(), dst.data(), 1024));
   for (size_t i = 0; i < 1024; i++) {
     ASSERT_EQ(0x4cU, dst[i]);
   }
 
   memset(src.data(), 0x23, 512);
-  ASSERT_TRUE(local.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
+  ASSERT_TRUE(local.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
   ASSERT_EQ(0, memcmp(src.data(), dst.data(), 1024));
   for (size_t i = 0; i < 512; i++) {
     ASSERT_EQ(0x23U, dst[i]);
@@ -53,8 +54,8 @@
   MemoryLocal local;
 
   std::vector<uint8_t> dst(100);
-  ASSERT_FALSE(local.Read(0, dst.data(), 1));
-  ASSERT_FALSE(local.Read(0, dst.data(), 100));
+  ASSERT_FALSE(local.ReadFully(0, dst.data(), 1));
+  ASSERT_FALSE(local.ReadFully(0, dst.data(), 100));
 }
 
 TEST(MemoryLocalTest, read_overflow) {
@@ -64,7 +65,47 @@
   // version will always go through the overflow check.
   std::vector<uint8_t> dst(100);
   uint64_t value;
-  ASSERT_FALSE(local.Read(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
+  ASSERT_FALSE(local.ReadFully(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
+}
+
+TEST(MemoryLocalTest, Read) {
+  char* mapping = static_cast<char*>(
+      mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+
+  ASSERT_NE(MAP_FAILED, mapping);
+
+  mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE);
+  memset(mapping + getpagesize() - 1024, 0x4c, 1024);
+
+  MemoryLocal local;
+
+  std::vector<uint8_t> dst(4096);
+  ASSERT_EQ(1024U, local.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024),
+                              dst.data(), 4096));
+  for (size_t i = 0; i < 1024; i++) {
+    ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
+  }
+
+  ASSERT_EQ(0, munmap(mapping, 2 * getpagesize()));
+}
+
+TEST(MemoryLocalTest, read_hole) {
+  void* mapping =
+      mmap(nullptr, 3 * 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0xFF, 3 * 4096);
+  mprotect(static_cast<char*>(mapping) + 4096, 4096, PROT_NONE);
+
+  MemoryLocal local;
+  std::vector<uint8_t> dst(4096 * 3, 0xCC);
+  ASSERT_EQ(4096U, local.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), 4096 * 3));
+  for (size_t i = 0; i < 4096; ++i) {
+    ASSERT_EQ(0xFF, dst[i]);
+  }
+  for (size_t i = 4096; i < 4096 * 3; ++i) {
+    ASSERT_EQ(0xCC, dst[i]);
+  }
+  ASSERT_EQ(0, munmap(mapping, 3 * 4096));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 680fae9..cb1a0c9 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -35,10 +35,10 @@
   std::shared_ptr<Memory> process_memory(memory_fake);
   memory_fake->SetMemory(9001, src);
 
-  MemoryRange range(process_memory, 9001, 9001 + src.size());
+  MemoryRange range(process_memory, 9001, src.size(), 0);
 
   std::vector<uint8_t> dst(1024);
-  ASSERT_TRUE(range.Read(0, dst.data(), src.size()));
+  ASSERT_TRUE(range.ReadFully(0, dst.data(), src.size()));
   for (size_t i = 0; i < 1024; i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
@@ -51,29 +51,44 @@
   std::shared_ptr<Memory> process_memory(memory_fake);
   memory_fake->SetMemory(1000, src);
 
-  MemoryRange range(process_memory, 1000, 2024);
+  MemoryRange range(process_memory, 1000, 1024, 0);
 
   std::vector<uint8_t> dst(1024);
-  ASSERT_TRUE(range.Read(1020, dst.data(), 4));
+  ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
   for (size_t i = 0; i < 4; i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 
   // Verify that reads outside of the range will fail.
-  ASSERT_FALSE(range.Read(1020, dst.data(), 5));
-  ASSERT_FALSE(range.Read(1024, dst.data(), 1));
-  ASSERT_FALSE(range.Read(1024, dst.data(), 1024));
+  ASSERT_FALSE(range.ReadFully(1020, dst.data(), 5));
+  ASSERT_FALSE(range.ReadFully(1024, dst.data(), 1));
+  ASSERT_FALSE(range.ReadFully(1024, dst.data(), 1024));
 
   // Verify that reading up to the end works.
-  ASSERT_TRUE(range.Read(1020, dst.data(), 4));
+  ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
 }
 
 TEST(MemoryRangeTest, read_overflow) {
   std::vector<uint8_t> buffer(100);
 
   std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero);
-  std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200));
-  ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100));
+  std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200, 0));
+  ASSERT_FALSE(overflow->ReadFully(UINT64_MAX - 10, buffer.data(), 100));
+}
+
+TEST(MemoryRangeTest, Read) {
+  std::vector<uint8_t> src(4096);
+  memset(src.data(), 0x4c, 4096);
+  MemoryFake* memory_fake = new MemoryFake;
+  std::shared_ptr<Memory> process_memory(memory_fake);
+  memory_fake->SetMemory(1000, src);
+
+  MemoryRange range(process_memory, 1000, 1024, 0);
+  std::vector<uint8_t> dst(1024);
+  ASSERT_EQ(4U, range.Read(1020, dst.data(), 1024));
+  for (size_t i = 0; i < 4; i++) {
+    ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
+  }
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index a66d0c5..8aa8605 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -71,7 +71,7 @@
   MemoryRemote remote(pid);
 
   std::vector<uint8_t> dst(1024);
-  ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
+  ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
   for (size_t i = 0; i < 1024; i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
@@ -79,6 +79,50 @@
   ASSERT_TRUE(Detach(pid));
 }
 
+TEST_F(MemoryRemoteTest, read_partial) {
+  char* mapping = static_cast<char*>(
+      mmap(nullptr, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0x4c, 4 * getpagesize());
+  ASSERT_EQ(0, mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE));
+  ASSERT_EQ(0, munmap(mapping + 3 * getpagesize(), getpagesize()));
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  // Unmap from our process.
+  ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
+
+  ASSERT_TRUE(Attach(pid));
+
+  MemoryRemote remote(pid);
+
+  std::vector<uint8_t> dst(4096);
+  size_t bytes =
+      remote.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024), dst.data(), 4096);
+  // Some read methods can read PROT_NONE maps, allow that.
+  ASSERT_LE(1024U, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
+  }
+
+  // Now verify that reading stops at the end of a map.
+  bytes =
+      remote.Read(reinterpret_cast<uint64_t>(mapping + 3 * getpagesize() - 1024), dst.data(), 4096);
+  ASSERT_EQ(1024U, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
+  }
+
+  ASSERT_TRUE(Detach(pid));
+}
+
 TEST_F(MemoryRemoteTest, read_fail) {
   int pagesize = getpagesize();
   void* src = mmap(nullptr, pagesize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1, 0);
@@ -101,17 +145,17 @@
   MemoryRemote remote(pid);
 
   std::vector<uint8_t> dst(pagesize);
-  ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src), dst.data(), pagesize));
+  ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src), dst.data(), pagesize));
   for (size_t i = 0; i < 1024; i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_FALSE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize, dst.data(), 1));
-  ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize - 1, dst.data(), 1));
-  ASSERT_FALSE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize - 4, dst.data(), 8));
+  ASSERT_FALSE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize, dst.data(), 1));
+  ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize - 1, dst.data(), 1));
+  ASSERT_FALSE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize - 4, dst.data(), 8));
 
   // Check overflow condition is caught properly.
-  ASSERT_FALSE(remote.Read(UINT64_MAX - 100, dst.data(), 200));
+  ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
 
   ASSERT_EQ(0, munmap(src, pagesize));
 
@@ -119,11 +163,24 @@
 }
 
 TEST_F(MemoryRemoteTest, read_overflow) {
-  MemoryFakeRemote remote;
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  ASSERT_TRUE(Attach(pid));
+
+  MemoryRemote remote(pid);
 
   // Check overflow condition is caught properly.
   std::vector<uint8_t> dst(200);
-  ASSERT_FALSE(remote.Read(UINT64_MAX - 100, dst.data(), 200));
+  ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
+
+  ASSERT_TRUE(Detach(pid));
 }
 
 TEST_F(MemoryRemoteTest, read_illegal) {
@@ -140,10 +197,77 @@
   MemoryRemote remote(pid);
 
   std::vector<uint8_t> dst(100);
-  ASSERT_FALSE(remote.Read(0, dst.data(), 1));
-  ASSERT_FALSE(remote.Read(0, dst.data(), 100));
+  ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
+  ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
 
   ASSERT_TRUE(Detach(pid));
 }
 
+TEST_F(MemoryRemoteTest, read_mprotect_hole) {
+  size_t page_size = getpagesize();
+  void* mapping =
+      mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0xFF, 3 * page_size);
+  ASSERT_EQ(0, mprotect(static_cast<char*>(mapping) + page_size, 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, 3 * page_size));
+
+  ASSERT_TRUE(Attach(pid));
+
+  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);
+  // 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) {
+    ASSERT_EQ(0xFF, dst[i]);
+  }
+  for (size_t i = read_size; i < dst.size(); ++i) {
+    ASSERT_EQ(0xCC, dst[i]);
+  }
+}
+
+TEST_F(MemoryRemoteTest, read_munmap_hole) {
+  size_t page_size = getpagesize();
+  void* mapping =
+      mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0xFF, 3 * page_size);
+  ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + page_size, page_size));
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  ASSERT_EQ(0, munmap(mapping, page_size));
+  ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
+
+  ASSERT_TRUE(Attach(pid));
+
+  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);
+  ASSERT_EQ(page_size, read_size);
+  for (size_t i = 0; i < read_size; ++i) {
+    ASSERT_EQ(0xFF, dst[i]);
+  }
+  for (size_t i = read_size; i < dst.size(); ++i) {
+    ASSERT_EQ(0xCC, dst[i]);
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 2a02669..3320f77 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -147,28 +147,29 @@
 }
 
 TEST_F(RegsTest, elf_invalid) {
-  Elf invalid_elf(new MemoryFake);
   RegsArm regs_arm;
   RegsArm64 regs_arm64;
   RegsX86 regs_x86;
   RegsX86_64 regs_x86_64;
-  MapInfo map_info{.start = 0x1000, .end = 0x2000};
+  MapInfo map_info(0x1000, 0x2000);
+  Elf* invalid_elf = new Elf(new MemoryFake);
+  map_info.elf = invalid_elf;
 
   regs_arm.set_pc(0x1500);
-  ASSERT_EQ(0x500U, invalid_elf.GetRelPc(regs_arm.pc(), &map_info));
-  ASSERT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, &invalid_elf));
+  EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
+  EXPECT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, invalid_elf));
 
   regs_arm64.set_pc(0x1600);
-  ASSERT_EQ(0x600U, invalid_elf.GetRelPc(regs_arm64.pc(), &map_info));
-  ASSERT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, &invalid_elf));
+  EXPECT_EQ(0x600U, invalid_elf->GetRelPc(regs_arm64.pc(), &map_info));
+  EXPECT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, invalid_elf));
 
   regs_x86.set_pc(0x1700);
-  ASSERT_EQ(0x700U, invalid_elf.GetRelPc(regs_x86.pc(), &map_info));
-  ASSERT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, &invalid_elf));
+  EXPECT_EQ(0x700U, invalid_elf->GetRelPc(regs_x86.pc(), &map_info));
+  EXPECT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, invalid_elf));
 
   regs_x86_64.set_pc(0x1800);
-  ASSERT_EQ(0x800U, invalid_elf.GetRelPc(regs_x86_64.pc(), &map_info));
-  ASSERT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, &invalid_elf));
+  EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
+  EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
 }
 
 TEST_F(RegsTest, arm_set_from_raw) {
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
new file mode 100644
index 0000000..d24abe4
--- /dev/null
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
+
+#include "Machine.h"
+
+#include "ElfTestUtils.h"
+
+namespace unwindstack {
+
+static std::string DumpFrames(Unwinder& unwinder) {
+  std::string str;
+  for (size_t i = 0; i < unwinder.NumFrames(); i++) {
+    str += unwinder.FormatFrame(i) + "\n";
+  }
+  return str;
+}
+
+TEST(UnwindOfflineTest, pc_straddle_arm32) {
+  std::string dir(TestGetFileDirectory() + "offline/straddle_arm32/");
+
+  MemoryOffline* memory = new MemoryOffline;
+  ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
+
+  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
+  ASSERT_TRUE(fp != nullptr);
+  RegsArm regs;
+  uint64_t reg_value;
+  ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
+  regs[ARM_REG_PC] = reg_value;
+  ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
+  regs[ARM_REG_SP] = reg_value;
+  ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
+  regs[ARM_REG_LR] = reg_value;
+  regs.SetFromRaw();
+  fclose(fp);
+
+  fp = fopen((dir + "maps.txt").c_str(), "r");
+  ASSERT_TRUE(fp != nullptr);
+  // The file is guaranteed to be less than 4096 bytes.
+  std::vector<char> buffer(4096);
+  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
+  fclose(fp);
+
+  BufferMaps maps(buffer.data());
+  ASSERT_TRUE(maps.Parse());
+
+  ASSERT_EQ(static_cast<uint32_t>(EM_ARM), regs.MachineType());
+
+  std::shared_ptr<Memory> process_memory(memory);
+
+  char* cwd = getcwd(nullptr, 0);
+  ASSERT_EQ(0, chdir(dir.c_str()));
+  Unwinder unwinder(128, &maps, &regs, process_memory);
+  unwinder.Unwind();
+  ASSERT_EQ(0, chdir(cwd));
+  free(cwd);
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 0001a9f8  libc.so (abort+63)\n"
+      "  #01 pc 00006a1b  libbase.so (_ZN7android4base14DefaultAborterEPKc+6)\n"
+      "  #02 pc 00007441  libbase.so (_ZN7android4base10LogMessageD2Ev+748)\n"
+      "  #03 pc 00015149  /does/not/exist/libhidlbase.so\n",
+      frame_info);
+}
+
+TEST(UnwindOfflineTest, pc_straddle_arm64) {
+  std::string dir(TestGetFileDirectory() + "offline/straddle_arm64/");
+
+  MemoryOffline* memory = new MemoryOffline;
+  ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
+
+  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
+  ASSERT_TRUE(fp != nullptr);
+  RegsArm64 regs;
+  uint64_t reg_value;
+  ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
+  regs[ARM64_REG_PC] = reg_value;
+  ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
+  regs[ARM64_REG_SP] = reg_value;
+  ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
+  regs[ARM64_REG_LR] = reg_value;
+  ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", &reg_value));
+  regs[ARM64_REG_R29] = reg_value;
+  regs.SetFromRaw();
+  fclose(fp);
+
+  fp = fopen((dir + "maps.txt").c_str(), "r");
+  ASSERT_TRUE(fp != nullptr);
+  // The file is guaranteed to be less than 4096 bytes.
+  std::vector<char> buffer(4096);
+  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
+  fclose(fp);
+
+  BufferMaps maps(buffer.data());
+  ASSERT_TRUE(maps.Parse());
+
+  ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
+
+  std::shared_ptr<Memory> process_memory(memory);
+
+  char* cwd = getcwd(nullptr, 0);
+  ASSERT_EQ(0, chdir(dir.c_str()));
+  Unwinder unwinder(128, &maps, &regs, process_memory);
+  unwinder.Unwind();
+  ASSERT_EQ(0, chdir(cwd));
+  free(cwd);
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 0000000000429fd8  libunwindstack_test (SignalInnerFunction+24)\n"
+      "  #01 pc 000000000042a078  libunwindstack_test (SignalMiddleFunction+8)\n"
+      "  #02 pc 000000000042a08c  libunwindstack_test (SignalOuterFunction+8)\n"
+      "  #03 pc 000000000042d8fc  libunwindstack_test "
+      "(_ZN11unwindstackL19RemoteThroughSignalEij+20)\n"
+      "  #04 pc 000000000042d8d8  libunwindstack_test "
+      "(_ZN11unwindstack37UnwindTest_remote_through_signal_Test8TestBodyEv+32)\n"
+      "  #05 pc 0000000000455d70  libunwindstack_test (_ZN7testing4Test3RunEv+392)\n",
+      frame_info);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 9f9ca8b..b372fd0 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -174,7 +174,7 @@
       MemoryRemote memory(pid);
       // Read the remote value to see if we are ready.
       bool value;
-      if (memory.Read(addr, &value, sizeof(value)) && value) {
+      if (memory.ReadFully(addr, &value, sizeof(value)) && value) {
         *completed = true;
       }
       if (!*completed || !leave_attached) {
@@ -311,4 +311,39 @@
   RemoteThroughSignal(SIGSEGV, SA_SIGINFO);
 }
 
+// Verify that using the same map while unwinding multiple threads at the
+// same time doesn't cause problems.
+TEST_F(UnwindTest, multiple_threads_unwind_same_map) {
+  static constexpr size_t kNumConcurrentThreads = 100;
+
+  LocalMaps maps;
+  ASSERT_TRUE(maps.Parse());
+  auto process_memory(Memory::CreateProcessMemory(getpid()));
+
+  std::vector<std::thread*> threads;
+
+  std::atomic_bool wait;
+  wait = true;
+  size_t frames[kNumConcurrentThreads];
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    std::thread* thread = new std::thread([i, &frames, &maps, &process_memory, &wait]() {
+      while (wait)
+        ;
+      std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+      RegsGetLocal(regs.get());
+
+      Unwinder unwinder(512, &maps, regs.get(), process_memory);
+      unwinder.Unwind();
+      frames[i] = unwinder.NumFrames();
+      ASSERT_LE(3U, frames[i]) << "Failed for thread " << i;
+    });
+    threads.push_back(thread);
+  }
+  wait = false;
+  for (auto thread : threads) {
+    thread->join();
+    delete thread;
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 869d118..098459e 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -45,82 +45,51 @@
 
   void FakeClear() { maps_.clear(); }
 
-  void FakeAddMapInfo(const MapInfo& map_info) { maps_.push_back(map_info); }
+  void FakeAddMapInfo(MapInfo* map_info) { maps_.push_back(map_info); }
 };
 
 class UnwinderTest : public ::testing::Test {
  protected:
   static void SetUpTestCase() {
     maps_.FakeClear();
-    MapInfo info;
-    info.name = "/system/fake/libc.so";
-    info.start = 0x1000;
-    info.end = 0x8000;
-    info.offset = 0;
-    info.flags = PROT_READ | PROT_WRITE;
+    MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
     ElfFake* elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    info.elf_offset = 0;
     maps_.FakeAddMapInfo(info);
 
-    info.name = "[stack]";
-    info.start = 0x10000;
-    info.end = 0x12000;
-    info.flags = PROT_READ | PROT_WRITE;
-    info.elf = nullptr;
+    info = new MapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/dev/fake_device";
-    info.start = 0x13000;
-    info.end = 0x15000;
-    info.flags = PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP;
-    info.elf = nullptr;
+    info = new MapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
+                       "/dev/fake_device");
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/system/fake/libunwind.so";
-    info.start = 0x20000;
-    info.end = 0x22000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/libanother.so";
-    info.start = 0x23000;
-    info.end = 0x24000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/compressed.so";
-    info.start = 0x33000;
-    info.end = 0x34000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/fake.apk";
-    info.start = 0x43000;
-    info.end = 0x44000;
-    info.offset = 0x1d000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/fake.oat";
-    info.start = 0x53000;
-    info.end = 0x54000;
-    info.offset = 0;
-    info.flags = PROT_READ | PROT_WRITE;
-    info.elf = nullptr;
+    info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
     maps_.FakeAddMapInfo(info);
   }
 
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libbase.so b/libunwindstack/tests/files/offline/straddle_arm32/libbase.so
new file mode 100644
index 0000000..d1f16ee
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/libbase.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libc.so b/libunwindstack/tests/files/offline/straddle_arm32/libc.so
new file mode 100644
index 0000000..4dc19ca
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/maps.txt b/libunwindstack/tests/files/offline/straddle_arm32/maps.txt
new file mode 100644
index 0000000..8c26479
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/maps.txt
@@ -0,0 +1,4 @@
+f2d9a000-f2da7fff r-xp 00000000 00:00 0   libbase.so
+f3002000-f3005fff rw-p 00000000 00:00 0   [stack:25941]
+f31d0000-f326bfff r-xp 00000000 00:00 0   libc.so
+f3352000-f336bfff r-xp 00000000 00:00 0   /does/not/exist/libhidlbase.so
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/regs.txt b/libunwindstack/tests/files/offline/straddle_arm32/regs.txt
new file mode 100644
index 0000000..3baedf3
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/regs.txt
@@ -0,0 +1,3 @@
+pc: f31ea9f8
+sp: e9c866f8
+lr: f31f179f
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/stack.data b/libunwindstack/tests/files/offline/straddle_arm32/stack.data
new file mode 100644
index 0000000..83aeb4a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm32/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
new file mode 100644
index 0000000..092fc3a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/maps.txt b/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
new file mode 100644
index 0000000..bdf29b5
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
@@ -0,0 +1,2 @@
+00000064d05ab000-00000064d0a6cfff r-xp 00000000 00:00 0  libunwindstack_test
+0000007fe0d64000-0000007fe0d84fff rw-p 00000000 00:00 0  [stack]
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/regs.txt b/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
new file mode 100644
index 0000000..ff8a936
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
@@ -0,0 +1,4 @@
+pc: 00000064d09d4fd8
+sp: 0000007fe0d84040
+lr: 00000064d09d507c
+x29: 0000007fe0d84070
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/stack.data b/libunwindstack/tests/files/offline/straddle_arm64/stack.data
new file mode 100644
index 0000000..824d0e2
--- /dev/null
+++ b/libunwindstack/tests/files/offline/straddle_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 77f3bb2..a00b2ee 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -102,12 +103,12 @@
   }
 }
 
-int GetElfInfo(const char* file) {
+int GetElfInfo(const char* file, uint64_t offset) {
   // Send all log messages to stdout.
   log_to_stdout(true);
 
   MemoryFileAtOffset* memory = new MemoryFileAtOffset;
-  if (!memory->Init(file, 0)) {
+  if (!memory->Init(file, offset)) {
     // Initializatation failed.
     printf("Failed to init\n");
     return 1;
@@ -164,8 +165,12 @@
 }  // namespace unwindstack
 
 int main(int argc, char** argv) {
-  if (argc != 2) {
-    printf("Need to pass the name of an elf file to the program.\n");
+  if (argc != 2 && argc != 3) {
+    printf("Usage: unwind_info ELF_FILE [OFFSET]\n");
+    printf("  ELF_FILE\n");
+    printf("    The path to an elf file.\n");
+    printf("  OFFSET\n");
+    printf("    Use the offset into the ELF file as the beginning of the elf.\n");
     return 1;
   }
 
@@ -179,5 +184,15 @@
     return 1;
   }
 
-  return unwindstack::GetElfInfo(argv[1]);
+  uint64_t offset = 0;
+  if (argc == 3) {
+    char* end;
+    offset = strtoull(argv[2], &end, 16);
+    if (*end != '\0') {
+      printf("Malformed OFFSET value: %s\n", argv[2]);
+      return 1;
+    }
+  }
+
+  return unwindstack::GetElfInfo(argv[1], offset);
 }
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 4bd2a98..6b50f0c 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -136,9 +136,12 @@
             cflags: ["-Wno-unused-parameter"],
         },
 
-        // Under MinGW, ctype.h doesn't need multi-byte support
         windows: {
-            cflags: ["-DMB_CUR_MAX=1"],
+            cflags: [
+                // Under MinGW, ctype.h doesn't need multi-byte support
+                "-DMB_CUR_MAX=1",
+                "-Wno-unused-private-field",
+            ],
 
             enabled: true,
         },
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 6317c32..7d7f0e2 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -348,7 +348,7 @@
     mState = (void*) hMutex;
 }
 
-Mutex::Mutex(const char* name)
+Mutex::Mutex(const char* /*name*/)
 {
     // XXX: name not used for now
     HANDLE hMutex;
@@ -359,7 +359,7 @@
     mState = (void*) hMutex;
 }
 
-Mutex::Mutex(int type, const char* name)
+Mutex::Mutex(int /*type*/, const char* /*name*/)
 {
     // XXX: type and name not used for now
     HANDLE hMutex;
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index cb3d338..15ed19f 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -35,9 +35,7 @@
 
 // ---------------------------------------------------------------------------
 
-class SharedBuffer;
 class String8;
-class TextOutput;
 
 //! This is a string holding UTF-16 characters.
 class String16
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 1f3e5d8..0225c6b 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -31,7 +31,6 @@
 namespace android {
 
 class String16;
-class TextOutput;
 
 //! This is a string holding UTF-8 characters. Does not allow the value more
 // than 0x10FFFF, which is not valid unicode codepoint.
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
index d95fd05..da28dfa 100644
--- a/libutils/misc.cpp
+++ b/libutils/misc.cpp
@@ -44,8 +44,8 @@
 static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
 #endif
 
-void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
 #if !defined(_WIN32)
+void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
     pthread_mutex_lock(&gSyspropMutex);
     if (gSyspropList == NULL) {
         gSyspropList = new Vector<sysprop_change_callback_info>();
@@ -65,8 +65,10 @@
         gSyspropList->add(info);
     }
     pthread_mutex_unlock(&gSyspropMutex);
-#endif
 }
+#else
+void add_sysprop_change_callback(sysprop_change_callback, int) {}
+#endif
 
 #if defined(__ANDROID__)
 void (*get_report_sysprop_change_func())() {
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 91e775f..5ccbcc2 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -100,6 +100,11 @@
 }
 
 static uint32_t ComputeHash(const ZipString& name) {
+#if !defined(_WIN32)
+  return std::hash<std::string_view>{}(
+      std::string_view(reinterpret_cast<const char*>(name.name), name.name_length));
+#else
+  // Remove this code path once the windows compiler knows how to compile the above statement.
   uint32_t hash = 0;
   uint16_t len = name.name_length;
   const uint8_t* str = name.name;
@@ -109,6 +114,7 @@
   }
 
   return hash;
+#endif
 }
 
 /*
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 43362fb..560f490 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -213,7 +213,7 @@
         int prio = ANDROID_LOG_INFO;
         const char* tag = nullptr;
         size_t tag_len = 0;
-        if (log_id == LOG_ID_EVENTS) {
+        if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
             tag = tagToName(elem->getTag());
             if (tag) {
                 tag_len = strlen(tag);
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 8808aac..ac3cf9a 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -25,9 +25,9 @@
 #include <sys/types.h>
 
 #include <algorithm>  // std::max
-#include <experimental/string_view>
 #include <memory>
-#include <string>  // std::string
+#include <string>
+#include <string_view>
 #include <unordered_map>
 
 #include <android-base/stringprintf.h>
@@ -495,7 +495,7 @@
 
 struct TagNameKey {
     std::string* alloc;
-    std::experimental::string_view name;  // Saves space if const char*
+    std::string_view name;  // Saves space if const char*
 
     explicit TagNameKey(const LogBufferElement* element)
         : alloc(nullptr), name("", strlen("")) {
@@ -504,31 +504,31 @@
             if (tag) {
                 const char* cp = android::tagToName(tag);
                 if (cp) {
-                    name = std::experimental::string_view(cp, strlen(cp));
+                    name = std::string_view(cp, strlen(cp));
                     return;
                 }
             }
             alloc = new std::string(
                 android::base::StringPrintf("[%" PRIu32 "]", tag));
             if (!alloc) return;
-            name = std::experimental::string_view(alloc->c_str(), alloc->size());
+            name = std::string_view(alloc->c_str(), alloc->size());
             return;
         }
         const char* msg = element->getMsg();
         if (!msg) {
-            name = std::experimental::string_view("chatty", strlen("chatty"));
+            name = std::string_view("chatty", strlen("chatty"));
             return;
         }
         ++msg;
         unsigned short len = element->getMsgLen();
         len = (len <= 1) ? 0 : strnlen(msg, len - 1);
         if (!len) {
-            name = std::experimental::string_view("<NULL>", strlen("<NULL>"));
+            name = std::string_view("<NULL>", strlen("<NULL>"));
             return;
         }
         alloc = new std::string(msg, len);
         if (!alloc) return;
-        name = std::experimental::string_view(alloc->c_str(), alloc->size());
+        name = std::string_view(alloc->c_str(), alloc->size());
     }
 
     explicit TagNameKey(TagNameKey&& rval)
@@ -545,7 +545,7 @@
         if (alloc) delete alloc;
     }
 
-    operator const std::experimental::string_view() const {
+    operator const std::string_view() const {
         return name;
     }
 
@@ -576,8 +576,7 @@
     : public std::unary_function<const TagNameKey&, size_t> {
     size_t operator()(const TagNameKey& __t) const noexcept {
         if (!__t.length()) return 0;
-        return std::hash<std::experimental::string_view>()(
-            std::experimental::string_view(__t));
+        return std::hash<std::string_view>()(std::string_view(__t));
     }
 };
 
diff --git a/logd/logd.rc b/logd/logd.rc
index 8804246..bd303b7 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -20,4 +20,3 @@
 "
     chown logd logd /dev/event-log-tags
     chmod 0644 /dev/event-log-tags
-    restorecon /dev/event-log-tags
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index 751cbf7..baca5d6 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -4,7 +4,7 @@
 #
 
 # Don't change the order here. The first pattern that matches with the
-# absolution path of an executable is selected.
+# absolute path of an executable is selected.
 dir.system = /system/bin/
 dir.system = /system/xbin/
 dir.vendor = /vendor/bin/
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 10f0caf..3d5451b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -436,6 +436,8 @@
     mkdir /data/misc/update_engine 0700 root root
     mkdir /data/misc/update_engine_log 02750 root log
     mkdir /data/misc/trace 0700 root root
+    # create location to store surface and window trace files
+    mkdir /data/misc/wmtrace 0700 system system
     # profile file layout
     mkdir /data/misc/profiles 0771 system system
     mkdir /data/misc/profiles/cur 0771 system system
@@ -734,6 +736,8 @@
     # Give writes to anyone for the trace folder on debug builds.
     # The folder is used to store method traces.
     chmod 0773 /data/misc/trace
+    # Give reads to anyone for the window trace folder on debug builds.
+    chmod 0775 /data/misc/wmtrace
     start console
 
 service flash_recovery /system/bin/install-recovery.sh
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 9620d63..4203db4 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -1,6 +1,8 @@
 phony {
     name: "shell_and_utilities",
     required: [
+        "awk",
+        "awk_vendor",
         "bzip2",
         "grep",
         "grep_vendor",
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index c4e8aac..206204b 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -21,7 +21,8 @@
 Not everything is provided by toybox, though. We currently still use
 the BSD dd and grep (because the toybox versions are still unfinished),
 and for the bzip2 command-line tools we use the ones that are part of
-the bzip2 distribution.
+the bzip2 distribution. The awk added in Android P is Brian Kernighan's
+"one true" awk.
 
 The lists below show what tools were provided and where they came from in
 each release starting with Gingerbread. This doesn't tell the full story,
@@ -164,3 +165,29 @@
 sysctl tac tail tar taskset tee time timeout top touch tr true truncate
 tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
 vmstat wc which whoami xargs xxd yes zcat
+
+Android P
+---------
+
+BSD: dd grep
+
+bzip2: bzcat bzip2 bunzip2
+
+one-true-awk: awk
+
+toolbox: getevent newfs\_msdos
+
+toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
+dos2unix du echo env expand expr fallocate false file find flock free
+getenforce getprop groups gunzip gzip head hostname hwclock id ifconfig
+inotifyd insmod ionice iorenice kill killall ln load\_policy log logname
+losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod
+mkswap mktemp modinfo modprobe more mount mountpoint mv netstat nice
+nl nohup od paste patch pgrep pidof pkill pmap printenv printf ps pwd
+readlink realpath renice restorecon rm rmdir rmmod runcon sed sendevent
+seq setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
+sha512sum sleep sort split start stat stop strings swapoff swapon sync
+sysctl tac tail tar taskset tee time timeout top touch tr true truncate
+tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
+vmstat wc which whoami xargs xxd yes zcat
diff --git a/storaged/Android.bp b/storaged/Android.bp
index 35868bb..2c7dea1 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -61,7 +61,7 @@
         "storaged_uid_monitor.cpp",
         "uid_info.cpp",
         "storaged.proto",
-        "binder/android/os/IStoraged.aidl",
+        ":storaged_aidl",
         "binder/android/os/storaged/IStoragedPrivate.aidl",
     ],
 
@@ -100,3 +100,11 @@
 
     static_libs: ["libstoraged"],
 }
+
+// AIDL interface between storaged and framework.jar
+filegroup {
+    name: "storaged_aidl",
+    srcs: [
+        "binder/android/os/IStoraged.aidl",
+    ],
+}
diff --git a/trusty/keymaster/trusty_keymaster_ipc.cpp b/trusty/keymaster/trusty_keymaster_ipc.cpp
index fbd0eb3..686e7ae 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/trusty_keymaster_ipc.cpp
@@ -55,6 +55,11 @@
 
     size_t msg_size = in_size + sizeof(struct keymaster_message);
     struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
+    if (!msg) {
+        ALOGE("failed to allocate msg buffer\n");
+        return -EINVAL;
+    }
+
     msg->cmd = cmd;
     memcpy(msg->payload, in, in_size);