Merge "Revert "init: Reboot after timeout passes during reboot"" into pi-dev
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 87ed3db..c2e9337 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -58,10 +58,6 @@
 #define cpu_to_le16(x) htole16(x)
 #define cpu_to_le32(x) htole32(x)
 
-#define FUNCTIONFS_ENDPOINT_ALLOC       _IOR('g', 231, __u32)
-
-static constexpr size_t ENDPOINT_ALLOC_RETRIES = 10;
-
 static int dummy_fd = -1;
 
 struct func_desc {
@@ -256,7 +252,6 @@
     ssize_t ret;
     struct desc_v1 v1_descriptor;
     struct desc_v2 v2_descriptor;
-    size_t retries = 0;
 
     v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
     v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
@@ -324,30 +319,6 @@
 
     h->read_aiob.fd = h->bulk_out;
     h->write_aiob.fd = h->bulk_in;
-
-    h->max_rw = MAX_PAYLOAD;
-    while (h->max_rw >= USB_FFS_BULK_SIZE && retries < ENDPOINT_ALLOC_RETRIES) {
-        int ret_in = ioctl(h->bulk_in, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
-        int errno_in = errno;
-        int ret_out = ioctl(h->bulk_out, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
-        int errno_out = errno;
-
-        if (ret_in || ret_out) {
-            if (errno_in == ENODEV || errno_out == ENODEV) {
-                std::this_thread::sleep_for(100ms);
-                retries += 1;
-                continue;
-            }
-            h->max_rw /= 2;
-        } else {
-            return true;
-        }
-    }
-
-    D("[ adb: cannot call endpoint alloc: errno=%d ]", errno);
-    // Kernel pre-allocation could have failed for recoverable reasons.
-    // Continue running with a safe max rw size.
-    h->max_rw = USB_FFS_BULK_SIZE;
     return true;
 
 err:
@@ -401,7 +372,7 @@
 
     const char* buf = static_cast<const char*>(data);
     while (len > 0) {
-        int write_len = std::min(h->max_rw, len);
+        int write_len = std::min(USB_FFS_BULK_SIZE, len);
         int n = adb_write(h->bulk_in, buf, write_len);
         if (n < 0) {
             D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
@@ -420,7 +391,7 @@
 
     char* buf = static_cast<char*>(data);
     while (len > 0) {
-        int read_len = std::min(h->max_rw, len);
+        int read_len = std::min(USB_FFS_BULK_SIZE, len);
         int n = adb_read(h->bulk_out, buf, read_len);
         if (n < 0) {
             D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
diff --git a/adb/daemon/usb.h b/adb/daemon/usb.h
index db1a6d6..15a7f65 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/usb.h
@@ -54,7 +54,5 @@
     // read and write threads.
     struct aio_block read_aiob;
     struct aio_block write_aiob;
-
-    int max_rw;
 };
 
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index 49e0363..0fcf89b 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -98,13 +98,22 @@
     return android::base::GetProperty("ro.boot.slot_suffix", "");
 }
 
+static bool is_avb_device_locked() {
+    return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
+}
+
 /* Use AVB to turn verity on/off */
 static bool set_avb_verity_enabled_state(int fd, AvbOps* ops, bool enable_verity) {
     std::string ab_suffix = get_ab_suffix();
-
     bool verity_enabled;
+
+    if (is_avb_device_locked()) {
+        WriteFdFmt(fd, "Device is locked. Please unlock the device first\n");
+        return false;
+    }
+
     if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
-        WriteFdFmt(fd, "Error getting verity state\n");
+        WriteFdFmt(fd, "Error getting verity state. Try adb root first?\n");
         return false;
     }
 
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index afff2c9..cc7aaf6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -105,6 +105,9 @@
 
 void DefaultAborter(const char* abort_message);
 
+std::string GetDefaultTag();
+void SetDefaultTag(const std::string& tag);
+
 #ifdef __ANDROID__
 // We expose this even though it is the default because a user that wants to
 // override the default log buffer will have to construct this themselves.
diff --git a/base/logging.cpp b/base/logging.cpp
index 1f7bc2a..a31feef 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -139,9 +139,27 @@
   return aborter;
 }
 
-static std::string& ProgramInvocationName() {
-  static auto& programInvocationName = *new std::string(getprogname());
-  return programInvocationName;
+static std::recursive_mutex& TagLock() {
+  static auto& tag_lock = *new std::recursive_mutex();
+  return tag_lock;
+}
+static std::string* gDefaultTag;
+std::string GetDefaultTag() {
+  std::lock_guard<std::recursive_mutex> lock(TagLock());
+  if (gDefaultTag == nullptr) {
+    return "";
+  }
+  return *gDefaultTag;
+}
+void SetDefaultTag(const std::string& tag) {
+  std::lock_guard<std::recursive_mutex> lock(TagLock());
+  if (gDefaultTag != nullptr) {
+    delete gDefaultTag;
+    gDefaultTag = nullptr;
+  }
+  if (!tag.empty()) {
+    gDefaultTag = new std::string(tag);
+  }
 }
 
 static bool gInitialized = false;
@@ -269,8 +287,7 @@
   // Linux to recover this, but we don't have that luxury on the Mac/Windows,
   // and there are a couple of argv[0] variants that are commonly used.
   if (argv != nullptr) {
-    std::lock_guard<std::mutex> lock(LoggingLock());
-    ProgramInvocationName() = basename(argv[0]);
+    SetDefaultTag(basename(argv[0]));
   }
 
   const char* tags = getenv("ANDROID_LOG_TAGS");
@@ -448,8 +465,15 @@
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
                          const char* tag, const char* message) {
-  if (tag == nullptr) tag = ProgramInvocationName().c_str();
-  Logger()(id, severity, tag, file, line, message);
+  if (tag == nullptr) {
+    std::lock_guard<std::recursive_mutex> lock(TagLock());
+    if (gDefaultTag == nullptr) {
+      gDefaultTag = new std::string(getprogname());
+    }
+    Logger()(id, severity, gDefaultTag->c_str(), file, line, message);
+  } else {
+    Logger()(id, severity, tag, file, line, message);
+  }
 }
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 6f05d9b..5f689fa 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -206,8 +206,8 @@
 }
 #endif
 
-static void CheckMessage(const CapturedStderr& cap,
-                         android::base::LogSeverity severity, const char* expected) {
+static void CheckMessage(const CapturedStderr& cap, android::base::LogSeverity severity,
+                         const char* expected, const char* expected_tag = nullptr) {
   std::string output;
   ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
   android::base::ReadFdToString(cap.fd(), &output);
@@ -217,9 +217,18 @@
   // many characters are in the log message.
   ASSERT_GT(output.length(), strlen(expected));
   ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
+  if (expected_tag != nullptr) {
+    ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output;
+  }
 
 #if !defined(_WIN32)
-  std::regex message_regex(make_log_pattern(severity, expected));
+  std::string regex_str;
+  if (expected_tag != nullptr) {
+    regex_str.append(expected_tag);
+    regex_str.append(" ");
+  }
+  regex_str.append(make_log_pattern(severity, expected));
+  std::regex message_regex(regex_str);
   ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
 }
@@ -600,3 +609,17 @@
 __attribute__((constructor)) void TestLoggingInConstructor() {
   LOG(ERROR) << "foobar";
 }
+
+TEST(logging, SetDefaultTag) {
+  constexpr const char* expected_tag = "test_tag";
+  constexpr const char* expected_msg = "foobar";
+  CapturedStderr cap;
+  {
+    std::string old_default_tag = android::base::GetDefaultTag();
+    android::base::SetDefaultTag(expected_tag);
+    android::base::ScopedLogSeverity sls(android::base::LogSeverity::INFO);
+    LOG(INFO) << expected_msg;
+    android::base::SetDefaultTag(old_default_tag);
+  }
+  CheckMessage(cap, android::base::LogSeverity::INFO, expected_msg, expected_tag);
+}
diff --git a/init/stable_properties.h b/init/stable_properties.h
index be35457..4d47434 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -29,10 +29,12 @@
 };
 
 static const std::set<std::string> kExportedActionableProperties = {
+    "init.svc.console",
     "init.svc.mediadrm",
     "init.svc.zygote",
     "persist.bluetooth.btsnoopenable",
     "persist.sys.crash_rcu",
+    "persist.sys.usb.usbradio.config",
     "persist.sys.zram_enabled",
     "ro.bootmode",
     "ro.build.type",
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index ac1d7c7..24b14c4 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -83,8 +83,8 @@
 }
 
 UeventListener::UeventListener() {
-    // is 256K enough? udev uses 16MB!
-    device_fd_.reset(uevent_open_socket(256 * 1024, true));
+    // is 2MB enough? udev uses 128MB!
+    device_fd_.reset(uevent_open_socket(2 * 1024 * 1024, true));
     if (device_fd_ == -1) {
         LOG(FATAL) << "Could not open uevent socket";
     }
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index 1eab46c..1915f22 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -149,8 +149,8 @@
     }
 
     constexpr int kMaxMessageSize = sizeof(FuseBuffer);
-    if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0 ||
-        setsockopt(fds[1], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0) {
+    if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0 ||
+        setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0) {
         PLOG(ERROR) << "Failed to update buffer size for socket";
         return false;
     }
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 7a70bf3..3063815 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -25,7 +25,7 @@
 
 // The numbers came from sdcard.c.
 // Maximum number of bytes to write/read in one request/one reply.
-constexpr size_t kFuseMaxWrite = 256 * 1024;
+constexpr size_t kFuseMaxWrite = 128 * 1024;
 constexpr size_t kFuseMaxRead = 128 * 1024;
 constexpr int32_t kFuseSuccess = 0;
 
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index d03a2b6..2754e6e 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -243,7 +243,7 @@
 
 static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
   struct android_log_transport_write* node;
-  int ret;
+  int ret, save_errno;
   struct timespec ts;
   size_t len, i;
 
@@ -254,20 +254,24 @@
     return -EINVAL;
   }
 
+  save_errno = errno;
 #if defined(__ANDROID__)
   clock_gettime(android_log_clockid(), &ts);
 
   if (log_id == LOG_ID_SECURITY) {
     if (vec[0].iov_len < 4) {
+      errno = save_errno;
       return -EINVAL;
     }
 
     ret = check_log_uid_permissions();
     if (ret < 0) {
+      errno = save_errno;
       return ret;
     }
     if (!__android_log_security()) {
       /* If only we could reset downstream logd counter */
+      errno = save_errno;
       return -EPERM;
     }
   } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
@@ -276,6 +280,7 @@
     EventTagMap *m, *f;
 
     if (vec[0].iov_len < 4) {
+      errno = save_errno;
       return -EINVAL;
     }
 
@@ -311,6 +316,7 @@
       android_closeEventTagMap(f);
     }
     if (!ret) {
+      errno = save_errno;
       return -EPERM;
     }
   } else {
@@ -340,6 +346,7 @@
     }
 
     if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
