Merge "Remove fs_config entries for webview_zygote."
diff --git a/adb/Android.bp b/adb/Android.bp
index 41f7b89..0858a6c 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -13,39 +13,39 @@
 // limitations under the License.
 
 python_binary_host {
-  name: "adb_integration_test_adb",
-  main: "test_adb.py",
-  srcs: [
-    "test_adb.py",
-  ],
-  libs: [
-    "adb_py",
-  ],
-  version: {
-    py2: {
-      enabled: true,
+    name: "adb_integration_test_adb",
+    main: "test_adb.py",
+    srcs: [
+        "test_adb.py",
+    ],
+    libs: [
+        "adb_py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
     },
-    py3: {
-      enabled: false,
-    },
-  },
 }
 
 python_binary_host {
-  name: "adb_integration_test_device",
-  main: "test_device.py",
-  srcs: [
-    "test_device.py",
-  ],
-  libs: [
-    "adb_py",
-  ],
-  version: {
-    py2: {
-      enabled: true,
+    name: "adb_integration_test_device",
+    main: "test_device.py",
+    srcs: [
+        "test_device.py",
+    ],
+    libs: [
+        "adb_py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
     },
-    py3: {
-      enabled: false,
-    },
-  },
 }
diff --git a/adb/services.cpp b/adb/services.cpp
index 6dc71cf..fe74eb6 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -296,6 +296,7 @@
         void* arg = strdup(name + 7);
         if (arg == NULL) return -1;
         ret = create_service_thread("reboot", reboot_service, arg);
+        if (ret < 0) free(arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread("root", restart_root_service, nullptr);
     } else if(!strncmp(name, "unroot:", 7)) {
diff --git a/base/Android.bp b/base/Android.bp
index 6cadcfc..5d70d47 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -15,8 +15,12 @@
 //
 
 cc_defaults {
-    name: "libbase_defaults",
-    cflags: ["-Wall", "-Werror", "-Wextra"],
+    name: "libbase_cflags_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
 }
 
 cc_library_headers {
@@ -35,15 +39,9 @@
     },
 }
 
-cc_library {
-    name: "libbase",
-    defaults: ["libbase_defaults"],
-    vendor_available: true,
-    host_supported: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+cc_defaults {
+    name: "libbase_defaults",
+    defaults: ["libbase_cflags_defaults"],
     srcs: [
         "chrono_utils.cpp",
         "file.cpp",
@@ -55,11 +53,6 @@
         "test_utils.cpp",
     ],
 
-    header_libs: [
-        "libbase_headers",
-    ],
-    export_header_lib_headers: ["libbase_headers"],
-
     shared_libs: ["liblog"],
     target: {
         android: {
@@ -96,11 +89,34 @@
     },
 }
 
+cc_library {
+    name: "libbase",
+    defaults: ["libbase_defaults"],
+    vendor_available: true,
+    host_supported: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    header_libs: [
+        "libbase_headers",
+    ],
+    export_header_lib_headers: ["libbase_headers"],
+}
+
+cc_library_static {
+    name: "libbase_ndk",
+    defaults: ["libbase_defaults"],
+    sdk_version: "current",
+    stl: "c++_static",
+    export_include_dirs: ["include"],
+}
+
 // Tests
 // ------------------------------------------------------------------------------
 cc_test {
     name: "libbase_test",
-    defaults: ["libbase_defaults"],
+    defaults: ["libbase_cflags_defaults"],
     host_supported: true,
     srcs: [
         "endian_test.cpp",
diff --git a/base/logging.cpp b/base/logging.cpp
index 0f2012a..1f7bc2a 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -45,7 +45,7 @@
 
 // Headers for LogMessage::LogLine.
 #ifdef __ANDROID__
-#include <log/log.h>
+#include <android/log.h>
 #include <android/set_abort_message.h>
 #else
 #include <sys/types.h>
diff --git a/base/properties.cpp b/base/properties.cpp
index ca8e96f..6cf43f9 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -28,8 +28,6 @@
 
 #include <android-base/parseint.h>
 
-using namespace std::chrono_literals;
-
 namespace android {
 namespace base {
 
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5323524..7e6f24d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -16,7 +16,7 @@
 
 cc_library_headers {
     name: "libdebuggerd_common_headers",
-    export_include_dirs: ["common/include"]
+    export_include_dirs: ["common/include"],
 }
 
 cc_library_shared {
@@ -39,7 +39,7 @@
     ],
 
     export_header_lib_headers: ["libdebuggerd_common_headers"],
-    export_include_dirs: ["tombstoned/include"]
+    export_include_dirs: ["tombstoned/include"],
 }
 
 // Utility library to tombstoned and get an output fd.
@@ -60,7 +60,7 @@
     ],
 
     export_header_lib_headers: ["libdebuggerd_common_headers"],
-    export_include_dirs: ["tombstoned/include"]
+    export_include_dirs: ["tombstoned/include"],
 }
 
 // Core implementation, linked into libdebuggerd_handler and the dynamic linker.
@@ -186,7 +186,10 @@
                 "client/debuggerd_client_test.cpp",
                 "debuggerd_test.cpp",
             ],
-            static_libs: ["libasync_safe", "libtombstoned_client_static"],
+            static_libs: [
+                "libasync_safe",
+                "libtombstoned_client_static",
+            ],
         },
     },
 
@@ -197,7 +200,7 @@
         "libdebuggerd_client",
         "liblog",
         "libminijail",
-        "libnativehelper"
+        "libnativehelper",
     ],
 
     static_libs: [
@@ -298,7 +301,7 @@
         "liblog",
     ],
 
-    init_rc: ["tombstoned/tombstoned.rc"]
+    init_rc: ["tombstoned/tombstoned.rc"],
 }
 
 subdirs = [
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 0f049fd..7b04e71 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -68,7 +68,7 @@
 class Memory;
 }
 
-void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const char* fmt, ...);
+void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
 
 void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
 
diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
index 7c8a0ea..be39582 100644
--- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
@@ -201,7 +201,7 @@
   }
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
-  dump_memory(&log_, memory_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0x12345678, "memory near r1");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -221,7 +221,7 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
   memory_mock_->SetPartialReadAmount(96);
 
-  dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near r1");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -240,7 +240,7 @@
   }
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
-  dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0x12345679, "memory near r1");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -253,7 +253,7 @@
 }
 
 TEST_F(DumpMemoryTest, memory_unreadable) {
-  dump_memory(&log_, memory_mock_.get(), 0xa2345678, "memory near pc:");
+  dump_memory(&log_, memory_mock_.get(), 0xa2345678, "memory near pc");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -309,7 +309,7 @@
   }
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
-  dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
+  dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -329,7 +329,7 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
   memory_mock_->SetPartialReadAmount(102);
 
-  dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
+  dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -354,7 +354,7 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
   memory_mock_->SetPartialReadAmount(45);
 
-  dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc:");
+  dump_memory(&log_, memory_mock_.get(), 0x12345600, "memory near pc");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -380,7 +380,7 @@
   memset(buffer, 0, sizeof(buffer));
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
-  dump_memory(&log_, memory_mock_.get(), 0x1000, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0x1000, "memory near r1");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -434,7 +434,7 @@
   memset(buffer, 0, sizeof(buffer));
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
-  dump_memory(&log_, memory_mock_.get(), 0, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0, "memory near r1");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -452,13 +452,13 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
 #if defined(__LP64__)
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near r1");
 #else
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near r1");
 #endif
 
   std::string tombstone_contents;
@@ -477,9 +477,9 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
 #if defined(__LP64__)
-  dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near r1");
 #else
-  dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
+  dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near r1");
 #endif
 
   std::string tombstone_contents;
@@ -500,9 +500,9 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
 #if defined(__LP64__)
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
+  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near r4");
 #else
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
+  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near r4");
 #endif
 
   std::string tombstone_contents;
@@ -562,7 +562,7 @@
 
   size_t page_size = sysconf(_SC_PAGE_SIZE);
   uintptr_t addr = 0x10000020 + page_size - 120;
-  dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
+  dump_memory(&log_, memory_mock_.get(), addr, "memory near r4");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -621,7 +621,7 @@
 
   size_t page_size = sysconf(_SC_PAGE_SIZE);
   uintptr_t addr = 0x10000020 + page_size - 192;
-  dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
+  dump_memory(&log_, memory_mock_.get(), addr, "memory near r4");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -679,7 +679,7 @@
   memory_mock_->SetPartialReadAmount(0);
 
   uintptr_t addr = 0x10000020;
-  dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
+  dump_memory(&log_, memory_mock_.get(), addr, "memory near r4");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -739,7 +739,7 @@
   size_t page_size = sysconf(_SC_PAGE_SIZE);
   uintptr_t addr = 0x10000020 + page_size - 256;
 
-  dump_memory(&log_, memory_mock_.get(), addr, "memory near %.2s:", "r4");
+  dump_memory(&log_, memory_mock_.get(), addr, "memory near r4");
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 7d85602..140ef6d 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -65,6 +65,8 @@
 using unwindstack::Memory;
 using unwindstack::Regs;
 
+using namespace std::literals::string_literals;
+
 #define STACK_WORDS 16
 
 static void dump_header_info(log_t* log) {
@@ -148,8 +150,9 @@
 
     backtrace_map_t map;
     backtrace_map->FillIn(stack_data[i], &map);
-    if (BacktraceMap::IsValid(map) && !map.name.empty()) {
-      line += "  " + map.name;
+    std::string map_name{map.Name()};
+    if (BacktraceMap::IsValid(map) && !map_name.empty()) {
+      line += "  " + map_name;
       uint64_t offset = 0;
       std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
       if (!func_name.empty()) {
@@ -382,9 +385,16 @@
   print_register_row(log, special_row);
 }
 
-void dump_memory_and_code(log_t* log, Memory* memory, Regs* regs) {
-  regs->IterateRegisters([log, memory](const char* name, uint64_t value) {
-    dump_memory(log, memory, value, "memory near %s:", name);
+void dump_memory_and_code(log_t* log, BacktraceMap* map, Memory* memory, Regs* regs) {
+  regs->IterateRegisters([log, map, memory](const char* reg_name, uint64_t reg_value) {
+    std::string label{"memory near "s + reg_name};
+    if (map) {
+      backtrace_map_t map_info;
+      map->FillIn(reg_value, &map_info);
+      std::string map_name{map_info.Name()};
+      if (!map_name.empty()) label += " (" + map_info.Name() + ")";
+    }
+    dump_memory(log, memory, reg_value, label);
   });
 }
 
@@ -423,7 +433,7 @@
   }
 
   if (primary_thread) {
-    dump_memory_and_code(log, process_memory, thread_info.registers.get());
+    dump_memory_and_code(log, map, process_memory, thread_info.registers.get());
     if (map) {
       uint64_t addr = 0;
       siginfo_t* si = thread_info.siginfo;
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 3ac98f5..d153865 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -124,13 +124,7 @@
 #define MEMORY_BYTES_TO_DUMP 256
 #define MEMORY_BYTES_PER_LINE 16
 
-void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const char* fmt, ...) {
-  std::string log_msg;
-  va_list ap;
-  va_start(ap, fmt);
-  android::base::StringAppendV(&log_msg, fmt, ap);
-  va_end(ap);
-
+void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const std::string& label) {
   // Align the address to sizeof(long) and start 32 bytes before the address.
   addr &= ~(sizeof(long) - 1);
   if (addr >= 4128) {
@@ -147,7 +141,7 @@
     return;
   }
 
-  _LOG(log, logtype::MEMORY, "\n%s\n", log_msg.c_str());
+  _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
 
   // Dump 256 bytes
   uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy
index b1f459d..254330d 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm.policy
@@ -26,11 +26,11 @@
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
-mprotect: arg2 in PROT_READ|PROT_WRITE
+mprotect: arg2 in 0x1|0x2
 munmap: 1
 getuid32: 1
 fstat64: 1
-mmap2: arg2 in PROT_READ|PROT_WRITE
+mmap2: arg2 in 0x1|0x2
 geteuid32: 1
 getgid32: 1
 getegid32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
index e5e7afb..9b3ef09 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -25,11 +25,11 @@
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
-mprotect: arg2 in PROT_READ|PROT_WRITE
+mprotect: arg2 in 0x1|0x2
 munmap: 1
 getuid: 1
 fstat: 1
-mmap: arg2 in PROT_READ|PROT_WRITE
+mmap: arg2 in 0x1|0x2
 geteuid: 1
 getgid: 1
 getegid: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
index b78c94a..2ef31b0 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -35,6 +35,14 @@
 #define PR_SET_VMA 0x53564d41
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA
 
+#if 0
+libminijail on vendor partitions older than P does not have constants from <sys/mman.h>.
+Define the values of PROT_READ and PROT_WRITE ourselves to maintain backwards compatibility.
+#else
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#endif
+
 madvise: 1
 mprotect: arg2 in PROT_READ|PROT_WRITE
 munmap: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy
index b1f459d..254330d 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86.policy
@@ -26,11 +26,11 @@
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
-mprotect: arg2 in PROT_READ|PROT_WRITE
+mprotect: arg2 in 0x1|0x2
 munmap: 1
 getuid32: 1
 fstat64: 1
-mmap2: arg2 in PROT_READ|PROT_WRITE
+mmap2: arg2 in 0x1|0x2
 geteuid32: 1
 getgid32: 1
 getegid32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.x86_64.policy b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
index e5e7afb..9b3ef09 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86_64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
@@ -25,11 +25,11 @@
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
-mprotect: arg2 in PROT_READ|PROT_WRITE
+mprotect: arg2 in 0x1|0x2
 munmap: 1
 getuid: 1
 fstat: 1
-mmap: arg2 in PROT_READ|PROT_WRITE
+mmap: arg2 in 0x1|0x2
 geteuid: 1
 getgid: 1
 getegid: 1
diff --git a/demangle/Android.bp b/demangle/Android.bp
index 89b8772..8d5b135 100644
--- a/demangle/Android.bp
+++ b/demangle/Android.bp
@@ -42,11 +42,11 @@
     ],
 
     local_include_dirs: [
-       "include",
+        "include",
     ],
 
     export_include_dirs: [
-       "include",
+        "include",
     ],
 }
 
diff --git a/init/Android.bp b/init/Android.bp
index 6c80ee6..69b4ee4 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -56,7 +56,7 @@
         },
         uml: {
             cppflags: ["-DUSER_MODE_LINUX"],
-        }
+        },
     },
     static_libs: [
         "libbootloader_message",
@@ -93,6 +93,8 @@
     defaults: ["init_defaults"],
     srcs: [
         "action.cpp",
+        "action_manager.cpp",
+        "action_parser.cpp",
         "bootchart.cpp",
         "builtins.cpp",
         "capabilities.cpp",
diff --git a/init/action.cpp b/init/action.cpp
index ba03e66..11335ca 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -21,11 +21,9 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 
-#include "stable_properties.h"
 #include "util.h"
 
 using android::base::Join;
-using android::base::StartsWith;
 
 namespace android {
 namespace init {
@@ -70,8 +68,15 @@
     return Join(args_, ' ');
 }
 
-Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line)
-    : oneshot_(oneshot), subcontext_(subcontext), filename_(filename), line_(line) {}
+Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
+               const std::string& event_trigger,
+               const std::map<std::string, std::string>& property_triggers)
+    : property_triggers_(property_triggers),
+      event_trigger_(event_trigger),
+      oneshot_(oneshot),
+      subcontext_(subcontext),
+      filename_(filename),
+      line_(line) {}
 
 const KeywordFunctionMap* Action::function_map_ = nullptr;
 
@@ -135,85 +140,6 @@
     }
 }
 
-static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
-    static bool enabled =
-        android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
-
-    if (subcontext == nullptr || !enabled) {
-        return true;
-    }
-
-    if (kExportedActionableProperties.count(prop_name) == 1) {
-        return true;
-    }
-    for (const auto& prefix : kPartnerPrefixes) {
-        if (android::base::StartsWith(prop_name, prefix)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
-    const static std::string prop_str("property:");
-    std::string prop_name(trigger.substr(prop_str.length()));
-    size_t equal_pos = prop_name.find('=');
-    if (equal_pos == std::string::npos) {
-        return Error() << "property trigger found without matching '='";
-    }
-
-    std::string prop_value(prop_name.substr(equal_pos + 1));
-    prop_name.erase(equal_pos);
-
-    if (!IsActionableProperty(subcontext_, prop_name)) {
-        return Error() << "unexported property tigger found: " << prop_name;
-    }
-
-    if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
-        return Error() << "multiple property triggers found for same property";
-    }
-    return Success();
-}
-
-Result<Success> Action::InitTriggers(const std::vector<std::string>& args) {
-    const static std::string prop_str("property:");
-    for (std::size_t i = 0; i < args.size(); ++i) {
-        if (args[i].empty()) {
-            return Error() << "empty trigger is not valid";
-        }
-
-        if (i % 2) {
-            if (args[i] != "&&") {
-                return Error() << "&& is the only symbol allowed to concatenate actions";
-            } else {
-                continue;
-            }
-        }
-
-        if (!args[i].compare(0, prop_str.length(), prop_str)) {
-            if (auto result = ParsePropertyTrigger(args[i]); !result) {
-                return result;
-            }
-        } else {
-            if (!event_trigger_.empty()) {
-                return Error() << "multiple event triggers are not allowed";
-            }
-
-            event_trigger_ = args[i];
-        }
-    }
-
-    return Success();
-}
-
-Result<Success> Action::InitSingleTrigger(const std::string& trigger) {
-    std::vector<std::string> name_vector{trigger};
-    if (auto result = InitTriggers(name_vector); !result) {
-        return Error() << "InitTriggers() failed: " << result.error();
-    }
-    return Success();
-}
-
 // This function checks that all property triggers are satisfied, that is
 // for each (name, value) in property_triggers_, check that the current
 // value of the property 'name' == value.
@@ -281,142 +207,5 @@
     }
 }
 
