Merge "Set $TMPDIR for `adb shell`."
diff --git a/adb/Android.mk b/adb/Android.mk
index 2b6df70..d76d175 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -101,6 +101,8 @@
     sysdeps_win32.cpp \
     sysdeps/win32/errno.cpp \
     sysdeps/win32/stat.cpp \
+    client/usb_dispatch.cpp \
+    client/usb_libusb.cpp \
     client/usb_windows.cpp \
 
 LIBADB_TEST_windows_SRCS := \
@@ -159,9 +161,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libmdnssd
-LOCAL_STATIC_LIBRARIES_linux := libusb
-LOCAL_STATIC_LIBRARIES_darwin := libusb
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libmdnssd libusb
 
 LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
 LOCAL_MULTILIB := first
@@ -230,9 +230,7 @@
     libdiagnose_usb \
     libmdnssd \
     libgmock_host \
-
-LOCAL_STATIC_LIBRARIES_linux := libusb
-LOCAL_STATIC_LIBRARIES_darwin := libusb
+    libusb \
 
 # Set entrypoint to wmain from sysdeps_win32.cpp instead of main
 LOCAL_LDFLAGS_windows := -municode
@@ -298,14 +296,12 @@
     libdiagnose_usb \
     liblog \
     libmdnssd \
+    libusb \
 
 # Don't use libcutils on Windows.
 LOCAL_STATIC_LIBRARIES_darwin := libcutils
 LOCAL_STATIC_LIBRARIES_linux := libcutils
 
-LOCAL_STATIC_LIBRARIES_darwin += libusb
-LOCAL_STATIC_LIBRARIES_linux += libusb
-
 LOCAL_CXX_STL := libc++_static
 
 # Don't add anything here, we don't want additional shared dependencies
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 8120199..a5e6f23 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -41,8 +41,6 @@
 #include "transport.h"
 #include "usb.h"
 
-using namespace std::literals;
-
 using android::base::StringPrintf;
 
 // RAII wrappers for libusb.
@@ -222,7 +220,7 @@
 
     // Use size_t for interface_num so <iostream>s don't mangle it.
     size_t interface_num;
-    uint16_t zero_mask;
+    uint16_t zero_mask = 0;
     uint8_t bulk_in = 0, bulk_out = 0;
     size_t packet_size = 0;
     bool found_adb = false;
@@ -372,9 +370,9 @@
 #endif
     }
 
-    auto result =
-        std::make_unique<usb_handle>(device_address, device_serial, std::move(handle),
-                                     interface_num, bulk_in, bulk_out, zero_mask, packet_size);
+    std::unique_ptr<usb_handle> result(new usb_handle(device_address, device_serial,
+                                                      std::move(handle), interface_num, bulk_in,
+                                                      bulk_out, zero_mask, packet_size));
     usb_handle* usb_handle_raw = result.get();
 
     {
@@ -397,7 +395,7 @@
     // hack around this by inserting a sleep.
     auto thread = std::thread([device]() {
         std::string device_path = get_device_dev_path(device);
-        std::this_thread::sleep_for(1s);
+        std::this_thread::sleep_for(std::chrono::seconds(1));
 
         process_device(device);
         if (--connecting_devices == 0) {
@@ -448,8 +446,8 @@
     }
 }
 
-static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
-                            void*) {
+static LIBUSB_CALL int hotplug_callback(libusb_context*, libusb_device* device,
+                                        libusb_hotplug_event event, void*) {
     // We're called with the libusb lock taken. Call these on a separate thread outside of this
     // function so that the usb_handle mutex is always taken before the libusb mutex.
     static std::once_flag once;
@@ -493,59 +491,60 @@
     libusb_hotplug_deregister_callback(nullptr, hotplug_handle);
 }
 
+static LIBUSB_CALL void transfer_callback(libusb_transfer* transfer) {
+    transfer_info* info = static_cast<transfer_info*>(transfer->user_data);
+
+    LOG(DEBUG) << info->name << " transfer callback entered";
+
+    // Make sure that the original submitter has made it to the condition_variable wait.
+    std::unique_lock<std::mutex> lock(info->mutex);
+
+    LOG(DEBUG) << info->name << " callback successfully acquired lock";
+
+    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+        LOG(WARNING) << info->name << " transfer failed: " << libusb_error_name(transfer->status);
+        info->Notify();
+        return;
+    }
+
+    // usb_read() can return when receiving some data.
+    if (info->is_bulk_out && transfer->actual_length != transfer->length) {
+        LOG(DEBUG) << info->name << " transfer incomplete, resubmitting";
+        transfer->length -= transfer->actual_length;
+        transfer->buffer += transfer->actual_length;
+        int rc = libusb_submit_transfer(transfer);
+        if (rc != 0) {
+            LOG(WARNING) << "failed to submit " << info->name
+                         << " transfer: " << libusb_error_name(rc);
+            transfer->status = LIBUSB_TRANSFER_ERROR;
+            info->Notify();
+        }
+        return;
+    }
+
+    if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) {
+        LOG(DEBUG) << "submitting zero-length write";
+        transfer->length = 0;
+        int rc = libusb_submit_transfer(transfer);
+        if (rc != 0) {
+            LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc);
+            transfer->status = LIBUSB_TRANSFER_ERROR;
+            info->Notify();
+        }
+        return;
+    }
+
+    LOG(VERBOSE) << info->name << "transfer fully complete";
+    info->Notify();
+}
+
 // Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result.
 static int perform_usb_transfer(usb_handle* h, transfer_info* info,
                                 std::unique_lock<std::mutex> device_lock) {
     libusb_transfer* transfer = info->transfer;
 
     transfer->user_data = info;
-    transfer->callback = [](libusb_transfer* transfer) {
-        transfer_info* info = static_cast<transfer_info*>(transfer->user_data);
-
-        LOG(DEBUG) << info->name << " transfer callback entered";
-
-        // Make sure that the original submitter has made it to the condition_variable wait.
-        std::unique_lock<std::mutex> lock(info->mutex);
-
-        LOG(DEBUG) << info->name << " callback successfully acquired lock";
-
-        if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
-            LOG(WARNING) << info->name
-                         << " transfer failed: " << libusb_error_name(transfer->status);
-            info->Notify();
-            return;
-        }
-
-        // usb_read() can return when receiving some data.
-        if (info->is_bulk_out && transfer->actual_length != transfer->length) {
-            LOG(DEBUG) << info->name << " transfer incomplete, resubmitting";
-            transfer->length -= transfer->actual_length;
-            transfer->buffer += transfer->actual_length;
-            int rc = libusb_submit_transfer(transfer);
-            if (rc != 0) {
-                LOG(WARNING) << "failed to submit " << info->name
-                             << " transfer: " << libusb_error_name(rc);
-                transfer->status = LIBUSB_TRANSFER_ERROR;
-                info->Notify();
-            }
-            return;
-        }
-
-        if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) {
-            LOG(DEBUG) << "submitting zero-length write";
-            transfer->length = 0;
-            int rc = libusb_submit_transfer(transfer);
-            if (rc != 0) {
-                LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc);
-                transfer->status = LIBUSB_TRANSFER_ERROR;
-                info->Notify();
-            }
-            return;
-        }
-
-        LOG(VERBOSE) << info->name << "transfer fully complete";
-        info->Notify();
-    };
+    transfer->callback = transfer_callback;
 
     LOG(DEBUG) << "locking " << info->name << " transfer_info mutex";
     std::unique_lock<std::mutex> lock(info->mutex);
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 61981b1..9751ebf 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <algorithm>
 #include <mutex>
 #include <thread>
 
@@ -40,6 +41,8 @@
 #include "sysdeps/chrono.h"
 #include "transport.h"
 
+namespace native {
+
 /** Structure usb_handle describes our connection to the usb device via
   AdbWinApi.dll. This structure is returned from usb_open() routine and
   is expected in each subsequent call that is accessing the device.
@@ -48,13 +51,7 @@
   rely on AdbWinApi.dll's handle validation and AdbCloseHandle(endpoint)'s
   ability to break a thread out of pipe IO.
 */
-struct usb_handle {
-    /// Previous entry in the list of opened usb handles
-    usb_handle* prev;
-
-    /// Next entry in the list of opened usb handles
-    usb_handle* next;
-
+struct usb_handle : public ::usb_handle {
     /// Handle to USB interface
     ADBAPIHANDLE adb_interface;
 
@@ -78,9 +75,7 @@
 static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
 
 /// List of opened usb handles
-static usb_handle handle_list = {
-    .prev = &handle_list, .next = &handle_list,
-};
+static std::vector<usb_handle*> handle_list;
 
 /// Locker for the list of opened usb handles
 static std::mutex& usb_lock = *new std::mutex();
@@ -131,11 +126,9 @@
 int usb_close(usb_handle* handle);
 
 int known_device_locked(const wchar_t* dev_name) {
-    usb_handle* usb;
-
     if (NULL != dev_name) {
         // Iterate through the list looking for the name match.
-        for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        for (usb_handle* usb : handle_list) {
             // In Windows names are not case sensetive!
             if ((NULL != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
                 return 1;
@@ -168,10 +161,7 @@
     }
 
     // Not in the list. Add this handle to the list.
-    handle->next = &handle_list;
-    handle->prev = handle_list.prev;
-    handle->prev->next = handle;
-    handle->next->prev = handle;
+    handle_list.push_back(handle);
 
     return 1;
 }
@@ -274,10 +264,6 @@
         goto fail;
     }
 
-    // Set linkers back to the handle
-    ret->next = ret;
-    ret->prev = ret;
-
     // Create interface.
     ret->adb_interface = AdbCreateInterfaceByName(interface_name);
     if (NULL == ret->adb_interface) {
@@ -484,13 +470,8 @@
         // Remove handle from the list
         {
             std::lock_guard<std::mutex> lock(usb_lock);
-
-            if ((handle->next != handle) && (handle->prev != handle)) {
-                handle->next->prev = handle->prev;
-                handle->prev->next = handle->next;
-                handle->prev = handle;
-                handle->next = handle;
-            }
+            handle_list.erase(std::remove(handle_list.begin(), handle_list.end(), handle),
+                              handle_list.end());
         }
 
         // Cleanup handle
@@ -623,7 +604,9 @@
     // Need to acquire lock to safely walk the list which might be modified
     // by another thread.
     std::lock_guard<std::mutex> lock(usb_lock);
-    for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+    for (usb_handle* usb : handle_list) {
         usb_kick_locked(usb);
     }
 }
+
+}  // namespace native
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index a00ed5e..c3ac344 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -195,7 +195,7 @@
 }
 
 bool should_use_libusb() {
-#if defined(_WIN32) || !ADB_HOST
+#if !ADB_HOST
     return false;
 #else
     static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
diff --git a/adb/usb.h b/adb/usb.h
index f428ede..cd83c42 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -29,8 +29,8 @@
     void usb_kick(handle_ref_type h);                            \
     size_t usb_get_max_packet_size(handle_ref_type)
 
-#if defined(_WIN32) || !ADB_HOST
-// Windows and the daemon have a single implementation.
+#if !ADB_HOST
+// The daemon has a single implementation.
 
 struct usb_handle;
 ADB_USB_INTERFACE(usb_handle*);
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 3041492..641f712 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -222,6 +222,7 @@
     } else {
       num_ignore_frames--;
     }
+    is_debug_frame_used_ = false;
     ret = unw_step(&cursor);
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
@@ -318,7 +319,8 @@
       }
     }
   }