+      errno = save_errno;
       return -EPERM;
     }
   }
@@ -371,21 +378,23 @@
     }
   }
 
+  errno = save_errno;
   return ret;
 }
 
 static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
+  int ret, save_errno = errno;
+
   __android_log_lock();
 
   if (write_to_log == __write_to_log_init) {
-    int ret;
-
     ret = __write_to_log_initialize();
     if (ret < 0) {
       __android_log_unlock();
       if (!list_empty(&__android_log_persist_write)) {
         __write_to_log_daemon(log_id, vec, nr);
       }
+      errno = save_errno;
       return ret;
     }
 
@@ -394,7 +403,9 @@
 
   __android_log_unlock();
 
-  return write_to_log(log_id, vec, nr);
+  ret = write_to_log(log_id, vec, nr);
+  errno = save_errno;
+  return ret;
 }
 
 LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag,
diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h
index 663b8b0..ea92007 100644
--- a/libsystem/include/system/graphics-base.h
+++ b/libsystem/include/system/graphics-base.h
@@ -4,12 +4,4 @@
 #include "graphics-base-v1.0.h"
 #include "graphics-base-v1.1.h"
 
-/* Legacy formats not in the HAL definitions. */
-typedef enum {
-    HAL_PIXEL_FORMAT_YCBCR_422_888 = 39,   // 0x27
-    HAL_PIXEL_FORMAT_YCBCR_444_888 = 40,   // 0x28
-    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41,    // 0x29
-    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42,  // 0x2A
-} android_pixel_format_legacy_t;
-
 #endif  // SYSTEM_CORE_GRAPHICS_BASE_H_
diff --git a/libsystem/include/system/graphics-sw.h b/libsystem/include/system/graphics-sw.h
new file mode 100644
index 0000000..9e1a88e
--- /dev/null
+++ b/libsystem/include/system/graphics-sw.h
@@ -0,0 +1,16 @@
+#ifndef SYSTEM_CORE_GRAPHICS_SW_H_
+#define SYSTEM_CORE_GRAPHICS_SW_H_
+
+/* Software formats not in the HAL definitions. */
+typedef enum {
+    HAL_PIXEL_FORMAT_YCBCR_422_888 = 39,   // 0x27
+    HAL_PIXEL_FORMAT_YCBCR_444_888 = 40,   // 0x28
+    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41,    // 0x29
+    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42,  // 0x2A
+} android_pixel_format_sw_t;
+
+/* for compatibility */
+#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
+#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
+
+#endif  // SYSTEM_CORE_GRAPHICS_SW_H_
diff --git a/libsystem/include/system/graphics.h b/libsystem/include/system/graphics.h
index 657370b..1b6060a 100644
--- a/libsystem/include/system/graphics.h
+++ b/libsystem/include/system/graphics.h
@@ -25,6 +25,7 @@
  * generated.
  */
 #include "graphics-base.h"
+#include "graphics-sw.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -32,8 +33,6 @@
 
 /* for compatibility */
 #define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888
-#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
-#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
 #define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP
 #define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP
 #define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 7f92904..35a3063 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -137,6 +137,12 @@
         switch(rta->rta_type) {
             case IFLA_IFNAME:
                 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
+                // We can get the interface change information from sysfs update
+                // already. But in case we missed those message when devices start.
+                // We do a update again when received a kLinkUp event. To make
+                // the message consistent, use IFINDEX here as well since sysfs
+                // uses IFINDEX.
+                asprintf(&mParams[1], "IFINDEX=%d", ifi->ifi_index);
                 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp :
                                                             Action::kLinkDown;
                 mSubsystem = strdup("net");
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 124c70e..ab01726 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -253,6 +253,7 @@
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
+        "tests/files/offline/art_quick_osr_stub_arm/*",
         "tests/files/offline/bad_eh_frame_hdr_arm64/*",
         "tests/files/offline/debug_frame_first_x86/*",
         "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index 4fc95c7..aa8cd3a 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -424,7 +424,10 @@
 
 template <typename AddressType>
 bool DwarfCfa<AddressType>::cfa_def_cfa_expression(dwarf_loc_regs_t* loc_regs) {
-  (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_EXPRESSION,
+  // There is only one type of expression for CFA evaluation and the DWARF
+  // specification is unclear whether it returns the address or the
+  // dereferenced value. GDB expects the value, so will we.
+  (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_VAL_EXPRESSION,
                           .values = {operands_[0], memory_->cur_offset()}};
   return true;
 }
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 7649798..5586e72 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -190,8 +190,6 @@
   // Always set the dex pc to zero when evaluating.
   cur_regs->set_dex_pc(0);
 
-  AddressType prev_cfa = regs->sp();
-
   EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs,
                                   .cie = cie,
                                   .regular_memory = regular_memory,
@@ -204,31 +202,16 @@
         last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
         return false;
       }
-      // If the stack pointer register is the CFA, and the stack
-      // pointer register does not have any associated location
-      // information, use the current cfa value.
-      if (regs->sp_reg() == loc->values[0] && loc_regs.count(regs->sp_reg()) == 0) {
-        eval_info.cfa = prev_cfa;
-      } else {
-        eval_info.cfa = (*cur_regs)[loc->values[0]];
-      }
+      eval_info.cfa = (*cur_regs)[loc->values[0]];
       eval_info.cfa += loc->values[1];
       break;
-    case DWARF_LOCATION_EXPRESSION:
     case DWARF_LOCATION_VAL_EXPRESSION: {
       AddressType value;
       if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) {
         return false;
       }
-      if (loc->type == DWARF_LOCATION_EXPRESSION) {
-        if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
-          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-          last_error_.address = value;
-          return false;
-        }
-      } else {
-        eval_info.cfa = value;
-      }
+      // There is only one type of valid expression for CFA evaluation.
+      eval_info.cfa = value;
       break;
     }
     default:
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index dfb8e8f..f93baeb 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -127,13 +127,9 @@
   if (arm.ExtractEntryData(entry_offset) && arm.Eval()) {
     // If the pc was not set, then use the LR registers for the PC.
     if (!arm.pc_set()) {
-      regs_arm->set_pc((*regs_arm)[ARM_REG_LR]);
-      (*regs_arm)[ARM_REG_PC] = regs_arm->pc();
-    } else {
-      regs_arm->set_pc((*regs_arm)[ARM_REG_PC]);
+      (*regs_arm)[ARM_REG_PC] = (*regs_arm)[ARM_REG_LR];
     }
-    regs_arm->set_sp(arm.cfa());
-    (*regs_arm)[ARM_REG_SP] = regs_arm->sp();
+    (*regs_arm)[ARM_REG_SP] = arm.cfa();
     return_value = true;
 
     // If the pc was set to zero, consider this the final frame.
@@ -171,4 +167,17 @@
   return return_value;
 }
 