-ActionManager::ActionManager() : current_command_(0) {
-}
-
-ActionManager& ActionManager::GetInstance() {
-    static ActionManager instance;
-    return instance;
-}
-
-void ActionManager::AddAction(std::unique_ptr<Action> action) {
-    actions_.emplace_back(std::move(action));
-}
-
-void ActionManager::QueueEventTrigger(const std::string& trigger) {
-    event_queue_.emplace(trigger);
-}
-
-void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
-    event_queue_.emplace(std::make_pair(name, value));
-}
-
-void ActionManager::QueueAllPropertyActions() {
-    QueuePropertyChange("", "");
-}
-
-void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
-    auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0);
-    std::vector<std::string> name_vector{name};
-
-    if (auto result = action->InitSingleTrigger(name); !result) {
-        LOG(ERROR) << "Cannot queue BuiltinAction for " << name << ": " << result.error();
-        return;
-    }
-
-    action->AddCommand(func, name_vector, 0);
-
-    event_queue_.emplace(action.get());
-    actions_.emplace_back(std::move(action));
-}
-
-void ActionManager::ExecuteOneCommand() {
-    // Loop through the event queue until we have an action to execute
-    while (current_executing_actions_.empty() && !event_queue_.empty()) {
-        for (const auto& action : actions_) {
-            if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
-                           event_queue_.front())) {
-                current_executing_actions_.emplace(action.get());
-            }
-        }
-        event_queue_.pop();
-    }
-
-    if (current_executing_actions_.empty()) {
-        return;
-    }
-
-    auto action = current_executing_actions_.front();
-
-    if (current_command_ == 0) {
-        std::string trigger_name = action->BuildTriggersString();
-        LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
-                  << ":" << action->line() << ")";
-    }
-
-    action->ExecuteOneCommand(current_command_);
-
-    // If this was the last command in the current action, then remove
-    // the action from the executing list.
-    // If this action was oneshot, then also remove it from actions_.
-    ++current_command_;
-    if (current_command_ == action->NumCommands()) {
-        current_executing_actions_.pop();
-        current_command_ = 0;
-        if (action->oneshot()) {
-            auto eraser = [&action] (std::unique_ptr<Action>& a) {
-                return a.get() == action;
-            };
-            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
-        }
-    }
-}
-
-bool ActionManager::HasMoreCommands() const {
-    return !current_executing_actions_.empty() || !event_queue_.empty();
-}
-
-void ActionManager::DumpState() const {
-    for (const auto& a : actions_) {
-        a->DumpState();
-    }
-}
-
-void ActionManager::ClearQueue() {
-    // We are shutting down so don't claim the oneshot builtin actions back
-    current_executing_actions_ = {};
-    event_queue_ = {};
-    current_command_ = 0;
-}
-
-Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
-                                           const std::string& filename, int line) {
-    std::vector<std::string> triggers(args.begin() + 1, args.end());
-    if (triggers.size() < 1) {
-        return Error() << "Actions must have a trigger";
-    }
-
-    Subcontext* action_subcontext = nullptr;
-    if (subcontexts_) {
-        for (auto& subcontext : *subcontexts_) {
-            if (StartsWith(filename, subcontext.path_prefix())) {
-                action_subcontext = &subcontext;
-                break;
-            }
-        }
-    }
-
-    auto action = std::make_unique<Action>(false, action_subcontext, filename, line);
-
-    if (auto result = action->InitTriggers(triggers); !result) {
-        return Error() << "InitTriggers() failed: " << result.error();
-    }
-
-    action_ = std::move(action);
-    return Success();
-}
-
-Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
-    return action_ ? action_->AddCommand(std::move(args), line) : Success();
-}
-
-Result<Success> ActionParser::EndSection() {
-    if (action_ && action_->NumCommands() > 0) {
-        action_manager_->AddAction(std::move(action_));
-    }
-
-    return Success();
-}
-
 }  // namespace init
 }  // namespace android
diff --git a/init/action.h b/init/action.h
index 1bfc6c7..4f063cc 100644
--- a/init/action.h
+++ b/init/action.h
@@ -25,7 +25,6 @@
 
 #include "builtins.h"
 #include "keyword_map.h"
-#include "parser.h"
 #include "result.h"
 #include "subcontext.h"
 
@@ -58,12 +57,12 @@
 
 class Action {
   public:
-    Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line);
+    Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
+           const std::string& event_trigger,
+           const std::map<std::string, std::string>& property_triggers);
 
     Result<Success> AddCommand(const std::vector<std::string>& args, int line);
     void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
-    Result<Success> InitTriggers(const std::vector<std::string>& args);
-    Result<Success> InitSingleTrigger(const std::string& trigger);
     std::size_t NumCommands() const;
     void ExecuteOneCommand(std::size_t command) const;
     void ExecuteAllCommands() const;
@@ -84,7 +83,6 @@
     void ExecuteCommand(const Command& command) const;
     bool CheckPropertyTriggers(const std::string& name = "",
                                const std::string& value = "") const;
-    Result<Success> ParsePropertyTrigger(const std::string& trigger);
 
     std::map<std::string, std::string> property_triggers_;
     std::string event_trigger_;
@@ -96,48 +94,6 @@
     static const KeywordFunctionMap* function_map_;
 };
 
-class ActionManager {
-  public:
-    static ActionManager& GetInstance();
-
-    // Exposed for testing
-    ActionManager();
-
-    void AddAction(std::unique_ptr<Action> action);
-    void QueueEventTrigger(const std::string& trigger);
-    void QueuePropertyChange(const std::string& name, const std::string& value);
-    void QueueAllPropertyActions();
-    void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
-    void ExecuteOneCommand();
-    bool HasMoreCommands() const;
-    void DumpState() const;
-    void ClearQueue();
-
-  private:
-    ActionManager(ActionManager const&) = delete;
-    void operator=(ActionManager const&) = delete;
-
-    std::vector<std::unique_ptr<Action>> actions_;
-    std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
-    std::queue<const Action*> current_executing_actions_;
-    std::size_t current_command_;
-};
-
-class ActionParser : public SectionParser {
-  public:
-    ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
-        : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
-    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
-                                 int line) override;
-    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
-    Result<Success> EndSection() override;
-
-  private:
-    ActionManager* action_manager_;
-    std::vector<Subcontext>* subcontexts_;
-    std::unique_ptr<Action> action_;
-};
-
 }  // namespace init
 }  // namespace android
 
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
new file mode 100644
index 0000000..22977bb
--- /dev/null
+++ b/init/action_manager.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 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 "action_manager.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace init {
+
+ActionManager::ActionManager() : current_command_(0) {}
+
+ActionManager& ActionManager::GetInstance() {
+    static ActionManager instance;
+    return instance;
+}
+
+void ActionManager::AddAction(std::unique_ptr<Action> action) {
+    actions_.emplace_back(std::move(action));
+}
+
+void ActionManager::QueueEventTrigger(const std::string& trigger) {
+    event_queue_.emplace(trigger);
+}
+
+void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
+    event_queue_.emplace(std::make_pair(name, value));
+}
+
+void ActionManager::QueueAllPropertyActions() {
+    QueuePropertyChange("", "");
+}
+
+void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
+    auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
+                                           std::map<std::string, std::string>{});
+    std::vector<std::string> name_vector{name};
+
+    action->AddCommand(func, name_vector, 0);
+
+    event_queue_.emplace(action.get());
+    actions_.emplace_back(std::move(action));
+}
+
+void ActionManager::ExecuteOneCommand() {
+    // Loop through the event queue until we have an action to execute
+    while (current_executing_actions_.empty() && !event_queue_.empty()) {
+        for (const auto& action : actions_) {
+            if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
+                           event_queue_.front())) {
+                current_executing_actions_.emplace(action.get());
+            }
+        }
+        event_queue_.pop();
+    }
+
+    if (current_executing_actions_.empty()) {
+        return;
+    }
+
+    auto action = current_executing_actions_.front();
+
+    if (current_command_ == 0) {
+        std::string trigger_name = action->BuildTriggersString();
+        LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
+                  << ":" << action->line() << ")";
+    }
+
+    action->ExecuteOneCommand(current_command_);
+
+    // If this was the last command in the current action, then remove
+    // the action from the executing list.
+    // If this action was oneshot, then also remove it from actions_.
+    ++current_command_;
+    if (current_command_ == action->NumCommands()) {
+        current_executing_actions_.pop();
+        current_command_ = 0;
+        if (action->oneshot()) {
+            auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
+            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
+        }
+    }
+}
+
+bool ActionManager::HasMoreCommands() const {
+    return !current_executing_actions_.empty() || !event_queue_.empty();
+}
+
+void ActionManager::DumpState() const {
+    for (const auto& a : actions_) {
+        a->DumpState();
+    }
+}
+
+void ActionManager::ClearQueue() {
+    // We are shutting down so don't claim the oneshot builtin actions back
+    current_executing_actions_ = {};
+    event_queue_ = {};
+    current_command_ = 0;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/action_manager.h b/init/action_manager.h
new file mode 100644
index 0000000..5f47a6d
--- /dev/null
+++ b/init/action_manager.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_ACTION_MANAGER_H
+#define _INIT_ACTION_MANAGER_H
+
+#include <string>
+#include <vector>
+
+#include "action.h"
+#include "builtins.h"
+
+namespace android {
+namespace init {
+
+class ActionManager {
+  public:
+    static ActionManager& GetInstance();
+
+    // Exposed for testing
+    ActionManager();
+
+    void AddAction(std::unique_ptr<Action> action);
+    void QueueEventTrigger(const std::string& trigger);
+    void QueuePropertyChange(const std::string& name, const std::string& value);
+    void QueueAllPropertyActions();
+    void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
+    void ExecuteOneCommand();
+    bool HasMoreCommands() const;
+    void DumpState() const;
+    void ClearQueue();
+
+  private:
+    ActionManager(ActionManager const&) = delete;
+    void operator=(ActionManager const&) = delete;
+
+    std::vector<std::unique_ptr<Action>> actions_;
+    std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
+    std::queue<const Action*> current_executing_actions_;
+    std::size_t current_command_;
+};
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
new file mode 100644
index 0000000..8a4b518
--- /dev/null
+++ b/init/action_parser.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2018 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 "action_parser.h"
+
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+
+#include "stable_properties.h"
+
+using android::base::GetBoolProperty;
+using android::base::StartsWith;
+
+namespace android {
+namespace init {
+
+namespace {
+
+bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
+    static bool enabled = GetBoolProperty("ro.actionable_compatible_property.enabled", false);
+
+    if (subcontext == nullptr || !enabled) {
+        return true;
+    }
+
+    if (kExportedActionableProperties.count(prop_name) == 1) {
+        return true;
+    }
+    for (const auto& prefix : kPartnerPrefixes) {
+        if (android::base::StartsWith(prop_name, prefix)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+Result<Success> ParsePropertyTrigger(const std::string& trigger, Subcontext* subcontext,
+                                     std::map<std::string, std::string>* property_triggers) {
+    const static std::string prop_str("property:");
+    std::string prop_name(trigger.substr(prop_str.length()));
+    size_t equal_pos = prop_name.find('=');
+    if (equal_pos == std::string::npos) {
+        return Error() << "property trigger found without matching '='";
+    }
+
+    std::string prop_value(prop_name.substr(equal_pos + 1));
+    prop_name.erase(equal_pos);
+
+    if (!IsActionableProperty(subcontext, prop_name)) {
+        return Error() << "unexported property tigger found: " << prop_name;
+    }
+
+    if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
+        return Error() << "multiple property triggers found for same property";
+    }
+    return Success();
+}
+
+Result<Success> ParseTriggers(const std::vector<std::string>& args, Subcontext* subcontext,
+                              std::string* event_trigger,
+                              std::map<std::string, std::string>* property_triggers) {
+    const static std::string prop_str("property:");
+    for (std::size_t i = 0; i < args.size(); ++i) {
+        if (args[i].empty()) {
+            return Error() << "empty trigger is not valid";
+        }
+
+        if (i % 2) {
+            if (args[i] != "&&") {
+                return Error() << "&& is the only symbol allowed to concatenate actions";
+            } else {
+                continue;
+            }
+        }
+
+        if (!args[i].compare(0, prop_str.length(), prop_str)) {
+            if (auto result = ParsePropertyTrigger(args[i], subcontext, property_triggers);
+                !result) {
+                return result;
+            }
+        } else {
+            if (!event_trigger->empty()) {
+                return Error() << "multiple event triggers are not allowed";
+            }
+
+            *event_trigger = args[i];
+        }
+    }
+
+    return Success();
+}
+
+}  // namespace
+
+Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
+                                           const std::string& filename, int line) {
+    std::vector<std::string> triggers(args.begin() + 1, args.end());
+    if (triggers.size() < 1) {
+        return Error() << "Actions must have a trigger";
+    }
+
+    Subcontext* action_subcontext = nullptr;
+    if (subcontexts_) {
+        for (auto& subcontext : *subcontexts_) {
+            if (StartsWith(filename, subcontext.path_prefix())) {
+                action_subcontext = &subcontext;
+                break;
+            }
+        }
+    }
+
+    std::string event_trigger;
+    std::map<std::string, std::string> property_triggers;
+
+    if (auto result = ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
+        !result) {
+        return Error() << "ParseTriggers() failed: " << result.error();
+    }
+
+    auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
+                                           property_triggers);
+
+    action_ = std::move(action);
+    return Success();
+}
+
+Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
+    return action_ ? action_->AddCommand(std::move(args), line) : Success();
+}
+
+Result<Success> ActionParser::EndSection() {
+    if (action_ && action_->NumCommands() > 0) {
+        action_manager_->AddAction(std::move(action_));
+    }
+
+    return Success();
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/action_parser.h b/init/action_parser.h
new file mode 100644
index 0000000..b7f7074
--- /dev/null
+++ b/init/action_parser.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_ACTION_PARSER_H
+#define _INIT_ACTION_PARSER_H
+
+#include <string>
+#include <vector>
+
+#include "action.h"
+#include "action_manager.h"
+#include "parser.h"
+#include "subcontext.h"
+
+namespace android {
+namespace init {
+
+class ActionParser : public SectionParser {
+  public:
+    ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
+        : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
+    Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+                                 int line) override;
+    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
+    Result<Success> EndSection() override;
+
+  private:
+    ActionManager* action_manager_;
+    std::vector<Subcontext>* subcontexts_;
+    std::unique_ptr<Action> action_;
+};
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index be259c2..1040b47 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -58,7 +58,7 @@
 #include <selinux/selinux.h>
 #include <system/thread_defs.h>
 
-#include "action.h"
+#include "action_manager.h"
 #include "bootchart.h"
 #include "init.h"
 #include "parser.h"
@@ -285,11 +285,8 @@
 
     if (e4crypt_is_native()) {
         if (e4crypt_set_directory_policy(args[1].c_str())) {
-            const std::vector<std::string> options = {
-                "--prompt_and_wipe_data",
-                "--reason=set_policy_failed:"s + args[1]};
-            reboot_into_recovery(options);
-            return Success();
+            reboot_into_recovery(
+                {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
         }
     }
     return Success();
@@ -987,6 +984,24 @@
     return android::base::GetProperty("ro.crypto.type", "") == "file";
 }
 
+static Result<Success> ExecWithRebootOnFailure(const std::string& reboot_reason,
+                                               const std::vector<std::string>& args) {
+    auto service = Service::MakeTemporaryOneshotService(args);
+    if (!service) {
+        return Error() << "Could not create exec service";
+    }
+    service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
+        if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
+            reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+        }
+    });
+    if (auto result = service->ExecStart(); !result) {
+        return Error() << "Could not start exec service: " << result.error();
+    }
+    ServiceList::GetInstance().AddService(std::move(service));
+    return Success();
+}
+
 static Result<Success> do_installkey(const BuiltinArguments& args) {
     if (!is_file_crypto()) return Success();
 
@@ -994,15 +1009,13 @@
     if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
         return ErrnoError() << "Failed to create " << unencrypted_dir;
     }
-    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
-                                          "enablefilecrypto"};
-    return do_exec({std::move(exec_args), args.context});
+    return ExecWithRebootOnFailure("enablefilecrypto_failed", {"exec", "/system/bin/vdc", "--wait",
+                                                               "cryptfs", "enablefilecrypto"});
 }
 
 static Result<Success> do_init_user0(const BuiltinArguments& args) {
-    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
-                                          "init_user0"};
-    return do_exec({std::move(exec_args), args.context});
+    return ExecWithRebootOnFailure("init_user0_failed",
+                                   {"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"});
 }
 
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
diff --git a/init/init.cpp b/init/init.cpp
index bd09e4b..efb9c1d 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -35,6 +35,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/android_reboot.h>
 #include <keyutils.h>