-  if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
+  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
diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h
index c0b686e..70a9842 100644
--- a/libbacktrace/BacktraceOffline.h
+++ b/libbacktrace/BacktraceOffline.h
@@ -48,7 +48,8 @@
                    bool cache_file)
       : Backtrace(pid, tid, map),
         cache_file_(cache_file),
-        context_(nullptr) {
+        context_(nullptr),
+        is_debug_frame_used_(false) {
     stack_space_.start = stack.start;
     stack_space_.end = stack.end;
     stack_space_.data = stack.data;
@@ -78,6 +79,14 @@
   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/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
index bb4134f..a23e3b4 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -103,8 +103,9 @@
       exit(1);
     }
 
-    if (num_maps != kNumMaps) {
-      fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected.\n", num_maps, kNumMaps);
+    if (num_maps < kNumMaps) {
+      fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected at least.\n", num_maps,
+              kNumMaps);
       std::string str;
       android::base::ReadFileToString("/proc/self/maps", &str);
       fprintf(stderr, "%s\n", str.c_str());
@@ -121,12 +122,12 @@
 
   size_t num_maps = 0;
   for (size_t i = 0; i < 2000; i++) {
-    if (CountMaps(pid, &num_maps) && num_maps == kNumMaps) {
+    if (CountMaps(pid, &num_maps) && num_maps >= kNumMaps) {
       break;
     }
     usleep(1000);
   }
-  if (num_maps != kNumMaps) {
+  if (num_maps < kNumMaps) {
     fprintf(stderr, "Timed out waiting for the number of maps available: %zu\n", num_maps);
     return;
   }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index d1b44a1..9ba2b1c 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -357,68 +357,24 @@
   BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
 }
 
-// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
-// overlap with each other, which appears in /system/lib/libart.so.
-TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
-  // TODO: For now, only run on the given arch.
-  if (std::string(ABI_STRING) != "arm") {
+static void LibUnwindingTest(const std::string& arch, 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("libart.so"));
+  const std::string testlib_path(GetTestPath(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("offline_testdata_for_libart"));
+  const std::string offline_testdata_path(GetTestPath(testdata_name));
   OfflineTestData testdata;
   ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
 
-  // Fix path of /system/lib/libart.so.
+  // Fix path of the testlib.
   for (auto& map : testdata.maps) {
-    if (map.name.find("libart.so") != std::string::npos) {
-      map.name = testlib_path;
-    }
-  }
-
-  // Do offline backtrace.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
-  ASSERT_TRUE(map != nullptr);
-
-  std::unique_ptr<Backtrace> backtrace(
-      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
-  ASSERT_TRUE(backtrace != nullptr);
-
-  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
-  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
-
-  // The last frame is outside of libart.so
-  ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
-  for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
-    uintptr_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);
-    ASSERT_EQ(name, testdata.symbols[i].name);
-  }
-}
-
-TEST(libbacktrace, offline_debug_frame_with_load_bias) {
-  if (std::string(ABI_STRING) != "arm") {
-    GTEST_LOG_(INFO) << "Skipping test since offline for arm on " << ABI_STRING
-                     << " isn't supported.";
-    return;
-  }
-  const std::string testlib_path(GetTestPath("libandroid_runtime.so"));
-  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("offline_testdata_for_libandroid_runtime"));
-  OfflineTestData testdata;
-  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
-
-  // Fix path of /system/lib/libandroid_runtime.so.
-  for (auto& map : testdata.maps) {
-    if (map.name.find("libandroid_runtime.so") != std::string::npos) {
+    if (map.name.find(testlib_name) != std::string::npos) {
       map.name = testlib_path;
     }
   }
@@ -442,3 +398,17 @@
     ASSERT_EQ(name, testdata.symbols[i].name);
   }
 }
+
+// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
+// overlap with each other, which appears in /system/lib/libart.so.
+TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+  LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
+}
+
+TEST(libbacktrace, offline_debug_frame_with_load_bias) {
+  LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
+}
+
+TEST(libbacktrace, offline_try_armexidx_after_debug_frame) {
+  LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
+}
diff --git a/libbacktrace/testdata/arm/libGLESv2_adreno.so b/libbacktrace/testdata/arm/libGLESv2_adreno.so
new file mode 100644
index 0000000..871f6dc
--- /dev/null
+++ b/libbacktrace/testdata/arm/libGLESv2_adreno.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
new file mode 100644
index 0000000..1f96834
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
@@ -0,0 +1,6 @@
+pid: 7288 tid: 31656
+regs: pc: cc416235 sp: cc17f000
+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
+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_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
index 03e1df5..db9bf8d 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libart
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -1,7 +1,7 @@
 pid: 32232 tid: 32233
 registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
 map: start: e9380000 end: e9766000 offset: 0 load_bias: b000 flags: 5 name: /system/lib/libart.so
-stack: start: ffd12dc0 end: ffd16000 size: 12864 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d8952431abed6fac33576fb438d1ff030000007800502400000000a0005024060000007893476f00908eec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004489bd6f78005024d00c5024a0005024a431d1ff2c31d1ff9b99aa71a4d49c6f30d8952400000000e8d895244489bd6fa8e5bc6fc8b895240100000000000000b033d1ff56000000637171e900000000d00c5024c8b89524000000000100000000000000b033d1ff560000006431d1ffa431d1ff000000009fb671e9b033d1ff00000000a431d1ff6431d1ffc431d1ff000000000000000081b771e9b033d1ff00000000c431d1ff8431d1ff01000000020000002429000001000000dc501b002033d1ff0100000018f9736f0100000000908eec58d8952440f180e9a8ec01245b215ce8a4d49c6f00908eec0832d1ffb033d1ff040000008c908eeca832d1ffabc141e9b033d1ff5b215ce82832d1ffb033d1ff080000008c908eec000000000035d1ff0834d1ffa832d1ffa4d49c6f04000000cca312e800908eec6832d1ffb033d1ff0834d1ff6bc354e9b033d1ff5b215ce8cca312e800908eec8832d1ffb033d1ff0834d1ff6bc354e900908eeca4d49c6f44b8bfeb1833d1ff000000006832d1ffb033d1ff478054e9b033d1ff1b8054e90834d1ffa4d49c6f0000000000000000000000000000000008000000000000000834d1ff0000000000000000000000000000000000000000000000000000000058d895240000000000000000000000000000000000000000000000000000000058d89524b17e54e98c56af6f00000000a4d49c6f288944e800908eec00000000d032d1ff0000000000000000000000000000000000000000000000007e8ea6c358a58cec00f580e90834d1ffa4d49c6f58d8952400908eecb033d1ffe9100000da8844e8833c70e9e9100000b033d1ff0200000058d8952408b1796f0200000000908eecda8844e82c34d1ff00908eece9100000005d70e9070000007d1300006034d1ff98d170e9b033d1ff0834d1ff148844e800908eecb033d1ffa034d1ffa833d1ff0100000044b8bfeb41f252e9e91fdeeaa491deea000000004700000001000000d9c4ddea0000000000000000b834d1ff00b051ff0834d1ff00908eecf833d1ffa034d1ff148844e800000000020000004d4c53e900000000000000000000000000908eec44b8bfeb0834d1ff3835d1ff148844e85035d1ffbb936fe90000000044b8bfebb033d1ffda8844e8148844e8000000000d0000005a0000007d137d13d00c502400000000600480240400000070048024f80c5024170000000100000002000000000000000040000000000000d0018024d00c502400000000600480240000000070048024f80c5024000000000000000000000000000000000000000000000000d001802465906fe97b2e5ce8000000000300000000000000881388131a00000001000000000000004cdd76e9010000007b2e5ce8020000009835d1ff5835d1ffc435d1ff010000000000000000000000010000000000000000dd76e90834d1ff0d0000000100000000000000000000005035d1ff9036d1ff00000000a435d1ff7e8ea6c3080000000000000000000000000000000000000038cb7e7044b8bfeb7d2e5ce800000000c037d1ff5600000000908eec00000000cc35d1ff55af71e9e0285a6f040000000800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e00000018eb01243173d870040000007d2e5ce800000000c037d1ff5600000000000000cc35d1ff637171e90000000018eb012402000000010000007d2e5ce800000000c037d1ff560000004436d1ff000000000000000081b771e9c037d1ff000000004436d1ff0436d1ff00e68dec0800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e000000adf861e918eb01243173d870040000007b2e5ce844b8bfeb00908eeca836d1ffc037d1ff040000008c908eec7c37d1ffd5c141e9c037d1ff7b2e5ce80000000000908eecd036d1ff00000000b038d1ff183ad1ff0000000044b8bfeb1038d1ff7c37d1ff6c37d1ffc037d1ff7b2e5ce8000000007b2e5ce8610d67e9c037d1ff7b2e5ce8280477e99835456f960300009a35456f10aa5e6f9a35456f9835456f68b85e6f881e77e9b30a47e9e81382e94c95b4ec7100000000908eec9c908eec30528bec1038d1ff7b2e5ce800000000c78469e91038d1ff0aeb3b52208989ec150645e9010000001038d1ff6c37d1ff44b8bfeb6c37d1ff00000000d837d1ff1038d1ff7b2e5ce8000000006c38d1ff8f0b67e97b2e5ce818eb012400000000000000000838d1ff7b2e5ce802000000040000007c37d1ff18eb01249835456f00000000901e77e9180000000300000000908eec480000004800000043000000640477e97669747954687265070000001a00000060eb0124000000000000000000000000a500000044b8bfeb1038d1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce96c38d1ff18eb012400908eeceeac73e943000000640477e9000059008bc95ce900908eec30528bec409181e900908eec430000005900000000528bec409181e900004300710000000300000030528bec89c75ce944b8bfebe2050000103dd1ff03000000a3f6a7eb89c75ce96c38d1ff7e8ea6c389c75ce997f5a7eb710000000000000030528bec7e8ea6c3e83cd1ff2079002488beba6ff0ca726f5600000000908eec000000005439d1ff8b1db8aa803a89ec7e8ea6c3000000009173d870ec55af6f00000000010000004892796f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003801802488beba6ff0ca726f56000000000000005439d1ff9d3daa71cc55af6f7039d1ff0b0000006839d1ff7d2e5ce800000000483bd1ff637171e900000000207900240b00000058a58cec40f180e9010000007d2e5ce800000000483bd1ff56000000cc39d1ff000000000000000081b771e9483bd1ff00000000cc39d1ff8c39d1ff05000000050000000c000000040000000100000012000000958c00000100000074d73500483bd1ff01000000e880746f0100000000908eec903ad1ff40f180e97e02000000908eec2079002400000000383ad1ff7b2e5ce8cc55af6f00908eec303ad1ff483bd1ff040000008c908eec043bd1ffd5c141e9483bd1ff7b2e5ce840f180e900908eec583ad1ff00000000000000000000000000000000cc55af6f983bd1ff043bd1fff43ad1ff483bd1ff7b2e5ce8000000007b2e5ce8610d67e9483bd1ff7b2e5ce8280477e94892796f860100004e92796f00a088ec4e92796f4892796f18a688ec881e77e9b30a47e978e388ec4c95b4ec2100000000908eec9c908eec30528bec983bd1ff7b2e5ce800000000c78469e9983bd1ff06b005fdf0298aec150645e901000000983bd1fff43ad1ffcc55af6ff43ad1ff00000000603bd1ff983bd1ff7b2e5ce800000000f43bd1ff8f0b67e97b2e5ce8e00864e80000000000000000903bd1ff7b2e5ce80200000004000000043bd1ff207900249c908eec04000000583bd1ff603bd1ff4892796f04000000ac3bd1ff01000000901e77e917885ee9010000004d5cb1eb485cb1eb00908eec4892796f00000000000000000000000000004300cc55af6f983bd1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce9f43bd1ff55000000ac3bd1ffeeac73e943000000640477e900005900e3225ce900908eec30528bec409181e900908eec430000005900000000528bec409181e9000043005500000078e388ec2100000009215ce901000000ce3fb8aae83cd1ff40420f00a3f6a7eb09215ce9f43bd1ff7e8ea6c309215ce9ed0ea8eb2100000075270000003289ec0000000030528becef665c74db0e42e911ac58e99daf58e9103dd1ff010000007e8ea6c31b000000385cd1ff385cd1ff02000000103dd1ff0300000087e26deae43cd1ff0200000001000000a31eb8aa020000007c3cd1ff18ac89ec1dac89ec0f000000fc94b4ec7c3cd1ff18ac89ec7e8ea6c3e83cd1ff884dd1ff741ab8aaa81ab8aa000000000700000004000000e43cd1ff3b19b8aa000000000000000000000000000000000000000000000000884dd1ff0000000001000000844dd1ff7e8ea6c3f065b4ec00fd0000205db8aa308789ec010000000000000004000000b8e78aec18ac89ec005db8aa2ceab2eb101082e935000000000000000800000001100000ba5bd1ff99000000b8e78aec205db8aa508789ec030000000000000004000000e2050000108789ec00000000d991aeece583aeec10d0acec10d0acec50d0acec6170705f70726f63657373333200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080a4ec00000000001000009dfe6feb00000000975673eb000000002516b8aa844dd1ff08000000a84dd1ff0000000000000000000000007c4dd1ff3b996feb00000000000000000000000000000000000000005015b8aad45cb8aadc5cb8aae85cb8aa804dd1ff0000000015b8aeec08000000ba5bd1ffd45bd1ffe05bd1ffee5bd1ff0f5cd1ff335cd1ff355cd1ff385cd1ff00000000535cd1ff6f5cd1ff825cd1ff9d5cd1ffbf5cd1ffd45cd1ffee5cd1ff015dd1ff1c5dd1ffe35ed1fffc5ed1ff465fd1ffc55fd1ff0000000010000000d6b0270006000000001000001100000064000000030000003400b8aa040000002000000005000000090000000700000000d0adec080000000000000009000000ec14b8aa0b000000752700000c000000752700000d000000752700000e000000752700001700000000000000190000007c4ed1ff1a0000001f0000001f000000de5fd1ff0f0000008c4ed1ff00000000000000000000000086da76325883c1a6b44d586d68c7843576386c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000636f6d2e6578616d706c652e7375646f67616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f3d2f73797374656d2f62696e2f6170705f70726f63657373333200414e44524f49445f444154413d2f6461746100444f574e4c4f41445f43414348453d2f646174612f636163686500414e44524f49445f534f434b45545f7a79676f74655f7365636f6e646172793d3900414e44524f49445f524f4f543d2f73797374656d00415345435f4d4f554e54504f494e543d2f6d6e742f6173656300414e44524f49445f424f4f544c4f474f3d3100414e44524f49445f4153534554533d2f73797374656d2f61707000424f4f54434c415353504154483d2f73797374656d2f6672616d65776f726b2f636f72652d6f6a2e6a61723a2f73797374656d2f6672616d65776f726b2f636f72652d6c69626172742e6a61723a2f73797374656d2f6672616d65776f726b2f636f6e7363727970742e6a61723a2f73797374656d2f6672616d65776f726b2f6f6b687474702e6a61723a2f73797374656d2f6672616d65776f726b2f6c65676163792d746573742e6a61723a2f73797374656d2f6672616d65776f726b2f626f756e6379636173746c652e6a61723a2f73797374656d2f6672616d65776f726b2f6578742e6a61723a2f73797374656d2f6672616d65776f726b2f6672616d65776f726b2e6a61723a2f73797374656d2f6672616d65776f726b2f74656c6570686f6e792d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f766f69702d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f696d732d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f6170616368652d786d6c2e6a61723a2f73797374656d2f6672616d65776f726b2f6f72672e6170616368652e687474702e6c65676163792e626f6f742e6a617200414e44524f49445f53544f524147453d2f73746f7261676500504154483d2f7362696e3a2f73797374656d2f7362696e3a2f73797374656d2f62696e3a2f73797374656d2f7862696e3a2f76656e646f722f62696e3a2f76656e646f722f7862696e0053595354454d534552564552434c415353504154483d2f73797374656d2f6672616d65776f726b2f73657276696365732e6a61723a2f73797374656d2f6672616d65776f726b2f65746865726e65742d736572766963652e6a61723a2f73797374656d2f6672616d65776f726b2f776966692d736572766963652e6a61720045585445524e414c5f53544f524147453d2f736463617264002f73797374656d2f62696e2f6170705f70726f636573733332000000000000000000
+stack: start: ffd12dc0 end: ffd1306c size: 684 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d89524
 function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
 function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
 function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 4125b12..21dd306 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -64,6 +64,8 @@
         "RegsArm64.cpp",
         "RegsX86.cpp",
         "RegsX86_64.cpp",
+        "RegsMips.cpp",
+        "RegsMips64.cpp",
         "Unwinder.cpp",
         "Symbols.cpp",
     ],