+bool ElfInterfaceArm::GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+                                      uint64_t* offset) {
+  // For ARM, thumb function symbols have bit 0 set, but the address passed
+  // in here might not have this bit set and result in a failure to find
+  // the thumb function names. Adjust the address and offset to account
+  // for this possible case.
+  if (ElfInterface32::GetFunctionName(addr | 1, load_bias, name, offset)) {
+    *offset &= ~1;
+    return true;
+  }
+  return false;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index 9c067ba..c1597ce 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -76,6 +76,9 @@
   bool StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
                  bool* finished);
 
+  bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+                       uint64_t* offset) override;
+
   uint64_t start_offset() { return start_offset_; }
 
   size_t total_entries() { return total_entries_; }
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
index 5502ce1..e2a9cb0 100644
--- a/libunwindstack/RegsArm.cpp
+++ b/libunwindstack/RegsArm.cpp
@@ -28,13 +28,28 @@
 
 namespace unwindstack {
 
-RegsArm::RegsArm()
-    : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
+RegsArm::RegsArm() : RegsImpl<uint32_t>(ARM_REG_LAST, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
 
 ArchEnum RegsArm::Arch() {
   return ARCH_ARM;
 }
 
+uint64_t RegsArm::pc() {
+  return regs_[ARM_REG_PC];
+}
+
+uint64_t RegsArm::sp() {
+  return regs_[ARM_REG_SP];
+}
+
+void RegsArm::set_pc(uint64_t pc) {
+  regs_[ARM_REG_PC] = pc;
+}
+
+void RegsArm::set_sp(uint64_t sp) {
+  regs_[ARM_REG_SP] = sp;
+}
+
 uint64_t RegsArm::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   uint64_t load_bias = elf->GetLoadBias();
   if (rel_pc < load_bias) {
@@ -56,17 +71,13 @@
   return 4;
 }
 
-void RegsArm::SetFromRaw() {
-  set_pc(regs_[ARM_REG_PC]);
-  set_sp(regs_[ARM_REG_SP]);
-}
-
 bool RegsArm::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[ARM_REG_LR]) {
+  uint32_t lr = regs_[ARM_REG_LR];
+  if (regs_[ARM_REG_PC] == lr) {
     return false;
   }
 
-  set_pc(regs_[ARM_REG_LR]);
+  regs_[ARM_REG_PC] = lr;
   return true;
 }
 
@@ -94,7 +105,6 @@
 
   RegsArm* regs = new RegsArm();
   memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -103,7 +113,6 @@
 
   RegsArm* regs = new RegsArm();
   memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -118,6 +127,7 @@
 
   uint64_t offset = 0;
   if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+    uint64_t sp = regs_[ARM_REG_SP];
     // non-RT sigreturn call.
     // __restore:
     //
@@ -131,17 +141,18 @@
     // Form 3 (thumb):
     // 0x77 0x27              movs r7, #77
     // 0x00 0xdf              svc 0
-    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+    if (!process_memory->ReadFully(sp, &data, sizeof(data))) {
       return false;
     }
     if (data == 0x5ac3c35a) {
       // SP + uc_mcontext offset + r0 offset.
-      offset = sp() + 0x14 + 0xc;
+      offset = sp + 0x14 + 0xc;
     } else {
       // SP + r0 offset
-      offset = sp() + 0xc;
+      offset = sp + 0xc;
     }
   } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+    uint64_t sp = regs_[ARM_REG_SP];
     // RT sigreturn call.
     // __restore_rt:
     //
@@ -155,15 +166,15 @@
     // Form 3 (thumb):
     // 0xad 0x27              movs r7, #ad
     // 0x00 0xdf              svc 0
-    if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+    if (!process_memory->ReadFully(sp, &data, sizeof(data))) {
       return false;
     }
-    if (data == sp() + 8) {
+    if (data == sp + 8) {
       // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
-      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+      offset = sp + 8 + 0x80 + 0x14 + 0xc;
     } else {
       // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
-      offset = sp() + 0x80 + 0x14 + 0xc;
+      offset = sp + 0x80 + 0x14 + 0xc;
     }
   }
   if (offset == 0) {
@@ -173,7 +184,6 @@
   if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
     return false;
   }
-  SetFromRaw();
   return true;
 }
 
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index cc6f5ce..fe24c80 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -29,12 +29,28 @@
 namespace unwindstack {
 
 RegsArm64::RegsArm64()
-    : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
+    : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
 
 ArchEnum RegsArm64::Arch() {
   return ARCH_ARM64;
 }
 
+uint64_t RegsArm64::pc() {
+  return regs_[ARM64_REG_PC];
+}
+
+uint64_t RegsArm64::sp() {
+  return regs_[ARM64_REG_SP];
+}
+
+void RegsArm64::set_pc(uint64_t pc) {
+  regs_[ARM64_REG_PC] = pc;
+}
+
+void RegsArm64::set_sp(uint64_t sp) {
+  regs_[ARM64_REG_SP] = sp;
+}
+
 uint64_t RegsArm64::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   if (!elf->valid() || rel_pc < 4) {
     return 0;
@@ -42,17 +58,13 @@
   return 4;
 }
 
-void RegsArm64::SetFromRaw() {
-  set_pc(regs_[ARM64_REG_PC]);
-  set_sp(regs_[ARM64_REG_SP]);
-}
-
 bool RegsArm64::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[ARM64_REG_LR]) {
+  uint64_t lr = regs_[ARM64_REG_LR];
+  if (regs_[ARM64_REG_PC] == lr) {
     return false;
   }
 
-  set_pc(regs_[ARM64_REG_LR]);
+  regs_[ARM64_REG_PC] = lr;
   return true;
 }
 
@@ -100,7 +112,6 @@
   uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
   reg_data[ARM64_REG_PC] = user->pc;
   reg_data[ARM64_REG_SP] = user->sp;
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -109,7 +120,6 @@
 
   RegsArm64* regs = new RegsArm64();
   memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -131,12 +141,10 @@
   }
 
   // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
-  if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+  if (!process_memory->ReadFully(regs_[ARM64_REG_SP] + 0x80 + 0xb0 + 0x08, regs_.data(),
                                  sizeof(uint64_t) * ARM64_REG_LAST)) {
     return false;
   }
-
-  SetFromRaw();
   return true;
 }
 
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
index 5d20bef..0b10e21 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -29,12 +29,28 @@
 namespace unwindstack {
 
 RegsMips::RegsMips()
-    : RegsImpl<uint32_t>(MIPS_REG_LAST, MIPS_REG_SP, Location(LOCATION_REGISTER, MIPS_REG_RA)) {}
+    : RegsImpl<uint32_t>(MIPS_REG_LAST, Location(LOCATION_REGISTER, MIPS_REG_RA)) {}
 
 ArchEnum RegsMips::Arch() {
   return ARCH_MIPS;
 }
 
+uint64_t RegsMips::pc() {
+  return regs_[MIPS_REG_PC];
+}
+
+uint64_t RegsMips::sp() {
+  return regs_[MIPS_REG_SP];
+}
+
+void RegsMips::set_pc(uint64_t pc) {
+  regs_[MIPS_REG_PC] = static_cast<uint32_t>(pc);
+}
+
+void RegsMips::set_sp(uint64_t sp) {
+  regs_[MIPS_REG_SP] = static_cast<uint32_t>(sp);
+}
+
 uint64_t RegsMips::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   if (!elf->valid() || rel_pc < 8) {
     return 0;
@@ -43,17 +59,13 @@
   return 8;
 }
 
-void RegsMips::SetFromRaw() {
-  set_pc(regs_[MIPS_REG_PC]);
-  set_sp(regs_[MIPS_REG_SP]);
-}
-
 bool RegsMips::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[MIPS_REG_RA]) {
+  uint32_t ra = regs_[MIPS_REG_RA];
+  if (regs_[MIPS_REG_PC] == ra) {
     return false;
   }
 
-  set_pc(regs_[MIPS_REG_RA]);
+  regs_[MIPS_REG_PC] = ra;
   return true;
 }
 
@@ -101,7 +113,6 @@
   memcpy(regs->RawData(), &user->regs[MIPS32_EF_R0], (MIPS_REG_R31 + 1) * sizeof(uint32_t));
 
   reg_data[MIPS_REG_PC] = user->regs[MIPS32_EF_CP0_EPC];
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -114,7 +125,6 @@
       (*regs)[MIPS_REG_R0 + i] = mips_ucontext->uc_mcontext.sc_regs[i];
   }
   (*regs)[MIPS_REG_PC] = mips_ucontext->uc_mcontext.sc_pc;
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -149,7 +159,7 @@
 
   // read sc_pc and sc_regs[32] from stack
   uint64_t values[MIPS_REG_LAST];
