Merge "Remove urb request size maximum."
diff --git a/adb/Android.mk b/adb/Android.mk
index 0eeafb6..e52f0cb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -11,6 +11,7 @@
 adb_target_sanitize :=
 
 ADB_COMMON_CFLAGS := \
+    -frtti \
     -Wall -Wextra -Werror \
     -Wno-unused-parameter \
     -Wno-missing-field-initializers \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 0e38897..ee3503b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -474,13 +474,14 @@
             asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
             if (s) {
                 unsigned rid = p->msg.arg0;
-                p->len = p->msg.data_length;
 
-                if (s->enqueue(s, p) == 0) {
+                // TODO: Convert apacket::data to a type that we can move out of.
+                std::string copy(p->data, p->data + p->msg.data_length);
+
+                if (s->enqueue(s, std::move(copy)) == 0) {
                     D("Enqueue the socket");
                     send_ready(s->id, rid, t);
                 }
-                return;
             }
         }
         break;
diff --git a/adb/adb.h b/adb/adb.h
index 21e5d4b..c9c635a 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -73,11 +73,6 @@
 };
 
 struct apacket {
-    apacket* next;
-
-    size_t len;
-    char* ptr;
-
     amessage msg;
     char data[MAX_PAYLOAD];
 };
@@ -136,9 +131,6 @@
 int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
 
 /* initialize a transport object's func pointers and state */
-#if ADB_HOST
-int get_available_local_transport_index();
-#endif
 int init_socket_transport(atransport* t, int s, int port, int local);
 void init_usb_transport(atransport* t, usb_handle* usb);
 
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index eac923d..a8ec5fb 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -42,7 +42,11 @@
                const char* message) {
     android::base::StderrLogger(id, severity, tag, file, line, message);
 #if !ADB_HOST
-    gLogdLogger(id, severity, tag, file, line, message);
+    // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
+    // doesn't result in exponential logging.
+    if (severity >= android::base::INFO) {
+        gLogdLogger(id, severity, tag, file, line, message);
+    }
 #endif
 }
 
@@ -137,11 +141,15 @@
             // -1 is used for the special values "1" and "all" that enable all
             // tracing.
             adb_trace_mask = ~0;
-            return;
+            break;
         } else {
             adb_trace_mask |= 1 << flag->second;
         }
     }
+
+    if (adb_trace_mask != 0) {
+        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    }
 }
 
 void adb_trace_init(char** argv) {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index fc6560c..1d2c8c7 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -43,11 +43,11 @@
 #define VLOG_IS_ON(TAG) \
     ((adb_trace_mask & (1 << (TAG))) != 0)
 
-#define VLOG(TAG)         \
+#define VLOG(TAG)                 \
     if (LIKELY(!VLOG_IS_ON(TAG))) \
-        ;                 \
-    else                  \
-        LOG(INFO)
+        ;                         \
+    else                          \
+        LOG(DEBUG)
 
 // You must define TRACE_TAG before using this macro.
 #define D(...) \
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index f0dff06..7adbf2d 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -453,7 +453,7 @@
  **/
 
 struct JdwpSocket : public asocket {
-    bool pass;
+    bool pass = false;
 };
 
 static void jdwp_socket_close(asocket* s) {
@@ -467,13 +467,12 @@
     }
 
     remove_socket(s);
-    free(s);
+    delete s;
 }
 
-static int jdwp_socket_enqueue(asocket* s, apacket* p) {
+static int jdwp_socket_enqueue(asocket* s, std::string) {
     /* you can't write to this asocket */
     D("LS(%d): JDWP socket received data?", s->id);
-    put_apacket(p);
     s->peer->close(s->peer);
     return -1;
 }
@@ -486,9 +485,11 @@
      * on the second one, close the connection
      */
     if (!jdwp->pass) {
-        apacket* p = get_apacket();
-        p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
-        peer->enqueue(peer, p);
+        std::string data;
+        data.resize(s->get_max_payload());
+        size_t len = jdwp_process_list(&data[0], data.size());
+        data.resize(len);
+        peer->enqueue(peer, std::move(data));
         jdwp->pass = true;
     } else {
         peer->close(peer);
@@ -496,7 +497,7 @@
 }
 
 asocket* create_jdwp_service_socket(void) {
-    JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
+    JdwpSocket* s = new JdwpSocket();
 
     if (!s) {
         fatal("failed to allocate JdwpSocket");
@@ -524,17 +525,14 @@
 static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
 
 static void jdwp_process_list_updated(void) {
-    char buffer[1024];
-    int len = jdwp_process_list_msg(buffer, sizeof(buffer));
+    std::string data;
+    data.resize(1024);
+    data.resize(jdwp_process_list_msg(&data[0], data.size()));
 
     for (auto& t : _jdwp_trackers) {
-        apacket* p = get_apacket();
-        memcpy(p->data, buffer, len);
-        p->len = len;
-
         if (t->peer) {
             // The tracker might not have been connected yet.
-            t->peer->enqueue(t->peer, p);
+            t->peer->enqueue(t->peer, data);
         }
     }
 }
@@ -560,17 +558,17 @@
     JdwpTracker* t = (JdwpTracker*)s;
 
     if (t->need_initial) {
-        apacket* p = get_apacket();
+        std::string data;
+        data.resize(s->get_max_payload());
+        data.resize(jdwp_process_list_msg(&data[0], data.size()));
         t->need_initial = false;
-        p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
-        s->peer->enqueue(s->peer, p);
+        s->peer->enqueue(s->peer, std::move(data));
     }
 }
 
-static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
+static int jdwp_tracker_enqueue(asocket* s, std::string) {
     /* you can't write to this socket */
     D("LS(%d): JDWP tracker received data?", s->id);
-    put_apacket(p);
     s->peer->close(s->peer);
     return -1;
 }
diff --git a/adb/range.h b/adb/range.h
new file mode 100644
index 0000000..7a0b822
--- /dev/null
+++ b/adb/range.h
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ * 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 <string>
+
+#include <android-base/logging.h>
+
+struct Range {
+    explicit Range(std::string data) : data_(std::move(data)) {}
+
+    Range(const Range& copy) = delete;
+    Range& operator=(const Range& copy) = delete;
+
+    Range(Range&& move) = default;
+    Range& operator=(Range&& move) = default;
+
+    bool empty() const {
+        return size() == 0;
+    }
+
+    size_t size() const {
+        return data_.size() - begin_offset_ - end_offset_;
+    };
+
+    void drop_front(size_t n) {
+        CHECK_GE(size(), n);
+        begin_offset_ += n;
+    }
+
+    void drop_end(size_t n) {
+        CHECK_GE(size(), n);
+        end_offset_ += n;
+    }
+
+    char* data() {
+        return &data_[0] + begin_offset_;
+    }
+
+    std::string::iterator begin() {
+        return data_.begin() + begin_offset_;
+    }
+
+    std::string::iterator end() {
+        return data_.end() - end_offset_;
+    }
+
+    std::string data_;
+    size_t begin_offset_ = 0;
+    size_t end_offset_ = 0;
+};
diff --git a/adb/services.cpp b/adb/services.cpp
index aff7012..6dc71cf 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -407,14 +407,6 @@
         return;
     }
 
-    // Check if more emulators can be registered. Similar unproblematic
-    // race condition as above.
-    int candidate_slot = get_available_local_transport_index();
-    if (candidate_slot < 0) {
-        *response = "Cannot accept more emulators";
-        return;
-    }
-
     // Preconditions met, try to connect to the emulator.
     std::string error;
     if (!local_connect_arbitrary_ports(console_port, adb_port, &error)) {
diff --git a/adb/socket.h b/adb/socket.h
index 64d05a9..2f09080 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -19,9 +19,12 @@
 
 #include <stddef.h>
 
+#include <deque>
 #include <memory>
+#include <string>
 
 #include "fdevent.h"
+#include "range.h"
 
 struct apacket;
 class atransport;
@@ -31,43 +34,38 @@
  * remote asocket is bound to the protocol engine.
  */
 struct asocket {
-    /* chain pointers for the local/remote list of
-     * asockets that this asocket lives in
-     */
-    asocket* next;
-    asocket* prev;
-
     /* the unique identifier for this asocket
      */
-    unsigned id;
+    unsigned id = 0;
 
     /* flag: set when the socket's peer has closed
      * but packets are still queued for delivery
      */
-    int closing;
+    int closing = 0;
 
     // flag: set when the socket failed to write, so the socket will not wait to
     // write packets and close directly.
-    bool has_write_error;
+    bool has_write_error = 0;
 
     /* flag: quit adbd when both ends close the
      * local service socket
      */
-    int exit_on_close;
+    int exit_on_close = 0;
 
     // the asocket we are connected to
-    asocket* peer;
+    asocket* peer = nullptr;
 
     /* For local asockets, the fde is used to bind
      * us to our fd event system.  For remote asockets
      * these fields are not used.
      */
-    fdevent fde;
-    int fd;
+    fdevent fde = {};
+    int fd = 0;
 
-    // queue of apackets waiting to be written
-    apacket* pkt_first;
-    apacket* pkt_last;
+    // queue of data waiting to be written
+    std::deque<Range> packet_queue;
+
+    std::string smart_socket_data;
 
     /* enqueue is called by our peer when it has data
      * for us.  It should return 0 if we can accept more
@@ -75,27 +73,27 @@
      * peer->ready() when we once again are ready to
      * receive data.
      */
-    int (*enqueue)(asocket* s, apacket* pkt);
+    int (*enqueue)(asocket* s, std::string data) = nullptr;
 
     /* ready is called by the peer when it is ready for
      * us to send data via enqueue again
      */
-    void (*ready)(asocket* s);
+    void (*ready)(asocket* s) = nullptr;
 
     /* shutdown is called by the peer before it goes away.
      * the socket should not do any further calls on its peer.
      * Always followed by a call to close. Optional, i.e. can be NULL.
      */
-    void (*shutdown)(asocket* s);
+    void (*shutdown)(asocket* s) = nullptr;
 
     /* close is called by the peer when it has gone away.
      * we are not allowed to make any further calls on the
      * peer once our close method is called.
      */
-    void (*close)(asocket* s);
+    void (*close)(asocket* s) = nullptr;
 
     /* A socket is bound to atransport */
-    atransport* transport;
+    atransport* transport = nullptr;
 
     size_t get_max_payload() const;
 };
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index f7c66db..04ad6f3 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -114,10 +114,10 @@
     ASSERT_TRUE(s != nullptr);
     arg->bytes_written = 0;
     while (true) {
-        apacket* p = get_apacket();
-        p->len = sizeof(p->data);
-        arg->bytes_written += p->len;
-        int ret = s->enqueue(s, p);
+        std::string data;
+        data.resize(MAX_PAYLOAD);
+        arg->bytes_written += data.size();
+        int ret = s->enqueue(s, std::move(data));
         if (ret == 1) {
             // The writer has one packet waiting to send.
             break;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index c53fbb4..307cbfe 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,32 +37,28 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "range.h"
 #include "transport.h"
 
 static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
 static unsigned local_socket_next_id = 1;
 
-static asocket local_socket_list = {
-    .next = &local_socket_list, .prev = &local_socket_list,
-};
+static auto& local_socket_list = *new std::vector<asocket*>();
 
 /* the the list of currently closing local sockets.
 ** these have no peer anymore, but still packets to
 ** write to their fd.
 */
-static asocket local_socket_closing_list = {
-    .next = &local_socket_closing_list, .prev = &local_socket_closing_list,
-};
+static auto& local_socket_closing_list = *new std::vector<asocket*>();
 
 // Parse the global list of sockets to find one with id |local_id|.
 // If |peer_id| is not 0, also check that it is connected to a peer
 // with id |peer_id|. Returns an asocket handle on success, NULL on failure.
 asocket* find_local_socket(unsigned local_id, unsigned peer_id) {
-    asocket* s;
-    asocket* result = NULL;
+    asocket* result = nullptr;
 
     std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
-    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+    for (asocket* s : local_socket_list) {
         if (s->id != local_id) {
             continue;
         }
@@ -75,13 +71,6 @@
     return result;
 }
 
-static void insert_local_socket(asocket* s, asocket* list) {
-    s->next = list;
-    s->prev = s->next->prev;
-    s->prev->next = s;
-    s->next->prev = s;
-}
-
 void install_local_socket(asocket* s) {
     std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
 
@@ -92,29 +81,24 @@
         fatal("local socket id overflow");
     }
 
-    insert_local_socket(s, &local_socket_list);
+    local_socket_list.push_back(s);
 }
 
 void remove_socket(asocket* s) {
     std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
-    if (s->prev && s->next) {
-        s->prev->next = s->next;
-        s->next->prev = s->prev;
-        s->next = 0;
-        s->prev = 0;
-        s->id = 0;
+    for (auto list : { &local_socket_list, &local_socket_closing_list }) {
+        list->erase(std::remove_if(list->begin(), list->end(), [s](asocket* x) { return x == s; }),
+                    list->end());
     }
 }
 
 void close_all_sockets(atransport* t) {
-    asocket* s;
-
     /* this is a little gross, but since s->close() *will* modify
     ** the list out from under you, your options are limited.
     */
     std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
 restart:
-    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+    for (asocket* s : local_socket_list) {
         if (s->transport == t || (s->peer && s->peer->transport == t)) {
             s->close(s);
             goto restart;
@@ -122,55 +106,47 @@
     }
 }
 
-static int local_socket_enqueue(asocket* s, apacket* p) {
-    D("LS(%d): enqueue %zu", s->id, p->len);
+static int local_socket_enqueue(asocket* s, std::string data) {
+    D("LS(%d): enqueue %zu", s->id, data.size());
 
-    p->ptr = p->data;
+    Range r(std::move(data));
 
     /* if there is already data queue'd, we will receive
     ** events when it's time to write.  just add this to
     ** the tail
     */
-    if (s->pkt_first) {
+    if (!s->packet_queue.empty()) {
         goto enqueue;
     }
 
     /* write as much as we can, until we
     ** would block or there is an error/eof
     */
-    while (p->len > 0) {
-        int r = adb_write(s->fd, p->ptr, p->len);
-        if (r > 0) {
-            p->len -= r;
-            p->ptr += r;
+    while (!r.empty()) {
+        int rc = adb_write(s->fd, r.data(), r.size());
+        if (rc > 0) {
+            r.drop_front(rc);
             continue;
         }
-        if ((r == 0) || (errno != EAGAIN)) {
+
+        if (rc == 0 || errno != EAGAIN) {
             D("LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno));
-            put_apacket(p);
             s->has_write_error = true;
             s->close(s);
             return 1; /* not ready (error) */
         } else {
+            // errno == EAGAIN
             break;
         }
     }
 
-    if (p->len == 0) {
-        put_apacket(p);
+    if (r.empty()) {
         return 0; /* ready for more data */
     }
 
 enqueue:
-    p->next = 0;
-    if (s->pkt_first) {
-        s->pkt_last->next = p;
-    } else {
-        s->pkt_first = p;
-    }
-    s->pkt_last = p;
-
     /* make sure we are notified when we can drain the queue */
+    s->packet_queue.push_back(std::move(r));
     fdevent_add(&s->fde, FDE_WRITE);
 
     return 1; /* not ready (backlog) */
@@ -184,7 +160,6 @@
 
 // be sure to hold the socket list lock when calling this
 static void local_socket_destroy(asocket* s) {
-    apacket *p, *n;
     int exit_on_close = s->exit_on_close;
 
     D("LS(%d): destroying fde.fd=%d", s->id, s->fde.fd);
@@ -194,14 +169,8 @@
     */
     fdevent_remove(&s->fde);
 
-    /* dispose of any unwritten data */
-    for (p = s->pkt_first; p; p = n) {
-        D("LS(%d): discarding %zu bytes", s->id, p->len);
-        n = p->next;
-        put_apacket(p);
-    }
     remove_socket(s);
-    free(s);
+    delete s;
 
     if (exit_on_close) {
         D("local_socket_destroy: exiting");
@@ -229,7 +198,7 @@
     /* If we are already closing, or if there are no
     ** pending packets, destroy immediately
     */
-    if (s->closing || s->has_write_error || s->pkt_first == NULL) {
+    if (s->closing || s->has_write_error || s->packet_queue.empty()) {
         int id = s->id;
         local_socket_destroy(s);
         D("LS(%d): closed", id);
@@ -243,7 +212,7 @@
     fdevent_del(&s->fde, FDE_READ);
     remove_socket(s);
     D("LS(%d): put on socket_closing_list fd=%d", s->id, s->fd);
-    insert_local_socket(s, &local_socket_closing_list);
+    local_socket_closing_list.push_back(s);
     CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE);
 }
 
@@ -255,35 +224,30 @@
     ** in order to simplify the code.
     */
     if (ev & FDE_WRITE) {
-        apacket* p;
-        while ((p = s->pkt_first) != nullptr) {
-            while (p->len > 0) {
-                int r = adb_write(fd, p->ptr, p->len);
-                if (r == -1) {
+        while (!s->packet_queue.empty()) {
+            Range& r = s->packet_queue.front();
+            while (!r.empty()) {
+                int rc = adb_write(fd, r.data(), r.size());
+                if (rc == -1) {
                     /* returning here is ok because FDE_READ will
                     ** be processed in the next iteration loop
                     */
                     if (errno == EAGAIN) {
                         return;
                     }
-                } else if (r > 0) {
-                    p->ptr += r;
-                    p->len -= r;
+                } else if (rc > 0) {
+                    r.drop_front(rc);
                     continue;
                 }
 
-                D(" closing after write because r=%d and errno is %d", r, errno);
+                D(" closing after write because rc=%d and errno is %d", rc, errno);
                 s->has_write_error = true;
                 s->close(s);
                 return;
             }
 
-            if (p->len == 0) {
-                s->pkt_first = p->next;
-                if (s->pkt_first == 0) {
-                    s->pkt_last = 0;
-                }
-                put_apacket(p);
+            if (r.empty()) {
+                s->packet_queue.pop_front();
             }
         }
 
@@ -305,9 +269,10 @@
     }
 
     if (ev & FDE_READ) {
-        apacket* p = get_apacket();
-        char* x = p->data;
         const size_t max_payload = s->get_max_payload();
+        std::string data;
+        data.resize(max_payload);
+        char* x = &data[0];
         size_t avail = max_payload;
         int r = 0;
         int is_eof = 0;
@@ -332,16 +297,15 @@
         }
         D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof,
           s->fde.force_eof);
-        if ((avail == max_payload) || (s->peer == 0)) {
-            put_apacket(p);
-        } else {
-            p->len = max_payload - avail;
+
+        if (avail != max_payload && s->peer) {
+            data.resize(max_payload - avail);
 
             // s->peer->enqueue() may call s->close() and free s,
             // so save variables for debug printing below.
             unsigned saved_id = s->id;
             int saved_fd = s->fd;
-            r = s->peer->enqueue(s->peer, p);
+            r = s->peer->enqueue(s->peer, std::move(data));
             D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r);
 
             if (r < 0) {
@@ -383,10 +347,7 @@
 }
 
 asocket* create_local_socket(int fd) {
-    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
-    if (s == NULL) {
-        fatal("cannot allocate socket");
-    }
+    asocket* s = new asocket();
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
     s->ready = local_socket_ready;
@@ -445,12 +406,22 @@
 }
 #endif /* ADB_HOST */
 
-static int remote_socket_enqueue(asocket* s, apacket* p) {
+static int remote_socket_enqueue(asocket* s, std::string data) {
     D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
+    apacket* p = get_apacket();
+
     p->msg.command = A_WRTE;
     p->msg.arg0 = s->peer->id;
     p->msg.arg1 = s->id;
-    p->msg.data_length = p->len;
+    p->msg.data_length = data.size();
+
+    if (data.size() > sizeof(p->data)) {
+        put_apacket(p);
+        return -1;
+    }
+
+    // TODO: Convert apacket::data to a type that we can move into.
+    memcpy(p->data, data.data(), data.size());
     send_packet(p, s->transport);
     return 1;
 }
@@ -485,7 +456,7 @@
     D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
       s->peer ? s->peer->fd : -1);
     D("RS(%d): closed", s->id);
-    free(s);
+    delete s;
 }
 
 // Create a remote socket to exchange packets with a remote service through transport
@@ -496,11 +467,7 @@
     if (id == 0) {
         fatal("invalid remote socket id (0)");
     }
-    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
-
-    if (s == NULL) {
-        fatal("cannot allocate socket");
-    }
+    asocket* s = new asocket();
     s->id = id;
     s->enqueue = remote_socket_enqueue;
     s->ready = remote_socket_ready;
@@ -550,7 +517,7 @@
     s->close(s);
 }
 
-static unsigned unhex(char* s, int len) {
+static unsigned unhex(const char* s, int len) {
     unsigned n = 0, c;
 
     while (len-- > 0) {
@@ -654,8 +621,7 @@
 
 #endif  // ADB_HOST
 
-static int smart_socket_enqueue(asocket* s, apacket* p) {
-    unsigned len;
+static int smart_socket_enqueue(asocket* s, std::string data) {
 #if ADB_HOST
     char* service = nullptr;
     char* serial = nullptr;
@@ -663,49 +629,38 @@
     TransportType type = kTransportAny;
 #endif
 
-    D("SS(%d): enqueue %zu", s->id, p->len);
+    D("SS(%d): enqueue %zu", s->id, data.size());
 
-    if (s->pkt_first == 0) {
-        s->pkt_first = p;
-        s->pkt_last = p;
+    if (s->smart_socket_data.empty()) {
+        s->smart_socket_data = std::move(data);
     } else {
-        if ((s->pkt_first->len + p->len) > s->get_max_payload()) {
-            D("SS(%d): overflow", s->id);
-            put_apacket(p);
-            goto fail;
-        }
-
-        memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len);
-        s->pkt_first->len += p->len;
-        put_apacket(p);
-
-        p = s->pkt_first;
+        std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
     }
 
     /* don't bother if we can't decode the length */
-    if (p->len < 4) {
+    if (s->smart_socket_data.size() < 4) {
         return 0;
     }
 
-    len = unhex(p->data, 4);
-    if ((len < 1) || (len > MAX_PAYLOAD)) {
-        D("SS(%d): bad size (%d)", s->id, len);
+    uint32_t len = unhex(s->smart_socket_data.data(), 4);
+    if (len == 0 || len > MAX_PAYLOAD) {
+        D("SS(%d): bad size (%u)", s->id, len);
         goto fail;
     }
 
-    D("SS(%d): len is %d", s->id, len);
+    D("SS(%d): len is %u", s->id, len);
     /* can't do anything until we have the full header */
-    if ((len + 4) > p->len) {
-        D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len);
+    if ((len + 4) > s->smart_socket_data.size()) {
+        D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - s->smart_socket_data.size());
         return 0;
     }
 
-    p->data[len + 4] = 0;
+    s->smart_socket_data[len + 4] = 0;
 
-    D("SS(%d): '%s'", s->id, (char*)(p->data + 4));
+    D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4));
 
 #if ADB_HOST
-    service = (char*)p->data + 4;
+    service = &s->smart_socket_data[4];
     if (!strncmp(service, "host-serial:", strlen("host-serial:"))) {
         char* serial_end;
         service += strlen("host-serial:");
@@ -753,7 +708,7 @@
         }
         if (!strncmp(service, "transport", strlen("transport"))) {
             D("SS(%d): okay transport", s->id);
-            p->len = 0;
+            s->smart_socket_data.clear();
             return 0;
         }
 
@@ -824,7 +779,7 @@
     /* give him our transport and upref it */
     s->peer->transport = s->transport;
 
-    connect_to_remote(s->peer, (char*)(p->data + 4));
+    connect_to_remote(s->peer, s->smart_socket_data.data() + 4);
     s->peer = 0;
     s->close(s);
     return 1;
@@ -844,21 +799,17 @@
 
 static void smart_socket_close(asocket* s) {
     D("SS(%d): closed", s->id);
-    if (s->pkt_first) {
-        put_apacket(s->pkt_first);
-    }
     if (s->peer) {
         s->peer->peer = 0;
         s->peer->close(s->peer);
         s->peer = 0;
     }
-    free(s);
+    delete s;
 }
 
 static asocket* create_smart_socket(void) {
     D("Creating smart socket");
-    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
-    if (s == NULL) fatal("cannot allocate socket");
+    asocket* s = new asocket();
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
     s->shutdown = NULL;
diff --git a/adb/transport.cpp b/adb/transport.cpp
index f221785..9ae1297 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -41,6 +41,7 @@
 
 #include "adb.h"
 #include "adb_auth.h"
+#include "adb_io.h"
 #include "adb_trace.h"
 #include "adb_utils.h"
 #include "diagnose_usb.h"
@@ -65,6 +66,41 @@
     return next++;
 }
 
+bool FdConnection::Read(apacket* packet) {
+    if (!ReadFdExactly(fd_.get(), &packet->msg, sizeof(amessage))) {
+        D("remote local: read terminated (message)");
+        return false;
+    }
+
+    if (packet->msg.data_length > sizeof(packet->data)) {
+        D("remote local: read overflow (data length = %" PRIu32 ")", packet->msg.data_length);
+        return false;
+    }
+
+    if (!ReadFdExactly(fd_.get(), &packet->data, packet->msg.data_length)) {
+        D("remote local: terminated (data)");
+        return false;
+    }
+
+    return true;
+}
+
+bool FdConnection::Write(apacket* packet) {
+    uint32_t length = packet->msg.data_length;
+
+    if (!WriteFdExactly(fd_.get(), &packet->msg, sizeof(amessage) + length)) {
+        D("remote local: write terminated");
+        return false;
+    }
+
+    return true;
+}
+
+void FdConnection::Close() {
+    adb_shutdown(fd_.get());
+    fd_.reset();
+}
+
 static std::string dump_packet(const char* name, const char* func, apacket* p) {
     unsigned command = p->msg.command;
     int len = p->msg.data_length;
@@ -220,13 +256,21 @@
 
         {
             ATRACE_NAME("read_transport read_remote");
-            if (t->read_from_remote(p, t) != 0) {
+            if (!t->connection->Read(p)) {
                 D("%s: remote read failed for transport", t->serial);
                 put_apacket(p);
                 break;
             }
+
+            if (!check_header(p, t)) {
+                D("%s: remote read: bad header", t->serial);
+                put_apacket(p);
+                break;
+            }
+
 #if ADB_HOST
             if (p->msg.command == 0) {
+                put_apacket(p);
                 continue;
             }
 #endif
@@ -334,9 +378,9 @@
  */
 struct device_tracker {
     asocket socket;
-    bool update_needed;
-    bool long_output;
-    device_tracker* next;
+    bool update_needed = false;
+    bool long_output = false;
+    device_tracker* next = nullptr;
 };
 
 /* linked list of all device trackers */
@@ -367,24 +411,25 @@
         peer->close(peer);
     }
     device_tracker_remove(tracker);
-    free(tracker);
+    delete tracker;
 }
 
-static int device_tracker_enqueue(asocket* socket, apacket* p) {
+static int device_tracker_enqueue(asocket* socket, std::string) {
     /* you can't read from a device tracker, close immediately */
-    put_apacket(p);
     device_tracker_close(socket);
     return -1;
 }
 
 static int device_tracker_send(device_tracker* tracker, const std::string& string) {
-    apacket* p = get_apacket();
     asocket* peer = tracker->socket.peer;
 
-    snprintf(reinterpret_cast<char*>(p->data), 5, "%04x", static_cast<int>(string.size()));
-    memcpy(&p->data[4], string.data(), string.size());
-    p->len = 4 + string.size();
-    return peer->enqueue(peer, p);
+    std::string data;
+    data.resize(4 + string.size());
+    char buf[5];
+    snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size()));
+    memcpy(&data[0], buf, 4);
+    memcpy(&data[4], string.data(), string.size());
+    return peer->enqueue(peer, std::move(data));
 }
 
 static void device_tracker_ready(asocket* socket) {
@@ -401,7 +446,7 @@
 }
 
 asocket* create_device_tracker(bool long_output) {
-    device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
+    device_tracker* tracker = new device_tracker();
     if (tracker == nullptr) fatal("cannot allocate device tracker");
 
     D("device tracker %p created", tracker);
@@ -625,7 +670,7 @@
     t->ref_count--;
     if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)", t->serial);
-        t->close(t);
+        t->connection->Close();
         remove_transport(t);
     } else {
         D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
@@ -753,14 +798,14 @@
 }
 
 int atransport::Write(apacket* p) {
-    return write_func_(p, this);
+    return this->connection->Write(p) ? 0 : -1;
 }
 
 void atransport::Kick() {
     if (!kicked_) {
+        D("kicking transport %s", this->serial);
         kicked_ = true;
-        CHECK(kick_func_ != nullptr);
-        kick_func_(this);
+        this->connection->Close();
     }
 }
 
@@ -1082,8 +1127,12 @@
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb) {
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
-    transport_list.remove_if(
-        [usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; });
+    transport_list.remove_if([usb](atransport* t) {
+        if (auto connection = dynamic_cast<UsbConnection*>(t->connection.get())) {
+            return connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
+        }
+        return false;
+    });
 }
 
 bool check_header(apacket* p, atransport* t) {
diff --git a/adb/transport.h b/adb/transport.h
index 86cd992..9700f44 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -28,10 +28,11 @@
 #include <string>
 #include <unordered_set>
 
-#include "adb.h"
-
 #include <openssl/rsa.h>
 
+#include "adb.h"
+#include "adb_unique_fd.h"
+
 typedef std::unordered_set<std::string> FeatureSet;
 
 const FeatureSet& supported_features();
@@ -56,6 +57,50 @@
 
 TransportId NextTransportId();
 
+// Abstraction for a blocking packet transport.
+struct Connection {
+    Connection() = default;
+    Connection(const Connection& copy) = delete;
+    Connection(Connection&& move) = delete;
+
+    // Destroy a Connection. Formerly known as 'Close' in atransport.
+    virtual ~Connection() = default;
+
+    // Read/Write a packet. These functions are concurrently called from a transport's reader/writer
+    // threads.
+    virtual bool Read(apacket* packet) = 0;
+    virtual bool Write(apacket* packet) = 0;
+
+    // Terminate a connection.
+    // This method must be thread-safe, and must cause concurrent Reads/Writes to terminate.
+    // Formerly known as 'Kick' in atransport.
+    virtual void Close() = 0;
+};
+
+struct FdConnection : public Connection {
+    explicit FdConnection(unique_fd fd) : fd_(std::move(fd)) {}
+
+    bool Read(apacket* packet) override final;
+    bool Write(apacket* packet) override final;
+
+    void Close() override;
+
+  private:
+    unique_fd fd_;
+};
+
+struct UsbConnection : public Connection {
+    explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
+    ~UsbConnection();
+
+    bool Read(apacket* packet) override final;
+    bool Write(apacket* packet) override final;
+
+    void Close() override final;
+
+    usb_handle* handle_;
+};
+
 class atransport {
   public:
     // TODO(danalbert): We expose waaaaaaay too much stuff because this was
@@ -73,12 +118,6 @@
     }
     virtual ~atransport() {}
 
-    int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
-    void (*close)(atransport* t) = nullptr;
-
-    void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
-    void SetKickFunction(void (*kick_func)(atransport*)) { kick_func_ = kick_func; }
-    bool IsKicked() { return kicked_; }
     int Write(apacket* p);
     void Kick();
 
@@ -95,9 +134,7 @@
     bool online = false;
     TransportType type = kTransportAny;
 
-    // USB handle or socket fd as needed.
-    usb_handle* usb = nullptr;
-    int sfd = -1;
+    std::unique_ptr<Connection> connection;
 
     // Used to identify transports for clients.
     char* serial = nullptr;
@@ -105,22 +142,8 @@
     char* model = nullptr;
     char* device = nullptr;
     char* devpath = nullptr;
-    void SetLocalPortForEmulator(int port) {
-        CHECK_EQ(local_port_for_emulator_, -1);
-        local_port_for_emulator_ = port;
-    }
 
-    bool GetLocalPortForEmulator(int* port) const {
-        if (type == kTransportLocal && local_port_for_emulator_ != -1) {
-            *port = local_port_for_emulator_;
-            return true;
-        }
-        return false;
-    }
-
-    bool IsTcpDevice() const {
-        return type == kTransportLocal && local_port_for_emulator_ == -1;
-    }
+    bool IsTcpDevice() const { return type == kTransportLocal; }
 
 #if ADB_HOST
     std::shared_ptr<RSA> NextKey();
@@ -165,10 +188,7 @@
     bool MatchesTarget(const std::string& target) const;
 
 private:
-    int local_port_for_emulator_ = -1;
     bool kicked_ = false;
-    void (*kick_func_)(atransport*) = nullptr;
-    int (*write_func_)(apacket*, atransport*) = nullptr;
 
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index d6c84da..560a031 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -28,10 +28,12 @@
 #include <condition_variable>
 #include <mutex>
 #include <thread>
+#include <unordered_map>
 #include <vector>
 
 #include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
@@ -40,6 +42,7 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "sysdeps/chrono.h"
 
@@ -53,48 +56,15 @@
 
 static std::mutex& local_transports_lock = *new std::mutex();
 
-/* we keep a list of opened transports. The atransport struct knows to which
- * local transport it is connected. The list is used to detect when we're
- * trying to connect twice to a given local transport.
- */
-static atransport*  local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
+// We keep a map from emulator port to transport.
+// TODO: weak_ptr?
+static auto& local_transports GUARDED_BY(local_transports_lock) =
+    *new std::unordered_map<int, atransport*>();
 #endif /* ADB_HOST */
 
-static int remote_read(apacket *p, atransport *t)
-{
-    if (!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))) {
-        D("remote local: read terminated (message)");
-        return -1;
-    }
-
-    if (!check_header(p, t)) {
-        D("bad header: terminated (data)");
-        return -1;
-    }
-
-    if (!ReadFdExactly(t->sfd, p->data, p->msg.data_length)) {
-        D("remote local: terminated (data)");
-        return -1;
-    }
-
-    return 0;
-}
-
-static int remote_write(apacket *p, atransport *t)
-{
-    int   length = p->msg.data_length;
-
-    if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) {
-        D("remote local: write terminated");
-        return -1;
-    }
-
-    return 0;
-}
-
 bool local_connect(int port) {
     std::string dummy;
-    return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
+    return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
 }
 
 void connect_device(const std::string& address, std::string* response) {
@@ -423,130 +393,83 @@
     std::thread(func, port).detach();
 }
 
-static void remote_kick(atransport *t)
-{
-    int fd = t->sfd;
-    t->sfd = -1;
-    adb_shutdown(fd);
-    adb_close(fd);
-
 #if ADB_HOST
-    int  nn;
-    std::lock_guard<std::mutex> lock(local_transports_lock);
-    for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
-        if (local_transports[nn] == t) {
-            local_transports[nn] = NULL;
-            break;
-        }
-    }
-#endif
-}
+struct EmulatorConnection : public FdConnection {
+    EmulatorConnection(unique_fd fd, int local_port)
+        : FdConnection(std::move(fd)), local_port_(local_port) {}
 
-static void remote_close(atransport *t)
-{
-    int fd = t->sfd;
-    if (fd != -1) {
-        t->sfd = -1;
-        adb_close(fd);
-    }
-#if ADB_HOST
-    int local_port;
-    if (t->GetLocalPortForEmulator(&local_port)) {
-        VLOG(TRANSPORT) << "remote_close, local_port = " << local_port;
+    ~EmulatorConnection() {
+        VLOG(TRANSPORT) << "remote_close, local_port = " << local_port_;
         std::unique_lock<std::mutex> lock(retry_ports_lock);
         RetryPort port;
-        port.port = local_port;
+        port.port = local_port_;
         port.retry_count = LOCAL_PORT_RETRY_COUNT;
         retry_ports.push_back(port);
         retry_ports_cond.notify_one();
     }
-#endif
-}
 
+    void Close() override {
+        std::lock_guard<std::mutex> lock(local_transports_lock);
+        local_transports.erase(local_port_);
+        FdConnection::Close();
+    }
 
-#if ADB_HOST
+    int local_port_;
+};
+
 /* Only call this function if you already hold local_transports_lock. */
 static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
-{
-    int i;
-    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
-        int local_port;
-        if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
-            if (local_port == adb_port) {
-                return local_transports[i];
-            }
-        }
+    REQUIRES(local_transports_lock) {
+    auto it = local_transports.find(adb_port);
+    if (it == local_transports.end()) {
+        return nullptr;
     }
-    return NULL;
+    return it->second;
 }
 
-std::string getEmulatorSerialString(int console_port)
-{
+std::string getEmulatorSerialString(int console_port) {
     return android::base::StringPrintf("emulator-%d", console_port);
 }
 
-atransport* find_emulator_transport_by_adb_port(int adb_port)
-{
+atransport* find_emulator_transport_by_adb_port(int adb_port) {
     std::lock_guard<std::mutex> lock(local_transports_lock);
-    atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
-    return result;
+    return find_emulator_transport_by_adb_port_locked(adb_port);
 }
 
-atransport* find_emulator_transport_by_console_port(int console_port)
-{
+atransport* find_emulator_transport_by_console_port(int console_port) {
     return find_transport(getEmulatorSerialString(console_port).c_str());
 }
-
-
-/* Only call this function if you already hold local_transports_lock. */
-int get_available_local_transport_index_locked()
-{
-    int i;
-    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
-        if (local_transports[i] == NULL) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-int get_available_local_transport_index()
-{
-    std::lock_guard<std::mutex> lock(local_transports_lock);
-    int result = get_available_local_transport_index_locked();
-    return result;
-}
 #endif
 
-int init_socket_transport(atransport *t, int s, int adb_port, int local)
-{
-    int  fail = 0;
+int init_socket_transport(atransport* t, int s, int adb_port, int local) {
+    int fail = 0;
 
-    t->SetKickFunction(remote_kick);
-    t->SetWriteFunction(remote_write);
-    t->close = remote_close;
-    t->read_from_remote = remote_read;
-    t->sfd = s;
+    unique_fd fd(s);
     t->sync_token = 1;
     t->type = kTransportLocal;
 
 #if ADB_HOST
+    // Emulator connection.
     if (local) {
+        t->connection.reset(new EmulatorConnection(std::move(fd), adb_port));
         std::lock_guard<std::mutex> lock(local_transports_lock);
-        t->SetLocalPortForEmulator(adb_port);
         atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
-        int index = get_available_local_transport_index_locked();
         if (existing_transport != NULL) {
             D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
             fail = -1;
-        } else if (index < 0) {
+        } else if (local_transports.size() >= ADB_LOCAL_TRANSPORT_MAX) {
             // Too many emulators.
             D("cannot register more emulators. Maximum is %d", ADB_LOCAL_TRANSPORT_MAX);
             fail = -1;
         } else {
-            local_transports[index] = t;
+            local_transports[adb_port] = t;
         }
+
+        return fail;
     }
 #endif
+
+    // Regular tcp connection.
+    t->connection.reset(new FdConnection(std::move(fd)));
     return fail;
 }
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 68689d4..d987d4f 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,22 +20,6 @@
 
 #include "adb.h"
 
-TEST(transport, kick_transport) {
-  atransport t;
-  static size_t kick_count;
-  kick_count = 0;
-  // Mutate some member so we can test that the function is run.
-  t.SetKickFunction([](atransport* trans) { kick_count++; });
-  ASSERT_FALSE(t.IsKicked());
-  t.Kick();
-  ASSERT_TRUE(t.IsKicked());
-  ASSERT_EQ(1u, kick_count);
-  // A transport can only be kicked once.
-  t.Kick();
-  ASSERT_TRUE(t.IsKicked());
-  ASSERT_EQ(1u, kick_count);
-}
-
 static void DisconnectFunc(void* arg, atransport*) {
     int* count = reinterpret_cast<int*>(arg);
     ++*count;
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 3474820..a108699 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -61,6 +61,10 @@
 static int UsbReadPayload(usb_handle* h, apacket* p) {
     D("UsbReadPayload(%d)", p->msg.data_length);
 
+    if (p->msg.data_length > sizeof(p->data)) {
+        return -1;
+    }
+
 #if CHECK_PACKET_OVERFLOW
     size_t usb_packet_size = usb_get_max_packet_size(h);
     CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
@@ -80,25 +84,18 @@
 #endif
 }
 
-static int remote_read(apacket* p, atransport* t) {
-    int n = UsbReadMessage(t->usb, &p->msg);
+static int remote_read(apacket* p, usb_handle* usb) {
+    int n = UsbReadMessage(usb, &p->msg);
     if (n < 0) {
         D("remote usb: read terminated (message)");
         return -1;
     }
-    if (static_cast<size_t>(n) != sizeof(p->msg) || !check_header(p, t)) {
-        D("remote usb: check_header failed, skip it");
-        goto err_msg;
-    }
-    if (t->GetConnectionState() == kCsOffline) {
-        // If we read a wrong msg header declaring a large message payload, don't read its payload.
-        // Otherwise we may miss true messages from the device.
-        if (p->msg.command != A_CNXN && p->msg.command != A_AUTH) {
-            goto err_msg;
-        }
+    if (static_cast<size_t>(n) != sizeof(p->msg)) {
+        D("remote usb: read received unexpected header length %d", n);
+        return -1;
     }
     if (p->msg.data_length) {
-        n = UsbReadPayload(t->usb, p);
+        n = UsbReadPayload(usb, p);
         if (n < 0) {
             D("remote usb: terminated (data)");
             return -1;
@@ -106,34 +103,29 @@
         if (static_cast<uint32_t>(n) != p->msg.data_length) {
             D("remote usb: read payload failed (need %u bytes, give %d bytes), skip it",
               p->msg.data_length, n);
-            goto err_msg;
+            return -1;
         }
     }
     return 0;
-
-err_msg:
-    p->msg.command = 0;
-    return 0;
 }
 
 #else
 
 // On Android devices, we rely on the kernel to provide buffered read.
 // So we can recover automatically from EOVERFLOW.
-static int remote_read(apacket *p, atransport *t)
-{
-    if (usb_read(t->usb, &p->msg, sizeof(amessage))) {
+static int remote_read(apacket* p, usb_handle* usb) {
+    if (usb_read(usb, &p->msg, sizeof(amessage))) {
         PLOG(ERROR) << "remote usb: read terminated (message)";
         return -1;
     }
 
-    if (!check_header(p, t)) {
-        LOG(ERROR) << "remote usb: check_header failed";
-        return -1;
-    }
-
     if (p->msg.data_length) {
-        if (usb_read(t->usb, p->data, p->msg.data_length)) {
+        if (p->msg.data_length > sizeof(p->data)) {
+            PLOG(ERROR) << "remote usb: read overflow (data length = " << p->msg.data_length << ")";
+            return -1;
+        }
+
+        if (usb_read(usb, p->data, p->msg.data_length)) {
             PLOG(ERROR) << "remote usb: terminated (data)";
             return -1;
         }
@@ -143,45 +135,43 @@
 }
 #endif
 
-static int remote_write(apacket *p, atransport *t)
-{
-    unsigned size = p->msg.data_length;
+UsbConnection::~UsbConnection() {
+    usb_close(handle_);
+}
 
-    if (usb_write(t->usb, &p->msg, sizeof(amessage))) {
+bool UsbConnection::Read(apacket* packet) {
+    int rc = remote_read(packet, handle_);
+    return rc == 0;
+}
+
+bool UsbConnection::Write(apacket* packet) {
+    unsigned size = packet->msg.data_length;
+
+    if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != 0) {
         PLOG(ERROR) << "remote usb: 1 - write terminated";
-        return -1;
+        return false;
     }
-    if (p->msg.data_length == 0) return 0;
-    if (usb_write(t->usb, &p->data, size)) {
+
+    if (packet->msg.data_length != 0 && usb_write(handle_, &packet->data, size) != 0) {
         PLOG(ERROR) << "remote usb: 2 - write terminated";
-        return -1;
+        return false;
     }
 
-    return 0;
+    return true;
 }
 
-static void remote_close(atransport* t) {
-    usb_close(t->usb);
-    t->usb = 0;
-}
-
-static void remote_kick(atransport* t) {
-    usb_kick(t->usb);
+void UsbConnection::Close() {
+    usb_kick(handle_);
 }
 
 void init_usb_transport(atransport* t, usb_handle* h) {
     D("transport: usb");
-    t->close = remote_close;
-    t->SetKickFunction(remote_kick);
-    t->SetWriteFunction(remote_write);
-    t->read_from_remote = remote_read;
+    t->connection.reset(new UsbConnection(h));
     t->sync_token = 1;
     t->type = kTransportUsb;
-    t->usb = h;
 }
 
-int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
-{
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) {
     return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 }
 
diff --git a/base/Android.bp b/base/Android.bp
index 01800af..6cadcfc 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -45,6 +45,7 @@
         support_system_process: true,
     },
     srcs: [
+        "chrono_utils.cpp",
         "file.cpp",
         "logging.cpp",
         "parsenetaddress.cpp",
@@ -72,14 +73,12 @@
         },
         linux: {
             srcs: [
-                "chrono_utils.cpp",
                 "errors_unix.cpp",
             ],
             cppflags: ["-Wexit-time-destructors"],
         },
         darwin: {
             srcs: [
-                "chrono_utils.cpp",
                 "errors_unix.cpp",
             ],
             cppflags: ["-Wexit-time-destructors"],
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
index dbe5483..19080a5 100644
--- a/base/chrono_utils.cpp
+++ b/base/chrono_utils.cpp
@@ -28,7 +28,7 @@
   return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
                                 std::chrono::nanoseconds(ts.tv_nsec));
 #else
-  // Darwin does not support clock_gettime.
+  // Darwin and Windows do not support clock_gettime.
   return boot_clock::time_point();
 #endif  // __linux__
 }
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
index 7679d4c..c3396ee 100644
--- a/base/include/android-base/chrono_utils.h
+++ b/base/include/android-base/chrono_utils.h
@@ -20,7 +20,9 @@
 #include <chrono>
 #include <sstream>
 
+#if __cplusplus > 201103L  // C++14
 using namespace std::chrono_literals;
+#endif
 
 namespace android {
 namespace base {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index ae0a401..a1fe6ed 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -281,6 +281,10 @@
     {"warm_reset_0x80", 141},
     {"pon_reason_0xb0", 142},
     {"reboot_download", 143},
+    {"reboot_recovery_mode", 144},
+    {"oem_sdi_err_fatal", 145},
+    {"pmic_watchdog", 146},
+    {"software_master", 147},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index fb8a205..5323524 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -114,6 +114,7 @@
         "libbacktrace",
         "libunwind",
         "libunwindstack",
+        "libdexfile",
         "liblzma",
         "libcutils",
     ],
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 5fddddc..364fca5 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -55,7 +55,7 @@
 using android::base::unique_fd;
 using unwindstack::Regs;
 
-extern "C" void __linker_enable_fallback_allocator();
+extern "C" bool __linker_enable_fallback_allocator();
 extern "C" void __linker_disable_fallback_allocator();
 
 // This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
@@ -65,7 +65,11 @@
 // This isn't the default method of dumping because it can fail in cases such as address space
 // exhaustion.
 static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
-  __linker_enable_fallback_allocator();
+  if (!__linker_enable_fallback_allocator()) {
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
+    return;
+  }
+
   {
     std::unique_ptr<Regs> regs;
 
@@ -84,7 +88,11 @@
 
 static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
                                          void* abort_message) {
-  __linker_enable_fallback_allocator();
+  if (!__linker_enable_fallback_allocator()) {
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
+    return;
+  }
+
   engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
                              ucontext);
   __linker_disable_fallback_allocator();
@@ -116,7 +124,7 @@
   closedir(dir);
 }
 
-static bool forward_output(int src_fd, int dst_fd) {
+static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
   // Make sure the thread actually got the signal.
   struct pollfd pfd = {
     .fd = src_fd, .events = POLLIN,
@@ -127,6 +135,18 @@
     return false;
   }
 
+  pid_t tid;
+  if (TEMP_FAILURE_RETRY(read(src_fd, &tid, sizeof(tid))) != sizeof(tid)) {
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to read tid");
+    return false;
+  }
+
+  if (tid != expected_tid) {
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "received tid %d, expected %d", tid,
+                          expected_tid);
+    return false;
+  }
+
   while (true) {
     char buf[512];
     ssize_t rc = TEMP_FAILURE_RETRY(read(src_fd, buf, sizeof(buf)));
@@ -144,16 +164,54 @@
   }
 }
 
+struct __attribute__((__packed__)) packed_thread_output {
+  int32_t tid;
+  int32_t fd;
+};
+
+static uint64_t pack_thread_fd(pid_t tid, int fd) {
+  packed_thread_output packed = {.tid = tid, .fd = fd};
+  uint64_t result;
+  static_assert(sizeof(packed) == sizeof(result));
+  memcpy(&result, &packed, sizeof(packed));
+  return result;
+}
+
+static std::pair<pid_t, int> unpack_thread_fd(uint64_t value) {
+  packed_thread_output result;
+  memcpy(&result, &value, sizeof(value));
+  return std::make_pair(result.tid, result.fd);
+}
+
 static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
-  static std::atomic<int> trace_output_fd(-1);
+  static std::atomic<uint64_t> trace_output(pack_thread_fd(-1, -1));
 
   if (info->si_value.sival_int == ~0) {
     // Asked to dump by the original signal recipient.
-    debuggerd_fallback_trace(trace_output_fd, ucontext);
+    uint64_t val = trace_output.load();
+    auto [tid, fd] = unpack_thread_fd(val);
+    if (tid != gettid()) {
+      // We received some other thread's info request?
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                            "thread %d received output fd for thread %d?", gettid(), tid);
+      return;
+    }
 
-    int tmp = trace_output_fd.load();
-    trace_output_fd.store(-1);
-    close(tmp);
+    if (!trace_output.compare_exchange_strong(val, pack_thread_fd(-1, -1))) {
+      // Presumably, the timeout in forward_output expired, and the main thread moved on.
+      // If this happened, the main thread closed our fd for us, so just return.
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc", "cmpxchg for thread %d failed", gettid());
+      return;
+    }
+
+    // Write our tid to the output fd to let the main thread know that we're working.
+    if (TEMP_FAILURE_RETRY(write(fd, &tid, sizeof(tid))) == sizeof(tid)) {
+      debuggerd_fallback_trace(fd, ucontext);
+    } else {
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write to output fd");
+    }
+
+    close(fd);
     return;
   }
 
@@ -189,7 +247,14 @@
           return false;
         }
 
-        trace_output_fd.store(pipe_write.get());
+        uint64_t expected = pack_thread_fd(-1, -1);
+        if (!trace_output.compare_exchange_strong(expected,
+                                                  pack_thread_fd(tid, pipe_write.release()))) {
+          auto [tid, fd] = unpack_thread_fd(expected);
+          async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                                "thread %d is already outputting to fd %d?", tid, fd);
+          return false;
+        }
 
         siginfo_t siginfo = {};
         siginfo.si_code = SI_QUEUE;
@@ -203,12 +268,20 @@
           return false;
         }
 
-        bool success = forward_output(pipe_read.get(), output_fd);
-        if (success) {
-          // The signaled thread has closed trace_output_fd already.
-          (void)pipe_write.release();
-        } else {
-          trace_output_fd.store(-1);
+        bool success = forward_output(pipe_read.get(), output_fd, tid);
+        if (!success) {
+          async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                                "timeout expired while waiting for thread %d to dump", tid);
+        }
+
+        // Regardless of whether the poll succeeds, check to see if the thread took fd ownership.
+        uint64_t post_wait = trace_output.exchange(pack_thread_fd(-1, -1));
+        if (post_wait != pack_thread_fd(-1, -1)) {
+          auto [tid, fd] = unpack_thread_fd(post_wait);
+          if (fd != -1) {
+            async_safe_format_log(ANDROID_LOG_ERROR, "libc", "closing fd %d for thread %d", fd, tid);
+            close(fd);
+          }
         }
 
         return true;
diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy
index c64e288..b1f459d 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm.policy
@@ -22,6 +22,7 @@
 process_vm_readv: 1
 tgkill: 1
 rt_sigprocmask: 1
+rt_sigaction: 1
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
@@ -30,7 +31,6 @@
 getuid32: 1
 fstat64: 1
 mmap2: arg2 in PROT_READ|PROT_WRITE
-sigaction: 1
 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 0c689bb..e5e7afb 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -21,6 +21,7 @@
 process_vm_readv: 1
 tgkill: 1
 rt_sigprocmask: 1
+rt_sigaction: 1
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
@@ -29,7 +30,6 @@
 getuid: 1
 fstat: 1
 mmap: arg2 in PROT_READ|PROT_WRITE
-rt_sigaction: 1
 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 dadffac..b78c94a 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -29,6 +29,7 @@
 
 tgkill: 1
 rt_sigprocmask: 1
+rt_sigaction: 1
 rt_tgsigqueueinfo: 1
 
 #define PR_SET_VMA 0x53564d41
@@ -42,12 +43,10 @@
 getuid: 1
 fstat: 1
 mmap: arg2 in PROT_READ|PROT_WRITE
-rt_sigaction: 1
 #else
 getuid32: 1
 fstat64: 1
 mmap2: arg2 in PROT_READ|PROT_WRITE
-sigaction: 1
 #endif
 
 // Needed for logging.
diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy
index c64e288..b1f459d 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86.policy
@@ -22,6 +22,7 @@
 process_vm_readv: 1
 tgkill: 1
 rt_sigprocmask: 1
+rt_sigaction: 1
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
@@ -30,7 +31,6 @@
 getuid32: 1
 fstat64: 1
 mmap2: arg2 in PROT_READ|PROT_WRITE
-sigaction: 1
 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 0c689bb..e5e7afb 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86_64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
@@ -21,6 +21,7 @@
 process_vm_readv: 1
 tgkill: 1
 rt_sigprocmask: 1
+rt_sigaction: 1
 rt_tgsigqueueinfo: 1
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
@@ -29,7 +30,6 @@
 getuid: 1
 fstat: 1
 mmap: arg2 in PROT_READ|PROT_WRITE
-rt_sigaction: 1
 geteuid: 1
 getgid: 1
 getegid: 1
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index 46a6f76..1787031 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -509,6 +509,29 @@
   ASSERT_EQ("_ZTH_N3oneE", demangler.Parse("_ZTH_N3oneE"));
 }
 
+TEST(DemangleTest, r_value_reference) {
+  Demangler demangler;
+  ASSERT_EQ(
+      "android::SurfaceComposerClient::Transaction::merge(android::SurfaceComposerClient::"
+      "Transaction&&)",
+      demangler.Parse("_ZN7android21SurfaceComposerClient11Transaction5mergeEOS1_"));
+}
+
+TEST(DemangleTest, initial_St) {
+  Demangler demangler;
+  EXPECT_EQ("std::state", demangler.Parse("_ZSt5state"));
+  EXPECT_EQ("std::_In::ward", demangler.Parse("_ZNSt3_In4wardE"));
+  EXPECT_EQ("std::__terminate(void (*)())", demangler.Parse("_ZSt11__terminatePFvvE"));
+}
+
+TEST(DemangleTest, cfi) {
+  Demangler demangler;
+  EXPECT_EQ("nfa_sys_ptim_timer_update(tPTIM_CB*)",
+            demangler.Parse("_Z25nfa_sys_ptim_timer_updateP8tPTIM_CB"));
+  EXPECT_EQ("nfa_sys_ptim_timer_update(tPTIM_CB*) [clone .cfi]",
+            demangler.Parse("_Z25nfa_sys_ptim_timer_updateP8tPTIM_CB.cfi"));
+}
+
 TEST(DemangleTest, demangle) {
   std::string str;
 
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index af2816c..7a3aa81 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -580,6 +580,10 @@
     }
     return name + 1;
 
+  case 'O':
+    cur_state_.suffixes.push_back("&&");
+    return name + 1;
+
   case 'K':
   case 'V': {
     const char* suffix;
@@ -701,6 +705,9 @@
         cur_state_.str.clear();
       }
       return name;
+    } else if (strcmp(name, ".cfi") == 0) {
+      function_suffix_ += " [clone .cfi]";
+      return name + 4;
     }
   }
   return nullptr;
@@ -816,6 +823,16 @@
     return name + 1;
   }
 
+  if (*name == 'S') {
+    name++;
+    if (*name == 't') {
+      function_name_ = "std::";
+      name++;
+    } else {
+      return nullptr;
+    }
+  }
+
   if (std::isdigit(*name)) {
     name = GetStringFromLength(name, &function_name_);
   } else if (*name == 'L' && std::isdigit(name[1])) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index a2b80ad..9aab0ba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -32,11 +32,14 @@
 #include <unistd.h>
 
 #include <memory>
+#include <string>
 #include <thread>
+#include <vector>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/android_filesystem_config.h>
 #include <cutils/android_reboot.h>
@@ -775,6 +778,22 @@
     }
 }
 
+static bool call_vdc(const std::vector<std::string>& args) {
+    std::vector<char const*> argv;
+    argv.emplace_back("/system/bin/vdc");
+    for (auto& arg : args) {
+        argv.emplace_back(arg.c_str());
+    }
+    LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
+    int ret = android_fork_execvp(4, const_cast<char**>(argv.data()), nullptr, false, true);
+    if (ret != 0) {
+        LOG(ERROR) << "vdc returned error code: " << ret;
+        return false;
+    }
+    LOG(DEBUG) << "vdc finished successfully";
+    return true;
+}
+
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
  * first successful mount.
@@ -881,6 +900,13 @@
                     LERROR << "Only one encryptable/encrypted partition supported";
                 }
                 encryptable = status;
+                if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+                    if (!call_vdc(
+                            {"cryptfs", "encryptFstab", fstab->recs[attempted_idx].mount_point})) {
+                        LERROR << "Encryption failed";
+                        return FS_MGR_MNTALL_FAIL;
+                    }
+                }
             }
 
             /* Success!  Go get the next one */
@@ -955,7 +981,11 @@
             encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
         } else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
                    should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+            if (!call_vdc({"cryptfs", "mountFstab", fstab->recs[attempted_idx].mount_point})) {
+                ++error_count;
+            }
             encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
+            continue;
         } else {
             // fs_options might be null so we cannot use PERROR << directly.
             // Use StringPrintf to output "(null)" instead.
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 676ee41..08b8b26 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -42,7 +42,6 @@
 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
 #define FAKE_BATTERY_CAPACITY 42
 #define FAKE_BATTERY_TEMPERATURE 424
-#define ALWAYS_PLUGGED_CAPACITY 100
 #define MILLION 1.0e6
 #define DEFAULT_VBUS_VOLTAGE 5000000
 
@@ -81,8 +80,11 @@
     props->batteryTechnology.clear();
 }
 
-BatteryMonitor::BatteryMonitor() : mHealthdConfig(nullptr), mBatteryDevicePresent(false),
-    mAlwaysPluggedDevice(false), mBatteryFixedCapacity(0), mBatteryFixedTemperature(0) {
+BatteryMonitor::BatteryMonitor()
+    : mHealthdConfig(nullptr),
+      mBatteryDevicePresent(false),
+      mBatteryFixedCapacity(0),
+      mBatteryFixedTemperature(0) {
     initBatteryProperties(&props);
 }
 
@@ -223,15 +225,6 @@
         mBatteryFixedTemperature :
         getIntField(mHealthdConfig->batteryTemperaturePath);
 
-    // For devices which do not have battery and are always plugged
-    // into power souce.
-    if (mAlwaysPluggedDevice) {
-        props.chargerAcOnline = true;
-        props.batteryPresent = true;
-        props.batteryStatus = BATTERY_STATUS_CHARGING;
-        props.batteryHealth = BATTERY_HEALTH_GOOD;
-    }
-
     std::string buf;
 
     if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
@@ -405,11 +398,7 @@
         break;
 
     case BATTERY_PROP_BATTERY_STATUS:
-        if (mAlwaysPluggedDevice) {
-            val->valueInt64 = BATTERY_STATUS_CHARGING;
-        } else {
-            val->valueInt64 = getChargeStatus();
-        }
+        val->valueInt64 = getChargeStatus();
         ret = NO_ERROR;
         break;
 
@@ -628,9 +617,6 @@
         KLOG_WARNING(LOG_TAG, "No battery devices found\n");
         hc->periodic_chores_interval_fast = -1;
         hc->periodic_chores_interval_slow = -1;
-        mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY;
-        mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
-        mAlwaysPluggedDevice = true;
     } else {
         if (mHealthdConfig->batteryStatusPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 8865a7d..194e667 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -48,7 +48,6 @@
     struct healthd_config *mHealthdConfig;
     Vector<String8> mChargerNames;
     bool mBatteryDevicePresent;
-    bool mAlwaysPluggedDevice;
     int mBatteryFixedCapacity;
     int mBatteryFixedTemperature;
     struct BatteryProperties props;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 413d11e..be259c2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -514,8 +514,9 @@
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
 
-        // defaultcrypto detects file/block encryption. init flow is same for each.
-        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+        // Although encrypted, vold has already set the device up, so we do not need to
+        // do anything different from the nonencrypted case.
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
         return Success();
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
         if (e4crypt_install_keyring()) {
@@ -523,8 +524,9 @@
         }
         property_set("ro.crypto.type", "file");
 
-        // encrypt detects file/block encryption. init flow is same for each.
-        ActionManager::GetInstance().QueueEventTrigger("encrypt");
+        // Although encrypted, vold has already set the device up, so we do not need to
+        // do anything different from the nonencrypted case.
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
         return Success();
     } else if (code > 0) {
         Error() << "fs_mgr_mount_all() returned unexpected error " << code;
@@ -1030,6 +1032,10 @@
         {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
         {"loglevel",                {1,     1,    {false,  do_loglevel}}},
         {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
+        // TODO: Do mount operations in vendor_init.
+        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
+        // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
+        // mount and umount are run in the same context as mount_all for symmetry.
         {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
         {"mount",                   {3,     kMax, {false,  do_mount}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
diff --git a/init/init.cpp b/init/init.cpp
index 95f272b..bd09e4b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <paths.h>
+#include <pthread.h>
 #include <seccomp_policy.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -110,12 +111,15 @@
         if (!parser.ParseConfig("/system/etc/init")) {
             late_import_paths.emplace_back("/system/etc/init");
         }
-        if (!parser.ParseConfig("/vendor/etc/init")) {
-            late_import_paths.emplace_back("/vendor/etc/init");
+        if (!parser.ParseConfig("/product/etc/init")) {
+            late_import_paths.emplace_back("/product/etc/init");
         }
         if (!parser.ParseConfig("/odm/etc/init")) {
             late_import_paths.emplace_back("/odm/etc/init");
         }
+        if (!parser.ParseConfig("/vendor/etc/init")) {
+            late_import_paths.emplace_back("/vendor/etc/init");
+        }
     } else {
         parser.ParseConfig(bootscript);
     }
@@ -488,6 +492,16 @@
     HandlePowerctlMessage("shutdown,container");
 }
 
+static void UnblockSigterm() {
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGTERM);
+
+    if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+        PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+    }
+}
+
 static void InstallSigtermHandler() {
     sigset_t mask;
     sigemptyset(&mask);
@@ -497,6 +511,12 @@
         PLOG(FATAL) << "failed to block SIGTERM";
     }
 
+    // Register a handler to unblock SIGTERM in the child processes.
+    const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+    if (result != 0) {
+        LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
+    }
+
     sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
     if (sigterm_signal_fd == -1) {
         PLOG(FATAL) << "failed to create signalfd for SIGTERM";
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 6fa07e7..0f4cc68 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -56,6 +56,7 @@
     bool InitDevices();
 
   protected:
+    ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
     bool InitRequiredDevices();
     bool InitVerityDevice(const std::string& verity_device);
     bool MountPartitions();
@@ -209,6 +210,24 @@
     return true;
 }
 
+ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
+    // Matches partition name to create device nodes.
+    // Both required_devices_partition_names_ and uevent->partition_name have A/B
+    // suffix when A/B is used.
+    auto iter = required_devices_partition_names_.find(name);
+    if (iter != required_devices_partition_names_.end()) {
+        LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
+        required_devices_partition_names_.erase(iter);
+        device_handler_.HandleDeviceEvent(uevent);
+        if (required_devices_partition_names_.empty()) {
+            return ListenerAction::kStop;
+        } else {
+            return ListenerAction::kContinue;
+        }
+    }
+    return ListenerAction::kContinue;
+}
+
 ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
     // Ignores everything that is not a block device.
     if (uevent.subsystem != "block") {
@@ -216,19 +235,11 @@
     }
 
     if (!uevent.partition_name.empty()) {
-        // Matches partition name to create device nodes.
-        // Both required_devices_partition_names_ and uevent->partition_name have A/B
-        // suffix when A/B is used.
-        auto iter = required_devices_partition_names_.find(uevent.partition_name);
-        if (iter != required_devices_partition_names_.end()) {
-            LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
-            required_devices_partition_names_.erase(iter);
-            device_handler_.HandleDeviceEvent(uevent);
-            if (required_devices_partition_names_.empty()) {
-                return ListenerAction::kStop;
-            } else {
-                return ListenerAction::kContinue;
-            }
+        return HandleBlockDevice(uevent.partition_name, uevent);
+    } else {
+        size_t base_idx = uevent.path.rfind('/');
+        if (base_idx != std::string::npos) {
+            return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
         }
     }
     // Not found a partition or find an unneeded partition, continue to find others.
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0cb9e63..ecd5baa 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -641,6 +641,7 @@
             load_properties_from_file("/default.prop", NULL);
         }
     }
+    load_properties_from_file("/product/build.prop", NULL);
     load_properties_from_file("/odm/default.prop", NULL);
     load_properties_from_file("/vendor/default.prop", NULL);
 
@@ -761,12 +762,20 @@
         // Don't check for failure here, so we always have a sane list of properties.
         // E.g. In case of recovery, the vendor partition will not have mounted and we
         // still need the system / platform properties to function.
-        LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts", &property_infos);
+        if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
+                                      &property_infos)) {
+            // Fallback to nonplat_* if vendor_* doesn't exist.
+            LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
+                                     &property_infos);
+        }
     } else {
         if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
             return;
         }
-        LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+        if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
+            // Fallback to nonplat_* if vendor_* doesn't exist.
+            LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+        }
     }
 
     auto serialized_contexts = std::string();
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 1febccd..6aba9c1 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -420,14 +420,19 @@
 
     selinux_android_restorecon("/plat_file_contexts", 0);
     selinux_android_restorecon("/nonplat_file_contexts", 0);
+    selinux_android_restorecon("/vendor_file_contexts", 0);
     selinux_android_restorecon("/plat_property_contexts", 0);
     selinux_android_restorecon("/nonplat_property_contexts", 0);
+    selinux_android_restorecon("/vendor_property_contexts", 0);
     selinux_android_restorecon("/plat_seapp_contexts", 0);
     selinux_android_restorecon("/nonplat_seapp_contexts", 0);
+    selinux_android_restorecon("/vendor_seapp_contexts", 0);
     selinux_android_restorecon("/plat_service_contexts", 0);
     selinux_android_restorecon("/nonplat_service_contexts", 0);
+    selinux_android_restorecon("/vendor_service_contexts", 0);
     selinux_android_restorecon("/plat_hwservice_contexts", 0);
     selinux_android_restorecon("/nonplat_hwservice_contexts", 0);
+    selinux_android_restorecon("/vendor_hwservice_contexts", 0);
     selinux_android_restorecon("/sepolicy", 0);
     selinux_android_restorecon("/vndservice_contexts", 0);
 
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 8219838..be35457 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -24,19 +24,27 @@
 namespace init {
 
 static constexpr const char* kPartnerPrefixes[] = {
-    "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
-    "init.svc.odm.",    "ro.odm.",    "persist.odm.",    "odm.",
+    "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.", "init.svc.odm.", "ro.odm.",
+    "persist.odm.",     "odm.",       "ro.boot.",
 };
 
 static const std::set<std::string> kExportedActionableProperties = {
-    "init.svc.zygote",         "persist.bluetooth.btsnoopenable",
-    "persist.sys.crash_rcu",   "persist.sys.zram_enabled",
-    "ro.boot.revision",        "ro.bootmode",
-    "ro.build.type",           "sys.boot_completed",
-    "sys.retaildemo.enabled",  "sys.shutdown.requested",
-    "sys.usb.config",          "sys.usb.configfs",
-    "sys.usb.ffs.mtp.ready",   "sys.usb.ffs.ready",
-    "sys.user.0.ce_available", "sys.vdso",
+    "init.svc.mediadrm",
+    "init.svc.zygote",
+    "persist.bluetooth.btsnoopenable",
+    "persist.sys.crash_rcu",
+    "persist.sys.zram_enabled",
+    "ro.bootmode",
+    "ro.build.type",
+    "sys.boot_completed",
+    "sys.retaildemo.enabled",
+    "sys.shutdown.requested",
+    "sys.usb.config",
+    "sys.usb.configfs",
+    "sys.usb.ffs.mtp.ready",
+    "sys.usb.ffs.ready",
+    "sys.user.0.ce_available",
+    "sys.vdso",
     "vts.native_server.on",
 };
 
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index d9eed76..10a4e46 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -92,13 +92,26 @@
                 "liblog",
                 "libunwind",
                 "libunwindstack",
+                "libdexfile",
             ],
 
             static_libs: ["libcutils"],
+
+            // libdexfile will eventually properly export headers, for now
+            // include these directly.
+            include_dirs: [
+                "art/runtime",
+            ],
+
+            header_libs: [ "jni_headers", ],
         },
         android: {
             static_libs: ["libasync_safe"],
         },
+        vendor: {
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+            exclude_shared_libs: ["libdexfile"],
+        }
     },
     whole_static_libs: ["libdemangle"],
 }
@@ -113,39 +126,8 @@
     cflags: ["-O0"],
     srcs: ["backtrace_testlib.cpp"],
 
-    target: {
-        linux: {
-            shared_libs: [
-                "libunwind",
-                "libunwindstack",
-            ],
-        },
-    }
-}
-
-//-------------------------------------------------------------------------
-// The libbacktrace_offline static library.
-//-------------------------------------------------------------------------
-cc_library_static {
-    name: "libbacktrace_offline",
-    defaults: ["libbacktrace_common"],
-    host_supported: true,
-    srcs: ["BacktraceOffline.cpp"],
-
-    cflags: [
-        "-D__STDC_CONSTANT_MACROS",
-        "-D__STDC_LIMIT_MACROS",
-        "-D__STDC_FORMAT_MACROS",
-    ],
-
-    header_libs: ["llvm-headers"],
-
-    // Use shared libraries so their headers get included during build.
-    shared_libs = [
-        "libbase",
-        "libunwind",
-        "libunwindstack",
-        "libziparchive",
+    shared_libs: [
+      "libunwindstack",
     ],
 }
 
@@ -172,31 +154,15 @@
     shared_libs: [
         "libbacktrace_test",
         "libbacktrace",
+        "libdexfile",
         "libbase",
         "libcutils",
         "liblog",
-        "libunwind",
         "libunwindstack",
     ],
 
     group_static_libs: true,
 
-    // Statically link LLVMlibraries to remove dependency on llvm shared library.
-    static_libs = [
-        "libbacktrace_offline",
-        "libLLVMObject",
-        "libLLVMBitReader",
-        "libLLVMMC",
-        "libLLVMMCParser",
-        "libLLVMCore",
-        "libLLVMSupport",
-
-        "libziparchive",
-        "libz",
-    ],
-
-    header_libs: ["llvm-headers"],
-
     target: {
         android: {
             cflags: ["-DENABLE_PSS_TESTS"],
@@ -205,13 +171,16 @@
             ],
         },
         linux_glibc: {
-            host_ldlibs: [
-                "-lncurses",
-            ],
             static_libs: ["libutils"],
         },
     },
 
+    // libdexfile will eventually properly export headers, for now
+    // include these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+
     data: [
         "testdata/arm/*",
         "testdata/arm64/*",
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 1195e5f..dec241c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -168,5 +168,9 @@
       return "Failed to find a function in debug sections";
     case BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED:
       return "Failed to execute dwarf instructions in debug sections";
+    case BACKTRACE_UNWIND_ERROR_UNWIND_INFO:
+      return "Failed to unwind due to invalid unwind information";
+    case BACKTRACE_UNWIND_ERROR_REPEATED_FRAME:
+      return "Failed to unwind due to same sp/pc repeating";
   }
 }
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index d61b281..f6f4423 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -64,7 +64,7 @@
   return bytes;
 }
 
-bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+bool BacktraceCurrent::Unwind(size_t num_ignore_frames, void* ucontext) {
   if (GetMap() == nullptr) {
     // Without a map object, we can't do anything.
     error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
index 60a9117..48c14ea 100644
--- a/libbacktrace/BacktraceCurrent.h
+++ b/libbacktrace/BacktraceCurrent.h
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#include <ucontext.h>
 
 #include <backtrace/Backtrace.h>
 
@@ -44,7 +43,7 @@
 
   bool ReadWord(uint64_t ptr, word_t* out_value) override;
 
-  bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
+  bool Unwind(size_t num_ignore_frames, void* ucontext) override;
 
  protected:
   bool DiscardFrame(const backtrace_frame_data_t& frame);
@@ -52,7 +51,7 @@
  private:
   bool UnwindThread(size_t num_ignore_frames);
 
-  virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
+  virtual bool UnwindFromContext(size_t num_ignore_frames, void* ucontext) = 0;
 };
 
 #endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 2a657b8..c8a500c 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -146,13 +146,3 @@
   return map;
 }
 #endif
-
-BacktraceMap* BacktraceMap::Create(pid_t pid, const std::vector<backtrace_map_t>& maps) {
-    BacktraceMap* backtrace_map = new BacktraceMap(pid);
-    backtrace_map->maps_.insert(backtrace_map->maps_.begin(), maps.begin(), maps.end());
-    std::sort(backtrace_map->maps_.begin(), backtrace_map->maps_.end(),
-            [](const backtrace_map_t& map1, const backtrace_map_t& map2) {
-              return map1.start < map2.start;
-            });
-    return backtrace_map;
-}
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
deleted file mode 100644
index a056716..0000000
--- a/libbacktrace/BacktraceOffline.cpp
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*
- * Copyright (C) 2015 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 "BacktraceOffline.h"
-
-extern "C" {
-#define UNW_REMOTE_ONLY
-#include <dwarf.h>
-}
-
-#include <pthread.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-#include <ziparchive/zip_archive.h>
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
-#include <llvm/ADT/StringRef.h>
-#include <llvm/Object/Binary.h>
-#include <llvm/Object/ELFObjectFile.h>
-#include <llvm/Object/ObjectFile.h>
-
-#pragma clang diagnostic pop
-
-#include "BacktraceLog.h"
-
-struct EhFrame {
-  uint64_t hdr_vaddr;
-  uint64_t vaddr;
-  uint64_t fde_table_offset;
-  uint64_t min_func_vaddr;
-  std::vector<uint8_t> hdr_data;
-  std::vector<uint8_t> data;
-};
-
-struct ArmIdxEntry {
-  uint32_t func_offset;
-  uint32_t value;
-};
-
-struct ArmExidx {
-  uint64_t exidx_vaddr;
-  uint64_t extab_vaddr;
-  std::vector<ArmIdxEntry> exidx_data;
-  std::vector<uint8_t> extab_data;
-  // There is a one-to-one map from exidx_data.func_offset to func_vaddr_array.
-  std::vector<uint32_t> func_vaddr_array;
-};
-
-struct DebugFrameInfo {
-  bool has_arm_exidx;
-  bool has_eh_frame;
-  bool has_debug_frame;
-  bool has_gnu_debugdata;
-
-  EhFrame eh_frame;
-  ArmExidx arm_exidx;
-
-  uint64_t min_vaddr;
-  uint64_t text_end_vaddr;
-
-  DebugFrameInfo() : has_arm_exidx(false), has_eh_frame(false),
-      has_debug_frame(false), has_gnu_debugdata(false) { }
-};
-
-void Space::Clear() {
-  start = 0;
-  end = 0;
-  data = nullptr;
-}
-
-size_t Space::Read(uint64_t addr, uint8_t* buffer, size_t size) {
-  if (addr >= start && addr < end) {
-    size_t read_size = std::min(size, static_cast<size_t>(end - addr));
-    memcpy(buffer, data + (addr - start), read_size);
-    return read_size;
-  }
-  return 0;
-}
-
-static int FindProcInfo(unw_addr_space_t addr_space, unw_word_t ip, unw_proc_info* proc_info,
-                        int need_unwind_info, void* arg) {
-  BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
-  bool result = backtrace->FindProcInfo(addr_space, ip, proc_info, need_unwind_info);
-  return result ? 0 : -UNW_EINVAL;
-}
-
-static void PutUnwindInfo(unw_addr_space_t, unw_proc_info_t*, void*) {
-}
-
-static int GetDynInfoListAddr(unw_addr_space_t, unw_word_t*, void*) {
-  return -UNW_ENOINFO;
-}
-
-static int AccessMem(unw_addr_space_t, unw_word_t addr, unw_word_t* value, int write, void* arg) {
-  if (write == 1) {
-    return -UNW_EINVAL;
-  }
-  BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
-  *value = 0;
-  size_t read_size = backtrace->Read(addr, reinterpret_cast<uint8_t*>(value), sizeof(unw_word_t));
-  // Strictly we should check if read_size matches sizeof(unw_word_t), but it is possible in
-  // .eh_frame_hdr that the section can end at a position not aligned in sizeof(unw_word_t), and
-  // we should permit the read at the end of the section.
-  return (read_size > 0u ? 0 : -UNW_EINVAL);
-}
-
-static int AccessReg(unw_addr_space_t, unw_regnum_t unwind_reg, unw_word_t* value, int write,
-                     void* arg) {
-  if (write == 1) {
-    return -UNW_EINVAL;
-  }
-  BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
-  uint64_t reg_value;
-  bool result = backtrace->ReadReg(unwind_reg, &reg_value);
-  if (result) {
-    *value = static_cast<unw_word_t>(reg_value);
-  }
-  return result ? 0 : -UNW_EINVAL;
-}
-
-static int AccessFpReg(unw_addr_space_t, unw_regnum_t, unw_fpreg_t*, int, void*) {
-  return -UNW_EINVAL;
-}
-
-static int Resume(unw_addr_space_t, unw_cursor_t*, void*) {
-  return -UNW_EINVAL;
-}
-
-static int GetProcName(unw_addr_space_t, unw_word_t, char*, size_t, unw_word_t*, void*) {
-  return -UNW_EINVAL;
-}
-
-static unw_accessors_t accessors = {
-    .find_proc_info = FindProcInfo,
-    .put_unwind_info = PutUnwindInfo,
-    .get_dyn_info_list_addr = GetDynInfoListAddr,
-    .access_mem = AccessMem,
-    .access_reg = AccessReg,
-    .access_fpreg = AccessFpReg,
-    .resume = Resume,
-    .get_proc_name = GetProcName,
-};
-
-bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
-  if (context == nullptr) {
-    BACK_LOGW("The context is needed for offline backtracing.");
-    error_.error_code = BACKTRACE_UNWIND_ERROR_NO_CONTEXT;
-    return false;
-  }
-  context_ = context;
-  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-
-  unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
-  unw_cursor_t cursor;
-  int ret = unw_init_remote(&cursor, addr_space, this);
-  if (ret != 0) {
-    BACK_LOGW("unw_init_remote failed %d", ret);
-    unw_destroy_addr_space(addr_space);
-    error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-    return false;
-  }
-  size_t num_frames = 0;
-  while (true) {
-    unw_word_t pc;
-    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
-    if (ret < 0) {
-      BACK_LOGW("Failed to read IP %d", ret);
-      error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
-      error_.error_info.regno = UNW_REG_IP;
-      break;
-    }
-    unw_word_t sp;
-    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
-    if (ret < 0) {
-      BACK_LOGW("Failed to read SP %d", ret);
-      error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
-      error_.error_info.regno = UNW_REG_SP;
-      break;
-    }
-
-    if (num_ignore_frames == 0) {
-      backtrace_map_t map;
-      FillInMap(pc, &map);
-      if (map.start == 0 || (map.flags & PROT_EXEC) == 0) {
-        // .eh_frame and .ARM.exidx doesn't know how to unwind from instructions setting up or
-        // destroying stack frames. It can lead to wrong callchains, which may contain pcs outside
-        // executable mapping areas. Stop unwinding once this is detected.
-        error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
-        break;
-      }
-      frames_.resize(num_frames + 1);
-      backtrace_frame_data_t* frame = &frames_[num_frames];
-      frame->num = num_frames;
-      frame->pc = static_cast<uint64_t>(pc);
-      frame->sp = static_cast<uint64_t>(sp);
-      frame->stack_size = 0;
-
-      if (num_frames > 0) {
-        backtrace_frame_data_t* prev = &frames_[num_frames - 1];
-        prev->stack_size = frame->sp - prev->sp;
-      }
-      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
-      frame->map = map;
-      num_frames++;
-    } else {
-      num_ignore_frames--;
-    }
-    is_debug_frame_used_ = false;
-    ret = unw_step(&cursor);
-    if (ret <= 0) {
-      if (error_.error_code == BACKTRACE_UNWIND_NO_ERROR) {
-        error_.error_code = BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED;
-      }
-      break;
-    }
-    if (num_frames == MAX_BACKTRACE_FRAMES) {
-      error_.error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT;
-      break;
-    }
-  }
-  unw_destroy_addr_space(addr_space);
-  context_ = nullptr;
-  return true;
-}
-
-bool BacktraceOffline::ReadWord(uint64_t ptr, word_t* out_value) {
-  size_t bytes_read = Read(ptr, reinterpret_cast<uint8_t*>(out_value), sizeof(word_t));
-  return bytes_read == sizeof(word_t);
-}
-
-size_t BacktraceOffline::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
-  // Normally, libunwind needs stack information and call frame information to do remote unwinding.
-  // If call frame information is stored in .debug_frame, libunwind can read it from file
-  // by itself. If call frame information is stored in .eh_frame, we need to provide data in
-  // .eh_frame/.eh_frame_hdr sections.
-  // The order of readings below doesn't matter, as the spaces don't overlap with each other.
-  size_t read_size = eh_frame_hdr_space_.Read(addr, buffer, bytes);
-  if (read_size != 0) {
-    return read_size;
-  }
-  read_size = eh_frame_space_.Read(addr, buffer, bytes);
-  if (read_size != 0) {
-    return read_size;
-  }
-  read_size = arm_exidx_space_.Read(addr, buffer, bytes);
-  if (read_size != 0) {
-    return read_size;
-  }
-  read_size = arm_extab_space_.Read(addr, buffer, bytes);
-  if (read_size != 0) {
-    return read_size;
-  }
-  read_size = stack_space_.Read(addr, buffer, bytes);
-  if (read_size != 0) {
-    return read_size;
-  }
-  // In some libraries (like /system/lib64/libskia.so), some CIE entries in .eh_frame use
-  // augmentation "P", which makes libunwind/libunwindstack try to read personality routine in
-  // memory. However, that is not available in offline unwinding. Work around this by returning
-  // all zero data.
-  error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED;
-  error_.error_info.addr = addr;
-  memset(buffer, 0, bytes);
-  return bytes;
-}
-
-bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip,
-                                    unw_proc_info_t* proc_info, int need_unwind_info) {
-  backtrace_map_t map;
-  FillInMap(ip, &map);
-  if (!BacktraceMap::IsValid(map)) {
-    error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
-    return false;
-  }
-  const std::string& filename = map.name;
-  DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename);
-  if (debug_frame == nullptr) {
-    error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
-    return false;
-  }
-  // Each FindProcInfo() is a new attempt to unwind, so reset the reason.
-  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-
-  eh_frame_hdr_space_.Clear();
-  eh_frame_space_.Clear();
-  arm_exidx_space_.Clear();
-  arm_extab_space_.Clear();
-
-  // vaddr in the elf file.
-  uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
-
-  // The unwind info can come from .ARM.exidx or .eh_frame, or .debug_frame/.gnu_debugdata.
-  // First check .eh_frame/.debug_frame, then check .ARM.exidx. Because .eh_frame/.debug_frame has
-  // function range for each entry, by matching ip address with the function range, we know exactly
-  // whether the ip address hits an entry. But .ARM.exidx doesn't have function range for each
-  // entry, it thinks that an ip address hits an entry when (entry.addr <= ip < next_entry.addr).
-  // To prevent ip addresses hit in .eh_frame/.debug_frame being regarded as addresses hit in
-  // .ARM.exidx, we need to check .eh_frame/.debug_frame first.
-
-  // Check .debug_frame/.gnu_debugdata before .eh_frame, because .debug_frame can unwind from
-  // instructions setting up or destroying stack frames, while .eh_frame can't.
-  if (!is_debug_frame_used_ && (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata)) {
-    is_debug_frame_used_ = true;
-    unw_dyn_info_t di;
-    unw_word_t segbase = map.start - debug_frame->min_vaddr;
-    // TODO: http://b/32916571
-    // TODO: Do it ourselves is more efficient than calling libunwind functions.
-    int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end);
-    if (found == 1) {
-      int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
-      if (ret == 0) {
-        return true;
-      }
-    }
-  }
-  if (debug_frame->has_eh_frame) {
-    if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
-        ip_vaddr < debug_frame->text_end_vaddr) {
-      // Prepare eh_frame_hdr space and eh_frame space.
-      eh_frame_hdr_space_.start = ip - ip_vaddr + debug_frame->eh_frame.hdr_vaddr;
-      eh_frame_hdr_space_.end =
-          eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
-      eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
-      eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
-      eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
-      eh_frame_space_.data = debug_frame->eh_frame.data.data();
-
-      unw_dyn_info di;
-      memset(&di, '\0', sizeof(di));
-      di.start_ip = map.start;
-      di.end_ip = map.end;
-      di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
-      di.u.rti.name_ptr = 0;
-      di.u.rti.segbase = eh_frame_hdr_space_.start;
-      di.u.rti.table_data =
-          eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset;
-      di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t);
-      // TODO: Do it ourselves is more efficient than calling this function.
-      int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
-      if (ret == 0) {
-        return true;
-      }
-    }
-  }
-
-  if (debug_frame->has_arm_exidx) {
-    auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
-    if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
-      // Use binary search to find the correct function.
-      auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
-                                 static_cast<uint32_t>(ip_vaddr));
-      if (it != func_vaddrs.begin()) {
-        --it;
-        // Found the exidx entry.
-        size_t index = it - func_vaddrs.begin();
-        proc_info->start_ip = *it;
-        proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
-        proc_info->unwind_info = reinterpret_cast<void*>(
-            static_cast<uint64_t>(index * sizeof(ArmIdxEntry) + debug_frame->arm_exidx.exidx_vaddr +
-                                  debug_frame->min_vaddr));
-        eh_frame_hdr_space_.Clear();
-        eh_frame_space_.Clear();
-        // Prepare arm_exidx space and arm_extab space.
-        arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
-        arm_exidx_space_.end = arm_exidx_space_.start +
-            debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
-        arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
-            debug_frame->arm_exidx.exidx_data.data());
-
-        arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
-        arm_extab_space_.end = arm_extab_space_.start +
-            debug_frame->arm_exidx.extab_data.size();
-        arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
-        return true;
-      }
-    }
-  }
-  error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
-  return false;
-}
-
-bool BacktraceOffline::ReadReg(size_t reg, uint64_t* value) {
-  bool result = true;
-#if defined(__arm__)
-  switch (reg) {
-    case UNW_ARM_R0:
-      *value = context_->uc_mcontext.arm_r0;
-      break;
-    case UNW_ARM_R1:
-      *value = context_->uc_mcontext.arm_r1;
-      break;
-    case UNW_ARM_R2:
-      *value = context_->uc_mcontext.arm_r2;
-      break;
-    case UNW_ARM_R3:
-      *value = context_->uc_mcontext.arm_r3;
-      break;
-    case UNW_ARM_R4:
-      *value = context_->uc_mcontext.arm_r4;
-      break;
-    case UNW_ARM_R5:
-      *value = context_->uc_mcontext.arm_r5;
-      break;
-    case UNW_ARM_R6:
-      *value = context_->uc_mcontext.arm_r6;
-      break;
-    case UNW_ARM_R7:
-      *value = context_->uc_mcontext.arm_r7;
-      break;
-    case UNW_ARM_R8:
-      *value = context_->uc_mcontext.arm_r8;
-      break;
-    case UNW_ARM_R9:
-      *value = context_->uc_mcontext.arm_r9;
-      break;
-    case UNW_ARM_R10:
-      *value = context_->uc_mcontext.arm_r10;
-      break;
-    case UNW_ARM_R11:
-      *value = context_->uc_mcontext.arm_fp;
-      break;
-    case UNW_ARM_R12:
-      *value = context_->uc_mcontext.arm_ip;
-      break;
-    case UNW_ARM_R13:
-      *value = context_->uc_mcontext.arm_sp;
-      break;
-    case UNW_ARM_R14:
-      *value = context_->uc_mcontext.arm_lr;
-      break;
-    case UNW_ARM_R15:
-      *value = context_->uc_mcontext.arm_pc;
-      break;
-    default:
-      result = false;
-  }
-#elif defined(__aarch64__)
-  if (reg <= UNW_AARCH64_PC) {
-    *value = context_->uc_mcontext.regs[reg];
-  } else {
-    result = false;
-  }
-#elif defined(__x86_64__)
-  switch (reg) {
-    case UNW_X86_64_R8:
-      *value = context_->uc_mcontext.gregs[REG_R8];
-      break;
-    case UNW_X86_64_R9:
-      *value = context_->uc_mcontext.gregs[REG_R9];
-      break;
-    case UNW_X86_64_R10:
-      *value = context_->uc_mcontext.gregs[REG_R10];
-      break;
-    case UNW_X86_64_R11:
-      *value = context_->uc_mcontext.gregs[REG_R11];
-      break;
-    case UNW_X86_64_R12:
-      *value = context_->uc_mcontext.gregs[REG_R12];
-      break;
-    case UNW_X86_64_R13:
-      *value = context_->uc_mcontext.gregs[REG_R13];
-      break;
-    case UNW_X86_64_R14:
-      *value = context_->uc_mcontext.gregs[REG_R14];
-      break;
-    case UNW_X86_64_R15:
-      *value = context_->uc_mcontext.gregs[REG_R15];
-      break;
-    case UNW_X86_64_RDI:
-      *value = context_->uc_mcontext.gregs[REG_RDI];
-      break;
-    case UNW_X86_64_RSI:
-      *value = context_->uc_mcontext.gregs[REG_RSI];
-      break;
-    case UNW_X86_64_RBP:
-      *value = context_->uc_mcontext.gregs[REG_RBP];
-      break;
-    case UNW_X86_64_RBX:
-      *value = context_->uc_mcontext.gregs[REG_RBX];
-      break;
-    case UNW_X86_64_RDX:
-      *value = context_->uc_mcontext.gregs[REG_RDX];
-      break;
-    case UNW_X86_64_RAX:
-      *value = context_->uc_mcontext.gregs[REG_RAX];
-      break;
-    case UNW_X86_64_RCX:
-      *value = context_->uc_mcontext.gregs[REG_RCX];
-      break;
-    case UNW_X86_64_RSP:
-      *value = context_->uc_mcontext.gregs[REG_RSP];
-      break;
-    case UNW_X86_64_RIP:
-      *value = context_->uc_mcontext.gregs[REG_RIP];
-      break;
-    default:
-      result = false;
-  }
-#elif defined(__i386__)
-  switch (reg) {
-    case UNW_X86_GS:
-      *value = context_->uc_mcontext.gregs[REG_GS];
-      break;
-    case UNW_X86_FS:
-      *value = context_->uc_mcontext.gregs[REG_FS];
-      break;
-    case UNW_X86_ES:
-      *value = context_->uc_mcontext.gregs[REG_ES];
-      break;
-    case UNW_X86_DS:
-      *value = context_->uc_mcontext.gregs[REG_DS];
-      break;
-    case UNW_X86_EAX:
-      *value = context_->uc_mcontext.gregs[REG_EAX];
-      break;
-    case UNW_X86_EBX:
-      *value = context_->uc_mcontext.gregs[REG_EBX];
-      break;
-    case UNW_X86_ECX:
-      *value = context_->uc_mcontext.gregs[REG_ECX];
-      break;
-    case UNW_X86_EDX:
-      *value = context_->uc_mcontext.gregs[REG_EDX];
-      break;
-    case UNW_X86_ESI:
-      *value = context_->uc_mcontext.gregs[REG_ESI];
-      break;
-    case UNW_X86_EDI:
-      *value = context_->uc_mcontext.gregs[REG_EDI];
-      break;
-    case UNW_X86_EBP:
-      *value = context_->uc_mcontext.gregs[REG_EBP];
-      break;
-    case UNW_X86_EIP:
-      *value = context_->uc_mcontext.gregs[REG_EIP];
-      break;
-    case UNW_X86_ESP:
-      *value = context_->uc_mcontext.gregs[REG_ESP];
-      break;
-    case UNW_X86_TRAPNO:
-      *value = context_->uc_mcontext.gregs[REG_TRAPNO];
-      break;
-    case UNW_X86_CS:
-      *value = context_->uc_mcontext.gregs[REG_CS];
-      break;
-    case UNW_X86_EFLAGS:
-      *value = context_->uc_mcontext.gregs[REG_EFL];
-      break;
-    case UNW_X86_SS:
-      *value = context_->uc_mcontext.gregs[REG_SS];
-      break;
-    default:
-      result = false;
-  }
-#else
-  UNUSED(reg);
-  UNUSED(value);
-  result = false;
-#endif
-  if (!result) {
-    error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
-    error_.error_info.regno = reg;
-  }
-  return result;
-}
-
-std::string BacktraceOffline::GetFunctionNameRaw(uint64_t, uint64_t* offset) {
-  // We don't have enough information to support this. And it is expensive.
-  *offset = 0;
-  return "";
-}
-
-static std::mutex g_lock;
-static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>* g_debug_frames = nullptr;
-
-static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
-
-DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
-  if (cache_file_) {
-    std::lock_guard<std::mutex> lock(g_lock);
-    if (g_debug_frames != nullptr) {
-      auto it = g_debug_frames->find(filename);
-      if (it != g_debug_frames->end()) {
-        return it->second.get();
-      }
-    }
-  }
-  DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
-  if (cache_file_) {
-    std::lock_guard<std::mutex> lock(g_lock);
-    if (g_debug_frames == nullptr) {
-      g_debug_frames = new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
-    }
-    auto pair = g_debug_frames->emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
-    if (!pair.second) {
-      debug_frame = pair.first->second.get();
-    }
-  }
-  return debug_frame;
-}
-
-static bool OmitEncodedValue(uint8_t encode, const uint8_t*& p, bool is_elf64) {
-  if (encode == DW_EH_PE_omit) {
-    return 0;
-  }
-  uint8_t format = encode & 0x0f;
-  switch (format) {
-    case DW_EH_PE_ptr:
-      p += is_elf64 ? 8 : 4;
-      break;
-    case DW_EH_PE_uleb128:
-    case DW_EH_PE_sleb128:
-      while ((*p & 0x80) != 0) {
-        ++p;
-      }
-      ++p;
-      break;
-    case DW_EH_PE_udata2:
-    case DW_EH_PE_sdata2:
-      p += 2;
-      break;
-    case DW_EH_PE_udata4:
-    case DW_EH_PE_sdata4:
-      p += 4;
-      break;
-    case DW_EH_PE_udata8:
-    case DW_EH_PE_sdata8:
-      p += 8;
-      break;
-    default:
-      return false;
-  }
-  return true;
-}
-
-static bool GetFdeTableOffsetInEhFrameHdr(const std::vector<uint8_t>& data,
-                                          uint64_t* table_offset_in_eh_frame_hdr, bool is_elf64) {
-  const uint8_t* p = data.data();
-  const uint8_t* end = p + data.size();
-  if (p + 4 > end) {
-    return false;
-  }
-  uint8_t version = *p++;
-  if (version != 1) {
-    return false;
-  }
-  uint8_t eh_frame_ptr_encode = *p++;
-  uint8_t fde_count_encode = *p++;
-  uint8_t fde_table_encode = *p++;
-
-  if (fde_table_encode != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
-    return false;
-  }
-
-  if (!OmitEncodedValue(eh_frame_ptr_encode, p, is_elf64) ||
-      !OmitEncodedValue(fde_count_encode, p, is_elf64)) {
-    return false;
-  }
-  if (p >= end) {
-    return false;
-  }
-  *table_offset_in_eh_frame_hdr = p - data.data();
-  return true;
-}
-
-static uint64_t ReadFromBuffer(const uint8_t*& p, size_t size) {
-  uint64_t result = 0;
-  int shift = 0;
-  while (size-- > 0) {
-    uint64_t tmp = *p++;
-    result |= tmp << shift;
-    shift += 8;
-  }
-  return result;
-}
-
-static uint64_t ReadSignValueFromBuffer(const uint8_t*& p, size_t size) {
-  uint64_t result = 0;
-  int shift = 0;
-  for (size_t i = 0; i < size; ++i) {
-    uint64_t tmp = *p++;
-    result |= tmp << shift;
-    shift += 8;
-  }
-  if (*(p - 1) & 0x80) {
-    result |= (-1ULL) << (size * 8);
-  }
-  return result;
-}
-
-static const char* ReadStrFromBuffer(const uint8_t*& p) {
-  const char* result = reinterpret_cast<const char*>(p);
-  p += strlen(result) + 1;
-  return result;
-}
-
-static int64_t ReadLEB128FromBuffer(const uint8_t*& p) {
-  int64_t result = 0;
-  int64_t tmp;
-  int shift = 0;
-  while (*p & 0x80) {
-    tmp = *p & 0x7f;
-    result |= tmp << shift;
-    shift += 7;
-    p++;
-  }
-  tmp = *p;
-  result |= tmp << shift;
-  if (*p & 0x40) {
-    result |= -((tmp & 0x40) << shift);
-  }
-  p++;
-  return result;
-}
-
-static uint64_t ReadULEB128FromBuffer(const uint8_t*& p) {
-  uint64_t result = 0;
-  uint64_t tmp;
-  int shift = 0;
-  while (*p & 0x80) {
-    tmp = *p & 0x7f;
-    result |= tmp << shift;
-    shift += 7;
-    p++;
-  }
-  tmp = *p;
-  result |= tmp << shift;
-  p++;
-  return result;
-}
-
-static uint64_t ReadEhEncoding(const uint8_t*& p, uint8_t encoding, bool is_elf64,
-                               uint64_t section_vaddr, const uint8_t* section_begin) {
-  const uint8_t* init_addr = p;
-  uint64_t result = 0;
-  switch (encoding & 0x0f) {
-    case DW_EH_PE_absptr:
-      result = ReadFromBuffer(p, is_elf64 ? 8 : 4);
-      break;
-    case DW_EH_PE_omit:
-      result = 0;
-      break;
-    case DW_EH_PE_uleb128:
-      result = ReadULEB128FromBuffer(p);
-      break;
-    case DW_EH_PE_udata2:
-      result = ReadFromBuffer(p, 2);
-      break;
-    case DW_EH_PE_udata4:
-      result = ReadFromBuffer(p, 4);
-      break;
-    case DW_EH_PE_udata8:
-      result = ReadFromBuffer(p, 8);
-      break;
-    case DW_EH_PE_sleb128:
-      result = ReadLEB128FromBuffer(p);
-      break;
-    case DW_EH_PE_sdata2:
-      result = ReadSignValueFromBuffer(p, 2);
-      break;
-    case DW_EH_PE_sdata4:
-      result = ReadSignValueFromBuffer(p, 4);
-      break;
-    case DW_EH_PE_sdata8:
-      result = ReadSignValueFromBuffer(p, 8);
-      break;
-  }
-  switch (encoding & 0xf0) {
-    case DW_EH_PE_pcrel:
-      result += init_addr - section_begin + section_vaddr;
-      break;
-    case DW_EH_PE_datarel:
-      result += section_vaddr;
-      break;
-  }
-  return result;
-}
-
-static bool BuildEhFrameHdr(DebugFrameInfo* info, bool is_elf64) {
-  // For each fde entry, collect its (func_vaddr, fde_vaddr) pair.
-  std::vector<std::pair<uint64_t, uint64_t>> index_table;
-  // Map form cie_offset to fde encoding.
-  std::unordered_map<size_t, uint8_t> cie_map;
-  const uint8_t* eh_frame_begin = info->eh_frame.data.data();
-  const uint8_t* eh_frame_end = eh_frame_begin + info->eh_frame.data.size();
-  const uint8_t* p = eh_frame_begin;
-  uint64_t eh_frame_vaddr = info->eh_frame.vaddr;
-  while (p < eh_frame_end) {
-    const uint8_t* unit_begin = p;
-    uint64_t unit_len = ReadFromBuffer(p, 4);
-    size_t secbytes = 4;
-    if (unit_len == 0xffffffff) {
-      unit_len = ReadFromBuffer(p, 8);
-      secbytes = 8;
-    }
-    const uint8_t* unit_end = p + unit_len;
-    uint64_t cie_id = ReadFromBuffer(p, secbytes);
-    if (cie_id == 0) {
-      // This is a CIE.
-      // Read version
-      uint8_t version = *p++;
-      // Read augmentation
-      const char* augmentation = ReadStrFromBuffer(p);
-      if (version >= 4) {
-        // Read address size and segment size
-        p += 2;
-      }
-      // Read code alignment factor
-      ReadULEB128FromBuffer(p);
-      // Read data alignment factor
-      ReadLEB128FromBuffer(p);
-      // Read return address register
-      if (version == 1) {
-        p++;
-      } else {
-        ReadULEB128FromBuffer(p);
-      }
-      uint8_t fde_pointer_encoding = 0;
-      if (augmentation[0] == 'z') {
-        // Read augmentation length.
-        ReadULEB128FromBuffer(p);
-        for (int i = 1; augmentation[i] != '\0'; ++i) {
-          char c = augmentation[i];
-          if (c == 'R') {
-            fde_pointer_encoding = *p++;
-          } else if (c == 'P') {
-            // Read personality handler
-            uint8_t encoding = *p++;
-            OmitEncodedValue(encoding, p, is_elf64);
-          } else if (c == 'L') {
-            // Read lsda encoding
-            p++;
-          }
-        }
-      }
-      cie_map[unit_begin - eh_frame_begin] = fde_pointer_encoding;
-    } else {
-      // This is an FDE.
-      size_t cie_offset = p - secbytes - eh_frame_begin - cie_id;
-      auto it = cie_map.find(cie_offset);
-      if (it != cie_map.end()) {
-        uint8_t fde_pointer_encoding = it->second;
-        uint64_t initial_location =
-            ReadEhEncoding(p, fde_pointer_encoding, is_elf64, eh_frame_vaddr, eh_frame_begin);
-        uint64_t fde_vaddr = unit_begin - eh_frame_begin + eh_frame_vaddr;
-        index_table.push_back(std::make_pair(initial_location, fde_vaddr));
-      }
-    }
-    p = unit_end;
-  }
-  if (index_table.empty()) {
-    return false;
-  }
-  std::sort(index_table.begin(), index_table.end());
-  info->eh_frame.hdr_vaddr = 0;
-  info->eh_frame.hdr_data.resize(index_table.size() * 8);
-  uint32_t* ptr = reinterpret_cast<uint32_t*>(info->eh_frame.hdr_data.data());
-  for (auto& pair : index_table) {
-    *ptr++ = static_cast<uint32_t>(pair.first - info->eh_frame.hdr_vaddr);
-    *ptr++ = static_cast<uint32_t>(pair.second - info->eh_frame.hdr_vaddr);
-  }
-  info->eh_frame.fde_table_offset = 0;
-  info->eh_frame.min_func_vaddr = index_table[0].first;
-  return true;
-}
-
-template <class ELFT>
-DebugFrameInfo* ReadDebugFrameFromELFFile(const llvm::object::ELFFile<ELFT>* elf) {
-  DebugFrameInfo* result = new DebugFrameInfo;
-  result->eh_frame.hdr_vaddr = 0;
-  result->text_end_vaddr = std::numeric_limits<uint64_t>::max();
-
-  bool is_elf64 = (elf->getHeader()->getFileClass() == llvm::ELF::ELFCLASS64);
-  bool has_eh_frame_hdr = false;
-  bool has_eh_frame = false;
-
-  for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
-    llvm::ErrorOr<llvm::StringRef> name = elf->getSectionName(&*it);
-    if (name) {
-      std::string s = name.get();
-      if (s == ".debug_frame") {
-        result->has_debug_frame = true;
-      } else if (s == ".gnu_debugdata") {
-        result->has_gnu_debugdata = true;
-      } else if (s == ".eh_frame_hdr") {
-        result->eh_frame.hdr_vaddr = it->sh_addr;
-        llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
-        if (data) {
-          result->eh_frame.hdr_data.insert(result->eh_frame.hdr_data.end(),
-              data->data(), data->data() + data->size());
-
-          uint64_t fde_table_offset;
-          if (GetFdeTableOffsetInEhFrameHdr(result->eh_frame.hdr_data, &fde_table_offset, is_elf64)) {
-            result->eh_frame.fde_table_offset = fde_table_offset;
-            // Make sure we have at least one entry in fde_table.
-            if (fde_table_offset + 2 * sizeof(int32_t) <= data->size()) {
-              intptr_t eh_frame_hdr_vaddr = it->sh_addr;
-              int32_t sdata;
-              uint8_t* p = result->eh_frame.hdr_data.data() + fde_table_offset;
-              memcpy(&sdata, p, sizeof(sdata));
-              result->eh_frame.min_func_vaddr = eh_frame_hdr_vaddr + sdata;
-              has_eh_frame_hdr = true;
-            }
-          }
-        }
-      } else if (s == ".eh_frame") {
-        result->eh_frame.vaddr = it->sh_addr;
-        llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
-        if (data) {
-          result->eh_frame.data.insert(result->eh_frame.data.end(),
-                                                data->data(), data->data() + data->size());
-          has_eh_frame = true;
-        }
-      } else if (s == ".ARM.exidx") {
-        result->arm_exidx.exidx_vaddr = it->sh_addr;
-        llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
-        if (data) {
-          size_t entry_count = data->size() / sizeof(ArmIdxEntry);
-          result->arm_exidx.exidx_data.resize(entry_count);
-          memcpy(result->arm_exidx.exidx_data.data(), data->data(),
-                 entry_count * sizeof(ArmIdxEntry));
-          if (entry_count > 0u) {
-            // Change IdxEntry.func_offset into vaddr.
-            result->arm_exidx.func_vaddr_array.reserve(entry_count);
-            uint32_t vaddr = it->sh_addr;
-            for (auto& entry : result->arm_exidx.exidx_data) {
-              uint32_t func_offset = entry.func_offset + vaddr;
-              // Clear bit 31 for the prel31 offset.
-              // Arm sets bit 0 to mark it as thumb code, remove the flag.
-              result->arm_exidx.func_vaddr_array.push_back(
-                  func_offset & 0x7ffffffe);
-              vaddr += 8;
-            }
-            result->has_arm_exidx = true;
-          }
-        }
-      } else if (s == ".ARM.extab") {
-        result->arm_exidx.extab_vaddr = it->sh_addr;
-        llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
-        if (data) {
-          result->arm_exidx.extab_data.insert(result->arm_exidx.extab_data.end(),
-                                              data->data(), data->data() + data->size());
-        }
-      } else if (s == ".text") {
-        result->text_end_vaddr = it->sh_addr + it->sh_size;
-      }
-    }
-  }
-
-  if (has_eh_frame) {
-    if (!has_eh_frame_hdr) {
-      // Some libraries (like /vendor/lib64/egl/eglSubDriverAndroid.so) contain empty
-      // .eh_frame_hdr.
-      if (BuildEhFrameHdr(result, is_elf64)) {
-        has_eh_frame_hdr = true;
-      }
-    }
-    if (has_eh_frame_hdr) {
-      result->has_eh_frame = true;
-    }
-  }
-  if (has_eh_frame_hdr && has_eh_frame) {
-    result->has_eh_frame = true;
-  }
-
-  result->min_vaddr = std::numeric_limits<uint64_t>::max();
-  for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
-    if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
-      if (it->p_vaddr < result->min_vaddr) {
-        result->min_vaddr = it->p_vaddr;
-      }
-    }
-  }
-  if (!result->has_eh_frame && !result->has_arm_exidx && !result->has_debug_frame &&
-      !result->has_gnu_debugdata) {
-    delete result;
-    return nullptr;
-  }
-  return result;
-}
-
-static bool IsValidElfPath(const std::string& filename) {
-  static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
-
-  struct stat st;
-  if (stat(filename.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
-    return false;
-  }
-  FILE* fp = fopen(filename.c_str(), "reb");
-  if (fp == nullptr) {
-    return false;
-  }
-  char buf[4];
-  if (fread(buf, 4, 1, fp) != 1) {
-    fclose(fp);
-    return false;
-  }
-  fclose(fp);
-  return memcmp(buf, elf_magic, 4) == 0;
-}
-
-static bool IsValidApkPath(const std::string& apk_path) {
-  static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04};
-  struct stat st;
-  if (stat(apk_path.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
-    return false;
-  }
-  FILE* fp = fopen(apk_path.c_str(), "reb");
-  if (fp == nullptr) {
-    return false;
-  }
-  char buf[4];
-  if (fread(buf, 4, 1, fp) != 1) {
-    fclose(fp);
-    return false;
-  }
-  fclose(fp);
-  return memcmp(buf, zip_preamble, 4) == 0;
-}
-
-class ScopedZiparchiveHandle {
- public:
-  explicit ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
-  }
-
-  ~ScopedZiparchiveHandle() {
-    CloseArchive(handle_);
-  }
-
- private:
-  ZipArchiveHandle handle_;
-};
-
-llvm::object::OwningBinary<llvm::object::Binary> OpenEmbeddedElfFile(const std::string& filename) {
-  llvm::object::OwningBinary<llvm::object::Binary> nothing;
-  size_t pos = filename.find("!/");
-  if (pos == std::string::npos) {
-    return nothing;
-  }
-  std::string apk_file = filename.substr(0, pos);
-  std::string elf_file = filename.substr(pos + 2);
-  if (!IsValidApkPath(apk_file)) {
-    BACK_LOGW("%s is not a valid apk file", apk_file.c_str());
-    return nothing;
-  }
-  ZipArchiveHandle handle;
-  int32_t ret_code = OpenArchive(apk_file.c_str(), &handle);
-  if (ret_code != 0) {
-    CloseArchive(handle);
-    BACK_LOGW("failed to open archive %s: %s", apk_file.c_str(), ErrorCodeString(ret_code));
-    return nothing;
-  }
-  ScopedZiparchiveHandle scoped_handle(handle);
-  ZipEntry zentry;
-  ret_code = FindEntry(handle, ZipString(elf_file.c_str()), &zentry);
-  if (ret_code != 0) {
-    BACK_LOGW("failed to find %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
-              ErrorCodeString(ret_code));
-    return nothing;
-  }
-  if (zentry.method != kCompressStored || zentry.compressed_length != zentry.uncompressed_length) {
-    BACK_LOGW("%s is compressed in %s, which doesn't support running directly", elf_file.c_str(),
-              apk_file.c_str());
-    return nothing;
-  }
-  auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(GetFileDescriptor(handle), apk_file,
-                                                            zentry.uncompressed_length,
-                                                            zentry.offset);
-  if (!buffer_or_err) {
-    BACK_LOGW("failed to read %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
-              buffer_or_err.getError().message().c_str());
-    return nothing;
-  }
-  auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
-  if (!binary_or_err) {
-    BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
-              llvm::toString(binary_or_err.takeError()).c_str());
-    return nothing;
-  }
-  return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
-                                                          std::move(buffer_or_err.get()));
-}
-
-static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
-  llvm::object::OwningBinary<llvm::object::Binary> owning_binary;
-  if (filename.find("!/") != std::string::npos) {
-    owning_binary = OpenEmbeddedElfFile(filename);
-  } else {
-    if (!IsValidElfPath(filename)) {
-      return nullptr;
-    }
-    auto binary_or_err = llvm::object::createBinary(llvm::StringRef(filename));
-    if (!binary_or_err) {
-      return nullptr;
-    }
-    owning_binary = std::move(binary_or_err.get());
-  }
-  llvm::object::Binary* binary = owning_binary.getBinary();
-  auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
-  if (obj == nullptr) {
-    return nullptr;
-  }
-  if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
-    return ReadDebugFrameFromELFFile(elf->getELFFile());
-  }
-  if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
-    return ReadDebugFrameFromELFFile(elf->getELFFile());
-  }
-  return nullptr;
-}
-
-Backtrace* Backtrace::CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map,
-                                    const backtrace_stackinfo_t& stack, bool cache_file) {
-  return new BacktraceOffline(pid, tid, map, stack, cache_file);
-}
diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h
deleted file mode 100644
index e028cd8..0000000
--- a/libbacktrace/BacktraceOffline.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 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 _LIBBACKTRACE_UNWIND_OFFLINE_H
-#define _LIBBACKTRACE_UNWIND_OFFLINE_H
-
-#include <libunwind.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-#include <unordered_map>
-#include <unordered_set>
-
-#include <backtrace/Backtrace.h>
-
-struct Space {
-  uint64_t start;
-  uint64_t end;
-  const uint8_t* data;
-
-  Space() { Clear(); }
-
-  void Clear();
-  size_t Read(uint64_t addr, uint8_t* buffer, size_t size);
-};
-
-struct DebugFrameInfo;
-
-class BacktraceOffline : public Backtrace {
- public:
-  BacktraceOffline(pid_t pid, pid_t tid, BacktraceMap* map, const backtrace_stackinfo_t& stack,
-                   bool cache_file)
-      : Backtrace(pid, tid, map),
-        cache_file_(cache_file),
-        context_(nullptr),
-        is_debug_frame_used_(false) {
-    stack_space_.start = stack.start;
-    stack_space_.end = stack.end;
-    stack_space_.data = stack.data;
-  }
-
-  virtual ~BacktraceOffline() = default;
-
-  bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
-
-  bool ReadWord(uint64_t ptr, word_t* out_value) override;
-
-  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
-
-  bool FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info,
-                    int need_unwind_info);
-
-  bool ReadReg(size_t reg_index, uint64_t* value);
-
- protected:
-  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
-  DebugFrameInfo* GetDebugFrameInFile(const std::string& filename);
-
-  bool cache_file_;
-  ucontext_t* context_;
-  Space eh_frame_hdr_space_;
-  Space eh_frame_space_;
-  Space arm_extab_space_;
-  Space arm_exidx_space_;
-  Space stack_space_;
-
-  // is_debug_frame_used_ is to make sure we can try both .debug_frame and .ARM.exidx in
-  // FindProcInfo() on ARM. One example is EsxContext::Clear() in
-  // vendor/lib/egl/libGLESv2_adreno.so. EsxContext::Clear() appears in both .debug_frame and
-  // .ARM.exidx. However, libunwind fails to execute debug_frame instruction
-  // "DW_CFA_offset_extended: r265 at cfa-48". So we need to try .ARM.exidx to unwind that
-  // function.
-  bool is_debug_frame_used_;
-};
-
-#endif  // _LIBBACKTRACE_BACKTRACE_OFFLINE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index a748d1b..7e2e6d0 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -18,7 +18,6 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ucontext.h>
 
 #include <memory>
 #include <set>
@@ -37,6 +36,9 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsGetLocal.h>
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
 #include <unwindstack/Unwinder.h>
 
 #include "BacktraceLog.h"
@@ -45,7 +47,7 @@
 
 bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                        std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
-                       std::vector<std::string>* skip_names) {
+                       std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
   UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
   auto process_memory = stack_map->process_memory();
   unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
@@ -53,26 +55,63 @@
   if (stack_map->GetJitDebug() != nullptr) {
     unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
   }
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  if (stack_map->GetDexFiles() != nullptr) {
+    unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
+  }
+#endif
   unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
+  if (error != nullptr) {
+    switch (unwinder.LastErrorCode()) {
+      case unwindstack::ERROR_NONE:
+        error->error_code = BACKTRACE_UNWIND_NO_ERROR;
+        break;
+
+      case unwindstack::ERROR_MEMORY_INVALID:
+        error->error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED;
+        error->error_info.addr = unwinder.LastErrorAddress();
+        break;
+
+      case unwindstack::ERROR_UNWIND_INFO:
+        error->error_code = BACKTRACE_UNWIND_ERROR_UNWIND_INFO;
+        break;
+
+      case unwindstack::ERROR_UNSUPPORTED:
+        error->error_code = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
+        break;
+
+      case unwindstack::ERROR_INVALID_MAP:
+        error->error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
+        break;
+
+      case unwindstack::ERROR_MAX_FRAMES_EXCEEDED:
+        error->error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT;
+        break;
+
+      case unwindstack::ERROR_REPEATED_FRAME:
+        error->error_code = BACKTRACE_UNWIND_ERROR_REPEATED_FRAME;
+        break;
+    }
+  }
 
   if (num_ignore_frames >= unwinder.NumFrames()) {
     frames->resize(0);
     return true;
   }
 
-  frames->resize(unwinder.NumFrames() - num_ignore_frames);
   auto unwinder_frames = unwinder.frames();
+  frames->resize(unwinder.NumFrames() - num_ignore_frames);
   size_t cur_frame = 0;
-  for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, cur_frame++) {
+  for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
     auto frame = &unwinder_frames[i];
+
     backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
 
-    back_frame->num = frame->num - num_ignore_frames;
+    back_frame->num = cur_frame++;
 
     back_frame->rel_pc = frame->rel_pc;
     back_frame->pc = frame->pc;
     back_frame->sp = frame->sp;
-    back_frame->dex_pc = frame->dex_pc;
 
     back_frame->func_name = demangle(frame->function_name.c_str());
     back_frame->func_offset = frame->function_offset;
@@ -95,7 +134,7 @@
   return GetMap()->GetFunctionName(pc, offset);
 }
 
-bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
+bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, void* ucontext) {
   std::unique_ptr<unwindstack::Regs> regs;
   if (ucontext == nullptr) {
     regs.reset(unwindstack::Regs::CreateFromLocal());
@@ -106,9 +145,8 @@
     regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
   }
 
-  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
   std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
-  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names);
+  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names, &error_);
 }
 
 UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
@@ -118,7 +156,7 @@
   return GetMap()->GetFunctionName(pc, offset);
 }
 
-bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
+bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, void* context) {
   std::unique_ptr<unwindstack::Regs> regs;
   if (context == nullptr) {
     regs.reset(unwindstack::Regs::RemoteGet(Tid()));
@@ -126,10 +164,77 @@
     regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context));
   }
 
-  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
+  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_);
 }
 
 size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
   return memory_.Read(addr, buffer, bytes);
 }
+
+UnwindStackOffline::UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map,
+                                       bool map_shared)
+    : Backtrace(pid, tid, map), arch_(arch) {
+  map_shared_ = map_shared;
+}
+
+bool UnwindStackOffline::Unwind(size_t num_ignore_frames, void* ucontext) {
+  if (ucontext == nullptr) {
+    return false;
+  }
+
+  unwindstack::ArchEnum arch;
+  switch (arch_) {
+    case ARCH_ARM:
+      arch = unwindstack::ARCH_ARM;
+      break;
+    case ARCH_ARM64:
+      arch = unwindstack::ARCH_ARM64;
+      break;
+    case ARCH_X86:
+      arch = unwindstack::ARCH_X86;
+      break;
+    case ARCH_X86_64:
+      arch = unwindstack::ARCH_X86_64;
+      break;
+    default:
+      return false;
+  }
+
+  std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
+
+  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_);
+}
+
+std::string UnwindStackOffline::GetFunctionNameRaw(uint64_t, uint64_t*) {
+  return "";
+}
+
+size_t UnwindStackOffline::Read(uint64_t, uint8_t*, size_t) {
+  return 0;
+}
+
+bool UnwindStackOffline::ReadWord(uint64_t, word_t*) {
+  return false;
+}
+
+Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
+                                    const std::vector<backtrace_map_t>& maps,
+                                    const backtrace_stackinfo_t& stack) {
+  BacktraceMap* map = BacktraceMap::CreateOffline(pid, maps, stack);
+  if (map == nullptr) {
+    return nullptr;
+  }
+
+  return new UnwindStackOffline(arch, pid, tid, map, false);
+}
+
+Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map) {
+  if (map == nullptr) {
+    return nullptr;
+  }
+  return new UnwindStackOffline(arch, pid, tid, map, true);
+}
+
+void Backtrace::SetGlobalElfCache(bool enable) {
+  unwindstack::Elf::SetCachingEnabled(enable);
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index 498ad4e..33c4282 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -34,7 +34,7 @@
 
   std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
 
-  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
+  bool UnwindFromContext(size_t num_ignore_frames, void* ucontext) override;
 };
 
 class UnwindStackPtrace : public BacktracePtrace {
@@ -42,9 +42,9 @@
   UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~UnwindStackPtrace() = default;
 
-  bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
+  bool Unwind(size_t num_ignore_frames, void* context) override;
 
-  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
+  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
 
   size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
@@ -52,4 +52,20 @@
   unwindstack::MemoryRemote memory_;
 };
 
+class UnwindStackOffline : public Backtrace {
+ public:
+  UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map, bool map_shared);
+
+  bool Unwind(size_t num_ignore_frames, void* context) override;
+
+  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
+
+  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
+
+  bool ReadWord(uint64_t ptr, word_t* out_value) override;
+
+ private:
+  ArchEnum arch_;
+};
+
 #endif  // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 60c7952..6dcc621 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -45,6 +45,9 @@
   // Create a JitDebug object for getting jit unwind information.
   std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
   jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_));
+#endif
 
   if (!stack_maps_->Parse()) {
     return false;
@@ -118,6 +121,43 @@
   return process_memory_;
 }
 
+UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
+
+bool UnwindStackOfflineMap::Build() {
+  return false;
+}
+
+bool UnwindStackOfflineMap::Build(const std::vector<backtrace_map_t>& backtrace_maps,
+                                  const backtrace_stackinfo_t& stack) {
+  if (stack.start >= stack.end) {
+    return false;
+  }
+
+  for (const backtrace_map_t& map : backtrace_maps) {
+    maps_.push_back(map);
+  }
+
+  std::sort(maps_.begin(), maps_.end(),
+            [](const backtrace_map_t& a, const backtrace_map_t& b) { return a.start < b.start; });
+
+  unwindstack::Maps* maps = new unwindstack::Maps;
+  stack_maps_.reset(maps);
+  for (const backtrace_map_t& map : maps_) {
+    maps->Add(map.start, map.end, map.offset, map.flags, map.name, map.load_bias);
+  }
+
+  // Create the process memory from the stack data.
+  uint64_t size = stack.end - stack.start;
+  unwindstack::MemoryBuffer* memory = new unwindstack::MemoryBuffer;
+  memory->Resize(size);
+  memcpy(memory->GetPtr(0), stack.data, size);
+  std::shared_ptr<unwindstack::Memory> shared_memory(memory);
+
+  process_memory_.reset(new unwindstack::MemoryRange(shared_memory, 0, size, stack.start));
+
+  return true;
+}
+
 //-------------------------------------------------------------------------
 // BacktraceMap create function.
 //-------------------------------------------------------------------------
@@ -138,3 +178,16 @@
   }
   return map;
 }
+
+//-------------------------------------------------------------------------
+// BacktraceMap create offline function.
+//-------------------------------------------------------------------------
+BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps,
+                                          const backtrace_stackinfo_t& stack) {
+  UnwindStackOfflineMap* map = new UnwindStackOfflineMap(pid);
+  if (!map->Build(maps, stack)) {
+    delete map;
+    return nullptr;
+  }
+  return map;
+}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 6b98809..94cbfb2 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -21,11 +21,21 @@
 #include <sys/types.h>
 
 #include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
 
+#include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
 
+// Forward declarations.
+class UnwindDexFile;
+
 class UnwindStackMap : public BacktraceMap {
  public:
   explicit UnwindStackMap(pid_t pid);
@@ -44,12 +54,29 @@
 
   unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
+
  protected:
   uint64_t GetLoadBias(size_t index) override;
 
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
   std::unique_ptr<unwindstack::JitDebug> jit_debug_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<unwindstack::DexFiles> dex_files_;
+#endif
+};
+
+class UnwindStackOfflineMap : public UnwindStackMap {
+ public:
+  UnwindStackOfflineMap(pid_t pid);
+  ~UnwindStackOfflineMap() = default;
+
+  bool Build() override;
+
+  bool Build(const std::vector<backtrace_map_t>& maps, const backtrace_stackinfo_t& stack);
 };
 
 #endif  // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index e2a7441..9877f29 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -15,9 +15,9 @@
  */
 
 #include <inttypes.h>
-#include <libunwind.h>
 #include <pthread.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <functional>
@@ -44,33 +44,7 @@
 int test_level_three(int, int, int, int, void (*)(void*), void*);
 int test_level_four(int, int, int, int, void (*)(void*), void*);
 int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(unw_context_t* unw_context, volatile int* exit_flag);
-}
-
-static ucontext_t GetUContextFromUnwContext(const unw_context_t& unw_context) {
-  ucontext_t ucontext;
-  memset(&ucontext, 0, sizeof(ucontext));
-#if defined(__arm__)
-  ucontext.uc_mcontext.arm_r0 = unw_context.regs[0];
-  ucontext.uc_mcontext.arm_r1 = unw_context.regs[1];
-  ucontext.uc_mcontext.arm_r2 = unw_context.regs[2];
-  ucontext.uc_mcontext.arm_r3 = unw_context.regs[3];
-  ucontext.uc_mcontext.arm_r4 = unw_context.regs[4];
-  ucontext.uc_mcontext.arm_r5 = unw_context.regs[5];
-  ucontext.uc_mcontext.arm_r6 = unw_context.regs[6];
-  ucontext.uc_mcontext.arm_r7 = unw_context.regs[7];
-  ucontext.uc_mcontext.arm_r8 = unw_context.regs[8];
-  ucontext.uc_mcontext.arm_r9 = unw_context.regs[9];
-  ucontext.uc_mcontext.arm_r10 = unw_context.regs[10];
-  ucontext.uc_mcontext.arm_fp = unw_context.regs[11];
-  ucontext.uc_mcontext.arm_ip = unw_context.regs[12];
-  ucontext.uc_mcontext.arm_sp = unw_context.regs[13];
-  ucontext.uc_mcontext.arm_lr = unw_context.regs[14];
-  ucontext.uc_mcontext.arm_pc = unw_context.regs[15];
-#else
-  ucontext.uc_mcontext = unw_context.uc_mcontext;
-#endif
-  return ucontext;
+void test_get_context_and_wait(void* context, volatile int* exit_flag);
 }
 
 struct FunctionSymbol {
@@ -108,18 +82,17 @@
   return s;
 }
 
-static void HexStringToRawData(const char* s, void* data, size_t size) {
-  uint8_t* p = static_cast<uint8_t*>(data);
+static void HexStringToRawData(const char* s, std::vector<uint8_t>* data, size_t size) {
   for (size_t i = 0; i < size; ++i) {
     int value;
     sscanf(s, "%02x", &value);
-    *p++ = static_cast<uint8_t>(value);
+    data->push_back(value);
     s += 2;
   }
 }
 
 struct OfflineThreadArg {
-  unw_context_t unw_context;
+  std::vector<uint8_t> ucontext;
   pid_t tid;
   volatile int exit_flag;
 };
@@ -127,12 +100,12 @@
 static void* OfflineThreadFunc(void* arg) {
   OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
   fn_arg->tid = gettid();
-  test_get_context_and_wait(&fn_arg->unw_context, &fn_arg->exit_flag);
+  test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
   return nullptr;
 }
 
-std::string GetTestPath(std::string path) {
-  return android::base::GetExecutableDirectory() + "/testdata/" + ABI_STRING + '/' + path;
+std::string GetTestPath(const std::string& arch, const std::string& path) {
+  return android::base::GetExecutableDirectory() + "/testdata/" + arch + '/' + path;
 }
 
 // This test is disable because it is for generating test data.
@@ -149,7 +122,7 @@
   OfflineThreadArg arg;
   arg.exit_flag = 0;
   ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg));
-  // Wait for the offline thread to generate the stack and unw_context information.
+  // Wait for the offline thread to generate the stack and context information.
   sleep(1);
   // Copy the stack information.
   std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
@@ -179,9 +152,9 @@
                                     entry->start, entry->end, entry->offset, entry->load_bias,
                                     entry->flags, entry->name.c_str());
   }
-  // 3. Dump registers
-  testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
-  testdata += RawDataToHexString(&arg.unw_context, sizeof(arg.unw_context));
+  // 3. Dump ucontext
+  testdata += android::base::StringPrintf("ucontext: %zu ", arg.ucontext.size());
+  testdata += RawDataToHexString(arg.ucontext.data(), arg.ucontext.size());
   testdata.push_back('\n');
 
   // 4. Dump stack
@@ -218,7 +191,7 @@
   int pid;
   int tid;
   std::vector<backtrace_map_t> maps;
-  unw_context_t unw_context;
+  std::vector<uint8_t> ucontext;
   backtrace_stackinfo_t stack_info;
   std::vector<uint8_t> stack;
   std::vector<FunctionSymbol> symbols;
@@ -231,7 +204,6 @@
   }
   // Parse offline_testdata.
   std::vector<std::string> lines = android::base::Split(s, "\n");
-  memset(&testdata->unw_context, 0, sizeof(testdata->unw_context));
   for (const auto& line : lines) {
     if (android::base::StartsWith(line, "pid:")) {
       sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
@@ -244,50 +216,12 @@
              " flags: %d name: %n",
              &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
       map.name = android::base::Trim(line.substr(pos));
-    } else if (android::base::StartsWith(line, "registers:")) {
+    } else if (android::base::StartsWith(line, "ucontext:")) {
       size_t size;
       int pos;
-      sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
-      if (sizeof(testdata->unw_context) != size) {
-        return false;
-      }
-      HexStringToRawData(&line[pos], &testdata->unw_context, size);
-    } else if (android::base::StartsWith(line, "regs:")) {
-      std::vector<std::string> strs = android::base::Split(line.substr(6), " ");
-      if (strs.size() % 2 != 0) {
-        return false;
-      }
-      std::vector<std::pair<std::string, uint64_t>> items;
-      for (size_t i = 0; i + 1 < strs.size(); i += 2) {
-        if (!android::base::EndsWith(strs[i], ":")) {
-          return false;
-        }
-        uint64_t value = std::stoul(strs[i + 1], nullptr, 16);
-        items.push_back(std::make_pair(strs[i].substr(0, strs[i].size() - 1), value));
-      }
-#if defined(__arm__)
-      for (auto& item : items) {
-        if (item.first == "sp") {
-          testdata->unw_context.regs[13] = item.second;
-        } else if (item.first == "pc") {
-          testdata->unw_context.regs[15] = item.second;
-        } else {
-          return false;
-        }
-      }
-#elif defined(__aarch64__)
-      for (auto& item : items) {
-        if (item.first == "pc") {
-          testdata->unw_context.uc_mcontext.pc = item.second;
-        } else if (item.first == "sp") {
-          testdata->unw_context.uc_mcontext.sp = item.second;
-        } else if (item.first == "x29") {
-          testdata->unw_context.uc_mcontext.regs[UNW_AARCH64_X29] = item.second;
-        } else {
-          return false;
-        }
-      }
-#endif
+      testdata->ucontext.clear();
+      sscanf(line.c_str(), "ucontext: %zu %n", &size, &pos);
+      HexStringToRawData(&line[pos], &testdata->ucontext, size);
     } else if (android::base::StartsWith(line, "stack:")) {
       size_t size;
       int pos;
@@ -295,8 +229,8 @@
              "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
              &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
       CHECK_EQ(testdata->stack_info.end - testdata->stack_info.start, size);
-      testdata->stack.resize(size);
-      HexStringToRawData(&line[pos], &testdata->stack[0], size);
+      testdata->stack.clear();
+      HexStringToRawData(&line[pos], &testdata->stack, size);
       testdata->stack_info.data = testdata->stack.data();
     } else if (android::base::StartsWith(line, "function:")) {
       testdata->symbols.resize(testdata->symbols.size() + 1);
@@ -310,17 +244,11 @@
   return true;
 }
 
-static void BacktraceOfflineTest(const char* arch, const std::string& testlib_name) {
-  // TODO: For now, we can only run this on the same arch as the library arch.
-  if (std::string(ABI_STRING) != arch) {
-    GTEST_LOG_(INFO) << "Ignoring arch " << arch << " for lib " << testlib_name;
-    return;
-  }
-
-  const std::string testlib_path(GetTestPath(testlib_name));
-  const std::string offline_testdata_path(GetTestPath("offline_testdata"));
+static void BacktraceOfflineTest(std::string arch_str, const std::string& testlib_name) {
+  const std::string testlib_path(GetTestPath(arch_str, testlib_name));
+  const std::string offline_testdata_path(GetTestPath(arch_str, "offline_testdata"));
   OfflineTestData testdata;
-  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata)) << "Failed " << arch_str;
 
   // Fix path of libbacktrace_testlib.so.
   for (auto& map : testdata.maps) {
@@ -329,16 +257,24 @@
     }
   }
 
-  // Do offline backtrace.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
-  ASSERT_TRUE(map != nullptr);
+  Backtrace::ArchEnum arch;
+  if (arch_str == "arm") {
+    arch = Backtrace::ARCH_ARM;
+  } else if (arch_str == "arm64") {
+    arch = Backtrace::ARCH_ARM64;
+  } else if (arch_str == "x86") {
+    arch = Backtrace::ARCH_X86;
+  } else if (arch_str == "x86_64") {
+    arch = Backtrace::ARCH_X86_64;
+  } else {
+    abort();
+  }
 
-  std::unique_ptr<Backtrace> backtrace(
-      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
-  ASSERT_TRUE(backtrace != nullptr);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
+      arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
+  ASSERT_TRUE(backtrace != nullptr) << "Failed " << arch_str;
 
-  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
-  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+  ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data())) << "Failed " << arch_str;
 
   // Collect pc values of the call stack frames.
   std::vector<uint64_t> pc_values;
@@ -354,14 +290,17 @@
     }
   }
 
-  ASSERT_GE(test_one_index, 3u);
-  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols));
-  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1],
-                                                     testdata.symbols));
-  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2],
-                                                       testdata.symbols));
-  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3],
-                                                      testdata.symbols));
+  ASSERT_GE(test_one_index, 3u) << "Failed " << arch_str;
+  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols))
+      << "Failed " << arch_str;
+  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], testdata.symbols))
+      << "Failed " << arch_str;
+  ASSERT_EQ("test_level_three",
+            FunctionNameForAddress(pc_values[test_one_index - 2], testdata.symbols))
+      << "Failed " << arch_str;
+  ASSERT_EQ("test_level_four",
+            FunctionNameForAddress(pc_values[test_one_index - 3], testdata.symbols))
+      << "Failed " << arch_str;
 }
 
 // For now, these tests can only run on the given architectures.
@@ -384,18 +323,13 @@
   BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
 }
 
-static void LibUnwindingTest(const std::string& arch, const std::string& testdata_name,
+static void LibUnwindingTest(const std::string& arch_str, const std::string& testdata_name,
                              const std::string& testlib_name) {
-  if (std::string(ABI_STRING) != arch) {
-    GTEST_LOG_(INFO) << "Skipping test since offline for arm on " << ABI_STRING
-                     << " isn't supported.";
-    return;
-  }
-  const std::string testlib_path(GetTestPath(testlib_name));
+  const std::string testlib_path(GetTestPath(arch_str, testlib_name));
   struct stat st;
   ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
 
-  const std::string offline_testdata_path(GetTestPath(testdata_name));
+  const std::string offline_testdata_path(GetTestPath(arch_str, testdata_name));
   OfflineTestData testdata;
   ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
 
@@ -406,26 +340,35 @@
     }
   }
 
-  // Do offline backtrace.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
-  ASSERT_TRUE(map != nullptr);
+  Backtrace::ArchEnum arch;
+  if (arch_str == "arm") {
+    arch = Backtrace::ARCH_ARM;
+  } else if (arch_str == "arm64") {
+    arch = Backtrace::ARCH_ARM64;
+  } else if (arch_str == "x86") {
+    arch = Backtrace::ARCH_X86;
+  } else if (arch_str == "x86_64") {
+    arch = Backtrace::ARCH_X86_64;
+  } else {
+    ASSERT_TRUE(false) << "Unsupported arch " << arch_str;
+    abort();
+  }
 
-  std::unique_ptr<Backtrace> backtrace(
-      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+  // Do offline backtrace.
+  std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
+      arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
   ASSERT_TRUE(backtrace != nullptr);
 
-  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
-  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+  ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data()));
 
   ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
-    uint64_t vaddr_in_file =
-        backtrace->GetFrame(i)->pc - testdata.maps[0].start + testdata.maps[0].load_bias;
-    std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+    std::string name = FunctionNameForAddress(backtrace->GetFrame(i)->rel_pc, testdata.symbols);
     ASSERT_EQ(name, testdata.symbols[i].name);
   }
   ASSERT_TRUE(backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED ||
-              backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING);
+              backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING ||
+              backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_REPEATED_FRAME);
 }
 
 // This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 10152f7..aab6db9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <time.h>
+#include <ucontext.h>
 #include <unistd.h>
 
 #include <algorithm>
@@ -143,6 +144,17 @@
   ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 
+#if !defined(__ANDROID__) || defined(__arm__)
+// On host and arm target we aren't guaranteed that we will terminate cleanly.
+#define VERIFY_NO_ERROR(error_code)                               \
+  ASSERT_TRUE(error_code == BACKTRACE_UNWIND_NO_ERROR ||          \
+              error_code == BACKTRACE_UNWIND_ERROR_UNWIND_INFO || \
+              error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING)   \
+      << "Unknown error code " << std::to_string(error_code);
+#else
+#define VERIFY_NO_ERROR(error_code) ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, error_code);
+#endif
+
 static bool ReadyLevelBacktrace(Backtrace* backtrace) {
   // See if test_level_four is in the backtrace.
   bool found = false;
@@ -189,7 +201,7 @@
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  VERIFY_NO_ERROR(backtrace->GetError().error_code);
 
   VerifyLevelDump(backtrace.get());
 }
@@ -211,7 +223,7 @@
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
 
   VerifyMaxDump(backtrace.get());
 }
@@ -241,7 +253,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  VERIFY_NO_ERROR(backtrace->GetError().error_code);
 
   ASSERT_TRUE(backtrace->NumFrames() != 0);
   for (const auto& frame : *backtrace ) {
@@ -292,19 +304,19 @@
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError().error_code);
+  VERIFY_NO_ERROR(all->GetError().error_code);
 
   std::unique_ptr<Backtrace> ign1(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code);
+  VERIFY_NO_ERROR(ign1->GetError().error_code);
 
   std::unique_ptr<Backtrace> ign2(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code);
+  VERIFY_NO_ERROR(ign2->GetError().error_code);
 
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
 }
@@ -340,7 +352,6 @@
       std::unique_ptr<Backtrace> backtrace(create_func(pid, tid, map.get()));
       ASSERT_TRUE(backtrace.get() != nullptr);
       ASSERT_TRUE(backtrace->Unwind(0));
-      ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
       if (ReadyFunc(backtrace.get())) {
         VerifyFunc(backtrace.get(), create_func, map_create_func);
         verified = true;
@@ -389,12 +400,12 @@
   std::unique_ptr<Backtrace> ign1(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
   ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code);
+  VERIFY_NO_ERROR(ign1->GetError().error_code);
 
   std::unique_ptr<Backtrace> ign2(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
   ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code);
+  VERIFY_NO_ERROR(ign2->GetError().error_code);
 
   VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
 }
@@ -480,7 +491,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  VERIFY_NO_ERROR(backtrace->GetError().error_code);
 
   VerifyLevelDump(backtrace.get());
 }
@@ -493,7 +504,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
 
   VerifyMaxDump(backtrace.get());
 }
@@ -535,7 +546,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  VERIFY_NO_ERROR(backtrace->GetError().error_code);
 
   VerifyLevelDump(backtrace.get());
 
@@ -575,17 +586,17 @@
   std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError().error_code);
+  VERIFY_NO_ERROR(all->GetError().error_code);
 
   std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code);
+  VERIFY_NO_ERROR(ign1->GetError().error_code);
 
   std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code);
+  VERIFY_NO_ERROR(ign2->GetError().error_code);
 
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr);
 
@@ -616,7 +627,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
 
   VerifyMaxDump(backtrace.get());
 
@@ -713,21 +724,21 @@
   Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
   ASSERT_TRUE(back1 != nullptr);
   EXPECT_TRUE(back1->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back1->GetError().error_code);
+  VERIFY_NO_ERROR(back1->GetError().error_code);
   delete back1;
   delete map1;
 
   Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
   ASSERT_TRUE(back2 != nullptr);
   EXPECT_TRUE(back2->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back2->GetError().error_code);
+  VERIFY_NO_ERROR(back2->GetError().error_code);
   delete back2;
   delete map2;
 
   Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
   ASSERT_TRUE(back3 != nullptr);
   EXPECT_TRUE(back3->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back3->GetError().error_code);
+  VERIFY_NO_ERROR(back3->GetError().error_code);
   delete back3;
   delete map3;
 }
@@ -991,7 +1002,7 @@
   uint8_t* expected = new uint8_t[pagesize];
   InitMemory(expected, pagesize);
 
-  uint8_t* data = new uint8_t[2*pagesize];
+  uint8_t* data = new uint8_t[2 * pagesize];
   // Verify that we can only read one page worth of data.
   size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
   ASSERT_EQ(pagesize, bytes_read);
@@ -1042,8 +1053,10 @@
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
 }
 
+// The code requires these variables are the same size.
 volatile uint64_t g_ready = 0;
 volatile uint64_t g_addr = 0;
+static_assert(sizeof(g_ready) == sizeof(g_addr), "g_ready/g_addr must be same size");
 
 static void ForkedReadTest() {
   // Create two map pages.
@@ -1091,13 +1104,13 @@
 
       uint64_t read_addr;
       size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
-                                          reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
-      ASSERT_EQ(sizeof(uint64_t), bytes_read);
+                                          reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_ready));
+      ASSERT_EQ(sizeof(g_ready), bytes_read);
       if (read_addr) {
         // The forked process is ready to be read.
         bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
-                                     reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
-        ASSERT_EQ(sizeof(uint64_t), bytes_read);
+                                     reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_addr));
+        ASSERT_EQ(sizeof(g_addr), bytes_read);
 
         RunReadTest(backtrace.get(), read_addr);
 
@@ -1176,7 +1189,7 @@
   int fd = open(tmp_so_name, O_RDONLY);
   ASSERT_TRUE(fd != -1);
 
-  void* map = mmap(NULL, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
+  void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
   ASSERT_TRUE(map != MAP_FAILED);
   close(fd);
   ASSERT_TRUE(unlink(tmp_so_name) != -1);
@@ -1225,7 +1238,7 @@
       exit(0);
     }
 
-    void* map = mmap(NULL, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
+    void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
     if (map == MAP_FAILED) {
       fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
       unlink(tmp_so_name);
@@ -1258,11 +1271,11 @@
     ASSERT_TRUE(backtrace.get() != nullptr);
 
     uint64_t read_addr;
-    ASSERT_EQ(sizeof(uint64_t),
+    ASSERT_EQ(sizeof(g_ready),
               backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
-                              reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
+                              reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_ready)));
     if (read_addr) {
-      ASSERT_EQ(sizeof(uint64_t),
+      ASSERT_EQ(sizeof(g_addr),
                 backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
                                 reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
 
@@ -1328,15 +1341,16 @@
 }
 
 static void VerifyUnreadableElfBacktrace(void* func) {
-  uint64_t test_func = reinterpret_cast<uint64_t>(func);
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
                                                          BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
-  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+  VERIFY_NO_ERROR(backtrace->GetError().error_code);
 
   size_t frame_num;
-  ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
+  uint64_t test_func = reinterpret_cast<uint64_t>(func);
+  ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num))
+      << DumpFrames(backtrace.get());
 
   VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
 }
@@ -1390,7 +1404,7 @@
     std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
     ASSERT_TRUE(backtrace.get() != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
-    ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+    VERIFY_NO_ERROR(backtrace->GetError().error_code);
 
     size_t frame_num;
     if (FindFuncFrameInBacktrace(backtrace.get(), reinterpret_cast<uint64_t>(test_func),
@@ -1786,7 +1800,7 @@
     Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
-    ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+    VERIFY_NO_ERROR(backtrace->GetError().error_code);
     delete backtrace;
   }
   size_t stable_pss = GetPssBytes();
@@ -1797,7 +1811,7 @@
     Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
-    ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+    VERIFY_NO_ERROR(backtrace->GetError().error_code);
     delete backtrace;
   }
   size_t new_pss = GetPssBytes();
diff --git a/libbacktrace/backtrace_testlib.cpp b/libbacktrace/backtrace_testlib.cpp
index 3081d64..fec7d98 100644
--- a/libbacktrace/backtrace_testlib.cpp
+++ b/libbacktrace/backtrace_testlib.cpp
@@ -14,9 +14,15 @@
  * limitations under the License.
  */
 
-#include <libunwind.h>
 #include <signal.h>
 #include <stdio.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
 
 #include "backtrace_testlib.h"
 
@@ -66,21 +72,70 @@
 }
 
 typedef struct {
-  unw_context_t* unw_context;
+  std::vector<uint8_t>* ucontext;
   volatile int* exit_flag;
 } GetContextArg;
 
 static void GetContextAndExit(void* data) {
-  GetContextArg* arg = (GetContextArg*)data;
-  unw_getcontext(arg->unw_context);
+  GetContextArg* arg = reinterpret_cast<GetContextArg*>(data);
+
+  std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+  unwindstack::RegsGetLocal(regs.get());
+
+  ucontext_t ucontext;
+  memset(&ucontext, 0, sizeof(ucontext));
+#if defined(__arm__)
+  memcpy(&ucontext.uc_mcontext, regs->RawData(), sizeof(uint32_t) * 16);
+#elif defined(__aarch64__)
+  memcpy(&ucontext.uc_mcontext, regs->RawData(), sizeof(uint64_t) * 33);
+#elif defined(__i386__)
+  uint32_t* reg_data = reinterpret_cast<uint32_t*>(regs->RawData());
+  ucontext.uc_mcontext.gregs[0] = reg_data[15];
+  ucontext.uc_mcontext.gregs[1] = reg_data[14];
+  ucontext.uc_mcontext.gregs[2] = reg_data[13];
+  ucontext.uc_mcontext.gregs[3] = reg_data[12];
+  ucontext.uc_mcontext.gregs[4] = reg_data[7];
+  ucontext.uc_mcontext.gregs[5] = reg_data[6];
+  ucontext.uc_mcontext.gregs[6] = reg_data[5];
+  ucontext.uc_mcontext.gregs[7] = reg_data[4];
+  ucontext.uc_mcontext.gregs[8] = reg_data[3];
+  ucontext.uc_mcontext.gregs[9] = reg_data[2];
+  ucontext.uc_mcontext.gregs[10] = reg_data[1];
+  ucontext.uc_mcontext.gregs[11] = reg_data[0];
+  ucontext.uc_mcontext.gregs[14] = reg_data[8];
+  ucontext.uc_mcontext.gregs[15] = reg_data[10];
+#elif defined(__x86_64__)
+  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+  ucontext.uc_mcontext.gregs[0] = reg_data[8];
+  ucontext.uc_mcontext.gregs[1] = reg_data[9];
+  ucontext.uc_mcontext.gregs[2] = reg_data[10];
+  ucontext.uc_mcontext.gregs[3] = reg_data[11];
+  ucontext.uc_mcontext.gregs[4] = reg_data[12];
+  ucontext.uc_mcontext.gregs[5] = reg_data[13];
+  ucontext.uc_mcontext.gregs[6] = reg_data[14];
+  ucontext.uc_mcontext.gregs[7] = reg_data[15];
+  ucontext.uc_mcontext.gregs[8] = reg_data[5];
+  ucontext.uc_mcontext.gregs[9] = reg_data[4];
+  ucontext.uc_mcontext.gregs[10] = reg_data[6];
+  ucontext.uc_mcontext.gregs[11] = reg_data[3];
+  ucontext.uc_mcontext.gregs[12] = reg_data[1];
+  ucontext.uc_mcontext.gregs[13] = reg_data[0];
+  ucontext.uc_mcontext.gregs[14] = reg_data[2];
+  ucontext.uc_mcontext.gregs[15] = reg_data[7];
+  ucontext.uc_mcontext.gregs[16] = reg_data[16];
+#endif
+
+  arg->ucontext->resize(sizeof(ucontext));
+  memcpy(arg->ucontext->data(), &ucontext, sizeof(ucontext));
+
   // Don't touch the stack anymore.
   while (*arg->exit_flag == 0) {
   }
 }
 
-void test_get_context_and_wait(unw_context_t* unw_context, volatile int* exit_flag) {
+void test_get_context_and_wait(void* ucontext, volatile int* exit_flag) {
   GetContextArg arg;
-  arg.unw_context = unw_context;
+  arg.ucontext = reinterpret_cast<std::vector<uint8_t>*>(ucontext);
   arg.exit_flag = exit_flag;
   test_level_one(1, 2, 3, 4, GetContextAndExit, &arg);
 }
diff --git a/libbacktrace/backtrace_testlib.h b/libbacktrace/backtrace_testlib.h
index 16fedc4..9b55e56 100644
--- a/libbacktrace/backtrace_testlib.h
+++ b/libbacktrace/backtrace_testlib.h
@@ -19,8 +19,6 @@
 
 #include <sys/cdefs.h>
 
-#include <libunwind.h>
-
 __BEGIN_DECLS
 
 void test_loop_forever();
@@ -31,7 +29,7 @@
 int test_level_two(int, int, int, int, void (*)(void*), void*);
 int test_level_one(int, int, int, int, void (*)(void*), void*);
 int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(unw_context_t*, volatile int*);
+void test_get_context_and_wait(void*, volatile int*);
 
 __END_DECLS
 
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 1b8ad19..7a37015 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -60,6 +60,10 @@
   BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED,
   // Failed to execute dwarf instructions in debug sections.
   BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED,
+  // Unwind information is incorrect.
+  BACKTRACE_UNWIND_ERROR_UNWIND_INFO,
+  // Unwind information stopped due to sp/pc repeating.
+  BACKTRACE_UNWIND_ERROR_REPEATED_FRAME,
 };
 
 struct BacktraceUnwindError {
@@ -81,21 +85,12 @@
   uint64_t rel_pc;        // The relative pc.
   uint64_t sp;            // The top of the stack.
   size_t stack_size;      // The size of the stack, zero indicate an unknown stack size.
-  uint64_t dex_pc;        // If non-zero, the Dex PC for the ART interpreter.
   backtrace_map_t map;    // The map associated with the given pc.
   std::string func_name;  // The function name associated with this pc, NULL if not found.
   uint64_t func_offset;  // pc relative to the start of the function, only valid if func_name is not
                          // NULL.
 };
 
-#if defined(__APPLE__)
-struct __darwin_ucontext;
-typedef __darwin_ucontext ucontext_t;
-#else
-struct ucontext;
-typedef ucontext ucontext_t;
-#endif
-
 struct backtrace_stackinfo_t {
   uint64_t start;
   uint64_t end;
@@ -107,7 +102,16 @@
 }
 
 class Backtrace {
-public:
+ public:
+  enum ArchEnum : uint8_t {
+    ARCH_ARM,
+    ARCH_ARM64,
+    ARCH_X86,
+    ARCH_X86_64,
+  };
+
+  static void SetGlobalElfCache(bool enable);
+
   // Create the correct Backtrace object based on what is to be unwound.
   // If pid < 0 or equals the current pid, then the Backtrace object
   // corresponds to the current process.
@@ -121,6 +125,16 @@
   static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
 
   // Create an offline Backtrace object that can be used to do an unwind without a process
+  // that is still running. By default, information is only cached in the map
+  // file. If the calling code creates the map, data can be cached between
+  // unwinds. If not, all cached data will be destroyed when the Backtrace
+  // object is destroyed.
+  static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
+                                  const std::vector<backtrace_map_t>& maps,
+                                  const backtrace_stackinfo_t& stack);
+  static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map);
+
+  // Create an offline Backtrace object that can be used to do an unwind without a process
   // that is still running. If cache_file is set to true, then elf information will be cached
   // for this call. The cached information survives until the calling process ends. This means
   // that subsequent calls to create offline Backtrace objects will continue to use the same
@@ -131,11 +145,11 @@
   virtual ~Backtrace();
 
   // Get the current stack trace and store in the backtrace_ structure.
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
+  virtual bool Unwind(size_t num_ignore_frames, void* context = NULL) = 0;
 
   static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                      std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
-                     std::vector<std::string>* skip_names);
+                     std::vector<std::string>* skip_names, BacktraceUnwindError* error = nullptr);
 
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found,
@@ -185,7 +199,7 @@
 
   std::string GetErrorString(BacktraceUnwindError error);
 
-protected:
+ protected:
   Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);
 
   // The name returned is not demangled, GetFunctionName() takes care of
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 4d020e6..e19c413 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -34,6 +34,9 @@
 #include <string>
 #include <vector>
 
+// Forward declaration.
+struct backtrace_stackinfo_t;
+
 // Special flag to indicate a map is in /dev/. However, a map in
 // /dev/ashmem/... does not set this flag.
 static constexpr int PROT_DEVICE_MAP = 0x8000;
@@ -58,7 +61,8 @@
   // is unsupported.
   static BacktraceMap* Create(pid_t pid, bool uncached = false);
 
-  static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
+  static BacktraceMap* CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps,
+                                     const backtrace_stackinfo_t& stack);
 
   virtual ~BacktraceMap();
 
diff --git a/libbacktrace/testdata/arm/offline_testdata b/libbacktrace/testdata/arm/offline_testdata
index 6acea29..d5b8f47 100644
--- a/libbacktrace/testdata/arm/offline_testdata
+++ b/libbacktrace/testdata/arm/offline_testdata
@@ -93,7 +93,7 @@
 map: start: e8813000 end: e8815000 offset: 0 load_bias: 0 flags: 3 name: 
 map: start: ff886000 end: ff8a9000 offset: 0 load_bias: 0 flags: 3 name: [stack]
 map: start: ffff0000 end: ffff1000 offset: 0 load_bias: 0 flags: 5 name: [vectors]
-registers: 64 34868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee7
+ucontext: 104 000000000000000000000000000000000000000000000000000000000000000034868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee70000000000000000
 stack: start: e8715000 end: e8719000 size: 16384 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc8871e87dba6ee734868affdc8871e8dc8871e85dba6ee7070000000e000000150000001c000000dc8871e85dba6ee71c000000150000000e00000007000000100000000c0000000800000004000000ddb86ee75dba6ee7dc8871e804000000080000000c00000010000000dc8871e85dba6ee7100000000c000000080000000400000008000000060000000400000002000000288871e835b96ee75dba6ee7dc8871e802000000040000000600000008000000dc8871e85dba6ee70800000006000000040000000200000004000000030000000200000001000000708871e88db96ee75dba6ee7dc8871e801000000020000000300000004000000dc8871e85dba6ee70400000003000000020000000100000004000000208971e8208971e878000000e87d00003dba6ee75dba6ee7dc8871e878000000c5807ce7fc7183e734868aff78868aff78868aff34868aff34868aff78868affe0879437208971e84154d2aa0020000034868aff34868aff34868aff78000000c9b87ee7b1b87ee7a3f47be7288971e8b1b87ee7208971e800000000f83481e800000000e97d0000e87d000000000000005071e82039000000100000000000000000000000000000000000002354d2aa34868aff00000000002071e801000000000000000000000000000000708971e8208971e8000000000000000000000000e0879437000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: e76eb835 name: unknown_start
 function: start: e76eb835 end: e76eb88d name: test_level_four
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
index 1f96834..d7c186e 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
@@ -1,6 +1,6 @@
 pid: 7288 tid: 31656
-regs: pc: cc416235 sp: cc17f000
+ucontext: 104 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f017cc00000000356241cc0000000000000000
 map: start: cc361000 end: cc758000 offset: 0 load_bias: 9000 flags: 5 name: /vendor/lib/egl/libGLESv2_adreno.so
-stack: start: cc17f254 end: cc17f258 size: 4 b36141cc
+stack: start: cc17f234 end: cc17f258 size: 36 0000000000000000000000000000000000000000000000000000000000000000b36141cc
 function: start: be1f0 end: be304 name: EsxContext::Clear(unsigned int, unsigned int, unsigned int, EsxClearValues*)
 function: start: be058 end: be1f0 name: EsxContext::ClearBuffersForDebug()
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
index a12bc3c..54f3525 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
@@ -1,6 +1,6 @@
 pid: 7288 tid: 31656
-regs: pc: f1f6dc49 sp: d8fe6930
+ucontext: 104 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003069fed80000000049dcf6f10000000000000000
 map: start: f1f10000 end: f2049000 offset: 0 load_bias: 10000 flags: 5 name: /system/lib/libandroid_runtime.so
-stack: start: d8fe6954 end: d8fe6958 size: 4 e7dcf6f1
+stack: start: d8fe6948 end: d8fe6958 size: 16 000000000000000000000000e7dcf6f1
 function: start: 6dbf9 end: 6dce5 name: android::AndroidRuntime::javaThreadShell
 function: start: 6dce5 end: 6dd79 name: android::AndroidRuntime::javaCreateThreadEtc
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
index db9bf8d..c1369ff 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libart
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -1,5 +1,5 @@
 pid: 32232 tid: 32233
-registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
+ucontext: 104 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e90000000000000000
 map: start: e9380000 end: e9766000 offset: 0 load_bias: b000 flags: 5 name: /system/lib/libart.so
 stack: start: ffd12dc0 end: ffd1306c size: 684 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d89524
 function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
diff --git a/libbacktrace/testdata/arm64/offline_testdata b/libbacktrace/testdata/arm64/offline_testdata
index 75a2f12..cee9f72 100644
--- a/libbacktrace/testdata/arm64/offline_testdata
+++ b/libbacktrace/testdata/arm64/offline_testdata
@@ -95,7 +95,7 @@
 map: start: 70160e4000 end: 70160e5000 offset: 0 load_bias: 0 flags: 1 name: 
 map: start: 70160e5000 end: 70160e8000 offset: 0 load_bias: 0 flags: 3 name: 
 map: start: 7fd8baf000 end: 7fd8be6000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-registers: 4560 679a0b1670000000f3eb6d705500000090f56e7055000000000000000000000000206f705500000014e0677055000000d038bed87f0000004cde67705500000041000000000000001900000000000000c00f241470000000d3aec914588f4bcd0400000000000000e493af157000000090f56e7055000000060000000000000023c00b1670000000b1d1fd15700000003039bed87f000000c898041670000000304cbed87f000000b8130e1670000000303cbed87f000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000003003167000000001000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000033000000000000000300000000000000003303167000000008330316700000000000000006000000f8320316700000005839bed87f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000c84cbed87f000000e84cbed87f000000984dbed87f00000078170e167000000002fd0000000000001400000000000000ff8100000100000000000000000000000000000000000000000000000000000078145700000000000010000000000000902b000000000000bdd04058000000000000000000000000bdd04058000000000000000000000000ccb58a560000000042487408000000000000000000000000cc57041670000000004704167000000010c0fd157000000010c0fd157000000090c0fd15700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000002f48bed87f000000d3aec914588f4bcd2045bed87f0000002045bed87f0000002f48bed87f00000001000000000000002f000080000000005045bed87f0000000045bed87f000000c0a0c315700000006045bed87f0000006045bed87f000000010000000000000001000000000000000344bed87f00000001000000100000009c3fbed87f0000009b3fbed87f0000000344bed87f0000009a3fbed87f0000000100000000000000953fbed87f0000004344bed80100000001000000010000002c48bed87f0000000444bed87f0000004344bed80100000000000000000000000100000000000000b03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd000000000100000000000000000000000100000000000000f03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03fbed87f0000000000000000000000000000000000000000000000000000000000000000000000d3aec914588f4bcd08226f70550000000000000000000000000000000000000000000000000000001048bed87f0000008047bed87f0000006047bed87f000000e0ffffff80ffffff03000000000000000000000000000000891d6e7055000000d3aec914588f4bcd5047bed87f0000005047bed87f000000861d6e705500000003000000000000002f00008000000000f0a6ca15700000004047bed87f000000c0a0c31570000000891d6e7055000000d3aec914000000000100000000000000a047bed800000000f9006e70550000000100000000000000dc41bed87f000000db41bed87f0000004346bed87f000000da41bed87f0000000100000000000000d541bed87f00000001000000010000000100000001000000861d6e70550000004446bed87f0000002c42bed80300000000000000000000000100000000000000f041bed87f0000009b1e6e700100000000000000000000000000000000000000d3aec914588f4bcd8e1e6e70550000000d000000000000002f00008000000000f0a6ca15700000003048bed87f000000c0a0c31570000000661e6e700100000000000000000000002f000000000000001000000000000000e21e6e7055000000d3aec914588f4bcdb048bed87f000000b048bed87f000000e21e6e70550000002f000000000000002f00008000000000f0a6ca1570000000a048bed87f000000c0a0c315700000008e1e6e7055000000000000000000000022000000000000000000000000000000205827147000000022000000000000003c43bed87f0000003b43bed87f000000a347bed87f0000003a43bed87f00000001000000000000003543bed87f000000f048bed8010000000100000001000000dd1e6e7055000000a447bed87f0000008c43bed82f000000000000000000000001000000000000005043bed87f000000861d6e700300000000000000000000000000000000000000d3aec914588f4bcd721e6e7055000000f447bed87f000000981123141800000000000000000000000100000000000000a043bed87f000000861d6e70030000000000000000000000d042bed87f0000000000000000000000981123147000000098112314700000009811231470000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000504abed87f000000b049bed87f0000008049bed87f00000000000000000000004043bed87f0000000000000000000000991123147000000000000000000000008e1e6e70550000000d00000000000000a04abed87f000000000000000000000000000000000000000000000000000000504abed87f000000e049bed87f000000a049bed87f000000c8ffffff80ffffff591e6e70550000000d0000000000000098112314700000000000000000000000df1e6e7055000000010000000000000020582714700000002200000000000000f049bed87f000000c8ffffff80ffffff9811231470000000980023147000000098112314700000009811231470000000741e6e7055000000060000000000000009f12914700000000c00000000000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b149bed87f000000b149bed87f000000f049be317f000000f049bed87f000000f049bed87f000000b149bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000f149bed87f000000f049bed87f000000d3aec914588f4bcdfcb58a56000000006cbb687055000000160000000000000098112314700000009911231470000000991123147000000098112314700000009911231470000000fcb58a5600000000010000000000000000000000000000000100000000000000604a050000000000e845bed87f0000006048bed87f000000a046bed87f00000017000000000000002c48bed87f0000009046bed87f000000ac73c515700000009911231470000000d3aec914588f4bcd1048bed87f0000008047bed87f0000006047bed87f000000e8ffffff80ffffffffffffffffffffff99112314700000006148bed87f000000981123141500000008020000ffffffff6048bed87f000000160000000000000058112314700000001700000000000000a849bed87f0000000000000000000000284abed87f0000001700000000000000284abed87f000000284abed87f000000d249bed87f00000001000000000000009a112314700000001600000000000000284abed87f000000ffffffffffffffff284abed87f000000284abed87f000000284abed87f000000284abed87f0000001700000000000000ffffffffffffffff284abed87f000000284abed87f000000ff49bed87f000000284abed87f00000000000000000000000000000000000000d049bed87f000000d049bed87f000000004abed87f000000d049bed87f0000000100000000000000d049bed87f000000d049bed87f000000d049bed87f00000017000000000000000100000000000000ffffffffffffffff991123147000000001000000000000003448bed87f0000009911231470000000b0ca687055000000ffffffffffffffff010000000000000099112314700000007047bed87f000000d3aec914588f4bcdfcb58a56000000000100000000000000000000000000000050226f70550000000000000000000000b44b05000000000000102a1470000000861d6e70550000000300000000000000f0a6ca1570000000a047bed87f0000006c79c31570000000f048bed87f0000008048bed87f0000004048bed87f000000c8ffffff80ffffff0000000000000000d3aec914588f4bcdf849bed87f000000f0a6ca15700000000200000000000000085b0e1670000000e048bed87f0000002c6fc515700000009048bed87f000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a89912314700000000000000000000000e9216f70550000008991231470000000e449bed87f0000008991231470000000000000000000000000000000000000008891231470000000899123147000000089912314700000008891231470000000170000000000000088912314700000008891231470000000d3aec914588f4bcd899123147000000016000000000000000000000000000000e9216f705500000088912314700000008891231470000000889123147000000088912314700000008891231470000000f0a6ca15700000000049bed87f0000006c79c31570000000889123147000000088912314700000008891231470000000889123147000000088912314700000008891231470000000889123147000000089912314700000008991231470000000085b0e1670000000404abed87f0000002c6fc51570000000c80a6f7055000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a3b3325736d001b5b6d002c20776865726520002573203d202573000a526570650000000000000000000000000000000000000000000000008891231470000000000000000000000088912314700000008891231470000000889123147000000088912314700000000000000000000000889123147000000088912314700000008891231470000000470000000000000000502a1470000000d3aec914588f4bcdf05727147000000000b2221470000000604abed87f0000005c716c7055000000fcb58a56000000007c706c7055000000fcb58a5600000000ea4b050000000000
+ucontext: 464 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000
 stack: start: 7015fd3000 end: 7015fd7000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000004038bed87f000000b863fd1570000000b863fd1570000000b863fd1570000000ec59cf15700000001c000000150000000e000000070000003063fd15700000001c58cf1570000000b863fd1570000000ec59cf1570000000100000000c00000008000000040000006063fd15700000007c58cf1570000000b863fd1570000000ec59cf1570000000080000000600000004000000020000009063fd1570000000dc58cf1570000000b863fd1570000000ec59cf157000000004000000030000000200000001000000d063fd1570000000c459cf15700000000100000000000000144abed87f0000004038bed87f0000004038bed87f000000144abed87f000000d3aec914588f4bcd1064fd157000000074fd6770550000004038bed87f0000004038bed87f000000ec84c41570000000e484c41570000000c484c4157000000000000000000000004064fd15700000004015c01570000000b67e0000000000000000000000000000705a0e1670000000185b0e167000000000000000000000000000000000000000705a0e16700000000000000000000000b77e0000b67e000000000000550000000030fd157000000050340000000000000010000000000000000000000000000000b222147000000000102a14700000000000000000000000000000000000000040fd6770550000004038bed87f000000000000000000000000a0fa1570000000010000000000000000000000000000000000000000000000e864fd15700000005064fd1570000000000000000000000000000000000000000000000000000000d3aec914588f4bcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: 7015cf5760 name: unknown_start
 function: start: 7015cf5760 end: 7015cf57cc name: test_level_four
diff --git a/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid b/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
index dfad172..673e30e 100644
--- a/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
+++ b/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
@@ -1,6 +1,6 @@
 pid: 12276 tid: 12303
-regs: pc: 7b8c027f64 sp: 7b8c157010 x29: 7b8c157040
 map: start: 7b8c01e000 end: 7b8c030000 offset: 0 load_bias: 0 flags: 5 name: /vendor/lib64/egl/eglSubDriverAndroid.so
-stack: start: 7b8c157048 end: 7b8c157050 size: 8 547e028c7b000000
+ucontext: 464 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004070158c7b00000000000000000000001070158c7b000000647f028c7b00000000000000000000000000000000000000
+stack: start: 7b8c157020 end: 7b8c157050 size: 48 00000000000000000000000000000000000000000000000000000000000000000000000000000000547e028c7b000000
 function: start: 9ed8 end: a1b0 name: EglAndroidWindowSurface::Initialize(EglAndroidConfig*, int const*)
 function: start: 9dcc end: 9ed8 name: EglAndroidWindowSurface::Create(ANativeWindow*, EglAndroidConfig*, EglAndroidWindowSurface**, int const*)
diff --git a/libbacktrace/testdata/arm64/offline_testdata_for_libskia b/libbacktrace/testdata/arm64/offline_testdata_for_libskia
index 1027c55..da820c0 100644
--- a/libbacktrace/testdata/arm64/offline_testdata_for_libskia
+++ b/libbacktrace/testdata/arm64/offline_testdata_for_libskia
@@ -1,6 +1,6 @@
 pid: 32232 tid: 32233
-regs: pc: 7c25189a0c sp: 7b8c154b50 x29: 7b8c154bb0
 map: start: 7c24c80000 end: 7c25413000 offset: 0 load_bias: 5f000 flags: 5 name: /system/lib64/libskia.so
-stack: start: 7b8c154bb8 end: 7b8c154bc0 size: 8 ec43f2247c000000
+ucontext: 464 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b04b158c7b0000000000000000000000504b158c7b0000000c9a18257c00000000000000000000000000000000000000
+stack: start: 7b8c154b80 end: 7b8c154bc0 size: 64 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ec43f2247c000000
 function: start: 568970 end: 568c08 name: SkScalerContext_FreeType::generateImage(SkGlyph const&)
 function: start: 30330c end: 3044b0 name: SkScalerContext::getImage(SkGlyph const&)
diff --git a/libbacktrace/testdata/x86/offline_testdata b/libbacktrace/testdata/x86/offline_testdata
index e8b7a99..920b338 100644
--- a/libbacktrace/testdata/x86/offline_testdata
+++ b/libbacktrace/testdata/x86/offline_testdata
@@ -70,7 +70,7 @@
 map: start: f77d5000 end: f77d6000 offset: 0 load_bias: 0 flags: 3 name: 
 map: start: f7ec6000 end: f7ee7000 offset: 0 load_bias: 0 flags: 3 name: [heap]
 map: start: ffe4e000 end: ffe70000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-registers: 348 00000000abdae6fff83b7df704000000a6ec77f7abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000008c8decf78c8decf7ceca48f7a8dae6ff8d8decf70a0000000000000014dae6ff8c8decf78c8decf78c8decf78c8decf78c8decf7a9dae6ff06000000c03a23f78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78d8decf78d8decf7c03a23f7543b23f7000033f75f5f0ff7c03a23f7503423f77000000098000000020000000f2700006c0000000e00000080000000000000008c8decf7000000008c8decf77f03ffff0000ffffffffffff0000000000000000000000000000ffff040000000f27000008000000003023f78d8decf7f069ec000046bdaa308decf715537df7f83b7df78c8decf74c1c71f78c8decf715537df70000000000000000f069ecf7f83b7df75064ecf792e671f7f069ecf7
+ucontext: 96 0000000000000000000000000000000000000000abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000000000000000000000ceca48f7a8dae6ff000000000000000000000000
 stack: start: f732c000 end: f7330000 size: 16384 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009d9d49f761b009f71e382ff7000000000000000000000000000000000000000002000000f6372ff704c82bf70000000000204bf7f0a908f7ceca48f728d9e6fff4a449f70000000020f332f720f332f7d0df48f7f8f132f794c748f720f332f70c144205978142a8d4be08f7d0df48f720f332f7a0ca48f71c000000150000000e000000070000001c000000a0ca48f7d0df48f748f232f739c848f7070000000e000000150000001c000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7100000000c000000080000000400000010000000a0ca48f7d0df48f798f232f7c9c848f704000000080000000c00000010000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f70800000006000000040000000200000008000000a0ca48f7d0df48f7e8f232f759c948f702000000040000000600000008000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7040000000300000002000000010000000046bdaa00000000d0df48f738f332f77cca48f701000000020000000300000004000000a0ca48f720f332f700000000f83b7df7696d4df7d0df48f788dae6ff28d9e6ff28d9e6ff88dae6ff58f332f70046bdaa40fb32f7f83b7df758f332f78d6d4df728d9e6ff88dae6fff83b7df728d9e6ff28d9e6ff009030f728f432f7726f2ff728d9e6ff40fb32f740fb32f740fb32f790f332f700000000000000000000000000000000000000000000000000000000009030f740fb32f7000f3d0028f432f703b12c75032f144e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a06e2ff700000000000f3d00000000008e3f17f740fb32f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03823f7c4fd32f700000000e0341df7e02e1df7e03d1df70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040fb32f7188eecf740fb32f70100000030647cf70046bdaa28658876000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060a705f7a4b130f7f2860000f1860000b0fb32f7ecffffff000000000000000090f332f7000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccfb32f70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c2638cfa7f3e1d0000000000000000000000000000000000406d4df728d9e6ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c032f7004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: f748c740 name: unknown_start
 function: start: f748c740 end: f748c7c0 name: test_level_four
diff --git a/libbacktrace/testdata/x86_64/offline_testdata b/libbacktrace/testdata/x86_64/offline_testdata
index f8d0dc0..c6bb241 100644
--- a/libbacktrace/testdata/x86_64/offline_testdata
+++ b/libbacktrace/testdata/x86_64/offline_testdata
@@ -81,7 +81,7 @@
 map: start: 7ffcf47ed000 end: 7ffcf480f000 offset: 0 load_bias: 0 flags: 3 name: [stack]
 map: start: 7ffcf48d5000 end: 7ffcf48d7000 offset: 0 load_bias: ffffffffff700000 flags: 5 name: [vdso]
 map: start: ffffffffff600000 end: ffffffffff601000 offset: 0 load_bias: 0 flags: 5 name: [vsyscall]
-registers: 936 010000000000000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f0000b92455add57f0000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000a0b180f4fc7f000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f000078b480f4fc7f000078b480f4fc7f00007f03ffff0000ffffffffffff000000000000000000000000801f0000fc7f000078b480f4fc7f000060b280f4fc7f000000006a80f3f73cf110b480f4fc7f0000de66d6abd57f00000000000000000000000000000000000000006a80f3f73cf128b480f4fc7f0000782455add57f0000fd96d6abd57f0000092555add57f0000000000000000000057b480f4fc7f0000092555add57f000060b480f4fc7f00006994d6abd57f0000b0e0c6abd57f000071b280f4fc7f000070b280f4fc7f0000256c640000000000a8b180f4fc7f000090b480f4fc7f0000082555add57f0000092555add57f0000092555add57f0000082555add57f00001700000000000000082555add57f0000082555add57f0000f93cfcabd57f0000092555add57f000016000000000000000000000000000000090c07acd57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f000010b380f4fc7f000078b480f4fc7f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000092555add57f0000092555add57f0000b92455add57f000028b480f4fc7f0000c800000000000000014c7f0b0380ffff0d000000fc7f0000030000000000000033000000d57f000000b480f4fc7f00000000000000000000a0e154ad5b000000000000000000000000000000000000006e000000770000000000000000000000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f00006027b4aad57f0000c800000000000000a0e154add57f0000c0e354add57f0000092555add57f000000006a80f3f73cf1e0e054add57f0000e0e554add57f0000d14df6abd57f0000
+ucontext: 224 00000000000000000000000000000000000000000000000000000000000000000000000000000000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 stack: start: 7fd5abb6b000 end: 7fd5abb6f000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c4eaeabd57f00000000000000000000978142a8000000000f0000000000000012000000000000003888b4abd57f0000e657aeabd57f00000000000000000000a0dcb6abd57f0000307d78aad57f0000b0ddb6abd57f000028d978aad57f0000060aa10200000000a0ddb6abd57f0000000000000000000000000000000000002091b1abd57f0000e094b4abd57f000017008cabd57f0000c84d79aad57f000028e28babd57f00000000000005000000d503000001000000000000000000000068deb6abd57f000040deb6abd57f00002091b1abd57f00000100000000000000e0f3c6abd57f000088f0c6abd57f00006159aeabd57f000000000000000000002091b1abd57f000005000000000000000000000000000000010000000000000088f0c6abd57f00000000000000000000d07bcfabd57f00000000000000000000000000000000000098deb6abd57f000098deb6abd57f0000b0ddb6abd57f00006179cfabd57f000098deb6abd57f0000b07bcfabd57f00001c000000150000000e00000007000000f0ddb6abd57f0000e179cfabd57f00000000000000000000150000001c00000098deb6abd57f0000b07bcfabd57f0000100000000c000000080000000400000030deb6abd57f0000417acfabd57f000000000000000000000c0000001000000098deb6abd57f0000b07bcfabd57f00000800000006000000040000000200000070deb6abd57f0000a17acfabd57f00000000000000000000060000000800000098deb6abd57f0000b07bcfabd57f000004000000030000000200000001000000b0deb6abd57f0000817bcfabd57f0000000000000000000074b480f4fc7f0000c8b080f4fc7f0000c8b080f4fc7f000074b480f4fc7f000000006a80f3f73cf1d0deb6abd57f00002a52d5abd57f0000c8b080f4fc7f0000c8b080f4fc7f0000000000000000000084518cabd57f0000000000000000000000e7b6abd57f000000e7b6abd57f00008f990b1e3bad5a6700000000000000000000000000000000c0e354add57f000000e7b6abd57f00008f99cba356faf1988f9991bc23faf1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f00007de387aad57f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006030b4aad57f0000b8edb6abd57f00000000000000000000000000000000000080b88eaad57f0000000000000000000080b28eaad57f0000000000000000000080c18eaad57f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f0000402555add57f000000e7b6abd57f00000100000000000000000000000000000000006a80f3f73cf1058f9d56adb3c7cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407ab1abd57f000030a3adabd57f00005c64000053640000e0e9b6abd57f0000e0e9b6abd57f0000e0ffffffffffffff00000000000000000000000000000000f0deb6abd57f00000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010eab6abd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c46ad90f52391d00000000000000000000000000000000000000000000000000f051d5abd57f0000c8b080f4fc7f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b6abd57f000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 function: start: 0 end: 7fd5abcf7930 name: unknown_start
 function: start: 7fd5abcf7930 end: 7fd5abcf7990 name: test_level_four
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index f45472e..a993d41 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -141,6 +141,7 @@
     { 00444, AID_ROOT,      AID_ROOT,      0, odm_conf_file + 1 },
     { 00444, AID_ROOT,      AID_ROOT,      0, oem_conf_dir + 1 },
     { 00444, AID_ROOT,      AID_ROOT,      0, oem_conf_file + 1 },
+    { 00600, AID_ROOT,      AID_ROOT,      0, "product/build.prop" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5753e49..5d17698 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -55,6 +55,9 @@
  */
 
 #define AID_ROOT 0 /* traditional unix root user */
+/* The following are for LTP and should only be used for testing */
+#define AID_DAEMON 1 /* traditional unix daemon owner */
+#define AID_BIN 2    /* traditional unix binaries owner */
 
 #define AID_SYSTEM 1000 /* system server */
 
@@ -125,6 +128,7 @@
 #define AID_RESERVED_DISK 1065   /* GID that has access to reserved disk space */
 #define AID_STATSD 1066          /* statsd daemon */
 #define AID_INCIDENTD 1067       /* incidentd daemon */
+#define AID_SECURE_ELEMENT 1068  /* secure element subsystem */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
index a87e23e..b37d020 100644
--- a/libcutils/tests/AshmemTest.cpp
+++ b/libcutils/tests/AshmemTest.cpp
@@ -14,11 +14,18 @@
  * limitations under the License.
  */
 
+#include <errno.h>
+#include <linux/fs.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 #include <cutils/ashmem.h>
 #include <gtest/gtest.h>
-#include <linux/fs.h>
-#include <sys/mman.h>
 
 using android::base::unique_fd;
 
@@ -31,15 +38,21 @@
 }
 
 void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
     *region = mmap(nullptr, size, prot, MAP_SHARED, fd, off);
     ASSERT_NE(MAP_FAILED, *region);
 }
 
 void TestProtDenied(const unique_fd &fd, size_t size, int prot) {
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
     EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
 }
 
 void TestProtIs(const unique_fd& fd, int prot) {
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
     EXPECT_EQ(prot, ioctl(fd, ASHMEM_GET_PROT_MASK));
 }
 
@@ -86,18 +99,23 @@
     ASSERT_EQ(0, memcmp(region1, &data, size));
     EXPECT_EQ(0, munmap(region1, size));
 
-    ASSERT_EXIT({
-        void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-        if (region2 == MAP_FAILED) {
-            _exit(1);
-        }
-        if (memcmp(region2, &data, size) != 0) {
-            _exit(2);
-        }
-        memset(region2, 0, size);
-        munmap(region2, size);
-        _exit(0);
-    }, ::testing::ExitedWithCode(0),"");
+    ASSERT_EXIT(
+        {
+            if (!ashmem_valid(fd)) {
+                _exit(3);
+            }
+            void* region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+            if (region2 == MAP_FAILED) {
+                _exit(1);
+            }
+            if (memcmp(region2, &data, size) != 0) {
+                _exit(2);
+            }
+            memset(region2, 0, size);
+            munmap(region2, size);
+            _exit(0);
+        },
+        ::testing::ExitedWithCode(0), "");
 
     memset(&data, 0, size);
     void *region2;
@@ -146,6 +164,7 @@
     };
     for (const auto& cfg : seeks) {
         errno = 0;
+        ASSERT_TRUE(ashmem_valid(fd));
         auto off = lseek(fd, cfg.offset, cfg.whence);
         ASSERT_EQ(cfg.ret, off) << "lseek(" << cfg.offset << ", " << cfg.whence << ") failed"
                                 << (errno ? ": " : "") << (errno ? strerror(errno) : "");
@@ -196,15 +215,19 @@
     constexpr size_t size = PAGE_SIZE;
 
     int protFlags[] = { PROT_READ, PROT_WRITE };
-    for (int i = 0; i < 2; i++) {
+    for (size_t i = 0; i < arraysize(protFlags); i++) {
         ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
-        ASSERT_EXIT({
-            if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
-                _exit(0);
-            } else {
-                _exit(1);
-            }
-        }, ::testing::ExitedWithCode(0), "");
+        ASSERT_EXIT(
+            {
+                if (!ashmem_valid(fd)) {
+                    _exit(3);
+                } else if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
+                    _exit(0);
+                } else {
+                    _exit(1);
+                }
+            },
+            ::testing::ExitedWithCode(0), "");
         ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, protFlags[1-i]));
     }
 }
@@ -227,6 +250,9 @@
 
     ASSERT_EXIT({
         for (int i = 0; i < nRegions; i++) {
+            if (!ashmem_valid(fd[i])) {
+                _exit(3);
+            }
             void *region = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
             if (region == MAP_FAILED) {
                 _exit(1);
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index f32330a..f95c6c5 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -70,7 +70,7 @@
     for (int i = 0; i < count; i++) {
         snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
         property_get(buf, value, "");
-        if (strcmp(value, cmdline) == 0) {
+        if (strcmp(value, "*") == 0 || strcmp(value, cmdline) == 0) {
             return true;
         }
     }
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 15fba8b..ade2821 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -34,9 +34,11 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-/*
- * Support routines to send messages to the Android in-kernel log buffer,
- * which can later be accessed through the 'logcat' utility.
+/**
+ * \file
+ *
+ * Support routines to send messages to the Android log buffer,
+ * which can later be accessed through the `logcat` utility.
  *
  * Each log message must have
  *   - a priority
@@ -47,24 +49,22 @@
  * and should be reasonably small.
  *
  * Log message text may be truncated to less than an implementation-specific
- * limit (e.g. 1023 characters max).
+ * limit (1023 bytes).
  *
  * Note that a newline character ("\n") will be appended automatically to your
  * log message, if not already there. It is not possible to send several
  * messages and have them appear on a single line in logcat.
  *
- * PLEASE USE LOGS WITH MODERATION:
+ * Please use logging in moderation:
  *
  *  - Sending log messages eats CPU and slow down your application and the
  *    system.
  *
- *  - The circular log buffer is pretty small (<64KB), sending many messages
- *    might push off other important log messages from the rest of the system.
+ *  - The circular log buffer is pretty small, so sending many messages
+ *    will hide other important log messages.
  *
  *  - In release builds, only send log messages to account for exceptional
  *    conditions.
- *
- * NOTE: These functions MUST be implemented by /system/lib/liblog.so
  */
 
 #include <stdarg.h>
@@ -73,28 +73,40 @@
 extern "C" {
 #endif
 
-/*
- * Android log priority values, in ascending priority order.
+/**
+ * Android log priority values, in increasing order of priority.
  */
 typedef enum android_LogPriority {
+  /** For internal use only.  */
   ANDROID_LOG_UNKNOWN = 0,
+  /** The default priority, for internal use only.  */
   ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+  /** Verbose logging. Should typically be disabled for a release apk. */
   ANDROID_LOG_VERBOSE,
+  /** Debug logging. Should typically be disabled for a release apk. */
   ANDROID_LOG_DEBUG,
+  /** Informational logging. Should typically be disabled for a release apk. */
   ANDROID_LOG_INFO,
+  /** Warning logging. For use with recoverable failures. */
   ANDROID_LOG_WARN,
+  /** Error logging. For use with unrecoverable failures. */
   ANDROID_LOG_ERROR,
+  /** Fatal logging. For use when aborting. */
   ANDROID_LOG_FATAL,
+  /** For internal use only.  */
   ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
 } android_LogPriority;
 
-/*
- * Send a simple string to the log.
+/**
+ * Writes the constant string `text` to the log, with priority `prio` and tag
+ * `tag`.
  */
 int __android_log_write(int prio, const char* tag, const char* text);
 
-/*
- * Send a formatted string to the log, used like printf(fmt,...)
+/**
+ * Writes a formatted string to the log, with priority `prio` and tag `tag`.
+ * The details of formatting are the same as for
+ * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
  */
 int __android_log_print(int prio, const char* tag, const char* fmt, ...)
 #if defined(__GNUC__)
@@ -110,9 +122,9 @@
 #endif
     ;
 
-/*
- * A variant of __android_log_print() that takes a va_list to list
- * additional parameters.
+/**
+ * Equivalent to `__android_log_print`, but taking a `va_list`.
+ * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
  */
 int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
 #if defined(__GNUC__)
@@ -128,9 +140,20 @@
 #endif
     ;
 
-/*
- * Log an assertion failure and abort the process to have a chance
- * to inspect it if a debugger is attached. This uses the FATAL priority.
+/**
+ * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
+ * stderr, before calling
+ * [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
+ *
+ * If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
+ * `Assertion failed: %s` is used with `cond` as the string argument.
+ * If both `fmt` and `cond` are null, a default string is provided.
+ *
+ * Most callers should use
+ * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
+ * `<assert.h>` instead, or the `__assert` and `__assert2` functions provided by
+ * bionic if more control is needed. They support automatically including the
+ * source filename and line number more conveniently than this function.
  */
 void __android_log_assert(const char* cond, const char* tag, const char* fmt,
                           ...)
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index aca2a82..61a1d24 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -98,6 +98,7 @@
     return (*reinterpret_cast<std::function<int()>*>(arg))();
   };
 
+  // See README.md for why we create the child process this way
   child_pid_ = clone(proxy, stack_->top(), CLONE_VM | CLONE_FS | CLONE_FILES /*|CLONE_UNTRACED*/,
                      reinterpret_cast<void*>(&func_));
   if (child_pid_ < 0) {
diff --git a/libmemunreachable/README.md b/libmemunreachable/README.md
index 61a47de..ae8fa94 100644
--- a/libmemunreachable/README.md
+++ b/libmemunreachable/README.md
@@ -36,7 +36,7 @@
 
  1. *Original process*: Leak detection is requested by calling `GetUnreachableMemory()`
  2. Allocations are disabled using `malloc_disable()`
- 3. The collection process is spawned.  The collection process is similar to a normal `fork()` child process, except that it shares the address space of the parent - any writes by the original process are visible to the collection process, and vice-versa.
+ 3. The collection process is spawned.  The collection process, created using clone, is similar to a normal `fork()` child process, except that it shares the address space of the parent - any writes by the original process are visible to the collection process, and vice-versa. If we forked instead of using clone, the address space might get out of sync with observed post-ptrace thread state, since it takes some time to pause the parent.
  4. *Collection process*: All threads in the original process are paused with `ptrace()`.
  5. Registers contents, active stack areas, and memory mapping information are collected.
  6. *Original process*: Allocations are re-enabled using `malloc_enable()`, but all threads are still paused with `ptrace()`.
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 6ddec4d..0ebb226 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -236,6 +236,10 @@
       // Different name is useful for debugging
       namespace_name = kVendorClassloaderNamespaceName;
       ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
+    } else if (!oem_public_libraries_.empty()) {
+      // oem_public_libraries are NOT available to vendor apks, otherwise it
+      // would be system->vendor violation.
+      system_exposed_libraries = system_exposed_libraries + ":" + oem_public_libraries_.c_str();
     }
 
     NativeLoaderNamespace native_loader_ns;
@@ -353,9 +357,36 @@
         "Error reading public native library list from \"%s\": %s",
         public_native_libraries_system_config.c_str(), error_msg.c_str());
 
+    // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+    // variable to add libraries to the list. This is intended for platform tests only.
+    if (is_debuggable()) {
+      const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+      if (additional_libs != nullptr && additional_libs[0] != '\0') {
+        std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
+        std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
+                  std::back_inserter(sonames));
+      }
+    }
+
+    // android_init_namespaces() expects all the public libraries
+    // to be loaded so that they can be found by soname alone.
+    //
+    // TODO(dimitry): this is a bit misleading since we do not know
+    // if the vendor public library is going to be opened from /vendor/lib
+    // we might as well end up loading them from /system/lib
+    // For now we rely on CTS test to catch things like this but
+    // it should probably be addressed in the future.
+    for (const auto& soname : sonames) {
+      LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+                          "Error preloading public library %s: %s", soname.c_str(), dlerror());
+    }
+
+    system_public_libraries_ = base::Join(sonames, ':');
+
     // read /system/etc/public.libraries-<companyname>.txt which contain partner defined
     // system libs that are exposed to apps. The libs in the txt files must be
     // named as lib<name>.<companyname>.so.
+    sonames.clear();
     std::string dirname = base::Dirname(public_native_libraries_system_config);
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir);
     if (dir != nullptr) {
@@ -396,39 +427,12 @@
         }
       }
     }
+    oem_public_libraries_ = base::Join(sonames, ':');
 
     // Insert VNDK version to llndk and vndksp config file names.
     insert_vndk_version_str(&llndk_native_libraries_system_config);
     insert_vndk_version_str(&vndksp_native_libraries_system_config);
 
-    // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
-    // variable to add libraries to the list. This is intended for platform tests only.
-    if (is_debuggable()) {
-      const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
-      if (additional_libs != nullptr && additional_libs[0] != '\0') {
-        std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
-        std::copy(additional_libs_vector.begin(),
-                  additional_libs_vector.end(),
-                  std::back_inserter(sonames));
-      }
-    }
-
-    // android_init_namespaces() expects all the public libraries
-    // to be loaded so that they can be found by soname alone.
-    //
-    // TODO(dimitry): this is a bit misleading since we do not know
-    // if the vendor public library is going to be opened from /vendor/lib
-    // we might as well end up loading them from /system/lib
-    // For now we rely on CTS test to catch things like this but
-    // it should probably be addressed in the future.
-    for (const auto& soname : sonames) {
-      LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
-                          "Error preloading public library %s: %s",
-                          soname.c_str(), dlerror());
-    }
-
-    system_public_libraries_ = base::Join(sonames, ':');
-
     sonames.clear();
     ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
     system_llndk_libraries_ = base::Join(sonames, ':');
@@ -554,6 +558,7 @@
   std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
   std::string system_public_libraries_;
   std::string vendor_public_libraries_;
+  std::string oem_public_libraries_;
   std::string system_llndk_libraries_;
   std::string system_vndksp_libraries_;
 
diff --git a/libnativeloader/test/Android.mk b/libnativeloader/test/Android.mk
index 4c3da4a..e625454 100644
--- a/libnativeloader/test/Android.mk
+++ b/libnativeloader/test/Android.mk
@@ -28,3 +28,23 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := oemlibrarytest-system
+LOCAL_MODULE_TAGS := tests
+LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := oemlibrarytest-vendor
+LOCAL_MODULE_TAGS := tests
+LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_APPS)
+include $(BUILD_PACKAGE)
diff --git a/libnativeloader/test/runtest.sh b/libnativeloader/test/runtest.sh
new file mode 100755
index 0000000..40beb5b
--- /dev/null
+++ b/libnativeloader/test/runtest.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+adb root
+adb remount
+adb sync
+adb shell stop
+adb shell start
+sleep 5 # wait until device reboots
+adb logcat -c;
+adb shell am start -n android.test.app.system/android.test.app.TestActivity
+adb shell am start -n android.test.app.vendor/android.test.app.TestActivity
+adb logcat | grep android.test.app
diff --git a/libnativeloader/test/src/android/test/app/TestActivity.java b/libnativeloader/test/src/android/test/app/TestActivity.java
new file mode 100644
index 0000000..214892d
--- /dev/null
+++ b/libnativeloader/test/src/android/test/app/TestActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.test.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle icicle) {
+         super.onCreate(icicle);
+         tryLoadingLib("foo.oem1");
+         tryLoadingLib("bar.oem1");
+         tryLoadingLib("foo.oem2");
+         tryLoadingLib("bar.oem2");
+    }
+
+    private void tryLoadingLib(String name) {
+        try {
+            System.loadLibrary(name);
+            Log.d(getPackageName(), "library " + name + " is successfully loaded");
+        } catch (UnsatisfiedLinkError e) {
+            Log.d(getPackageName(), "failed to load libarary " + name, e);
+        }
+    }
+}
diff --git a/libnativeloader/test/system/AndroidManifest.xml b/libnativeloader/test/system/AndroidManifest.xml
new file mode 100644
index 0000000..c304889
--- /dev/null
+++ b/libnativeloader/test/system/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.test.app.system">
+
+    <application>
+        <activity android:name="android.test.app.TestActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
+
diff --git a/libnativeloader/test/vendor/AndroidManifest.xml b/libnativeloader/test/vendor/AndroidManifest.xml
new file mode 100644
index 0000000..c4c1a9c
--- /dev/null
+++ b/libnativeloader/test/vendor/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.test.app.vendor">
+
+    <application>
+        <activity android:name="android.test.app.TestActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
+
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
new file mode 100644
index 0000000..aeb160c
--- /dev/null
+++ b/libsystem/OWNERS
@@ -0,0 +1,2 @@
+jessehall@google.com
+olv@google.com
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 9389b40..34bfcef 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -80,7 +80,13 @@
         host: {
             cflags: ["-O0", "-g"],
         },
+        vendor: {
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+            exclude_static_libs: ["libunwindstack_dex"],
+            exclude_shared_libs: ["libdexfile"],
+        },
     },
+    whole_static_libs: ["libunwindstack_dex"],
 
     arch: {
         x86: {
@@ -99,14 +105,81 @@
 
     shared_libs: [
         "libbase",
+        "libdexfile",
         "liblog",
         "liblzma",
     ],
 }
 
+// Isolate the dex file processing into a separate library. Currently,
+// it is necessary to add art include directories directly, which also
+// adds the art elf.h file in the include path, overriding the system one.
+// Work to isolate libdexfile is b/72216369.
+cc_library_static {
+    name: "libunwindstack_dex",
+    vendor_available: false,
+    defaults: ["libunwindstack_flags"],
+
+    cflags: [
+        "-Wexit-time-destructors",
+    ],
+
+    srcs: [
+        "DexFile.cpp",
+        "DexFiles.cpp",
+    ],
+    target: {
+        // Always disable optimizations for host to make it easier to debug.
+        host: {
+            cflags: ["-O0", "-g"],
+        },
+    },
+
+    shared_libs: [
+        "libbase",
+        "libdexfile",
+    ],
+    local_include_dirs: ["include"],
+    allow_undefined_symbols: true,
+
+    // libdexfile will eventually properly export headers, for now include
+    // these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+}
+
 //-------------------------------------------------------------------------
 // Unit Tests
 //-------------------------------------------------------------------------
+cc_test_library {
+    name: "libunwindstack_dex_test",
+    vendor_available: false,
+    defaults: ["libunwindstack_flags"],
+
+    shared: {
+        enabled: false,
+    },
+
+    srcs: [
+        "tests/DexFileTest.cpp",
+        "tests/DexFilesTest.cpp",
+    ],
+    local_include_dirs: ["include"],
+    allow_undefined_symbols: true,
+
+    shared_libs: [
+        "libbase",
+        "libunwindstack",
+    ],
+
+    // libdexfile will eventually properly export headers, for now include
+    // these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+}
+
 cc_test {
     name: "libunwindstack_test",
     defaults: ["libunwindstack_flags"],
@@ -124,6 +197,7 @@
         "tests/DwarfOpTest.cpp",
         "tests/DwarfSectionTest.cpp",
         "tests/DwarfSectionImplTest.cpp",
+        "tests/ElfCacheTest.cpp",
         "tests/ElfFake.cpp",
         "tests/ElfInterfaceArmTest.cpp",
         "tests/ElfInterfaceTest.cpp",
@@ -167,13 +241,18 @@
         "libgmock",
     ],
 
+    whole_static_libs: ["libunwindstack_dex_test"],
+
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
-        "tests/files/offline/jit_debug_arm32/*",
-        "tests/files/offline/jit_debug_x86_32/*",
-        "tests/files/offline/gnu_debugdata_arm32/*",
-        "tests/files/offline/straddle_arm32/*",
+        "tests/files/offline/bad_eh_frame_hdr_arm64/*",
+        "tests/files/offline/debug_frame_first_x86/*",
+        "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
+        "tests/files/offline/jit_debug_arm/*",
+        "tests/files/offline/jit_debug_x86/*",
+        "tests/files/offline/gnu_debugdata_arm/*",
+        "tests/files/offline/straddle_arm/*",
         "tests/files/offline/straddle_arm64/*",
     ],
 }
@@ -228,6 +307,15 @@
     ],
 }
 
+cc_binary {
+    name: "unwind_reg_info",
+    defaults: ["libunwindstack_tools"],
+
+    srcs: [
+        "tools/unwind_reg_info.cpp",
+    ],
+}
+
 // Generates the elf data for use in the tests for .gnu_debugdata frames.
 // Once these files are generated, use the xz command to compress the data.
 cc_binary_host {
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index 6b0646f..6e397e3 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -22,12 +22,12 @@
 #include <android-base/stringprintf.h>
 
 #include <unwindstack/Log.h>
+#include <unwindstack/MachineArm.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 #include "Check.h"
-#include "MachineArm.h"
 
 namespace unwindstack {
 
@@ -57,6 +57,7 @@
   uint32_t data;
   if (!elf_memory_->Read32(entry_offset + 4, &data)) {
     status_ = ARM_STATUS_READ_FAILED;
+    status_address_ = entry_offset + 4;
     return false;
   }
   if (data == 1) {
@@ -97,6 +98,7 @@
   uint32_t addr = (entry_offset + 4) + signed_data;
   if (!elf_memory_->Read32(addr, &data)) {
     status_ = ARM_STATUS_READ_FAILED;
+    status_address_ = addr;
     return false;
   }
 
@@ -128,6 +130,7 @@
     addr += 4;
     if (!elf_memory_->Read32(addr, &data)) {
       status_ = ARM_STATUS_READ_FAILED;
+      status_address_ = addr;
       return false;
     }
     num_table_words = (data >> 24) & 0xff;
@@ -145,6 +148,7 @@
   for (size_t i = 0; i < num_table_words; i++) {
     if (!elf_memory_->Read32(addr, &data)) {
       status_ = ARM_STATUS_READ_FAILED;
+      status_address_ = addr;
       return false;
     }
     data_.push_back((data >> 24) & 0xff);
@@ -216,6 +220,7 @@
     if (registers & (1 << reg)) {
       if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
         status_ = ARM_STATUS_READ_FAILED;
+        status_address_ = cfa_;
         return false;
       }
       cfa_ += 4;
@@ -284,6 +289,7 @@
   for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
     if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
       status_ = ARM_STATUS_READ_FAILED;
+      status_address_ = cfa_;
       return false;
     }
     cfa_ += 4;
@@ -291,6 +297,7 @@
   if (byte & 0x8) {
     if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
       status_ = ARM_STATUS_READ_FAILED;
+      status_address_ = cfa_;
       return false;
     }
     cfa_ += 4;
@@ -357,6 +364,7 @@
     if (byte & (1 << reg)) {
       if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
         status_ = ARM_STATUS_READ_FAILED;
+        status_address_ = cfa_;
         return false;
       }
       cfa_ += 4;
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
index f4361d4..96756a0 100644
--- a/libunwindstack/ArmExidx.h
+++ b/libunwindstack/ArmExidx.h
@@ -61,6 +61,7 @@
   std::deque<uint8_t>* data() { return &data_; }
 
   ArmStatus status() { return status_; }
+  uint64_t status_address() { return status_address_; }
 
   RegsArm* regs() { return regs_; }
 
@@ -97,6 +98,7 @@
   uint32_t cfa_ = 0;
   std::deque<uint8_t> data_;
   ArmStatus status_ = ARM_STATUS_NONE;
+  uint64_t status_address_ = 0;
 
   Memory* elf_memory_;
   Memory* process_memory_;
diff --git a/libunwindstack/AsmGetRegsX86.S b/libunwindstack/AsmGetRegsX86.S
index 14927a3..021e628 100644
--- a/libunwindstack/AsmGetRegsX86.S
+++ b/libunwindstack/AsmGetRegsX86.S
@@ -50,12 +50,12 @@
   movl (%esp), %ecx
   movl %ecx, 32(%eax)
 
-  movl %cs, 36(%eax)
-  movl %ss, 40(%eax)
-  movl %ds, 44(%eax)
-  movl %es, 48(%eax)
-  movl %fs, 52(%eax)
-  movl %gs, 56(%eax)
+  mov  %cs, 36(%eax)
+  mov  %ss, 40(%eax)
+  mov  %ds, 44(%eax)
+  mov  %es, 48(%eax)
+  mov  %fs, 52(%eax)
+  mov  %gs, 56(%eax)
   ret
 
   .cfi_endproc
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
index 2d216d7..9643d76 100644
--- a/libunwindstack/Check.h
+++ b/libunwindstack/Check.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _LIBUNWINDSTACK_ERROR_H
-#define _LIBUNWINDSTACK_ERROR_H
+#ifndef _LIBUNWINDSTACK_CHECK_H
+#define _LIBUNWINDSTACK_CHECK_H
 
 #include <stdlib.h>
 
@@ -31,4 +31,4 @@
 
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_ERROR_H
+#endif  // _LIBUNWINDSTACK_CHECK_H
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
new file mode 100644
index 0000000..b18b0ce
--- /dev/null
+++ b/libunwindstack/DexFile.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <android-base/unique_fd.h>
+
+#include <dex/code_item_accessors-inl.h>
+#include <dex/compact_dex_file.h>
+#include <dex/dex_file-inl.h>
+#include <dex/dex_file_loader.h>
+#include <dex/standard_dex_file.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
+  if (!info->name.empty()) {
+    std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
+    if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
+      return dex_file.release();
+    }
+  }
+
+  std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
+  if (dex_file->Open(dex_file_offset_in_memory, memory)) {
+    return dex_file.release();
+  }
+  return nullptr;
+}
+
+DexFileFromFile::~DexFileFromFile() {
+  if (size_ != 0) {
+    munmap(mapped_memory_, size_);
+  }
+}
+
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+                                   uint64_t* method_offset) {
+  if (dex_file_ == nullptr) {
+    return false;
+  }
+
+  if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
+    return false;  // The DEX offset is not within the bytecode of this dex file.
+  }
+
+  for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
+    const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i);
+    const uint8_t* class_data = dex_file_->GetClassData(class_def);
+    if (class_data == nullptr) {
+      continue;
+    }
+    for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) {
+      if (!it.IsAtMethod()) {
+        continue;
+      }
+      const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+      if (code_item == nullptr) {
+        continue;
+      }
+      art::CodeItemInstructionAccessor code(*dex_file_.get(), code_item);
+      if (!code.HasCodeItem()) {
+        continue;
+      }
+
+      uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+      size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
+      if (offset <= dex_offset && dex_offset < offset + size) {
+        *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
+        *method_offset = dex_offset - offset;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
+  if (fd == -1) {
+    return false;
+  }
+  struct stat buf;
+  if (fstat(fd, &buf) == -1) {
+    return false;
+  }
+  uint64_t length;
+  if (buf.st_size < 0 ||
+      __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
+      static_cast<uint64_t>(buf.st_size) < length) {
+    return false;
+  }
+
+  mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (mapped_memory_ == MAP_FAILED) {
+    return false;
+  }
+  size_ = buf.st_size;
+
+  uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);
+
+  art::DexFile::Header* header =
+      reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
+  if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
+      !art::CompactDexFile::IsMagicValid(header->magic_)) {
+    return false;
+  }
+
+  if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
+      static_cast<uint64_t>(buf.st_size) < length) {
+    return false;
+  }
+
+  art::DexFileLoader loader;
+  std::string error_msg;
+  auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
+                         false, false, &error_msg);
+  dex_file_.reset(dex.release());
+  return dex_file_ != nullptr;
+}
+
+bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
+  memory_.resize(sizeof(art::DexFile::Header));
+  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
+    return false;
+  }
+
+  art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+  uint32_t file_size = header->file_size_;
+  if (art::CompactDexFile::IsMagicValid(header->magic_)) {
+    // Compact dex file store data section separately so that it can be shared.
+    // Therefore we need to extend the read memory range to include it.
+    // TODO: This might be wasteful as we might read data in between as well.
+    //       In practice, this should be fine, as such sharing only happens on disk.
+    uint32_t computed_file_size;
+    if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
+      return false;
+    }
+    if (computed_file_size > file_size) {
+      file_size = computed_file_size;
+    }
+  } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
+    return false;
+  }
+
+  memory_.resize(file_size);
+  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
+    return false;
+  }
+
+  header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+
+  art::DexFileLoader loader;
+  std::string error_msg;
+  auto dex =
+      loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
+  dex_file_.reset(dex.release());
+  return dex_file_ != nullptr;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
new file mode 100644
index 0000000..3ce2f1e
--- /dev/null
+++ b/libunwindstack/DexFile.h
@@ -0,0 +1,68 @@
+/*
+ * 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 _LIBUNWINDSTACK_DEX_FILE_H
+#define _LIBUNWINDSTACK_DEX_FILE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dex/dex_file-inl.h>
+
+namespace unwindstack {
+
+class DexFile {
+ public:
+  DexFile() = default;
+  virtual ~DexFile() = default;
+
+  bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+
+  static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
+
+ protected:
+  std::unique_ptr<const art::DexFile> dex_file_;
+};
+
+class DexFileFromFile : public DexFile {
+ public:
+  DexFileFromFile() = default;
+  virtual ~DexFileFromFile();
+
+  bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+
+ private:
+  void* mapped_memory_ = nullptr;
+  size_t size_ = 0;
+};
+
+class DexFileFromMemory : public DexFile {
+ public:
+  DexFileFromMemory() = default;
+  virtual ~DexFileFromMemory() = default;
+
+  bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
+
+ private:
+  std::vector<uint8_t> memory_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..c5f8138
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,204 @@
+/*
+ * 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 <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+struct DEXFileEntry32 {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t dex_file;
+};
+
+struct DEXFileEntry64 {
+  uint64_t next;
+  uint64_t prev;
+  uint64_t dex_file;
+};
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : memory_(memory), search_libs_(search_libs) {}
+
+DexFiles::~DexFiles() {
+  for (auto& entry : files_) {
+    delete entry.second;
+  }
+}
+
+void DexFiles::SetArch(ArchEnum arch) {
+  switch (arch) {
+    case ARCH_ARM:
+    case ARCH_MIPS:
+    case ARCH_X86:
+      read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32;
+      read_entry_func_ = &DexFiles::ReadEntry32;
+      break;
+
+    case ARCH_ARM64:
+    case ARCH_MIPS64:
+    case ARCH_X86_64:
+      read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64;
+      read_entry_func_ = &DexFiles::ReadEntry64;
+      break;
+
+    case ARCH_UNKNOWN:
+      abort();
+  }
+}
+
+uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
+  uint32_t entry;
+  if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+  uint64_t entry;
+  if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+bool DexFiles::ReadEntry32() {
+  DEXFileEntry32 entry;
+  if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+    entry_addr_ = 0;
+    return false;
+  }
+
+  addrs_.push_back(entry.dex_file);
+  entry_addr_ = entry.next;
+  return true;
+}
+
+bool DexFiles::ReadEntry64() {
+  DEXFileEntry64 entry;
+  if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+    entry_addr_ = 0;
+    return false;
+  }
+
+  addrs_.push_back(entry.dex_file);
+  entry_addr_ = entry.next;
+  return true;
+}
+
+void DexFiles::Init(Maps* maps) {
+  if (initialized_) {
+    return;
+  }
+  initialized_ = true;
+  entry_addr_ = 0;
+
+  const std::string dex_debug_name("__art_debug_dexfiles");
+  for (MapInfo* info : *maps) {
+    if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+      continue;
+    }
+
+    if (!search_libs_.empty()) {
+      bool found = false;
+      const char* lib = basename(info->name.c_str());
+      for (const std::string& name : search_libs_) {
+        if (name == lib) {
+          found = true;
+          break;
+        }
+      }
+      if (!found) {
+        continue;
+      }
+    }
+
+    Elf* elf = info->GetElf(memory_, true);
+    uint64_t ptr;
+    // Find first non-empty list (libart might be loaded multiple times).
+    if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
+      entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
+      if (entry_addr_ != 0) {
+        break;
+      }
+    }
+  }
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+  // Lock while processing the data.
+  DexFile* dex_file;
+  auto entry = files_.find(dex_file_offset);
+  if (entry == files_.end()) {
+    dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+    files_[dex_file_offset] = dex_file;
+  } else {
+    dex_file = entry->second;
+  }
+  return dex_file;
+}
+
+bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
+  if (index < addrs_.size()) {
+    *addr = addrs_[index];
+    return true;
+  }
+  if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
+    *addr = addrs_.back();
+    return true;
+  }
+  return false;
+}
+
+void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
+                                    std::string* method_name, uint64_t* method_offset) {
+  std::lock_guard<std::mutex> guard(lock_);
+  if (!initialized_) {
+    Init(maps);
+  }
+
+  size_t index = 0;
+  uint64_t addr;
+  while (GetAddr(index++, &addr)) {
+    if (addr < info->start || addr >= info->end) {
+      continue;
+    }
+
+    DexFile* dex_file = GetDexFile(addr, info);
+    if (dex_file != nullptr &&
+        dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
+      break;
+    }
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index b1d55ba..4fc95c7 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -23,12 +23,12 @@
 
 #include <android-base/stringprintf.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/Log.h>
 
 #include "DwarfCfa.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 namespace unwindstack {
@@ -44,7 +44,8 @@
       (*loc_regs)[entry.first] = entry.second;
     }
   }
-  last_error_ = DWARF_ERROR_NONE;
+  last_error_.code = DWARF_ERROR_NONE;
+  last_error_.address = 0;
 
   memory_->set_cur_offset(start_offset);
   uint64_t cfa_offset;
@@ -54,7 +55,8 @@
     // Read the cfa information.
     uint8_t cfa_value;
     if (!memory_->ReadBytes(&cfa_value, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_->cur_offset();
       return false;
     }
     uint8_t cfa_low = cfa_value & 0x3f;
@@ -66,7 +68,8 @@
       case 2: {
         uint64_t offset;
         if (!memory_->ReadULEB128(&offset)) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_->cur_offset();
           return false;
         }
         SignedType signed_offset =
@@ -78,7 +81,7 @@
       case 3: {
         if (cie_loc_regs_ == nullptr) {
           log(0, "restore while processing cie");
-          last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+          last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
           return false;
         }
 
@@ -93,7 +96,7 @@
       case 0: {
         const auto handle_func = DwarfCfa<AddressType>::kCallbackTable[cfa_low];
         if (handle_func == nullptr) {
-          last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+          last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
           return false;
         }
 
@@ -102,7 +105,8 @@
           if (cfa->operands[i] == DW_EH_PE_block) {
             uint64_t block_length;
             if (!memory_->ReadULEB128(&block_length)) {
-              last_error_ = DWARF_ERROR_MEMORY_INVALID;
+              last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+              last_error_.address = memory_->cur_offset();
               return false;
             }
             operands_.push_back(block_length);
@@ -111,7 +115,8 @@
           }
           uint64_t value;
           if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
-            last_error_ = DWARF_ERROR_MEMORY_INVALID;
+            last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+            last_error_.address = memory_->cur_offset();
             return false;
           }
           operands_.push_back(value);
@@ -334,7 +339,7 @@
   AddressType reg = operands_[0];
   if (cie_loc_regs_ == nullptr) {
     log(0, "restore while processing cie");
-    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
     return false;
   }
   auto reg_entry = cie_loc_regs_->find(reg);
@@ -396,7 +401,7 @@
   auto cfa_location = loc_regs->find(CFA_REG);
   if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
     log(0, "Attempt to set new register, but cfa is not already set to a register.");
-    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
     return false;
   }
 
@@ -410,7 +415,7 @@
   auto cfa_location = loc_regs->find(CFA_REG);
   if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
     log(0, "Attempt to set offset, but cfa is not set to a register.");
-    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
     return false;
   }
   cfa_location->second.values[1] = operands_[0];
@@ -454,7 +459,7 @@
   auto cfa_location = loc_regs->find(CFA_REG);
   if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
     log(0, "Attempt to set offset, but cfa is not set to a register.");
-    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
     return false;
   }
   SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index 62b9b7a..16c66e2 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -24,12 +24,11 @@
 #include <type_traits>
 #include <vector>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfStructs.h>
 
-#include "DwarfError.h"
-
 namespace unwindstack {
 
 // DWARF Standard home: http://dwarfstd.org/
@@ -75,7 +74,9 @@
   bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset,
            uint64_t end_offset);
 
-  DwarfError last_error() { return last_error_; }
+  const DwarfErrorData& last_error() { return last_error_; }
+  DwarfErrorCode LastErrorCode() { return last_error_.code; }
+  uint64_t LastErrorAddress() { return last_error_.address; }
 
   AddressType cur_pc() { return cur_pc_; }
 
@@ -89,7 +90,7 @@
   bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc);
 
  private:
-  DwarfError last_error_;
+  DwarfErrorData last_error_;
   DwarfMemory* memory_;
   const DwarfFde* fde_;
 
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 2589c89..7a41e45 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -46,4 +46,4 @@
 
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
+#endif  // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index 0337dba..9a49013 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -16,12 +16,12 @@
 
 #include <stdint.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfStructs.h>
 #include <unwindstack/Memory.h>
 
 #include "Check.h"
 #include "DwarfEhFrameWithHdr.h"
-#include "DwarfError.h"
 
 namespace unwindstack {
 
@@ -36,14 +36,15 @@
 
   // Read the first four bytes all at once.
   if (!memory_.ReadBytes(data, 4)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
   version_ = data[0];
   if (version_ != 1) {
     // Unknown version.
-    last_error_ = DWARF_ERROR_UNSUPPORTED_VERSION;
+    last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
     return false;
   }
 
@@ -54,13 +55,20 @@
 
   memory_.set_pc_offset(memory_.cur_offset());
   if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
   memory_.set_pc_offset(memory_.cur_offset());
   if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  if (fde_count_ == 0) {
+    last_error_.code = DWARF_ERROR_NO_FDES;
     return false;
   }
 
@@ -96,11 +104,12 @@
   uint64_t value;
   if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
       !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     fde_info_.erase(index);
     return nullptr;
   }
-  info->pc = value + 4;
+  info->pc = value;
   return info;
 }
 
@@ -142,7 +151,9 @@
 template <typename AddressType>
 bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
   CHECK(fde_count_ != 0);
-  last_error_ = DWARF_ERROR_NONE;
+  last_error_.code = DWARF_ERROR_NONE;
+  last_error_.address = 0;
+
   // We can do a binary search if the pc is in the range of the elements
   // that have already been cached.
   if (!fde_info_.empty()) {
@@ -171,14 +182,16 @@
     memory_.set_pc_offset(memory_.cur_offset());
     uint64_t value;
     if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
 
     FdeInfo* info = &fde_info_[current];
     if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
       fde_info_.erase(current);
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     info->pc = value + 4;
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index 3b3d340..dcf04e6 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -22,12 +22,12 @@
 
 #include <android-base/stringprintf.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/Log.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 namespace unwindstack {
@@ -48,7 +48,7 @@
     // To protect against a branch that creates an infinite loop,
     // terminate if the number of iterations gets too high.
     if (iterations++ == 1000) {
-      last_error_ = DWARF_ERROR_TOO_MANY_ITERATIONS;
+      last_error_.code = DWARF_ERROR_TOO_MANY_ITERATIONS;
       return false;
     }
   }
@@ -57,28 +57,29 @@
 
 template <typename AddressType>
 bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
-  last_error_ = DWARF_ERROR_NONE;
+  last_error_.code = DWARF_ERROR_NONE;
   if (!memory_->ReadBytes(&cur_op_, 1)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_->cur_offset();
     return false;
   }
 
   const auto* op = &kCallbackTable[cur_op_];
   const auto handle_func = op->handle_func;
   if (handle_func == nullptr) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
 
   // Check for an unsupported opcode.
   if (dwarf_version < op->supported_version) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
 
   // Make sure that the required number of stack elements is available.
   if (stack_.size() < op->num_required_stack_values) {
-    last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID;
+    last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
     return false;
   }
 
@@ -86,7 +87,8 @@
   for (size_t i = 0; i < op->num_operands; i++) {
     uint64_t value;
     if (!memory_->ReadEncodedValue<AddressType>(op->operands[i], &value)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_->cur_offset();
       return false;
     }
     operands_.push_back(value);
@@ -142,7 +144,8 @@
   AddressType addr = StackPop();
   AddressType value;
   if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = addr;
     return false;
   }
   stack_.push_front(value);
@@ -153,14 +156,15 @@
 bool DwarfOp<AddressType>::op_deref_size() {
   AddressType bytes_to_read = OperandAt(0);
   if (bytes_to_read > sizeof(AddressType) || bytes_to_read == 0) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
   // Read the address and dereference it.
   AddressType addr = StackPop();
   AddressType value = 0;
   if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = addr;
     return false;
   }
   stack_.push_front(value);
@@ -198,7 +202,7 @@
 bool DwarfOp<AddressType>::op_pick() {
   AddressType index = OperandAt(0);
   if (index > StackSize()) {
-    last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID;
+    last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
     return false;
   }
   stack_.push_front(StackAt(index));
@@ -243,7 +247,7 @@
 bool DwarfOp<AddressType>::op_div() {
   AddressType top = StackPop();
   if (top == 0) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
   SignedType signed_divisor = static_cast<SignedType>(top);
@@ -263,7 +267,7 @@
 bool DwarfOp<AddressType>::op_mod() {
   AddressType top = StackPop();
   if (top == 0) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
   stack_[0] %= top;
@@ -431,7 +435,7 @@
 bool DwarfOp<AddressType>::op_breg() {
   uint16_t reg = cur_op() - 0x70;
   if (reg >= regs_->total_regs()) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
   stack_.push_front((*regs_)[reg] + OperandAt(0));
@@ -442,7 +446,7 @@
 bool DwarfOp<AddressType>::op_bregx() {
   AddressType reg = OperandAt(0);
   if (reg >= regs_->total_regs()) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
   stack_.push_front((*regs_)[reg] + OperandAt(1));
@@ -456,7 +460,7 @@
 
 template <typename AddressType>
 bool DwarfOp<AddressType>::op_not_implemented() {
-  last_error_ = DWARF_ERROR_NOT_IMPLEMENTED;
+  last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
   return false;
 }
 
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index c29bf35..40b7b23 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -24,8 +24,9 @@
 #include <type_traits>
 #include <vector>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 namespace unwindstack {
 
@@ -72,7 +73,9 @@
 
   void set_regs(RegsImpl<AddressType>* regs) { regs_ = regs; }
 
-  DwarfError last_error() { return last_error_; }
+  const DwarfErrorData& last_error() { return last_error_; }
+  DwarfErrorCode LastErrorCode() { return last_error_.code; }
+  uint64_t LastErrorAddress() { return last_error_.address; }
 
   bool is_register() { return is_register_; }
 
@@ -96,7 +99,7 @@
 
   RegsImpl<AddressType>* regs_;
   bool is_register_ = false;
-  DwarfError last_error_ = DWARF_ERROR_NONE;
+  DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
   uint8_t cur_op_;
   std::vector<AddressType> operands_;
   std::deque<AddressType> stack_;
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 91d855b..4e94f88 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -16,6 +16,7 @@
 
 #include <stdint.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfSection.h>
@@ -26,7 +27,6 @@
 
 #include "DwarfCfa.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 #include "DwarfDebugFrame.h"
@@ -36,7 +36,7 @@
 
 constexpr uint64_t DEX_PC_REG = 0x20444558;
 
-DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
+DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
 
 const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
   uint64_t fde_offset;
@@ -52,15 +52,15 @@
   if (pc < fde->pc_end) {
     return fde;
   }
-  last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+  last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
   return nullptr;
 }
 
 bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
-  last_error_ = DWARF_ERROR_NONE;
+  last_error_.code = DWARF_ERROR_NONE;
   const DwarfFde* fde = GetFdeFromPc(pc);
   if (fde == nullptr || fde->cie == nullptr) {
-    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
     return false;
   }
 
@@ -87,12 +87,12 @@
     return false;
   }
   if (op.StackSize() == 0) {
-    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
     return false;
   }
   // We don't support an expression that evaluates to a register number.
   if (op.is_register()) {
-    last_error_ = DWARF_ERROR_NOT_IMPLEMENTED;
+    last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
     return false;
   }
   *value = op.StackAt(0);
@@ -119,7 +119,8 @@
   switch (loc->type) {
     case DWARF_LOCATION_OFFSET:
       if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = eval_info->cfa + loc->values[0];
         return false;
       }
       break;
@@ -129,7 +130,7 @@
     case DWARF_LOCATION_REGISTER: {
       uint32_t cur_reg = loc->values[0];
       if (cur_reg >= eval_info->cur_regs->total_regs()) {
-        last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+        last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
         return false;
       }
       AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
@@ -158,7 +159,8 @@
       }
       if (loc->type == DWARF_LOCATION_EXPRESSION) {
         if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = value;
           return false;
         }
       } else {
@@ -183,14 +185,14 @@
                                          bool* finished) {
   RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs);
   if (cie->return_address_register >= cur_regs->total_regs()) {
-    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
     return false;
   }
 
   // Get the cfa value;
   auto cfa_entry = loc_regs.find(CFA_REG);
   if (cfa_entry == loc_regs.end()) {
-    last_error_ = DWARF_ERROR_CFA_NOT_DEFINED;
+    last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED;
     return false;
   }
 
@@ -206,7 +208,7 @@
   switch (loc->type) {
     case DWARF_LOCATION_REGISTER:
       if (loc->values[0] >= cur_regs->total_regs()) {
-        last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+        last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
         return false;
       }
       // If the stack pointer register is the CFA, and the stack
@@ -227,7 +229,8 @@
       }
       if (loc->type == DWARF_LOCATION_EXPRESSION) {
         if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = value;
           return false;
         }
       } else {
@@ -236,7 +239,7 @@
       break;
     }
     default:
-      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
       return false;
   }
 
@@ -305,7 +308,8 @@
 bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
   uint32_t length32;
   if (!memory_.ReadBytes(&length32, sizeof(length32))) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   // Set the default for the lsda encoding.
@@ -315,7 +319,8 @@
     // 64 bit Cie
     uint64_t length64;
     if (!memory_.ReadBytes(&length64, sizeof(length64))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
 
@@ -324,12 +329,13 @@
 
     uint64_t cie_id;
     if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     if (cie_id != cie64_value_) {
       // This is not a Cie, something has gone horribly wrong.
-      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
       return false;
     }
   } else {
@@ -339,24 +345,26 @@
 
     uint32_t cie_id;
     if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     if (cie_id != cie32_value_) {
       // This is not a Cie, something has gone horribly wrong.
-      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
       return false;
     }
   }
 
   if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
   if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
     // Unrecognized version.
-    last_error_ = DWARF_ERROR_UNSUPPORTED_VERSION;
+    last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
     return false;
   }
 
@@ -364,7 +372,8 @@
   char aug_value;
   do {
     if (!memory_.ReadBytes(&aug_value, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     cie->augmentation_string.push_back(aug_value);
@@ -376,20 +385,23 @@
 
     // Segment Size
     if (!memory_.ReadBytes(&cie->segment_size, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
   }
 
   // Code Alignment Factor
   if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
   // Data Alignment Factor
   if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
@@ -397,12 +409,14 @@
     // Return Address is a single byte.
     uint8_t return_address_register;
     if (!memory_.ReadBytes(&return_address_register, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     cie->return_address_register = return_address_register;
   } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
@@ -413,7 +427,8 @@
 
   uint64_t aug_length;
   if (!memory_.ReadULEB128(&aug_length)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
@@ -422,24 +437,28 @@
     switch (cie->augmentation_string[i]) {
       case 'L':
         if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
           return false;
         }
         break;
       case 'P': {
         uint8_t encoding;
         if (!memory_.ReadBytes(&encoding, 1)) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
           return false;
         }
         if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
           return false;
         }
       } break;
       case 'R':
         if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
           return false;
         }
         break;
@@ -467,7 +486,8 @@
 bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
   uint32_t length32;
   if (!memory_.ReadBytes(&length32, sizeof(length32))) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
 
@@ -475,19 +495,21 @@
     // 64 bit Fde.
     uint64_t length64;
     if (!memory_.ReadBytes(&length64, sizeof(length64))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     fde->cfa_instructions_end = memory_.cur_offset() + length64;
 
     uint64_t value64;
     if (!memory_.ReadBytes(&value64, sizeof(value64))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     if (value64 == cie64_value_) {
       // This is a Cie, this means something has gone wrong.
-      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
       return false;
     }
 
@@ -500,12 +522,13 @@
 
     uint32_t value32;
     if (!memory_.ReadBytes(&value32, sizeof(value32))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     if (value32 == cie32_value_) {
       // This is a Cie, this means something has gone wrong.
-      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
       return false;
     }
 
@@ -528,13 +551,15 @@
   memory_.set_cur_offset(cur_offset);
 
   if (!memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding & 0xf, &fde->pc_start)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   fde->pc_start = AdjustPcFromFde(fde->pc_start);
 
   if (!memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding & 0xf, &fde->pc_end)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   fde->pc_end += fde->pc_start;
@@ -542,13 +567,15 @@
     // Augmentation Size
     uint64_t aug_length;
     if (!memory_.ReadULEB128(&aug_length)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     uint64_t cur_offset = memory_.cur_offset();
 
     if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
 
@@ -619,7 +646,8 @@
 bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
   uint8_t version;
   if (!memory_.ReadBytes(&version, 1)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   // Read the augmentation string.
@@ -628,7 +656,8 @@
   bool get_encoding = false;
   do {
     if (!memory_.ReadBytes(&aug_value, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
     if (aug_value == 'R') {
@@ -643,7 +672,8 @@
 
     // Read the segment size.
     if (!memory_.ReadBytes(segment_size, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
   } else {
@@ -659,7 +689,8 @@
   uint8_t value;
   do {
     if (!memory_.ReadBytes(&value, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
   } while (value & 0x80);
@@ -667,7 +698,8 @@
   // Skip data alignment factor
   do {
     if (!memory_.ReadBytes(&value, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
   } while (value & 0x80);
@@ -679,7 +711,8 @@
     // Skip return address register.
     do {
       if (!memory_.ReadBytes(&value, 1)) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
     } while (value & 0x80);
@@ -688,7 +721,8 @@
   // Skip the augmentation length.
   do {
     if (!memory_.ReadBytes(&value, 1)) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
   } while (value & 0x80);
@@ -696,7 +730,8 @@
   for (size_t i = 1; i < aug_string.size(); i++) {
     if (aug_string[i] == 'R') {
       if (!memory_.ReadBytes(encoding, 1)) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
       // Got the encoding, that's all we are looking for.
@@ -706,12 +741,14 @@
     } else if (aug_string[i] == 'P') {
       uint8_t encoding;
       if (!memory_.ReadBytes(&encoding, 1)) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
       uint64_t value;
       if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
     }
@@ -730,14 +767,16 @@
 
   uint64_t start;
   if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &start)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   start = AdjustPcFromFde(start);
 
   uint64_t length;
   if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &length)) {
-    last_error_ = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
     return false;
   }
   if (length != 0) {
@@ -764,7 +803,8 @@
     // Figure out the entry length and type.
     uint32_t value32;
     if (!memory_.ReadBytes(&value32, sizeof(value32))) {
-      last_error_ = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
       return false;
     }
 
@@ -772,14 +812,16 @@
     if (value32 == static_cast<uint32_t>(-1)) {
       uint64_t value64;
       if (!memory_.ReadBytes(&value64, sizeof(value64))) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
       next_entry_offset = memory_.cur_offset() + value64;
 
       // Read the Cie Id of a Cie or the pointer of the Fde.
       if (!memory_.ReadBytes(&value64, sizeof(value64))) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
 
@@ -794,7 +836,7 @@
         uint64_t last_cie_offset = GetCieOffsetFromFde64(value64);
         if (last_cie_offset != cie_offset) {
           // This means that this Fde is not following the Cie.
-          last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+          last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
           return false;
         }
 
@@ -808,7 +850,8 @@
 
       // Read the Cie Id of a Cie or the pointer of the Fde.
       if (!memory_.ReadBytes(&value32, sizeof(value32))) {
-        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+        last_error_.address = memory_.cur_offset();
         return false;
       }
 
@@ -823,7 +866,7 @@
         uint64_t last_cie_offset = GetCieOffsetFromFde32(value32);
         if (last_cie_offset != cie_offset) {
           // This means that this Fde is not following the Cie.
-          last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+          last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
           return false;
         }
 
@@ -835,9 +878,8 @@
     }
 
     if (next_entry_offset < memory_.cur_offset()) {
-      // This indicates some kind of corruption, or malformed section data.
-      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
-      return false;
+      // Simply consider the processing done in this case.
+      break;
     }
     memory_.set_cur_offset(next_entry_offset);
   }
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 220e549..dbf772e 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -35,6 +35,10 @@
 
 namespace unwindstack {
 
+bool Elf::cache_enabled_;
+std::unordered_map<std::string, std::shared_ptr<Elf>>* Elf::cache_;
+std::mutex* Elf::cache_lock_;
+
 bool Elf::Init(bool init_gnu_debugdata) {
   load_bias_ = 0;
   if (!memory_) {
@@ -134,6 +138,26 @@
   return true;
 }
 
+void Elf::GetLastError(ErrorData* data) {
+  if (valid_) {
+    *data = interface_->last_error();
+  }
+}
+
+ErrorCode Elf::GetLastErrorCode() {
+  if (valid_) {
+    return interface_->LastErrorCode();
+  }
+  return ERROR_NONE;
+}
+
+uint64_t Elf::GetLastErrorAddress() {
+  if (valid_) {
+    return interface_->LastErrorAddress();
+  }
+  return 0;
+}
+
 // The relative pc is always relative to the start of the map from which it comes.
 bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
                Memory* process_memory, bool* finished) {
@@ -281,4 +305,42 @@
   return 0;
 }
 
+void Elf::SetCachingEnabled(bool enable) {
+  if (!cache_enabled_ && enable) {
+    cache_enabled_ = true;
+    cache_ = new std::unordered_map<std::string, std::shared_ptr<Elf>>;
+    cache_lock_ = new std::mutex;
+  } else if (cache_enabled_ && !enable) {
+    cache_enabled_ = false;
+    delete cache_;
+    delete cache_lock_;
+  }
+}
+
+void Elf::CacheLock() {
+  cache_lock_->lock();
+}
+
+void Elf::CacheUnlock() {
+  cache_lock_->unlock();
+}
+
+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;
+  }
+}
+
+bool Elf::CacheGet(const std::string& name, std::shared_ptr<Elf>* elf) {
+  auto entry = cache_->find(name);
+  if (entry != cache_->end()) {
+    *elf = entry->second;
+    return true;
+  }
+  return false;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 0e3ab2c..e413081 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -24,6 +24,7 @@
 #include <Xz.h>
 #include <XzCrc64.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfSection.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Log.h>
@@ -126,22 +127,26 @@
   if (eh_frame_hdr_offset_ != 0) {
     eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
     if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) {
-      // Even if the eh_frame_offset_ is non-zero, do not bother
-      // trying to read that since something has gone wrong.
       eh_frame_.reset(nullptr);
-      eh_frame_hdr_offset_ = 0;
-      eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
     }
-  } else if (eh_frame_offset_ != 0) {
-    // If there is a eh_frame section without a eh_frame_hdr section.
+  }
+
+  if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) {
+    // If there is an eh_frame section without an eh_frame_hdr section,
+    // or using the frame hdr object failed to init.
     eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
     if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
       eh_frame_.reset(nullptr);
-      eh_frame_offset_ = 0;
-      eh_frame_size_ = static_cast<uint64_t>(-1);
     }
   }
 
+  if (eh_frame_.get() == nullptr) {
+    eh_frame_hdr_offset_ = 0;
+    eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
+    eh_frame_offset_ = 0;
+    eh_frame_size_ = static_cast<uint64_t>(-1);
+  }
+
   if (debug_frame_offset_ != 0) {
     debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
     if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
@@ -156,6 +161,8 @@
 bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
   EhdrType ehdr;
   if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
+    last_error_.code = ERROR_MEMORY_INVALID;
+    last_error_.address = 0;
     return false;
   }
 
@@ -197,6 +204,9 @@
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
     PhdrType phdr;
     if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
+      last_error_.code = ERROR_MEMORY_INVALID;
+      last_error_.address =
+          offset + reinterpret_cast<uintptr_t>(&phdr.p_type) - reinterpret_cast<uintptr_t>(&phdr);
       return false;
     }
 
@@ -209,6 +219,9 @@
     {
       // Get the flags first, if this isn't an executable header, ignore it.
       if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_flags) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       if ((phdr.p_flags & PF_X) == 0) {
@@ -216,12 +229,21 @@
       }
 
       if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
@@ -234,11 +256,17 @@
 
     case PT_GNU_EH_FRAME:
       if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       // This is really the pointer to the .eh_frame_hdr section.
       eh_frame_hdr_offset_ = phdr.p_offset;
       if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       eh_frame_hdr_size_ = phdr.p_memsz;
@@ -246,14 +274,23 @@
 
     case PT_DYNAMIC:
       if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       dynamic_offset_ = phdr.p_offset;
       if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       dynamic_vaddr_ = phdr.p_vaddr;
       if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
+                              reinterpret_cast<uintptr_t>(&phdr);
         return false;
       }
       dynamic_size_ = phdr.p_memsz;
@@ -286,31 +323,47 @@
   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))) {
+      last_error_.code = ERROR_MEMORY_INVALID;
+      last_error_.address =
+          offset + reinterpret_cast<uintptr_t>(&shdr.sh_type) - reinterpret_cast<uintptr_t>(&shdr);
       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;
       if (shdr.sh_link >= ehdr.e_shnum) {
+        last_error_.code = ERROR_UNWIND_INFO;
         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))) {
+        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);
         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,
@@ -318,6 +371,9 @@
     } 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) {
@@ -373,6 +429,8 @@
   uint64_t max_offset = offset + dynamic_size_;
   for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
     if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
+      last_error_.code = ERROR_MEMORY_INVALID;
+      last_error_.address = offset;
       return false;
     }
 
@@ -430,21 +488,26 @@
 
 bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
                         bool* finished) {
+  last_error_.code = ERROR_NONE;
+  last_error_.address = 0;
+
   // Adjust the load bias to get the real relative pc.
   if (pc < load_bias) {
+    last_error_.code = ERROR_UNWIND_INFO;
     return false;
   }
   uint64_t adjusted_pc = pc - load_bias;
 
-  // Try the eh_frame first.
-  DwarfSection* eh_frame = eh_frame_.get();
-  if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
+  // Try the debug_frame first since it contains the most specific unwind
+  // information.
+  DwarfSection* debug_frame = debug_frame_.get();
+  if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
     return true;
   }
 
-  // Try the debug_frame next.
-  DwarfSection* debug_frame = debug_frame_.get();
-  if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
+  // Try the eh_frame next.
+  DwarfSection* eh_frame = eh_frame_.get();
+  if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
     return true;
   }
 
@@ -453,6 +516,46 @@
       gnu_debugdata_interface_->Step(pc, 0, regs, process_memory, finished)) {
     return true;
   }
+
+  // Set the error code based on the first error encountered.
+  DwarfSection* section = nullptr;
+  if (debug_frame_ != nullptr) {
+    section = debug_frame_.get();
+  } else if (eh_frame_ != nullptr) {
+    section = eh_frame_.get();
+  } else if (gnu_debugdata_interface_ != nullptr) {
+    last_error_ = gnu_debugdata_interface_->last_error();
+    return false;
+  } else {
+    return false;
+  }
+
+  // Convert the DWARF ERROR to an external error.
+  DwarfErrorCode code = section->LastErrorCode();
+  switch (code) {
+    case DWARF_ERROR_NONE:
+      last_error_.code = ERROR_NONE;
+      break;
+
+    case DWARF_ERROR_MEMORY_INVALID:
+      last_error_.code = ERROR_MEMORY_INVALID;
+      last_error_.address = section->LastErrorAddress();
+      break;
+
+    case DWARF_ERROR_ILLEGAL_VALUE:
+    case DWARF_ERROR_ILLEGAL_STATE:
+    case DWARF_ERROR_STACK_INDEX_NOT_VALID:
+    case DWARF_ERROR_TOO_MANY_ITERATIONS:
+    case DWARF_ERROR_CFA_NOT_DEFINED:
+    case DWARF_ERROR_NO_FDES:
+      last_error_.code = ERROR_UNWIND_INFO;
+      break;
+
+    case DWARF_ERROR_NOT_IMPLEMENTED:
+    case DWARF_ERROR_UNSUPPORTED_VERSION:
+      last_error_.code = ERROR_UNSUPPORTED;
+      break;
+  }
   return false;
 }
 
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 5d99bd7..dfb8e8f 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -17,17 +17,18 @@
 #include <elf.h>
 #include <stdint.h>
 
+#include <unwindstack/MachineArm.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsArm.h>
 
 #include "ArmExidx.h"
 #include "ElfInterfaceArm.h"
-#include "MachineArm.h"
 
 namespace unwindstack {
 
 bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
   if (start_offset_ == 0 || total_entries_ == 0) {
+    last_error_.code = ERROR_UNWIND_INFO;
     return false;
   }
 
@@ -56,12 +57,15 @@
     *entry_offset = start_offset_ + (last - 1) * 8;
     return true;
   }
+  last_error_.code = ERROR_UNWIND_INFO;
   return false;
 }
 
 bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) {
   uint32_t data;
   if (!memory_->Read32(offset, &data)) {
+    last_error_.code = ERROR_MEMORY_INVALID;
+    last_error_.address = offset;
     return false;
   }
 
@@ -106,6 +110,7 @@
                                 bool* finished) {
   // Adjust the load bias to get the real relative pc.
   if (pc < load_bias) {
+    last_error_.code = ERROR_UNWIND_INFO;
     return false;
   }
   pc -= load_bias;
@@ -139,6 +144,30 @@
     *finished = true;
     return true;
   }
+
+  if (!return_value) {
+    switch (arm.status()) {
+      case ARM_STATUS_NONE:
+      case ARM_STATUS_NO_UNWIND:
+      case ARM_STATUS_FINISH:
+        last_error_.code = ERROR_NONE;
+        break;
+
+      case ARM_STATUS_RESERVED:
+      case ARM_STATUS_SPARE:
+      case ARM_STATUS_TRUNCATED:
+      case ARM_STATUS_MALFORMED:
+      case ARM_STATUS_INVALID_ALIGNMENT:
+      case ARM_STATUS_INVALID_PERSONALITY:
+        last_error_.code = ERROR_UNWIND_INFO;
+        break;
+
+      case ARM_STATUS_READ_FAILED:
+        last_error_.code = ERROR_MEMORY_INVALID;
+        last_error_.address = arm.status_address();
+        break;
+    }
+  }
   return return_value;
 }
 
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index d1dc0e6..0c319ec 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -172,7 +172,7 @@
   // Regardless of what happens below, consider the init finished.
   initialized_ = true;
 
-  std::string descriptor_name("__jit_debug_descriptor");
+  const std::string descriptor_name("__jit_debug_descriptor");
   for (MapInfo* info : *maps) {
     if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
       continue;
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 89fe038..0c15335 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -109,16 +109,46 @@
   // Make sure no other thread is trying to add the elf to this map.
   std::lock_guard<std::mutex> guard(mutex_);
 
-  if (elf) {
-    return elf;
+  if (elf.get() != nullptr) {
+    return elf.get();
   }
 
-  elf = new Elf(CreateMemory(process_memory));
-  elf->Init(init_gnu_debugdata);
+  bool locked = false;
+  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)) {
+      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)) {
+      delete memory;
+      Elf::CacheUnlock();
+      return elf.get();
+    }
+  }
+  elf.reset(new Elf(memory));
   // If the init fails, keep the elf around as an invalid object so we
   // don't try to reinit the object.
-  return elf;
+  elf->Init(init_gnu_debugdata);
+
+  if (locked) {
+    Elf::CacheAdd(this);
+    Elf::CacheUnlock();
+  }
+  return elf.get();
 }
 
 uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 7feafad..c7dec52 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -25,17 +25,16 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsArm.h>
 #include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
 #include <unwindstack/RegsMips.h>
 #include <unwindstack/RegsMips64.h>
-
-#include "UserArm.h"
-#include "UserArm64.h"
-#include "UserX86.h"
-#include "UserX86_64.h"
-#include "UserMips.h"
-#include "UserMips64.h"
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
+#include <unwindstack/UserArm.h>
+#include <unwindstack/UserArm64.h>
+#include <unwindstack/UserMips.h>
+#include <unwindstack/UserMips64.h>
+#include <unwindstack/UserX86.h>
+#include <unwindstack/UserX86_64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
index d05c3e2..7f16146 100644
--- a/libunwindstack/RegsArm.cpp
+++ b/libunwindstack/RegsArm.cpp
@@ -19,13 +19,12 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineArm.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsArm.h>
-
-#include "MachineArm.h"
-#include "UcontextArm.h"
-#include "UserArm.h"
+#include <unwindstack/UcontextArm.h>
+#include <unwindstack/UserArm.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index 2077bc5..d6b467a 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -19,13 +19,12 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineArm64.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsArm64.h>
-
-#include "MachineArm64.h"
-#include "UcontextArm64.h"
-#include "UserArm64.h"
+#include <unwindstack/UcontextArm64.h>
+#include <unwindstack/UserArm64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
index 44cde05..6751f52 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -19,13 +19,12 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineMips.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsMips.h>
-
-#include "MachineMips.h"
-#include "UcontextMips.h"
-#include "UserMips.h"
+#include <unwindstack/UcontextMips.h>
+#include <unwindstack/UserMips.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
index b4e5246..97082bd 100644
--- a/libunwindstack/RegsMips64.cpp
+++ b/libunwindstack/RegsMips64.cpp
@@ -19,13 +19,12 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineMips64.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsMips64.h>
-
-#include "MachineMips64.h"
-#include "UcontextMips64.h"
-#include "UserMips64.h"
+#include <unwindstack/UcontextMips64.h>
+#include <unwindstack/UserMips64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
index ef2f3de..27476b7 100644
--- a/libunwindstack/RegsX86.cpp
+++ b/libunwindstack/RegsX86.cpp
@@ -19,13 +19,12 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineX86.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsX86.h>
-
-#include "MachineX86.h"
-#include "UcontextX86.h"
-#include "UserX86.h"
+#include <unwindstack/UcontextX86.h>
+#include <unwindstack/UserX86.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index 70921f8..0f66943 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -19,13 +19,12 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineX86_64.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsX86_64.h>
-
-#include "MachineX86_64.h"
-#include "UcontextX86_64.h"
-#include "UserX86_64.h"
+#include <unwindstack/UcontextX86_64.h>
+#include <unwindstack/UserX86_64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index d711772..5e32933 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -31,8 +31,53 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Unwinder.h>
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
+
 namespace unwindstack {
 
+// Inject extra 'virtual' frame that represents the dex pc data.
+// The dex pc is a magic register defined in the Mterp interpreter,
+// and thus it will be restored/observed in the frame after it.
+// Adding the dex frame first here will create something like:
+//   #7 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
+//   #8 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
+//   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
+void Unwinder::FillInDexFrame() {
+  size_t frame_num = frames_.size();
+  frames_.resize(frame_num + 1);
+  FrameData* frame = &frames_.at(frame_num);
+
+  uint64_t dex_pc = regs_->dex_pc();
+  frame->pc = dex_pc;
+  frame->sp = regs_->sp();
+
+  MapInfo* info = maps_->Find(dex_pc);
+  if (info != nullptr) {
+    frame->map_start = info->start;
+    frame->map_end = info->end;
+    frame->map_offset = info->offset;
+    frame->map_load_bias = info->load_bias;
+    frame->map_flags = info->flags;
+    frame->map_name = info->name;
+    frame->rel_pc = dex_pc - info->start;
+  } else {
+    frame->rel_pc = dex_pc;
+    return;
+  }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  if (dex_files_ == nullptr) {
+    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
+}
+
 void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
   size_t frame_num = frames_.size();
   frames_.resize(frame_num + 1);
@@ -40,14 +85,13 @@
   frame->num = frame_num;
   frame->sp = regs_->sp();
   frame->rel_pc = adjusted_rel_pc;
-  frame->dex_pc = regs_->dex_pc();
 
   if (map_info == nullptr) {
     frame->pc = regs_->pc();
     return;
   }
 
-  frame->pc = map_info->start + adjusted_rel_pc;
+  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;
@@ -78,6 +122,8 @@
 void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
                       const std::vector<std::string>* map_suffixes_to_ignore) {
   frames_.clear();
+  last_error_.code = ERROR_NONE;
+  last_error_.address = 0;
 
   bool return_address_attempt = false;
   bool adjust_pc = false;
@@ -95,6 +141,7 @@
       rel_pc = regs_->pc();
       adjusted_rel_pc = rel_pc;
       adjusted_pc = rel_pc;
+      last_error_.code = ERROR_INVALID_MAP;
     } else {
       if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
         break;
@@ -125,6 +172,13 @@
     if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
         std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
                   basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
+      if (regs_->dex_pc() != 0) {
+        // Add a frame to represent the dex file.
+        FillInDexFrame();
+        // Clear the dex pc so that we don't repeat this frame later.
+        regs_->set_dex_pc(0);
+      }
+
       FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
 
       // Once a frame is added, stop skipping frames.
@@ -155,6 +209,7 @@
           bool finished;
           stepped = elf->Step(rel_pc, adjusted_pc, map_info->elf_offset, regs_,
                               process_memory_.get(), &finished);
+          elf->GetLastError(&last_error_);
           if (stepped && finished) {
             break;
           }
@@ -180,10 +235,14 @@
       }
     } else {
       return_address_attempt = false;
+      if (max_frames_ == frames_.size()) {
+        last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
+      }
     }
 
     // If the pc and sp didn't change, then consider everything stopped.
     if (cur_pc == regs_->pc() && cur_sp == regs_->sp()) {
+      last_error_.code = ERROR_REPEATED_FRAME;
       break;
     }
   }
@@ -232,4 +291,11 @@
   jit_debug_ = jit_debug;
 }
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+  dex_files->SetArch(arch);
+  dex_files_ = dex_files;
+}
+#endif
+
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..26f5d35
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,78 @@
+/*
+ * 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 _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+class Memory;
+enum ArchEnum : uint8_t;
+
+class DexFiles {
+ public:
+  explicit DexFiles(std::shared_ptr<Memory>& memory);
+  DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  ~DexFiles();
+
+  DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
+
+  void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
+                            uint64_t* method_offset);
+
+  void SetArch(ArchEnum arch);
+
+ private:
+  void Init(Maps* maps);
+
+  bool GetAddr(size_t index, uint64_t* addr);
+
+  uint64_t ReadEntryPtr32(uint64_t addr);
+
+  uint64_t ReadEntryPtr64(uint64_t addr);
+
+  bool ReadEntry32();
+
+  bool ReadEntry64();
+
+  std::shared_ptr<Memory> memory_;
+  std::vector<std::string> search_libs_;
+
+  std::mutex lock_;
+  bool initialized_ = false;
+  std::unordered_map<uint64_t, DexFile*> files_;
+
+  uint64_t entry_addr_ = 0;
+  uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
+  bool (DexFiles::*read_entry_func_)() = nullptr;
+  std::vector<uint64_t> addrs_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/DwarfError.h b/libunwindstack/include/unwindstack/DwarfError.h
similarity index 89%
rename from libunwindstack/DwarfError.h
rename to libunwindstack/include/unwindstack/DwarfError.h
index 54199b8..763e2cb 100644
--- a/libunwindstack/DwarfError.h
+++ b/libunwindstack/include/unwindstack/DwarfError.h
@@ -21,7 +21,7 @@
 
 namespace unwindstack {
 
-enum DwarfError : uint8_t {
+enum DwarfErrorCode : uint8_t {
   DWARF_ERROR_NONE,
   DWARF_ERROR_MEMORY_INVALID,
   DWARF_ERROR_ILLEGAL_VALUE,
@@ -31,6 +31,12 @@
   DWARF_ERROR_TOO_MANY_ITERATIONS,
   DWARF_ERROR_CFA_NOT_DEFINED,
   DWARF_ERROR_UNSUPPORTED_VERSION,
+  DWARF_ERROR_NO_FDES,
+};
+
+struct DwarfErrorData {
+  DwarfErrorCode code;
+  uint64_t address;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index e0004aa..03f40d6 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -22,6 +22,7 @@
 #include <iterator>
 #include <unordered_map>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfStructs.h>
@@ -29,7 +30,6 @@
 namespace unwindstack {
 
 // Forward declarations.
-enum DwarfError : uint8_t;
 class Memory;
 class Regs;
 
@@ -72,7 +72,8 @@
   iterator begin() { return iterator(this, 0); }
   iterator end() { return iterator(this, fde_count_); }
 
-  DwarfError last_error() { return last_error_; }
+  DwarfErrorCode LastErrorCode() { return last_error_.code; }
+  uint64_t LastErrorAddress() { return last_error_.address; }
 
   virtual bool Init(uint64_t offset, uint64_t size) = 0;
 
@@ -100,7 +101,7 @@
 
  protected:
   DwarfMemory memory_;
-  DwarfError last_error_;
+  DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
 
   uint32_t cie32_value_ = 0;
   uint64_t cie64_value_ = 0;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 5f34391..a874709 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -22,6 +22,7 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <unordered_map>
 
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Memory.h>
@@ -72,6 +73,10 @@
 
   bool IsValidPc(uint64_t pc);
 
+  void GetLastError(ErrorData* data);
+  ErrorCode GetLastErrorCode();
+  uint64_t GetLastErrorAddress();
+
   bool valid() { return valid_; }
 
   uint32_t machine_type() { return machine_type_; }
@@ -92,6 +97,14 @@
 
   static uint64_t GetLoadBias(Memory* memory);
 
+  static void SetCachingEnabled(bool enable);
+  static bool CachingEnabled() { return cache_enabled_; }
+
+  static void CacheLock();
+  static void CacheUnlock();
+  static void CacheAdd(MapInfo* info);
+  static bool CacheGet(const std::string& name, std::shared_ptr<Elf>* elf);
+
  protected:
   bool valid_ = false;
   uint64_t load_bias_ = 0;
@@ -105,6 +118,10 @@
 
   std::unique_ptr<Memory> gnu_debugdata_memory_;
   std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
+
+  static bool cache_enabled_;
+  static std::unordered_map<std::string, std::shared_ptr<Elf>>* cache_;
+  static std::mutex* cache_lock_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index faa61ee..ea9ec9d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include <unwindstack/DwarfSection.h>
+#include <unwindstack/Error.h>
 
 namespace unwindstack {
 
@@ -90,6 +91,10 @@
   DwarfSection* eh_frame() { return eh_frame_.get(); }
   DwarfSection* debug_frame() { return debug_frame_.get(); }
 
+  const ErrorData& last_error() { return last_error_; }
+  ErrorCode LastErrorCode() { return last_error_.code; }
+  uint64_t LastErrorAddress() { return last_error_.address; }
+
   template <typename EhdrType, typename PhdrType>
   static uint64_t GetLoadBias(Memory* memory);
 
@@ -144,6 +149,8 @@
   uint8_t soname_type_ = SONAME_UNKNOWN;
   std::string soname_;
 
+  ErrorData last_error_{ERROR_NONE, 0};
+
   std::unique_ptr<DwarfSection> eh_frame_;
   std::unique_ptr<DwarfSection> debug_frame_;
   // The Elf object owns the gnu_debugdata interface object.
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
new file mode 100644
index 0000000..6ed0e0f
--- /dev/null
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -0,0 +1,42 @@
+/*
+ * 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 _LIBUNWINDSTACK_ERROR_H
+#define _LIBUNWINDSTACK_ERROR_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum ErrorCode : uint8_t {
+  ERROR_NONE,                 // No error.
+  ERROR_MEMORY_INVALID,       // Memory read failed.
+  ERROR_UNWIND_INFO,          // Unable to use unwind information to unwind.
+  ERROR_UNSUPPORTED,          // Encountered unsupported feature.
+  ERROR_INVALID_MAP,          // Unwind in an invalid map.
+  ERROR_MAX_FRAMES_EXCEEDED,  // The number of frames exceed the total allowed.
+  ERROR_REPEATED_FRAME,       // The last frame has the same pc/sp as the next.
+};
+
+struct ErrorData {
+  ErrorCode code;
+  uint64_t address;  // Only valid when code is ERROR_MEMORY_INVALID.
+                     // Indicates the failing address.
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/MachineArm.h b/libunwindstack/include/unwindstack/MachineArm.h
similarity index 100%
rename from libunwindstack/MachineArm.h
rename to libunwindstack/include/unwindstack/MachineArm.h
diff --git a/libunwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
similarity index 100%
rename from libunwindstack/MachineArm64.h
rename to libunwindstack/include/unwindstack/MachineArm64.h
diff --git a/libunwindstack/MachineMips.h b/libunwindstack/include/unwindstack/MachineMips.h
similarity index 100%
rename from libunwindstack/MachineMips.h
rename to libunwindstack/include/unwindstack/MachineMips.h
diff --git a/libunwindstack/MachineMips64.h b/libunwindstack/include/unwindstack/MachineMips64.h
similarity index 100%
rename from libunwindstack/MachineMips64.h
rename to libunwindstack/include/unwindstack/MachineMips64.h
diff --git a/libunwindstack/MachineX86.h b/libunwindstack/include/unwindstack/MachineX86.h
similarity index 100%
rename from libunwindstack/MachineX86.h
rename to libunwindstack/include/unwindstack/MachineX86.h
diff --git a/libunwindstack/MachineX86_64.h b/libunwindstack/include/unwindstack/MachineX86_64.h
similarity index 100%
rename from libunwindstack/MachineX86_64.h
rename to libunwindstack/include/unwindstack/MachineX86_64.h
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 22e48f7..a57fe68 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include <atomic>
+#include <memory>
 #include <mutex>
 #include <string>
 
@@ -40,14 +41,14 @@
         flags(flags),
         name(name),
         load_bias(static_cast<uint64_t>(-1)) {}
-  ~MapInfo() { delete elf; }
+  ~MapInfo() = default;
 
   uint64_t start = 0;
   uint64_t end = 0;
   uint64_t offset = 0;
   uint16_t flags = 0;
   std::string name;
-  Elf* elf = nullptr;
+  std::shared_ptr<Elf> elf;
   // This value is only non-zero if the offset is non-zero but there is
   // no elf signature found at that offset. This indicates that the
   // entire file is represented by the Memory object returned by CreateMemory,
diff --git a/libunwindstack/UcontextArm.h b/libunwindstack/include/unwindstack/UcontextArm.h
similarity index 98%
rename from libunwindstack/UcontextArm.h
rename to libunwindstack/include/unwindstack/UcontextArm.h
index 8c94166..7d1ec3b 100644
--- a/libunwindstack/UcontextArm.h
+++ b/libunwindstack/include/unwindstack/UcontextArm.h
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 
-#include "MachineArm.h"
+#include <unwindstack/MachineArm.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/UcontextArm64.h b/libunwindstack/include/unwindstack/UcontextArm64.h
similarity index 98%
rename from libunwindstack/UcontextArm64.h
rename to libunwindstack/include/unwindstack/UcontextArm64.h
index 655719f..a68be3b 100644
--- a/libunwindstack/UcontextArm64.h
+++ b/libunwindstack/include/unwindstack/UcontextArm64.h
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 
-#include "MachineArm64.h"
+#include <unwindstack/MachineArm64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/UcontextMips.h b/libunwindstack/include/unwindstack/UcontextMips.h
similarity index 97%
rename from libunwindstack/UcontextMips.h
rename to libunwindstack/include/unwindstack/UcontextMips.h
index 27185e7..02e33b6 100644
--- a/libunwindstack/UcontextMips.h
+++ b/libunwindstack/include/unwindstack/UcontextMips.h
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 
-#include "MachineMips.h"
+#include <unwindstack/MachineMips.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/UcontextMips64.h b/libunwindstack/include/unwindstack/UcontextMips64.h
similarity index 96%
rename from libunwindstack/UcontextMips64.h
rename to libunwindstack/include/unwindstack/UcontextMips64.h
index 623bf3a..5b92a55 100644
--- a/libunwindstack/UcontextMips64.h
+++ b/libunwindstack/include/unwindstack/UcontextMips64.h
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 
-#include "MachineMips64.h"
+#include <unwindstack/MachineMips64.h>
 
 namespace unwindstack {
 
@@ -66,4 +66,4 @@
 
 }  // namespace unwindstack
 
-#endif  // _LIBUNWINDSTACK_UCONTEXT_MIPS6464_H
+#endif  // _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
diff --git a/libunwindstack/UcontextX86.h b/libunwindstack/include/unwindstack/UcontextX86.h
similarity index 98%
rename from libunwindstack/UcontextX86.h
rename to libunwindstack/include/unwindstack/UcontextX86.h
index f79d92b..c96ebb7 100644
--- a/libunwindstack/UcontextX86.h
+++ b/libunwindstack/include/unwindstack/UcontextX86.h
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 
-#include "MachineX86.h"
+#include <unwindstack/MachineX86.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/UcontextX86_64.h b/libunwindstack/include/unwindstack/UcontextX86_64.h
similarity index 98%
rename from libunwindstack/UcontextX86_64.h
rename to libunwindstack/include/unwindstack/UcontextX86_64.h
index 2b8bdc4..4e163e5 100644
--- a/libunwindstack/UcontextX86_64.h
+++ b/libunwindstack/include/unwindstack/UcontextX86_64.h
@@ -31,7 +31,7 @@
 
 #include <stdint.h>
 
-#include "MachineX86_64.h"
+#include <unwindstack/MachineX86_64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 32858ae..ebe7b0a 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include <unwindstack/Error.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
@@ -31,6 +32,7 @@
 namespace unwindstack {
 
 // Forward declarations.
+class DexFiles;
 class Elf;
 class JitDebug;
 enum ArchEnum : uint8_t;
@@ -41,17 +43,16 @@
   uint64_t rel_pc;
   uint64_t pc;
   uint64_t sp;
-  uint64_t dex_pc;
 
   std::string function_name;
-  uint64_t function_offset;
+  uint64_t function_offset = 0;
 
   std::string map_name;
-  uint64_t map_offset;
-  uint64_t map_start;
-  uint64_t map_end;
-  uint64_t map_load_bias;
-  int map_flags;
+  uint64_t map_offset = 0;
+  uint64_t map_start = 0;
+  uint64_t map_end = 0;
+  uint64_t map_load_bias = 0;
+  int map_flags = 0;
 };
 
 class Unwinder {
@@ -74,7 +75,15 @@
 
   void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+#endif
+
+  ErrorCode LastErrorCode() { return last_error_.code; }
+  uint64_t LastErrorAddress() { return last_error_.address; }
+
  private:
+  void FillInDexFrame();
   void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
 
   size_t max_frames_;
@@ -83,6 +92,10 @@
   std::vector<FrameData> frames_;
   std::shared_ptr<Memory> process_memory_;
   JitDebug* jit_debug_ = nullptr;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  DexFiles* dex_files_ = nullptr;
+#endif
+  ErrorData last_error_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/UserArm.h b/libunwindstack/include/unwindstack/UserArm.h
similarity index 100%
rename from libunwindstack/UserArm.h
rename to libunwindstack/include/unwindstack/UserArm.h
diff --git a/libunwindstack/UserArm64.h b/libunwindstack/include/unwindstack/UserArm64.h
similarity index 100%
rename from libunwindstack/UserArm64.h
rename to libunwindstack/include/unwindstack/UserArm64.h
diff --git a/libunwindstack/UserMips.h b/libunwindstack/include/unwindstack/UserMips.h
similarity index 100%
rename from libunwindstack/UserMips.h
rename to libunwindstack/include/unwindstack/UserMips.h
diff --git a/libunwindstack/UserMips64.h b/libunwindstack/include/unwindstack/UserMips64.h
similarity index 100%
rename from libunwindstack/UserMips64.h
rename to libunwindstack/include/unwindstack/UserMips64.h
diff --git a/libunwindstack/UserX86.h b/libunwindstack/include/unwindstack/UserX86.h
similarity index 100%
rename from libunwindstack/UserX86.h
rename to libunwindstack/include/unwindstack/UserX86.h
diff --git a/libunwindstack/UserX86_64.h b/libunwindstack/include/unwindstack/UserX86_64.h
similarity index 100%
rename from libunwindstack/UserX86_64.h
rename to libunwindstack/include/unwindstack/UserX86_64.h
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
index caad131..8d0f0e5 100644
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ b/libunwindstack/tests/ArmExidxExtractTest.cpp
@@ -257,22 +257,27 @@
 TEST_F(ArmExidxExtractTest, read_failures) {
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5004U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5000, 0x100);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5004U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5004, 0x100);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5104U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5104, 0x1);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5108U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5108, 0x01010203);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x510cU, exidx_->status_address());
 }
 
 TEST_F(ArmExidxExtractTest, malformed) {
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
new file mode 100644
index 0000000..6975c68
--- /dev/null
+++ b/libunwindstack/tests/DexFileData.h
@@ -0,0 +1,45 @@
+/*
+ * 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 _LIBUNWINDSTACK_DEXFILESDATA_H
+#define _LIBUNWINDSTACK_DEXFILESDATA_H
+
+namespace unwindstack {
+
+// Borrowed from art/dex/dex_file_test.cc.
+static constexpr uint32_t kDexData[] = {
+    0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+    0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+    0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+    0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+    0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+    0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+    0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+    0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+    0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+    0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+    0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+    0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+    0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+    0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+    0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+    0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+    0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEXFILESDATA_H
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
new file mode 100644
index 0000000..0b02c5b
--- /dev/null
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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 <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unordered_map>
+
+#include <android-base/test_utils.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include <dex/code_item_accessors-inl.h>
+#include <dex/standard_dex_file.h>
+
+#include <gtest/gtest.h>
+
+#include "DexFile.h"
+
+#include "DexFileData.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+TEST(DexFileTest, from_file_open_non_exist) {
+  DexFileFromFile dex_file;
+  ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+}
+
+TEST(DexFileTest, from_file_open_too_small) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+            static_cast<size_t>(
+                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+
+  // Header too small.
+  DexFileFromFile dex_file;
+  ASSERT_FALSE(dex_file.Open(0, tf.path));
+
+  // Header correct, file too small.
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
+  ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
+                                              tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+  ASSERT_FALSE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  DexFileFromFile dex_file;
+  ASSERT_TRUE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open_non_zero_offset) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  DexFileFromFile dex_file;
+  ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_header) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
+  DexFileFromMemory dex_file;
+
+  ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_data) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
+  DexFileFromMemory dex_file;
+
+  ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_open) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
+  DexFileFromMemory dex_file;
+
+  ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, create_using_file) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  MemoryFake memory;
+  MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_start) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  MemoryFake memory;
+  MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_offset) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  MemoryFake memory;
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_empty_file) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_does_not_exist) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_is_malformed) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(kDexData) - 10,
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
+
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+
+  // Check it came from memory by clearing memory and verifying it fails.
+  memory.Clear();
+  dex_file.reset(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file == nullptr);
+}
+
+TEST(DexFileTest, get_method_not_opened) {
+  std::string method("something");
+  uint64_t method_offset = 100;
+  DexFile dex_file;
+  dex_file.GetMethodInformation(0x100, &method, &method_offset);
+  EXPECT_EQ("something", method);
+  EXPECT_EQ(100U, method_offset);
+}
+
+TEST(DexFileTest, get_method) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+
+  std::string method;
+  uint64_t method_offset;
+  dex_file->GetMethodInformation(0x102, &method, &method_offset);
+  EXPECT_EQ("Main.<init>", method);
+  EXPECT_EQ(2U, method_offset);
+
+  method = "not_in_a_method";
+  method_offset = 0x123;
+  dex_file->GetMethodInformation(0x100000, &method, &method_offset);
+  EXPECT_EQ("not_in_a_method", method);
+  EXPECT_EQ(0x123U, method_offset);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
new file mode 100644
index 0000000..dca5605
--- /dev/null
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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 <elf.h>
+#include <string.h>
+
+#include <memory>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFileData.h"
+#include "ElfFake.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class DexFilesTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
+
+    dex_files_.reset(new DexFiles(process_memory_));
+    dex_files_->SetArch(ARCH_ARM);
+
+    maps_.reset(
+        new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
+                       "4000-6000 r--s 00000000 00:00 0\n"
+                       "6000-8000 -w-s 00000000 00:00 0\n"
+                       "a000-c000 r-xp 00000000 00:00 0\n"
+                       "c000-f000 rwxp 00000000 00:00 0\n"
+                       "f000-11000 r-xp 00000000 00:00 0\n"
+                       "100000-110000 rw-p 0000000 00:00 0\n"
+                       "200000-210000 rw-p 0000000 00:00 0\n"
+                       "300000-400000 rw-p 0000000 00:00 0\n"));
+    ASSERT_TRUE(maps_->Parse());
+
+    // Global variable in a section that is not readable/executable.
+    MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+    ASSERT_TRUE(map_info != nullptr);
+    MemoryFake* memory = new MemoryFake;
+    ElfFake* elf = new ElfFake(memory);
+    elf->FakeSetValid(true);
+    ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    map_info->elf.reset(elf);
+
+    // Global variable not set by default.
+    map_info = maps_->Get(kMapGlobalSetToZero);
+    ASSERT_TRUE(map_info != nullptr);
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
+    elf->FakeSetValid(true);
+    interface = new ElfInterfaceFake(memory);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    map_info->elf.reset(elf);
+
+    // Global variable set in this map.
+    map_info = maps_->Get(kMapGlobal);
+    ASSERT_TRUE(map_info != nullptr);
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
+    elf->FakeSetValid(true);
+    interface = new ElfInterfaceFake(memory);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    map_info->elf.reset(elf);
+  }
+
+  void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
+  void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
+  void WriteDex(uint64_t dex_file);
+
+  static constexpr size_t kMapGlobalNonReadableExectable = 3;
+  static constexpr size_t kMapGlobalSetToZero = 4;
+  static constexpr size_t kMapGlobal = 5;
+  static constexpr size_t kMapDexFileEntries = 7;
+  static constexpr size_t kMapDexFiles = 8;
+
+  std::shared_ptr<Memory> process_memory_;
+  MemoryFake* memory_;
+  std::unique_ptr<DexFiles> dex_files_;
+  std::unique_ptr<BufferMaps> maps_;
+};
+
+void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
+                                uint32_t dex_file) {
+  // Format of the 32 bit DEXFileEntry structure:
+  //   uint32_t next
+  memory_->SetData32(entry_addr, next);
+  //   uint32_t prev
+  memory_->SetData32(entry_addr + 4, prev);
+  //   uint32_t dex_file
+  memory_->SetData32(entry_addr + 8, dex_file);
+}
+
+void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
+                                uint64_t dex_file) {
+  // Format of the 64 bit DEXFileEntry structure:
+  //   uint64_t next
+  memory_->SetData64(entry_addr, next);
+  //   uint64_t prev
+  memory_->SetData64(entry_addr + 8, prev);
+  //   uint64_t dex_file
+  memory_->SetData64(entry_addr + 16, dex_file);
+}
+
+void DexFilesTest::WriteDex(uint64_t dex_file) {
+  memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
+}
+
+TEST_F(DexFilesTest, get_method_information_invalid) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFileEntries);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
+  EXPECT_EQ("nothing", method_name);
+  EXPECT_EQ(0x124U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_32) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_64) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  dex_files_->SetArch(ARCH_ARM64);
+  memory_->SetData64(0xf800, 0x200000);
+  WriteEntry64(0x200000, 0, 0, 0x301000);
+  WriteDex(0x301000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(2U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(4U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  dex_files_->SetArch(ARCH_ARM64);
+  memory_->SetData64(0xf800, 0x200000);
+  WriteEntry64(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry64(0x200100, 0, 0x200000, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(6U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_cached) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+
+  // Clear all memory and make sure that data is acquired from the cache.
+  memory_->Clear();
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_search_libs) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+  WriteDex(0x300000);
+
+  // Only search a given named list of libs.
+  std::vector<std::string> libs{"libart.so"};
+  dex_files_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  EXPECT_EQ("nothing", method_name);
+  EXPECT_EQ(0x124U, method_offset);
+
+  MapInfo* map_info = maps_->Get(kMapGlobal);
+  map_info->name = "/system/lib/libart.so";
+  dex_files_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
+  // Make sure that clearing out copy of the libs doesn't affect the
+  // DexFiles object.
+  libs.clear();
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(4U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  // First global variable found, but value is zero.
+  memory_->SetData32(0xc800, 0);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+
+  // Verify that second is ignored when first is set to non-zero
+  dex_files_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM);
+  method_name = "fail";
+  method_offset = 0x123;
+  memory_->SetData32(0xc800, 0x100000);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("fail", method_name);
+  EXPECT_EQ(0x123U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  // First global variable found, but value is zero.
+  memory_->SetData64(0xc800, 0);
+
+  memory_->SetData64(0xf800, 0x200000);
+  WriteEntry64(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->SetArch(ARCH_ARM64);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+
+  // Verify that second is ignored when first is set to non-zero
+  dex_files_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM64);
+  method_name = "fail";
+  method_offset = 0x123;
+  memory_->SetData32(0xc800, 0x100000);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("fail", method_name);
+  EXPECT_EQ(0x123U, method_offset);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 73a67ac..68dc30c 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -21,13 +21,13 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfStructs.h>
 #include <unwindstack/Log.h>
 
 #include "DwarfCfa.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -78,7 +78,7 @@
     dwarf_loc_regs_t loc_regs;
 
     ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode());
     ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
 
     ASSERT_EQ("", GetFakeLogPrint());
@@ -198,7 +198,7 @@
   dwarf_loc_regs_t loc_regs;
 
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
   ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
   ASSERT_EQ(0U, loc_regs.size());
 
@@ -227,7 +227,7 @@
   dwarf_loc_regs_t loc_regs;
 
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4000, 0x4002, &loc_regs));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
   ASSERT_EQ(0x4002U, this->dmem_->cur_offset());
   ASSERT_EQ(0U, loc_regs.size());
 
@@ -594,7 +594,7 @@
   // This fails because the cfa is not defined as a register.
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
   ASSERT_EQ(0U, loc_regs.size());
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
 
   ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n",
             GetFakeLogPrint());
@@ -637,7 +637,7 @@
   // This fails because the cfa is not defined as a register.
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
   ASSERT_EQ(0U, loc_regs.size());
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
 
   ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
             GetFakeLogPrint());
@@ -679,7 +679,7 @@
 
   // This fails because the cfa is not defined as a register.
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
 
   ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
             GetFakeLogPrint());
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 07204bc..c28a41e 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -19,9 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfDebugFrame.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -142,7 +143,46 @@
   this->memory_.SetData32(0x510c, 0x200);
 
   ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
+  // CIE 32 information.
+  this->memory_.SetData32(0x5000, 0xfc);
+  this->memory_.SetData32(0x5004, 0xffffffff);
+  this->memory_.SetData8(0x5008, 1);
+  this->memory_.SetData8(0x5009, '\0');
+
+  // FDE 32 information.
+  this->memory_.SetData32(0x5100, 0xfc);
+  this->memory_.SetData32(0x5104, 0);
+  this->memory_.SetData32(0x5108, 0x1500);
+  this->memory_.SetData32(0x510c, 0x200);
+
+  this->memory_.SetData32(0x5200, 0xfc);
+  this->memory_.SetData32(0x5204, 0);
+  this->memory_.SetData32(0x5208, 0x2500);
+  this->memory_.SetData32(0x520c, 0x300);
+
+  // CIE 32 information.
+  this->memory_.SetData32(0x5300, 0);
+  this->memory_.SetData32(0x5304, 0xffffffff);
+  this->memory_.SetData8(0x5308, 1);
+  this->memory_.SetData8(0x5309, '\0');
+
+  // FDE 32 information.
+  this->memory_.SetData32(0x5400, 0xfc);
+  this->memory_.SetData32(0x5404, 0x300);
+  this->memory_.SetData32(0x5408, 0x3500);
+  this->memory_.SetData32(0x540c, 0x400);
+
+  this->memory_.SetData32(0x5500, 0xfc);
+  this->memory_.SetData32(0x5504, 0x300);
+  this->memory_.SetData32(0x5508, 0x4500);
+  this->memory_.SetData32(0x550c, 0x500);
+
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
+  ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
 }
 
 TYPED_TEST_P(DwarfDebugFrameTest, Init64) {
@@ -228,7 +268,52 @@
   this->memory_.SetData64(0x511c, 0x200);
 
   ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
+  // CIE 64 information.
+  this->memory_.SetData32(0x5000, 0xffffffff);
+  this->memory_.SetData64(0x5004, 0xf4);
+  this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
+  this->memory_.SetData8(0x5014, 1);
+  this->memory_.SetData8(0x5015, '\0');
+
+  // FDE 64 information.
+  this->memory_.SetData32(0x5100, 0xffffffff);
+  this->memory_.SetData64(0x5104, 0xf4);
+  this->memory_.SetData64(0x510c, 0);
+  this->memory_.SetData64(0x5114, 0x1500);
+  this->memory_.SetData64(0x511c, 0x200);
+
+  this->memory_.SetData32(0x5200, 0xffffffff);
+  this->memory_.SetData64(0x5204, 0xf4);
+  this->memory_.SetData64(0x520c, 0);
+  this->memory_.SetData64(0x5214, 0x2500);
+  this->memory_.SetData64(0x521c, 0x300);
+
+  // CIE 64 information.
+  this->memory_.SetData32(0x5300, 0xffffffff);
+  this->memory_.SetData64(0x5304, 0);
+  this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
+  this->memory_.SetData8(0x5314, 1);
+  this->memory_.SetData8(0x5315, '\0');
+
+  // FDE 64 information.
+  this->memory_.SetData32(0x5400, 0xffffffff);
+  this->memory_.SetData64(0x5404, 0xf4);
+  this->memory_.SetData64(0x540c, 0x300);
+  this->memory_.SetData64(0x5414, 0x3500);
+  this->memory_.SetData64(0x541c, 0x400);
+
+  this->memory_.SetData32(0x5500, 0xffffffff);
+  this->memory_.SetData64(0x5504, 0xf4);
+  this->memory_.SetData64(0x550c, 0x300);
+  this->memory_.SetData64(0x5514, 0x4500);
+  this->memory_.SetData64(0x551c, 0x500);
+
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
+  ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
 }
 
 TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
@@ -320,11 +405,11 @@
   this->debug_frame_->TestSetFdeCount(0);
   uint64_t fde_offset;
   ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
 
   this->debug_frame_->TestSetFdeCount(9);
   ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
   // Odd number of elements.
   for (size_t i = 0; i < 9; i++) {
     TypeParam pc = 0x1000 * (i + 1);
@@ -338,7 +423,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
   }
 
   // Even number of elements.
@@ -360,7 +445,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
   }
 }
 
@@ -450,9 +535,11 @@
   EXPECT_EQ(0x20U, fde->cie->return_address_register);
 }
 
-REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie, Init64,
-                           Init64_fde_not_following_cie, Init_version1, Init_version4,
-                           GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie,
+                           Init32_do_not_fail_on_bad_next_entry, Init64,
+                           Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie,
+                           Init_version1, Init_version4, GetFdeOffsetFromPc, GetCieFde32,
+                           GetCieFde64);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 3a629f8..a73db65 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -19,9 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfEhFrame.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -142,7 +143,7 @@
   this->memory_.SetData32(0x510c, 0x200);
 
   ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init64) {
@@ -228,7 +229,7 @@
   this->memory_.SetData64(0x511c, 0x200);
 
   ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
@@ -320,11 +321,11 @@
   this->eh_frame_->TestSetFdeCount(0);
   uint64_t fde_offset;
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 
   this->eh_frame_->TestSetFdeCount(9);
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   // Odd number of elements.
   for (size_t i = 0; i < 9; i++) {
     TypeParam pc = 0x1000 * (i + 1);
@@ -337,7 +338,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   }
 
   // Even number of elements.
@@ -358,7 +359,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   }
 }
 
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 64b325b..4240419 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -19,9 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfEhFrameWithHdr.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -94,22 +95,32 @@
   EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
   EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
 
+  // Verify a zero fde count fails to init.
+  this->memory_.SetData32(0x1006, 0);
+  ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
+  ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->LastErrorCode());
+
   // Verify an unexpected version will cause a fail.
+  this->memory_.SetData32(0x1006, 126);
   this->memory_.SetData8(0x1000, 0);
   ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
-  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
   this->memory_.SetData8(0x1000, 2);
   ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
-  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
   this->eh_frame_->TestSetTableEntrySize(0x10);
   this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
+  this->eh_frame_->TestSetEntriesOffset(0x1000);
+
   ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
+  EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
   ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
+  EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
@@ -123,7 +134,7 @@
 
   auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x1384U, info->pc);
+  EXPECT_EQ(0x1380U, info->pc);
   EXPECT_EQ(0x1540U, info->offset);
 }
 
@@ -138,7 +149,7 @@
 
   auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x3344U, info->pc);
+  EXPECT_EQ(0x3340U, info->pc);
   EXPECT_EQ(0x3500U, info->offset);
 }
 
@@ -152,7 +163,7 @@
 
   auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x344U, info->pc);
+  EXPECT_EQ(0x340U, info->pc);
   EXPECT_EQ(0x500U, info->offset);
 
   // Clear the memory so that this will fail if it doesn't read cached data.
@@ -160,7 +171,7 @@
 
   info = this->eh_frame_->GetFdeInfoFromIndex(2);
   ASSERT_TRUE(info != nullptr);
-  EXPECT_EQ(0x344U, info->pc);
+  EXPECT_EQ(0x340U, info->pc);
   EXPECT_EQ(0x500U, info->offset);
 }
 
@@ -178,7 +189,7 @@
   uint64_t fde_offset;
   EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
   // Not an error, just not found.
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   // Even number of elements.
   for (size_t i = 0; i < 10; i++) {
     TypeParam pc = 0x1000 * (i + 1);
@@ -274,7 +285,7 @@
 
   uint64_t fde_offset;
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
@@ -282,7 +293,7 @@
 
   uint64_t fde_offset;
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) {
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index 234d1c9..3f09dd8 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -21,11 +21,11 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/Log.h>
 #include <unwindstack/Regs.h>
 
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 #include "MemoryFake.h"
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 2d5007b..036226d 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -21,10 +21,10 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/Log.h>
 
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 #include "MemoryFake.h"
@@ -53,13 +53,14 @@
 TYPED_TEST_P(DwarfOpTest, decode) {
   // Memory error.
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  EXPECT_EQ(0U, this->op_->LastErrorAddress());
 
   // No error.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x96});
   this->mem_->set_cur_offset(0);
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
   ASSERT_EQ(0x96U, this->op_->cur_op());
   ASSERT_EQ(1U, this->mem_->cur_offset());
 }
@@ -67,7 +68,8 @@
 TYPED_TEST_P(DwarfOpTest, eval) {
   // Memory error.
   ASSERT_FALSE(this->op_->Eval(0, 2, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  EXPECT_EQ(0U, this->op_->LastErrorAddress());
 
   // Register set.
   // Do this first, to verify that subsequent calls reset the value.
@@ -84,7 +86,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_TRUE(this->op_->Eval(0, 8, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
   ASSERT_FALSE(this->op_->is_register());
   ASSERT_EQ(8U, this->mem_->cur_offset());
   ASSERT_EQ(4U, this->op_->StackSize());
@@ -96,7 +98,7 @@
   // Infinite loop.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x2f, 0xfd, 0xff});
   ASSERT_FALSE(this->op_->Eval(0, 4, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->LastErrorCode());
   ASSERT_FALSE(this->op_->is_register());
   ASSERT_EQ(0U, this->op_->StackSize());
 }
@@ -111,7 +113,7 @@
 
   for (size_t i = 0; i < opcode_buffer.size(); i++) {
     ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
     ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
   }
 }
@@ -122,7 +124,7 @@
 
   for (size_t i = 0; i < opcode_buffer.size(); i++) {
     ASSERT_FALSE(this->op_->Decode(2));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
     ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
   }
 }
@@ -133,7 +135,7 @@
 
   for (size_t i = 0; i < opcode_buffer.size(); i++) {
     ASSERT_FALSE(this->op_->Decode(3));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
     ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
   }
 }
@@ -178,7 +180,7 @@
 
   while (this->mem_->cur_offset() < opcode_buffer.size()) {
     ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-    ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->LastErrorCode());
   }
 }
 
@@ -216,7 +218,7 @@
   this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -226,7 +228,8 @@
   ASSERT_EQ(value, this->op_->StackAt(0));
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  ASSERT_EQ(0x12345678U, this->op_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_deref_size) {
@@ -235,7 +238,7 @@
   this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   // Read all byte sizes up to the sizeof the type.
   for (size_t i = 1; i < sizeof(TypeParam); i++) {
@@ -252,17 +255,18 @@
   // Zero byte read.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, 0x00});
   ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 
   // Read too many bytes.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, sizeof(TypeParam) + 1});
   ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 
   // Force bad memory read.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x40, 0x94, 0x01});
   ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  EXPECT_EQ(0x4010U, this->op_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfOpTest, const_unsigned) {
@@ -529,7 +533,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x12, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -577,7 +581,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x13, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_over) {
@@ -612,7 +616,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x14, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_pick) {
@@ -654,7 +658,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x15, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_swap) {
@@ -686,7 +690,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x16, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_rot) {
@@ -703,19 +707,19 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(3U, this->op_->StackSize());
@@ -753,7 +757,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -805,13 +809,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   // Two positive values.
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
@@ -854,7 +858,7 @@
   ASSERT_EQ(5U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_div) {
@@ -871,13 +875,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -902,13 +906,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -935,13 +939,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -957,7 +961,7 @@
   ASSERT_EQ(3U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_mul) {
@@ -974,13 +978,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1003,7 +1007,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -1034,7 +1038,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -1067,13 +1071,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1098,13 +1102,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1125,7 +1129,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -1150,13 +1154,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1181,13 +1185,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1216,13 +1220,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1247,13 +1251,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1280,7 +1284,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   // Push on a non-zero value with a positive branch.
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
@@ -1342,12 +1346,12 @@
 
     ASSERT_FALSE(this->op_->Eval(0, 1, DWARF_VERSION_MAX));
     ASSERT_EQ(opcode, this->op_->cur_op());
-    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
     ASSERT_FALSE(this->op_->Eval(1, 4, DWARF_VERSION_MAX));
     ASSERT_EQ(opcode, this->op_->cur_op());
     ASSERT_EQ(1U, this->op_->StackSize());
-    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
   }
 }
 
@@ -1532,7 +1536,7 @@
 
   // Should fail since this references a non-existent register.
   ASSERT_FALSE(this->op_->Eval(2, 4, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_bregx) {
@@ -1560,7 +1564,7 @@
   ASSERT_EQ(0x90U, this->op_->StackAt(0));
 
   ASSERT_FALSE(this->op_->Eval(7, 12, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_nop) {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index dfd2ce0..7e10935 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -19,10 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfSection.h>
 
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -67,7 +67,7 @@
   }
   void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
 
-  void TestClearError() { this->last_error_ = DWARF_ERROR_NONE; }
+  void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
 };
 
 template <typename TypeParam>
@@ -102,7 +102,8 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x5000U, this->section_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) {
@@ -118,7 +119,7 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) {
@@ -172,7 +173,7 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) {
@@ -182,7 +183,7 @@
 
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) {
@@ -192,7 +193,7 @@
 
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) {
@@ -203,25 +204,25 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 
   this->section_->TestClearError();
   loc_regs.erase(CFA_REG);
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}};
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 
   this->section_->TestClearError();
   loc_regs.erase(CFA_REG);
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}};
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 
   this->section_->TestClearError();
   loc_regs.erase(CFA_REG);
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}};
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) {
@@ -341,7 +342,7 @@
   loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) {
@@ -489,10 +490,12 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
   ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
@@ -518,24 +521,24 @@
   EXPECT_EQ(4U, cie->code_alignment_factor);
   EXPECT_EQ(8, cie->data_alignment_factor);
   EXPECT_EQ(0x20U, cie->return_address_register);
-  EXPECT_EQ(DWARF_ERROR_NONE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode());
 
   this->section_->TestClearCachedCieEntry();
   // Set version to 0, 2, 5 and verify we fail.
   this->memory_.SetData8(0x5008, 0x0);
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
 
   this->memory_.SetData8(0x5008, 0x2);
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
 
   this->memory_.SetData8(0x5008, 0x5);
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
@@ -681,10 +684,12 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
   ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
new file mode 100644
index 0000000..0086c9e
--- /dev/null
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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 <elf.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+
+#include "ElfTestUtils.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class ElfCacheTest : public ::testing::Test {
+ protected:
+  static void SetUpTestCase() { memory_.reset(new MemoryFake); }
+
+  void SetUp() override { Elf::SetCachingEnabled(true); }
+
+  void TearDown() override { Elf::SetCachingEnabled(false); }
+
+  void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
+    ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
+    size_t ehdr_size;
+    Elf32_Ehdr ehdr32;
+    Elf64_Ehdr ehdr64;
+    void* ptr;
+    if (type == EM_ARM || type == EM_386) {
+      ehdr_size = sizeof(ehdr32);
+      ptr = &ehdr32;
+      TestInitEhdr(&ehdr32, ELFCLASS32, type);
+    } else {
+      ehdr_size = sizeof(ehdr64);
+      ptr = &ehdr64;
+      TestInitEhdr(&ehdr64, ELFCLASS64, type);
+    }
+
+    ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
+    ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
+  }
+
+  void VerifyWithinSameMap(bool cache_enabled);
+  void VerifySameMap(bool cache_enabled);
+
+  static std::shared_ptr<Memory> memory_;
+};
+
+std::shared_ptr<Memory> ElfCacheTest::memory_;
+
+void ElfCacheTest::VerifySameMap(bool cache_enabled) {
+  if (!cache_enabled) {
+    Elf::SetCachingEnabled(false);
+  }
+
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  WriteElfFile(0, &tf, EM_ARM);
+  close(tf.fd);
+
+  uint64_t start = 0x1000;
+  uint64_t end = 0x20000;
+  MapInfo info1(start, end, 0, 0x5, tf.path);
+  MapInfo info2(start, end, 0, 0x5, tf.path);
+
+  Elf* elf1 = info1.GetElf(memory_, true);
+  ASSERT_TRUE(elf1->valid());
+  Elf* elf2 = info2.GetElf(memory_, true);
+  ASSERT_TRUE(elf2->valid());
+
+  if (cache_enabled) {
+    EXPECT_EQ(elf1, elf2);
+  } else {
+    EXPECT_NE(elf1, elf2);
+  }
+}
+
+TEST_F(ElfCacheTest, no_caching) {
+  VerifySameMap(false);
+}
+
+TEST_F(ElfCacheTest, caching_invalid_elf) {
+  VerifySameMap(true);
+}
+
+void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
+  if (!cache_enabled) {
+    Elf::SetCachingEnabled(false);
+  }
+
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  WriteElfFile(0, &tf, EM_ARM);
+  WriteElfFile(0x100, &tf, EM_386);
+  WriteElfFile(0x200, &tf, EM_X86_64);
+  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;
+  // Will have an elf at offset 0 in file.
+  MapInfo info0_1(start, end, 0, 0x5, tf.path);
+  MapInfo info0_2(start, end, 0, 0x5, tf.path);
+  // Will have an elf at offset 0x100 in file.
+  MapInfo info100_1(start, end, 0x100, 0x5, tf.path);
+  MapInfo info100_2(start, end, 0x100, 0x5, tf.path);
+  // Will have an elf at offset 0x200 in file.
+  MapInfo info200_1(start, end, 0x200, 0x5, tf.path);
+  MapInfo info200_2(start, end, 0x200, 0x5, tf.path);
+  // Will have an elf at offset 0 in file.
+  MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
+  MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
+
+  Elf* elf0_1 = info0_1.GetElf(memory_, true);
+  ASSERT_TRUE(elf0_1->valid());
+  EXPECT_EQ(ARCH_ARM, elf0_1->arch());
+  Elf* elf0_2 = info0_2.GetElf(memory_, true);
+  ASSERT_TRUE(elf0_2->valid());
+  EXPECT_EQ(ARCH_ARM, elf0_2->arch());
+  EXPECT_EQ(0U, info0_1.elf_offset);
+  EXPECT_EQ(0U, info0_2.elf_offset);
+  if (cache_enabled) {
+    EXPECT_EQ(elf0_1, elf0_2);
+  } else {
+    EXPECT_NE(elf0_1, elf0_2);
+  }
+
+  Elf* elf100_1 = info100_1.GetElf(memory_, true);
+  ASSERT_TRUE(elf100_1->valid());
+  EXPECT_EQ(ARCH_X86, elf100_1->arch());
+  Elf* elf100_2 = info100_2.GetElf(memory_, true);
+  ASSERT_TRUE(elf100_2->valid());
+  EXPECT_EQ(ARCH_X86, elf100_2->arch());
+  EXPECT_EQ(0U, info100_1.elf_offset);
+  EXPECT_EQ(0U, info100_2.elf_offset);
+  if (cache_enabled) {
+    EXPECT_EQ(elf100_1, elf100_2);
+  } else {
+    EXPECT_NE(elf100_1, elf100_2);
+  }
+
+  Elf* elf200_1 = info200_1.GetElf(memory_, true);
+  ASSERT_TRUE(elf200_1->valid());
+  EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
+  Elf* elf200_2 = info200_2.GetElf(memory_, true);
+  ASSERT_TRUE(elf200_2->valid());
+  EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
+  EXPECT_EQ(0U, info200_1.elf_offset);
+  EXPECT_EQ(0U, info200_2.elf_offset);
+  if (cache_enabled) {
+    EXPECT_EQ(elf200_1, elf200_2);
+  } else {
+    EXPECT_NE(elf200_1, elf200_2);
+  }
+
+  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);
+    EXPECT_EQ(elf0_1, elf300_1);
+  } else {
+    EXPECT_NE(elf300_1, elf300_2);
+    EXPECT_NE(elf0_1, elf300_1);
+  }
+}
+
+TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
+  VerifyWithinSameMap(false);
+}
+
+TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
+  VerifyWithinSameMap(true);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 099026c..e232986 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -87,6 +87,10 @@
     steps_.clear();
   }
 
+  void FakeSetErrorCode(ErrorCode code) { last_error_.code = code; }
+
+  void FakeSetErrorAddress(uint64_t address) { last_error_.address = address; }
+
  private:
   std::unordered_map<std::string, uint64_t> globals_;
 
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index e6763ab..70a52ad 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,10 +20,10 @@
 
 #include <vector>
 
+#include <unwindstack/MachineArm.h>
 #include <unwindstack/RegsArm.h>
 
 #include "ElfInterfaceArm.h"
-#include "MachineArm.h"
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
@@ -303,6 +303,7 @@
   // FindEntry fails.
   bool finished;
   ASSERT_FALSE(interface.StepExidx(0x7000, 0, nullptr, nullptr, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 
   // ExtractEntry should fail.
   interface.FakeSetStartOffset(0x1000);
@@ -316,14 +317,18 @@
   regs.set_sp(regs[ARM_REG_SP]);
   regs.set_pc(0x1234);
   ASSERT_FALSE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_MEMORY_INVALID, interface.LastErrorCode());
+  EXPECT_EQ(0x1004U, interface.LastErrorAddress());
 
   // Eval should fail.
   memory_.SetData32(0x1004, 0x81000000);
   ASSERT_FALSE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 
   // Everything should pass.
   memory_.SetData32(0x1004, 0x80b0b0b0);
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
   ASSERT_FALSE(finished);
   ASSERT_EQ(0x1000U, regs.sp());
   ASSERT_EQ(0x1000U, regs[ARM_REG_SP]);
@@ -332,9 +337,11 @@
 
   // Load bias is non-zero.
   ASSERT_TRUE(interface.StepExidx(0x8000, 0x1000, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 
   // Pc too small.
   ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 }
 
 TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
@@ -356,6 +363,7 @@
   // Everything should pass.
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_FALSE(finished);
   ASSERT_EQ(0x10004U, regs.sp());
   ASSERT_EQ(0x10004U, regs[ARM_REG_SP]);
@@ -379,6 +387,7 @@
 
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0x10000U, regs.sp());
   ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
@@ -401,6 +410,7 @@
 
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0x10000U, regs.sp());
   ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
@@ -427,6 +437,7 @@
 
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0U, regs.pc());
 
@@ -439,6 +450,7 @@
   regs.set_pc(0x1234);
 
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0U, regs.pc());
 }
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 7e6a62a..eb85033 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -581,4 +581,30 @@
   EXPECT_TRUE(elf.IsValidPc(0x1500));
 }
 
+TEST_F(ElfTest, error_code_not_valid) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(false);
+
+  ErrorData error{ERROR_MEMORY_INVALID, 0x100};
+  elf.GetLastError(&error);
+  EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
+  EXPECT_EQ(0x100U, error.address);
+}
+
+TEST_F(ElfTest, error_code_valid) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(true);
+  ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+  elf.FakeSetInterface(interface);
+  interface->FakeSetErrorCode(ERROR_MEMORY_INVALID);
+  interface->FakeSetErrorAddress(0x1000);
+
+  ErrorData error{ERROR_NONE, 0};
+  elf.GetLastError(&error);
+  EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
+  EXPECT_EQ(0x1000U, error.address);
+  EXPECT_EQ(ERROR_MEMORY_INVALID, elf.GetLastErrorCode());
+  EXPECT_EQ(0x1000U, elf.GetLastErrorAddress());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 1a50989..c1c45f8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -56,33 +56,33 @@
 
     MapInfo* map_info = maps_->Get(3);
     ASSERT_TRUE(map_info != nullptr);
-    elf_memories_.push_back(new MemoryFake);
-    ElfFake* elf = new ElfFake(elf_memories_.back());
+    MemoryFake* memory = new MemoryFake;
+    ElfFake* elf = new ElfFake(memory);
     elf->FakeSetValid(true);
-    ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
+    ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
-    map_info->elf = elf;
+    map_info->elf.reset(elf);
 
     map_info = maps_->Get(5);
     ASSERT_TRUE(map_info != nullptr);
-    elf_memories_.push_back(new MemoryFake);
-    elf = new ElfFake(elf_memories_.back());
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
     elf->FakeSetValid(true);
-    interface = new ElfInterfaceFake(elf_memories_.back());
+    interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
-    map_info->elf = elf;
+    map_info->elf.reset(elf);
 
     map_info = maps_->Get(6);
     ASSERT_TRUE(map_info != nullptr);
-    elf_memories_.push_back(new MemoryFake);
-    elf = new ElfFake(elf_memories_.back());
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
     elf->FakeSetValid(true);
-    interface = new ElfInterfaceFake(elf_memories_.back());
+    interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
-    map_info->elf = elf;
+    map_info->elf.reset(elf);
   }
 
   template <typename EhdrType, typename ShdrType>
@@ -171,7 +171,6 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::vector<MemoryFake*> elf_memories_;
   std::unique_ptr<JitDebug> jit_debug_;
   std::unique_ptr<BufferMaps> maps_;
 };
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 948597b..f599503 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -180,16 +180,14 @@
   ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
-  delete info.elf;
-  info.elf = nullptr;
+  info.elf.reset();
   info.end = 0xfff;
   elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
   // Make sure this test is valid.
-  delete info.elf;
-  info.elf = nullptr;
+  info.elf.reset();
   info.end = 0x2000;
   elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf != nullptr);
@@ -328,8 +326,7 @@
   ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
-  delete info.elf;
-  info.elf = nullptr;
+  info.elf.reset();
   info.flags = PROT_READ;
   elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf->valid());
@@ -352,15 +349,13 @@
   ASSERT_FALSE(elf->valid());
 
   // Set the name to nothing to verify that it still fails.
-  delete info.elf;
-  info.elf = nullptr;
+  info.elf.reset();
   info.name = "";
   elf = info.GetElf(process_memory_, false);
   ASSERT_FALSE(elf->valid());
 
   // Change the flags and verify the elf is valid now.
-  delete info.elf;
-  info.elf = nullptr;
+  info.elf.reset();
   info.flags = PROT_READ;
   elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf->valid());
@@ -403,7 +398,7 @@
   }
 
   // Now verify that all of the elf files are exactly the same and valid.
-  Elf* elf = info.elf;
+  Elf* elf = info.elf.get();
   ASSERT_TRUE(elf != nullptr);
   EXPECT_TRUE(elf->valid());
   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index 631036b..7e64a8a 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -69,7 +69,7 @@
 }
 
 TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
-  map_info_->elf = elf_container_.release();
+  map_info_->elf.reset(elf_container_.release());
 
   elf_->FakeSetLoadBias(0);
   EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
@@ -79,7 +79,7 @@
 }
 
 TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
-  map_info_->elf = elf_container_.release();
+  map_info_->elf.reset(elf_container_.release());
 
   elf_->FakeSetLoadBias(0);
   EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
@@ -122,7 +122,7 @@
 }
 
 TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
-  map_info_->elf = elf_container_.release();
+  map_info_->elf.reset(elf_container_.release());
   elf_->FakeSetLoadBias(0x1000);
 
   MultipleThreadTest(0x1000);
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 8f7d913..cd7f2ff 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -56,6 +56,7 @@
   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; }
 
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index 8b5b31f..9a27dbd 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -24,20 +24,19 @@
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
+#include <unwindstack/MachineArm.h>
+#include <unwindstack/MachineArm64.h>
+#include <unwindstack/MachineMips.h>
+#include <unwindstack/MachineMips64.h>
+#include <unwindstack/MachineX86.h>
+#include <unwindstack/MachineX86_64.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/RegsArm.h>
 #include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
 #include <unwindstack/RegsMips.h>
 #include <unwindstack/RegsMips64.h>
-
-#include "MachineArm.h"
-#include "MachineArm64.h"
-#include "MachineX86.h"
-#include "MachineX86_64.h"
-#include "MachineMips.h"
-#include "MachineMips64.h"
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index ef9e61c..ecd4051 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -19,19 +19,18 @@
 #include <gtest/gtest.h>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineArm.h>
+#include <unwindstack/MachineArm64.h>
+#include <unwindstack/MachineMips.h>
+#include <unwindstack/MachineMips64.h>
+#include <unwindstack/MachineX86.h>
+#include <unwindstack/MachineX86_64.h>
 #include <unwindstack/RegsArm.h>
 #include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
 #include <unwindstack/RegsMips.h>
 #include <unwindstack/RegsMips64.h>
-
-#include "MachineArm.h"
-#include "MachineArm64.h"
-#include "MachineX86.h"
-#include "MachineX86_64.h"
-#include "MachineMips.h"
-#include "MachineMips64.h"
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 
 #include "MemoryFake.h"
 
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 15d5458..7c06373 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -184,7 +184,7 @@
   RegsMips64 regs_mips64;
   MapInfo map_info(0x1000, 0x2000);
   Elf* invalid_elf = new Elf(new MemoryFake);
-  map_info.elf = invalid_elf;
+  map_info.elf.reset(invalid_elf);
 
   regs_arm.set_pc(0x1500);
   EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 582ac18..df262f5 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -23,24 +23,154 @@
 #include <gtest/gtest.h>
 
 #include <string>
+#include <unordered_map>
 #include <vector>
 
+#include <android-base/file.h>
+
 #include <unwindstack/JitDebug.h>
+#include <unwindstack/MachineArm.h>
+#include <unwindstack/MachineArm64.h>
+#include <unwindstack/MachineX86.h>
+#include <unwindstack/MachineX86_64.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/RegsArm.h>
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
 #include <unwindstack/Unwinder.h>
 
-#include "MachineArm.h"
-#include "MachineArm64.h"
-#include "MachineX86.h"
-
 #include "ElfTestUtils.h"
 
 namespace unwindstack {
 
+class UnwindOfflineTest : public ::testing::Test {
+ protected:
+  void TearDown() override {
+    if (cwd_ != nullptr) {
+      ASSERT_EQ(0, chdir(cwd_));
+    }
+    free(cwd_);
+  }
+
+  void Init(const char* file_dir, ArchEnum arch) {
+    dir_ = TestGetFileDirectory() + "offline/" + file_dir;
+
+    std::string data;
+    ASSERT_TRUE(android::base::ReadFileToString((dir_ + "maps.txt"), &data));
+
+    maps_.reset(new BufferMaps(data.c_str()));
+    ASSERT_TRUE(maps_->Parse());
+
+    std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
+    ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
+    process_memory_.reset(stack_memory.release());
+
+    switch (arch) {
+      case ARCH_ARM: {
+        RegsArm* regs = new RegsArm;
+        regs_.reset(regs);
+        ReadRegs<uint32_t>(regs, arm_regs_);
+        break;
+      }
+      case ARCH_ARM64: {
+        RegsArm64* regs = new RegsArm64;
+        regs_.reset(regs);
+        ReadRegs<uint64_t>(regs, arm64_regs_);
+        break;
+      }
+      case ARCH_X86: {
+        RegsX86* regs = new RegsX86;
+        regs_.reset(regs);
+        ReadRegs<uint32_t>(regs, x86_regs_);
+        break;
+      }
+      case ARCH_X86_64: {
+        RegsX86_64* regs = new RegsX86_64;
+        regs_.reset(regs);
+        ReadRegs<uint64_t>(regs, x86_64_regs_);
+        break;
+      }
+      default:
+        ASSERT_TRUE(false) << "Unknown arch " << std::to_string(arch);
+    }
+    cwd_ = getcwd(nullptr, 0);
+    // Make dir_ an absolute directory.
+    if (dir_.empty() || dir_[0] != '/') {
+      dir_ = std::string(cwd_) + '/' + dir_;
+    }
+    ASSERT_EQ(0, chdir(dir_.c_str()));
+  }
+
+  template <typename AddressType>
+  void ReadRegs(RegsImpl<AddressType>* regs,
+                const std::unordered_map<std::string, uint32_t>& name_to_reg) {
+    FILE* fp = fopen((dir_ + "regs.txt").c_str(), "r");
+    ASSERT_TRUE(fp != nullptr);
+    while (!feof(fp)) {
+      uint64_t value;
+      char reg_name[100];
+      ASSERT_EQ(2, fscanf(fp, "%s %" SCNx64 "\n", reg_name, &value));
+      std::string name(reg_name);
+      if (!name.empty()) {
+        // Remove the : from the end.
+        name.resize(name.size() - 1);
+      }
+      auto entry = name_to_reg.find(name);
+      ASSERT_TRUE(entry != name_to_reg.end()) << "Unknown register named " << name;
+      (*regs)[entry->second] = value;
+    }
+    fclose(fp);
+    regs->SetFromRaw();
+  }
+
+  static std::unordered_map<std::string, uint32_t> arm_regs_;
+  static std::unordered_map<std::string, uint32_t> arm64_regs_;
+  static std::unordered_map<std::string, uint32_t> x86_regs_;
+  static std::unordered_map<std::string, uint32_t> x86_64_regs_;
+
+  char* cwd_ = nullptr;
+  std::string dir_;
+  std::unique_ptr<Regs> regs_;
+  std::unique_ptr<Maps> maps_;
+  std::shared_ptr<Memory> process_memory_;
+};
+
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm_regs_ = {
+    {"r0", ARM_REG_R0},  {"r1", ARM_REG_R1}, {"r2", ARM_REG_R2},   {"r3", ARM_REG_R3},
+    {"r4", ARM_REG_R4},  {"r5", ARM_REG_R5}, {"r6", ARM_REG_R6},   {"r7", ARM_REG_R7},
+    {"r8", ARM_REG_R8},  {"r9", ARM_REG_R9}, {"r10", ARM_REG_R10}, {"r11", ARM_REG_R11},
+    {"ip", ARM_REG_R12}, {"sp", ARM_REG_SP}, {"lr", ARM_REG_LR},   {"pc", ARM_REG_PC},
+};
+
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm64_regs_ = {
+    {"x0", ARM64_REG_R0},   {"x1", ARM64_REG_R1},   {"x2", ARM64_REG_R2},   {"x3", ARM64_REG_R3},
+    {"x4", ARM64_REG_R4},   {"x5", ARM64_REG_R5},   {"x6", ARM64_REG_R6},   {"x7", ARM64_REG_R7},
+    {"x8", ARM64_REG_R8},   {"x9", ARM64_REG_R9},   {"x10", ARM64_REG_R10}, {"x11", ARM64_REG_R11},
+    {"x12", ARM64_REG_R12}, {"x13", ARM64_REG_R13}, {"x14", ARM64_REG_R14}, {"x15", ARM64_REG_R15},
+    {"x16", ARM64_REG_R16}, {"x17", ARM64_REG_R17}, {"x18", ARM64_REG_R18}, {"x19", ARM64_REG_R19},
+    {"x20", ARM64_REG_R20}, {"x21", ARM64_REG_R21}, {"x22", ARM64_REG_R22}, {"x23", ARM64_REG_R23},
+    {"x24", ARM64_REG_R24}, {"x25", ARM64_REG_R25}, {"x26", ARM64_REG_R26}, {"x27", ARM64_REG_R27},
+    {"x28", ARM64_REG_R28}, {"x29", ARM64_REG_R29}, {"sp", ARM64_REG_SP},   {"lr", ARM64_REG_LR},
+    {"pc", ARM64_REG_PC},
+};
+
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_regs_ = {
+    {"eax", X86_REG_EAX}, {"ebx", X86_REG_EBX}, {"ecx", X86_REG_ECX},
+    {"edx", X86_REG_EDX}, {"ebp", X86_REG_EBP}, {"edi", X86_REG_EDI},
+    {"esi", X86_REG_ESI}, {"esp", X86_REG_ESP}, {"eip", X86_REG_EIP},
+};
+
+std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_64_regs_ = {
+    {"rax", X86_64_REG_RAX}, {"rbx", X86_64_REG_RBX}, {"rcx", X86_64_REG_RCX},
+    {"rdx", X86_64_REG_RDX}, {"r8", X86_64_REG_R8},   {"r9", X86_64_REG_R9},
+    {"r10", X86_64_REG_R10}, {"r11", X86_64_REG_R11}, {"r12", X86_64_REG_R12},
+    {"r13", X86_64_REG_R13}, {"r14", X86_64_REG_R14}, {"r15", X86_64_REG_R15},
+    {"rdi", X86_64_REG_RDI}, {"rsi", X86_64_REG_RSI}, {"rbp", X86_64_REG_RBP},
+    {"rsp", X86_64_REG_RSP}, {"rip", X86_64_REG_RIP},
+};
+
 static std::string DumpFrames(Unwinder& unwinder) {
   std::string str;
   for (size_t i = 0; i < unwinder.NumFrames(); i++) {
@@ -49,45 +179,11 @@
   return str;
 }
 
-TEST(UnwindOfflineTest, pc_straddle_arm32) {
-  std::string dir(TestGetFileDirectory() + "offline/straddle_arm32/");
+TEST_F(UnwindOfflineTest, pc_straddle_arm) {
+  Init("straddle_arm/", ARCH_ARM);
 
-  MemoryOffline* memory = new MemoryOffline;
-  ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
-  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  RegsArm regs;
-  uint64_t reg_value;
-  ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_PC] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_SP] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_LR] = reg_value;
-  regs.SetFromRaw();
-  fclose(fp);
-
-  fp = fopen((dir + "maps.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  // The file is guaranteed to be less than 4096 bytes.
-  std::vector<char> buffer(4096);
-  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
-  fclose(fp);
-
-  BufferMaps maps(buffer.data());
-  ASSERT_TRUE(maps.Parse());
-
-  ASSERT_EQ(ARCH_ARM, regs.Arch());
-
-  std::shared_ptr<Memory> process_memory(memory);
-
-  char* cwd = getcwd(nullptr, 0);
-  ASSERT_EQ(0, chdir(dir.c_str()));
-  Unwinder unwinder(128, &maps, &regs, process_memory);
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
-  ASSERT_EQ(0, chdir(cwd));
-  free(cwd);
 
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -99,43 +195,11 @@
       frame_info);
 }
 
-TEST(UnwindOfflineTest, pc_in_gnu_debugdata_arm32) {
-  std::string dir(TestGetFileDirectory() + "offline/gnu_debugdata_arm32/");
+TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
+  Init("gnu_debugdata_arm/", ARCH_ARM);
 
-  MemoryOffline* memory = new MemoryOffline;
-  ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
-  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  RegsArm regs;
-  uint64_t reg_value;
-  ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_PC] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_SP] = reg_value;
-  regs.SetFromRaw();
-  fclose(fp);
-
-  fp = fopen((dir + "maps.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  // The file is guaranteed to be less than 4096 bytes.
-  std::vector<char> buffer(4096);
-  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
-  fclose(fp);
-
-  BufferMaps maps(buffer.data());
-  ASSERT_TRUE(maps.Parse());
-
-  ASSERT_EQ(ARCH_ARM, regs.Arch());
-
-  std::shared_ptr<Memory> process_memory(memory);
-
-  char* cwd = getcwd(nullptr, 0);
-  ASSERT_EQ(0, chdir(dir.c_str()));
-  Unwinder unwinder(128, &maps, &regs, process_memory);
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
-  ASSERT_EQ(0, chdir(cwd));
-  free(cwd);
 
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(2U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -147,47 +211,11 @@
       frame_info);
 }
 
-TEST(UnwindOfflineTest, pc_straddle_arm64) {
-  std::string dir(TestGetFileDirectory() + "offline/straddle_arm64/");
+TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
+  Init("straddle_arm64/", ARCH_ARM64);
 
-  MemoryOffline* memory = new MemoryOffline;
-  ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
-  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  RegsArm64 regs;
-  uint64_t reg_value;
-  ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
-  regs[ARM64_REG_PC] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
-  regs[ARM64_REG_SP] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
-  regs[ARM64_REG_LR] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", &reg_value));
-  regs[ARM64_REG_R29] = reg_value;
-  regs.SetFromRaw();
-  fclose(fp);
-
-  fp = fopen((dir + "maps.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  // The file is guaranteed to be less than 4096 bytes.
-  std::vector<char> buffer(4096);
-  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
-  fclose(fp);
-
-  BufferMaps maps(buffer.data());
-  ASSERT_TRUE(maps.Parse());
-
-  ASSERT_EQ(ARCH_ARM64, regs.Arch());
-
-  std::shared_ptr<Memory> process_memory(memory);
-
-  char* cwd = getcwd(nullptr, 0);
-  ASSERT_EQ(0, chdir(dir.c_str()));
-  Unwinder unwinder(128, &maps, &regs, process_memory);
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
   unwinder.Unwind();
-  ASSERT_EQ(0, chdir(cwd));
-  free(cwd);
 
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -209,64 +237,22 @@
   parts->Add(memory);
 }
 
-TEST(UnwindOfflineTest, jit_debug_x86_32) {
-  std::string dir(TestGetFileDirectory() + "offline/jit_debug_x86_32/");
+TEST_F(UnwindOfflineTest, jit_debug_x86) {
+  Init("jit_debug_x86/", ARCH_X86);
 
   MemoryOfflineParts* memory = new MemoryOfflineParts;
-  AddMemory(dir + "descriptor.data", memory);
-  AddMemory(dir + "stack.data", memory);
+  AddMemory(dir_ + "descriptor.data", memory);
+  AddMemory(dir_ + "stack.data", memory);
   for (size_t i = 0; i < 7; i++) {
-    AddMemory(dir + "entry" + std::to_string(i) + ".data", memory);
-    AddMemory(dir + "jit" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
   }
+  process_memory_.reset(memory);
 
-  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  RegsX86 regs;
-  uint64_t reg_value;
-  ASSERT_EQ(1, fscanf(fp, "eax: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_EAX] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "ebx: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_EBX] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "ecx: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_ECX] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "edx: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_EDX] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "ebp: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_EBP] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "edi: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_EDI] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "esi: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_ESI] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "esp: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_ESP] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "eip: %" SCNx64 "\n", &reg_value));
-  regs[X86_REG_EIP] = reg_value;
-  regs.SetFromRaw();
-  fclose(fp);
-
-  fp = fopen((dir + "maps.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  // The file is guaranteed to be less than 4096 bytes.
-  std::vector<char> buffer(4096);
-  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
-  fclose(fp);
-
-  BufferMaps maps(buffer.data());
-  ASSERT_TRUE(maps.Parse());
-
-  ASSERT_EQ(ARCH_X86, regs.Arch());
-
-  std::shared_ptr<Memory> process_memory(memory);
-
-  char* cwd = getcwd(nullptr, 0);
-  ASSERT_EQ(0, chdir(dir.c_str()));
-  JitDebug jit_debug(process_memory);
-  Unwinder unwinder(128, &maps, &regs, process_memory);
-  unwinder.SetJitDebug(&jit_debug, regs.Arch());
+  JitDebug jit_debug(process_memory_);
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
-  ASSERT_EQ(0, chdir(cwd));
-  free(cwd);
 
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(69U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -406,79 +392,23 @@
       frame_info);
 }
 
-TEST(UnwindOfflineTest, jit_debug_arm32) {
-  std::string dir(TestGetFileDirectory() + "offline/jit_debug_arm32/");
+TEST_F(UnwindOfflineTest, jit_debug_arm) {
+  Init("jit_debug_arm/", ARCH_ARM);
 
   MemoryOfflineParts* memory = new MemoryOfflineParts;
-  AddMemory(dir + "descriptor.data", memory);
-  AddMemory(dir + "descriptor1.data", memory);
-  AddMemory(dir + "stack.data", memory);
+  AddMemory(dir_ + "descriptor.data", memory);
+  AddMemory(dir_ + "descriptor1.data", memory);
+  AddMemory(dir_ + "stack.data", memory);
   for (size_t i = 0; i < 7; i++) {
-    AddMemory(dir + "entry" + std::to_string(i) + ".data", memory);
-    AddMemory(dir + "jit" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
   }
+  process_memory_.reset(memory);
 
-  FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  RegsArm regs;
-  uint64_t reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r0: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R0] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r1: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R1] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r2: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R2] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r3: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R3] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r4: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R4] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r5: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R5] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r6: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R6] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r7: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R7] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r8: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R8] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r9: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R9] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r10: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R10] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "r11: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R11] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "ip: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_R12] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_SP] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_LR] = reg_value;
-  ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
-  regs[ARM_REG_PC] = reg_value;
-  regs.SetFromRaw();
-  fclose(fp);
-
-  fp = fopen((dir + "maps.txt").c_str(), "r");
-  ASSERT_TRUE(fp != nullptr);
-  // The file is guaranteed to be less than 4096 bytes.
-  std::vector<char> buffer(4096);
-  ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
-  fclose(fp);
-
-  BufferMaps maps(buffer.data());
-  ASSERT_TRUE(maps.Parse());
-
-  ASSERT_EQ(ARCH_ARM, regs.Arch());
-
-  std::shared_ptr<Memory> process_memory(memory);
-
-  char* cwd = getcwd(nullptr, 0);
-  ASSERT_EQ(0, chdir(dir.c_str()));
-  JitDebug jit_debug(process_memory);
-  Unwinder unwinder(128, &maps, &regs, process_memory);
-  unwinder.SetJitDebug(&jit_debug, regs.Arch());
+  JitDebug jit_debug(process_memory_);
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
-  ASSERT_EQ(0, chdir(cwd));
-  free(cwd);
 
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -625,4 +555,61 @@
       frame_info);
 }
 
+// The eh_frame_hdr data is present but set to zero fdes. This should
+// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
+// No .gnu_debugdata section in the elf file, so no symbols.
+TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
+  Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64);
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 0000000000000550  waiter64\n"
+      "  #01 pc 0000000000000568  waiter64\n"
+      "  #02 pc 000000000000057c  waiter64\n"
+      "  #03 pc 0000000000000590  waiter64\n"
+      "  #04 pc 00000000000a8e98  libc.so (__libc_init+88)\n",
+      frame_info);
+}
+
+// The elf has bad eh_frame unwind information for the pcs. If eh_frame
+// is used first, the unwind will not match the expected output.
+TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
+  Init("debug_frame_first_x86/", ARCH_X86);
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 00000685  waiter (call_level3+53)\n"
+      "  #01 pc 000006b7  waiter (call_level2+23)\n"
+      "  #02 pc 000006d7  waiter (call_level1+23)\n"
+      "  #03 pc 000006f7  waiter (main+23)\n"
+      "  #04 pc 00018275  libc.so\n",
+      frame_info);
+}
+
+// Make sure that a pc that is at the beginning of an fde unwinds correctly.
+TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
+  Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64);
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 0000000000000a80  unwind_test64 (calling3)\n"
+      "  #01 pc 0000000000000dd9  unwind_test64 (calling2+633)\n"
+      "  #02 pc 000000000000121e  unwind_test64 (calling1+638)\n"
+      "  #03 pc 00000000000013ed  unwind_test64 (main+13)\n"
+      "  #04 pc 00000000000202b0  libc.so\n",
+      frame_info);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index cd46807..7fbae4c 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -60,7 +60,7 @@
     maps_.FakeClear();
     MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
     ElfFake* elf = new ElfFake(new MemoryFake);
-    info->elf = elf;
+    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
@@ -73,31 +73,51 @@
 
     info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf = elf;
+    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf = elf;
+    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf = elf;
+    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
     elf = new ElfFake(new MemoryFake);
-    info->elf = elf;
+    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
     maps_.FakeAddMapInfo(info);
 
+    info = new MapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+    info->load_bias = 0;
+    maps_.FakeAddMapInfo(info);
+
+    info = new MapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                       "/fake/fake_load_bias.so");
+    elf = new ElfFake(new MemoryFake);
+    info->elf.reset(elf);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    elf->FakeSetLoadBias(0x5000);
+    maps_.FakeAddMapInfo(info);
+
+    info = new MapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                       "/fake/fake_offset.oat");
+    elf = new ElfFake(new MemoryFake);
+    info->elf.reset(elf);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    info->elf_offset = 0x8000;
+    maps_.FakeAddMapInfo(info);
+
     process_memory_.reset(new MemoryFake);
   }
 
@@ -129,6 +149,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -175,6 +196,62 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, non_zero_load_bias) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.FakeSetPc(0xa5500);
+  regs_.FakeSetSp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x5500U, frame->rel_pc);
+  EXPECT_EQ(0xa5500U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0xa5000U, frame->map_start);
+  EXPECT_EQ(0xa6000U, frame->map_end);
+  EXPECT_EQ(0x5000U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, non_zero_elf_offset) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.FakeSetPc(0xa7500);
+  regs_.FakeSetSp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x8500U, frame->rel_pc);
+  EXPECT_EQ(0xa7500U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/fake_offset.oat", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0xa7000U, frame->map_start);
+  EXPECT_EQ(0xa8000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
 TEST_F(UnwinderTest, non_zero_map_offset) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
 
@@ -184,6 +261,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -218,6 +296,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -248,6 +327,7 @@
 
   Unwinder unwinder(20, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
 
   ASSERT_EQ(20U, unwinder.NumFrames());
 
@@ -288,6 +368,7 @@
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -346,6 +427,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -392,6 +474,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -410,6 +493,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -423,6 +507,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -457,6 +542,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -517,6 +603,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -552,6 +639,7 @@
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
   // Make sure the elf was not initialized.
@@ -607,6 +695,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -653,6 +742,146 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, dex_pc_in_map) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  regs_.FakeSetPc(0x1000);
+  regs_.FakeSetSp(0x10000);
+  regs_.FakeSetDexPc(0xa3400);
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(2U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x400U, frame->rel_pc);
+  EXPECT_EQ(0xa3400U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0xa3000U, frame->map_start);
+  EXPECT_EQ(0xa4000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+
+  frame = &unwinder.frames()[1];
+  EXPECT_EQ(1U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x1000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", 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, dex_pc_not_in_map) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  regs_.FakeSetPc(0x1000);
+  regs_.FakeSetSp(0x10000);
+  regs_.FakeSetDexPc(0x50000);
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(2U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50000U, frame->rel_pc);
+  EXPECT_EQ(0x50000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_start);
+  EXPECT_EQ(0U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(0, frame->map_flags);
+
+  frame = &unwinder.frames()[1];
+  EXPECT_EQ(1U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x1000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", 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, dex_pc_multiple_frames) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+  regs_.FakeSetPc(0x1000);
+  regs_.FakeSetSp(0x10000);
+  regs_.FakeSetDexPc(0xa3400);
+  ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  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(0x400U, frame->rel_pc);
+  EXPECT_EQ(0xa3400U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0xa3000U, frame->map_start);
+  EXPECT_EQ(0xa4000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+
+  frame = &unwinder.frames()[1];
+  EXPECT_EQ(1U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x1000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", 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(0x400U, frame->rel_pc);
+  EXPECT_EQ(0x33400U, frame->pc);
+  EXPECT_EQ(0x10010U, frame->sp);
+  EXPECT_EQ("Frame1", frame->function_name);
+  EXPECT_EQ(1U, frame->function_offset);
+  EXPECT_EQ("/fake/compressed.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0x33000U, frame->map_start);
+  EXPECT_EQ(0x34000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame_static) {
   FrameData frame;
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
new file mode 100644
index 0000000..78449bf
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
new file mode 100644
index 0000000..7cada15
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
@@ -0,0 +1,2 @@
+60a9fdf000-60a9fe0000 r-xp 0 00:00 0   waiter64
+7542cc0000-7542d8e000 r-xp 0 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
new file mode 100644
index 0000000..c24adbe
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
@@ -0,0 +1,4 @@
+pc: 60a9fdf550
+sp: 7fdd141990
+lr: 60a9fdf56c
+x29: 7fdd1419a0
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
new file mode 100644
index 0000000..b56d420
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
new file mode 100644
index 0000000..81bda1d
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
similarity index 100%
copy from libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so
copy to libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
new file mode 100644
index 0000000..74fc89f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
@@ -0,0 +1,2 @@
+56598000-56599000 r-xp 0 00:00 0   waiter
+f7432000-f75e3000 r-xp 0 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
new file mode 100644
index 0000000..48f4440
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
@@ -0,0 +1,9 @@
+eax: 1d88ef8c
+ebx: 56599fe8
+ecx: 3
+edx: ffcf9ea4
+ebp: ffcf9e48
+edi: f75e5000
+esi: 1
+esp: ffcf9e38
+eip: 56598685
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
new file mode 100644
index 0000000..0cf7d55
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
new file mode 100644
index 0000000..b1fc024
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
new file mode 100644
index 0000000..46b6f45
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
new file mode 100644
index 0000000..ac2e564
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
@@ -0,0 +1,2 @@
+561550b17000-561550b1a000 r-xp 0 00:00 0   unwind_test64
+7f4de61f6000-7f4de638b000 r-xp 0 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
new file mode 100644
index 0000000..38af274
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
@@ -0,0 +1,11 @@
+rax: 92134c6fbbdc12ff
+rbx: 0
+rcx: 92134c6fbbdc1200
+rdx: 92134c6fbbdc1200
+r8: 561552153034
+r12: 561550b17930
+r13: 7ffcc8597270
+rsi: 561552153034
+rbp: 7ffcc8596f30
+rsp: 7ffcc8596ce8
+rip: 561550b17a80
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
new file mode 100644
index 0000000..cc7882b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64 b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
new file mode 100644
index 0000000..ab0ef8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/libandroid_runtime.so b/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/libandroid_runtime.so
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/maps.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/maps.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/regs.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/regs.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/stack.data b/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/stack.data
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/137-cfi.odex
rename to libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/dalvikvm32
rename to libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/descriptor1.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/descriptor1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry0.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry1.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry2.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry3.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry4.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry5.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry6.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit0.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit1.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit2.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit3.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit4.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit5.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit6.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libart.so b/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libart.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libartd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libartd.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libarttestd.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libc.so b/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libc.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/regs.txt b/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/stack.data b/libunwindstack/tests/files/offline/jit_debug_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/137-cfi.odex
rename to libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/dalvikvm32
rename to libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry0.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry1.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry2.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry3.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry4.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry5.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry6.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit0.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit1.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit2.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit3.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit4.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit5.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit6.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
new file mode 100644
index 0000000..92ed991
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
new file mode 100644
index 0000000..5efae02
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so b/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so
rename to libunwindstack/tests/files/offline/jit_debug_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/regs.txt b/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/stack.data b/libunwindstack/tests/files/offline/jit_debug_x86/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
deleted file mode 100644
index e72e673..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libbase.so b/libunwindstack/tests/files/offline/straddle_arm/libbase.so
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/libbase.so
rename to libunwindstack/tests/files/offline/straddle_arm/libbase.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libc.so b/libunwindstack/tests/files/offline/straddle_arm/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/libc.so
rename to libunwindstack/tests/files/offline/straddle_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/maps.txt b/libunwindstack/tests/files/offline/straddle_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/maps.txt
rename to libunwindstack/tests/files/offline/straddle_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/regs.txt b/libunwindstack/tests/files/offline/straddle_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/regs.txt
rename to libunwindstack/tests/files/offline/straddle_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/stack.data b/libunwindstack/tests/files/offline/straddle_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/stack.data
rename to libunwindstack/tests/files/offline/straddle_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 33e5527..22ca7bf 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -91,18 +92,18 @@
 
   auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
   unwindstack::Unwinder unwinder(128, &remote_maps, regs, process_memory);
+
   unwindstack::JitDebug jit_debug(process_memory);
   unwinder.SetJitDebug(&jit_debug, regs->Arch());
+
+  unwindstack::DexFiles dex_files(process_memory);
+  unwinder.SetDexFiles(&dex_files, regs->Arch());
+
   unwinder.Unwind();
 
   // Print the frames.
-  const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
   for (size_t i = 0; i < unwinder.NumFrames(); i++) {
     printf("%s\n", unwinder.FormatFrame(i).c_str());
-    const unwindstack::FrameData* frame = &frames[i];
-    if (frame->dex_pc != 0) {
-      printf("      dex pc %" PRIx64 "\n", frame->dex_pc);
-    }
   }
 }
 
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
new file mode 100644
index 0000000..4d89087
--- /dev/null
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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 <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Log.h>
+
+#include "DwarfOp.h"
+
+namespace unwindstack {
+
+void PrintSignedValue(int64_t value) {
+  if (value < 0) {
+    printf("- %" PRId64, -value);
+  } else if (value > 0) {
+    printf("+ %" PRId64, value);
+  }
+}
+
+void PrintExpression(Memory* memory, uint8_t class_type, uint64_t end, uint64_t length) {
+  std::vector<std::string> lines;
+  DwarfMemory dwarf_memory(memory);
+  if (class_type == ELFCLASS32) {
+    DwarfOp<uint32_t> op(&dwarf_memory, nullptr);
+    op.GetLogInfo(end - length, end, &lines);
+  } else {
+    DwarfOp<uint64_t> op(&dwarf_memory, nullptr);
+    op.GetLogInfo(end - length, end, &lines);
+  }
+  for (auto& line : lines) {
+    printf("    %s\n", line.c_str());
+  }
+}
+
+void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type) {
+  const DwarfFde* fde = section->GetFdeFromPc(pc);
+  if (fde == nullptr) {
+    printf("  No fde found.\n");
+    return;
+  }
+
+  dwarf_loc_regs_t regs;
+  if (!section->GetCfaLocationInfo(pc, fde, &regs)) {
+    printf("  Cannot get location information.\n");
+    return;
+  }
+
+  std::vector<std::pair<uint32_t, DwarfLocation>> loc_regs;
+  for (auto& loc : regs) {
+    loc_regs.push_back(loc);
+  }
+  std::sort(loc_regs.begin(), loc_regs.end(), [](auto a, auto b) {
+    if (a.first == CFA_REG) {
+      return true;
+    } else if (b.first == CFA_REG) {
+      return false;
+    }
+    return a.first < b.first;
+  });
+
+  for (auto& entry : loc_regs) {
+    const DwarfLocation* loc = &entry.second;
+    if (entry.first == CFA_REG) {
+      printf("  cfa = ");
+    } else {
+      printf("  r%d = ", entry.first);
+    }
+    switch (loc->type) {
+      case DWARF_LOCATION_OFFSET:
+        printf("[cfa ");
+        PrintSignedValue(loc->values[0]);
+        printf("]\n");
+        break;
+
+      case DWARF_LOCATION_VAL_OFFSET:
+        printf("cfa ");
+        PrintSignedValue(loc->values[0]);
+        printf("\n");
+        break;
+
+      case DWARF_LOCATION_REGISTER:
+        printf("r%" PRId64 " ", loc->values[0]);
+        PrintSignedValue(loc->values[1]);
+        printf("\n");
+        break;
+
+      case DWARF_LOCATION_EXPRESSION: {
+        printf("EXPRESSION\n");
+        PrintExpression(memory, class_type, loc->values[1], loc->values[0]);
+        break;
+      }
+
+      case DWARF_LOCATION_VAL_EXPRESSION: {
+        printf("VAL EXPRESSION\n");
+        PrintExpression(memory, class_type, loc->values[1], loc->values[0]);
+        break;
+      }
+
+      case DWARF_LOCATION_UNDEFINED:
+        printf("undefine\n");
+        break;
+
+      case DWARF_LOCATION_INVALID:
+        printf("INVALID\n");
+        break;
+    }
+  }
+}
+
+int GetInfo(const char* file, uint64_t pc) {
+  MemoryFileAtOffset* memory = new MemoryFileAtOffset;
+  if (!memory->Init(file, 0)) {
+    // Initializatation failed.
+    printf("Failed to init\n");
+    return 1;
+  }
+
+  Elf elf(memory);
+  if (!elf.Init(true) || !elf.valid()) {
+    printf("%s is not a valid elf file.\n", file);
+    return 1;
+  }
+
+  ElfInterface* interface = elf.interface();
+  uint64_t load_bias = elf.GetLoadBias();
+  if (pc < load_bias) {
+    printf("PC is less than load bias.\n");
+    return 1;
+  }
+
+  printf("PC 0x%" PRIx64 ":\n", pc);
+
+  DwarfSection* section = interface->eh_frame();
+  if (section != nullptr) {
+    printf("\neh_frame:\n");
+    PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
+  } else {
+    printf("\nno eh_frame information\n");
+  }
+
+  section = interface->debug_frame();
+  if (section != nullptr) {
+    printf("\ndebug_frame:\n");
+    PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
+    printf("\n");
+  } else {
+    printf("\nno debug_frame information\n");
+  }
+
+  // If there is a gnu_debugdata interface, dump the information for that.
+  ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
+  if (gnu_debugdata_interface != nullptr) {
+    section = gnu_debugdata_interface->eh_frame();
+    if (section != nullptr) {
+      printf("\ngnu_debugdata (eh_frame):\n");
+      PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type());
+      printf("\n");
+    } else {
+      printf("\nno gnu_debugdata (eh_frame)\n");
+    }
+
+    section = gnu_debugdata_interface->debug_frame();
+    if (section != nullptr) {
+      printf("\ngnu_debugdata (debug_frame):\n");
+      PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type());
+      printf("\n");
+    } else {
+      printf("\nno gnu_debugdata (debug_frame)\n");
+    }
+  } else {
+    printf("\nno valid gnu_debugdata information\n");
+  }
+
+  return 0;
+}
+
+}  // namespace unwindstack
+
+int main(int argc, char** argv) {
+  if (argc != 3) {
+    printf("Usage: unwind_reg_info ELF_FILE PC\n");
+    printf("  ELF_FILE\n");
+    printf("    The path to an elf file.\n");
+    printf("  PC\n");
+    printf("    The pc for which the register information should be obtained.\n");
+    return 1;
+  }
+
+  struct stat st;
+  if (stat(argv[1], &st) == -1) {
+    printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
+    return 1;
+  }
+  if (!S_ISREG(st.st_mode)) {
+    printf("%s is not a regular file.\n", argv[1]);
+    return 1;
+  }
+
+  uint64_t pc = 0;
+  char* end;
+  pc = strtoull(argv[2], &end, 16);
+  if (*end != '\0') {
+    printf("Malformed OFFSET value: %s\n", argv[2]);
+    return 1;
+  }
+
+  return unwindstack::GetInfo(argv[1], pc);
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3bca6c8..2be5d98 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -157,6 +157,7 @@
 cc_library {
     name: "libutilscallstack",
     defaults: ["libutils_defaults"],
+    vendor_available: false,
 
     srcs: [
         "CallStack.cpp",
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index fd83ecc..15471e0 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -615,11 +615,11 @@
     pid_remove(pid);
 
     if (r) {
-        ALOGE("kill(%d): errno=%d", procp->pid, errno);
+        ALOGE("kill(%d): errno=%d", pid, errno);
         return -1;
-    } else {
-        return tasksize;
     }
+
+    return tasksize;
 }
 
 /*
@@ -900,7 +900,16 @@
     downgrade_pressure = (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 60);
     is_go_device = property_get_bool("ro.config.low_ram", false);
 
-    if (mlockall(MCL_CURRENT | MCL_FUTURE))
+    // MCL_ONFAULT pins pages as they fault instead of loading
+    // everything immediately all at once. (Which would be bad,
+    // because as of this writing, we have a lot of mapped pages we
+    // never use.) Old kernels will see MCL_ONFAULT and fail with
+    // EINVAL; we ignore this failure.
+    //
+    // N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
+    // pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
+    // in pages.
+    if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && errno != EINVAL)
         ALOGW("mlockall failed: errno=%d", errno);
 
     sched_setscheduler(0, SCHED_FIFO, &param);
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index ca992d6..f4509a4 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -88,6 +88,11 @@
 else
   LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
 endif
+ifdef BOARD_USES_PRODUCTIMAGE
+  LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product
+else
+  LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product
+endif
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
 else
@@ -187,11 +192,12 @@
 # ld.config.txt
 #
 # For VNDK enforced devices that have defined BOARD_VNDK_VERSION, use
-# "ld.config.txt.in" as a source file. This configuration includes strict VNDK
+# "ld.config.txt" as a source file. This configuration includes strict VNDK
 # run-time restrictions for vendor process.
 # Other treblized devices, that have not defined BOARD_VNDK_VERSION or that
-# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.txt" as a source
-# file. This configuration does not have strict VNDK run-time restrictions.
+# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.vndk_lite.txt"
+# as a source file. This configuration does not have strict VNDK run-time
+# restrictions.
 # If the device is not treblized, use "ld.config.legacy.txt" for legacy
 # namespace configuration.
 include $(CLEAR_VARS)
@@ -211,7 +217,7 @@
 LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
 include $(BUILD_SYSTEM)/base_rules.mk
 $(eval $(call update_and_install_ld_config,\
-  $(LOCAL_PATH)/etc/ld.config.txt.in,\
+  $(LOCAL_PATH)/etc/ld.config.txt,\
   $(LOCAL_BUILT_MODULE),\
   $(PLATFORM_VNDK_VERSION)))
 
@@ -220,7 +226,7 @@
 LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
 include $(BUILD_SYSTEM)/base_rules.mk
 $(eval $(call update_and_install_ld_config,\
-  $(LOCAL_PATH)/etc/ld.config.txt,\
+  $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
   $(LOCAL_BUILT_MODULE),\
   $(if $(BOARD_VNDK_VERSION),$(PLATFORM_VNDK_VERSION))))
 
@@ -239,9 +245,9 @@
 #
 # This file is a temporary configuration file only for GSI. Originally GSI has
 # BOARD_VNDK_VERSION defined and has strict VNDK enforcing rule based on
-# "ld.config.txt.in". However for the devices, that have not defined
+# "ld.config.txt". However for the devices, that have not defined
 # BOARD_VNDK_VERSION, GSI provides this configuration file which is based on
-# "ld.config.txt".
+# "ld.config.vndk_lite.txt".
 # Do not install this file for the devices other than GSI.
 include $(CLEAR_VARS)
 LOCAL_MODULE := ld.config.noenforce.txt
@@ -250,7 +256,7 @@
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
 $(eval $(call update_and_install_ld_config,\
-  $(LOCAL_PATH)/etc/ld.config.txt,\
+  $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
   $(LOCAL_BUILT_MODULE),\
   $(PLATFORM_VNDK_VERSION)))
 
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 5d97a73..c8d87c8 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -30,21 +30,55 @@
 ###############################################################################
 # "default" namespace
 #
-# Framework-side code runs in this namespace. However, libs from other
-# partitions are also allowed temporarily.
+# Framework-side code runs in this namespace. Libs from /vendor partition
+# can't be loaded in this namespace.
 ###############################################################################
-namespace.default.isolated = false
+namespace.default.isolated = true
 
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
+namespace.default.search.paths = /system/${LIB}
+
+# We can't have entire /system/${LIB} as permitted paths because doing so
+# makes it possible to load libs in /system/${LIB}/vndk* directories by
+# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
+# VNDK libs are built with previous versions of Android and thus must not be
+# loaded into this namespace where libs built with the current version of
+# Android are loaded. Mixing the two types of libs in the same namespace can
+# cause unexpected problem.
+namespace.default.permitted.paths  = /system/${LIB}/drm
+namespace.default.permitted.paths += /system/${LIB}/extractors
+namespace.default.permitted.paths += /system/${LIB}/hw
+# These are where odex files are located. libart has to be able to dlopen the files
+namespace.default.permitted.paths += /system/framework
+namespace.default.permitted.paths += /system/app
+namespace.default.permitted.paths += /system/priv-app
+namespace.default.permitted.paths += /vendor/framework
+namespace.default.permitted.paths += /vendor/app
+namespace.default.permitted.paths += /vendor/priv-app
+namespace.default.permitted.paths += /oem/app
+namespace.default.permitted.paths += /product/framework
+namespace.default.permitted.paths += /product/app
+namespace.default.permitted.paths += /product/priv-app
+namespace.default.permitted.paths += /data
+namespace.default.permitted.paths += /mnt/expand
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
+
+namespace.default.asan.permitted.paths  = /data
+namespace.default.asan.permitted.paths += /system/${LIB}/drm
+namespace.default.asan.permitted.paths += /system/${LIB}/extractors
+namespace.default.asan.permitted.paths += /system/${LIB}/hw
+namespace.default.asan.permitted.paths += /system/framework
+namespace.default.asan.permitted.paths += /system/app
+namespace.default.asan.permitted.paths += /system/priv-app
+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 += /oem/app
+namespace.default.asan.permitted.paths += /product/framework
+namespace.default.asan.permitted.paths += /product/app
+namespace.default.asan.permitted.paths += /product/priv-app
+namespace.default.asan.permitted.paths += /mnt/expand
 
 ###############################################################################
 # "sphal" namespace
@@ -82,35 +116,10 @@
 # libs listed here can be used.
 namespace.sphal.links = default,vndk,rs
 
-# WARNING: only NDK libs can be listed here.
-namespace.sphal.link.default.shared_libs  = libc.so
-namespace.sphal.link.default.shared_libs += libEGL.so
-namespace.sphal.link.default.shared_libs += libGLESv1_CM.so
-namespace.sphal.link.default.shared_libs += libGLESv2.so
-namespace.sphal.link.default.shared_libs += libdl.so
-namespace.sphal.link.default.shared_libs += liblog.so
-namespace.sphal.link.default.shared_libs += libm.so
-namespace.sphal.link.default.shared_libs += libnativewindow.so
-namespace.sphal.link.default.shared_libs += libstdc++.so
-namespace.sphal.link.default.shared_libs += libsync.so
-namespace.sphal.link.default.shared_libs += libvndksupport.so
-namespace.sphal.link.default.shared_libs += libz.so
+namespace.sphal.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
-# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
-namespace.sphal.link.vndk.shared_libs  = android.hardware.renderscript@1.0.so
-namespace.sphal.link.vndk.shared_libs += android.hardware.graphics.common@1.0.so
-namespace.sphal.link.vndk.shared_libs += android.hardware.graphics.mapper@2.0.so
-namespace.sphal.link.vndk.shared_libs += android.hidl.memory@1.0.so
-namespace.sphal.link.vndk.shared_libs += libbase.so
-namespace.sphal.link.vndk.shared_libs += libc++.so
-namespace.sphal.link.vndk.shared_libs += libcutils.so
-namespace.sphal.link.vndk.shared_libs += libhardware.so
-namespace.sphal.link.vndk.shared_libs += libhidlbase.so
-namespace.sphal.link.vndk.shared_libs += libhidlmemory.so
-namespace.sphal.link.vndk.shared_libs += libhidltransport.so
-namespace.sphal.link.vndk.shared_libs += libhwbinder.so
-namespace.sphal.link.vndk.shared_libs += libion.so
-namespace.sphal.link.vndk.shared_libs += libutils.so
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
 # Renderscript gets separate namespace
 namespace.sphal.link.rs.shared_libs = libRS_internal.so
@@ -155,38 +164,13 @@
 
 namespace.rs.links = default,vndk
 
-namespace.rs.link.default.shared_libs  = libc.so
-namespace.rs.link.default.shared_libs += libEGL.so
-namespace.rs.link.default.shared_libs += libGLESv1_CM.so
-namespace.rs.link.default.shared_libs += libGLESv2.so
-namespace.rs.link.default.shared_libs += libdl.so
-namespace.rs.link.default.shared_libs += liblog.so
-namespace.rs.link.default.shared_libs += libm.so
-namespace.rs.link.default.shared_libs += libnativewindow.so
-namespace.rs.link.default.shared_libs += libstdc++.so
-namespace.rs.link.default.shared_libs += libsync.so
-namespace.rs.link.default.shared_libs += libvndksupport.so
-namespace.rs.link.default.shared_libs += libz.so
-# These two libs are private LLNDK libs but are exceptionally visible
-# in this 'rs' namespace because RenderScript framework libraries
-# which are loaded into this namespace are using them.
-namespace.rs.link.default.shared_libs += libft2.so
-namespace.rs.link.default.shared_libs += libmediandk.so
+namespace.rs.link.default.shared_libs  =  %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
 
-namespace.rs.link.vndk.shared_libs  = android.hardware.renderscript@1.0.so
-namespace.rs.link.vndk.shared_libs += android.hardware.graphics.common@1.0.so
-namespace.rs.link.vndk.shared_libs += android.hardware.graphics.mapper@2.0.so
-namespace.rs.link.vndk.shared_libs += android.hidl.memory@1.0.so
-namespace.rs.link.vndk.shared_libs += libbase.so
-namespace.rs.link.vndk.shared_libs += libc++.so
-namespace.rs.link.vndk.shared_libs += libcutils.so
-namespace.rs.link.vndk.shared_libs += libhardware.so
-namespace.rs.link.vndk.shared_libs += libhidlbase.so
-namespace.rs.link.vndk.shared_libs += libhidlmemory.so
-namespace.rs.link.vndk.shared_libs += libhidltransport.so
-namespace.rs.link.vndk.shared_libs += libhwbinder.so
-namespace.rs.link.vndk.shared_libs += libion.so
-namespace.rs.link.vndk.shared_libs += libutils.so
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
 ###############################################################################
 # "vndk" namespace
@@ -204,6 +188,8 @@
 namespace.vndk.permitted.paths += /odm/${LIB}/egl
 namespace.vndk.permitted.paths += /vendor/${LIB}/hw
 namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
 
 namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
 namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
@@ -221,21 +207,15 @@
 namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
 namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/egl
 
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
+namespace.vndk.asan.permitted.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
 # When these NDK libs are required inside this namespace, then it is redirected
 # to the default namespace. This is possible since their ABI is stable across
 # Android releases.
 namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs  = android.hidl.memory@1.0-impl.so
-namespace.vndk.link.default.shared_libs += libEGL.so
-namespace.vndk.link.default.shared_libs += libc.so
-namespace.vndk.link.default.shared_libs += libdl.so
-namespace.vndk.link.default.shared_libs += liblog.so
-namespace.vndk.link.default.shared_libs += libm.so
-namespace.vndk.link.default.shared_libs += libnativewindow.so
-namespace.vndk.link.default.shared_libs += libstdc++.so
-namespace.vndk.link.default.shared_libs += libsync.so
-namespace.vndk.link.default.shared_libs += libvndksupport.so
-namespace.vndk.link.default.shared_libs += libz.so
+namespace.vndk.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 ###############################################################################
 # Namespace config for vendor processes. In O, no restriction is enforced for
@@ -244,35 +224,88 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
-namespace.default.isolated = false
+additional.namespaces = system,vndk
+
+###############################################################################
+# "default" namespace
+#
+# This is the default linker namespace for a vendor process (a process started
+# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
+# are loaded directly into this namespace. However, other libs under the system
+# partition (VNDK and LLNDK libraries) are not loaded here but from the
+# separate namespace 'system'. The delegation to the system namespace is done
+# via the 'namespace.default.link.system.shared_libs' property below.
+###############################################################################
+namespace.default.isolated = true
+namespace.default.visible = true
 
 namespace.default.search.paths  = /odm/${LIB}
-namespace.default.search.paths += /odm/${LIB}/vndk
-namespace.default.search.paths += /odm/${LIB}/vndk-sp
 namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /vendor/${LIB}/vndk
-namespace.default.search.paths += /vendor/${LIB}/vndk-sp
 
-# Access to system libraries are allowed
-namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}
+namespace.default.permitted.paths  = /odm
+namespace.default.permitted.paths += /vendor
 
 namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
 namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
-namespace.default.asan.search.paths +=           /odm/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.default.asan.search.paths +=           /odm/${LIB}/vndk-sp
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
+
+namespace.default.asan.permitted.paths  = /data/asan/odm
+namespace.default.asan.permitted.paths +=           /odm
+namespace.default.asan.permitted.paths += /data/asan/vendor
+namespace.default.asan.permitted.paths +=           /vendor
+
+namespace.default.links = system,vndk
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.vndk.shared_libs  = %VNDK_SAMEPROCESS_LIBRARIES%
+namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is where VNDK and VNDK-SP libraries are loaded for
+# a vendor process.
+###############################################################################
+namespace.vndk.isolated = false
+
+namespace.vndk.search.paths  = /odm/${LIB}/vndk
+namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
+
+namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk
+namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the system namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = system,default
+namespace.vndk.link.system.shared_libs  = %LLNDK_LIBRARIES%
+namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.vndk.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "system" namespace
+#
+# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
+# a vendor process.
+###############################################################################
+namespace.system.isolated = false
+
+namespace.system.search.paths = /system/${LIB}
+
+namespace.system.asan.search.paths  = /data/asan/system/${LIB}
+namespace.system.asan.search.paths +=           /system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
deleted file mode 100644
index 2a801fa..0000000
--- a/rootdir/etc/ld.config.txt.in
+++ /dev/null
@@ -1,303 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-#
-
-# Don't change the order here. The first pattern that matches with the
-# absolute path of an executable is selected.
-dir.system = /system/bin/
-dir.system = /system/xbin/
-
-dir.vendor = /odm/bin/
-dir.vendor = /vendor/bin/
-dir.vendor = /data/nativetest/odm
-dir.vendor = /data/nativetest64/odm
-dir.vendor = /data/benchmarktest/odm
-dir.vendor = /data/benchmarktest64/odm
-dir.vendor = /data/nativetest/vendor
-dir.vendor = /data/nativetest64/vendor
-dir.vendor = /data/benchmarktest/vendor
-dir.vendor = /data/benchmarktest64/vendor
-
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
-[system]
-additional.namespaces = sphal,vndk,rs
-
-###############################################################################
-# "default" namespace
-#
-# Framework-side code runs in this namespace. Libs from /vendor partition
-# can't be loaded in this namespace.
-###############################################################################
-namespace.default.isolated = true
-
-namespace.default.search.paths = /system/${LIB}
-
-# We can't have entire /system/${LIB} as permitted paths because doing so
-# makes it possible to load libs in /system/${LIB}/vndk* directories by
-# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
-# VNDK libs are built with previous versions of Android and thus must not be
-# loaded into this namespace where libs built with the current version of
-# Android are loaded. Mixing the two types of libs in the same namespace can
-# cause unexpected problem.
-namespace.default.permitted.paths  = /system/${LIB}/drm
-namespace.default.permitted.paths += /system/${LIB}/extractors
-namespace.default.permitted.paths += /system/${LIB}/hw
-# These are where odex files are located. libart has to be able to dlopen the files
-namespace.default.permitted.paths += /system/framework
-namespace.default.permitted.paths += /system/app
-namespace.default.permitted.paths += /system/priv-app
-namespace.default.permitted.paths += /vendor/framework
-namespace.default.permitted.paths += /vendor/app
-namespace.default.permitted.paths += /vendor/priv-app
-namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /data
-namespace.default.permitted.paths += /mnt/expand
-
-namespace.default.asan.search.paths  = /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-
-namespace.default.asan.permitted.paths  = /data
-namespace.default.asan.permitted.paths += /system/${LIB}/drm
-namespace.default.asan.permitted.paths += /system/${LIB}/extractors
-namespace.default.asan.permitted.paths += /system/${LIB}/hw
-namespace.default.asan.permitted.paths += /system/framework
-namespace.default.asan.permitted.paths += /system/app
-namespace.default.asan.permitted.paths += /system/priv-app
-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 += /oem/app
-namespace.default.asan.permitted.paths += /mnt/expand
-
-###############################################################################
-# "sphal" namespace
-#
-# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
-# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
-# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
-#
-# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
-# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
-# that they should be searched and loaded from this namespace.
-#
-# Note that there is no link from the default namespace to this namespace.
-###############################################################################
-namespace.sphal.isolated = true
-namespace.sphal.visible = true
-
-namespace.sphal.search.paths  = /odm/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}
-
-namespace.sphal.permitted.paths  = /odm/${LIB}
-namespace.sphal.permitted.paths += /vendor/${LIB}
-
-namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}
-namespace.sphal.asan.search.paths +=           /odm/${LIB}
-namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.search.paths +=           /vendor/${LIB}
-
-namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}
-namespace.sphal.asan.permitted.paths +=           /odm/${LIB}
-namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.permitted.paths +=           /vendor/${LIB}
-
-# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
-
-namespace.sphal.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
-###############################################################################
-# "rs" namespace
-#
-# This namespace is exclusively for Renderscript internal libraries.
-# This namespace has slightly looser restriction than the vndk namespace because
-# of the genuine characteristics of Renderscript; /data is in the permitted path
-# to load the compiled *.so file and libmediandk.so can be used here.
-###############################################################################
-namespace.rs.isolated = true
-namespace.rs.visible = true
-
-namespace.rs.search.paths  = /odm/${LIB}/vndk-sp
-namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.search.paths += /odm/${LIB}
-namespace.rs.search.paths += /vendor/${LIB}
-
-namespace.rs.permitted.paths  = /odm/${LIB}
-namespace.rs.permitted.paths += /vendor/${LIB}
-namespace.rs.permitted.paths += /data
-
-namespace.rs.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
-namespace.rs.asan.search.paths +=           /odm/${LIB}
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.search.paths +=           /vendor/${LIB}
-
-namespace.rs.asan.permitted.paths  = /data/asan/odm/${LIB}
-namespace.rs.asan.permitted.paths +=           /odm/${LIB}
-namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.permitted.paths +=           /vendor/${LIB}
-namespace.rs.asan.permitted.paths += /data
-
-namespace.rs.links = default,vndk
-
-namespace.rs.link.default.shared_libs  =  %LLNDK_LIBRARIES%
-namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
-# namespace because RS framework libs are using them.
-namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-
-namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is exclusively for vndk-sp libs.
-###############################################################################
-namespace.vndk.isolated = true
-namespace.vndk.visible = true
-
-namespace.vndk.search.paths  = /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.permitted.paths  = /odm/${LIB}/hw
-namespace.vndk.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /vendor/${LIB}/egl
-# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
-namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.asan.permitted.paths  = /data/asan/odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
-namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/egl
-
-namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
-namespace.vndk.asan.permitted.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the default namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# Namespace config for vendor processes. In O, no restriction is enforced for
-# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
-# the default namespace. 'system' namespace will be added to give limited
-# (LL-NDK only) access.
-###############################################################################
-[vendor]
-additional.namespaces = system,vndk
-
-###############################################################################
-# "default" namespace
-#
-# This is the default linker namespace for a vendor process (a process started
-# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
-# are loaded directly into this namespace. However, other libs under the system
-# partition (VNDK and LLNDK libraries) are not loaded here but from the
-# separate namespace 'system'. The delegation to the system namespace is done
-# via the 'namespace.default.link.system.shared_libs' property below.
-###############################################################################
-namespace.default.isolated = true
-namespace.default.visible = true
-
-namespace.default.search.paths  = /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.permitted.paths  = /odm
-namespace.default.permitted.paths += /vendor
-
-namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-
-namespace.default.asan.permitted.paths  = /data/asan/odm
-namespace.default.asan.permitted.paths +=           /odm
-namespace.default.asan.permitted.paths += /data/asan/vendor
-namespace.default.asan.permitted.paths +=           /vendor
-
-namespace.default.links = system,vndk
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.default.link.vndk.shared_libs  = %VNDK_SAMEPROCESS_LIBRARIES%
-namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is where VNDK and VNDK-SP libraries are loaded for
-# a vendor process.
-###############################################################################
-namespace.vndk.isolated = false
-
-namespace.vndk.search.paths  = /odm/${LIB}/vndk
-namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the system namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = system
-namespace.vndk.link.system.shared_libs  = %LLNDK_LIBRARIES%
-namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "system" namespace
-#
-# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
-# a vendor process.
-###############################################################################
-namespace.system.isolated = false
-
-namespace.system.search.paths = /system/${LIB}
-
-namespace.system.asan.search.paths  = /data/asan/system/${LIB}
-namespace.system.asan.search.paths +=           /system/${LIB}
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
new file mode 100644
index 0000000..5256cb1
--- /dev/null
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -0,0 +1,224 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Bionic loader config file.
+#
+
+# Don't change the order here. The first pattern that matches with the
+# absolute path of an executable is selected.
+dir.system = /system/bin/
+dir.system = /system/xbin/
+
+dir.vendor = /odm/bin/
+dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/odm
+dir.vendor = /data/nativetest64/odm
+dir.vendor = /data/benchmarktest/odm
+dir.vendor = /data/benchmarktest64/odm
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
+
+[system]
+additional.namespaces = sphal,vndk,rs
+
+###############################################################################
+# "default" namespace
+#
+# Framework-side code runs in this namespace. However, libs from other
+# partitions are also allowed temporarily.
+###############################################################################
+namespace.default.isolated = false
+
+namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.asan.search.paths  = /data/asan/system/${LIB}
+namespace.default.asan.search.paths +=           /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths +=           /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths +=           /vendor/${LIB}
+
+###############################################################################
+# "sphal" namespace
+#
+# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
+# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
+# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
+#
+# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
+# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
+# that they should be searched and loaded from this namespace.
+#
+# Note that there is no link from the default namespace to this namespace.
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+
+namespace.sphal.search.paths  = /odm/${LIB}
+namespace.sphal.search.paths += /vendor/${LIB}
+
+namespace.sphal.permitted.paths  = /odm/${LIB}
+namespace.sphal.permitted.paths += /vendor/${LIB}
+
+namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}
+namespace.sphal.asan.search.paths +=           /odm/${LIB}
+namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.search.paths +=           /vendor/${LIB}
+
+namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}
+namespace.sphal.asan.permitted.paths +=           /odm/${LIB}
+namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.permitted.paths +=           /vendor/${LIB}
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = default,vndk,rs
+
+namespace.sphal.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
+
+###############################################################################
+# "rs" namespace
+#
+# This namespace is exclusively for Renderscript internal libraries.
+# This namespace has slightly looser restriction than the vndk namespace because
+# of the genuine characteristics of Renderscript; /data is in the permitted path
+# to load the compiled *.so file and libmediandk.so can be used here.
+###############################################################################
+namespace.rs.isolated = true
+namespace.rs.visible = true
+
+namespace.rs.search.paths  = /odm/${LIB}/vndk-sp
+namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
+namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.search.paths += /odm/${LIB}
+namespace.rs.search.paths += /vendor/${LIB}
+
+namespace.rs.permitted.paths  = /odm/${LIB}
+namespace.rs.permitted.paths += /vendor/${LIB}
+namespace.rs.permitted.paths += /data
+
+namespace.rs.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
+namespace.rs.asan.search.paths +=           /odm/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.rs.asan.search.paths +=           /vendor/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
+namespace.rs.asan.search.paths +=           /odm/${LIB}
+namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.rs.asan.search.paths +=           /vendor/${LIB}
+
+namespace.rs.asan.permitted.paths  = /data/asan/odm/${LIB}
+namespace.rs.asan.permitted.paths +=           /odm/${LIB}
+namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.rs.asan.permitted.paths +=           /vendor/${LIB}
+namespace.rs.asan.permitted.paths += /data
+
+namespace.rs.links = default,vndk
+
+namespace.rs.link.default.shared_libs  =  %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
+
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is exclusively for vndk-sp libs.
+###############################################################################
+namespace.vndk.isolated = true
+namespace.vndk.visible = true
+
+namespace.vndk.search.paths  = /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+
+namespace.vndk.permitted.paths  = /odm/${LIB}/hw
+namespace.vndk.permitted.paths += /odm/${LIB}/egl
+namespace.vndk.permitted.paths += /vendor/${LIB}/hw
+namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
+namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
+
+namespace.vndk.asan.permitted.paths  = /data/asan/odm/${LIB}/hw
+namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
+namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
+namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
+namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/egl
+
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
+namespace.vndk.asan.permitted.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the default namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = default
+namespace.vndk.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
+[vendor]
+namespace.default.isolated = false
+
+namespace.default.search.paths  = /odm/${LIB}
+namespace.default.search.paths += /odm/${LIB}/vndk
+namespace.default.search.paths += /odm/${LIB}/vndk-sp
+namespace.default.search.paths += /vendor/${LIB}
+namespace.default.search.paths += /vendor/${LIB}/vndk
+namespace.default.search.paths += /vendor/${LIB}/vndk-sp
+
+# Access to system libraries are allowed
+namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
+namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.search.paths += /system/${LIB}
+
+namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
+namespace.default.asan.search.paths +=           /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
+namespace.default.asan.search.paths +=           /odm/${LIB}/vndk
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.default.asan.search.paths +=           /odm/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths +=           /vendor/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.asan.search.paths += /data/asan/system/${LIB}
+namespace.default.asan.search.paths +=           /system/${LIB}
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 3168f40..f0681d2 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -18,10 +18,6 @@
     disabled
     seclabel u:r:adbd:s0
 
-# adbd on at boot in emulator
-on property:ro.kernel.qemu=1
-    start adbd
-
 on boot
     setprop sys.usb.configfs 0
 
diff --git a/usbd/usbd.rc b/usbd/usbd.rc
index c7838e8..809044a 100644
--- a/usbd/usbd.rc
+++ b/usbd/usbd.rc
@@ -2,4 +2,4 @@
     class late_start
     oneshot
     user root
-    group root usb
+    group root usb system