@@ -86,6 +88,12 @@
         x86_64: {
             srcs: ["AsmGetRegsX86_64.S"],
         },
+        mips: {
+            srcs: ["AsmGetRegsMips.S"],
+        },
+        mips64: {
+            srcs: ["AsmGetRegsMips64.S"],
+        },
     },
 
     shared_libs: [
diff --git a/libunwindstack/AsmGetRegsMips.S b/libunwindstack/AsmGetRegsMips.S
new file mode 100644
index 0000000..183d0a9
--- /dev/null
+++ b/libunwindstack/AsmGetRegsMips.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+  .text
+  .type     AsmGetRegs, %function
+  .globl    AsmGetRegs
+  .ent      AsmGetRegs
+  .balign   16
+AsmGetRegs:
+  .cfi_startproc
+  .cfi_def_cfa $sp, 0
+  .set push
+  .set noreorder
+  .cpload $t9
+  sw   $zero, 0($a0)
+  .set noat
+  sw   $at, 4($a0)
+  .set at
+  sw   $v0, 8($a0)
+  sw   $v1, 12($a0)
+  sw   $a0, 16($a0)
+  sw   $a1, 20($a0)
+  sw   $a2, 24($a0)
+  sw   $a3, 28($a0)
+  sw   $t0, 32($a0)
+  sw   $t1, 36($a0)
+  sw   $t2, 40($a0)
+  sw   $t3, 44($a0)
+  sw   $t4, 48($a0)
+  sw   $t5, 52($a0)
+  sw   $t6, 56($a0)
+  sw   $t7, 60($a0)
+  sw   $s0, 64($a0)
+  sw   $s1, 68($a0)
+  sw   $s2, 72($a0)
+  sw   $s3, 76($a0)
+  sw   $s4, 80($a0)
+  sw   $s5, 84($a0)
+  sw   $s6, 88($a0)
+  sw   $s7, 92($a0)
+  sw   $t8, 96($a0)
+  sw   $t9, 100($a0)
+  sw   $k0, 104($a0)
+  sw   $k1, 108($a0)
+  sw   $gp, 112($a0)
+  sw   $sp, 116($a0)
+  sw   $s8, 120($a0)
+  sw   $ra, 124($a0)
+  jalr $zero, $ra
+  sw   $ra, 128($a0)   // set PC to the calling function
+
+  .set pop
+  .cfi_endproc
+  .size     AsmGetRegs, .-AsmGetRegs
+  .end      AsmGetRegs
diff --git a/libunwindstack/AsmGetRegsMips64.S b/libunwindstack/AsmGetRegsMips64.S
new file mode 100644
index 0000000..7a244f6
--- /dev/null
+++ b/libunwindstack/AsmGetRegsMips64.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+  .text
+  .type     AsmGetRegs, %function
+  .globl    AsmGetRegs
+  .ent      AsmGetRegs
+  .balign    16
+AsmGetRegs:
+  .cfi_startproc
+  .cfi_def_cfa $sp, 0
+  .set push
+  .set noreorder
+  .cpload $t9
+  sd   $zero, 0($a0)
+  .set noat
+  sd   $at, 8($a0)
+  .set at
+  sd   $v0, 16($a0)
+  sd   $v1, 24($a0)
+  sd   $a0, 32($a0)
+  sd   $a1, 40($a0)
+  sd   $a2, 48($a0)
+  sd   $a3, 56($a0)
+  sd   $a4, 64($a0)
+  sd   $a5, 72($a0)
+  sd   $a6, 80($a0)
+  sd   $a7, 88($a0)
+  sd   $t0, 96($a0)
+  sd   $t1, 104($a0)
+  sd   $t2, 112($a0)
+  sd   $t3, 120($a0)
+  sd   $s0, 128($a0)
+  sd   $s1, 136($a0)
+  sd   $s2, 144($a0)
+  sd   $s3, 152($a0)
+  sd   $s4, 160($a0)
+  sd   $s5, 168($a0)
+  sd   $s6, 176($a0)
+  sd   $s7, 184($a0)
+  sd   $t8, 192($a0)
+  sd   $t9, 200($a0)
+  sd   $k0, 208($a0)
+  sd   $k1, 216($a0)
+  sd   $gp, 224($a0)
+  sd   $sp, 232($a0)
+  sd   $s8, 240($a0)
+  sd   $ra, 248($a0)
+  jalr $zero, $ra
+  sd   $ra, 256($a0)   // set PC to the calling function
+
+  .set pop
+  .cfi_endproc
+  .size AsmGetRegs, .-AsmGetRegs
+  .end      AsmGetRegs
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 025429f..f486e23 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -189,9 +189,12 @@
     } else if (e_machine == EM_386) {
       arch_ = ARCH_X86;
       interface.reset(new ElfInterface32(memory));
+    } else if (e_machine == EM_MIPS) {
+      arch_ = ARCH_MIPS;
+      interface.reset(new ElfInterface32(memory));
     } else {
       // Unsupported.
-      ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
+      ALOGI("32 bit elf that is neither arm nor x86 nor mips: e_machine = %d\n", e_machine);
       return nullptr;
     }
   } else if (class_type_ == ELFCLASS64) {
@@ -205,9 +208,12 @@
       arch_ = ARCH_ARM64;
     } else if (e_machine == EM_X86_64) {
       arch_ = ARCH_X86_64;
+    } else if (e_machine == EM_MIPS) {
+      arch_ = ARCH_MIPS64;
     } else {
       // Unsupported.
-      ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
+      ALOGI("64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = %d\n",
+            e_machine);
       return nullptr;
     }
     interface.reset(new ElfInterface64(memory));