@@ -45,6 +46,7 @@
 #include <memory>
 #include <optional>
 
+#include "action_parser.h"
 #include "import_parser.h"
 #include "init_first_stage.h"
 #include "keychords.h"
@@ -62,7 +64,10 @@
 
 using android::base::boot_clock;
 using android::base::GetProperty;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
 using android::base::Timer;
+using android::base::Trim;
 
 namespace android {
 namespace init {
@@ -245,7 +250,7 @@
     return control_message_functions;
 }
 
-void handle_control_message(const std::string& msg, const std::string& name) {
+void HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
     const auto& map = get_control_message_map();
     const auto it = map.find(msg);
 
@@ -254,6 +259,18 @@
         return;
     }
 
+    std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
+    std::string process_cmdline;
+    if (ReadFileToString(cmdline_path, &process_cmdline)) {
+        std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
+        process_cmdline = Trim(process_cmdline);
+    } else {
+        process_cmdline = "unknown process";
+    }
+
+    LOG(INFO) << "Received control message '" << msg << "' for '" << name << "' from pid: " << pid
+              << " (" << process_cmdline << ")";
+
     const ControlMessageFunction& function = it->second;
 
     if (function.target == ControlTarget::SERVICE) {
diff --git a/init/init.h b/init/init.h
index ff7bdeb..d4a0e96 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,10 +17,13 @@
 #ifndef _INIT_INIT_H
 #define _INIT_INIT_H
 
+#include <sys/types.h>
+
 #include <string>
 #include <vector>
 
 #include "action.h"
+#include "action_manager.h"
 #include "parser.h"
 #include "service.h"
 
@@ -35,7 +38,7 @@
 
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
 
-void handle_control_message(const std::string& msg, const std::string& arg);
+void HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
 
 void property_changed(const std::string& name, const std::string& value);
 
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 268873c..0f9635f 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -21,6 +21,8 @@
 #include <gtest/gtest.h>
 
 #include "action.h"
+#include "action_manager.h"
+#include "action_parser.h"
 #include "builtins.h"
 #include "import_parser.h"
 #include "keyword_map.h"
diff --git a/init/property_service.cpp b/init/property_service.cpp
index ecd5baa..0cf6184 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -436,7 +436,7 @@
             return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
         }
 
-        handle_control_message(name.c_str() + 4, value.c_str());
+        HandleControlMessage(name.c_str() + 4, value, cr.pid);
         return PROP_SUCCESS;
     }
 
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index 95dd340..c038aff 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -45,11 +45,13 @@
   // ...so we can send it a malformed request.
   uint32_t msg = PROP_MSG_SETPROP2;
   uint32_t size = 0xffffffff;
-  uint32_t data = 0xdeadbeef;
 
   ASSERT_EQ(static_cast<ssize_t>(sizeof(msg)), send(fd, &msg, sizeof(msg), 0));
   ASSERT_EQ(static_cast<ssize_t>(sizeof(size)), send(fd, &size, sizeof(size), 0));
-  ASSERT_EQ(static_cast<ssize_t>(sizeof(data)), send(fd, &data, sizeof(data), 0));
+  uint32_t result = 0;
+  ASSERT_EQ(static_cast<ssize_t>(sizeof(result)),
+            TEMP_FAILURE_RETRY(recv(fd, &result, sizeof(result), MSG_WAITALL)));
+  EXPECT_EQ(static_cast<uint32_t>(PROP_ERROR_READ_DATA), result);
   ASSERT_EQ(0, close(fd));
 }
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index a88a42d..242750a 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -50,6 +50,7 @@
 #include <private/android_filesystem_config.h>
 #include <selinux/selinux.h>
 
+#include "action_manager.h"
 #include "capabilities.h"
 #include "init.h"
 #include "property_service.h"
diff --git a/init/service.cpp b/init/service.cpp
index a4e33f7..35dd319 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -189,7 +189,8 @@
       capabilities_(capabilities),
       namespace_flags_(namespace_flags),
       seclabel_(seclabel),
-      onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0),
+      onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
+                 "onrestart", {}),
       keychord_id_(0),
       ioprio_class_(IoSchedClass_NONE),
       ioprio_pri_(0),
@@ -199,9 +200,7 @@
       soft_limit_in_bytes_(-1),
       limit_in_bytes_(-1),
       start_order_(0),
-      args_(args) {
-    onrestart_.InitSingleTrigger("onrestart");
-}
+      args_(args) {}
 
 void Service::NotifyStateChange(const std::string& new_state) const {
     if ((flags_ & SVC_TEMPORARY) != 0) {
@@ -299,7 +298,7 @@
     }
 }
 
-void Service::Reap() {
+void Service::Reap(const siginfo_t& siginfo) {
     if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
         KillProcessGroup(SIGKILL);
     }
@@ -308,6 +307,10 @@
     std::for_each(descriptors_.begin(), descriptors_.end(),
                   std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
 
+    for (const auto& f : reap_callbacks_) {
+        f(siginfo);
+    }
+
     if (flags_ & SVC_EXEC) UnSetExec();
 
     if (flags_ & SVC_TEMPORARY) return;
diff --git a/init/service.h b/init/service.h
index d46a413..bcf1943 100644
--- a/init/service.h
+++ b/init/service.h
@@ -17,6 +17,7 @@
 #ifndef _INIT_SERVICE_H
 #define _INIT_SERVICE_H
 
+#include <signal.h>
 #include <sys/resource.h>
 #include <sys/types.h>
 
@@ -81,7 +82,7 @@
     void Stop();
     void Terminate();
     void Restart();
-    void Reap();
+    void Reap(const siginfo_t& siginfo);
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
     bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@@ -89,6 +90,9 @@
         is_exec_service_running_ = false;
         flags_ &= ~SVC_EXEC;
     }
+    void AddReapCallback(std::function<void(const siginfo_t& siginfo)> callback) {
+        reap_callbacks_.emplace_back(std::move(callback));
+    }
 
     static bool is_exec_service_running() { return is_exec_service_running_; }
 
@@ -210,6 +214,8 @@
     std::vector<std::pair<int, rlimit>> rlimits_;
 
     std::vector<std::string> args_;
+
+    std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
 };
 
 class ServiceList {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 072a0fb..badacaf 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -84,16 +84,15 @@
         }
     }
 
-    auto status = siginfo.si_status;
-    if (WIFEXITED(status)) {
-        LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
-    } else if (WIFSIGNALED(status)) {
-        LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
+    if (siginfo.si_code == CLD_EXITED) {
+        LOG(INFO) << name << " exited with status " << siginfo.si_status << wait_string;
+    } else {
+        LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
     }
 
     if (!service) return true;
 
-    service->Reap();
+    service->Reap(siginfo);
 
     if (service->flags() & SVC_TEMPORARY) {
         ServiceList::GetInstance().RemoveService(*service);
diff --git a/init/test_service/Android.bp b/init/test_service/Android.bp
index 6399699..8bd16a7 100644
--- a/init/test_service/Android.bp
+++ b/init/test_service/Android.bp
@@ -17,7 +17,10 @@
 cc_binary {
     name: "test_service",
     srcs: ["test_service.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: ["libbase"],
     init_rc: ["test_service.rc"],
 }
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index 29ffe32..ae1481f 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -19,7 +19,7 @@
         "FuseBuffer.cc",
         "FuseBridgeLoop.cc",
         "EpollController.cc",
-    ]
+    ],
 }
 
 cc_test {
@@ -31,5 +31,5 @@
         "tests/FuseAppLoopTest.cc",
         "tests/FuseBridgeLoopTest.cc",
         "tests/FuseBufferTest.cc",
-    ]
+    ],
 }
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 9a12f0d..8a2afea 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -16,7 +16,11 @@
 
 cc_defaults {
     name: "libasyncio_defaults",
-    cflags: ["-Wall", "-Werror", "-Wextra"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
 }
 
 cc_library {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 10a4e46..4bd01d2 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -27,7 +27,6 @@
 
     include_dirs: ["external/libunwind/include/tdep"],
 
-
     target: {
         darwin: {
             enabled: false,
@@ -41,7 +40,7 @@
         lib64: {
             suffix: "64",
         },
-    }
+    },
 }
 
 libbacktrace_sources = [
@@ -83,6 +82,9 @@
     target: {
         darwin: {
             enabled: true,
+            shared_libs: [
+                "libbase",
+            ],
         },
         linux: {
             srcs: libbacktrace_sources,
@@ -103,7 +105,7 @@
                 "art/runtime",
             ],
 
-            header_libs: [ "jni_headers", ],
+            header_libs: ["jni_headers"],
         },
         android: {
             static_libs: ["libasync_safe"],
@@ -111,7 +113,7 @@
         vendor: {
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_shared_libs: ["libdexfile"],
-        }
+        },
     },
     whole_static_libs: ["libdemangle"],
 }