-  if (!process_memory->Read(sp() + offset, values, sizeof(values))) {
+  if (!process_memory->Read(regs_[MIPS_REG_SP] + offset, values, sizeof(values))) {
     return false;
   }
 
@@ -160,8 +170,6 @@
   for (int i = 0; i < 32; i++) {
       regs_[MIPS_REG_R0 + i] = values[1 + i];
   }
-
-  SetFromRaw();
   return true;
 }
 
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
index 4a03538..8848e3b 100644
--- a/libunwindstack/RegsMips64.cpp
+++ b/libunwindstack/RegsMips64.cpp
@@ -29,13 +29,28 @@
 namespace unwindstack {
 
 RegsMips64::RegsMips64()
-    : RegsImpl<uint64_t>(MIPS64_REG_LAST, MIPS64_REG_SP,
-                         Location(LOCATION_REGISTER, MIPS64_REG_RA)) {}
+    : RegsImpl<uint64_t>(MIPS64_REG_LAST, Location(LOCATION_REGISTER, MIPS64_REG_RA)) {}
 
 ArchEnum RegsMips64::Arch() {
   return ARCH_MIPS64;
 }
 
+uint64_t RegsMips64::pc() {
+  return regs_[MIPS64_REG_PC];
+}
+
+uint64_t RegsMips64::sp() {
+  return regs_[MIPS64_REG_SP];
+}
+
+void RegsMips64::set_pc(uint64_t pc) {
+  regs_[MIPS64_REG_PC] = pc;
+}
+
+void RegsMips64::set_sp(uint64_t sp) {
+  regs_[MIPS64_REG_SP] = sp;
+}
+
 uint64_t RegsMips64::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   if (!elf->valid() || rel_pc < 8) {
     return 0;
@@ -44,17 +59,13 @@
   return 8;
 }
 
-void RegsMips64::SetFromRaw() {
-  set_pc(regs_[MIPS64_REG_PC]);
-  set_sp(regs_[MIPS64_REG_SP]);
-}
-
 bool RegsMips64::SetPcFromReturnAddress(Memory*) {
-  if (pc() == regs_[MIPS64_REG_RA]) {
+  uint64_t ra = regs_[MIPS64_REG_RA];
+  if (regs_[MIPS64_REG_PC] == ra) {
     return false;
   }
 
-  set_pc(regs_[MIPS64_REG_RA]);
+  regs_[MIPS64_REG_PC] = ra;
   return true;
 }
 
@@ -102,7 +113,6 @@
   memcpy(regs->RawData(), &user->regs[MIPS64_EF_R0], (MIPS64_REG_R31 + 1) * sizeof(uint64_t));
 
   reg_data[MIPS64_REG_PC] = user->regs[MIPS64_EF_CP0_EPC];
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -113,7 +123,6 @@
   // Copy 64 bit sc_regs over to 64 bit regs
   memcpy(regs->RawData(), &mips64_ucontext->uc_mcontext.sc_regs[0], 32 * sizeof(uint64_t));
   (*regs)[MIPS64_REG_PC] = mips64_ucontext->uc_mcontext.sc_pc;
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -137,19 +146,17 @@
   // vdso_rt_sigreturn => read rt_sigframe
   // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset
   // read 64 bit sc_regs[32] from stack into 64 bit regs_
-  if (!process_memory->Read(sp() + 24 + 128 + 40, regs_.data(),
+  uint64_t sp = regs_[MIPS64_REG_SP];
+  if (!process_memory->Read(sp + 24 + 128 + 40, regs_.data(),
                             sizeof(uint64_t) * (MIPS64_REG_LAST - 1))) {
     return false;
   }
 
   // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
   // read 64 bit sc_pc from stack into 64 bit regs_[MIPS64_REG_PC]
-  if (!process_memory->Read(sp() + 24 + 128 + 40 + 576, &regs_[MIPS64_REG_PC],
-                            sizeof(uint64_t))) {
+  if (!process_memory->Read(sp + 24 + 128 + 40 + 576, &regs_[MIPS64_REG_PC], sizeof(uint64_t))) {
     return false;
   }
-
-  SetFromRaw();
   return true;
 }
 
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
index 573cb23..bb95a13 100644
--- a/libunwindstack/RegsX86.cpp
+++ b/libunwindstack/RegsX86.cpp
@@ -28,13 +28,28 @@
 
 namespace unwindstack {
 
-RegsX86::RegsX86()
-    : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
+RegsX86::RegsX86() : RegsImpl<uint32_t>(X86_REG_LAST, Location(LOCATION_SP_OFFSET, -4)) {}
 
 ArchEnum RegsX86::Arch() {
   return ARCH_X86;
 }
 
+uint64_t RegsX86::pc() {
+  return regs_[X86_REG_PC];
+}
+
+uint64_t RegsX86::sp() {
+  return regs_[X86_REG_SP];
+}
+
+void RegsX86::set_pc(uint64_t pc) {
+  regs_[X86_REG_PC] = static_cast<uint32_t>(pc);
+}
+
+void RegsX86::set_sp(uint64_t sp) {
+  regs_[X86_REG_SP] = static_cast<uint32_t>(sp);
+}
+
 uint64_t RegsX86::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   if (!elf->valid() || rel_pc == 0) {
     return 0;
@@ -42,19 +57,15 @@
   return 1;
 }
 
-void RegsX86::SetFromRaw() {
-  set_pc(regs_[X86_REG_PC]);
-  set_sp(regs_[X86_REG_SP]);
-}
-
 bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
   // Attempt to get the return address from the top of the stack.
   uint32_t new_pc;
-  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+  if (!process_memory->ReadFully(regs_[X86_REG_SP], &new_pc, sizeof(new_pc)) ||
+      new_pc == regs_[X86_REG_PC]) {
     return false;
   }
 
-  set_pc(new_pc);
+  regs_[X86_REG_PC] = new_pc;
   return true;
 }
 
@@ -84,7 +95,6 @@
   (*regs)[X86_REG_ESP] = user->esp;
   (*regs)[X86_REG_EIP] = user->eip;
 
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -99,7 +109,6 @@
   regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
   regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
   regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
-  SetFromRaw();
 }
 
 Regs* RegsX86::CreateFromUcontext(void* ucontext) {
@@ -131,7 +140,7 @@
     //   int signum
     //   struct sigcontext (same format as mcontext)
     struct x86_mcontext_t context;
-    if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
+    if (!process_memory->ReadFully(regs_[X86_REG_SP] + 4, &context, sizeof(context))) {
       return false;
     }
     regs_[X86_REG_EBP] = context.ebp;
@@ -141,7 +150,6 @@
     regs_[X86_REG_ECX] = context.ecx;
     regs_[X86_REG_EAX] = context.eax;
     regs_[X86_REG_EIP] = context.eip;
-    SetFromRaw();
     return true;
   } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
     // With SA_SIGINFO set, the return sequence is:
@@ -157,7 +165,7 @@
 
     // Get the location of the sigcontext data.
     uint32_t ptr;
-    if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
+    if (!process_memory->ReadFully(regs_[X86_REG_SP] + 8, &ptr, sizeof(ptr))) {
       return false;
     }
     // Only read the portion of the data structure we care about.
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index 3175a90..e57e2bc 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -28,13 +28,28 @@
 
 namespace unwindstack {
 
-RegsX86_64::RegsX86_64()
-    : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
+RegsX86_64::RegsX86_64() : RegsImpl<uint64_t>(X86_64_REG_LAST, Location(LOCATION_SP_OFFSET, -8)) {}
 
 ArchEnum RegsX86_64::Arch() {
   return ARCH_X86_64;
 }
 
+uint64_t RegsX86_64::pc() {
+  return regs_[X86_64_REG_PC];
+}
+
+uint64_t RegsX86_64::sp() {
+  return regs_[X86_64_REG_SP];
+}
+
+void RegsX86_64::set_pc(uint64_t pc) {
+  regs_[X86_64_REG_PC] = pc;
+}
+
+void RegsX86_64::set_sp(uint64_t sp) {
+  regs_[X86_64_REG_SP] = sp;
+}
+
 uint64_t RegsX86_64::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
   if (!elf->valid() || rel_pc == 0) {
     return 0;
@@ -42,19 +57,15 @@
   return 1;
 }
 
-void RegsX86_64::SetFromRaw() {
-  set_pc(regs_[X86_64_REG_PC]);
-  set_sp(regs_[X86_64_REG_SP]);
-}
-
 bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
   // Attempt to get the return address from the top of the stack.
   uint64_t new_pc;
-  if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+  if (!process_memory->ReadFully(regs_[X86_64_REG_SP], &new_pc, sizeof(new_pc)) ||
+      new_pc == regs_[X86_64_REG_PC]) {
     return false;
   }
 
-  set_pc(new_pc);
+  regs_[X86_64_REG_PC] = new_pc;
   return true;
 }
 
@@ -100,7 +111,6 @@
   (*regs)[X86_64_REG_RSP] = user->rsp;
   (*regs)[X86_64_REG_RIP] = user->rip;
 
-  regs->SetFromRaw();
   return regs;
 }
 
@@ -118,8 +128,6 @@
   regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
   regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
   regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
-
-  SetFromRaw();
 }
 
 Regs* RegsX86_64::CreateFromUcontext(void* ucontext) {
@@ -152,7 +160,7 @@
   // Read the mcontext data from the stack.
   // sp points to the ucontext data structure, read only the mcontext part.
   x86_64_ucontext_t x86_64_ucontext;
-  if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
+  if (!process_memory->ReadFully(regs_[X86_64_REG_SP] + 0x28, &x86_64_ucontext.uc_mcontext,
                                  sizeof(x86_64_mcontext_t))) {
     return false;
   }
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 7da6994..94edb1c 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -77,7 +77,6 @@
     return;
   }
 
-  // dex_files_->GetMethodInformation(dex_pc - dex_offset, dex_offset, info, &frame->function_name,
   dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
                                    &frame->function_offset);
 #endif
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index b0e7ea1..4bac473 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -45,8 +45,8 @@
     int16_t value;
   };
 