diff --git a/libunwindstack/MachineMips.h b/libunwindstack/MachineMips.h
new file mode 100644
index 0000000..2dfb1e9
--- /dev/null
+++ b/libunwindstack/MachineMips.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_MIPS_H
+#define _LIBUNWINDSTACK_MACHINE_MIPS_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum MipsReg : uint16_t {
+  MIPS_REG_R0 = 0,
+  MIPS_REG_R1,
+  MIPS_REG_R2,
+  MIPS_REG_R3,
+  MIPS_REG_R4,
+  MIPS_REG_R5,
+  MIPS_REG_R6,
+  MIPS_REG_R7,
+  MIPS_REG_R8,
+  MIPS_REG_R9,
+  MIPS_REG_R10,
+  MIPS_REG_R11,
+  MIPS_REG_R12,
+  MIPS_REG_R13,
+  MIPS_REG_R14,
+  MIPS_REG_R15,
+  MIPS_REG_R16,
+  MIPS_REG_R17,
+  MIPS_REG_R18,
+  MIPS_REG_R19,
+  MIPS_REG_R20,
+  MIPS_REG_R21,
+  MIPS_REG_R22,
+  MIPS_REG_R23,
+  MIPS_REG_R24,
+  MIPS_REG_R25,
+  MIPS_REG_R26,
+  MIPS_REG_R27,
+  MIPS_REG_R28,
+  MIPS_REG_R29,
+  MIPS_REG_R30,
+  MIPS_REG_R31,
+  MIPS_REG_PC,
+  MIPS_REG_LAST,
+
+  MIPS_REG_SP = MIPS_REG_R29,
+  MIPS_REG_RA = MIPS_REG_R31,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_MIPS_H
\ No newline at end of file
diff --git a/libunwindstack/MachineMips64.h b/libunwindstack/MachineMips64.h
new file mode 100644
index 0000000..34addf2
--- /dev/null
+++ b/libunwindstack/MachineMips64.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_MACHINE_MIPS64_H
+#define _LIBUNWINDSTACK_MACHINE_MIPS64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum Mips64Reg : uint16_t {
+  MIPS64_REG_R0 = 0,
+  MIPS64_REG_R1,
+  MIPS64_REG_R2,
+  MIPS64_REG_R3,
+  MIPS64_REG_R4,
+  MIPS64_REG_R5,
+  MIPS64_REG_R6,
+  MIPS64_REG_R7,
+  MIPS64_REG_R8,
+  MIPS64_REG_R9,
+  MIPS64_REG_R10,
+  MIPS64_REG_R11,
+  MIPS64_REG_R12,
+  MIPS64_REG_R13,
+  MIPS64_REG_R14,
+  MIPS64_REG_R15,
+  MIPS64_REG_R16,
+  MIPS64_REG_R17,
+  MIPS64_REG_R18,
+  MIPS64_REG_R19,
+  MIPS64_REG_R20,
+  MIPS64_REG_R21,
+  MIPS64_REG_R22,
+  MIPS64_REG_R23,
+  MIPS64_REG_R24,
+  MIPS64_REG_R25,
+  MIPS64_REG_R26,
+  MIPS64_REG_R27,
+  MIPS64_REG_R28,
+  MIPS64_REG_R29,
+  MIPS64_REG_R30,
+  MIPS64_REG_R31,
+  MIPS64_REG_PC,
+  MIPS64_REG_LAST,
+
+  MIPS64_REG_SP = MIPS64_REG_R29,
+  MIPS64_REG_RA = MIPS64_REG_R31,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MACHINE_MIPS64_H
\ No newline at end of file
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 29dbf9d..7feafad 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -27,16 +27,20 @@
 #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"
 
 namespace unwindstack {
 
 // The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
+constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10;
 
 // This function assumes that reg_data is already aligned to a 64 bit value.
 // If not this could crash with an unaligned access.
@@ -60,6 +64,10 @@
     return RegsArm::Read(buffer.data());
   case sizeof(arm64_user_regs):
     return RegsArm64::Read(buffer.data());
+  case sizeof(mips_user_regs):
+    return RegsMips::Read(buffer.data());
+  case sizeof(mips64_user_regs):
+    return RegsMips64::Read(buffer.data());
   }
   return nullptr;
 }
@@ -74,6 +82,10 @@
       return RegsArm::CreateFromUcontext(ucontext);
     case ARCH_ARM64:
       return RegsArm64::CreateFromUcontext(ucontext);
+    case ARCH_MIPS:
+      return RegsMips::CreateFromUcontext(ucontext);
+    case ARCH_MIPS64:
+      return RegsMips64::CreateFromUcontext(ucontext);
     case ARCH_UNKNOWN:
     default:
       return nullptr;
@@ -89,6 +101,10 @@
   return ARCH_X86;
 #elif defined(__x86_64__)
   return ARCH_X86_64;
+#elif defined(__mips__) && !defined(__LP64__)
+  return ARCH_MIPS;
+#elif defined(__mips__) && defined(__LP64__)
+  return ARCH_MIPS64;
 #else
   abort();
 #endif
@@ -104,6 +120,10 @@
   regs = new RegsX86();
 #elif defined(__x86_64__)
   regs = new RegsX86_64();