@@ -127,7 +129,7 @@
     srcs: ["backtrace_testlib.cpp"],
 
     shared_libs: [
-      "libunwindstack",
+        "libunwindstack",
     ],
 }
 
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index dec241c..6445a7c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -85,14 +85,12 @@
 std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
   std::string map_name;
   if (BacktraceMap::IsValid(frame->map)) {
+    map_name = frame->map.Name();
     if (!frame->map.name.empty()) {
-      map_name = frame->map.name.c_str();
       if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
         map_name.resize(map_name.size() - 1);
         map_name += StringPrintf(":%" PRIPTR "]", frame->map.start);
       }
-    } else {
-      map_name = StringPrintf("<anonymous:%" PRIPTR ">", frame->map.start);
     }
   } else {
     map_name = "<unknown>";
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index c8a500c..bdae140 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -24,11 +24,21 @@
 
 #include <log/log.h>
 
-#include <backtrace/backtrace_constants.h>
+#include <android-base/stringprintf.h>
+#include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#include <backtrace/backtrace_constants.h>
 
 #include "thread_utils.h"
 
+using android::base::StringPrintf;
+
+std::string backtrace_map_t::Name() const {
+  if (!name.empty()) return name;
+  if (start == 0 && end == 0) return "";
+  return StringPrintf("<anonymous:%" PRIPTR ">", start);
+}
+
 BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
   if (pid_ < 0) {
     pid_ = getpid();
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 7e2e6d0..0e32e47 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -52,6 +52,7 @@
   auto process_memory = stack_map->process_memory();
   unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
                                  regs, stack_map->process_memory());
+  unwinder.SetResolveNames(stack_map->ResolveNames());
   if (stack_map->GetJitDebug() != nullptr) {
     unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
   }
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index e19c413..da54472 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -48,6 +48,9 @@
   uint64_t load_bias = 0;
   int flags = 0;
   std::string name;
+
+  // Returns `name` if non-empty, or `<anonymous:0x...>` otherwise.
+  std::string Name() const;
 };
 
 namespace unwindstack {
@@ -151,6 +154,13 @@
 
   const std::vector<std::string>& GetSuffixesToIgnore() { return suffixes_to_ignore_; }
 
+  // Disabling the resolving of names results in the function name being
+  // set to an empty string and the function offset being set to zero
+  // in the frame data when unwinding.
+  void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
+
+  bool ResolveNames() { return resolve_names_; }
+
  protected:
   BacktraceMap(pid_t pid);
 
@@ -161,6 +171,7 @@
   pid_t pid_;
   std::deque<backtrace_map_t> maps_;
   std::vector<std::string> suffixes_to_ignore_;
+  bool resolve_names_ = true;
 };
 
 class ScopedBacktraceMapIteratorLock {
diff --git a/libion/Android.bp b/libion/Android.bp
index 6d9fae0..2f73d92 100644
--- a/libion/Android.bp
+++ b/libion/Android.bp
@@ -1,4 +1,3 @@
-
 cc_library {
     name: "libion",
     vendor_available: true,
diff --git a/libion/ion_test.c b/libion/ion_test.c
index b7d5583..f3874ae 100644
--- a/libion/ion_test.c
+++ b/libion/ion_test.c
@@ -250,7 +250,7 @@
         case 'p':
             prot = 0;
             prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0;
-            prot |= strstr(optarg, "MAP_SHARED") ? MAP_PRIVATE : 0;
+            prot |= strstr(optarg, "MAP_SHARED") ? MAP_SHARED : 0;
             break;
         case 'f':
             alloc_flags = atol(optarg);
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index ade2821..28c87e4 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -171,6 +171,36 @@
 #endif
     ;
 
+#ifndef log_id_t_defined
+#define log_id_t_defined
+typedef enum log_id {
+  LOG_ID_MIN = 0,
+
+  LOG_ID_MAIN = 0,
+  LOG_ID_RADIO = 1,
+  LOG_ID_EVENTS = 2,
+  LOG_ID_SYSTEM = 3,
+  LOG_ID_CRASH = 4,
+  LOG_ID_STATS = 5,
+  LOG_ID_SECURITY = 6,
+  LOG_ID_KERNEL = 7, /* place last, third-parties can not use it */
+
+  LOG_ID_MAX
+} log_id_t;
+#endif
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char* tag,
+                            const char* text);
+int __android_log_buf_print(int bufID, int prio, const char* tag,
+                            const char* fmt, ...)
+#if defined(__GNUC__)
+    __attribute__((__format__(printf, 4, 5)))
+#endif
+    ;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 9d21e56..66670fe 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -3,8 +3,8 @@
     android_name_to_log_id; # vndk
     android_log_id_to_name; # vndk
     __android_log_assert;
-    __android_log_buf_print; # vndk
-    __android_log_buf_write; # vndk
+    __android_log_buf_print;
+    __android_log_buf_write;
     __android_log_print;
     __android_log_vprint;
     __android_log_write;
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 8b76a65..b428dd7 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -16,7 +16,7 @@
         },
         host: {
             shared_libs: ["liblog"],
-        }
+        },
     },
 }
 
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 089f3b8..6e63b74 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -1,9 +1,8 @@
-
 cc_library_headers {
     name: "libnativebridge-dummy-headers",
 
     host_supported: true,
-    export_include_dirs=["include"],
+    export_include_dirs: ["include"],
 }
 
 cc_library {
@@ -11,9 +10,12 @@
 
     host_supported: true,
     srcs: ["native_bridge.cc"],
-    shared_libs: ["liblog", "libbase"],
+    shared_libs: [
+        "liblog",
+        "libbase",
+    ],
 
-    export_include_dirs=["include"],
+    export_include_dirs: ["include"],
 
     cflags: [
         "-Werror",
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index 2d33704..5cf88b0 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -17,31 +17,34 @@
 cc_library {
     name: "libfoo.oem1",
     srcs: ["test.cpp"],
-    cflags : ["-DLIBNAME=\"libfoo.oem1.so\""],
+    cflags: ["-DLIBNAME=\"libfoo.oem1.so\""],
     shared_libs: [
         "libbase",
     ],
 }
+
 cc_library {
     name: "libbar.oem1",
     srcs: ["test.cpp"],
-    cflags : ["-DLIBNAME=\"libbar.oem1.so\""],
+    cflags: ["-DLIBNAME=\"libbar.oem1.so\""],
     shared_libs: [
         "libbase",
     ],
 }
+
 cc_library {
     name: "libfoo.oem2",
     srcs: ["test.cpp"],
-    cflags : ["-DLIBNAME=\"libfoo.oem2.so\""],
+    cflags: ["-DLIBNAME=\"libfoo.oem2.so\""],
     shared_libs: [
         "libbase",
     ],
 }
+
 cc_library {
     name: "libbar.oem2",
     srcs: ["test.cpp"],
-    cflags : ["-DLIBNAME=\"libbar.oem2.so\""],
+    cflags: ["-DLIBNAME=\"libbar.oem2.so\""],
     shared_libs: [
         "libbase",
     ],
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index 3d202fc..27693b3 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -2,7 +2,10 @@
 
     name: "libpackagelistparser",
     srcs: ["packagelistparser.c"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: ["liblog"],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 1cfabd5..83b0a7f 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -16,7 +16,11 @@
 
 cc_defaults {
     name: "libprocinfo_defaults",
-    cflags: ["-Wall", "-Werror", "-Wextra"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
 }
 
 cc_library {
@@ -65,7 +69,10 @@
         },
     },
 
-    shared_libs: ["libbase", "libprocinfo"],
+    shared_libs: [
+        "libbase",
+        "libprocinfo",
+    ],
 
     compile_multilib: "both",
     multilib: {
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index 846a585..82bf1bc 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -11,5 +11,5 @@
         windows: {
             enabled: true,
         },
-    }
+    },
 }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 34bfcef..124c70e 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -78,7 +78,10 @@
     target: {
         // Always disable optimizations for host to make it easier to debug.
         host: {
-            cflags: ["-O0", "-g"],
+            cflags: [
+                "-O0",
+                "-g",
+            ],
         },
         vendor: {
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
@@ -131,7 +134,10 @@
     target: {
         // Always disable optimizations for host to make it easier to debug.
         host: {
-            cflags: ["-O0", "-g"],
+            cflags: [
+                "-O0",
+                "-g",
+            ],
         },
     },
 
@@ -171,6 +177,7 @@
     shared_libs: [
         "libbase",
         "libunwindstack",
+        "libdexfile",
     ],
 
     // libdexfile will eventually properly export headers, for now include
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index dbf772e..02f8a9a 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -20,6 +20,7 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <utility>
 
 #define LOG_TAG "unwind"
 #include <log/log.h>
@@ -36,7 +37,7 @@
 namespace unwindstack {
 
 bool Elf::cache_enabled_;
-std::unordered_map<std::string, std::shared_ptr<Elf>>* Elf::cache_;
+std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* Elf::cache_;
 std::mutex* Elf::cache_lock_;
 
 bool Elf::Init(bool init_gnu_debugdata) {
@@ -308,7 +309,7 @@
 void Elf::SetCachingEnabled(bool enable) {
   if (!cache_enabled_ && enable) {
     cache_enabled_ = true;
-    cache_ = new std::unordered_map<std::string, std::shared_ptr<Elf>>;
+    cache_ = new std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>;
     cache_lock_ = new std::mutex;
   } else if (cache_enabled_ && !enable) {
     cache_enabled_ = false;
@@ -326,18 +327,54 @@
 }
 
 void Elf::CacheAdd(MapInfo* info) {
-  if (info->offset == 0) {
-    (*cache_)[info->name] = info->elf;
-  } else {
-    std::string name(info->name + ':' + std::to_string(info->offset));
-    (*cache_)[name] = info->elf;
+  // If elf_offset != 0, then cache both name:offset and name.
+  // The cached name is used to do lookups if multiple maps for the same
+  // named elf file exist.
+  // For example, if there are two maps boot.odex:1000 and boot.odex:2000
+  // where each reference the entire boot.odex, the cache will properly
+  // use the same cached elf object.
+
+  if (info->offset == 0 || info->elf_offset != 0) {
+    (*cache_)[info->name] = std::make_pair(info->elf, true);
+  }
+
+  if (info->offset != 0) {
+    // The second element in the pair indicates whether elf_offset should
+    // be set to offset when getting out of the cache.
+    (*cache_)[info->name + ':' + std::to_string(info->offset)] =
+        std::make_pair(info->elf, info->elf_offset != 0);
   }
 }
 
-bool Elf::CacheGet(const std::string& name, std::shared_ptr<Elf>* elf) {
+bool Elf::CacheAfterCreateMemory(MapInfo* info) {
+  if (info->name.empty() || info->offset == 0 || info->elf_offset == 0) {
+    return false;
+  }
+
+  auto entry = cache_->find(info->name);
+  if (entry == cache_->end()) {
+    return false;
+  }
+
+  // In this case, the whole file is the elf, and the name has already
+  // been cached. Add an entry at name:offset to get this directly out
+  // of the cache next time.
+  info->elf = entry->second.first;
+  (*cache_)[info->name + ':' + std::to_string(info->offset)] = std::make_pair(info->elf, true);
+  return true;
+}
+
+bool Elf::CacheGet(MapInfo* info) {
+  std::string name(info->name);
+  if (info->offset != 0) {
+    name += ':' + std::to_string(info->offset);
+  }
   auto entry = cache_->find(name);
   if (entry != cache_->end()) {
-    *elf = entry->second;
+    info->elf = entry->second.first;
+    if (entry->second.second) {
+      info->elf_offset = info->offset;
+    }
     return true;
   }
   return false;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index e413081..10afe33 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include <7zCrc.h>
 #include <Xz.h>
@@ -322,19 +323,13 @@
   // Skip the first header, it's always going to be NULL.
   offset += ehdr.e_shentsize;
   for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
-    if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
+    if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
       last_error_.code = ERROR_MEMORY_INVALID;
-      last_error_.address =
-          offset + reinterpret_cast<uintptr_t>(&shdr.sh_type) - reinterpret_cast<uintptr_t>(&shdr);
+      last_error_.address = offset;
       return false;
     }
 
     if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
-      if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
-        last_error_.code = ERROR_MEMORY_INVALID;
-        last_error_.address = offset;
-        return false;
-      }
       // Need to go get the information about the section that contains
       // the string terminated names.
       ShdrType str_shdr;
@@ -343,39 +338,19 @@
         return false;
       }
       uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
-      if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) {
+      if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) {
         last_error_.code = ERROR_MEMORY_INVALID;
-        last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_type) -
-                              reinterpret_cast<uintptr_t>(&str_shdr);
+        last_error_.address = str_offset;
         return false;
       }
       if (str_shdr.sh_type != SHT_STRTAB) {
         last_error_.code = ERROR_UNWIND_INFO;
         return false;
       }
-      if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
-                              sizeof(str_shdr.sh_offset))) {
-        last_error_.code = ERROR_MEMORY_INVALID;
-        last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_offset) -
-                              reinterpret_cast<uintptr_t>(&str_shdr);
-        return false;
-      }
-      if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
-        last_error_.code = ERROR_MEMORY_INVALID;
-        last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_size) -
-                              reinterpret_cast<uintptr_t>(&str_shdr);
-        return false;
-      }
       symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
                                      str_shdr.sh_offset, str_shdr.sh_size));
     } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
       // Look for the .debug_frame and .gnu_debugdata.
-      if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
-        last_error_.code = ERROR_MEMORY_INVALID;
-        last_error_.address = offset + reinterpret_cast<uintptr_t>(&shdr.sh_name) -
-                              reinterpret_cast<uintptr_t>(&shdr);
-        return false;
-      }
       if (shdr.sh_name < sec_size) {
         std::string name;
         if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
@@ -394,14 +369,16 @@
             offset_ptr = &eh_frame_hdr_offset_;
             size_ptr = &eh_frame_hdr_size_;
           }
-          if (offset_ptr != nullptr &&
-              memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
-              memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
+          if (offset_ptr != nullptr) {
             *offset_ptr = shdr.sh_offset;
             *size_ptr = shdr.sh_size;
           }
         }
       }
+    } else if (shdr.sh_type == SHT_STRTAB) {
+      // In order to read soname, keep track of address to offset mapping.
+      strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
+                                                            static_cast<uint64_t>(shdr.sh_offset)));
     }
   }
   return true;
@@ -420,7 +397,7 @@
   soname_type_ = SONAME_INVALID;
 
   uint64_t soname_offset = 0;
-  uint64_t strtab_offset = 0;
+  uint64_t strtab_addr = 0;
   uint64_t strtab_size = 0;
 
   // Find the soname location from the dynamic headers section.
@@ -435,7 +412,7 @@
     }
 
     if (dyn.d_tag == DT_STRTAB) {
-      strtab_offset = dyn.d_un.d_ptr;
+      strtab_addr = dyn.d_un.d_ptr;
     } else if (dyn.d_tag == DT_STRSZ) {
       strtab_size = dyn.d_un.d_val;
     } else if (dyn.d_tag == DT_SONAME) {
@@ -445,16 +422,22 @@
     }
   }
 
-  soname_offset += strtab_offset;
-  if (soname_offset >= strtab_offset + strtab_size) {
-    return false;
+  // Need to map the strtab address to the real offset.
+  for (const auto& entry : strtabs_) {
+    if (entry.first == strtab_addr) {
+      soname_offset = entry.second + soname_offset;
+      if (soname_offset >= entry.second + strtab_size) {
+        return false;
+      }
+      if (!memory_->ReadString(soname_offset, &soname_)) {
+        return false;
+      }
+      soname_type_ = SONAME_VALID;
+      *soname = soname_;
+      return true;
+    }
   }
-  if (!memory_->ReadString(soname_offset, &soname_)) {
-    return false;
-  }
-  soname_type_ = SONAME_VALID;
-  *soname = soname_;
-  return true;
+  return false;
 }
 
 template <typename SymType>
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 0c15335..39378a3 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -117,23 +117,15 @@
   if (Elf::CachingEnabled() && !name.empty()) {
     Elf::CacheLock();
     locked = true;
-    if (offset != 0) {
-      std::string hash(name + ':' + std::to_string(offset));
-      if (Elf::CacheGet(hash, &elf)) {
-        Elf::CacheUnlock();
-        return elf.get();
-      }
-    } else if (Elf::CacheGet(name, &elf)) {
+    if (Elf::CacheGet(this)) {
       Elf::CacheUnlock();
       return elf.get();
     }
   }
 
   Memory* memory = CreateMemory(process_memory);
-  if (locked && offset != 0 && elf_offset != 0) {
-    // In this case, the whole file is the elf, need to see if the elf
-    // data was cached.
-    if (Elf::CacheGet(name, &elf)) {
+  if (locked) {
+    if (Elf::CacheAfterCreateMemory(this)) {
       delete memory;
       Elf::CacheUnlock();
       return elf.get();
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
index 7f16146..5502ce1 100644
--- a/libunwindstack/RegsArm.cpp
+++ b/libunwindstack/RegsArm.cpp
@@ -35,26 +35,25 @@
   return ARCH_ARM;
 }
 
-uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+uint64_t RegsArm::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   uint64_t load_bias = elf->GetLoadBias();
   if (rel_pc < load_bias) {
-    return rel_pc;
+    return 0;
   }
   uint64_t adjusted_rel_pc = rel_pc - load_bias;
-
   if (adjusted_rel_pc < 5) {
-    return rel_pc;
+    return 0;
   }
 
   if (adjusted_rel_pc & 1) {
     // This is a thumb instruction, it could be 2 or 4 bytes.
     uint32_t value;
-    if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
+    if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
         (value & 0xe000f000) != 0xe000f000) {
-      return rel_pc - 2;
+      return 2;
     }
   }
-  return rel_pc - 4;
+  return 4;
 }
 
 void RegsArm::SetFromRaw() {
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index d6b467a..cc6f5ce 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -35,15 +35,11 @@
   return ARCH_ARM64;
 }
 
-uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
+uint64_t RegsArm64::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid() || rel_pc < 4) {
+    return 0;
   }
-
-  if (rel_pc < 4) {
-    return rel_pc;
-  }
-  return rel_pc - 4;
+  return 4;
 }
 
 void RegsArm64::SetFromRaw() {
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
index 6751f52..5d20bef 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -35,16 +35,12 @@
   return ARCH_MIPS;
 }
 
-uint64_t RegsMips::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
+uint64_t RegsMips::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid() || rel_pc < 8) {
+    return 0;
   }