-  Regs(uint16_t total_regs, uint16_t sp_reg, const Location& return_loc)
-      : total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {}
+  Regs(uint16_t total_regs, const Location& return_loc)
+      : total_regs_(total_regs), return_loc_(return_loc) {}
   virtual ~Regs() = default;
 
   virtual ArchEnum Arch() = 0;
@@ -57,6 +57,9 @@
   virtual uint64_t pc() = 0;
   virtual uint64_t sp() = 0;
 
+  virtual void set_pc(uint64_t pc) = 0;
+  virtual void set_sp(uint64_t sp) = 0;
+
   uint64_t dex_pc() { return dex_pc_; }
   void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
 
@@ -64,13 +67,10 @@
 
   virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
 
-  virtual void SetFromRaw() = 0;
-
   virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
 
   virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) = 0;
 
-  uint16_t sp_reg() { return sp_reg_; }
   uint16_t total_regs() { return total_regs_; }
 
   static ArchEnum CurrentArch();
@@ -80,7 +80,6 @@
 
  protected:
   uint16_t total_regs_;
-  uint16_t sp_reg_;
   Location return_loc_;
   uint64_t dex_pc_ = 0;
 };
@@ -88,16 +87,10 @@
 template <typename AddressType>
 class RegsImpl : public Regs {
  public:
-  RegsImpl(uint16_t total_regs, uint16_t sp_reg, Location return_loc)
-      : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {}
+  RegsImpl(uint16_t total_regs, Location return_loc)
+      : Regs(total_regs, return_loc), regs_(total_regs) {}
   virtual ~RegsImpl() = default;
 
-  uint64_t pc() override { return pc_; }
-  uint64_t sp() override { return sp_; }
-
-  void set_pc(AddressType pc) { pc_ = pc; }
-  void set_sp(AddressType sp) { sp_ = sp; }
-
   bool Is32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
 
   inline AddressType& operator[](size_t reg) { return regs_[reg]; }
@@ -111,8 +104,6 @@
   }
 
  protected:
-  AddressType pc_;
-  AddressType sp_;
   std::vector<AddressType> regs_;
 };
 
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
index 5af90d3..31e6797 100644
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -34,17 +34,21 @@
   RegsArm();
   virtual ~RegsArm() = default;
 
-  virtual ArchEnum Arch() override final;
+  ArchEnum Arch() override final;
 
   uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
-  void SetFromRaw() override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
 
   static Regs* Read(void* data);
 
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index cb05732..0c45eba 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -34,17 +34,21 @@
   RegsArm64();
   virtual ~RegsArm64() = default;
 
-  virtual ArchEnum Arch() override final;
+  ArchEnum Arch() override final;
 
   uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
-  void SetFromRaw() override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
 
   static Regs* Read(void* data);
 
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index 557eace..81c0af3 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -51,8 +51,6 @@
       : [base] "+r"(reg_data)
       :
       : "memory");
-
-  regs->SetFromRaw();
 }
 
 #elif defined(__aarch64__)
@@ -83,8 +81,6 @@
       : [base] "+r"(reg_data)
       :
       : "x12", "x13", "memory");
-
-  regs->SetFromRaw();
 }
 
 #elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
@@ -93,8 +89,6 @@
 
 inline void RegsGetLocal(Regs* regs) {
   AsmGetRegs(regs->RawData());
-
-  regs->SetFromRaw();
 }
 
 #endif
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
index 8e3c01f..709f9e2 100644
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -34,17 +34,21 @@
   RegsMips();
   virtual ~RegsMips() = default;
 
-  virtual ArchEnum Arch() override final;
+  ArchEnum Arch() override final;
 
   uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
-  void SetFromRaw() override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
 
   static Regs* Read(void* data);
 
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
index 8c2d443..1de83ea 100644
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -34,17 +34,21 @@
   RegsMips64();
   virtual ~RegsMips64() = default;
 
-  virtual ArchEnum Arch() override final;
+  ArchEnum Arch() override final;
 
   uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
-  void SetFromRaw() override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
 
   static Regs* Read(void* data);
 
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
index 1bc145d..586c9d8 100644
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -35,19 +35,23 @@
   RegsX86();
   virtual ~RegsX86() = default;
 
-  virtual ArchEnum Arch() override final;
+  ArchEnum Arch() override final;
 
   uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
-  void SetFromRaw() override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
   void SetFromUcontext(x86_ucontext_t* ucontext);
 
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
 
   static Regs* Read(void* data);
 
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
index 4cd45d4..061f479 100644
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -35,19 +35,23 @@
   RegsX86_64();
   virtual ~RegsX86_64() = default;
 
-  virtual ArchEnum Arch() override final;
+  ArchEnum Arch() override final;
 
   uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
 
-  void SetFromRaw() override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
   void SetFromUcontext(x86_64_ucontext_t* ucontext);
 
-  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  uint64_t pc() override;
+  uint64_t sp() override;
+
+  void set_pc(uint64_t pc) override;
+  void set_sp(uint64_t sp) override;
 
   static Regs* Read(void* data);
 
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 68dc30c..7395b04 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -737,6 +737,8 @@
   ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x284, &loc_regs));
   ASSERT_EQ(0x284U, this->dmem_->cur_offset());
   ASSERT_EQ(1U, loc_regs.size());
+  ASSERT_EQ(DWARF_LOCATION_VAL_EXPRESSION, loc_regs[CFA_REG].type);
+  ASSERT_EQ(0x81U, loc_regs[CFA_REG].values[0]);
 
   ASSERT_EQ("", GetFakeLogPrint());
   ASSERT_EQ("", GetFakeLogBuf());
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 6e15227..d424d5f 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -1468,7 +1468,7 @@
   }
   this->op_memory_.SetMemory(0, opcode_buffer);
 
-  RegsImplFake<TypeParam> regs(32, 10);
+  RegsImplFake<TypeParam> regs(32);
   for (size_t i = 0; i < 32; i++) {
     regs[i] = i + 10;
   }
@@ -1499,7 +1499,7 @@
   };
   this->op_memory_.SetMemory(0, opcode_buffer);
 
-  RegsImplFake<TypeParam> regs(16, 10);
+  RegsImplFake<TypeParam> regs(16);
   for (size_t i = 0; i < 16; i++) {
     regs[i] = i + 10;
   }
@@ -1526,7 +1526,7 @@
                                         0x92, 0x80, 0x15, 0x80, 0x02};
   this->op_memory_.SetMemory(0, opcode_buffer);
 
-  RegsImplFake<TypeParam> regs(10, 10);
+  RegsImplFake<TypeParam> regs(10);
   regs[5] = 0x45;
   regs[6] = 0x190;
   RegsInfo<TypeParam> regs_info(&regs);
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 37305b2..c85764c 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -92,14 +92,14 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
   regs.set_sp(0x2000);
   regs[5] = 0x20;
   regs[9] = 0x3000;
-  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5002}};
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x2, 0x5002}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
   EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
@@ -108,7 +108,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -116,7 +116,7 @@
   regs[5] = 0x20;
   regs[9] = 0x3000;
   this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96});
-  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5002}};
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x2, 0x5002}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
   EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode());
@@ -124,7 +124,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -136,15 +136,13 @@
   this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value));
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
   bool finished;
-  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_FALSE(finished);
-  EXPECT_EQ(0x12345U, regs.sp());
-  EXPECT_EQ(0x20U, regs.pc());
+  ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_val_expr) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -162,7 +160,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -170,7 +168,7 @@
   regs[5] = 0x20;
   regs[9] = 0x3000;
   this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96});
-  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5002}};
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x2, 0x5002}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
   EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode());
@@ -178,7 +176,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) {
   DwarfCie cie{.return_address_register = 60};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   bool finished;
@@ -188,7 +186,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   bool finished;
@@ -198,7 +196,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}};
@@ -227,7 +225,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -239,12 +237,12 @@
   ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
   EXPECT_FALSE(finished);
   EXPECT_EQ(0x20U, regs.pc());