+#elif defined(__mips__) && !defined(__LP64__)
+  regs = new RegsMips();
+#elif defined(__mips__) && defined(__LP64__)
+  regs = new RegsMips64();
 #else
   abort();
 #endif
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
new file mode 100644
index 0000000..44cde05
--- /dev/null
+++ b/libunwindstack/RegsMips.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsMips.h>
+
+#include "MachineMips.h"
+#include "UcontextMips.h"
+#include "UserMips.h"
+
+namespace unwindstack {
+
+RegsMips::RegsMips()
+    : RegsImpl<uint32_t>(MIPS_REG_LAST, MIPS_REG_SP, Location(LOCATION_REGISTER, MIPS_REG_RA)) {}
+
+ArchEnum RegsMips::Arch() {
+  return ARCH_MIPS;
+}
+
+uint64_t RegsMips::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  // For now, just assuming no compact branches
+  if (rel_pc < 8) {
+    return rel_pc;
+  }
+  return rel_pc - 8;
+}
+
+void RegsMips::SetFromRaw() {
+  set_pc(regs_[MIPS_REG_PC]);
+  set_sp(regs_[MIPS_REG_SP]);
+}
+
+bool RegsMips::SetPcFromReturnAddress(Memory*) {
+  if (pc() == regs_[MIPS_REG_RA]) {
+    return false;
+  }
+
+  set_pc(regs_[MIPS_REG_RA]);
+  return true;
+}
+
+void RegsMips::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("r0", regs_[MIPS_REG_R0]);
+  fn("r1", regs_[MIPS_REG_R1]);
+  fn("r2", regs_[MIPS_REG_R2]);
+  fn("r3", regs_[MIPS_REG_R3]);
+  fn("r4", regs_[MIPS_REG_R4]);
+  fn("r5", regs_[MIPS_REG_R5]);
+  fn("r6", regs_[MIPS_REG_R6]);
+  fn("r7", regs_[MIPS_REG_R7]);
+  fn("r8", regs_[MIPS_REG_R8]);
+  fn("r9", regs_[MIPS_REG_R9]);
+  fn("r10", regs_[MIPS_REG_R10]);
+  fn("r11", regs_[MIPS_REG_R11]);
+  fn("r12", regs_[MIPS_REG_R12]);
+  fn("r13", regs_[MIPS_REG_R13]);
+  fn("r14", regs_[MIPS_REG_R14]);
+  fn("r15", regs_[MIPS_REG_R15]);
+  fn("r16", regs_[MIPS_REG_R16]);
+  fn("r17", regs_[MIPS_REG_R17]);
+  fn("r18", regs_[MIPS_REG_R18]);
+  fn("r19", regs_[MIPS_REG_R19]);
+  fn("r20", regs_[MIPS_REG_R20]);
+  fn("r21", regs_[MIPS_REG_R21]);
+  fn("r22", regs_[MIPS_REG_R22]);
+  fn("r23", regs_[MIPS_REG_R23]);
+  fn("r24", regs_[MIPS_REG_R24]);
+  fn("r25", regs_[MIPS_REG_R25]);
+  fn("r26", regs_[MIPS_REG_R26]);
+  fn("r27", regs_[MIPS_REG_R27]);
+  fn("r28", regs_[MIPS_REG_R28]);
+  fn("sp", regs_[MIPS_REG_SP]);
+  fn("r30", regs_[MIPS_REG_R30]);
+  fn("ra", regs_[MIPS_REG_RA]);
+  fn("pc", regs_[MIPS_REG_PC]);
+}
+
+Regs* RegsMips::Read(void* remote_data) {
+  mips_user_regs* user = reinterpret_cast<mips_user_regs*>(remote_data);
+  RegsMips* regs = new RegsMips();
+  uint32_t* reg_data = reinterpret_cast<uint32_t*>(regs->RawData());
+
+  memcpy(regs->RawData(), &user->regs[MIPS32_EF_R0], (MIPS_REG_R31 + 1) * sizeof(uint32_t));
+
+  reg_data[MIPS_REG_PC] = user->regs[MIPS32_EF_CP0_EPC];
+  regs->SetFromRaw();
+  return regs;
+}
+
+Regs* RegsMips::CreateFromUcontext(void* ucontext) {
+  mips_ucontext_t* mips_ucontext = reinterpret_cast<mips_ucontext_t*>(ucontext);
+
+  RegsMips* regs = new RegsMips();
+  // Copy 64 bit sc_regs over to 32 bit regs
+  for (int i = 0; i < 32; i++) {
+      (*regs)[MIPS_REG_R0 + i] = mips_ucontext->uc_mcontext.sc_regs[i];
+  }
+  (*regs)[MIPS_REG_PC] = mips_ucontext->uc_mcontext.sc_pc;
+  regs->SetFromRaw();
+  return regs;
+}
+
+bool RegsMips::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  uint64_t offset = 0;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  // Look for the kernel sigreturn functions.
+  // __vdso_rt_sigreturn:
+  // 0x24021061     li  v0, 0x1061
+  // 0x0000000c     syscall
+  // __vdso_sigreturn:
+  // 0x24021017     li  v0, 0x1017
+  // 0x0000000c     syscall
+  if (data == 0x0000000c24021061ULL) {
+    // vdso_rt_sigreturn => read rt_sigframe
+    // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
+    offset = 24 + 128 + 24 + 8;
+  } else if (data == 0x0000000c24021017LL) {
+    // vdso_sigreturn => read sigframe
+    // offset = sigcontext offset + sc_pc offset
+    offset = 24 + 8;
+  } else {
+    return false;
+  }
+
+  // read sc_pc and sc_regs[32] from stack
+  uint64_t values[MIPS_REG_LAST];
+  if (!process_memory->Read(sp() + offset, values, sizeof(values))) {
+    return false;
+  }
+
+  // Copy 64 bit sc_pc over to 32 bit regs_[MIPS_REG_PC]
+  regs_[MIPS_REG_PC] = values[0];
+
+  // Copy 64 bit sc_regs over to 32 bit regs
+  for (int i = 0; i < 32; i++) {
+      regs_[MIPS_REG_R0 + i] = values[1 + i];
+  }
+
+  SetFromRaw();
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
new file mode 100644
index 0000000..b4e5246
--- /dev/null
+++ b/libunwindstack/RegsMips64.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/RegsMips64.h>
+
+#include "MachineMips64.h"
+#include "UcontextMips64.h"
+#include "UserMips64.h"
+
+namespace unwindstack {
+
+RegsMips64::RegsMips64()
+    : RegsImpl<uint64_t>(MIPS64_REG_LAST, MIPS64_REG_SP,
+                         Location(LOCATION_REGISTER, MIPS64_REG_RA)) {}
+
+ArchEnum RegsMips64::Arch() {
+  return ARCH_MIPS64;
+}
+
+uint64_t RegsMips64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+  if (!elf->valid()) {
+    return rel_pc;
+  }
+
+  // For now, just assuming no compact branches
+  if (rel_pc < 8) {
+    return rel_pc;
+  }
+  return rel_pc - 8;
+}
+
+void RegsMips64::SetFromRaw() {
+  set_pc(regs_[MIPS64_REG_PC]);
+  set_sp(regs_[MIPS64_REG_SP]);
+}
+
+bool RegsMips64::SetPcFromReturnAddress(Memory*) {
+  if (pc() == regs_[MIPS64_REG_RA]) {
+    return false;
+  }
+
+  set_pc(regs_[MIPS64_REG_RA]);
+  return true;
+}
+
+void RegsMips64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("r0", regs_[MIPS64_REG_R0]);
+  fn("r1", regs_[MIPS64_REG_R1]);
+  fn("r2", regs_[MIPS64_REG_R2]);
+  fn("r3", regs_[MIPS64_REG_R3]);
+  fn("r4", regs_[MIPS64_REG_R4]);
+  fn("r5", regs_[MIPS64_REG_R5]);
+  fn("r6", regs_[MIPS64_REG_R6]);
+  fn("r7", regs_[MIPS64_REG_R7]);
+  fn("r8", regs_[MIPS64_REG_R8]);
+  fn("r9", regs_[MIPS64_REG_R9]);
+  fn("r10", regs_[MIPS64_REG_R10]);
+  fn("r11", regs_[MIPS64_REG_R11]);
+  fn("r12", regs_[MIPS64_REG_R12]);
+  fn("r13", regs_[MIPS64_REG_R13]);
+  fn("r14", regs_[MIPS64_REG_R14]);
+  fn("r15", regs_[MIPS64_REG_R15]);
+  fn("r16", regs_[MIPS64_REG_R16]);
+  fn("r17", regs_[MIPS64_REG_R17]);
+  fn("r18", regs_[MIPS64_REG_R18]);
+  fn("r19", regs_[MIPS64_REG_R19]);
+  fn("r20", regs_[MIPS64_REG_R20]);
+  fn("r21", regs_[MIPS64_REG_R21]);
+  fn("r22", regs_[MIPS64_REG_R22]);
+  fn("r23", regs_[MIPS64_REG_R23]);
+  fn("r24", regs_[MIPS64_REG_R24]);
+  fn("r25", regs_[MIPS64_REG_R25]);
+  fn("r26", regs_[MIPS64_REG_R26]);
+  fn("r27", regs_[MIPS64_REG_R27]);
+  fn("r28", regs_[MIPS64_REG_R28]);
+  fn("sp", regs_[MIPS64_REG_SP]);
+  fn("r30", regs_[MIPS64_REG_R30]);
+  fn("ra", regs_[MIPS64_REG_RA]);
+  fn("pc", regs_[MIPS64_REG_PC]);
+}
+
+Regs* RegsMips64::Read(void* remote_data) {
+  mips64_user_regs* user = reinterpret_cast<mips64_user_regs*>(remote_data);
+  RegsMips64* regs = new RegsMips64();
+  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+
+  memcpy(regs->RawData(), &user->regs[MIPS64_EF_R0], (MIPS64_REG_R31 + 1) * sizeof(uint64_t));
+
+  reg_data[MIPS64_REG_PC] = user->regs[MIPS64_EF_CP0_EPC];
+  regs->SetFromRaw();
+  return regs;
+}
+
+Regs* RegsMips64::CreateFromUcontext(void* ucontext) {
+  mips64_ucontext_t* mips64_ucontext = reinterpret_cast<mips64_ucontext_t*>(ucontext);
+
+  RegsMips64* regs = new RegsMips64();
+  // Copy 64 bit sc_regs over to 64 bit regs
+  memcpy(regs->RawData(), &mips64_ucontext->uc_mcontext.sc_regs[0], 32 * sizeof(uint64_t));
+  (*regs)[MIPS64_REG_PC] = mips64_ucontext->uc_mcontext.sc_pc;
+  regs->SetFromRaw();
+  return regs;
+}
+
+bool RegsMips64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  // Look for the kernel sigreturn function.
+  // __vdso_rt_sigreturn:
+  // 0x2402145b     li  v0, 0x145b
+  // 0x0000000c     syscall
+  if (data != 0x0000000c2402145bULL) {
+    return false;
+  }
+
+  // vdso_rt_sigreturn => read rt_sigframe
+  // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset
+  // read 64 bit sc_regs[32] from stack into 64 bit regs_
+  if (!process_memory->Read(sp() + 24 + 128 + 40, regs_.data(),
+                            sizeof(uint64_t) * (MIPS64_REG_LAST - 1))) {
+    return false;
+  }
+
+  // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
+  // read 64 bit sc_pc from stack into 64 bit regs_[MIPS64_REG_PC]
+  if (!process_memory->Read(sp() + 24 + 128 + 40 + 576, &regs_[MIPS64_REG_PC],
+                            sizeof(uint64_t))) {
+    return false;
+  }
+
+  SetFromRaw();
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/UcontextMips.h b/libunwindstack/UcontextMips.h
new file mode 100644
index 0000000..27185e7
--- /dev/null
+++ b/libunwindstack/UcontextMips.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS_H
+#define _LIBUNWINDSTACK_UCONTEXT_MIPS_H
+
+#include <stdint.h>
+
+#include "MachineMips.h"
+
+namespace unwindstack {
+
+struct mips_stack_t {
+  uint32_t ss_sp;    // void __user*
+  uint32_t ss_size;  // size_t
+  int32_t ss_flags;  // int
+};
+
+struct mips_mcontext_t {
+  uint32_t sc_regmask;
+  uint32_t sc_status;
+  uint64_t sc_pc;
+  uint64_t sc_regs[32];
+  // Nothing else is used, so don't define it.
+};
+
+struct mips_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  mips_stack_t uc_stack;
+  mips_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_MIPS_H
diff --git a/libunwindstack/UcontextMips64.h b/libunwindstack/UcontextMips64.h
new file mode 100644
index 0000000..623bf3a
--- /dev/null
+++ b/libunwindstack/UcontextMips64.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
+#define _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
+
+#include <stdint.h>
+
+#include "MachineMips64.h"
+
+namespace unwindstack {
+
+struct mips64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  uint64_t ss_size;  // size_t
+  int32_t ss_flags;  // int
+};
+
+struct mips64_mcontext_t {
+  uint64_t sc_regs[32];
+  uint64_t sc_fpregs[32];
+  uint64_t sc_mdhi;
+  uint64_t sc_hi1;
+  uint64_t sc_hi2;
+  uint64_t sc_hi3;
+  uint64_t sc_mdlo;
+  uint64_t sc_lo1;
+  uint64_t sc_lo2;
+  uint64_t sc_lo3;
+  uint64_t sc_pc;
+  // Nothing else is used, so don't define it.
+};
+
+struct mips64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  mips64_stack_t uc_stack;
+  mips64_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_MIPS6464_H
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 4ae365d..a83f85b 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -174,7 +174,7 @@
   if (frame_num >= frames_.size()) {
     return "";
   }
-  return FormatFrame(frames_[frame_num], regs_->Arch() == ARCH_ARM || regs_->Arch() == ARCH_X86);
+  return FormatFrame(frames_[frame_num], regs_->Format32Bit());
 }
 
 std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) {
diff --git a/libunwindstack/UserMips.h b/libunwindstack/UserMips.h
new file mode 100644
index 0000000..184be4f
--- /dev/null
+++ b/libunwindstack/UserMips.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_USER_MIPS_H
+#define _LIBUNWINDSTACK_USER_MIPS_H
+
+namespace unwindstack {
+
+enum Mips32UserReg : uint16_t {
+  MIPS32_EF_R0 = 6,
+  MIPS32_EF_CP0_EPC = 40,
+};
+
+struct mips_user_regs {
+  uint32_t regs[45];
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_USER_MIPS_H
diff --git a/libunwindstack/UserMips64.h b/libunwindstack/UserMips64.h
new file mode 100644
index 0000000..c46befd
--- /dev/null
+++ b/libunwindstack/UserMips64.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_USER_MIPS64_H
+#define _LIBUNWINDSTACK_USER_MIPS64_H
+
+namespace unwindstack {
+
+enum Mips64UserReg : uint16_t {
+  MIPS64_EF_R0 = 0,
+  MIPS64_EF_CP0_EPC = 34,
+};
+
+struct mips64_user_regs {
+  uint64_t regs[45];
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_USER_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index d27727b..a85e5f4 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -42,6 +42,8 @@
   ARCH_ARM64,
   ARCH_X86,
   ARCH_X86_64,
+  ARCH_MIPS,
+  ARCH_MIPS64,
 };
 
 class Elf {
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 7025fcf..613682f 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -51,6 +51,8 @@
 
   virtual ArchEnum Arch() = 0;
 
+  virtual bool Format32Bit() = 0;
+
   virtual void* RawData() = 0;
   virtual uint64_t pc() = 0;
   virtual uint64_t sp() = 0;
@@ -92,6 +94,8 @@
   void set_pc(AddressType pc) { pc_ = pc; }
   void set_sp(AddressType sp) { sp_ = sp; }
 
+  bool Format32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
+
   inline AddressType& operator[](size_t reg) { return regs_[reg]; }
 
   void* RawData() override { return regs_.data(); }
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index c59e081..557eace 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -87,7 +87,7 @@
   regs->SetFromRaw();
 }
 
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
 
 extern "C" void AsmGetRegs(void* regs);
 
@@ -97,11 +97,6 @@
   regs->SetFromRaw();
 }
 
-#elif defined(__mips__)
-
-// Stub to allow mips to build.
-void RegsGetLocal(Regs*) {}
-
 #endif
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
new file mode 100644
index 0000000..3fe6a9f
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_MIPS_H
+#define _LIBUNWINDSTACK_REGS_MIPS_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsMips : public RegsImpl<uint32_t> {
+ public:
+  RegsMips();
+  virtual ~RegsMips() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_MIPS_H
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
new file mode 100644
index 0000000..6b4bcdf
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_MIPS64_H
+#define _LIBUNWINDSTACK_REGS_MIPS64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsMips64 : public RegsImpl<uint64_t> {
+ public:
+  RegsMips64();
+  virtual ~RegsMips64() = default;
+
+  virtual ArchEnum Arch() override final;
+
+  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool SetPcFromReturnAddress(Memory* process_memory) override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
+
+  static Regs* Read(void* data);
+
+  static Regs* CreateFromUcontext(void* ucontext);
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_MIPS64_H
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 00192f1..7491d40 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -145,7 +145,7 @@
   ASSERT_FALSE(elf.Init(false));
 
   ASSERT_EQ("", GetFakeLogBuf());
-  ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
+  ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86 nor mips: e_machine = 20\n\n",
             GetFakeLogPrint());
 }
 
@@ -158,7 +158,7 @@
   ASSERT_FALSE(elf.Init(false));
 
   ASSERT_EQ("", GetFakeLogBuf());
-  ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
+  ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = 21\n\n",
             GetFakeLogPrint());
 }
 