-
-  // For now, just assuming no compact branches
-  if (rel_pc < 8) {
-    return rel_pc;
-  }
-  return rel_pc - 8;
+  // For now, just assume no compact branches
+  return 8;
 }
 
 void RegsMips::SetFromRaw() {
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
index 97082bd..4a03538 100644
--- a/libunwindstack/RegsMips64.cpp
+++ b/libunwindstack/RegsMips64.cpp
@@ -36,16 +36,12 @@
   return ARCH_MIPS64;
 }
 
-uint64_t RegsMips64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
+uint64_t RegsMips64::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid() || rel_pc < 8) {
+    return 0;
   }
-
-  // For now, just assuming no compact branches
-  if (rel_pc < 8) {
-    return rel_pc;
-  }
-  return rel_pc - 8;
+  // For now, just assume no compact branches
+  return 8;
 }
 
 void RegsMips64::SetFromRaw() {
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
index 27476b7..573cb23 100644
--- a/libunwindstack/RegsX86.cpp
+++ b/libunwindstack/RegsX86.cpp
@@ -35,15 +35,11 @@
   return ARCH_X86;
 }
 
-uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc == 0) {
+uint64_t RegsX86::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid() || rel_pc == 0) {
     return 0;
   }
-  return rel_pc - 1;
+  return 1;
 }
 
 void RegsX86::SetFromRaw() {
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index 0f66943..3175a90 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -35,16 +35,11 @@
   return ARCH_X86_64;
 }
 
-uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return rel_pc;
-  }
-
-  if (rel_pc == 0) {
+uint64_t RegsX86_64::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid() || rel_pc == 0) {
     return 0;
   }
-
-  return rel_pc - 1;
+  return 1;
 }
 
 void RegsX86_64::SetFromRaw() {
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index d52a0bf..7da6994 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -68,6 +68,10 @@
     return;
   }
 
+  if (!resolve_names_) {
+    return;
+  }
+
 #if !defined(NO_LIBDEXFILE_SUPPORT)
   if (dex_files_ == nullptr) {
     return;
@@ -79,20 +83,20 @@
 #endif
 }
 
-void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
+void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
+                           uint64_t pc_adjustment) {
   size_t frame_num = frames_.size();
   frames_.resize(frame_num + 1);
   FrameData* frame = &frames_.at(frame_num);
   frame->num = frame_num;
   frame->sp = regs_->sp();
-  frame->rel_pc = adjusted_rel_pc;
+  frame->rel_pc = rel_pc - pc_adjustment;
+  frame->pc = regs_->pc() - pc_adjustment;
 
   if (map_info == nullptr) {
-    frame->pc = regs_->pc();
     return;
   }
 
-  frame->pc = map_info->start + adjusted_rel_pc - elf->GetLoadBias() - map_info->elf_offset;
   frame->map_name = map_info->name;
   frame->map_offset = map_info->offset;
   frame->map_start = map_info->start;
@@ -100,7 +104,8 @@
   frame->map_flags = map_info->flags;
   frame->map_load_bias = elf->GetLoadBias();
 
-  if (!elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) {
+  if (!resolve_names_ ||
+      !elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) {
     frame->function_name = "";
     frame->function_offset = 0;
   }
@@ -135,13 +140,12 @@
 
     MapInfo* map_info = maps_->Find(regs_->pc());
     uint64_t rel_pc;
-    uint64_t adjusted_pc;
-    uint64_t adjusted_rel_pc;
+    uint64_t pc_adjustment = 0;
+    uint64_t step_pc;
     Elf* elf;
     if (map_info == nullptr) {
       rel_pc = regs_->pc();
-      adjusted_rel_pc = rel_pc;
-      adjusted_pc = rel_pc;
+      step_pc = rel_pc;
       last_error_.code = ERROR_INVALID_MAP;
     } else {
       if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
@@ -150,21 +154,20 @@
       elf = map_info->GetElf(process_memory_, true);
       rel_pc = elf->GetRelPc(regs_->pc(), map_info);
       if (adjust_pc) {
-        adjusted_pc = regs_->GetAdjustedPc(rel_pc, elf);
+        pc_adjustment = regs_->GetPcAdjustment(rel_pc, elf);
       } else {
-        adjusted_pc = rel_pc;
+        pc_adjustment = 0;
       }
-      adjusted_rel_pc = adjusted_pc;
+      step_pc = rel_pc - pc_adjustment;
 
       // If the pc is in an invalid elf file, try and get an Elf object
       // using the jit debug information.
       if (!elf->valid() && jit_debug_ != nullptr) {
-        uint64_t adjusted_jit_pc = regs_->pc() - (rel_pc - adjusted_pc);
+        uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment;
         Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc);
         if (jit_elf != nullptr) {
           // The jit debug information requires a non relative adjusted pc.
-          adjusted_pc = adjusted_jit_pc;
-          adjusted_rel_pc = adjusted_pc - map_info->start;
+          step_pc = adjusted_jit_pc;
           elf = jit_elf;
         }
       }
@@ -180,7 +183,7 @@
         regs_->set_dex_pc(0);
       }
 
-      FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
+      FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
 
       // Once a frame is added, stop skipping frames.
       initial_map_names_to_skip = nullptr;
@@ -208,8 +211,8 @@
           in_device_map = true;
         } else {
           bool finished;
-          stepped = elf->Step(rel_pc, adjusted_pc, map_info->elf_offset, regs_,
-                              process_memory_.get(), &finished);
+          stepped = elf->Step(rel_pc, step_pc, map_info->elf_offset, regs_, process_memory_.get(),
+                              &finished);
           elf->GetLastError(&last_error_);
           if (stepped && finished) {
             break;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index a874709..385973e 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -23,6 +23,7 @@
 #include <mutex>
 #include <string>
 #include <unordered_map>
+#include <utility>
 
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Memory.h>
@@ -103,7 +104,8 @@
   static void CacheLock();
   static void CacheUnlock();
   static void CacheAdd(MapInfo* info);
-  static bool CacheGet(const std::string& name, std::shared_ptr<Elf>* elf);
+  static bool CacheGet(MapInfo* info);
+  static bool CacheAfterCreateMemory(MapInfo* info);
 
  protected:
   bool valid_ = false;
@@ -120,7 +122,7 @@
   std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
 
   static bool cache_enabled_;
-  static std::unordered_map<std::string, std::shared_ptr<Elf>>* cache_;
+  static std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* cache_;
   static std::mutex* cache_lock_;
 };
 
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index ea9ec9d..3a221bc 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -157,6 +157,7 @@
   ElfInterface* gnu_debugdata_interface_ = nullptr;
 
   std::vector<Symbols*> symbols_;
+  std::vector<std::pair<uint64_t, uint64_t>> strtabs_;
 };
 
 class ElfInterface32 : public ElfInterface {
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index a5ba7a0..b0e7ea1 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -60,7 +60,7 @@
   uint64_t dex_pc() { return dex_pc_; }
   void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
 
-  virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
+  virtual uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) = 0;
 
   virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
 
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
index b5d344b..5af90d3 100644
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -36,7 +36,7 @@
 
   virtual ArchEnum Arch() override final;
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
 
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index 30e626c..cb05732 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -36,7 +36,7 @@
 
   virtual ArchEnum Arch() override final;
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
 
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
index 3fe6a9f..8e3c01f 100644
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -36,7 +36,7 @@
 
   virtual ArchEnum Arch() override final;
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
 
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
index 6b4bcdf..8c2d443 100644
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -36,7 +36,7 @@
 
   virtual ArchEnum Arch() override final;
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
 
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
index a695bbf..1bc145d 100644
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -37,7 +37,7 @@
 
   virtual ArchEnum Arch() override final;
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
 
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
index 23a3f20..4cd45d4 100644
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -37,7 +37,7 @@
 
   virtual ArchEnum Arch() override final;
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
   void SetFromRaw() override;
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index ebe7b0a..56b0581 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -75,6 +75,10 @@
 
   void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
 
+  // Disabling the resolving of names results in the function name being
+  // set to an empty string and the function offset being set to zero.
+  void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
+
 #if !defined(NO_LIBDEXFILE_SUPPORT)
   void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
 #endif
@@ -84,7 +88,8 @@
 
  private:
   void FillInDexFrame();
-  void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
+  void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
+                   uint64_t pc_adjustment);
 
   size_t max_frames_;
   Maps* maps_;
@@ -95,6 +100,7 @@
 #if !defined(NO_LIBDEXFILE_SUPPORT)
   DexFiles* dex_files_ = nullptr;
 #endif
+  bool resolve_names_ = true;
   ErrorData last_error_;
 };
 
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
index 0086c9e..89331ea 100644
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -60,6 +60,7 @@
 
   void VerifyWithinSameMap(bool cache_enabled);
   void VerifySameMap(bool cache_enabled);
+  void VerifyWithinSameMapNeverReadAtZero(bool cache_enabled);
 
   static std::shared_ptr<Memory> memory_;
 };
@@ -198,4 +199,66 @@
   VerifyWithinSameMap(true);
 }
 
+// Verify that when reading from multiple non-zero offsets in the same map
+// that when cached, all of the elf objects are the same.
+void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
+  if (!cache_enabled) {
+    Elf::SetCachingEnabled(false);
+  }
+
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  WriteElfFile(0, &tf, EM_ARM);
+  lseek(tf.fd, 0x500, SEEK_SET);
+  uint8_t value = 0;
+  write(tf.fd, &value, 1);
+  close(tf.fd);
+
+  uint64_t start = 0x1000;
+  uint64_t end = 0x20000;
+  // Multiple info sections at different offsets will have non-zero elf offsets.
+  MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
+  MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
+  MapInfo info400_1(start, end, 0x400, 0x5, tf.path);
+  MapInfo info400_2(start, end, 0x400, 0x5, tf.path);
+
+  Elf* elf300_1 = info300_1.GetElf(memory_, true);
+  ASSERT_TRUE(elf300_1->valid());
+  EXPECT_EQ(ARCH_ARM, elf300_1->arch());
+  Elf* elf300_2 = info300_2.GetElf(memory_, true);
+  ASSERT_TRUE(elf300_2->valid());
+  EXPECT_EQ(ARCH_ARM, elf300_2->arch());
+  EXPECT_EQ(0x300U, info300_1.elf_offset);
+  EXPECT_EQ(0x300U, info300_2.elf_offset);
+  if (cache_enabled) {
+    EXPECT_EQ(elf300_1, elf300_2);
+  } else {
+    EXPECT_NE(elf300_1, elf300_2);
+  }
+
+  Elf* elf400_1 = info400_1.GetElf(memory_, true);
+  ASSERT_TRUE(elf400_1->valid());
+  EXPECT_EQ(ARCH_ARM, elf400_1->arch());
+  Elf* elf400_2 = info400_2.GetElf(memory_, true);
+  ASSERT_TRUE(elf400_2->valid());
+  EXPECT_EQ(ARCH_ARM, elf400_2->arch());
+  EXPECT_EQ(0x400U, info400_1.elf_offset);
+  EXPECT_EQ(0x400U, info400_2.elf_offset);
+  if (cache_enabled) {
+    EXPECT_EQ(elf400_1, elf400_2);
+    EXPECT_EQ(elf300_1, elf400_1);
+  } else {
+    EXPECT_NE(elf400_1, elf400_2);
+    EXPECT_NE(elf300_1, elf400_1);
+  }
+}
+
+TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero_never_read_at_zero) {
+  VerifyWithinSameMapNeverReadAtZero(false);
+}
+
+TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero_never_read_at_zero) {
+  VerifyWithinSameMapNeverReadAtZero(true);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 042c5fb..bf97e30 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -63,15 +63,28 @@
   template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
   void ManyPhdrs();
 
-  template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
+  enum SonameTestEnum : uint8_t {
+    SONAME_NORMAL,
+    SONAME_DTNULL_AFTER,
+    SONAME_DTSIZE_SMALL,
+    SONAME_MISSING_MAP,
+  };
+
+  template <typename Ehdr, typename Phdr, typename Shdr, typename Dyn>
+  void SonameInit(SonameTestEnum test_type = SONAME_NORMAL);
+
+  template <typename ElfInterfaceType>
   void Soname();
 
-  template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
+  template <typename ElfInterfaceType>
   void SonameAfterDtNull();
 
-  template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
+  template <typename ElfInterfaceType>
   void SonameSize();
 
+  template <typename ElfInterfaceType>
+  void SonameMissingMap();
+
   template <typename ElfType>
   void InitHeadersEhFrameTest();
 
@@ -465,17 +478,29 @@
   ASSERT_EQ(2U, elf_arm.total_entries());
 }
 
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
-void ElfInterfaceTest::Soname() {
-  std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
+template <typename Ehdr, typename Phdr, typename Shdr, typename Dyn>
+void ElfInterfaceTest::SonameInit(SonameTestEnum test_type) {
   Ehdr ehdr;
   memset(&ehdr, 0, sizeof(ehdr));
+  ehdr.e_shoff = 0x200;
+  ehdr.e_shnum = 2;
+  ehdr.e_shentsize = sizeof(Shdr);
   ehdr.e_phoff = 0x100;
   ehdr.e_phnum = 1;
   ehdr.e_phentsize = sizeof(Phdr);
   memory_.SetMemory(0, &ehdr, sizeof(ehdr));
 
+  Shdr shdr;
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_STRTAB;
+  if (test_type == SONAME_MISSING_MAP) {
+    shdr.sh_addr = 0x20100;
+  } else {
+    shdr.sh_addr = 0x10100;
+  }
+  shdr.sh_offset = 0x10000;
+  memory_.SetMemory(0x200 + sizeof(shdr), &shdr, sizeof(shdr));
+
   Phdr phdr;
   memset(&phdr, 0, sizeof(phdr));
   phdr.p_type = PT_DYNAMIC;
@@ -487,15 +512,25 @@
   Dyn dyn;
 
   dyn.d_tag = DT_STRTAB;
-  dyn.d_un.d_ptr = 0x10000;
+  dyn.d_un.d_ptr = 0x10100;
   memory_.SetMemory(offset, &dyn, sizeof(dyn));
   offset += sizeof(dyn);
 
   dyn.d_tag = DT_STRSZ;
-  dyn.d_un.d_val = 0x1000;
+  if (test_type == SONAME_DTSIZE_SMALL) {
+    dyn.d_un.d_val = 0x10;
+  } else {
+    dyn.d_un.d_val = 0x1000;
+  }
   memory_.SetMemory(offset, &dyn, sizeof(dyn));
   offset += sizeof(dyn);
 
+  if (test_type == SONAME_DTNULL_AFTER) {
+    dyn.d_tag = DT_NULL;
+    memory_.SetMemory(offset, &dyn, sizeof(dyn));
+    offset += sizeof(dyn);
+  }
+
   dyn.d_tag = DT_SONAME;
   dyn.d_un.d_val = 0x10;
   memory_.SetMemory(offset, &dyn, sizeof(dyn));
@@ -505,6 +540,11 @@
   memory_.SetMemory(offset, &dyn, sizeof(dyn));
 
   SetStringMemory(0x10010, "fake_soname.so");
+}
+
+template <typename ElfInterfaceType>
+void ElfInterfaceTest::Soname() {
+  std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
 
   uint64_t load_bias = 0;
   ASSERT_TRUE(elf->Init(&load_bias));
@@ -516,55 +556,19 @@
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname) {
-  Soname<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
+  SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>();
+  Soname<ElfInterface32>();
 }
 
 TEST_F(ElfInterfaceTest, elf64_soname) {
-  Soname<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
+  SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>();
+  Soname<ElfInterface64>();
 }
 
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
+template <typename ElfInterfaceType>
 void ElfInterfaceTest::SonameAfterDtNull() {
   std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
 
-  Ehdr ehdr;
-  memset(&ehdr, 0, sizeof(ehdr));
-  ehdr.e_phoff = 0x100;
-  ehdr.e_phnum = 1;
-  ehdr.e_phentsize = sizeof(Phdr);
-  memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
-  Phdr phdr;
-  memset(&phdr, 0, sizeof(phdr));
-  phdr.p_type = PT_DYNAMIC;
-  phdr.p_offset = 0x2000;
-  phdr.p_memsz = sizeof(Dyn) * 3;
-  memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
-  Dyn dyn;
-  uint64_t offset = 0x2000;
-
-  dyn.d_tag = DT_STRTAB;
-  dyn.d_un.d_ptr = 0x10000;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  dyn.d_tag = DT_STRSZ;
-  dyn.d_un.d_val = 0x1000;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  dyn.d_tag = DT_NULL;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  dyn.d_tag = DT_SONAME;
-  dyn.d_un.d_val = 0x10;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  SetStringMemory(0x10010, "fake_soname.so");
-
   uint64_t load_bias = 0;
   ASSERT_TRUE(elf->Init(&load_bias));
   EXPECT_EQ(0U, load_bias);
@@ -574,54 +578,19 @@
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname_after_dt_null) {
-  SonameAfterDtNull<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
+  SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTNULL_AFTER);
+  SonameAfterDtNull<ElfInterface32>();
 }
 
 TEST_F(ElfInterfaceTest, elf64_soname_after_dt_null) {
-  SonameAfterDtNull<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
+  SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTNULL_AFTER);
+  SonameAfterDtNull<ElfInterface64>();
 }
 
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
+template <typename ElfInterfaceType>
 void ElfInterfaceTest::SonameSize() {
   std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
 
-  Ehdr ehdr;
-  memset(&ehdr, 0, sizeof(ehdr));
-  ehdr.e_phoff = 0x100;
-  ehdr.e_phnum = 1;
-  ehdr.e_phentsize = sizeof(Phdr);
-  memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
-  Phdr phdr;
-  memset(&phdr, 0, sizeof(phdr));
-  phdr.p_type = PT_DYNAMIC;
-  phdr.p_offset = 0x2000;
-  phdr.p_memsz = sizeof(Dyn);
-  memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
-  Dyn dyn;
-  uint64_t offset = 0x2000;
-
-  dyn.d_tag = DT_STRTAB;
-  dyn.d_un.d_ptr = 0x10000;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  dyn.d_tag = DT_STRSZ;
-  dyn.d_un.d_val = 0x10;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  dyn.d_tag = DT_SONAME;
-  dyn.d_un.d_val = 0x10;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-  offset += sizeof(dyn);
-
-  dyn.d_tag = DT_NULL;
-  memory_.SetMemory(offset, &dyn, sizeof(dyn));
-
-  SetStringMemory(0x10010, "fake_soname.so");
-
   uint64_t load_bias = 0;
   ASSERT_TRUE(elf->Init(&load_bias));
   EXPECT_EQ(0U, load_bias);
@@ -631,11 +600,37 @@
 }
 
 TEST_F(ElfInterfaceTest, elf32_soname_size) {
-  SonameSize<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
+  SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTSIZE_SMALL);
+  SonameSize<ElfInterface32>();
 }
 
 TEST_F(ElfInterfaceTest, elf64_soname_size) {
-  SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
+  SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTSIZE_SMALL);
+  SonameSize<ElfInterface64>();
+}
+
+// Verify that there is no map from STRTAB in the dynamic section to a
+// STRTAB entry in the section headers.
+template <typename ElfInterfaceType>
+void ElfInterfaceTest::SonameMissingMap() {
+  std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
+
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
+
+  std::string name;
+  ASSERT_FALSE(elf->GetSoname(&name));
+}
+
+TEST_F(ElfInterfaceTest, elf32_soname_missing_map) {
+  SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_MISSING_MAP);
+  SonameMissingMap<ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, elf64_soname_missing_map) {
+  SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_MISSING_MAP);
+  SonameMissingMap<ElfInterface64>();
 }
 
 template <typename ElfType>
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index cd7f2ff..ab23194 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -47,7 +47,7 @@
 
   bool Is32Bit() { return false; }
 