-  EXPECT_EQ(0x2000U, regs.sp());
+  EXPECT_EQ(0x3000U, regs.sp());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_from_value) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -262,7 +260,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_double_indirection) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -283,7 +281,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_register_reference_chain) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -314,7 +312,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -333,7 +331,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -348,7 +346,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   if (sizeof(TypeParam) == sizeof(uint64_t)) {
@@ -382,7 +380,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address_undefined) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -400,7 +398,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_pc_zero) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -417,7 +415,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -434,7 +432,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_ignore_large_reg_loc) {
   DwarfCie cie{.return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -453,7 +451,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_expr) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
@@ -473,7 +471,7 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
-  RegsImplFake<TypeParam> regs(10, 9);
+  RegsImplFake<TypeParam> regs(10);
   dwarf_loc_regs_t loc_regs;
 
   regs.set_pc(0x100);
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp
index ae9da5e..66207db 100644
--- a/libunwindstack/tests/ElfFake.cpp
+++ b/libunwindstack/tests/ElfFake.cpp
@@ -65,8 +65,8 @@
   }
 
   RegsFake* fake_regs = reinterpret_cast<RegsFake*>(regs);
-  fake_regs->FakeSetPc(entry.pc);
-  fake_regs->FakeSetSp(entry.sp);
+  fake_regs->set_pc(entry.pc);
+  fake_regs->set_sp(entry.sp);
   *finished = entry.finished;
   return true;
 }
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index eb85033..f9028c4 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -316,7 +316,6 @@
   RegsArm regs;
   regs[13] = 0x50000;
   regs[15] = 0x8000;