@@ -174,6 +174,18 @@
   ASSERT_TRUE(elf.interface() != nullptr);
 }
 
+TEST_F(ElfTest, elf_mips) {
+  Elf elf(memory_);
+
+  InitElf32(EM_MIPS);
+
+  ASSERT_TRUE(elf.Init(false));
+  ASSERT_TRUE(elf.valid());
+  ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
+  ASSERT_EQ(ELFCLASS32, elf.class_type());
+  ASSERT_TRUE(elf.interface() != nullptr);
+}
+
 TEST_F(ElfTest, elf_x86) {
   Elf elf(memory_);
 
@@ -210,6 +222,18 @@
   ASSERT_TRUE(elf.interface() != nullptr);
 }
 
+TEST_F(ElfTest, elf_mips64) {
+  Elf elf(memory_);
+
+  InitElf64(EM_MIPS);
+
+  ASSERT_TRUE(elf.Init(false));
+  ASSERT_TRUE(elf.valid());
+  ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
+  ASSERT_EQ(ELFCLASS64, elf.class_type());
+  ASSERT_TRUE(elf.interface() != nullptr);
+}
+
 TEST_F(ElfTest, gnu_debugdata_init_fail32) {
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 3c5af4a..b81b2ca 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -45,6 +45,8 @@
 
   void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
 
+  bool Format32Bit() { return false; }
+
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
 
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index 0cb70ba..8b5b31f 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -29,11 +29,15 @@
 #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"
 
 namespace unwindstack {
 
@@ -152,7 +156,87 @@
   return result;
 }
 
-using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64>;
+template<>
+std::vector<Register> ExpectedRegisters<RegsMips>() {
+  std::vector<Register> result;
+  result.push_back({"r0", MIPS_REG_R0});
+  result.push_back({"r1", MIPS_REG_R1});
+  result.push_back({"r2", MIPS_REG_R2});
+  result.push_back({"r3", MIPS_REG_R3});
+  result.push_back({"r4", MIPS_REG_R4});
+  result.push_back({"r5", MIPS_REG_R5});
+  result.push_back({"r6", MIPS_REG_R6});
+  result.push_back({"r7", MIPS_REG_R7});
+  result.push_back({"r8", MIPS_REG_R8});
+  result.push_back({"r9", MIPS_REG_R9});
+  result.push_back({"r10", MIPS_REG_R10});
+  result.push_back({"r11", MIPS_REG_R11});
+  result.push_back({"r12", MIPS_REG_R12});
+  result.push_back({"r13", MIPS_REG_R13});
+  result.push_back({"r14", MIPS_REG_R14});
+  result.push_back({"r15", MIPS_REG_R15});
+  result.push_back({"r16", MIPS_REG_R16});
+  result.push_back({"r17", MIPS_REG_R17});
+  result.push_back({"r18", MIPS_REG_R18});
+  result.push_back({"r19", MIPS_REG_R19});
+  result.push_back({"r20", MIPS_REG_R20});
+  result.push_back({"r21", MIPS_REG_R21});
+  result.push_back({"r22", MIPS_REG_R22});
+  result.push_back({"r23", MIPS_REG_R23});
+  result.push_back({"r24", MIPS_REG_R24});
+  result.push_back({"r25", MIPS_REG_R25});
+  result.push_back({"r26", MIPS_REG_R26});
+  result.push_back({"r27", MIPS_REG_R27});
+  result.push_back({"r28", MIPS_REG_R28});
+  result.push_back({"sp", MIPS_REG_SP});
+  result.push_back({"r30", MIPS_REG_R30});
+  result.push_back({"ra", MIPS_REG_RA});
+  result.push_back({"pc", MIPS_REG_PC});
+
+  return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsMips64>() {
+  std::vector<Register> result;
+  result.push_back({"r0", MIPS64_REG_R0});
+  result.push_back({"r1", MIPS64_REG_R1});
+  result.push_back({"r2", MIPS64_REG_R2});
+  result.push_back({"r3", MIPS64_REG_R3});
+  result.push_back({"r4", MIPS64_REG_R4});
+  result.push_back({"r5", MIPS64_REG_R5});
+  result.push_back({"r6", MIPS64_REG_R6});
+  result.push_back({"r7", MIPS64_REG_R7});
+  result.push_back({"r8", MIPS64_REG_R8});
+  result.push_back({"r9", MIPS64_REG_R9});
+  result.push_back({"r10", MIPS64_REG_R10});
+  result.push_back({"r11", MIPS64_REG_R11});
+  result.push_back({"r12", MIPS64_REG_R12});
+  result.push_back({"r13", MIPS64_REG_R13});
+  result.push_back({"r14", MIPS64_REG_R14});
+  result.push_back({"r15", MIPS64_REG_R15});
+  result.push_back({"r16", MIPS64_REG_R16});
+  result.push_back({"r17", MIPS64_REG_R17});
+  result.push_back({"r18", MIPS64_REG_R18});
+  result.push_back({"r19", MIPS64_REG_R19});
+  result.push_back({"r20", MIPS64_REG_R20});
+  result.push_back({"r21", MIPS64_REG_R21});
+  result.push_back({"r22", MIPS64_REG_R22});
+  result.push_back({"r23", MIPS64_REG_R23});
+  result.push_back({"r24", MIPS64_REG_R24});
+  result.push_back({"r25", MIPS64_REG_R25});
+  result.push_back({"r26", MIPS64_REG_R26});
+  result.push_back({"r27", MIPS64_REG_R27});
+  result.push_back({"r28", MIPS64_REG_R28});
+  result.push_back({"sp", MIPS64_REG_SP});
+  result.push_back({"r30", MIPS64_REG_R30});
+  result.push_back({"ra", MIPS64_REG_RA});
+  result.push_back({"pc", MIPS64_REG_PC});
+
+  return result;
+}
+
+using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64, RegsMips, RegsMips64>;
 TYPED_TEST_CASE(RegsIterateTest, RegTypes);
 
 TYPED_TEST(RegsIterateTest, iterate) {
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index ae57caf..ef9e61c 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -23,11 +23,15 @@
 #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 "MemoryFake.h"
 
@@ -204,4 +208,64 @@
   EXPECT_EQ(0x150U, regs.pc());
 }
 
+TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_non_rt) {
+  uint64_t addr = 0x1000;
+  RegsMips regs;
+  regs[MIPS_REG_PC] = 0x8000;
+  regs[MIPS_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0x0000000c24021017ULL);
+
+  for (uint64_t index = 0; index <= 50; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x220U, regs[MIPS_REG_SP]);
+  EXPECT_EQ(0x040U, regs[MIPS_REG_PC]);
+  EXPECT_EQ(0x220U, regs.sp());
+  EXPECT_EQ(0x040U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_rt) {
+  uint64_t addr = 0x1000;
+  RegsMips regs;
+  regs[MIPS_REG_PC] = 0x8000;
+  regs[MIPS_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0x0000000c24021061ULL);
+
+  for (uint64_t index = 0; index <= 100; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x350U, regs[MIPS_REG_SP]);
+  EXPECT_EQ(0x170U, regs[MIPS_REG_PC]);
+  EXPECT_EQ(0x350U, regs.sp());
+  EXPECT_EQ(0x170U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, mips64_step_if_signal_handler) {
+  uint64_t addr = 0x1000;
+  RegsMips64 regs;
+  regs[MIPS64_REG_PC] = 0x8000;
+  regs[MIPS64_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0x0000000c2402145bULL);
+
+  for (uint64_t index = 0; index <= 100; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x350U, regs[MIPS64_REG_SP]);
+  EXPECT_EQ(0x600U, regs[MIPS64_REG_PC]);
+  EXPECT_EQ(0x350U, regs.sp());
+  EXPECT_EQ(0x600U, regs.pc());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index a932973..3f84890 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -25,6 +25,8 @@
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
 #include <unwindstack/RegsX86_64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
@@ -112,6 +114,30 @@
   ASSERT_EQ(0x1U,  x86_64.GetAdjustedPc(0x2, elf_.get()));
   ASSERT_EQ(0x0U,  x86_64.GetAdjustedPc(0x1, elf_.get()));
   ASSERT_EQ(0x0U,  x86_64.GetAdjustedPc(0x0, elf_.get()));
+
+  RegsMips mips;
+  ASSERT_EQ(0x8U, mips.GetAdjustedPc(0x10, elf_.get()));
+  ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x8, elf_.get()));
+  ASSERT_EQ(0x7U, mips.GetAdjustedPc(0x7, elf_.get()));
+  ASSERT_EQ(0x6U, mips.GetAdjustedPc(0x6, elf_.get()));
+  ASSERT_EQ(0x5U, mips.GetAdjustedPc(0x5, elf_.get()));
+  ASSERT_EQ(0x4U, mips.GetAdjustedPc(0x4, elf_.get()));
+  ASSERT_EQ(0x3U, mips.GetAdjustedPc(0x3, elf_.get()));
+  ASSERT_EQ(0x2U, mips.GetAdjustedPc(0x2, elf_.get()));
+  ASSERT_EQ(0x1U, mips.GetAdjustedPc(0x1, elf_.get()));
+  ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x0, elf_.get()));
+
+  RegsMips64 mips64;
+  ASSERT_EQ(0x8U, mips64.GetAdjustedPc(0x10, elf_.get()));
+  ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x8, elf_.get()));
+  ASSERT_EQ(0x7U, mips64.GetAdjustedPc(0x7, elf_.get()));
+  ASSERT_EQ(0x6U, mips64.GetAdjustedPc(0x6, elf_.get()));
+  ASSERT_EQ(0x5U, mips64.GetAdjustedPc(0x5, elf_.get()));
+  ASSERT_EQ(0x4U, mips64.GetAdjustedPc(0x4, elf_.get()));
+  ASSERT_EQ(0x3U, mips64.GetAdjustedPc(0x3, elf_.get()));
+  ASSERT_EQ(0x2U, mips64.GetAdjustedPc(0x2, elf_.get()));
+  ASSERT_EQ(0x1U, mips64.GetAdjustedPc(0x1, elf_.get()));
+  ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x0, elf_.get()));
 }
 
 TEST_F(RegsTest, rel_pc_arm) {
@@ -154,6 +180,8 @@
   RegsArm64 regs_arm64;
   RegsX86 regs_x86;
   RegsX86_64 regs_x86_64;
+  RegsMips regs_mips;
+  RegsMips64 regs_mips64;
   MapInfo map_info(0x1000, 0x2000);
   Elf* invalid_elf = new Elf(new MemoryFake);
   map_info.elf = invalid_elf;
@@ -173,6 +201,14 @@
   regs_x86_64.set_pc(0x1800);
   EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
   EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
+
+  regs_mips.set_pc(0x1900);
+  EXPECT_EQ(0x900U, invalid_elf->GetRelPc(regs_mips.pc(), &map_info));
+  EXPECT_EQ(0x900U, regs_mips.GetAdjustedPc(0x900U, invalid_elf));
+
+  regs_mips64.set_pc(0x1a00);
+  EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(regs_mips64.pc(), &map_info));
+  EXPECT_EQ(0xa00U, regs_mips64.GetAdjustedPc(0xa00U, invalid_elf));
 }
 
 TEST_F(RegsTest, arm_set_from_raw) {
@@ -215,6 +251,26 @@
   EXPECT_EQ(0x4900000000U, x86_64.pc());
 }
 