-  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
+  uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 2; }
 
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 
@@ -77,7 +77,7 @@
 
   ArchEnum Arch() override { return ARCH_UNKNOWN; }
 
-  uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
+  uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 0; }
   void SetFromRaw() override {}
   bool SetPcFromReturnAddress(Memory*) override { return false; }
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 7c06373..8b2f6c8 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -96,48 +96,48 @@
 
 TEST_F(RegsTest, rel_pc) {
   RegsArm64 arm64;
-  ASSERT_EQ(0xcU, arm64.GetAdjustedPc(0x10, elf_.get()));
-  ASSERT_EQ(0x0U, arm64.GetAdjustedPc(0x4, elf_.get()));
-  ASSERT_EQ(0x3U, arm64.GetAdjustedPc(0x3, elf_.get()));
-  ASSERT_EQ(0x2U, arm64.GetAdjustedPc(0x2, elf_.get()));
-  ASSERT_EQ(0x1U, arm64.GetAdjustedPc(0x1, elf_.get()));
-  ASSERT_EQ(0x0U, arm64.GetAdjustedPc(0x0, elf_.get()));
+  ASSERT_EQ(4U, arm64.GetPcAdjustment(0x10, elf_.get()));
+  ASSERT_EQ(4U, arm64.GetPcAdjustment(0x4, elf_.get()));
+  ASSERT_EQ(0U, arm64.GetPcAdjustment(0x3, elf_.get()));
+  ASSERT_EQ(0U, arm64.GetPcAdjustment(0x2, elf_.get()));
+  ASSERT_EQ(0U, arm64.GetPcAdjustment(0x1, elf_.get()));
+  ASSERT_EQ(0U, arm64.GetPcAdjustment(0x0, elf_.get()));
 
   RegsX86 x86;
-  ASSERT_EQ(0xffU,  x86.GetAdjustedPc(0x100, elf_.get()));
-  ASSERT_EQ(0x1U,  x86.GetAdjustedPc(0x2, elf_.get()));
-  ASSERT_EQ(0x0U,  x86.GetAdjustedPc(0x1, elf_.get()));
-  ASSERT_EQ(0x0U,  x86.GetAdjustedPc(0x0, elf_.get()));
+  ASSERT_EQ(1U, x86.GetPcAdjustment(0x100, elf_.get()));
+  ASSERT_EQ(1U, x86.GetPcAdjustment(0x2, elf_.get()));
+  ASSERT_EQ(1U, x86.GetPcAdjustment(0x1, elf_.get()));
+  ASSERT_EQ(0U, x86.GetPcAdjustment(0x0, elf_.get()));
 
   RegsX86_64 x86_64;
-  ASSERT_EQ(0xffU,  x86_64.GetAdjustedPc(0x100, elf_.get()));
-  ASSERT_EQ(0x1U,  x86_64.GetAdjustedPc(0x2, elf_.get()));
-  ASSERT_EQ(0x0U,  x86_64.GetAdjustedPc(0x1, elf_.get()));
-  ASSERT_EQ(0x0U,  x86_64.GetAdjustedPc(0x0, elf_.get()));
+  ASSERT_EQ(1U, x86_64.GetPcAdjustment(0x100, elf_.get()));
+  ASSERT_EQ(1U, x86_64.GetPcAdjustment(0x2, elf_.get()));
+  ASSERT_EQ(1U, x86_64.GetPcAdjustment(0x1, elf_.get()));
+  ASSERT_EQ(0U, x86_64.GetPcAdjustment(0x0, elf_.get()));
 
   RegsMips mips;
-  ASSERT_EQ(0x8U, mips.GetAdjustedPc(0x10, elf_.get()));
-  ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x8, elf_.get()));
-  ASSERT_EQ(0x7U, mips.GetAdjustedPc(0x7, elf_.get()));
-  ASSERT_EQ(0x6U, mips.GetAdjustedPc(0x6, elf_.get()));
-  ASSERT_EQ(0x5U, mips.GetAdjustedPc(0x5, elf_.get()));
-  ASSERT_EQ(0x4U, mips.GetAdjustedPc(0x4, elf_.get()));
-  ASSERT_EQ(0x3U, mips.GetAdjustedPc(0x3, elf_.get()));
-  ASSERT_EQ(0x2U, mips.GetAdjustedPc(0x2, elf_.get()));
-  ASSERT_EQ(0x1U, mips.GetAdjustedPc(0x1, elf_.get()));
-  ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x0, elf_.get()));
+  ASSERT_EQ(8U, mips.GetPcAdjustment(0x10, elf_.get()));
+  ASSERT_EQ(8U, mips.GetPcAdjustment(0x8, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x7, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x6, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x5, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x4, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x3, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x2, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x1, elf_.get()));
+  ASSERT_EQ(0U, mips.GetPcAdjustment(0x0, elf_.get()));
 
   RegsMips64 mips64;
-  ASSERT_EQ(0x8U, mips64.GetAdjustedPc(0x10, elf_.get()));
-  ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x8, elf_.get()));
-  ASSERT_EQ(0x7U, mips64.GetAdjustedPc(0x7, elf_.get()));
-  ASSERT_EQ(0x6U, mips64.GetAdjustedPc(0x6, elf_.get()));
-  ASSERT_EQ(0x5U, mips64.GetAdjustedPc(0x5, elf_.get()));
-  ASSERT_EQ(0x4U, mips64.GetAdjustedPc(0x4, elf_.get()));
-  ASSERT_EQ(0x3U, mips64.GetAdjustedPc(0x3, elf_.get()));
-  ASSERT_EQ(0x2U, mips64.GetAdjustedPc(0x2, elf_.get()));
-  ASSERT_EQ(0x1U, mips64.GetAdjustedPc(0x1, elf_.get()));
-  ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x0, elf_.get()));
+  ASSERT_EQ(8U, mips64.GetPcAdjustment(0x10, elf_.get()));
+  ASSERT_EQ(8U, mips64.GetPcAdjustment(0x8, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x7, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x6, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x5, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x4, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x3, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x2, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x1, elf_.get()));
+  ASSERT_EQ(0U, mips64.GetPcAdjustment(0x0, elf_.get()));
 }
 
 TEST_F(RegsTest, rel_pc_arm) {
@@ -145,34 +145,34 @@
 
   // Check fence posts.
   elf_->FakeSetLoadBias(0);
-  ASSERT_EQ(3U,  arm.GetAdjustedPc(0x5, elf_.get()));
-  ASSERT_EQ(4U,  arm.GetAdjustedPc(0x4, elf_.get()));
-  ASSERT_EQ(3U,  arm.GetAdjustedPc(0x3, elf_.get()));
-  ASSERT_EQ(2U,  arm.GetAdjustedPc(0x2, elf_.get()));
-  ASSERT_EQ(1U,  arm.GetAdjustedPc(0x1, elf_.get()));
-  ASSERT_EQ(0U,  arm.GetAdjustedPc(0x0, elf_.get()));
+  ASSERT_EQ(2U, arm.GetPcAdjustment(0x5, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x4, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x3, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x2, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x1, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x0, elf_.get()));
 
   elf_->FakeSetLoadBias(0x100);
-  ASSERT_EQ(0xffU,  arm.GetAdjustedPc(0xff, elf_.get()));
-  ASSERT_EQ(0x103U,  arm.GetAdjustedPc(0x105, elf_.get()));
-  ASSERT_EQ(0x104U,  arm.GetAdjustedPc(0x104, elf_.get()));
-  ASSERT_EQ(0x103U,  arm.GetAdjustedPc(0x103, elf_.get()));
-  ASSERT_EQ(0x102U,  arm.GetAdjustedPc(0x102, elf_.get()));
-  ASSERT_EQ(0x101U,  arm.GetAdjustedPc(0x101, elf_.get()));
-  ASSERT_EQ(0x100U,  arm.GetAdjustedPc(0x100, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0xff, elf_.get()));
+  ASSERT_EQ(2U, arm.GetPcAdjustment(0x105, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x104, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x103, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x102, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x101, elf_.get()));
+  ASSERT_EQ(0U, arm.GetPcAdjustment(0x100, elf_.get()));
 
   // Check thumb instructions handling.
   elf_->FakeSetLoadBias(0);
   memory_->SetData32(0x2000, 0);
-  ASSERT_EQ(0x2003U,  arm.GetAdjustedPc(0x2005, elf_.get()));
+  ASSERT_EQ(2U, arm.GetPcAdjustment(0x2005, elf_.get()));
   memory_->SetData32(0x2000, 0xe000f000);
-  ASSERT_EQ(0x2001U,  arm.GetAdjustedPc(0x2005, elf_.get()));
+  ASSERT_EQ(4U, arm.GetPcAdjustment(0x2005, elf_.get()));
 
   elf_->FakeSetLoadBias(0x400);
   memory_->SetData32(0x2100, 0);
-  ASSERT_EQ(0x2503U,  arm.GetAdjustedPc(0x2505, elf_.get()));
+  ASSERT_EQ(2U, arm.GetPcAdjustment(0x2505, elf_.get()));
   memory_->SetData32(0x2100, 0xf111f111);
-  ASSERT_EQ(0x2501U,  arm.GetAdjustedPc(0x2505, elf_.get()));
+  ASSERT_EQ(4U, arm.GetPcAdjustment(0x2505, elf_.get()));
 }
 
 TEST_F(RegsTest, elf_invalid) {
@@ -188,27 +188,27 @@
 
   regs_arm.set_pc(0x1500);
   EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
-  EXPECT_EQ(0x4fcU, regs_arm.GetAdjustedPc(0x500U, invalid_elf));
+  EXPECT_EQ(4U, regs_arm.GetPcAdjustment(0x500U, invalid_elf));
 
   regs_arm64.set_pc(0x1600);
   EXPECT_EQ(0x600U, invalid_elf->GetRelPc(regs_arm64.pc(), &map_info));
-  EXPECT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, invalid_elf));
+  EXPECT_EQ(0U, regs_arm64.GetPcAdjustment(0x600U, invalid_elf));
 
   regs_x86.set_pc(0x1700);
   EXPECT_EQ(0x700U, invalid_elf->GetRelPc(regs_x86.pc(), &map_info));
-  EXPECT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, invalid_elf));
+  EXPECT_EQ(0U, regs_x86.GetPcAdjustment(0x700U, invalid_elf));
 
   regs_x86_64.set_pc(0x1800);
   EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
-  EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
+  EXPECT_EQ(0U, regs_x86_64.GetPcAdjustment(0x800U, invalid_elf));
 
   regs_mips.set_pc(0x1900);
   EXPECT_EQ(0x900U, invalid_elf->GetRelPc(regs_mips.pc(), &map_info));
-  EXPECT_EQ(0x900U, regs_mips.GetAdjustedPc(0x900U, invalid_elf));
+  EXPECT_EQ(0U, regs_mips.GetPcAdjustment(0x900U, invalid_elf));
 
   regs_mips64.set_pc(0x1a00);
   EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(regs_mips64.pc(), &map_info));