-  regs.SetFromRaw();
 
   ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
   elf.FakeSetInterface(interface);
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index ab23194..ede16b3 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -27,14 +27,16 @@
 
 class RegsFake : public Regs {
  public:
-  RegsFake(uint16_t total_regs, uint16_t sp_reg)
-      : Regs(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
+  RegsFake(uint16_t total_regs) : Regs(total_regs, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsFake() = default;
 
   ArchEnum Arch() override { return fake_arch_; }
   void* RawData() override { return nullptr; }
   uint64_t pc() override { return fake_pc_; }
   uint64_t sp() override { return fake_sp_; }
+  void set_pc(uint64_t pc) override { fake_pc_ = pc; }
+  void set_sp(uint64_t sp) override { fake_sp_ = sp; }
+
   bool SetPcFromReturnAddress(Memory*) override {
     if (!fake_return_address_valid_) {
       return false;
@@ -51,11 +53,7 @@
 
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 
-  void SetFromRaw() override {}
-
   void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
-  void FakeSetPc(uint64_t pc) { fake_pc_ = pc; }
-  void FakeSetSp(uint64_t sp) { fake_sp_ = sp; }
   void FakeSetDexPc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
   void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; }
   void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; }
@@ -71,19 +69,23 @@
 template <typename TypeParam>
 class RegsImplFake : public RegsImpl<TypeParam> {
  public:
-  RegsImplFake(uint16_t total_regs, uint16_t sp_reg)
-      : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
+  RegsImplFake(uint16_t total_regs)
+      : RegsImpl<TypeParam>(total_regs, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsImplFake() = default;
 
   ArchEnum Arch() override { return ARCH_UNKNOWN; }
+  uint64_t pc() override { return fake_pc_; }
+  uint64_t sp() override { return fake_sp_; }
+  void set_pc(uint64_t pc) override { fake_pc_ = pc; }
+  void set_sp(uint64_t sp) override { fake_sp_ = sp; }
 
   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; }
 
-  void FakeSetPc(uint64_t pc) { this->pc_ = pc; }
-  void FakeSetSp(uint64_t sp) { this->sp_ = sp; }
+ private:
+  uint64_t fake_pc_ = 0;
+  uint64_t fake_sp_ = 0;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index ecd4051..eac12ca 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -56,7 +56,6 @@
   RegsArm regs;
   regs[ARM_REG_PC] = 0x5000;
   regs[ARM_REG_SP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData32(0x5000, pc_data);
 
@@ -87,7 +86,6 @@
   RegsArm regs;
   regs[ARM_REG_PC] = 0x5000;
   regs[ARM_REG_SP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData32(0x5000, pc_data);
 
@@ -118,7 +116,6 @@
   RegsArm64 regs;
   regs[ARM64_REG_PC] = 0x8000;
   regs[ARM64_REG_SP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x8000, 0xd4000001d2801168ULL);
 
@@ -138,7 +135,6 @@
   RegsX86 regs;
   regs[X86_REG_EIP] = 0x4100;
   regs[X86_REG_ESP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x4100, 0x80cd00000077b858ULL);
   for (uint64_t index = 0; index <= 25; index++) {
@@ -162,7 +158,6 @@
   RegsX86 regs;
   regs[X86_REG_EIP] = 0x4100;
   regs[X86_REG_ESP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x4100, 0x0080cd000000adb8ULL);
   addr += 8;
@@ -191,7 +186,6 @@
   RegsX86_64 regs;
   regs[X86_64_REG_RIP] = 0x7000;
   regs[X86_64_REG_RSP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x7000, 0x0f0000000fc0c748);
   elf_memory_->SetData16(0x7008, 0x0f05);
@@ -212,7 +206,6 @@
   RegsMips regs;
   regs[MIPS_REG_PC] = 0x8000;
   regs[MIPS_REG_SP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x8000, 0x0000000c24021017ULL);
 
@@ -232,7 +225,6 @@
   RegsMips regs;
   regs[MIPS_REG_PC] = 0x8000;
   regs[MIPS_REG_SP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x8000, 0x0000000c24021061ULL);
 
@@ -252,7 +244,6 @@
   RegsMips64 regs;
   regs[MIPS64_REG_PC] = 0x8000;
   regs[MIPS64_REG_SP] = addr;
-  regs.SetFromRaw();
 
   elf_memory_->SetData64(0x8000, 0x0000000c2402145bULL);
 
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 8b2f6c8..3e80733 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -49,9 +49,8 @@
 };
 
 TEST_F(RegsTest, regs32) {
-  RegsImplFake<uint32_t> regs32(50, 10);
+  RegsImplFake<uint32_t> regs32(50);
   ASSERT_EQ(50U, regs32.total_regs());
-  ASSERT_EQ(10U, regs32.sp_reg());
 
   uint32_t* raw = reinterpret_cast<uint32_t*>(regs32.RawData());
   for (size_t i = 0; i < 50; i++) {
@@ -72,9 +71,8 @@
 }
 
 TEST_F(RegsTest, regs64) {
-  RegsImplFake<uint64_t> regs64(30, 12);
+  RegsImplFake<uint64_t> regs64(30);
   ASSERT_EQ(30U, regs64.total_regs());
-  ASSERT_EQ(12U, regs64.sp_reg());
 
   uint64_t* raw = reinterpret_cast<uint64_t*>(regs64.RawData());
   for (size_t i = 0; i < 30; i++) {
@@ -211,62 +209,56 @@
   EXPECT_EQ(0U, regs_mips64.GetPcAdjustment(0xa00U, invalid_elf));
 }
 
-TEST_F(RegsTest, arm_set_from_raw) {
+TEST_F(RegsTest, arm_verify_sp_pc) {
   RegsArm arm;
   uint32_t* regs = reinterpret_cast<uint32_t*>(arm.RawData());
   regs[13] = 0x100;
   regs[15] = 0x200;
-  arm.SetFromRaw();
   EXPECT_EQ(0x100U, arm.sp());
   EXPECT_EQ(0x200U, arm.pc());
 }
 
-TEST_F(RegsTest, arm64_set_from_raw) {
+TEST_F(RegsTest, arm64_verify_sp_pc) {
   RegsArm64 arm64;
   uint64_t* regs = reinterpret_cast<uint64_t*>(arm64.RawData());
   regs[31] = 0xb100000000ULL;
   regs[32] = 0xc200000000ULL;
-  arm64.SetFromRaw();
   EXPECT_EQ(0xb100000000U, arm64.sp());
   EXPECT_EQ(0xc200000000U, arm64.pc());
 }
 
-TEST_F(RegsTest, x86_set_from_raw) {
+TEST_F(RegsTest, x86_verify_sp_pc) {
   RegsX86 x86;
   uint32_t* regs = reinterpret_cast<uint32_t*>(x86.RawData());
   regs[4] = 0x23450000;
   regs[8] = 0xabcd0000;
-  x86.SetFromRaw();
   EXPECT_EQ(0x23450000U, x86.sp());
   EXPECT_EQ(0xabcd0000U, x86.pc());
 }
 
-TEST_F(RegsTest, x86_64_set_from_raw) {
+TEST_F(RegsTest, x86_64_verify_sp_pc) {
   RegsX86_64 x86_64;
   uint64_t* regs = reinterpret_cast<uint64_t*>(x86_64.RawData());
   regs[7] = 0x1200000000ULL;
   regs[16] = 0x4900000000ULL;
-  x86_64.SetFromRaw();
   EXPECT_EQ(0x1200000000U, x86_64.sp());
   EXPECT_EQ(0x4900000000U, x86_64.pc());
 }
 
-TEST_F(RegsTest, mips_set_from_raw) {
+TEST_F(RegsTest, mips_verify_sp_pc) {
   RegsMips mips;
   uint32_t* regs = reinterpret_cast<uint32_t*>(mips.RawData());
   regs[29] = 0x100;
   regs[32] = 0x200;
-  mips.SetFromRaw();
   EXPECT_EQ(0x100U, mips.sp());
   EXPECT_EQ(0x200U, mips.pc());
 }
 
-TEST_F(RegsTest, mips64_set_from_raw) {
+TEST_F(RegsTest, mips64_verify_sp_pc) {
   RegsMips64 mips64;
   uint64_t* regs = reinterpret_cast<uint64_t*>(mips64.RawData());
   regs[29] = 0xb100000000ULL;
   regs[32] = 0xc200000000ULL;
-  mips64.SetFromRaw();
   EXPECT_EQ(0xb100000000U, mips64.sp());
   EXPECT_EQ(0xc200000000U, mips64.pc());
 }
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index af4a5b5..532640f 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -122,7 +122,6 @@
       (*regs)[entry->second] = value;
     }
     fclose(fp);
-    regs->SetFromRaw();
   }
 
   static std::unordered_map<std::string, uint32_t> arm_regs_;
@@ -188,7 +187,7 @@
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
-      "  #00 pc 0001a9f8  libc.so (abort+63)\n"
+      "  #00 pc 0001a9f8  libc.so (abort+64)\n"
       "  #01 pc 00006a1b  libbase.so (_ZN7android4base14DefaultAborterEPKc+6)\n"
       "  #02 pc 00007441  libbase.so (_ZN7android4base10LogMessageD2Ev+748)\n"
       "  #03 pc 00015147  /does/not/exist/libhidlbase.so\n",
@@ -575,7 +574,7 @@
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
-      "  #00 pc 00018a5e  libarttestd.so (Java_Main_unwindInProcess+865)\n"
+      "  #00 pc 00018a5e  libarttestd.so (Java_Main_unwindInProcess+866)\n"
       "  #01 pc 0000212d (offset 0x2000)  137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
       "boolean)+92)\n"
       "  #02 pc 00011cb1  anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
@@ -956,4 +955,119 @@
   EXPECT_EQ(0x7ffcc85971a0U, unwinder.frames()[4].sp);
 }
 
+TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
+  Init("art_quick_osr_stub_arm/", ARCH_ARM);
+
+  MemoryOfflineParts* memory = new MemoryOfflineParts;
+  AddMemory(dir_ + "descriptor.data", memory);
+  AddMemory(dir_ + "stack.data", memory);
+  for (size_t i = 0; i < 2; i++) {
+    AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+  }
+  process_memory_.reset(memory);
+
+  JitDebug jit_debug(process_memory_);
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(25U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 0000c788  <anonymous:d0250000> "
+      "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
+      "  #01 pc 0000cdd5  <anonymous:d0250000> "
+      "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
+      "  #02 pc 004135bb  libart.so (art_quick_osr_stub+42)\n"
+      "  #03 pc 002657a5  libart.so "
+      "(_ZN3art3jit3Jit25MaybeDoOnStackReplacementEPNS_6ThreadEPNS_9ArtMethodEjiPNS_6JValueE+876)\n"
+      "  #04 pc 004021a7  libart.so (MterpMaybeDoOnStackReplacement+86)\n"
+      "  #05 pc 00412474  libart.so (ExecuteMterpImpl+66164)\n"
+      "  #06 pc cd8365b0  <unknown>\n"  // symbol in dex file
+      "  #07 pc 001d7f1b  libart.so "
+      "(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
+      "6JValueEb+374)\n"
+      "  #08 pc 001dc593  libart.so "
+      "(_ZN3art11interpreter33ArtInterpreterToInterpreterBridgeEPNS_6ThreadERKNS_"
+      "20CodeItemDataAccessorEPNS_11ShadowFrameEPNS_6JValueE+154)\n"
+      "  #09 pc 001f4d01  libart.so "
+      "(_ZN3art11interpreter6DoCallILb0ELb0EEEbPNS_9ArtMethodEPNS_6ThreadERNS_11ShadowFrameEPKNS_"
+      "11InstructionEtPNS_6JValueE+732)\n"
+      "  #10 pc 003fe427  libart.so (MterpInvokeInterface+1354)\n"
+      "  #11 pc 00405b94  libart.so (ExecuteMterpImpl+14740)\n"
+      "  #12 pc 7004873e  <unknown>\n"  // symbol in dex file
+      "  #13 pc 001d7f1b  libart.so "
+      "(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
+      "6JValueEb+374)\n"
+      "  #14 pc 001dc4d5  libart.so "
+      "(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
+      "20CodeItemDataAccessorEPNS_11ShadowFrameE+92)\n"
+      "  #15 pc 003f25ab  libart.so (artQuickToInterpreterBridge+970)\n"
+      "  #16 pc 00417aff  libart.so (art_quick_to_interpreter_bridge+30)\n"
+      "  #17 pc 00413575  libart.so (art_quick_invoke_stub_internal+68)\n"
+      "  #18 pc 00418531  libart.so (art_quick_invoke_stub+236)\n"
+      "  #19 pc 000b468d  libart.so (_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+136)\n"
+      "  #20 pc 00362f49  libart.so "
+      "(_ZN3art12_GLOBAL__N_118InvokeWithArgArrayERKNS_33ScopedObjectAccessAlreadyRunnableEPNS_"
+      "9ArtMethodEPNS0_8ArgArrayEPNS_6JValueEPKc+52)\n"
+      "  #21 pc 00363cd9  libart.so "
+      "(_ZN3art35InvokeVirtualOrInterfaceWithJValuesERKNS_33ScopedObjectAccessAlreadyRunnableEP8_"
+      "jobjectP10_jmethodIDP6jvalue+332)\n"
+      "  #22 pc 003851dd  libart.so (_ZN3art6Thread14CreateCallbackEPv+868)\n"
+      "  #23 pc 00062925  libc.so (_ZL15__pthread_startPv+22)\n"
+      "  #24 pc 0001de39  libc.so (__start_thread+24)\n",
+      frame_info);
+  EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xcd4ff140U, unwinder.frames()[1].sp);
+  EXPECT_EQ(0xe4a755bbU, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xcd4ff160U, unwinder.frames()[2].sp);
+  EXPECT_EQ(0xe48c77a5U, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xcd4ff190U, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xe4a641a7U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xcd4ff298U, unwinder.frames()[4].sp);
+  EXPECT_EQ(0xe4a74474U, unwinder.frames()[5].pc);
+  EXPECT_EQ(0xcd4ff2b8U, unwinder.frames()[5].sp);
+  EXPECT_EQ(0xcd8365b0U, unwinder.frames()[6].pc);
+  EXPECT_EQ(0xcd4ff2e0U, unwinder.frames()[6].sp);
+  EXPECT_EQ(0xe4839f1bU, unwinder.frames()[7].pc);
+  EXPECT_EQ(0xcd4ff2e0U, unwinder.frames()[7].sp);
+  EXPECT_EQ(0xe483e593U, unwinder.frames()[8].pc);
+  EXPECT_EQ(0xcd4ff330U, unwinder.frames()[8].sp);
+  EXPECT_EQ(0xe4856d01U, unwinder.frames()[9].pc);
+  EXPECT_EQ(0xcd4ff380U, unwinder.frames()[9].sp);
+  EXPECT_EQ(0xe4a60427U, unwinder.frames()[10].pc);
+  EXPECT_EQ(0xcd4ff430U, unwinder.frames()[10].sp);
+  EXPECT_EQ(0xe4a67b94U, unwinder.frames()[11].pc);
+  EXPECT_EQ(0xcd4ff498U, unwinder.frames()[11].sp);
+  EXPECT_EQ(0x7004873eU, unwinder.frames()[12].pc);
+  EXPECT_EQ(0xcd4ff4c0U, unwinder.frames()[12].sp);
+  EXPECT_EQ(0xe4839f1bU, unwinder.frames()[13].pc);
+  EXPECT_EQ(0xcd4ff4c0U, unwinder.frames()[13].sp);
+  EXPECT_EQ(0xe483e4d5U, unwinder.frames()[14].pc);
+  EXPECT_EQ(0xcd4ff510U, unwinder.frames()[14].sp);
+  EXPECT_EQ(0xe4a545abU, unwinder.frames()[15].pc);
+  EXPECT_EQ(0xcd4ff538U, unwinder.frames()[15].sp);
+  EXPECT_EQ(0xe4a79affU, unwinder.frames()[16].pc);
+  EXPECT_EQ(0xcd4ff640U, unwinder.frames()[16].sp);
+  EXPECT_EQ(0xe4a75575U, unwinder.frames()[17].pc);
+  EXPECT_EQ(0xcd4ff6b0U, unwinder.frames()[17].sp);
+  EXPECT_EQ(0xe4a7a531U, unwinder.frames()[18].pc);
+  EXPECT_EQ(0xcd4ff6e8U, unwinder.frames()[18].sp);
+  EXPECT_EQ(0xe471668dU, unwinder.frames()[19].pc);
+  EXPECT_EQ(0xcd4ff770U, unwinder.frames()[19].sp);
+  EXPECT_EQ(0xe49c4f49U, unwinder.frames()[20].pc);
+  EXPECT_EQ(0xcd4ff7c8U, unwinder.frames()[20].sp);
+  EXPECT_EQ(0xe49c5cd9U, unwinder.frames()[21].pc);
+  EXPECT_EQ(0xcd4ff850U, unwinder.frames()[21].sp);
+  EXPECT_EQ(0xe49e71ddU, unwinder.frames()[22].pc);
+  EXPECT_EQ(0xcd4ff8e8U, unwinder.frames()[22].sp);
+  EXPECT_EQ(0xe7df3925U, unwinder.frames()[23].pc);
+  EXPECT_EQ(0xcd4ff958U, unwinder.frames()[23].sp);
+  EXPECT_EQ(0xe7daee39U, unwinder.frames()[24].pc);
+  EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index e44b225..b38fb5f 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -133,7 +133,7 @@
 };
 
 MapsFake UnwinderTest::maps_;
-RegsFake UnwinderTest::regs_(5, 0);
+RegsFake UnwinderTest::regs_(5);
 std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);
 
 TEST_F(UnwinderTest, multiple_frames) {
@@ -141,8 +141,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -201,8 +201,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -260,8 +260,8 @@
 TEST_F(UnwinderTest, non_zero_load_bias) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
 
-  regs_.FakeSetPc(0xa5500);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0xa5500);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
@@ -288,8 +288,8 @@
 TEST_F(UnwinderTest, non_zero_elf_offset) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
 
-  regs_.FakeSetPc(0xa7500);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0xa7500);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
@@ -316,8 +316,8 @@
 TEST_F(UnwinderTest, non_zero_map_offset) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
 
-  regs_.FakeSetPc(0x43000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x43000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
@@ -349,8 +349,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame4", 4));
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x1000, 0x10000, true));
   ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
@@ -383,8 +383,8 @@
     ElfInterfaceFake::FakePushStepData(StepData(0x1102 + i * 0x100, 0x10010 + i * 0x10, false));
   }
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
 
   Unwinder unwinder(20, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
@@ -415,8 +415,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
 
-  regs_.FakeSetPc(0x20000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x20000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x20002, 0x10030, false));
@@ -481,8 +481,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x63000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x63000);
   ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
@@ -527,8 +527,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
 
-  regs_.FakeSetPc(0x13000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x13000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -546,8 +546,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x13000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x13000);
   ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -563,8 +563,8 @@
 TEST_F(UnwinderTest, pc_without_map) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
 
-  regs_.FakeSetPc(0x41000);
-  regs_.FakeSetSp(0x13000);
+  regs_.set_pc(0x41000);
+  regs_.set_sp(0x13000);
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
@@ -593,8 +593,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
 
   // Fake as if code called a nullptr function.
-  regs_.FakeSetPc(0);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0);
+  regs_.set_sp(0x10000);
   regs_.FakeSetReturnAddress(0x1202);
   regs_.FakeSetReturnAddressValid(true);
 
@@ -657,8 +657,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
 
   // Fake as if code called a nullptr function.
-  regs_.FakeSetPc(0);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0);
+  regs_.set_sp(0x10000);
   regs_.FakeSetReturnAddress(0x1202);
   regs_.FakeSetReturnAddressValid(true);
 
@@ -691,8 +691,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
 
   // Fake as if code called a nullptr function.
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x43402, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -745,8 +745,8 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame4", 4));
 
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
@@ -805,8 +805,8 @@
 
 TEST_F(UnwinderTest, dex_pc_in_map) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0xa3400);
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
@@ -846,8 +846,8 @@
 
 TEST_F(UnwinderTest, dex_pc_not_in_map) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0x50000);
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
@@ -888,8 +888,8 @@
 TEST_F(UnwinderTest, dex_pc_multiple_frames) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
