Parse property contexts via a serialized trie
am: d853f77ed3
Change-Id: I41ae8b723364314520734fd945c22ce17e204269
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+enh@google.com
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/OWNERS b/adb/OWNERS
new file mode 100644
index 0000000..643b448
--- /dev/null
+++ b/adb/OWNERS
@@ -0,0 +1,2 @@
+jmgao@google.com
+yabinc@google.com
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_osx.cpp b/adb/client/usb_osx.cpp
index 2e999ee..b15d28a 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -305,6 +305,7 @@
handle->devpath = devpath;
usb_handle* handle_p = handle.get();
VLOG(USB) << "Add usb device " << serial;
+ LOG(INFO) << "reported max packet size for " << serial << " is " << handle->max_packet_size;
AddDevice(std::move(handle));
register_usb_transport(reinterpret_cast<::usb_handle*>(handle_p), serial, devpath.c_str(),
1);
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/shell_service.cpp b/adb/shell_service.cpp
index 0c7e1f9..f9f80c0 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -262,6 +262,7 @@
env["HOSTNAME"] = GetHostName();
env["LOGNAME"] = pw->pw_name;
env["SHELL"] = pw->pw_shell;
+ env["TMPDIR"] = "/data/local/tmp";
env["USER"] = pw->pw_name;
}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index fdecccf..c3ac344 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -27,11 +27,18 @@
#if ADB_HOST
+#if defined(__APPLE__)
+#define CHECK_PACKET_OVERFLOW 0
+#else
+#define CHECK_PACKET_OVERFLOW 1
+#endif
+
// Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
static int UsbReadMessage(usb_handle* h, amessage* msg) {
D("UsbReadMessage");
+#if CHECK_PACKET_OVERFLOW
size_t usb_packet_size = usb_get_max_packet_size(h);
CHECK_GE(usb_packet_size, sizeof(*msg));
CHECK_LT(usb_packet_size, 4096ULL);
@@ -44,6 +51,9 @@
}
memcpy(msg, buffer, sizeof(*msg));
return n;
+#else
+ return usb_read(h, msg, sizeof(*msg));
+#endif
}
// Call usb_read using a buffer having a multiple of usb_get_max_packet_size() bytes
@@ -51,6 +61,7 @@
static int UsbReadPayload(usb_handle* h, apacket* p) {
D("UsbReadPayload(%d)", p->msg.data_length);
+#if CHECK_PACKET_OVERFLOW
size_t usb_packet_size = usb_get_max_packet_size(h);
CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
@@ -64,6 +75,9 @@
}
CHECK_LE(len, sizeof(p->data));
return usb_read(h, &p->data, len);
+#else
+ return usb_read(h, &p->data, p->msg.data_length);
+#endif
}
static int remote_read(apacket* p, atransport* t) {
@@ -181,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/adf/OWNERS b/adf/OWNERS
new file mode 100644
index 0000000..72b8b5a
--- /dev/null
+++ b/adf/OWNERS
@@ -0,0 +1,2 @@
+ghackmann@google.com
+marissaw@google.com
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 0000000..97777f7
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,3 @@
+enh@google.com
+jmgao@google.com
+tomcherry@google.com
diff --git a/bootstat/OWNERS b/bootstat/OWNERS
new file mode 100644
index 0000000..7fe0443
--- /dev/null
+++ b/bootstat/OWNERS
@@ -0,0 +1 @@
+jhawkins@google.com
diff --git a/debuggerd/OWNERS b/debuggerd/OWNERS
new file mode 100644
index 0000000..bfeedca
--- /dev/null
+++ b/debuggerd/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+jmgao@google.com
diff --git a/demangle/OWNERS b/demangle/OWNERS
new file mode 100644
index 0000000..6f7e4a3
--- /dev/null
+++ b/demangle/OWNERS
@@ -0,0 +1 @@
+cferris@google.com
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e0f702d..10ef356 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -39,7 +39,7 @@
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs sload_f2fs
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -79,6 +79,7 @@
my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs$(HOST_EXECUTABLE_SUFFIX)
$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
ifdef HOST_CROSS_OS
# Archive fastboot.exe for win_sdk build.
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
new file mode 100644
index 0000000..2d12d50
--- /dev/null
+++ b/fastboot/OWNERS
@@ -0,0 +1,3 @@
+dpursell@google.com
+enh@google.com
+jmgao@google.com
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 9949eae..a1e1677 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -28,7 +28,7 @@
using android::base::unique_fd;
#ifdef WIN32
-static int exec_e2fs_cmd(const char* /*path*/, const char** argv, const char** envp) {
+static int exec_cmd(const char* path, const char** argv, const char** envp) {
std::string cmd;
int i = 0;
while (argv[i] != nullptr) {
@@ -76,10 +76,14 @@
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
- return exit_code != 0;
+ if (exit_code != 0) {
+ fprintf(stderr, "%s failed: %lu\n", path, exit_code);
+ return -1;
+ }
+ return 0;
}
#else
-static int exec_e2fs_cmd(const char* path, const char** argv, const char** envp) {
+static int exec_cmd(const char* path, const char** argv, const char** envp) {
int status;
pid_t child;
if ((child = fork()) == 0) {
@@ -97,11 +101,13 @@
int ret = -1;
if (WIFEXITED(status)) {
ret = WEXITSTATUS(status);
- if (ret != 0) {
- fprintf(stderr, "%s failed with status %d\n", path, ret);
- }
}
- return ret;
+
+ if (ret != 0) {
+ fprintf(stderr, "%s failed with status %d\n", path, ret);
+ return -1;
+ }
+ return 0;
}
#endif
@@ -140,9 +146,8 @@
const std::string mke2fs_env = "MKE2FS_CONFIG=" + GetExecutableDirectory() + "/mke2fs.conf";
std::vector<const char*> mke2fs_envp = {mke2fs_env.c_str(), nullptr};
- int ret = exec_e2fs_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
+ int ret = exec_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
if (ret != 0) {
- fprintf(stderr, "mke2fs failed: %d\n", ret);
return -1;
}
@@ -154,19 +159,12 @@
std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
fileName, nullptr};
- ret = exec_e2fs_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
- if (ret != 0) {
- fprintf(stderr, "e2fsdroid failed: %d\n", ret);
- return -1;
- }
-
- return 0;
+ return exec_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
}
static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned /* unused */, unsigned /* unused */)
{
-#ifndef WIN32
const std::string exec_dir = android::base::GetExecutableDirectory();
const std::string mkf2fs_path = exec_dir + "/make_f2fs";
std::vector<const char*> mkf2fs_args = {mkf2fs_path.c_str()};
@@ -182,22 +180,20 @@
mkf2fs_args.push_back(fileName);
mkf2fs_args.push_back(nullptr);
- int ret = exec_e2fs_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
+ int ret = exec_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
if (ret != 0) {
- fprintf(stderr, "mkf2fs failed: %d\n", ret);
return -1;
}
- if (!initial_dir.empty()) {
- fprintf(stderr, "sload.f2s not supported yet\n");
+ if (initial_dir.empty()) {
return 0;
}
- return 0;
-#else
- UNUSED(fileName, partSize, initial_dir);
- fprintf(stderr, "make_f2fs not supported on Windows\n");
- return -1;
-#endif
+
+ const std::string sload_path = exec_dir + "/sload_f2fs";
+ std::vector<const char*> sload_args = {sload_path.c_str(), "-S",
+ "-f", initial_dir.c_str(), fileName, nullptr};
+
+ return exec_cmd(sload_args[0], sload_args.data(), nullptr);
}
static const struct fs_generator {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
deleted file mode 100644
index 007189d..0000000
--- a/fs_mgr/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-common_static_libraries := \
- liblogwrap \
- libfec \
- libfec_rs \
- libbase \
- libcrypto_utils \
- libcrypto \
- libext4_utils \
- libsquashfs_utils \
- libselinux \
- libavb
-
-include $(CLEAR_VARS)
-LOCAL_SANITIZE := integer
-LOCAL_SRC_FILES:= fs_mgr_main.cpp
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_MODULE:= fs_mgr
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libfs_mgr \
- $(common_static_libraries) \
- libcutils \
- liblog \
- libc \
- libsparse \
- libz \
- libselinux
-LOCAL_CXX_STL := libc++_static
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS
new file mode 100644
index 0000000..817a0b8
--- /dev/null
+++ b/fs_mgr/OWNERS
@@ -0,0 +1,2 @@
+bowgotsai@google.com
+tomcherry@google.com
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index fc88217..85a593f 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -34,23 +34,35 @@
#include "fs_mgr_priv.h"
#include "cryptfs.h"
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+static int get_dev_sz(char *fs_blkdev, uint64_t *dev_sz)
{
- uint64_t dev_sz;
- int fd, rc = 0;
+ int fd;
- if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
+ if ((fd = open(fs_blkdev, O_RDONLY)) < 0) {
PERROR << "Cannot open block device";
return -1;
}
- if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
+ if ((ioctl(fd, BLKGETSIZE64, dev_sz)) == -1) {
PERROR << "Cannot get block device size";
close(fd);
return -1;
}
close(fd);
+ return 0;
+}
+
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+{
+ uint64_t dev_sz;
+ int rc = 0;
+ int status;
+
+ rc = get_dev_sz(fs_blkdev, &dev_sz);
+ if (rc) {
+ return rc;
+ }
/* Format the partition using the calculated length */
if (crypt_footer) {
@@ -85,9 +97,25 @@
return rc;
}
-static int format_f2fs(char *fs_blkdev)
+static int format_f2fs(char *fs_blkdev, uint64_t dev_sz, bool crypt_footer)
{
- const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
+ int status;
+
+ if (!dev_sz) {
+ int rc = get_dev_sz(fs_blkdev, &dev_sz);
+ if (rc) {
+ return rc;
+ }
+ }
+
+ /* Format the partition using the calculated length */
+ if (crypt_footer) {
+ dev_sz -= CRYPT_FOOTER_OFFSET;
+ }
+
+ std::string size_str = std::to_string(dev_sz / 4096);
+ const char* const args[] = {
+ "/system/bin/make_f2fs", "-f", "-O", "encrypt", fs_blkdev, size_str.c_str(), nullptr};
return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
LOG_KLOG, true, nullptr, nullptr, 0);
@@ -101,7 +129,7 @@
<< " as '" << fstab->fs_type << "'";
if (!strncmp(fstab->fs_type, "f2fs", 4)) {
- rc = format_f2fs(fstab->blk_device);
+ rc = format_f2fs(fstab->blk_device, fstab->length, crypt_footer);
} else if (!strncmp(fstab->fs_type, "ext4", 4)) {
rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
} else {
diff --git a/fs_mgr/fs_mgr_main.cpp b/fs_mgr/fs_mgr_main.cpp
deleted file mode 100644
index f3919d9..0000000
--- a/fs_mgr/fs_mgr_main.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2012 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 <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "fs_mgr_priv.h"
-
-#ifdef _LIBGEN_H
-#warning "libgen.h must not be included"
-#endif
-
-char *me = nullptr;
-
-static void usage(void)
-{
- LERROR << me << ": usage: " << me
- << " <-a | -n mnt_point blk_dev | -u> <fstab_file>";
- exit(1);
-}
-
-/* Parse the command line. If an error is encountered, print an error message
- * and exit the program, do not return to the caller.
- * Return the number of argv[] entries consumed.
- */
-static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
- const char **n_name, const char **n_blk_dev)
-{
- me = basename(argv[0]);
-
- if (argc <= 1) {
- usage();
- }
-
- if (!strcmp(argv[1], "-a")) {
- if (argc != 3) {
- usage();
- }
- *a_flag = 1;
- }
- if (!strcmp(argv[1], "-n")) {
- if (argc != 5) {
- usage();
- }
- *n_flag = 1;
- *n_name = argv[2];
- *n_blk_dev = argv[3];
- }
- if (!strcmp(argv[1], "-u")) {
- if (argc != 3) {
- usage();
- }
- *u_flag = 1;
- }
-
- /* If no flag is specified, it's an error */
- if (!(*a_flag | *n_flag | *u_flag)) {
- usage();
- }
-
- /* If more than one flag is specified, it's an error */
- if ((*a_flag + *n_flag + *u_flag) > 1) {
- usage();
- }
-
- return;
-}
-
-int main(int argc, char * const argv[])
-{
- int a_flag=0;
- int u_flag=0;
- int n_flag=0;
- const char *n_name=NULL;
- const char *n_blk_dev=NULL;
- const char *fstab_file=NULL;
- struct fstab *fstab=NULL;
-
- setenv("ANDROID_LOG_TAGS", "*:i", 1); // Set log level to INFO
- android::base::InitLogging(
- const_cast<char **>(argv), &android::base::KernelLogger);
-
- parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
-
- /* The name of the fstab file is last, after the option */
- fstab_file = argv[argc - 1];
-
- fstab = fs_mgr_read_fstab(fstab_file);
-
- if (a_flag) {
- return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
- } else if (n_flag) {
- return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
- } else if (u_flag) {
- return fs_mgr_unmount_all(fstab);
- } else {
- LERROR << me << ": Internal error, unknown option";
- exit(1);
- }
-
- fs_mgr_free_fstab(fstab);
-
- /* Should not get here */
- exit(1);
-}
diff --git a/healthd/OWNERS b/healthd/OWNERS
new file mode 100644
index 0000000..2375f7c
--- /dev/null
+++ b/healthd/OWNERS
@@ -0,0 +1 @@
+toddpoynor@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 45ee754..0ec348c 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -118,6 +118,8 @@
required: [
"e2fsdroid",
"mke2fs",
+ "sload_f2fs",
+ "make_f2fs",
],
static_executable: true,
srcs: [
diff --git a/init/Android.mk b/init/Android.mk
index 44300f6..516f1b3 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -88,6 +88,8 @@
LOCAL_REQUIRED_MODULES := \
e2fsdroid \
mke2fs \
+ sload_f2fs \
+ make_f2fs \
# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/OWNERS b/init/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/init/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 21010b0..1febccd 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -436,6 +436,9 @@
selinux_android_restorecon("/sbin/mke2fs_static", 0);
selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
+
+ selinux_android_restorecon("/sbin/mkfs.f2fs", 0);
+ selinux_android_restorecon("/sbin/sload.f2fs", 0);
}
// This function sets up SELinux logging to be written to kmsg, to match init's logging.
diff --git a/libappfuse/OWNERS b/libappfuse/OWNERS
new file mode 100644
index 0000000..cd7cb74
--- /dev/null
+++ b/libappfuse/OWNERS
@@ -0,0 +1 @@
+hirono@google.com
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 0b2ce1d..9eaeae8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -229,6 +229,7 @@
srcs: [
"backtrace_benchmarks.cpp",
+ "backtrace_read_benchmarks.cpp",
],
shared_libs: [
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/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
index 760817b..d110b48 100644
--- a/libbacktrace/BacktracePtrace.h
+++ b/libbacktrace/BacktracePtrace.h
@@ -29,9 +29,9 @@
BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktracePtrace() {}
- size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+ size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
- bool ReadWord(uintptr_t ptr, word_t* out_value);
+ bool ReadWord(uintptr_t ptr, word_t* out_value) override;
};
#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/OWNERS b/libbacktrace/OWNERS
new file mode 100644
index 0000000..bfeedca
--- /dev/null
+++ b/libbacktrace/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+jmgao@google.com
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 3a38839..56a6c68 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -99,8 +99,7 @@
// one extra function call appearing in the unwind.
unwindstack::RegsGetLocal(regs.get());
} else {
- regs.reset(
- unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext));
+ regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
@@ -109,7 +108,7 @@
}
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
- : BacktracePtrace(pid, tid, map) {}
+ : BacktracePtrace(pid, tid, map), memory_(pid) {}
std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
return GetMap()->GetFunctionName(pc, offset);
@@ -120,10 +119,13 @@
if (context == nullptr) {
regs.reset(unwindstack::Regs::RemoteGet(Tid()));
} else {
- regs.reset(
- unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context));
+ regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context));
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
}
+
+size_t UnwindStackPtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+ return memory_.Read(addr, buffer, bytes);
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index be9ef63..ee2a706 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -45,6 +45,11 @@
bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+ size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+
+ private:
+ unwindstack::MemoryRemote memory_;
};
#endif // _LIBBACKTRACE_UNWIND_STACK_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/backtrace_read_benchmarks.cpp b/libbacktrace/backtrace_read_benchmarks.cpp
new file mode 100644
index 0000000..6a688b0
--- /dev/null
+++ b/libbacktrace/backtrace_read_benchmarks.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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 <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+
+#include <backtrace/Backtrace.h>
+
+#define AT_COMMON_SIZES Arg(1)->Arg(4)->Arg(8)->Arg(16)->Arg(100)->Arg(200)->Arg(500)->Arg(1024)
+
+static void Attach(pid_t pid) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ perror("Failed to attach");
+ abort();
+ }
+
+ siginfo_t si;
+ // Wait for up to 5 seconds.
+ for (size_t i = 0; i < 5000; i++) {
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ return;
+ }
+ usleep(1000);
+ }
+ printf("Remote process failed to stop in five seconds.\n");
+ abort();
+}
+
+class ScopedPidReaper {
+ public:
+ ScopedPidReaper(pid_t pid) : pid_(pid) {}
+ ~ScopedPidReaper() {
+ kill(pid_, SIGKILL);
+ waitpid(pid_, nullptr, 0);
+ }
+
+ private:
+ pid_t pid_;
+};
+
+static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
+ struct iovec dst_iov = {
+ .iov_base = dst, .iov_len = len,
+ };
+
+ struct iovec src_iov = {
+ .iov_base = reinterpret_cast<void*>(remote_src), .iov_len = len,
+ };
+
+ ssize_t rc = process_vm_readv(pid, &dst_iov, 1, &src_iov, 1, 0);
+ return rc == -1 ? 0 : rc;
+}
+
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+ // ptrace() returns -1 and sets errno when the operation fails.
+ // To disambiguate -1 from a valid result, we clear errno beforehand.
+ errno = 0;
+ *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+ if (*value == -1 && errno) {
+ return false;
+ }
+ return true;
+}
+
+static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+ size_t bytes_read = 0;
+ long data;
+ for (size_t i = 0; i < bytes / sizeof(long); i++) {
+ if (!PtraceReadLong(pid, addr, &data)) {
+ return bytes_read;
+ }
+ memcpy(dst, &data, sizeof(long));
+ dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+ addr += sizeof(long);
+ bytes_read += sizeof(long);
+ }
+
+ size_t left_over = bytes & (sizeof(long) - 1);
+ if (left_over) {
+ if (!PtraceReadLong(pid, addr, &data)) {
+ return bytes_read;
+ }
+ memcpy(dst, &data, left_over);
+ bytes_read += left_over;
+ }
+ return bytes_read;
+}
+
+static void CreateRemoteProcess(size_t size, void** map, pid_t* pid) {
+ *map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (*map == MAP_FAILED) {
+ perror("Can't allocate memory");
+ abort();
+ }
+ memset(*map, 0xaa, size);
+
+ if ((*pid = fork()) == 0) {
+ for (volatile int i = 0;; i++)
+ ;
+ exit(1);
+ }
+ if (*pid < 0) {
+ perror("Failed to fork");
+ abort();
+ }
+ Attach(*pid);
+ // Don't need this map in the current process any more.
+ munmap(*map, size);
+}
+
+static void BM_read_with_ptrace(benchmark::State& state) {
+ void* map;
+ pid_t pid;
+ CreateRemoteProcess(state.range(0), &map, &pid);
+ ScopedPidReaper reap(pid);
+
+ std::vector<uint8_t> read_buffer(state.range(0));
+ uint64_t addr = reinterpret_cast<uint64_t>(map);
+ while (state.KeepRunning()) {
+ if (PtraceRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+ printf("Unexpected bad read.\n");
+ abort();
+ }
+ }
+ ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_ptrace)->AT_COMMON_SIZES;
+
+static void BM_read_with_process_vm_read(benchmark::State& state) {
+ void* map;
+ pid_t pid;
+ CreateRemoteProcess(state.range(0), &map, &pid);
+ ScopedPidReaper reap(pid);
+
+ std::vector<uint8_t> read_buffer(state.range(0));
+ uint64_t addr = reinterpret_cast<uint64_t>(map);
+ while (state.KeepRunning()) {
+ if (ProcessVmRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+ printf("Unexpected bad read.\n");
+ abort();
+ }
+ }
+ ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_process_vm_read)->AT_COMMON_SIZES;
+
+static void BM_read_with_backtrace_object(benchmark::State& state) {
+ void* map;
+ pid_t pid;
+ CreateRemoteProcess(state.range(0), &map, &pid);
+ ScopedPidReaper reap(pid);
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+ if (backtrace.get() == nullptr) {
+ printf("Failed to create backtrace.\n");
+ abort();
+ }
+
+ uint64_t addr = reinterpret_cast<uint64_t>(map);
+ std::vector<uint8_t> read_buffer(state.range(0));
+ while (state.KeepRunning()) {
+ if (backtrace->Read(addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
+ printf("Unexpected bad read.\n");
+ abort();
+ }
+ }
+ ptrace(PTRACE_DETACH, pid, 0, 0);
+}
+BENCHMARK(BM_read_with_backtrace_object)->AT_COMMON_SIZES;
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/liblog/OWNERS b/liblog/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/liblog/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/libmemtrack/OWNERS b/libmemtrack/OWNERS
new file mode 100644
index 0000000..70b375f
--- /dev/null
+++ b/libmemtrack/OWNERS
@@ -0,0 +1 @@
+ccross@google.com
diff --git a/libmemunreachable/OWNERS b/libmemunreachable/OWNERS
new file mode 100644
index 0000000..9127a93
--- /dev/null
+++ b/libmemunreachable/OWNERS
@@ -0,0 +1,2 @@
+ccross@google.com
+cferris@google.com
diff --git a/libmetricslogger/OWNERS b/libmetricslogger/OWNERS
new file mode 100644
index 0000000..7fe0443
--- /dev/null
+++ b/libmetricslogger/OWNERS
@@ -0,0 +1 @@
+jhawkins@google.com
diff --git a/libnativebridge/OWNERS b/libnativebridge/OWNERS
new file mode 100644
index 0000000..f2cc942
--- /dev/null
+++ b/libnativebridge/OWNERS
@@ -0,0 +1 @@
+dimitry@google.com
diff --git a/libnativeloader/OWNERS b/libnativeloader/OWNERS
new file mode 100644
index 0000000..f2cc942
--- /dev/null
+++ b/libnativeloader/OWNERS
@@ -0,0 +1 @@
+dimitry@google.com
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 5d160ee..f3c70de 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -35,6 +35,10 @@
#include <android-base/macros.h>
#include <android-base/strings.h>
+#ifdef __BIONIC__
+#include <android-base/properties.h>
+#endif
+
#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
"%s:%d: %s CHECK '" #predicate "' failed.",\
__FILE__, __LINE__, __FUNCTION__)
@@ -110,6 +114,25 @@
return std::string(debuggable) == "1";
}
+static std::string vndk_version_str() {
+#ifdef __BIONIC__
+ std::string version = android::base::GetProperty("ro.vndk.version", "");
+ if (version != "" && version != "current") {
+ return "." + version;
+ }
+#endif
+ return "";
+}
+
+static void insert_vndk_version_str(std::string* file_name) {
+ CHECK(file_name != nullptr);
+ size_t insert_pos = file_name->find_last_of(".");
+ if (insert_pos == std::string::npos) {
+ insert_pos = file_name->length();
+ }
+ file_name->insert(insert_pos, vndk_version_str());
+}
+
class LibraryNamespaces {
public:
LibraryNamespaces() : initialized_(false) { }
@@ -318,6 +341,10 @@
"Error reading public native library list from \"%s\": %s",
public_native_libraries_system_config.c_str(), error_msg.c_str());
+ // Insert VNDK version to llndk and vndksp config file names.
+ insert_vndk_version_str(&llndk_native_libraries_system_config);
+ insert_vndk_version_str(&vndksp_native_libraries_system_config);
+
// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
// variable to add libraries to the list. This is intended for platform tests only.
if (is_debuggable()) {
@@ -347,11 +374,11 @@
system_public_libraries_ = base::Join(sonames, ':');
sonames.clear();
- ReadConfig(kLlndkNativeLibrariesSystemConfigPathFromRoot, &sonames);
+ ReadConfig(llndk_native_libraries_system_config, &sonames);
system_llndk_libraries_ = base::Join(sonames, ':');
sonames.clear();
- ReadConfig(kVndkspNativeLibrariesSystemConfigPathFromRoot, &sonames);
+ ReadConfig(vndksp_native_libraries_system_config, &sonames);
system_vndksp_libraries_ = base::Join(sonames, ':');
sonames.clear();
diff --git a/libnetutils/OWNERS b/libnetutils/OWNERS
new file mode 100644
index 0000000..e3ec950
--- /dev/null
+++ b/libnetutils/OWNERS
@@ -0,0 +1,3 @@
+# TODO: should this be in system/netd?
+ek@google.com
+lorenzo@google.com
diff --git a/libprocinfo/OWNERS b/libprocinfo/OWNERS
new file mode 100644
index 0000000..a70cc57
--- /dev/null
+++ b/libprocinfo/OWNERS
@@ -0,0 +1 @@
+jmgao@google.com
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 74930d6..21dd306 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -60,6 +60,12 @@
"Maps.cpp",
"Memory.cpp",
"Regs.cpp",
+ "RegsArm.cpp",
+ "RegsArm64.cpp",
+ "RegsX86.cpp",
+ "RegsX86_64.cpp",
+ "RegsMips.cpp",
+ "RegsMips64.cpp",
"Unwinder.cpp",
"Symbols.cpp",
],
@@ -82,6 +88,12 @@
x86_64: {
srcs: ["AsmGetRegsX86_64.S"],
},
+ mips: {
+ srcs: ["AsmGetRegsMips.S"],
+ },
+ mips64: {
+ srcs: ["AsmGetRegsMips64.S"],
+ },
},
shared_libs: [
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index fed3e0e..6b0646f 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -23,11 +23,11 @@
#include <unwindstack/Log.h>
#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
#include "ArmExidx.h"
#include "Check.h"
-#include "Machine.h"
+#include "MachineArm.h"
namespace unwindstack {
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 5f307ed..f486e23 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -31,7 +31,6 @@
#include <unwindstack/Regs.h>
#include "ElfInterfaceArm.h"
-#include "Machine.h"
#include "Symbols.h"
namespace unwindstack {
@@ -183,19 +182,19 @@
return nullptr;
}
- if (e_machine != EM_ARM && e_machine != EM_386) {
- // Unsupported.
- ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
- return nullptr;
- }
-
machine_type_ = e_machine;
if (e_machine == EM_ARM) {
+ arch_ = ARCH_ARM;
interface.reset(new ElfInterfaceArm(memory));
} 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 {
- ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
+ // Unsupported.
+ 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) {
@@ -203,12 +202,20 @@
if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
return nullptr;
}
- if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
+
+ machine_type_ = e_machine;
+ if (e_machine == EM_AARCH64) {
+ 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;
}
- machine_type_ = e_machine;
interface.reset(new ElfInterface64(memory));
}
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 170a5cd..9841e24 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -18,11 +18,11 @@
#include <stdint.h>
#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
#include "ArmExidx.h"
#include "ElfInterfaceArm.h"
-#include "Machine.h"
+#include "MachineArm.h"
namespace unwindstack {
diff --git a/libunwindstack/Machine.h b/libunwindstack/Machine.h
deleted file mode 100644
index 1fb9309..0000000
--- a/libunwindstack/Machine.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 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_H
-#define _LIBUNWINDSTACK_MACHINE_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum ArmReg : uint16_t {
- ARM_REG_R0 = 0,
- ARM_REG_R1,
- ARM_REG_R2,
- ARM_REG_R3,
- ARM_REG_R4,
- ARM_REG_R5,
- ARM_REG_R6,
- ARM_REG_R7,
- ARM_REG_R8,
- ARM_REG_R9,
- ARM_REG_R10,
- ARM_REG_R11,
- ARM_REG_R12,
- ARM_REG_R13,
- ARM_REG_R14,
- ARM_REG_R15,
- ARM_REG_LAST,
-
- ARM_REG_SP = ARM_REG_R13,
- ARM_REG_LR = ARM_REG_R14,
- ARM_REG_PC = ARM_REG_R15,
-};
-
-enum Arm64Reg : uint16_t {
- ARM64_REG_R0 = 0,
- ARM64_REG_R1,
- ARM64_REG_R2,
- ARM64_REG_R3,
- ARM64_REG_R4,
- ARM64_REG_R5,
- ARM64_REG_R6,
- ARM64_REG_R7,
- ARM64_REG_R8,
- ARM64_REG_R9,
- ARM64_REG_R10,
- ARM64_REG_R11,
- ARM64_REG_R12,
- ARM64_REG_R13,
- ARM64_REG_R14,
- ARM64_REG_R15,
- ARM64_REG_R16,
- ARM64_REG_R17,
- ARM64_REG_R18,
- ARM64_REG_R19,
- ARM64_REG_R20,
- ARM64_REG_R21,
- ARM64_REG_R22,
- ARM64_REG_R23,
- ARM64_REG_R24,
- ARM64_REG_R25,
- ARM64_REG_R26,
- ARM64_REG_R27,
- ARM64_REG_R28,
- ARM64_REG_R29,
- ARM64_REG_R30,
- ARM64_REG_R31,
- ARM64_REG_PC,
- ARM64_REG_LAST,
-
- ARM64_REG_SP = ARM64_REG_R31,
- ARM64_REG_LR = ARM64_REG_R30,
-};
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86Reg : uint16_t {
- X86_REG_EAX = 0,
- X86_REG_ECX = 1,
- X86_REG_EDX = 2,
- X86_REG_EBX = 3,
- X86_REG_ESP = 4,
- X86_REG_EBP = 5,
- X86_REG_ESI = 6,
- X86_REG_EDI = 7,
- X86_REG_EIP = 8,
- X86_REG_EFL = 9,
- X86_REG_CS = 10,
- X86_REG_SS = 11,
- X86_REG_DS = 12,
- X86_REG_ES = 13,
- X86_REG_FS = 14,
- X86_REG_GS = 15,
- X86_REG_LAST,
-
- X86_REG_SP = X86_REG_ESP,
- X86_REG_PC = X86_REG_EIP,
-};
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86_64Reg : uint16_t {
- X86_64_REG_RAX = 0,
- X86_64_REG_RDX = 1,
- X86_64_REG_RCX = 2,
- X86_64_REG_RBX = 3,
- X86_64_REG_RSI = 4,
- X86_64_REG_RDI = 5,
- X86_64_REG_RBP = 6,
- X86_64_REG_RSP = 7,
- X86_64_REG_R8 = 8,
- X86_64_REG_R9 = 9,
- X86_64_REG_R10 = 10,
- X86_64_REG_R11 = 11,
- X86_64_REG_R12 = 12,
- X86_64_REG_R13 = 13,
- X86_64_REG_R14 = 14,
- X86_64_REG_R15 = 15,
- X86_64_REG_RIP = 16,
- X86_64_REG_LAST,
-
- X86_64_REG_SP = X86_64_REG_RSP,
- X86_64_REG_PC = X86_64_REG_RIP,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_H
diff --git a/libunwindstack/MachineArm.h b/libunwindstack/MachineArm.h
new file mode 100644
index 0000000..3f902b1
--- /dev/null
+++ b/libunwindstack/MachineArm.h
@@ -0,0 +1,50 @@
+/*
+ * 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_ARM_H
+#define _LIBUNWINDSTACK_MACHINE_ARM_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum ArmReg : uint16_t {
+ ARM_REG_R0 = 0,
+ ARM_REG_R1,
+ ARM_REG_R2,
+ ARM_REG_R3,
+ ARM_REG_R4,
+ ARM_REG_R5,
+ ARM_REG_R6,
+ ARM_REG_R7,
+ ARM_REG_R8,
+ ARM_REG_R9,
+ ARM_REG_R10,
+ ARM_REG_R11,
+ ARM_REG_R12,
+ ARM_REG_R13,
+ ARM_REG_R14,
+ ARM_REG_R15,
+ ARM_REG_LAST,
+
+ ARM_REG_SP = ARM_REG_R13,
+ ARM_REG_LR = ARM_REG_R14,
+ ARM_REG_PC = ARM_REG_R15,
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_ARM_H
diff --git a/libunwindstack/MachineArm64.h b/libunwindstack/MachineArm64.h
new file mode 100644
index 0000000..e8b778b
--- /dev/null
+++ b/libunwindstack/MachineArm64.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_ARM64_H
+#define _LIBUNWINDSTACK_MACHINE_ARM64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum Arm64Reg : uint16_t {
+ ARM64_REG_R0 = 0,
+ ARM64_REG_R1,
+ ARM64_REG_R2,
+ ARM64_REG_R3,
+ ARM64_REG_R4,
+ ARM64_REG_R5,
+ ARM64_REG_R6,
+ ARM64_REG_R7,
+ ARM64_REG_R8,
+ ARM64_REG_R9,
+ ARM64_REG_R10,
+ ARM64_REG_R11,
+ ARM64_REG_R12,
+ ARM64_REG_R13,
+ ARM64_REG_R14,
+ ARM64_REG_R15,
+ ARM64_REG_R16,
+ ARM64_REG_R17,
+ ARM64_REG_R18,
+ ARM64_REG_R19,
+ ARM64_REG_R20,
+ ARM64_REG_R21,
+ ARM64_REG_R22,
+ ARM64_REG_R23,
+ ARM64_REG_R24,
+ ARM64_REG_R25,
+ ARM64_REG_R26,
+ ARM64_REG_R27,
+ ARM64_REG_R28,
+ ARM64_REG_R29,
+ ARM64_REG_R30,
+ ARM64_REG_R31,
+ ARM64_REG_PC,
+ ARM64_REG_LAST,
+
+ ARM64_REG_SP = ARM64_REG_R31,
+ ARM64_REG_LR = ARM64_REG_R30,
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_ARM64_H
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/MachineX86.h b/libunwindstack/MachineX86.h
new file mode 100644
index 0000000..02adb98
--- /dev/null
+++ b/libunwindstack/MachineX86.h
@@ -0,0 +1,51 @@
+/*
+ * 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_X86_H
+#define _LIBUNWINDSTACK_MACHINE_X86_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
+enum X86Reg : uint16_t {
+ X86_REG_EAX = 0,
+ X86_REG_ECX = 1,
+ X86_REG_EDX = 2,
+ X86_REG_EBX = 3,
+ X86_REG_ESP = 4,
+ X86_REG_EBP = 5,
+ X86_REG_ESI = 6,
+ X86_REG_EDI = 7,
+ X86_REG_EIP = 8,
+ X86_REG_EFL = 9,
+ X86_REG_CS = 10,
+ X86_REG_SS = 11,
+ X86_REG_DS = 12,
+ X86_REG_ES = 13,
+ X86_REG_FS = 14,
+ X86_REG_GS = 15,
+ X86_REG_LAST,
+
+ X86_REG_SP = X86_REG_ESP,
+ X86_REG_PC = X86_REG_EIP,
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_X86_H
diff --git a/libunwindstack/MachineX86_64.h b/libunwindstack/MachineX86_64.h
new file mode 100644
index 0000000..af33fea
--- /dev/null
+++ b/libunwindstack/MachineX86_64.h
@@ -0,0 +1,52 @@
+/*
+ * 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_X86_64_H
+#define _LIBUNWINDSTACK_MACHINE_X86_64_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
+enum X86_64Reg : uint16_t {
+ X86_64_REG_RAX = 0,
+ X86_64_REG_RDX = 1,
+ X86_64_REG_RCX = 2,
+ X86_64_REG_RBX = 3,
+ X86_64_REG_RSI = 4,
+ X86_64_REG_RDI = 5,
+ X86_64_REG_RBP = 6,
+ X86_64_REG_RSP = 7,
+ X86_64_REG_R8 = 8,
+ X86_64_REG_R9 = 9,
+ X86_64_REG_R10 = 10,
+ X86_64_REG_R11 = 11,
+ X86_64_REG_R12 = 12,
+ X86_64_REG_R13 = 13,
+ X86_64_REG_R14 = 14,
+ X86_64_REG_R15 = 15,
+ X86_64_REG_RIP = 16,
+ X86_64_REG_LAST,
+
+ X86_64_REG_SP = X86_64_REG_RSP,
+ X86_64_REG_PC = X86_64_REG_RIP,
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MACHINE_X86_64_H
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index b1b39a0..1f3c6c3 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -32,7 +32,9 @@
#include "Check.h"
-static size_t ProcessVmRead(pid_t pid, void* dst, uint64_t remote_src, size_t len) {
+namespace unwindstack {
+
+static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
struct iovec dst_iov = {
.iov_base = dst,
.iov_len = len,
@@ -82,7 +84,59 @@
return rc == -1 ? 0 : rc;
}
-namespace unwindstack {
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+ // ptrace() returns -1 and sets errno when the operation fails.
+ // To disambiguate -1 from a valid result, we clear errno beforehand.
+ errno = 0;
+ *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+ if (*value == -1 && errno) {
+ return false;
+ }
+ return true;
+}
+
+static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+ // Make sure that there is no overflow.
+ uint64_t max_size;
+ if (__builtin_add_overflow(addr, bytes, &max_size)) {
+ return 0;
+ }
+
+ size_t bytes_read = 0;
+ long data;
+ size_t align_bytes = addr & (sizeof(long) - 1);
+ if (align_bytes != 0) {
+ if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
+ return 0;
+ }
+ size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
+ memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
+ addr += copy_bytes;
+ dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
+ bytes -= copy_bytes;
+ bytes_read += copy_bytes;
+ }
+
+ for (size_t i = 0; i < bytes / sizeof(long); i++) {
+ if (!PtraceReadLong(pid, addr, &data)) {
+ return bytes_read;
+ }
+ memcpy(dst, &data, sizeof(long));
+ dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+ addr += sizeof(long);
+ bytes_read += sizeof(long);
+ }
+
+ size_t left_over = bytes & (sizeof(long) - 1);
+ if (left_over) {
+ if (!PtraceReadLong(pid, addr, &data)) {
+ return bytes_read;
+ }
+ memcpy(dst, &data, left_over);
+ bytes_read += left_over;
+ }
+ return bytes_read;
+}
bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
size_t rc = Read(addr, dst, size);
@@ -198,72 +252,39 @@
return actual_len;
}
-static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
- // ptrace() returns -1 and sets errno when the operation fails.
- // To disambiguate -1 from a valid result, we clear errno beforehand.
- errno = 0;
- *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
- if (*value == -1 && errno) {
- return false;
- }
- return true;
-}
-
-static size_t ReadWithPtrace(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
- // Make sure that there is no overflow.
- uint64_t max_size;
- if (__builtin_add_overflow(addr, bytes, &max_size)) {
- return 0;
- }
-
- size_t bytes_read = 0;
- long data;
- size_t align_bytes = addr & (sizeof(long) - 1);
- if (align_bytes != 0) {
- if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
- return 0;
- }
- size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
- memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
- addr += copy_bytes;
- dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
- bytes -= copy_bytes;
- bytes_read += copy_bytes;
- }
-
- for (size_t i = 0; i < bytes / sizeof(long); i++) {
- if (!PtraceReadLong(pid, addr, &data)) {
- return bytes_read;
- }
- memcpy(dst, &data, sizeof(long));
- dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
- addr += sizeof(long);
- bytes_read += sizeof(long);
- }
-
- size_t left_over = bytes & (sizeof(long) - 1);
- if (left_over) {
- if (!PtraceReadLong(pid, addr, &data)) {
- return bytes_read;
- }
- memcpy(dst, &data, left_over);
- bytes_read += left_over;
- }
- return bytes_read;
-}
-
size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
#if !defined(__LP64__)
- // Cannot read an address greater than 32 bits.
+ // Cannot read an address greater than 32 bits in a 32 bit context.
if (addr > UINT32_MAX) {
return 0;
}
#endif
- return ReadWithPtrace(pid_, addr, dst, size);
+
+ size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
+ reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
+ if (read_func != nullptr) {
+ return read_func(pid_, addr, dst, size);
+ } else {
+ // Prefer process_vm_read, try it first. If it doesn't work, use the
+ // ptrace function. If at least one of them returns at least some data,
+ // set that as the permanent function to use.
+ // This assumes that if process_vm_read works once, it will continue
+ // to work.
+ size_t bytes = ProcessVmRead(pid_, addr, dst, size);
+ if (bytes > 0) {
+ read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
+ return bytes;
+ }
+ bytes = PtraceRead(pid_, addr, dst, size);
+ if (bytes > 0) {
+ read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
+ }
+ return bytes;
+ }
}
size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
- return ProcessVmRead(getpid(), dst, addr, size);
+ return ProcessVmRead(getpid(), addr, dst, size);
}
MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
diff --git a/libunwindstack/OWNERS b/libunwindstack/OWNERS
new file mode 100644
index 0000000..6f7e4a3
--- /dev/null
+++ b/libunwindstack/OWNERS
@@ -0,0 +1 @@
+cferris@google.com
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 28a77dc..7feafad 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <elf.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
@@ -23,315 +22,25 @@
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.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 "Check.h"
-#include "Machine.h"
-#include "Ucontext.h"
-#include "User.h"
+#include "UserArm.h"
+#include "UserArm64.h"
+#include "UserX86.h"
+#include "UserX86_64.h"
+#include "UserMips.h"
+#include "UserMips64.h"
namespace unwindstack {
-RegsArm::RegsArm()
- : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
-
-uint32_t RegsArm::MachineType() {
- return EM_ARM;
-}
-
-uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
- if (!elf->valid()) {
- return rel_pc;
- }
-
- uint64_t load_bias = elf->GetLoadBias();
- if (rel_pc < load_bias) {
- return rel_pc;
- }
- uint64_t adjusted_rel_pc = rel_pc - load_bias;
-
- if (adjusted_rel_pc < 5) {
- return rel_pc;
- }
-
- if (adjusted_rel_pc & 1) {
- // This is a thumb instruction, it could be 2 or 4 bytes.
- uint32_t value;
- if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
- (value & 0xe000f000) != 0xe000f000) {
- return rel_pc - 2;
- }
- }
- return rel_pc - 4;
-}
-
-void RegsArm::SetFromRaw() {
- set_pc(regs_[ARM_REG_PC]);
- set_sp(regs_[ARM_REG_SP]);
-}
-
-bool RegsArm::SetPcFromReturnAddress(Memory*) {
- if (pc() == regs_[ARM_REG_LR]) {
- return false;
- }
-
- set_pc(regs_[ARM_REG_LR]);
- return true;
-}
-
-void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("r0", regs_[ARM_REG_R0]);
- fn("r1", regs_[ARM_REG_R1]);
- fn("r2", regs_[ARM_REG_R2]);
- fn("r3", regs_[ARM_REG_R3]);
- fn("r4", regs_[ARM_REG_R4]);
- fn("r5", regs_[ARM_REG_R5]);
- fn("r6", regs_[ARM_REG_R6]);
- fn("r7", regs_[ARM_REG_R7]);
- fn("r8", regs_[ARM_REG_R8]);
- fn("r9", regs_[ARM_REG_R9]);
- fn("r10", regs_[ARM_REG_R10]);
- fn("r11", regs_[ARM_REG_R11]);
- fn("ip", regs_[ARM_REG_R12]);
- fn("sp", regs_[ARM_REG_SP]);
- fn("lr", regs_[ARM_REG_LR]);
- fn("pc", regs_[ARM_REG_PC]);
-}
-
-RegsArm64::RegsArm64()
- : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
-
-uint32_t RegsArm64::MachineType() {
- return EM_AARCH64;
-}
-
-uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
- if (!elf->valid()) {
- return rel_pc;
- }
-
- if (rel_pc < 4) {
- return rel_pc;
- }
- return rel_pc - 4;
-}
-
-void RegsArm64::SetFromRaw() {
- set_pc(regs_[ARM64_REG_PC]);
- set_sp(regs_[ARM64_REG_SP]);
-}
-
-bool RegsArm64::SetPcFromReturnAddress(Memory*) {
- if (pc() == regs_[ARM64_REG_LR]) {
- return false;
- }
-
- set_pc(regs_[ARM64_REG_LR]);
- return true;
-}
-
-void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("x0", regs_[ARM64_REG_R0]);
- fn("x1", regs_[ARM64_REG_R1]);
- fn("x2", regs_[ARM64_REG_R2]);
- fn("x3", regs_[ARM64_REG_R3]);
- fn("x4", regs_[ARM64_REG_R4]);
- fn("x5", regs_[ARM64_REG_R5]);
- fn("x6", regs_[ARM64_REG_R6]);
- fn("x7", regs_[ARM64_REG_R7]);
- fn("x8", regs_[ARM64_REG_R8]);
- fn("x9", regs_[ARM64_REG_R9]);
- fn("x10", regs_[ARM64_REG_R10]);
- fn("x11", regs_[ARM64_REG_R11]);
- fn("x12", regs_[ARM64_REG_R12]);
- fn("x13", regs_[ARM64_REG_R13]);
- fn("x14", regs_[ARM64_REG_R14]);
- fn("x15", regs_[ARM64_REG_R15]);
- fn("x16", regs_[ARM64_REG_R16]);
- fn("x17", regs_[ARM64_REG_R17]);
- fn("x18", regs_[ARM64_REG_R18]);
- fn("x19", regs_[ARM64_REG_R19]);
- fn("x20", regs_[ARM64_REG_R20]);
- fn("x21", regs_[ARM64_REG_R21]);
- fn("x22", regs_[ARM64_REG_R22]);
- fn("x23", regs_[ARM64_REG_R23]);
- fn("x24", regs_[ARM64_REG_R24]);
- fn("x25", regs_[ARM64_REG_R25]);
- fn("x26", regs_[ARM64_REG_R26]);
- fn("x27", regs_[ARM64_REG_R27]);
- fn("x28", regs_[ARM64_REG_R28]);
- fn("x29", regs_[ARM64_REG_R29]);
- fn("sp", regs_[ARM64_REG_SP]);
- fn("lr", regs_[ARM64_REG_LR]);
- fn("pc", regs_[ARM64_REG_PC]);
-}
-
-RegsX86::RegsX86()
- : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
-
-uint32_t RegsX86::MachineType() {
- return EM_386;
-}
-
-uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
- if (!elf->valid()) {
- return rel_pc;
- }
-
- if (rel_pc == 0) {
- return 0;
- }
- return rel_pc - 1;
-}
-
-void RegsX86::SetFromRaw() {
- set_pc(regs_[X86_REG_PC]);
- set_sp(regs_[X86_REG_SP]);
-}
-
-bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
- // Attempt to get the return address from the top of the stack.
- uint32_t new_pc;
- if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
- return false;
- }
-
- set_pc(new_pc);
- return true;
-}
-
-void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("eax", regs_[X86_REG_EAX]);
- fn("ebx", regs_[X86_REG_EBX]);
- fn("ecx", regs_[X86_REG_ECX]);
- fn("edx", regs_[X86_REG_EDX]);
- fn("ebp", regs_[X86_REG_EBP]);
- fn("edi", regs_[X86_REG_EDI]);
- fn("esi", regs_[X86_REG_ESI]);
- fn("esp", regs_[X86_REG_ESP]);
- fn("eip", regs_[X86_REG_EIP]);
-}
-
-RegsX86_64::RegsX86_64()
- : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
-
-uint32_t RegsX86_64::MachineType() {
- return EM_X86_64;
-}
-
-uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
- if (!elf->valid()) {
- return rel_pc;
- }
-
- if (rel_pc == 0) {
- return 0;
- }
-
- return rel_pc - 1;
-}
-
-void RegsX86_64::SetFromRaw() {
- set_pc(regs_[X86_64_REG_PC]);
- set_sp(regs_[X86_64_REG_SP]);
-}
-
-bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
- // Attempt to get the return address from the top of the stack.
- uint64_t new_pc;
- if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
- return false;
- }
-
- set_pc(new_pc);
- return true;
-}
-
-void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("rax", regs_[X86_64_REG_RAX]);
- fn("rbx", regs_[X86_64_REG_RBX]);
- fn("rcx", regs_[X86_64_REG_RCX]);
- fn("rdx", regs_[X86_64_REG_RDX]);
- fn("r8", regs_[X86_64_REG_R8]);
- fn("r9", regs_[X86_64_REG_R9]);
- fn("r10", regs_[X86_64_REG_R10]);
- fn("r11", regs_[X86_64_REG_R11]);
- fn("r12", regs_[X86_64_REG_R12]);
- fn("r13", regs_[X86_64_REG_R13]);
- fn("r14", regs_[X86_64_REG_R14]);
- fn("r15", regs_[X86_64_REG_R15]);
- fn("rdi", regs_[X86_64_REG_RDI]);
- fn("rsi", regs_[X86_64_REG_RSI]);
- fn("rbp", regs_[X86_64_REG_RBP]);
- fn("rsp", regs_[X86_64_REG_RSP]);
- fn("rip", regs_[X86_64_REG_RIP]);
-}
-
-static Regs* ReadArm(void* remote_data) {
- arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
-
- RegsArm* regs = new RegsArm();
- memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
- regs->SetFromRaw();
- return regs;
-}
-
-static Regs* ReadArm64(void* remote_data) {
- arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
-
- RegsArm64* regs = new RegsArm64();
- memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
- uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
- reg_data[ARM64_REG_PC] = user->pc;
- reg_data[ARM64_REG_SP] = user->sp;
- regs->SetFromRaw();
- return regs;
-}
-
-static Regs* ReadX86(void* remote_data) {
- x86_user_regs* user = reinterpret_cast<x86_user_regs*>(remote_data);
-
- RegsX86* regs = new RegsX86();
- (*regs)[X86_REG_EAX] = user->eax;
- (*regs)[X86_REG_EBX] = user->ebx;
- (*regs)[X86_REG_ECX] = user->ecx;
- (*regs)[X86_REG_EDX] = user->edx;
- (*regs)[X86_REG_EBP] = user->ebp;
- (*regs)[X86_REG_EDI] = user->edi;
- (*regs)[X86_REG_ESI] = user->esi;
- (*regs)[X86_REG_ESP] = user->esp;
- (*regs)[X86_REG_EIP] = user->eip;
-
- regs->SetFromRaw();
- return regs;
-}
-
-static Regs* ReadX86_64(void* remote_data) {
- x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
-
- RegsX86_64* regs = new RegsX86_64();
- (*regs)[X86_64_REG_RAX] = user->rax;
- (*regs)[X86_64_REG_RBX] = user->rbx;
- (*regs)[X86_64_REG_RCX] = user->rcx;
- (*regs)[X86_64_REG_RDX] = user->rdx;
- (*regs)[X86_64_REG_R8] = user->r8;
- (*regs)[X86_64_REG_R9] = user->r9;
- (*regs)[X86_64_REG_R10] = user->r10;
- (*regs)[X86_64_REG_R11] = user->r11;
- (*regs)[X86_64_REG_R12] = user->r12;
- (*regs)[X86_64_REG_R13] = user->r13;
- (*regs)[X86_64_REG_R14] = user->r14;
- (*regs)[X86_64_REG_R15] = user->r15;
- (*regs)[X86_64_REG_RDI] = user->rdi;
- (*regs)[X86_64_REG_RSI] = user->rsi;
- (*regs)[X86_64_REG_RBP] = user->rbp;
- (*regs)[X86_64_REG_RSP] = user->rsp;
- (*regs)[X86_64_REG_RIP] = user->rip;
-
- regs->SetFromRaw();
- return regs;
-}
+// The largest user structure.
+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.
@@ -348,106 +57,54 @@
switch (io.iov_len) {
case sizeof(x86_user_regs):
- return ReadX86(buffer.data());
+ return RegsX86::Read(buffer.data());
case sizeof(x86_64_user_regs):
- return ReadX86_64(buffer.data());
+ return RegsX86_64::Read(buffer.data());
case sizeof(arm_user_regs):
- return ReadArm(buffer.data());
+ return RegsArm::Read(buffer.data());
case sizeof(arm64_user_regs):
- return ReadArm64(buffer.data());
+ 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;
}
-static Regs* CreateFromArmUcontext(void* ucontext) {
- arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
-
- RegsArm* regs = new RegsArm();
- memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
- regs->SetFromRaw();
- return regs;
-}
-
-static Regs* CreateFromArm64Ucontext(void* ucontext) {
- arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
-
- RegsArm64* regs = new RegsArm64();
- memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
- regs->SetFromRaw();
- return regs;
-}
-
-void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
- // Put the registers in the expected order.
- regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
- regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
- regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
- regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
- regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
- regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
- regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
- regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
- regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
- SetFromRaw();
-}
-
-static Regs* CreateFromX86Ucontext(void* ucontext) {
- x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
-
- RegsX86* regs = new RegsX86();
- regs->SetFromUcontext(x86_ucontext);
- return regs;
-}
-
-void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
- // R8-R15
- memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
-
- // Rest of the registers.
- regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
- regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
- regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
- regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
- regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
- regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
- regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
- regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
- regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
-
- SetFromRaw();
-}
-
-static Regs* CreateFromX86_64Ucontext(void* ucontext) {
- x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
-
- RegsX86_64* regs = new RegsX86_64();
- regs->SetFromUcontext(x86_64_ucontext);
- return regs;
-}
-
-Regs* Regs::CreateFromUcontext(uint32_t machine_type, void* ucontext) {
- switch (machine_type) {
- case EM_386:
- return CreateFromX86Ucontext(ucontext);
- case EM_X86_64:
- return CreateFromX86_64Ucontext(ucontext);
- case EM_ARM:
- return CreateFromArmUcontext(ucontext);
- case EM_AARCH64:
- return CreateFromArm64Ucontext(ucontext);
+Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
+ switch (arch) {
+ case ARCH_X86:
+ return RegsX86::CreateFromUcontext(ucontext);
+ case ARCH_X86_64:
+ return RegsX86_64::CreateFromUcontext(ucontext);
+ case ARCH_ARM:
+ 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;
}
- return nullptr;
}
-uint32_t Regs::CurrentMachineType() {
+ArchEnum Regs::CurrentArch() {
#if defined(__arm__)
- return EM_ARM;
+ return ARCH_ARM;
#elif defined(__aarch64__)
- return EM_AARCH64;
+ return ARCH_ARM64;
#elif defined(__i386__)
- return EM_386;
+ return ARCH_X86;
#elif defined(__x86_64__)
- return EM_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
@@ -463,198 +120,14 @@
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
return regs;
}
-bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
- uint32_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->ReadFully(rel_pc, &data, sizeof(data))) {
- return false;
- }
-
- uint64_t offset = 0;
- if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
- // non-RT sigreturn call.
- // __restore:
- //
- // Form 1 (arm):
- // 0x77 0x70 mov r7, #0x77
- // 0xa0 0xe3 svc 0x00000000
- //
- // Form 2 (arm):
- // 0x77 0x00 0x90 0xef svc 0x00900077
- //
- // Form 3 (thumb):
- // 0x77 0x27 movs r7, #77
- // 0x00 0xdf svc 0
- if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
- return false;
- }
- if (data == 0x5ac3c35a) {
- // SP + uc_mcontext offset + r0 offset.
- offset = sp() + 0x14 + 0xc;
- } else {
- // SP + r0 offset
- offset = sp() + 0xc;
- }
- } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
- // RT sigreturn call.
- // __restore_rt:
- //
- // Form 1 (arm):
- // 0xad 0x70 mov r7, #0xad
- // 0xa0 0xe3 svc 0x00000000
- //
- // Form 2 (arm):
- // 0xad 0x00 0x90 0xef svc 0x009000ad
- //
- // Form 3 (thumb):
- // 0xad 0x27 movs r7, #ad
- // 0x00 0xdf svc 0
- if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
- return false;
- }
- if (data == sp() + 8) {
- // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
- offset = sp() + 8 + 0x80 + 0x14 + 0xc;
- } else {
- // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
- offset = sp() + 0x80 + 0x14 + 0xc;
- }
- }
- if (offset == 0) {
- return false;
- }
-
- if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
- return false;
- }
- SetFromRaw();
- return true;
-}
-
-bool RegsArm64::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->ReadFully(rel_pc, &data, sizeof(data))) {
- return false;
- }
-
- // Look for the kernel sigreturn function.
- // __kernel_rt_sigreturn:
- // 0xd2801168 mov x8, #0x8b
- // 0xd4000001 svc #0x0
- if (data != 0xd4000001d2801168ULL) {
- return false;
- }
-
- // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
- if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
- sizeof(uint64_t) * ARM64_REG_LAST)) {
- return false;
- }
-
- SetFromRaw();
- return true;
-}
-
-bool RegsX86::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->ReadFully(rel_pc, &data, sizeof(data))) {
- return false;
- }
-
- if (data == 0x80cd00000077b858ULL) {
- // Without SA_SIGINFO set, the return sequence is:
- //
- // __restore:
- // 0x58 pop %eax
- // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
- // 0xcd 0x80 int 0x80
- //
- // SP points at arguments:
- // int signum
- // struct sigcontext (same format as mcontext)
- struct x86_mcontext_t context;
- if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
- return false;
- }
- regs_[X86_REG_EBP] = context.ebp;
- regs_[X86_REG_ESP] = context.esp;
- regs_[X86_REG_EBX] = context.ebx;
- regs_[X86_REG_EDX] = context.edx;
- regs_[X86_REG_ECX] = context.ecx;
- regs_[X86_REG_EAX] = context.eax;
- regs_[X86_REG_EIP] = context.eip;
- SetFromRaw();
- return true;
- } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
- // With SA_SIGINFO set, the return sequence is:
- //
- // __restore_rt:
- // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
- // 0xcd 0x80 int 0x80
- //
- // SP points at arguments:
- // int signum
- // siginfo*
- // ucontext*
-
- // Get the location of the sigcontext data.
- uint32_t ptr;
- if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
- return false;
- }
- // Only read the portion of the data structure we care about.
- x86_ucontext_t x86_ucontext;
- if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
- return false;
- }
- SetFromUcontext(&x86_ucontext);
- return true;
- }
- return false;
-}
-
-bool RegsX86_64::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->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
- return false;
- }
-
- uint16_t data2;
- if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
- return false;
- }
-
- // __restore_rt:
- // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
- // 0x0f 0x05 syscall
- // 0x0f nopl 0x0($rax)
-
- // Read the mcontext data from the stack.
- // sp points to the ucontext data structure, read only the mcontext part.
- x86_64_ucontext_t x86_64_ucontext;
- if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
- sizeof(x86_64_mcontext_t))) {
- return false;
- }
- SetFromUcontext(&x86_64_ucontext);
- return true;
-}
-
} // namespace unwindstack
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
new file mode 100644
index 0000000..34f29bd
--- /dev/null
+++ b/libunwindstack/RegsArm.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 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/RegsArm.h>
+
+#include "MachineArm.h"
+#include "UcontextArm.h"
+#include "UserArm.h"
+
+namespace unwindstack {
+
+RegsArm::RegsArm()
+ : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
+
+ArchEnum RegsArm::Arch() {
+ return ARCH_ARM;
+}
+
+uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+ if (!elf->valid()) {
+ return rel_pc;
+ }
+
+ uint64_t load_bias = elf->GetLoadBias();
+ if (rel_pc < load_bias) {
+ return rel_pc;
+ }
+ uint64_t adjusted_rel_pc = rel_pc - load_bias;
+
+ if (adjusted_rel_pc < 5) {
+ return rel_pc;
+ }
+
+ if (adjusted_rel_pc & 1) {
+ // This is a thumb instruction, it could be 2 or 4 bytes.
+ uint32_t value;
+ if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
+ (value & 0xe000f000) != 0xe000f000) {
+ return rel_pc - 2;
+ }
+ }
+ return rel_pc - 4;
+}
+
+void RegsArm::SetFromRaw() {
+ set_pc(regs_[ARM_REG_PC]);
+ set_sp(regs_[ARM_REG_SP]);
+}
+
+bool RegsArm::SetPcFromReturnAddress(Memory*) {
+ if (pc() == regs_[ARM_REG_LR]) {
+ return false;
+ }
+
+ set_pc(regs_[ARM_REG_LR]);
+ return true;
+}
+
+void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("r0", regs_[ARM_REG_R0]);
+ fn("r1", regs_[ARM_REG_R1]);
+ fn("r2", regs_[ARM_REG_R2]);
+ fn("r3", regs_[ARM_REG_R3]);
+ fn("r4", regs_[ARM_REG_R4]);
+ fn("r5", regs_[ARM_REG_R5]);
+ fn("r6", regs_[ARM_REG_R6]);
+ fn("r7", regs_[ARM_REG_R7]);
+ fn("r8", regs_[ARM_REG_R8]);
+ fn("r9", regs_[ARM_REG_R9]);
+ fn("r10", regs_[ARM_REG_R10]);
+ fn("r11", regs_[ARM_REG_R11]);
+ fn("ip", regs_[ARM_REG_R12]);
+ fn("sp", regs_[ARM_REG_SP]);
+ fn("lr", regs_[ARM_REG_LR]);
+ fn("pc", regs_[ARM_REG_PC]);
+}
+
+Regs* RegsArm::Read(void* remote_data) {
+ arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
+
+ RegsArm* regs = new RegsArm();
+ memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
+ regs->SetFromRaw();
+ return regs;
+}
+
+Regs* RegsArm::CreateFromUcontext(void* ucontext) {
+ arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
+
+ RegsArm* regs = new RegsArm();
+ memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
+ regs->SetFromRaw();
+ return regs;
+}
+
+bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+ uint32_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->ReadFully(rel_pc, &data, sizeof(data))) {
+ return false;
+ }
+
+ uint64_t offset = 0;
+ if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+ // non-RT sigreturn call.
+ // __restore:
+ //
+ // Form 1 (arm):
+ // 0x77 0x70 mov r7, #0x77
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0x77 0x00 0x90 0xef svc 0x00900077
+ //
+ // Form 3 (thumb):
+ // 0x77 0x27 movs r7, #77
+ // 0x00 0xdf svc 0
+ if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == 0x5ac3c35a) {
+ // SP + uc_mcontext offset + r0 offset.
+ offset = sp() + 0x14 + 0xc;
+ } else {
+ // SP + r0 offset
+ offset = sp() + 0xc;
+ }
+ } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+ // RT sigreturn call.
+ // __restore_rt:
+ //
+ // Form 1 (arm):
+ // 0xad 0x70 mov r7, #0xad
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0xad 0x00 0x90 0xef svc 0x009000ad
+ //
+ // Form 3 (thumb):
+ // 0xad 0x27 movs r7, #ad
+ // 0x00 0xdf svc 0
+ if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == sp() + 8) {
+ // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+ } else {
+ // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 0x80 + 0x14 + 0xc;
+ }
+ }
+ if (offset == 0) {
+ return false;
+ }
+
+ if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+ return false;
+ }
+ SetFromRaw();
+ return true;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
new file mode 100644
index 0000000..2077bc5
--- /dev/null
+++ b/libunwindstack/RegsArm64.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 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/RegsArm64.h>
+
+#include "MachineArm64.h"
+#include "UcontextArm64.h"
+#include "UserArm64.h"
+
+namespace unwindstack {
+
+RegsArm64::RegsArm64()
+ : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
+
+ArchEnum RegsArm64::Arch() {
+ return ARCH_ARM64;
+}
+
+uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+ if (!elf->valid()) {
+ return rel_pc;
+ }
+
+ if (rel_pc < 4) {
+ return rel_pc;
+ }
+ return rel_pc - 4;
+}
+
+void RegsArm64::SetFromRaw() {
+ set_pc(regs_[ARM64_REG_PC]);
+ set_sp(regs_[ARM64_REG_SP]);
+}
+
+bool RegsArm64::SetPcFromReturnAddress(Memory*) {
+ if (pc() == regs_[ARM64_REG_LR]) {
+ return false;
+ }
+
+ set_pc(regs_[ARM64_REG_LR]);
+ return true;
+}
+
+void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("x0", regs_[ARM64_REG_R0]);
+ fn("x1", regs_[ARM64_REG_R1]);
+ fn("x2", regs_[ARM64_REG_R2]);
+ fn("x3", regs_[ARM64_REG_R3]);
+ fn("x4", regs_[ARM64_REG_R4]);
+ fn("x5", regs_[ARM64_REG_R5]);
+ fn("x6", regs_[ARM64_REG_R6]);
+ fn("x7", regs_[ARM64_REG_R7]);
+ fn("x8", regs_[ARM64_REG_R8]);
+ fn("x9", regs_[ARM64_REG_R9]);
+ fn("x10", regs_[ARM64_REG_R10]);
+ fn("x11", regs_[ARM64_REG_R11]);
+ fn("x12", regs_[ARM64_REG_R12]);
+ fn("x13", regs_[ARM64_REG_R13]);
+ fn("x14", regs_[ARM64_REG_R14]);
+ fn("x15", regs_[ARM64_REG_R15]);
+ fn("x16", regs_[ARM64_REG_R16]);
+ fn("x17", regs_[ARM64_REG_R17]);
+ fn("x18", regs_[ARM64_REG_R18]);
+ fn("x19", regs_[ARM64_REG_R19]);
+ fn("x20", regs_[ARM64_REG_R20]);
+ fn("x21", regs_[ARM64_REG_R21]);
+ fn("x22", regs_[ARM64_REG_R22]);
+ fn("x23", regs_[ARM64_REG_R23]);
+ fn("x24", regs_[ARM64_REG_R24]);
+ fn("x25", regs_[ARM64_REG_R25]);
+ fn("x26", regs_[ARM64_REG_R26]);
+ fn("x27", regs_[ARM64_REG_R27]);
+ fn("x28", regs_[ARM64_REG_R28]);
+ fn("x29", regs_[ARM64_REG_R29]);
+ fn("sp", regs_[ARM64_REG_SP]);
+ fn("lr", regs_[ARM64_REG_LR]);
+ fn("pc", regs_[ARM64_REG_PC]);
+}
+
+Regs* RegsArm64::Read(void* remote_data) {
+ arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
+
+ RegsArm64* regs = new RegsArm64();
+ memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
+ uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+ reg_data[ARM64_REG_PC] = user->pc;
+ reg_data[ARM64_REG_SP] = user->sp;
+ regs->SetFromRaw();
+ return regs;
+}
+
+Regs* RegsArm64::CreateFromUcontext(void* ucontext) {
+ arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
+
+ RegsArm64* regs = new RegsArm64();
+ memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
+ regs->SetFromRaw();
+ return regs;
+}
+
+bool RegsArm64::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->ReadFully(rel_pc, &data, sizeof(data))) {
+ return false;
+ }
+
+ // Look for the kernel sigreturn function.
+ // __kernel_rt_sigreturn:
+ // 0xd2801168 mov x8, #0x8b
+ // 0xd4000001 svc #0x0
+ if (data != 0xd4000001d2801168ULL) {
+ return false;
+ }
+
+ // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+ if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+ sizeof(uint64_t) * ARM64_REG_LAST)) {
+ return false;
+ }
+
+ SetFromRaw();
+ return true;
+}
+
+} // namespace unwindstack
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, ®s_[MIPS64_REG_PC],
+ sizeof(uint64_t))) {
+ return false;
+ }
+
+ SetFromRaw();
+ return true;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
new file mode 100644
index 0000000..ef2f3de
--- /dev/null
+++ b/libunwindstack/RegsX86.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 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/RegsX86.h>
+
+#include "MachineX86.h"
+#include "UcontextX86.h"
+#include "UserX86.h"
+
+namespace unwindstack {
+
+RegsX86::RegsX86()
+ : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
+
+ArchEnum RegsX86::Arch() {
+ return ARCH_X86;
+}
+
+uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+ if (!elf->valid()) {
+ return rel_pc;
+ }
+
+ if (rel_pc == 0) {
+ return 0;
+ }
+ return rel_pc - 1;
+}
+
+void RegsX86::SetFromRaw() {
+ set_pc(regs_[X86_REG_PC]);
+ set_sp(regs_[X86_REG_SP]);
+}
+
+bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
+ // Attempt to get the return address from the top of the stack.
+ uint32_t new_pc;
+ if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+ return false;
+ }
+
+ set_pc(new_pc);
+ return true;
+}
+
+void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("eax", regs_[X86_REG_EAX]);
+ fn("ebx", regs_[X86_REG_EBX]);
+ fn("ecx", regs_[X86_REG_ECX]);
+ fn("edx", regs_[X86_REG_EDX]);
+ fn("ebp", regs_[X86_REG_EBP]);
+ fn("edi", regs_[X86_REG_EDI]);
+ fn("esi", regs_[X86_REG_ESI]);
+ fn("esp", regs_[X86_REG_ESP]);
+ fn("eip", regs_[X86_REG_EIP]);
+}
+
+Regs* RegsX86::Read(void* user_data) {
+ x86_user_regs* user = reinterpret_cast<x86_user_regs*>(user_data);
+
+ RegsX86* regs = new RegsX86();
+ (*regs)[X86_REG_EAX] = user->eax;
+ (*regs)[X86_REG_EBX] = user->ebx;
+ (*regs)[X86_REG_ECX] = user->ecx;
+ (*regs)[X86_REG_EDX] = user->edx;
+ (*regs)[X86_REG_EBP] = user->ebp;
+ (*regs)[X86_REG_EDI] = user->edi;
+ (*regs)[X86_REG_ESI] = user->esi;
+ (*regs)[X86_REG_ESP] = user->esp;
+ (*regs)[X86_REG_EIP] = user->eip;
+
+ regs->SetFromRaw();
+ return regs;
+}
+
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+ // Put the registers in the expected order.
+ regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+ regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+ regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+ regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+ regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+ regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+ regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+ regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+ regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+ SetFromRaw();
+}
+
+Regs* RegsX86::CreateFromUcontext(void* ucontext) {
+ x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
+
+ RegsX86* regs = new RegsX86();
+ regs->SetFromUcontext(x86_ucontext);
+ return regs;
+}
+
+bool RegsX86::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->ReadFully(rel_pc, &data, sizeof(data))) {
+ return false;
+ }
+
+ if (data == 0x80cd00000077b858ULL) {
+ // Without SA_SIGINFO set, the return sequence is:
+ //
+ // __restore:
+ // 0x58 pop %eax
+ // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // struct sigcontext (same format as mcontext)
+ struct x86_mcontext_t context;
+ if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
+ return false;
+ }
+ regs_[X86_REG_EBP] = context.ebp;
+ regs_[X86_REG_ESP] = context.esp;
+ regs_[X86_REG_EBX] = context.ebx;
+ regs_[X86_REG_EDX] = context.edx;
+ regs_[X86_REG_ECX] = context.ecx;
+ regs_[X86_REG_EAX] = context.eax;
+ regs_[X86_REG_EIP] = context.eip;
+ SetFromRaw();
+ return true;
+ } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+ // With SA_SIGINFO set, the return sequence is:
+ //
+ // __restore_rt:
+ // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // siginfo*
+ // ucontext*
+
+ // Get the location of the sigcontext data.
+ uint32_t ptr;
+ if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
+ return false;
+ }
+ // Only read the portion of the data structure we care about.
+ x86_ucontext_t x86_ucontext;
+ if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_ucontext);
+ return true;
+ }
+ return false;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
new file mode 100644
index 0000000..70921f8
--- /dev/null
+++ b/libunwindstack/RegsX86_64.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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/RegsX86_64.h>
+
+#include "MachineX86_64.h"
+#include "UcontextX86_64.h"
+#include "UserX86_64.h"
+
+namespace unwindstack {
+
+RegsX86_64::RegsX86_64()
+ : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
+
+ArchEnum RegsX86_64::Arch() {
+ return ARCH_X86_64;
+}
+
+uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
+ if (!elf->valid()) {
+ return rel_pc;
+ }
+
+ if (rel_pc == 0) {
+ return 0;
+ }
+
+ return rel_pc - 1;
+}
+
+void RegsX86_64::SetFromRaw() {
+ set_pc(regs_[X86_64_REG_PC]);
+ set_sp(regs_[X86_64_REG_SP]);
+}
+
+bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
+ // Attempt to get the return address from the top of the stack.
+ uint64_t new_pc;
+ if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
+ return false;
+ }
+
+ set_pc(new_pc);
+ return true;
+}
+
+void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+ fn("rax", regs_[X86_64_REG_RAX]);
+ fn("rbx", regs_[X86_64_REG_RBX]);
+ fn("rcx", regs_[X86_64_REG_RCX]);
+ fn("rdx", regs_[X86_64_REG_RDX]);
+ fn("r8", regs_[X86_64_REG_R8]);
+ fn("r9", regs_[X86_64_REG_R9]);
+ fn("r10", regs_[X86_64_REG_R10]);
+ fn("r11", regs_[X86_64_REG_R11]);
+ fn("r12", regs_[X86_64_REG_R12]);
+ fn("r13", regs_[X86_64_REG_R13]);
+ fn("r14", regs_[X86_64_REG_R14]);
+ fn("r15", regs_[X86_64_REG_R15]);
+ fn("rdi", regs_[X86_64_REG_RDI]);
+ fn("rsi", regs_[X86_64_REG_RSI]);
+ fn("rbp", regs_[X86_64_REG_RBP]);
+ fn("rsp", regs_[X86_64_REG_RSP]);
+ fn("rip", regs_[X86_64_REG_RIP]);
+}
+
+Regs* RegsX86_64::Read(void* remote_data) {
+ x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
+
+ RegsX86_64* regs = new RegsX86_64();
+ (*regs)[X86_64_REG_RAX] = user->rax;
+ (*regs)[X86_64_REG_RBX] = user->rbx;
+ (*regs)[X86_64_REG_RCX] = user->rcx;
+ (*regs)[X86_64_REG_RDX] = user->rdx;
+ (*regs)[X86_64_REG_R8] = user->r8;
+ (*regs)[X86_64_REG_R9] = user->r9;
+ (*regs)[X86_64_REG_R10] = user->r10;
+ (*regs)[X86_64_REG_R11] = user->r11;
+ (*regs)[X86_64_REG_R12] = user->r12;
+ (*regs)[X86_64_REG_R13] = user->r13;
+ (*regs)[X86_64_REG_R14] = user->r14;
+ (*regs)[X86_64_REG_R15] = user->r15;
+ (*regs)[X86_64_REG_RDI] = user->rdi;
+ (*regs)[X86_64_REG_RSI] = user->rsi;
+ (*regs)[X86_64_REG_RBP] = user->rbp;
+ (*regs)[X86_64_REG_RSP] = user->rsp;
+ (*regs)[X86_64_REG_RIP] = user->rip;
+
+ regs->SetFromRaw();
+ return regs;
+}
+
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
+ // R8-R15
+ memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+ // Rest of the registers.
+ regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+ regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+ regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+ regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+ regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+ regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+ regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+ regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+ regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+ SetFromRaw();
+}
+
+Regs* RegsX86_64::CreateFromUcontext(void* ucontext) {
+ x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
+
+ RegsX86_64* regs = new RegsX86_64();
+ regs->SetFromUcontext(x86_64_ucontext);
+ return regs;
+}
+
+bool RegsX86_64::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->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+ return false;
+ }
+
+ uint16_t data2;
+ if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+ return false;
+ }
+
+ // __restore_rt:
+ // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
+ // 0x0f 0x05 syscall
+ // 0x0f nopl 0x0($rax)
+
+ // Read the mcontext data from the stack.
+ // sp points to the ucontext data structure, read only the mcontext part.
+ x86_64_ucontext_t x86_64_ucontext;
+ if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
+ sizeof(x86_64_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_64_ucontext);
+ return true;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
deleted file mode 100644
index 22f6a89..0000000
--- a/libunwindstack/Ucontext.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 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_H
-#define _LIBUNWINDSTACK_UCONTEXT_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-//-------------------------------------------------------------------
-// ARM ucontext structures
-//-------------------------------------------------------------------
-struct arm_stack_t {
- uint32_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint32_t ss_size; // size_t
-};
-
-struct arm_mcontext_t {
- uint32_t trap_no; // unsigned long
- uint32_t error_code; // unsigned long
- uint32_t oldmask; // unsigned long
- uint32_t regs[ARM_REG_LAST]; // unsigned long
- uint32_t cpsr; // unsigned long
- uint32_t fault_address; // unsigned long
-};
-
-struct arm_ucontext_t {
- uint32_t uc_flags; // unsigned long
- uint32_t uc_link; // struct ucontext*
- arm_stack_t uc_stack;
- arm_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// ARM64 ucontext structures
-//-------------------------------------------------------------------
-struct arm64_stack_t {
- uint64_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint64_t ss_size; // size_t
-};
-
-struct arm64_sigset_t {
- uint64_t sig; // unsigned long
-};
-
-struct arm64_mcontext_t {
- uint64_t fault_address; // __u64
- uint64_t regs[ARM64_REG_LAST]; // __u64
- uint64_t pstate; // __u64
- // Nothing else is used, so don't define it.
-};
-
-struct arm64_ucontext_t {
- uint64_t uc_flags; // unsigned long
- uint64_t uc_link; // struct ucontext*
- arm64_stack_t uc_stack;
- arm64_sigset_t uc_sigmask;
- // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
- char __padding[128 - sizeof(arm64_sigset_t)];
- // The full structure requires 16 byte alignment, but our partial structure
- // doesn't, so force the alignment.
- arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// X86 ucontext structures
-//-------------------------------------------------------------------
-struct x86_stack_t {
- uint32_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint32_t ss_size; // size_t
-};
-
-struct x86_mcontext_t {
- uint32_t gs;
- uint32_t fs;
- uint32_t es;
- uint32_t ds;
- uint32_t edi;
- uint32_t esi;
- uint32_t ebp;
- uint32_t esp;
- uint32_t ebx;
- uint32_t edx;
- uint32_t ecx;
- uint32_t eax;
- uint32_t trapno;
- uint32_t err;
- uint32_t eip;
- uint32_t cs;
- uint32_t efl;
- uint32_t uesp;
- uint32_t ss;
- // Only care about the registers, skip everything else.
-};
-
-struct x86_ucontext_t {
- uint32_t uc_flags; // unsigned long
- uint32_t uc_link; // struct ucontext*
- x86_stack_t uc_stack;
- x86_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-//-------------------------------------------------------------------
-// X86_64 ucontext structures
-//-------------------------------------------------------------------
-struct x86_64_stack_t {
- uint64_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint64_t ss_size; // size_t
-};
-
-struct x86_64_mcontext_t {
- uint64_t r8;
- uint64_t r9;
- uint64_t r10;
- uint64_t r11;
- uint64_t r12;
- uint64_t r13;
- uint64_t r14;
- uint64_t r15;
- uint64_t rdi;
- uint64_t rsi;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t rdx;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rsp;
- uint64_t rip;
- uint64_t efl;
- uint64_t csgsfs;
- uint64_t err;
- uint64_t trapno;
- uint64_t oldmask;
- uint64_t cr2;
- // Only care about the registers, skip everything else.
-};
-
-struct x86_64_ucontext_t {
- uint64_t uc_flags; // unsigned long
- uint64_t uc_link; // struct ucontext*
- x86_64_stack_t uc_stack;
- x86_64_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-//-------------------------------------------------------------------
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_H
diff --git a/libunwindstack/UcontextArm.h b/libunwindstack/UcontextArm.h
new file mode 100644
index 0000000..8c94166
--- /dev/null
+++ b/libunwindstack/UcontextArm.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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_ARM_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM_H
+
+#include <stdint.h>
+
+#include "MachineArm.h"
+
+namespace unwindstack {
+
+struct arm_stack_t {
+ uint32_t ss_sp; // void __user*
+ int32_t ss_flags; // int
+ uint32_t ss_size; // size_t
+};
+
+struct arm_mcontext_t {
+ uint32_t trap_no; // unsigned long
+ uint32_t error_code; // unsigned long
+ uint32_t oldmask; // unsigned long
+ uint32_t regs[ARM_REG_LAST]; // unsigned long
+ uint32_t cpsr; // unsigned long
+ uint32_t fault_address; // unsigned long
+};
+
+struct arm_ucontext_t {
+ uint32_t uc_flags; // unsigned long
+ uint32_t uc_link; // struct ucontext*
+ arm_stack_t uc_stack;
+ arm_mcontext_t uc_mcontext;
+ // Nothing else is used, so don't define it.
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_ARM_H
diff --git a/libunwindstack/UcontextArm64.h b/libunwindstack/UcontextArm64.h
new file mode 100644
index 0000000..655719f
--- /dev/null
+++ b/libunwindstack/UcontextArm64.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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_ARM64_H
+#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H
+
+#include <stdint.h>
+
+#include "MachineArm64.h"
+
+namespace unwindstack {
+
+struct arm64_stack_t {
+ uint64_t ss_sp; // void __user*
+ int32_t ss_flags; // int
+ uint64_t ss_size; // size_t
+};
+
+struct arm64_sigset_t {
+ uint64_t sig; // unsigned long
+};
+
+struct arm64_mcontext_t {
+ uint64_t fault_address; // __u64
+ uint64_t regs[ARM64_REG_LAST]; // __u64
+ uint64_t pstate; // __u64
+ // Nothing else is used, so don't define it.
+};
+
+struct arm64_ucontext_t {
+ uint64_t uc_flags; // unsigned long
+ uint64_t uc_link; // struct ucontext*
+ arm64_stack_t uc_stack;
+ arm64_sigset_t uc_sigmask;
+ // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
+ char __padding[128 - sizeof(arm64_sigset_t)];
+ // The full structure requires 16 byte alignment, but our partial structure
+ // doesn't, so force the alignment.
+ arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_UCONTEXT_ARM64_H
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/User.h b/libunwindstack/UcontextX86.h
similarity index 62%
copy from libunwindstack/User.h
copy to libunwindstack/UcontextX86.h
index 53f7e50..f79d92b 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UcontextX86.h
@@ -26,75 +26,52 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_H
+
+#include <stdint.h>
+
+#include "MachineX86.h"
namespace unwindstack {
-struct x86_user_regs {
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
+struct x86_stack_t {
+ uint32_t ss_sp; // void __user*
+ int32_t ss_flags; // int
+ uint32_t ss_size; // size_t
+};
+
+struct x86_mcontext_t {
+ uint32_t gs;
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
uint32_t edi;
+ uint32_t esi;
uint32_t ebp;
- uint32_t eax;
- uint32_t xds;
- uint32_t xes;
- uint32_t xfs;
- uint32_t xgs;
- uint32_t orig_eax;
- uint32_t eip;
- uint32_t xcs;
- uint32_t eflags;
uint32_t esp;
- uint32_t xss;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t efl;
+ uint32_t uesp;
+ uint32_t ss;
+ // Only care about the registers, skip everything else.
};
-struct x86_64_user_regs {
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t r11;
- uint64_t r10;
- uint64_t r9;
- uint64_t r8;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rdx;
- uint64_t rsi;
- uint64_t rdi;
- uint64_t orig_rax;
- uint64_t rip;
- uint64_t cs;
- uint64_t eflags;
- uint64_t rsp;
- uint64_t ss;
- uint64_t fs_base;
- uint64_t gs_base;
- uint64_t ds;
- uint64_t es;
- uint64_t fs;
- uint64_t gs;
+struct x86_ucontext_t {
+ uint32_t uc_flags; // unsigned long
+ uint32_t uc_link; // struct ucontext*
+ x86_stack_t uc_stack;
+ x86_mcontext_t uc_mcontext;
+ // Nothing else is used, so don't define it.
};
-struct arm_user_regs {
- uint32_t regs[18];
-};
-
-struct arm64_user_regs {
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_USER_H
+#endif // _LIBUNWINDSTACK_UCONTEXT_X86_H
diff --git a/libunwindstack/User.h b/libunwindstack/UcontextX86_64.h
similarity index 67%
copy from libunwindstack/User.h
copy to libunwindstack/UcontextX86_64.h
index 53f7e50..d689796 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UcontextX86_64.h
@@ -26,75 +26,56 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H
+
+#include <stdint.h>
+
+#include "MachineX86_64.h"
namespace unwindstack {
-struct x86_user_regs {
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t eax;
- uint32_t xds;
- uint32_t xes;
- uint32_t xfs;
- uint32_t xgs;
- uint32_t orig_eax;
- uint32_t eip;
- uint32_t xcs;
- uint32_t eflags;
- uint32_t esp;
- uint32_t xss;
+struct x86_64_stack_t {
+ uint64_t ss_sp; // void __user*
+ int32_t ss_flags; // int
+ uint64_t ss_size; // size_t
};
-struct x86_64_user_regs {
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
+struct x86_64_mcontext_t {
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rdi;
+ uint64_t rsi;
uint64_t rbp;
uint64_t rbx;
- uint64_t r11;
- uint64_t r10;
- uint64_t r9;
- uint64_t r8;
+ uint64_t rdx;
uint64_t rax;
uint64_t rcx;
- uint64_t rdx;
- uint64_t rsi;
- uint64_t rdi;
- uint64_t orig_rax;
- uint64_t rip;
- uint64_t cs;
- uint64_t eflags;
uint64_t rsp;
- uint64_t ss;
- uint64_t fs_base;
- uint64_t gs_base;
- uint64_t ds;
- uint64_t es;
- uint64_t fs;
- uint64_t gs;
+ uint64_t rip;
+ uint64_t efl;
+ uint64_t csgsfs;
+ uint64_t err;
+ uint64_t trapno;
+ uint64_t oldmask;
+ uint64_t cr2;
+ // Only care about the registers, skip everything else.
};
-struct arm_user_regs {
- uint32_t regs[18];
+struct x86_64_ucontext_t {
+ uint64_t uc_flags; // unsigned long
+ uint64_t uc_link; // struct ucontext*
+ x86_64_stack_t uc_stack;
+ x86_64_mcontext_t uc_mcontext;
+ // Nothing else is used, so don't define it.
};
-struct arm64_user_regs {
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_USER_H
+#endif // _LIBUNWINDSTACK_UCONTEXT_X86_64_H
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 3092a62..a83f85b 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -174,8 +174,7 @@
if (frame_num >= frames_.size()) {
return "";
}
- return FormatFrame(frames_[frame_num],
- regs_->MachineType() == EM_ARM || regs_->MachineType() == EM_386);
+ return FormatFrame(frames_[frame_num], regs_->Format32Bit());
}
std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) {
diff --git a/libunwindstack/UserArm.h b/libunwindstack/UserArm.h
new file mode 100644
index 0000000..7388c03
--- /dev/null
+++ b/libunwindstack/UserArm.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 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_ARM_H
+#define _LIBUNWINDSTACK_USER_ARM_H
+
+namespace unwindstack {
+
+struct arm_user_regs {
+ uint32_t regs[18];
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_USER_ARM_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserArm64.h
similarity index 60%
copy from libunwindstack/User.h
copy to libunwindstack/UserArm64.h
index 53f7e50..d74983f 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserArm64.h
@@ -26,65 +26,11 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_ARM64_H
+#define _LIBUNWINDSTACK_USER_ARM64_H
namespace unwindstack {
-struct x86_user_regs {
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t eax;
- uint32_t xds;
- uint32_t xes;
- uint32_t xfs;
- uint32_t xgs;
- uint32_t orig_eax;
- uint32_t eip;
- uint32_t xcs;
- uint32_t eflags;
- uint32_t esp;
- uint32_t xss;
-};
-
-struct x86_64_user_regs {
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t r11;
- uint64_t r10;
- uint64_t r9;
- uint64_t r8;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rdx;
- uint64_t rsi;
- uint64_t rdi;
- uint64_t orig_rax;
- uint64_t rip;
- uint64_t cs;
- uint64_t eflags;
- uint64_t rsp;
- uint64_t ss;
- uint64_t fs_base;
- uint64_t gs_base;
- uint64_t ds;
- uint64_t es;
- uint64_t fs;
- uint64_t gs;
-};
-
-struct arm_user_regs {
- uint32_t regs[18];
-};
-
struct arm64_user_regs {
uint64_t regs[31];
uint64_t sp;
@@ -92,9 +38,6 @@
uint64_t pstate;
};
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_USER_H
+#endif // _LIBUNWINDSTACK_USER_ARM64_H
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/User.h b/libunwindstack/UserX86.h
similarity index 68%
copy from libunwindstack/User.h
copy to libunwindstack/UserX86.h
index 53f7e50..a040560 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserX86.h
@@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_X86_H
+#define _LIBUNWINDSTACK_USER_X86_H
namespace unwindstack {
@@ -51,50 +51,6 @@
uint32_t xss;
};
-struct x86_64_user_regs {
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t r11;
- uint64_t r10;
- uint64_t r9;
- uint64_t r8;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rdx;
- uint64_t rsi;
- uint64_t rdi;
- uint64_t orig_rax;
- uint64_t rip;
- uint64_t cs;
- uint64_t eflags;
- uint64_t rsp;
- uint64_t ss;
- uint64_t fs_base;
- uint64_t gs_base;
- uint64_t ds;
- uint64_t es;
- uint64_t fs;
- uint64_t gs;
-};
-
-struct arm_user_regs {
- uint32_t regs[18];
-};
-
-struct arm64_user_regs {
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_USER_H
+#endif // _LIBUNWINDSTACK_USER_X86_H
diff --git a/libunwindstack/User.h b/libunwindstack/UserX86_64.h
similarity index 74%
rename from libunwindstack/User.h
rename to libunwindstack/UserX86_64.h
index 53f7e50..b80d201 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/UserX86_64.h
@@ -26,31 +26,11 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBUNWINDSTACK_USER_H
-#define _LIBUNWINDSTACK_USER_H
+#ifndef _LIBUNWINDSTACK_USER_X86_64_H
+#define _LIBUNWINDSTACK_USER_X86_64_H
namespace unwindstack {
-struct x86_user_regs {
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t eax;
- uint32_t xds;
- uint32_t xes;
- uint32_t xfs;
- uint32_t xgs;
- uint32_t orig_eax;
- uint32_t eip;
- uint32_t xcs;
- uint32_t eflags;
- uint32_t esp;
- uint32_t xss;
-};
-
struct x86_64_user_regs {
uint64_t r15;
uint64_t r14;
@@ -81,20 +61,6 @@
uint64_t gs;
};
-struct arm_user_regs {
- uint32_t regs[18];
-};
-
-struct arm64_user_regs {
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
-};
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
-
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_USER_H
+#endif // _LIBUNWINDSTACK_USER_X86_64_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index d9ea9c4..a85e5f4 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -36,6 +36,16 @@
struct MapInfo;
class Regs;
+enum ArchEnum : uint8_t {
+ ARCH_UNKNOWN = 0,
+ ARCH_ARM,
+ ARCH_ARM64,
+ ARCH_X86,
+ ARCH_X86_64,
+ ARCH_MIPS,
+ ARCH_MIPS64,
+};
+
class Elf {
public:
Elf(Memory* memory) : memory_(memory) {}
@@ -64,6 +74,8 @@
uint8_t class_type() { return class_type_; }
+ ArchEnum arch() { return arch_; }
+
Memory* memory() { return memory_.get(); }
ElfInterface* interface() { return interface_.get(); }
@@ -83,6 +95,7 @@
std::unique_ptr<Memory> memory_;
uint32_t machine_type_;
uint8_t class_type_;
+ ArchEnum arch_;
// Protect calls that can modify internal state of the interface object.
std::mutex lock_;
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 8163152..94ceaab 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <atomic>
#include <memory>
#include <string>
#include <vector>
@@ -99,7 +100,7 @@
class MemoryRemote : public Memory {
public:
- MemoryRemote(pid_t pid) : pid_(pid) {}
+ MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {}
virtual ~MemoryRemote() = default;
size_t Read(uint64_t addr, void* dst, size_t size) override;
@@ -108,6 +109,7 @@
private:
pid_t pid_;
+ std::atomic_uintptr_t read_redirect_func_;
};
class MemoryLocal : public Memory {
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 6576e4c..613682f 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -27,10 +27,8 @@
// Forward declarations.
class Elf;
-struct MapInfo;
+enum ArchEnum : uint8_t;
class Memory;
-struct x86_ucontext_t;
-struct x86_64_ucontext_t;
class Regs {
public:
@@ -51,7 +49,9 @@
: total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {}
virtual ~Regs() = default;
- virtual uint32_t MachineType() = 0;
+ virtual ArchEnum Arch() = 0;
+
+ virtual bool Format32Bit() = 0;
virtual void* RawData() = 0;
virtual uint64_t pc() = 0;
@@ -70,9 +70,9 @@
uint16_t sp_reg() { return sp_reg_; }
uint16_t total_regs() { return total_regs_; }
- static uint32_t CurrentMachineType();
+ static ArchEnum CurrentArch();
static Regs* RemoteGet(pid_t pid);
- static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext);
+ static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext);
static Regs* CreateFromLocal();
protected:
@@ -94,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(); }
@@ -110,82 +112,6 @@
std::vector<AddressType> regs_;
};
-class RegsArm : public RegsImpl<uint32_t> {
- public:
- RegsArm();
- virtual ~RegsArm() = default;
-
- virtual uint32_t MachineType() 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;
-};
-
-class RegsArm64 : public RegsImpl<uint64_t> {
- public:
- RegsArm64();
- virtual ~RegsArm64() = default;
-
- virtual uint32_t MachineType() 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;
-};
-
-class RegsX86 : public RegsImpl<uint32_t> {
- public:
- RegsX86();
- virtual ~RegsX86() = default;
-
- virtual uint32_t MachineType() 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;
-
- void SetFromUcontext(x86_ucontext_t* ucontext);
-
- virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
-class RegsX86_64 : public RegsImpl<uint64_t> {
- public:
- RegsX86_64();
- virtual ~RegsX86_64() = default;
-
- virtual uint32_t MachineType() 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;
-
- void SetFromUcontext(x86_64_ucontext_t* ucontext);
-
- virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-};
-
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
new file mode 100644
index 0000000..b5d344b
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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_ARM_H
+#define _LIBUNWINDSTACK_REGS_ARM_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsArm : public RegsImpl<uint32_t> {
+ public:
+ RegsArm();
+ virtual ~RegsArm() = 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_ARM_H
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
new file mode 100644
index 0000000..30e626c
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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_ARM64_H
+#define _LIBUNWINDSTACK_REGS_ARM64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+
+class RegsArm64 : public RegsImpl<uint64_t> {
+ public:
+ RegsArm64();
+ virtual ~RegsArm64() = 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_ARM64_H
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/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
new file mode 100644
index 0000000..a695bbf
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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_X86_H
+#define _LIBUNWINDSTACK_REGS_X86_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+struct x86_ucontext_t;
+
+class RegsX86 : public RegsImpl<uint32_t> {
+ public:
+ RegsX86();
+ virtual ~RegsX86() = 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;
+
+ void SetFromUcontext(x86_ucontext_t* ucontext);
+
+ 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_X86_H
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
new file mode 100644
index 0000000..23a3f20
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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_X86_64_H
+#define _LIBUNWINDSTACK_REGS_X86_64_H
+
+#include <stdint.h>
+
+#include <functional>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class Memory;
+struct x86_64_ucontext_t;
+
+class RegsX86_64 : public RegsImpl<uint64_t> {
+ public:
+ RegsX86_64();
+ virtual ~RegsX86_64() = 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;
+
+ void SetFromUcontext(x86_64_ucontext_t* ucontext);
+
+ 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_X86_64_H
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index 94cb493..8d6d00d 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -24,7 +24,7 @@
#include <gtest/gtest.h>
#include <unwindstack/Log.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
#include "ArmExidx.h"
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 4b621c9..5f7cf60 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,10 +20,10 @@
#include <vector>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
#include "ElfInterfaceArm.h"
-#include "Machine.h"
+#include "MachineArm.h"
#include "ElfFake.h"
#include "MemoryFake.h"
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index afd113d..7491d40 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -25,6 +25,7 @@
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
+#include <unwindstack/RegsArm.h>
#include "ElfFake.h"
#include "ElfTestUtils.h"
@@ -144,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());
}
@@ -157,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());
}
@@ -173,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_);
@@ -209,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/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 8aa8605..f5492a2 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -225,7 +225,7 @@
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
- size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+ size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
// Some read methods can read PROT_NONE maps, allow that.
ASSERT_LE(page_size, read_size);
for (size_t i = 0; i < read_size; ++i) {
@@ -260,7 +260,7 @@
MemoryRemote remote(pid);
std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
- size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+ size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
ASSERT_EQ(page_size, read_size);
for (size_t i = 0; i < read_size; ++i) {
ASSERT_EQ(0xFF, dst[i]);
@@ -270,4 +270,55 @@
}
}
+// Verify that the memory remote object chooses a memory read function
+// properly. Either process_vm_readv or ptrace.
+TEST_F(MemoryRemoteTest, read_choose_correctly) {
+ size_t page_size = getpagesize();
+ void* mapping =
+ mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ASSERT_NE(MAP_FAILED, mapping);
+ memset(mapping, 0xFC, 2 * page_size);
+ ASSERT_EQ(0, mprotect(static_cast<char*>(mapping), page_size, PROT_NONE));
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ while (true)
+ ;
+ exit(1);
+ }
+ ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_EQ(0, munmap(mapping, 2 * page_size));
+
+ ASSERT_TRUE(Attach(pid));
+
+ // We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
+ // Read from the PROT_NONE area first to force the choice of ptrace.
+ MemoryRemote remote_ptrace(pid);
+ uint32_t value;
+ size_t bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+ bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+ bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+
+ // Now verify that choosing process_vm_readv results in failing reads of
+ // the PROT_NONE part of the map. Read from a valid map first which
+ // should prefer process_vm_readv, and keep that as the read function.
+ MemoryRemote remote_readv(pid);
+ bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+ bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
+ ASSERT_EQ(0U, bytes);
+ bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
+ ASSERT_EQ(sizeof(value), bytes);
+ ASSERT_EQ(0xfcfcfcfcU, value);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index fedaf87..b81b2ca 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -19,6 +19,7 @@
#include <stdint.h>
+#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -30,7 +31,7 @@
: Regs(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
virtual ~RegsFake() = default;
- uint32_t MachineType() override { return fake_type_; }
+ ArchEnum Arch() override { return fake_arch_; }
void* RawData() override { return nullptr; }
uint64_t pc() override { return fake_pc_; }
uint64_t sp() override { return fake_sp_; }
@@ -44,20 +45,22 @@
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; }
void SetFromRaw() override {}
- void FakeSetMachineType(uint32_t type) { fake_type_ = type; }
+ void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
void FakeSetPc(uint64_t pc) { fake_pc_ = pc; }
void FakeSetSp(uint64_t sp) { fake_sp_ = sp; }
void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; }
void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; }
private:
- uint32_t fake_type_ = 0;
+ ArchEnum fake_arch_ = ARCH_UNKNOWN;
uint64_t fake_pc_ = 0;
uint64_t fake_sp_ = 0;
bool fake_return_address_valid_ = false;
@@ -71,7 +74,7 @@
: RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
virtual ~RegsImplFake() = default;
- uint32_t MachineType() override { return 0; }
+ ArchEnum Arch() override { return ARCH_UNKNOWN; }
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index c8d1d98..8b5b31f 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -25,9 +25,19 @@
#include <unwindstack/Elf.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/MapInfo.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 "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
+#include "MachineX86.h"
+#include "MachineX86_64.h"
+#include "MachineMips.h"
+#include "MachineMips64.h"
namespace unwindstack {
@@ -146,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 85192d5..ef9e61c 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -19,9 +19,19 @@
#include <gtest/gtest.h>
#include <unwindstack/Elf.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 "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
+#include "MachineX86.h"
+#include "MachineX86_64.h"
+#include "MachineMips.h"
+#include "MachineMips64.h"
#include "MemoryFake.h"
@@ -198,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 3320f77..3f84890 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -21,7 +21,12 @@
#include <unwindstack/Elf.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/MapInfo.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 "ElfFake.h"
#include "MemoryFake.h"
@@ -109,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) {
@@ -151,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;
@@ -170,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) {
@@ -212,4 +251,44 @@
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());
+
+ RegsArm64 arm64_regs;
+ EXPECT_EQ(ARCH_ARM64, arm64_regs.Arch());
+
+ RegsX86 x86_regs;
+ EXPECT_EQ(ARCH_X86, x86_regs.Arch());
+
+ 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/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index d24abe4..962f744 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -27,10 +27,12 @@
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
#include <unwindstack/Unwinder.h>
-#include "Machine.h"
+#include "MachineArm.h"
+#include "MachineArm64.h"
#include "ElfTestUtils.h"
@@ -73,7 +75,7 @@
BufferMaps maps(buffer.data());
ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(static_cast<uint32_t>(EM_ARM), regs.MachineType());
+ ASSERT_EQ(ARCH_ARM, regs.Arch());
std::shared_ptr<Memory> process_memory(memory);
@@ -125,7 +127,7 @@
BufferMaps maps(buffer.data());
ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
+ ASSERT_EQ(ARCH_ARM64, regs.Arch());
std::shared_ptr<Memory> process_memory(memory);
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index b372fd0..242cc6a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -250,7 +250,7 @@
LocalMaps maps;
ASSERT_TRUE(maps.Parse());
- std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext));
+ std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 098459e..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,36 +72,38 @@
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 {
ElfInterfaceFake::FakeClear();
- regs_.FakeSetMachineType(EM_ARM);
+ regs_.FakeSetArch(ARCH_ARM);
regs_.FakeSetReturnAddressValid(false);
}
@@ -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_, ®s_, 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_.FakeSetMachineType(EM_ARM);
- EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
- regs_.FakeSetMachineType(EM_386);
- 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_.FakeSetMachineType(EM_AARCH64);
- EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0));
- regs_.FakeSetMachineType(EM_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 f2530d7..81bedb7 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -63,19 +63,25 @@
}
printf("ABI: ");
- switch (regs->MachineType()) {
- case EM_ARM:
+ switch (regs->Arch()) {
+ case unwindstack::ARCH_ARM:
printf("arm");
break;
- case EM_386:
+ case unwindstack::ARCH_X86:
printf("x86");
break;
- case EM_AARCH64:
+ case unwindstack::ARCH_ARM64:
printf("arm64");
break;
- case EM_X86_64:
+ 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/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 44b878d..4d286bf 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -324,29 +324,39 @@
struct usb_device *usb_device_open(const char *dev_name)
{
- int fd, did_retry = 0, writeable = 1;
-
+ int fd, attempts, writeable = 1;
+ const int SLEEP_BETWEEN_ATTEMPTS_US = 100000; /* 100 ms */
+ const int64_t MAX_ATTEMPTS = 10; /* 1s */
D("usb_device_open %s\n", dev_name);
-retry:
- fd = open(dev_name, O_RDWR);
- if (fd < 0) {
- /* if we fail, see if have read-only access */
- fd = open(dev_name, O_RDONLY);
- D("usb_device_open open returned %d errno %d\n", fd, errno);
- if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
- /* work around race condition between inotify and permissions management */
- sleep(1);
- did_retry = 1;
- goto retry;
+ /* Hack around waiting for permissions to be set on the USB device node.
+ * Should really be a timeout instead of attempt count, and should REALLY
+ * be triggered by the perm change via inotify rather than polling.
+ */
+ for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
+ if (access(dev_name, R_OK | W_OK) == 0) {
+ writeable = 1;
+ break;
+ } else {
+ if (access(dev_name, R_OK) == 0) {
+ /* double check that write permission didn't just come along too! */
+ writeable = (access(dev_name, R_OK | W_OK) == 0);
+ break;
+ }
}
-
- if (fd < 0)
- return NULL;
- writeable = 0;
- D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
+ /* not writeable or readable - sleep and try again. */
+ D("usb_device_open no access sleeping\n");
+ usleep(SLEEP_BETWEEN_ATTEMPTS_US);
}
+ if (writeable) {
+ fd = open(dev_name, O_RDWR);
+ } else {
+ fd = open(dev_name, O_RDONLY);
+ }
+ D("usb_device_open open returned %d writeable %d errno %d\n", fd, writeable, errno);
+ if (fd < 0) return NULL;
+
struct usb_device* result = usb_device_new(dev_name, fd);
if (result)
result->writeable = writeable;
diff --git a/libutils/OWNERS b/libutils/OWNERS
new file mode 100644
index 0000000..40164aa
--- /dev/null
+++ b/libutils/OWNERS
@@ -0,0 +1 @@
+smoreland@google.com
diff --git a/libvndksupport/OWNERS b/libvndksupport/OWNERS
new file mode 100644
index 0000000..c7efc16
--- /dev/null
+++ b/libvndksupport/OWNERS
@@ -0,0 +1,2 @@
+jiyong@google.com
+smoreland@google.com
diff --git a/libziparchive/OWNERS b/libziparchive/OWNERS
new file mode 100644
index 0000000..fcc567a
--- /dev/null
+++ b/libziparchive/OWNERS
@@ -0,0 +1 @@
+narayan@google.com
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/logcat/OWNERS b/logcat/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/logcat/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/logd/OWNERS b/logd/OWNERS
new file mode 100644
index 0000000..2394e32
--- /dev/null
+++ b/logd/OWNERS
@@ -0,0 +1,2 @@
+cferris@google.com
+tomcherry@google.com
diff --git a/logwrapper/OWNERS b/logwrapper/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/logwrapper/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/qemu_pipe/OWNERS b/qemu_pipe/OWNERS
new file mode 100644
index 0000000..dbc1bf6
--- /dev/null
+++ b/qemu_pipe/OWNERS
@@ -0,0 +1 @@
+bohu@google.com
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index aa970d6..e9bd8d4 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)
@@ -142,6 +78,7 @@
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
sbin dev proc sys system data oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
@@ -206,18 +143,20 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-vndk_lib_md5 := $(word 1, $(shell echo $(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) | $(MD5SUM)))
-vndk_lib_dep := $(intermediates)/$(vndk_lib_md5).dep
-$(vndk_lib_dep):
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-llndk_libraries := $(subst $(space),:,$(addsuffix .so,$(LLNDK_LIBRARIES)))
+llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
-vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_SAMEPROCESS_LIBRARIES)))
+private_llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
+$(filter $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
-vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_CORE_LIBRARIES)))
+vndk_sameprocess_libraries := $(call normalize-path-list,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_SAMEPROCESS_LIBRARIES))))
-sanitizer_runtime_libraries := $(subst $(space),:,$(addsuffix .so,\
+vndk_core_libraries := $(call normalize-path-list,$(addsuffix .so,\
+$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES))))
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
$(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
$(UBSAN_RUNTIME_LIBRARY) \
$(TSAN_RUNTIME_LIBRARY) \
@@ -226,20 +165,20 @@
$(2ND_TSAN_RUNTIME_LIBRARY)))
$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(llndk_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_PRIVATE_LLNDK_LIBRARIES := $(private_llndk_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(vndk_sameprocess_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_PRIVATE_LIBRARIES := $(llndk_private_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(vndk_core_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in $(vndk_lib_dep)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
$(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
+ $(hide) sed -i -e 's?%PRIVATE_LLNDK_LIBRARIES%?$(PRIVATE_PRIVATE_LLNDK_LIBRARIES)?g' $@
$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $@
$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $@
$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
-vndk_lib_md5 :=
-vndk_lib_dep :=
llndk_libraries :=
vndk_sameprocess_libraries :=
vndk_core_libraries :=
@@ -266,13 +205,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-llndk_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-llndk_dep = $(intermediates)/$(llndk_md5).dep
-$(llndk_dep):
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(LLNDK_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(llndk_dep)
+$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
$(hide) echo -n > $@
@@ -287,13 +221,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-vndksp_md5 = $(word 1, $(shell echo $(LLNDK_LIBRARIES) | $(MD5SUM)))
-vndksp_dep = $(intermediates)/$(vndksp_md5).dep
-$(vndksp_dep):
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
-
$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(VNDK_SAMEPROCESS_LIBRARIES)
-$(LOCAL_BUILT_MODULE): $(vndksp_dep)
+$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
$(hide) echo -n > $@
diff --git a/rootdir/OWNERS b/rootdir/OWNERS
new file mode 100644
index 0000000..f335715
--- /dev/null
+++ b/rootdir/OWNERS
@@ -0,0 +1,3 @@
+jiyong@google.com
+smoreland@google.com
+tomcherry@google.com
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 9c108e2..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
@@ -51,7 +51,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}
@@ -79,14 +79,17 @@
###############################################################################
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
namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
###############################################################################
@@ -96,10 +99,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
@@ -120,28 +123,31 @@
###############################################################################
# "default" namespace
#
-# Vendor-side code runs in this namespace.
+# This is the default linker namespace for a vendor process (a process started
+# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
+# are loaded directly into this namespace. However, other libs under the system
+# partition (VNDK and LLNDK libraries) are not loaded here but from the
+# separate namespace 'system'. The delegation to the system namespace is done
+# via the 'namespace.default.link.system.shared_libs' property below.
###############################################################################
namespace.default.isolated = true
namespace.default.visible = true
-namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}
+namespace.default.permitted.paths = /vendor
-namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
-namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk${VNDK_VER}:/vendor/${LIB}/vndk${VNDK_VER}:/data/asan/vendor/${LIB}/vndk-sp${VNDK_VER}:/vendor/${LIB}/vndk-sp${VNDK_VER}:namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor
namespace.default.links = system
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:%VNDK_SAMEPROCESS_LIBRARIES%:%VNDK_CORE_LIBRARIES%
###############################################################################
# "system" namespace
#
-# This is for vendor process to use LL-NDK in system partition.
+# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
+# a vendor process.
###############################################################################
namespace.system.isolated = false
-namespace.system.search.paths = /system/${LIB}
-namespace.system.permitted.paths = /system/${LIB}
+namespace.system.search.paths = /system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}
-namespace.system.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
-namespace.system.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.system.asan.search.paths = /data/asan/system/${LIB}/vndk-sp${VNDK_VER}:/system/${LIB}/vndk-sp${VNDK_VER}:/data/asan/system/${LIB}/vndk${VNDK_VER}:/system/${LIB}/vndk${VNDK_VER}:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 51a8d2b..5fa77d8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -48,8 +48,10 @@
copy /proc/cmdline /dev/urandom
copy /default.prop /dev/urandom
- # Backward compatibility.
+ symlink /system/bin /bin
symlink /system/etc /etc
+
+ # Backward compatibility.
symlink /sys/kernel/debug /d
# Link /vendor to /system/vendor for devices without a vendor partition.
diff --git a/sdcard/OWNERS b/sdcard/OWNERS
new file mode 100644
index 0000000..199a0f8
--- /dev/null
+++ b/sdcard/OWNERS
@@ -0,0 +1 @@
+drosen@google.com
diff --git a/shell_and_utilities/OWNERS b/shell_and_utilities/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/shell_and_utilities/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/storaged/OWNERS b/storaged/OWNERS
new file mode 100644
index 0000000..7445270
--- /dev/null
+++ b/storaged/OWNERS
@@ -0,0 +1 @@
+jinqian@google.com
diff --git a/toolbox/OWNERS b/toolbox/OWNERS
new file mode 100644
index 0000000..682a067
--- /dev/null
+++ b/toolbox/OWNERS
@@ -0,0 +1 @@
+enh@google.com
diff --git a/trusty/OWNERS b/trusty/OWNERS
new file mode 100644
index 0000000..25291fd
--- /dev/null
+++ b/trusty/OWNERS
@@ -0,0 +1 @@
+bohr@google.com