-  EXPECT_EQ(0xa00U, regs_mips64.GetAdjustedPc(0xa00U, invalid_elf));
+  EXPECT_EQ(0U, regs_mips64.GetPcAdjustment(0xa00U, invalid_elf));
 }
 
 TEST_F(RegsTest, arm_set_from_raw) {
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index df262f5..af4a5b5 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -193,6 +193,14 @@
       "  #02 pc 00007441  libbase.so (_ZN7android4base10LogMessageD2Ev+748)\n"
       "  #03 pc 00015147  /does/not/exist/libhidlbase.so\n",
       frame_info);
+  EXPECT_EQ(0xf31ea9f8U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xe9c866f8U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xf2da0a1bU, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xe9c86728U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0xf2da1441U, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xe9c86730U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0xf3367147U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xe9c86778U, unwinder.frames()[3].sp);
 }
 
 TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
@@ -209,6 +217,10 @@
       "  #01 pc 0006dce5  libandroid_runtime.so "
       "(_ZN7android14AndroidRuntime19javaCreateThreadEtcEPFiPvES1_PKcijPS1_)\n",
       frame_info);
+  EXPECT_EQ(0xf1f6dc49U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xd8fe6930U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xf1f6dce5U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xd8fe6958U, unwinder.frames()[1].sp);
 }
 
 TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
@@ -229,6 +241,18 @@
       "(_ZN11unwindstack37UnwindTest_remote_through_signal_Test8TestBodyEv+32)\n"
       "  #05 pc 0000000000455d70  libunwindstack_test (_ZN7testing4Test3RunEv+392)\n",
       frame_info);
+  EXPECT_EQ(0x64d09d4fd8U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7fe0d84040U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x64d09d5078U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7fe0d84070U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x64d09d508cU, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7fe0d84080U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x64d09d88fcU, unwinder.frames()[3].pc);
+  EXPECT_EQ(0x7fe0d84090U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0x64d09d88d8U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0x7fe0d840f0U, unwinder.frames()[4].sp);
+  EXPECT_EQ(0x64d0a00d70U, unwinder.frames()[5].pc);
+  EXPECT_EQ(0x7fe0d84110U, unwinder.frames()[5].sp);
 }
 
 static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
@@ -390,6 +414,144 @@
       "  #67 pc 00001a80  dalvikvm32 (main+1312)\n"
       "  #68 pc 00018275  libc.so\n",
       frame_info);
+  EXPECT_EQ(0xeb89bfb8U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xffeb5280U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xeb89af00U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xffeb52a0U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0xec6061a8U, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xffeb5ce0U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0xee75be81U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xffeb5d30U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xf728e4d2U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xffeb5d60U, unwinder.frames()[4].sp);
+  EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[5].pc);
+  EXPECT_EQ(0xffeb5d80U, unwinder.frames()[5].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[6].pc);
+  EXPECT_EQ(0xffeb5e20U, unwinder.frames()[6].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[7].pc);
+  EXPECT_EQ(0xffeb5ec0U, unwinder.frames()[7].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[8].pc);
+  EXPECT_EQ(0xffeb5f40U, unwinder.frames()[8].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[9].pc);
+  EXPECT_EQ(0xffeb5fb0U, unwinder.frames()[9].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[10].pc);
+  EXPECT_EQ(0xffeb6110U, unwinder.frames()[10].sp);
+  EXPECT_EQ(0xee75be04U, unwinder.frames()[11].pc);
+  EXPECT_EQ(0xffeb6160U, unwinder.frames()[11].sp);
+  EXPECT_EQ(0xf728e4d2U, unwinder.frames()[12].pc);
+  EXPECT_EQ(0xffeb6180U, unwinder.frames()[12].sp);
+  EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[13].pc);
+  EXPECT_EQ(0xffeb61b0U, unwinder.frames()[13].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[14].pc);
+  EXPECT_EQ(0xffeb6250U, unwinder.frames()[14].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[15].pc);
+  EXPECT_EQ(0xffeb62f0U, unwinder.frames()[15].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[16].pc);
+  EXPECT_EQ(0xffeb6370U, unwinder.frames()[16].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[17].pc);
+  EXPECT_EQ(0xffeb63e0U, unwinder.frames()[17].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[18].pc);
+  EXPECT_EQ(0xffeb6530U, unwinder.frames()[18].sp);
+  EXPECT_EQ(0xee75bd3cU, unwinder.frames()[19].pc);
+  EXPECT_EQ(0xffeb6580U, unwinder.frames()[19].sp);
+  EXPECT_EQ(0xf728e4d2U, unwinder.frames()[20].pc);
+  EXPECT_EQ(0xffeb65b0U, unwinder.frames()[20].sp);
+  EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[21].pc);
+  EXPECT_EQ(0xffeb65e0U, unwinder.frames()[21].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[22].pc);
+  EXPECT_EQ(0xffeb6680U, unwinder.frames()[22].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[23].pc);
+  EXPECT_EQ(0xffeb6720U, unwinder.frames()[23].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[24].pc);
+  EXPECT_EQ(0xffeb67a0U, unwinder.frames()[24].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[25].pc);
+  EXPECT_EQ(0xffeb6810U, unwinder.frames()[25].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[26].pc);
+  EXPECT_EQ(0xffeb6960U, unwinder.frames()[26].sp);
+  EXPECT_EQ(0xee75bbdcU, unwinder.frames()[27].pc);
+  EXPECT_EQ(0xffeb69b0U, unwinder.frames()[27].sp);
+  EXPECT_EQ(0xf728e6a2U, unwinder.frames()[28].pc);
+  EXPECT_EQ(0xffeb69f0U, unwinder.frames()[28].sp);
+  EXPECT_EQ(0xf6d27acbU, unwinder.frames()[29].pc);
+  EXPECT_EQ(0xffeb6a20U, unwinder.frames()[29].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[30].pc);
+  EXPECT_EQ(0xffeb6ac0U, unwinder.frames()[30].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[31].pc);
+  EXPECT_EQ(0xffeb6b60U, unwinder.frames()[31].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[32].pc);
+  EXPECT_EQ(0xffeb6be0U, unwinder.frames()[32].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[33].pc);
+  EXPECT_EQ(0xffeb6c50U, unwinder.frames()[33].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[34].pc);
+  EXPECT_EQ(0xffeb6dd0U, unwinder.frames()[34].sp);
+  EXPECT_EQ(0xee75b625U, unwinder.frames()[35].pc);
+  EXPECT_EQ(0xffeb6e20U, unwinder.frames()[35].sp);
+  EXPECT_EQ(0xf728e4d2U, unwinder.frames()[36].pc);
+  EXPECT_EQ(0xffeb6e50U, unwinder.frames()[36].sp);
+  EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[37].pc);
+  EXPECT_EQ(0xffeb6e70U, unwinder.frames()[37].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[38].pc);
+  EXPECT_EQ(0xffeb6f10U, unwinder.frames()[38].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[39].pc);
+  EXPECT_EQ(0xffeb6fb0U, unwinder.frames()[39].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[40].pc);
+  EXPECT_EQ(0xffeb7030U, unwinder.frames()[40].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[41].pc);
+  EXPECT_EQ(0xffeb70a0U, unwinder.frames()[41].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[42].pc);
+  EXPECT_EQ(0xffeb71f0U, unwinder.frames()[42].sp);
+  EXPECT_EQ(0xee75aedcU, unwinder.frames()[43].pc);
+  EXPECT_EQ(0xffeb7240U, unwinder.frames()[43].sp);
+  EXPECT_EQ(0xf728e4d2U, unwinder.frames()[44].pc);
+  EXPECT_EQ(0xffeb72a0U, unwinder.frames()[44].sp);
+  EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[45].pc);
+  EXPECT_EQ(0xffeb72c0U, unwinder.frames()[45].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[46].pc);
+  EXPECT_EQ(0xffeb7360U, unwinder.frames()[46].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[47].pc);
+  EXPECT_EQ(0xffeb7400U, unwinder.frames()[47].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[48].pc);
+  EXPECT_EQ(0xffeb7480U, unwinder.frames()[48].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[49].pc);
+  EXPECT_EQ(0xffeb74f0U, unwinder.frames()[49].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[50].pc);
+  EXPECT_EQ(0xffeb7680U, unwinder.frames()[50].sp);
+  EXPECT_EQ(0xee756c22U, unwinder.frames()[51].pc);
+  EXPECT_EQ(0xffeb76d0U, unwinder.frames()[51].sp);
+  EXPECT_EQ(0xf728e6a2U, unwinder.frames()[52].pc);
+  EXPECT_EQ(0xffeb76f0U, unwinder.frames()[52].sp);
+  EXPECT_EQ(0xf6d27acbU, unwinder.frames()[53].pc);
+  EXPECT_EQ(0xffeb7710U, unwinder.frames()[53].sp);
+  EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[54].pc);
+  EXPECT_EQ(0xffeb77b0U, unwinder.frames()[54].sp);
+  EXPECT_EQ(0xf6f73552U, unwinder.frames()[55].pc);
+  EXPECT_EQ(0xffeb7850U, unwinder.frames()[55].sp);
+  EXPECT_EQ(0xf6f7499aU, unwinder.frames()[56].pc);
+  EXPECT_EQ(0xffeb78d0U, unwinder.frames()[56].sp);
+  EXPECT_EQ(0xf7265362U, unwinder.frames()[57].pc);
+  EXPECT_EQ(0xffeb7940U, unwinder.frames()[57].sp);
+  EXPECT_EQ(0xf72945bdU, unwinder.frames()[58].pc);
+  EXPECT_EQ(0xffeb7a80U, unwinder.frames()[58].sp);
+  EXPECT_EQ(0xf728e6a2U, unwinder.frames()[59].pc);
+  EXPECT_EQ(0xffeb7ad0U, unwinder.frames()[59].sp);
+  EXPECT_EQ(0xf6d27acbU, unwinder.frames()[60].pc);
+  EXPECT_EQ(0xffeb7af0U, unwinder.frames()[60].sp);
+  EXPECT_EQ(0xf718bc95U, unwinder.frames()[61].pc);
+  EXPECT_EQ(0xffeb7b90U, unwinder.frames()[61].sp);
+  EXPECT_EQ(0xf718bb5aU, unwinder.frames()[62].pc);
+  EXPECT_EQ(0xffeb7c50U, unwinder.frames()[62].sp);
+  EXPECT_EQ(0xf706b3ddU, unwinder.frames()[63].pc);
+  EXPECT_EQ(0xffeb7d10U, unwinder.frames()[63].sp);
+  EXPECT_EQ(0xf6d6548cU, unwinder.frames()[64].pc);
+  EXPECT_EQ(0xffeb7d70U, unwinder.frames()[64].sp);
+  EXPECT_EQ(0xf6d5df06U, unwinder.frames()[65].pc);
+  EXPECT_EQ(0xffeb7df0U, unwinder.frames()[65].sp);
+  EXPECT_EQ(0x56574d8cU, unwinder.frames()[66].pc);
+  EXPECT_EQ(0xffeb7e40U, unwinder.frames()[66].sp);
+  EXPECT_EQ(0x56574a80U, unwinder.frames()[67].pc);
+  EXPECT_EQ(0xffeb7e70U, unwinder.frames()[67].sp);
+  EXPECT_EQ(0xf7363275U, unwinder.frames()[68].pc);
+  EXPECT_EQ(0xffeb7ef0U, unwinder.frames()[68].sp);
 }
 
 TEST_F(UnwindOfflineTest, jit_debug_arm) {
@@ -553,6 +715,158 @@
       "  #74 pc 00001349  dalvikvm32 (main+896)\n"
       "  #75 pc 000850c9  libc.so\n",
       frame_info);