-  regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x10000);
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0xa3400);
   ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data
new file mode 100644
index 0000000..300646b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data
new file mode 100644
index 0000000..999cb79
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data
new file mode 100644
index 0000000..6aa1c82
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data
new file mode 100644
index 0000000..19d7b65
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data
new file mode 100644
index 0000000..edcd3e1
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
new file mode 100644
index 0000000..09ba495
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so
new file mode 100644
index 0000000..39c9025
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
new file mode 100644
index 0000000..55aaaf6
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
@@ -0,0 +1,3 @@
+d0250000-d2600000 r-xp 0 00:00 0 <anonymous:d0250000>
+e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
+e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt
new file mode 100644
index 0000000..0b51814
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: e814103c
+r1: 12dcf218
+r2: 1a90df75
+r3: ffffffbf
+r4: 0
+r5: 12dc0800
+r6: 12dcf218
+r7: 1a90df75
+r8: 0
+r9: dd23cc00
+r10: 1c
+r11: cd4ff16c
+ip: 0
+sp: cd4ff140
+lr: d025cdd7
+pc: d025c788
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data
new file mode 100644
index 0000000..f00917b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index a0abcca..5a8edfd 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -53,8 +53,7 @@
       printf("  PC 0x%" PRIx64, addr + load_bias);
       uint64_t func_offset;
       uint64_t pc = addr + load_bias;
-      // This might be a thumb function, so set the low bit.
-      if (interface->GetFunctionName(pc | 1, load_bias, &name, &func_offset) && !name.empty()) {
+      if (interface->GetFunctionName(pc, load_bias, &name, &func_offset) && !name.empty()) {
         printf(" <%s>", name.c_str());
       }
       printf("\n");
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 80dcdcb..a4fc4b4 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -160,7 +160,6 @@
 cc_library {
     name: "libutilscallstack",
     defaults: ["libutils_defaults"],
-    vendor_available: false,
 
     srcs: [
         "CallStack.cpp",
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index b8af2f0..a78319f 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -171,7 +171,9 @@
     }
 
     // audit message (except sequence number) identical?
-    if (last->isBinary()) {
+    if (last->isBinary() &&
+        (lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t))) &&
+        (lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t)))) {
         if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) -
                                             sizeof(int32_t))) {
             return DIFFERENT;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index feb100e..f488ed5 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -93,6 +93,23 @@
 else
   LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product
 endif
+
+# For /odm partition.
+LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm
+# For Treble Generic System Image (GSI), system-as-root GSI needs to work on
+# both devices with and without /odm partition. Those symlinks are for devices
+# without /odm partition. For devices with /odm partition, mount odm.img under
+# /odm will hide those symlinks.
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/app $(TARGET_ROOT_OUT)/odm/app
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/bin $(TARGET_ROOT_OUT)/odm/bin
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/etc $(TARGET_ROOT_OUT)/odm/etc
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/firmware $(TARGET_ROOT_OUT)/odm/firmware
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/framework $(TARGET_ROOT_OUT)/odm/framework
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/lib $(TARGET_ROOT_OUT)/odm/lib
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/lib64 $(TARGET_ROOT_OUT)/odm/lib64
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/overlay $(TARGET_ROOT_OUT)/odm/overlay
+LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
+
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
 else
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index c8d87c8..6e46295 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -54,6 +54,9 @@
 namespace.default.permitted.paths += /vendor/framework
 namespace.default.permitted.paths += /vendor/app
 namespace.default.permitted.paths += /vendor/priv-app
+namespace.default.permitted.paths += /odm/framework
+namespace.default.permitted.paths += /odm/app
+namespace.default.permitted.paths += /odm/priv-app
 namespace.default.permitted.paths += /oem/app
 namespace.default.permitted.paths += /product/framework
 namespace.default.permitted.paths += /product/app
@@ -74,6 +77,9 @@
 namespace.default.asan.permitted.paths += /vendor/framework
 namespace.default.asan.permitted.paths += /vendor/app
 namespace.default.asan.permitted.paths += /vendor/priv-app
+namespace.default.asan.permitted.paths += /odm/framework
+namespace.default.asan.permitted.paths += /odm/app
+namespace.default.asan.permitted.paths += /odm/priv-app
 namespace.default.asan.permitted.paths += /oem/app
 namespace.default.asan.permitted.paths += /product/framework
 namespace.default.asan.permitted.paths += /product/app