+TEST_F(RegsTest, mips_set_from_raw) {
+  RegsMips mips;
+  uint32_t* regs = reinterpret_cast<uint32_t*>(mips.RawData());
+  regs[29] = 0x100;
+  regs[32] = 0x200;
+  mips.SetFromRaw();
+  EXPECT_EQ(0x100U, mips.sp());
+  EXPECT_EQ(0x200U, mips.pc());
+}
+
+TEST_F(RegsTest, mips64_set_from_raw) {
+  RegsMips64 mips64;
+  uint64_t* regs = reinterpret_cast<uint64_t*>(mips64.RawData());
+  regs[29] = 0xb100000000ULL;
+  regs[32] = 0xc200000000ULL;
+  mips64.SetFromRaw();
+  EXPECT_EQ(0xb100000000U, mips64.sp());
+  EXPECT_EQ(0xc200000000U, mips64.pc());
+}
+
 TEST_F(RegsTest, machine_type) {
   RegsArm arm_regs;
   EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
@@ -227,6 +283,12 @@
 
   RegsX86_64 x86_64_regs;
   EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch());
+
+  RegsMips mips_regs;
+  EXPECT_EQ(ARCH_MIPS, mips_regs.Arch());
+
+  RegsMips64 mips64_regs;
+  EXPECT_EQ(ARCH_MIPS64, mips64_regs.Arch());
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 71103b4..cd46807 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -28,6 +28,12 @@
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
 #include <unwindstack/Unwinder.h>
 
 #include "ElfFake.h"