+  EXPECT_EQ(0xdfe66a5eU, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xff85d180U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xe044712dU, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xff85d200U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0xe27a7cb1U, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xff85d290U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xff85d2b0U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xed761129U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xff85d2e8U, unwinder.frames()[4].sp);
+  EXPECT_EQ(0xed3b97a9U, unwinder.frames()[5].pc);
+  EXPECT_EQ(0xff85d370U, unwinder.frames()[5].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[6].pc);
+  EXPECT_EQ(0xff85d3d8U, unwinder.frames()[6].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[7].pc);
+  EXPECT_EQ(0xff85d428U, unwinder.frames()[7].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[8].pc);
+  EXPECT_EQ(0xff85d470U, unwinder.frames()[8].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[9].pc);
+  EXPECT_EQ(0xff85d4b0U, unwinder.frames()[9].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[10].pc);
+  EXPECT_EQ(0xff85d5d0U, unwinder.frames()[10].sp);
+  EXPECT_EQ(0xe27a7c31U, unwinder.frames()[11].pc);
+  EXPECT_EQ(0xff85d640U, unwinder.frames()[11].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[12].pc);
+  EXPECT_EQ(0xff85d660U, unwinder.frames()[12].sp);
+  EXPECT_EQ(0xed761129U, unwinder.frames()[13].pc);
+  EXPECT_EQ(0xff85d698U, unwinder.frames()[13].sp);
+  EXPECT_EQ(0xed3b97a9U, unwinder.frames()[14].pc);
+  EXPECT_EQ(0xff85d720U, unwinder.frames()[14].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[15].pc);
+  EXPECT_EQ(0xff85d788U, unwinder.frames()[15].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[16].pc);
+  EXPECT_EQ(0xff85d7d8U, unwinder.frames()[16].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[17].pc);
+  EXPECT_EQ(0xff85d820U, unwinder.frames()[17].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[18].pc);
+  EXPECT_EQ(0xff85d860U, unwinder.frames()[18].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[19].pc);
+  EXPECT_EQ(0xff85d970U, unwinder.frames()[19].sp);
+  EXPECT_EQ(0xe27a7b77U, unwinder.frames()[20].pc);
+  EXPECT_EQ(0xff85d9e0U, unwinder.frames()[20].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[21].pc);
+  EXPECT_EQ(0xff85da10U, unwinder.frames()[21].sp);
+  EXPECT_EQ(0xed761129U, unwinder.frames()[22].pc);
+  EXPECT_EQ(0xff85da48U, unwinder.frames()[22].sp);
+  EXPECT_EQ(0xed3b97a9U, unwinder.frames()[23].pc);
+  EXPECT_EQ(0xff85dad0U, unwinder.frames()[23].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[24].pc);
+  EXPECT_EQ(0xff85db38U, unwinder.frames()[24].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[25].pc);
+  EXPECT_EQ(0xff85db88U, unwinder.frames()[25].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[26].pc);
+  EXPECT_EQ(0xff85dbd0U, unwinder.frames()[26].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[27].pc);
+  EXPECT_EQ(0xff85dc10U, unwinder.frames()[27].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[28].pc);
+  EXPECT_EQ(0xff85dd20U, unwinder.frames()[28].sp);
+  EXPECT_EQ(0xe27a7a29U, unwinder.frames()[29].pc);
+  EXPECT_EQ(0xff85dd90U, unwinder.frames()[29].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[30].pc);
+  EXPECT_EQ(0xff85ddc0U, unwinder.frames()[30].sp);
+  EXPECT_EQ(0xed76122fU, unwinder.frames()[31].pc);
+  EXPECT_EQ(0xff85de08U, unwinder.frames()[31].sp);
+  EXPECT_EQ(0xed3b97bbU, unwinder.frames()[32].pc);
+  EXPECT_EQ(0xff85de90U, unwinder.frames()[32].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[33].pc);
+  EXPECT_EQ(0xff85def8U, unwinder.frames()[33].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[34].pc);
+  EXPECT_EQ(0xff85df48U, unwinder.frames()[34].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[35].pc);
+  EXPECT_EQ(0xff85df90U, unwinder.frames()[35].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[36].pc);
+  EXPECT_EQ(0xff85dfd0U, unwinder.frames()[36].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[37].pc);
+  EXPECT_EQ(0xff85e110U, unwinder.frames()[37].sp);
+  EXPECT_EQ(0xe27a739bU, unwinder.frames()[38].pc);
+  EXPECT_EQ(0xff85e180U, unwinder.frames()[38].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[39].pc);
+  EXPECT_EQ(0xff85e1b0U, unwinder.frames()[39].sp);
+  EXPECT_EQ(0xed761129U, unwinder.frames()[40].pc);
+  EXPECT_EQ(0xff85e1e0U, unwinder.frames()[40].sp);
+  EXPECT_EQ(0xed3b97a9U, unwinder.frames()[41].pc);
+  EXPECT_EQ(0xff85e268U, unwinder.frames()[41].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[42].pc);
+  EXPECT_EQ(0xff85e2d0U, unwinder.frames()[42].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[43].pc);
+  EXPECT_EQ(0xff85e320U, unwinder.frames()[43].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[44].pc);
+  EXPECT_EQ(0xff85e368U, unwinder.frames()[44].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[45].pc);
+  EXPECT_EQ(0xff85e3a8U, unwinder.frames()[45].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[46].pc);
+  EXPECT_EQ(0xff85e4c0U, unwinder.frames()[46].sp);
+  EXPECT_EQ(0xe27a6aa7U, unwinder.frames()[47].pc);
+  EXPECT_EQ(0xff85e530U, unwinder.frames()[47].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[48].pc);
+  EXPECT_EQ(0xff85e5a0U, unwinder.frames()[48].sp);
+  EXPECT_EQ(0xed761129U, unwinder.frames()[49].pc);
+  EXPECT_EQ(0xff85e5d8U, unwinder.frames()[49].sp);
+  EXPECT_EQ(0xed3b97a9U, unwinder.frames()[50].pc);
+  EXPECT_EQ(0xff85e660U, unwinder.frames()[50].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[51].pc);
+  EXPECT_EQ(0xff85e6c8U, unwinder.frames()[51].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[52].pc);
+  EXPECT_EQ(0xff85e718U, unwinder.frames()[52].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[53].pc);
+  EXPECT_EQ(0xff85e760U, unwinder.frames()[53].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[54].pc);
+  EXPECT_EQ(0xff85e7a0U, unwinder.frames()[54].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[55].pc);
+  EXPECT_EQ(0xff85e8f0U, unwinder.frames()[55].sp);
+  EXPECT_EQ(0xe27a1a99U, unwinder.frames()[56].pc);
+  EXPECT_EQ(0xff85e960U, unwinder.frames()[56].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[57].pc);
+  EXPECT_EQ(0xff85e990U, unwinder.frames()[57].sp);
+  EXPECT_EQ(0xed76122fU, unwinder.frames()[58].pc);
+  EXPECT_EQ(0xff85e9c8U, unwinder.frames()[58].sp);
+  EXPECT_EQ(0xed3b97bbU, unwinder.frames()[59].pc);
+  EXPECT_EQ(0xff85ea50U, unwinder.frames()[59].sp);
+  EXPECT_EQ(0xed541833U, unwinder.frames()[60].pc);
+  EXPECT_EQ(0xff85eab8U, unwinder.frames()[60].sp);
+  EXPECT_EQ(0xed528935U, unwinder.frames()[61].pc);
+  EXPECT_EQ(0xff85eb08U, unwinder.frames()[61].sp);
+  EXPECT_EQ(0xed52971dU, unwinder.frames()[62].pc);
+  EXPECT_EQ(0xff85eb50U, unwinder.frames()[62].sp);
+  EXPECT_EQ(0xed73c865U, unwinder.frames()[63].pc);
+  EXPECT_EQ(0xff85eb90U, unwinder.frames()[63].sp);
+  EXPECT_EQ(0xed7606ffU, unwinder.frames()[64].pc);
+  EXPECT_EQ(0xff85ec90U, unwinder.frames()[64].sp);
+  EXPECT_EQ(0xed75c175U, unwinder.frames()[65].pc);
+  EXPECT_EQ(0xff85ed00U, unwinder.frames()[65].sp);
+  EXPECT_EQ(0xed76122fU, unwinder.frames()[66].pc);
+  EXPECT_EQ(0xff85ed38U, unwinder.frames()[66].sp);
+  EXPECT_EQ(0xed3b97bbU, unwinder.frames()[67].pc);
+  EXPECT_EQ(0xff85edc0U, unwinder.frames()[67].sp);
+  EXPECT_EQ(0xed6ac92dU, unwinder.frames()[68].pc);
+  EXPECT_EQ(0xff85ee28U, unwinder.frames()[68].sp);
+  EXPECT_EQ(0xed6ac6c3U, unwinder.frames()[69].pc);
+  EXPECT_EQ(0xff85eeb8U, unwinder.frames()[69].sp);
+  EXPECT_EQ(0xed602411U, unwinder.frames()[70].pc);
+  EXPECT_EQ(0xff85ef48U, unwinder.frames()[70].sp);
+  EXPECT_EQ(0xed3e0a9fU, unwinder.frames()[71].pc);
+  EXPECT_EQ(0xff85ef90U, unwinder.frames()[71].sp);
+  EXPECT_EQ(0xed3db9b9U, unwinder.frames()[72].pc);
+  EXPECT_EQ(0xff85f008U, unwinder.frames()[72].sp);
+  EXPECT_EQ(0xab0d459fU, unwinder.frames()[73].pc);
+  EXPECT_EQ(0xff85f038U, unwinder.frames()[73].sp);
+  EXPECT_EQ(0xab0d4349U, unwinder.frames()[74].pc);
+  EXPECT_EQ(0xff85f050U, unwinder.frames()[74].sp);
+  EXPECT_EQ(0xedb0d0c9U, unwinder.frames()[75].pc);
+  EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp);
 }
 
 // The eh_frame_hdr data is present but set to zero fdes. This should
@@ -573,6 +887,16 @@
       "  #03 pc 0000000000000590  waiter64\n"
       "  #04 pc 00000000000a8e98  libc.so (__libc_init+88)\n",
       frame_info);
+  EXPECT_EQ(0x60a9fdf550U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7fdd141990U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x60a9fdf568U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7fdd1419a0U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x60a9fdf57cU, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7fdd1419b0U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x60a9fdf590U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0x7fdd1419c0U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0x7542d68e98U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0x7fdd1419d0U, unwinder.frames()[4].sp);
 }
 
 // The elf has bad eh_frame unwind information for the pcs. If eh_frame
@@ -592,6 +916,16 @@
       "  #03 pc 000006f7  waiter (main+23)\n"
       "  #04 pc 00018275  libc.so\n",
       frame_info);
+  EXPECT_EQ(0x56598685U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xffcf9e38U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x565986b7U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xffcf9e50U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x565986d7U, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xffcf9e60U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x565986f7U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xffcf9e70U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xf744a275U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xffcf9e80U, unwinder.frames()[4].sp);
 }
 
 // Make sure that a pc that is at the beginning of an fde unwinds correctly.
@@ -610,6 +944,16 @@
       "  #03 pc 00000000000013ed  unwind_test64 (main+13)\n"
       "  #04 pc 00000000000202b0  libc.so\n",
       frame_info);
+  EXPECT_EQ(0x561550b17a80U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7ffcc8596ce8U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x561550b17dd9U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7ffcc8596cf0U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x561550b1821eU, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7ffcc8596f40U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x561550b183edU, unwinder.frames()[3].pc);
+  EXPECT_EQ(0x7ffcc8597190U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0x7f4de62162b0U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0x7ffcc85971a0U, unwinder.frames()[4].sp);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 7fbae4c..e44b225 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -196,6 +196,67 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
+
+  regs_.FakeSetPc(0x1000);
+  regs_.FakeSetSp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  unwinder.SetResolveNames(false);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(3U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x1000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0x1000U, frame->map_start);
+  EXPECT_EQ(0x8000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+
+  frame = &unwinder.frames()[1];
+  EXPECT_EQ(1U, frame->num);
+  EXPECT_EQ(0x100U, frame->rel_pc);
+  EXPECT_EQ(0x1100U, frame->pc);
+  EXPECT_EQ(0x10010U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0x1000U, frame->map_start);
+  EXPECT_EQ(0x8000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+
+  frame = &unwinder.frames()[2];
+  EXPECT_EQ(2U, frame->num);
+  EXPECT_EQ(0x200U, frame->rel_pc);
+  EXPECT_EQ(0x1200U, frame->pc);
+  EXPECT_EQ(0x10020U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0x1000U, frame->map_start);
+  EXPECT_EQ(0x8000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
 TEST_F(UnwinderTest, non_zero_load_bias) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
 
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 7f2d11d..a0abcca 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -120,6 +120,11 @@
     return 1;
   }
 
+  std::string soname;
+  if (elf.GetSoname(&soname)) {
+    printf("Soname: %s\n", soname.c_str());
+  }
+
   ElfInterface* interface = elf.interface();
   if (elf.machine_type() == EM_ARM) {
     DumpArm(reinterpret_cast<ElfInterfaceArm*>(interface));
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index 4d89087..47a4f91 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -157,6 +157,11 @@
     return 1;
   }
 
+  std::string soname;
+  if (elf.GetSoname(&soname)) {
+    printf("Soname: %s\n\n", soname.c_str());
+  }
+
   printf("PC 0x%" PRIx64 ":\n", pc);
 
   DwarfSection* section = interface->eh_frame();
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index 697e4cd..086dffe 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -71,6 +71,11 @@
     return 1;
   }
 
+  std::string soname;
+  if (elf.GetSoname(&soname)) {
+    printf("Soname: %s\n\n", soname.c_str());
+  }
+
   switch (elf.machine_type()) {
     case EM_ARM:
       printf("ABI: arm\n");
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 2be5d98..209bf9a 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -20,12 +20,12 @@
     header_libs: [
         "liblog_headers",
         "libsystem_headers",
-        "libcutils_headers"
+        "libcutils_headers",
     ],
     export_header_lib_headers: [
         "liblog_headers",
         "libsystem_headers",
-        "libcutils_headers"
+        "libcutils_headers",
     ],
     export_include_dirs: ["include"],
 
@@ -52,7 +52,10 @@
     },
     host_supported: true,
 
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     include_dirs: ["external/safe-iop/include"],
     header_libs: [
         "libutils_headers",
@@ -193,7 +196,10 @@
     static_libs: ["libutils"],
     shared_libs: ["liblog"],
     srcs: ["SharedBufferTest.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 }
 
 subdirs = ["tests"]
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index a3e7ffe..1390552 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -77,7 +77,10 @@
     host_supported: true,
     relative_install_path: "libutils_tests",
     srcs: ["Singleton_test1.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 }
 
 cc_test_library {
@@ -85,6 +88,9 @@
     host_supported: true,
     relative_install_path: "libutils_tests",
     srcs: ["Singleton_test2.cpp"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: ["libutils_tests_singleton1"],
 }
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index fec79b7..e73b366 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -3,7 +3,10 @@
 cc_library {
     name: "libvndksupport",
     srcs: ["linker.c"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     local_include_dirs: ["include/vndksupport"],
     export_include_dirs: ["include"],
     shared_libs: ["liblog"],
diff --git a/libvndksupport/tests/Android.bp b/libvndksupport/tests/Android.bp
index 5b467f8..2570cce 100644
--- a/libvndksupport/tests/Android.bp
+++ b/libvndksupport/tests/Android.bp
@@ -17,11 +17,14 @@
     srcs: [
         "linker_test.cpp",
     ],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     host_supported: false,
     shared_libs: [
         "libvndksupport",
         "libbase",
-    ]
+    ],
 }
diff --git a/logcat/Android.bp b/logcat/Android.bp
index afc7a01..01beb53 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -68,8 +68,11 @@
     srcs: ["logpersist"],
     init_rc: ["logcatd.rc"],
     required: ["logcatd"],
-    symlinks: ["logpersist.stop", "logpersist.cat"],
+    symlinks: [
+        "logpersist.stop",
+        "logpersist.cat",
+    ],
     strip: {
         none: true,
-    }
+    },
 }
diff --git a/logd/Android.bp b/logd/Android.bp
index 68b79d3..5c79976 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -25,7 +25,7 @@
     "-DAUDITD_LOG_TAG=1003",
     "-DCHATTY_LOG_TAG=1004",
     "-DTAG_DEF_LOG_TAG=1005",
-    "-DLIBLOG_LOG_TAG=1006"
+    "-DLIBLOG_LOG_TAG=1006",
 ]
 
 cc_library_static {
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index ccb1aa6..f163f57 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -49,5 +49,5 @@
     ],
     cflags: [
         "-Werror",
-    ]
+    ],
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f008c17..a213ffb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -82,10 +82,10 @@
 
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
-    mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
+    mount tmpfs tmpfs /mnt nodev noexec nosuid mode=0755,uid=0,gid=1000
     restorecon_recursive /mnt
 
-    mount configfs none /config
+    mount configfs none /config nodev noexec nosuid
     chmod 0775 /config/sdcardfs
     chown system package_info /config/sdcardfs
 
@@ -318,8 +318,9 @@
     start hwservicemanager
     start vndservicemanager
 
-    # once everything is setup, no need to modify /
-    mount rootfs rootfs / ro remount
+    # Once everything is setup, no need to modify /.
+    # The bind+ro combination avoids modifying any other mount flags.
+    mount rootfs rootfs / remount bind ro
     # Mount shared so changes propagate into child namespaces
     mount rootfs rootfs / shared rec
     # Mount default storage into root namespace
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 322a63d..5428e73 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -31,7 +31,10 @@
         "trusty_keymaster_ipc.cpp",
         "trusty_keymaster_main.cpp",
     ],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "libcrypto",
         "libcutils",
diff --git a/trusty/libtrusty/Android.bp b/trusty/libtrusty/Android.bp
index c48deed..f6e9bee 100644
--- a/trusty/libtrusty/Android.bp
+++ b/trusty/libtrusty/Android.bp
@@ -22,7 +22,10 @@
 
     srcs: ["trusty.c"],
     export_include_dirs: ["include"],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     shared_libs: ["liblog"],
 }
diff --git a/trusty/libtrusty/tipc-test/Android.bp b/trusty/libtrusty/tipc-test/Android.bp
index 1e8467f..32499e3 100644
--- a/trusty/libtrusty/tipc-test/Android.bp
+++ b/trusty/libtrusty/tipc-test/Android.bp
@@ -25,5 +25,8 @@
         "liblog",
     ],
     gtest: false,
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 }
diff --git a/trusty/storage/lib/Android.bp b/trusty/storage/lib/Android.bp
index 4e41674..2fba17e 100644
--- a/trusty/storage/lib/Android.bp
+++ b/trusty/storage/lib/Android.bp
@@ -34,5 +34,5 @@
         "-fvisibility=hidden",
         "-Wall",
         "-Werror",
-    ]
+    ],
 }
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index da8542d..b93facb 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -36,5 +36,5 @@
     cflags: [
         "-Wall",
         "-Werror",
-    ]
+    ],
 }
diff --git a/usbd/Android.bp b/usbd/Android.bp
index 4f9338f..3afa7a9 100644
--- a/usbd/Android.bp
+++ b/usbd/Android.bp
@@ -13,4 +13,3 @@
         "libcutils",
     ],
 }
-