@@ -53,7 +59,7 @@
   static void SetUpTestCase() {
     maps_.FakeClear();
     MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
-    ElfFake* elf = new ElfFake(nullptr);
+    ElfFake* elf = new ElfFake(new MemoryFake);
     info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
@@ -66,31 +72,33 @@
     maps_.FakeAddMapInfo(info);
 
     info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
-    elf = new ElfFake(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = 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(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = 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(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = 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(nullptr);
+    elf = new ElfFake(new MemoryFake);
     info->elf = 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);
+
+    process_memory_.reset(new MemoryFake);
   }
 
   void SetUp() override {
@@ -690,29 +698,79 @@
   EXPECT_EQ("  #01 pc 00001000  <unknown>", Unwinder::FormatFrame(frame, true));
 }
 
+static std::string ArchToString(ArchEnum arch) {
+  if (arch == ARCH_ARM) {
+    return "Arm";
+  } else if (arch == ARCH_ARM64) {
+    return "Arm64";
+  } else if (arch == ARCH_X86) {
+    return "X86";
+  } else if (arch == ARCH_X86_64) {
+    return "X86_64";
+  } else {
+    return "Unknown";
+  }
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame) {
-  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
+  std::vector<Regs*> reg_list;
+  RegsArm* arm = new RegsArm;
+  arm->set_pc(0x2300);
+  arm->set_sp(0x10000);
+  reg_list.push_back(arm);
 
-  regs_.FakeSetPc(0x2300);
-  regs_.FakeSetSp(0x10000);
+  RegsArm64* arm64 = new RegsArm64;
+  arm64->set_pc(0x2300);
+  arm64->set_sp(0x10000);
+  reg_list.push_back(arm64);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
-  unwinder.Unwind();
+  RegsX86* x86 = new RegsX86;
+  x86->set_pc(0x2300);
+  x86->set_sp(0x10000);
+  reg_list.push_back(x86);
 
-  ASSERT_EQ(1U, unwinder.NumFrames());
+  RegsX86_64* x86_64 = new RegsX86_64;
+  x86_64->set_pc(0x2300);
+  x86_64->set_sp(0x10000);
+  reg_list.push_back(x86_64);
 
-  regs_.FakeSetArch(ARCH_ARM);
-  EXPECT_EQ("  #00 pc 00001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
-  regs_.FakeSetArch(ARCH_X86);
-  EXPECT_EQ("  #00 pc 00001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
+  RegsMips* mips = new RegsMips;
+  mips->set_pc(0x2300);
+  mips->set_sp(0x10000);
+  reg_list.push_back(mips);
 
-  regs_.FakeSetArch(ARCH_ARM64);
-  EXPECT_EQ("  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
-  regs_.FakeSetArch(ARCH_X86_64);
-  EXPECT_EQ("  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
+  RegsMips64* mips64 = new RegsMips64;
+  mips64->set_pc(0x2300);
+  mips64->set_sp(0x10000);
+  reg_list.push_back(mips64);
 
-  EXPECT_EQ("", unwinder.FormatFrame(1));
+  for (auto regs : reg_list) {
+    ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
+
+    Unwinder unwinder(64, &maps_, regs, process_memory_);
+    unwinder.Unwind();
+
+    ASSERT_EQ(1U, unwinder.NumFrames());
+    std::string expected;
+    switch (regs->Arch()) {
+      case ARCH_ARM:
+      case ARCH_X86:
+      case ARCH_MIPS:
+        expected = "  #00 pc 00001300  /system/fake/libc.so (Frame0+10)";
+        break;
+      case ARCH_ARM64:
+      case ARCH_X86_64:
+      case ARCH_MIPS64:
+        expected = "  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)";
+        break;
+      default:
+        expected = "";
+    }
+    EXPECT_EQ(expected, unwinder.FormatFrame(0))
+        << "Mismatch of frame format for regs arch " << ArchToString(regs->Arch());
+    delete regs;
+  }
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 7896279..81bedb7 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -76,6 +76,12 @@
     case unwindstack::ARCH_X86_64:
       printf("x86_64");
       break;
+    case unwindstack::ARCH_MIPS:
+      printf("mips");
+      break;
+    case unwindstack::ARCH_MIPS64:
+      printf("mips64");
+      break;
     default:
       printf("unknown\n");
       return;
diff --git a/lmkd/OWNERS b/lmkd/OWNERS
new file mode 100644
index 0000000..b15bb48
--- /dev/null
+++ b/lmkd/OWNERS
@@ -0,0 +1 @@
+surenb@google.com
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 777fdb0..d1c0058 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -36,70 +36,6 @@
 
 include $(BUILD_PREBUILT)
 
-# Modules for asan.options.X files.
-
-ASAN_OPTIONS_FILES :=
-
-define create-asan-options-module
-include $$(CLEAR_VARS)
-LOCAL_MODULE := asan.options.$(1)
-ASAN_OPTIONS_FILES += asan.options.$(1)
-LOCAL_MODULE_CLASS := ETC
-# The asan.options.off.template tries to turn off as much of ASAN as is possible.
-LOCAL_SRC_FILES := asan.options.off.template
-LOCAL_MODULE_PATH := $(TARGET_OUT)
-include $$(BUILD_PREBUILT)
-endef
-
-# Pretty comprehensive set of native services. This list is helpful if all that's to be checked is an
-# app.
-ifeq ($(SANITIZE_LITE_SERVICES),true)
-SANITIZE_ASAN_OPTIONS_FOR := \
-  adbd \
-  ATFWD-daemon \
-  audioserver \
-  bridgemgrd \
-  cameraserver \
-  cnd \
-  debuggerd \
-  dex2oat \
-  drmserver \
-  fingerprintd \
-  gatekeeperd \
-  installd \
-  keystore \
-  lmkd \
-  logcat \
-  logd \
-  lowi-server \
-  media.codec \
-  mediadrmserver \
-  media.extractor \
-  mediaserver \
-  mm-qcamera-daemon \
-  mpdecision \
-  netmgrd \
-  perfd \
-  perfprofd \
-  qmuxd \
-  qseecomd \
-  rild \
-  sdcard \
-  servicemanager \
-  slim_daemon \
-  surfaceflinger \
-  thermal-engine \
-  time_daemon \
-  update_engine \
-  vold \
-  wpa_supplicant \
-  zip
-endif
-
-ifneq ($(SANITIZE_ASAN_OPTIONS_FOR),)
-  $(foreach binary, $(SANITIZE_ASAN_OPTIONS_FOR), $(eval $(call create-asan-options-module,$(binary))))
-endif
-
 # ASAN extration.
 ASAN_EXTRACT_FILES :=
 ifeq ($(SANITIZE_TARGET_SYSTEM),true)
diff --git a/rootdir/asan.options.off.template b/rootdir/asan.options.off.template
deleted file mode 100644
index 59a1249..0000000
--- a/rootdir/asan.options.off.template
+++ /dev/null
@@ -1,7 +0,0 @@
-quarantine_size_mb=0
-max_redzone=16
-poison_heap=false
-poison_partial=false
-poison_array_cookie=false
-alloc_dealloc_mismatch=false
-new_delete_type_mismatch=false
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index cae6e13..3183b80 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -63,7 +63,7 @@
 namespace.sphal.isolated = true
 namespace.sphal.visible = true
 namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp${VNDK_VER}/hw
 
 namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -91,10 +91,10 @@
 ###############################################################################
 namespace.rs.isolated = true
 namespace.rs.visible = true
-namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}
 namespace.rs.permitted.paths = /vendor/${LIB}:/data
 
-namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
 
 namespace.rs.links = default,vndk
@@ -108,10 +108,10 @@
 ###############################################################################
 namespace.vndk.isolated = true
 namespace.vndk.visible = true
-namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
 
-namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}
 namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
 
 # When these NDK libs are required inside this namespace, then it is redirected
@@ -128,6 +128,6 @@
 ###############################################################################
 [vendor]
 namespace.default.isolated = false
-namespace.default.search.paths = /odm/${LIB}/hw:/odm/${LIB}/egl:/odm/${LIB}:/vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/odm/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+namespace.default.search.paths = /odm/${LIB}/hw:/odm/${LIB}/egl:/odm/${LIB}:/vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk${VNDK_VER}:/odm/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}
 
-namespace.default.asan.search.paths = /data/asan/odm/${LIB}/hw:/odm/${LIB}/hw:/data/asan/odm/${LIB}/egl:/odm/${LIB}/egl:/data/asan/odm/${LIB}:/odm/${LIB}:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/odm/${LIB}/vndk-sp:/odm/${LIB}/vndk-sp:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+namespace.default.asan.search.paths = /data/asan/odm/${LIB}/hw:/odm/${LIB}/hw:/data/asan/odm/${LIB}/egl:/odm/${LIB}/egl:/data/asan/odm/${LIB}:/odm/${LIB}:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/odm/${LIB}/vndk-sp${VNDK_VER}:/odm/${LIB}/vndk-sp${VNDK_VER}:/data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index 3278ccf..2d05fca 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -30,10 +30,10 @@
 namespace.default.search.paths = /system/${LIB}
 # /vendor/app, /vendor/framework were added since libart should be able to dlopen
 # the odex files from the directory.
-namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
+namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/extractors:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
 
 namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
-namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
+namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/extractors:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
 
 ###############################################################################
 # "sphal" namespace