Merge "Atom: BootSequenceReported"
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index d8d7e4a..1ec5451 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -282,6 +282,10 @@
{"warm_reset_0x80", 141},
{"pon_reason_0xb0", 142},
{"reboot_download", 143},
+ {"reboot_recovery_mode", 144},
+ {"oem_sdi_err_fatal", 145},
+ {"pmic_watchdog", 146},
+ {"software_master", 147},
};
// Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index fb8a205..5323524 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -114,6 +114,7 @@
"libbacktrace",
"libunwind",
"libunwindstack",
+ "libdexfile",
"liblzma",
"libcutils",
],
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f584021..413d11e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1039,9 +1039,7 @@
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
{"rm", {1, 1, {true, do_rm}}},
{"rmdir", {1, 1, {true, do_rmdir}}},
- // TODO: setprop should be run in the subcontext, but property service needs to be split
- // out from init before that is possible.
- {"setprop", {2, 2, {false, do_setprop}}},
+ {"setprop", {2, 2, {true, do_setprop}}},
{"setrlimit", {3, 3, {false, do_setrlimit}}},
{"start", {1, 1, {false, do_start}}},
{"stop", {1, 1, {false, do_stop}}},
diff --git a/init/init.cpp b/init/init.cpp
index 95f272b..79623c3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -110,12 +110,15 @@
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
- if (!parser.ParseConfig("/vendor/etc/init")) {
- late_import_paths.emplace_back("/vendor/etc/init");
+ if (!parser.ParseConfig("/product/etc/init")) {
+ late_import_paths.emplace_back("/product/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
+ if (!parser.ParseConfig("/vendor/etc/init")) {
+ late_import_paths.emplace_back("/vendor/etc/init");
+ }
} else {
parser.ParseConfig(bootscript);
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 79f7f25..ecd5baa 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -84,6 +84,10 @@
static PropertyInfoAreaFile property_info_area;
+uint32_t InitPropertySet(const std::string& name, const std::string& value);
+
+uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
+
void CreateSerializedPropertyInfo();
void property_init() {
@@ -97,7 +101,7 @@
}
}
static bool CheckMacPerms(const std::string& name, const char* target_context,
- const char* source_context, struct ucred* cr) {
+ const char* source_context, const ucred& cr) {
if (!target_context || !source_context) {
return false;
}
@@ -105,7 +109,7 @@
property_audit_data audit_data;
audit_data.name = name.c_str();
- audit_data.cr = cr;
+ audit_data.cr = &cr;
bool has_access = (selinux_check_access(source_context, target_context, "property_service",
"set", &audit_data) == 0);
@@ -257,7 +261,7 @@
return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
}
-uint32_t property_set(const std::string& name, const std::string& value) {
+uint32_t PropertySet(const std::string& name, const std::string& value) {
if (name == "selinux.restorecon_recursive") {
return PropertySetAsync(name, value, RestoreconRecursiveAsync);
}
@@ -265,206 +269,208 @@
return PropertySetImpl(name, value);
}
+uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+ if (StartsWith(name, "ctl.")) {
+ LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly";
+ return PROP_ERROR_INVALID_NAME;
+ }
+
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type);
+
+ if (type == nullptr || !CheckType(type, value)) {
+ LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '"
+ << (type ?: "(null)") << "' value: '" << value << "'";
+ return PROP_ERROR_INVALID_VALUE;
+ }
+
+ return PropertySet(name, value);
+}
+
class SocketConnection {
- public:
- SocketConnection(int socket, const struct ucred& cred)
- : socket_(socket), cred_(cred) {}
+ public:
+ SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
- ~SocketConnection() {
- close(socket_);
- }
+ ~SocketConnection() { close(socket_); }
- bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
- return RecvFully(value, sizeof(*value), timeout_ms);
- }
-
- bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
- return RecvFully(chars, size, timeout_ms);
- }
-
- bool RecvString(std::string* value, uint32_t* timeout_ms) {
- uint32_t len = 0;
- if (!RecvUint32(&len, timeout_ms)) {
- return false;
+ bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
+ return RecvFully(value, sizeof(*value), timeout_ms);
}
- if (len == 0) {
- *value = "";
- return true;
+ bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
+ return RecvFully(chars, size, timeout_ms);
}
- // http://b/35166374: don't allow init to make arbitrarily large allocations.
- if (len > 0xffff) {
- LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
- errno = ENOMEM;
- return false;
- }
-
- std::vector<char> chars(len);
- if (!RecvChars(&chars[0], len, timeout_ms)) {
- return false;
- }
-
- *value = std::string(&chars[0], len);
- return true;
- }
-
- bool SendUint32(uint32_t value) {
- int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
- return result == sizeof(value);
- }
-
- int socket() {
- return socket_;
- }
-
- const struct ucred& cred() {
- return cred_;
- }
-
- private:
- bool PollIn(uint32_t* timeout_ms) {
- struct pollfd ufds[1];
- ufds[0].fd = socket_;
- ufds[0].events = POLLIN;
- ufds[0].revents = 0;
- while (*timeout_ms > 0) {
- auto start_time = std::chrono::steady_clock::now();
- int nr = poll(ufds, 1, *timeout_ms);
- auto now = std::chrono::steady_clock::now();
- auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
- uint64_t millis = time_elapsed.count();
- *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
-
- if (nr > 0) {
- return true;
- }
-
- if (nr == 0) {
- // Timeout
- break;
- }
-
- if (nr < 0 && errno != EINTR) {
- PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message";
- return false;
- } else { // errno == EINTR
- // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
- // to avoid slowing init down by causing EINTR with under millisecond timeout.
- if (*timeout_ms > 0) {
- --(*timeout_ms);
+ bool RecvString(std::string* value, uint32_t* timeout_ms) {
+ uint32_t len = 0;
+ if (!RecvUint32(&len, timeout_ms)) {
+ return false;
}
- }
+
+ if (len == 0) {
+ *value = "";
+ return true;
+ }
+
+ // http://b/35166374: don't allow init to make arbitrarily large allocations.
+ if (len > 0xffff) {
+ LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
+ errno = ENOMEM;
+ return false;
+ }
+
+ std::vector<char> chars(len);
+ if (!RecvChars(&chars[0], len, timeout_ms)) {
+ return false;
+ }
+
+ *value = std::string(&chars[0], len);
+ return true;
}
- LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message.";
- return false;
- }
-
- bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
- size_t bytes_left = size;
- char* data = static_cast<char*>(data_ptr);
- while (*timeout_ms > 0 && bytes_left > 0) {
- if (!PollIn(timeout_ms)) {
- return false;
- }
-
- int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
- if (result <= 0) {
- return false;
- }
-
- bytes_left -= result;
- data += result;
+ bool SendUint32(uint32_t value) {
+ int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
+ return result == sizeof(value);
}
- return bytes_left == 0;
- }
+ int socket() { return socket_; }
- int socket_;
- struct ucred cred_;
+ const ucred& cred() { return cred_; }
- DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
+ std::string source_context() const {
+ char* source_context = nullptr;
+ getpeercon(socket_, &source_context);
+ std::string result = source_context;
+ freecon(source_context);
+ return result;
+ }
+
+ private:
+ bool PollIn(uint32_t* timeout_ms) {
+ struct pollfd ufds[1];
+ ufds[0].fd = socket_;
+ ufds[0].events = POLLIN;
+ ufds[0].revents = 0;
+ while (*timeout_ms > 0) {
+ auto start_time = std::chrono::steady_clock::now();
+ int nr = poll(ufds, 1, *timeout_ms);
+ auto now = std::chrono::steady_clock::now();
+ auto time_elapsed =
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ uint64_t millis = time_elapsed.count();
+ *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
+
+ if (nr > 0) {
+ return true;
+ }
+
+ if (nr == 0) {
+ // Timeout
+ break;
+ }
+
+ if (nr < 0 && errno != EINTR) {
+ PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid
+ << " to send property message";
+ return false;
+ } else { // errno == EINTR
+ // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
+ // to avoid slowing init down by causing EINTR with under millisecond timeout.
+ if (*timeout_ms > 0) {
+ --(*timeout_ms);
+ }
+ }
+ }
+
+ LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid
+ << " to send property message.";
+ return false;
+ }
+
+ bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
+ size_t bytes_left = size;
+ char* data = static_cast<char*>(data_ptr);
+ while (*timeout_ms > 0 && bytes_left > 0) {
+ if (!PollIn(timeout_ms)) {
+ return false;
+ }
+
+ int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
+ if (result <= 0) {
+ return false;
+ }
+
+ bytes_left -= result;
+ data += result;
+ }
+
+ return bytes_left == 0;
+ }
+
+ int socket_;
+ ucred cred_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
};
-static void handle_property_set(SocketConnection& socket,
- const std::string& name,
- const std::string& value,
- bool legacy_protocol) {
- const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
- if (!is_legal_property_name(name)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
- socket.SendUint32(PROP_ERROR_INVALID_NAME);
- return;
- }
+// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
+uint32_t HandlePropertySet(const std::string& name, const std::string& value,
+ const std::string& source_context, const ucred& cr) {
+ if (!is_legal_property_name(name)) {
+ LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\"";
+ return PROP_ERROR_INVALID_NAME;
+ }
- struct ucred cr = socket.cred();
- char* source_ctx = nullptr;
- getpeercon(socket.socket(), &source_ctx);
- std::string source_context = source_ctx;
- freecon(source_ctx);
+ if (StartsWith(name, "ctl.")) {
+ // ctl. properties have their name ctl.<action> and their value is the name of the service
+ // to apply that action to. Permissions for these actions are based on the service, so we
+ // must create a fake name of ctl.<service> to check permissions.
+ auto control_string = "ctl." + value;
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
+ if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
+ LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl ["
+ << value << "]"
+ << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
+ return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+ }
- if (StartsWith(name, "ctl.")) {
- // ctl. properties have their name ctl.<action> and their value is the name of the service to
- // apply that action to. Permissions for these actions are based on the service, so we must
- // create a fake name of ctl.<service> to check permissions.
- auto control_string = "ctl." + value;
- const char* target_context = nullptr;
- const char* type = nullptr;
- property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
- if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
- << " service ctl [" << value << "]"
- << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
- }
- return;
- }
+ handle_control_message(name.c_str() + 4, value.c_str());
+ return PROP_SUCCESS;
+ }
- handle_control_message(name.c_str() + 4, value.c_str());
- if (!legacy_protocol) {
- socket.SendUint32(PROP_SUCCESS);
- }
- } else {
- const char* target_context = nullptr;
- const char* type = nullptr;
- property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
- if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid
- << " name:" << name;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
- }
- return;
- }
- if (type == nullptr || !CheckType(type, value)) {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
- << (type ?: "(null)") << "' value: '" << value << "'";
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_INVALID_VALUE);
- }
- return;
- }
- // sys.powerctl is a special property that is used to make the device reboot. We want to log
- // any process that sets this property to be able to accurately blame the cause of a shutdown.
- if (name == "sys.powerctl") {
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
- std::string process_cmdline;
- std::string process_log_string;
- if (ReadFileToString(cmdline_path, &process_cmdline)) {
- // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
- process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
- }
- LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
- << process_log_string;
- }
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
- uint32_t result = property_set(name, value);
- if (!legacy_protocol) {
- socket.SendUint32(result);
- }
- }
+ if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
+ LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name;
+ return PROP_ERROR_PERMISSION_DENIED;
+ }
+
+ if (type == nullptr || !CheckType(type, value)) {
+ LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '"
+ << (type ?: "(null)") << "' value: '" << value << "'";
+ return PROP_ERROR_INVALID_VALUE;
+ }
+
+ // sys.powerctl is a special property that is used to make the device reboot. We want to log
+ // any process that sets this property to be able to accurately blame the cause of a shutdown.
+ if (name == "sys.powerctl") {
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+ std::string process_cmdline;
+ std::string process_log_string;
+ if (ReadFileToString(cmdline_path, &process_cmdline)) {
+ // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
+ // path.
+ process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+ }
+ LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+ << process_log_string;
+ }
+
+ return PropertySet(name, value);
}
static void handle_property_set_fd() {
@@ -475,7 +481,7 @@
return;
}
- struct ucred cr;
+ ucred cr;
socklen_t cr_size = sizeof(cr);
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
@@ -507,7 +513,7 @@
prop_name[PROP_NAME_MAX-1] = 0;
prop_value[PROP_VALUE_MAX-1] = 0;
- handle_property_set(socket, prop_value, prop_value, true);
+ HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred());
break;
}
@@ -521,7 +527,8 @@
return;
}
- handle_property_set(socket, name, value, false);
+ auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred());
+ socket.SendUint32(result);
break;
}
@@ -634,6 +641,7 @@
load_properties_from_file("/default.prop", NULL);
}
}
+ load_properties_from_file("/product/build.prop", NULL);
load_properties_from_file("/odm/default.prop", NULL);
load_properties_from_file("/vendor/default.prop", NULL);
@@ -754,12 +762,20 @@
// Don't check for failure here, so we always have a sane list of properties.
// E.g. In case of recovery, the vendor partition will not have mounted and we
// still need the system / platform properties to function.
- LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts", &property_infos);
+ if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
+ &property_infos)) {
+ // Fallback to nonplat_* if vendor_* doesn't exist.
+ LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
+ &property_infos);
+ }
} else {
if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
return;
}
- LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+ if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
+ // Fallback to nonplat_* if vendor_* doesn't exist.
+ LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+ }
}
auto serialized_contexts = std::string();
diff --git a/init/property_service.h b/init/property_service.h
index a55e79c..8161b40 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -25,10 +25,15 @@
namespace init {
struct property_audit_data {
- ucred *cr;
+ const ucred* cr;
const char* name;
};
+extern uint32_t (*property_set)(const std::string& name, const std::string& value);
+
+uint32_t HandlePropertySet(const std::string& name, const std::string& value,
+ const std::string& source_context, const ucred& cr);
+
extern bool PropertyChildReap(pid_t pid);
void property_init(void);
@@ -36,7 +41,6 @@
void load_persist_props(void);
void load_system_props(void);
void start_property_service(void);
-uint32_t property_set(const std::string& name, const std::string& value);
bool is_legal_property_name(const std::string& name);
} // namespace init
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 1febccd..6aba9c1 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -420,14 +420,19 @@
selinux_android_restorecon("/plat_file_contexts", 0);
selinux_android_restorecon("/nonplat_file_contexts", 0);
+ selinux_android_restorecon("/vendor_file_contexts", 0);
selinux_android_restorecon("/plat_property_contexts", 0);
selinux_android_restorecon("/nonplat_property_contexts", 0);
+ selinux_android_restorecon("/vendor_property_contexts", 0);
selinux_android_restorecon("/plat_seapp_contexts", 0);
selinux_android_restorecon("/nonplat_seapp_contexts", 0);
+ selinux_android_restorecon("/vendor_seapp_contexts", 0);
selinux_android_restorecon("/plat_service_contexts", 0);
selinux_android_restorecon("/nonplat_service_contexts", 0);
+ selinux_android_restorecon("/vendor_service_contexts", 0);
selinux_android_restorecon("/plat_hwservice_contexts", 0);
selinux_android_restorecon("/nonplat_hwservice_contexts", 0);
+ selinux_android_restorecon("/vendor_hwservice_contexts", 0);
selinux_android_restorecon("/sepolicy", 0);
selinux_android_restorecon("/vndservice_contexts", 0);
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index be754da..f3b643a 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -27,9 +27,13 @@
#include <selinux/android.h>
#include "action.h"
+#include "property_service.h"
#include "selinux.h"
#include "util.h"
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
using android::base::GetExecutablePath;
using android::base::Join;
using android::base::Socketpair;
@@ -75,6 +79,13 @@
return Success();
}
+std::vector<std::pair<std::string, std::string>> properties_to_set;
+
+uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
+ properties_to_set.emplace_back(name, value);
+ return PROP_SUCCESS;
+}
+
class SubcontextProcess {
public:
SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd)
@@ -108,6 +119,14 @@
result = RunBuiltinFunction(map_result->second, args, context_);
}
+ for (const auto& [name, value] : properties_to_set) {
+ auto property = reply->add_properties_to_set();
+ property->set_name(name);
+ property->set_value(value);
+ }
+
+ properties_to_set.clear();
+
if (result) {
reply->set_success(true);
} else {
@@ -186,6 +205,9 @@
auto init_fd = std::atoi(argv[3]);
SelabelInitialize();
+
+ property_set = SubcontextPropertySet;
+
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
subcontext_process.MainLoop();
return 0;
@@ -257,10 +279,6 @@
Restart();
return Error() << "Unable to parse message from subcontext";
}
- if (subcontext_reply.reply_case() == SubcontextReply::kFailure) {
- auto& failure = subcontext_reply.failure();
- return ResultError(failure.error_string(), failure.error_errno());
- }
return subcontext_reply;
}
@@ -275,6 +293,16 @@
return subcontext_reply.error();
}
+ for (const auto& property : subcontext_reply->properties_to_set()) {
+ ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
+ HandlePropertySet(property.name(), property.value(), context_, cr);
+ }
+
+ if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
+ auto& failure = subcontext_reply->failure();
+ return ResultError(failure.error_string(), failure.error_errno());
+ }
+
if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
return Error() << "Unexpected message type from subcontext: "
<< subcontext_reply->reply_case();
@@ -294,6 +322,11 @@
return subcontext_reply.error();
}
+ if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
+ auto& failure = subcontext_reply->failure();
+ return ResultError(failure.error_string(), failure.error_errno());
+ }
+
if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
return Error() << "Unexpected message type from subcontext: "
<< subcontext_reply->reply_case();
diff --git a/init/subcontext.proto b/init/subcontext.proto
index e68115e..c31f4fb 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,4 +38,10 @@
Failure failure = 2;
ExpandArgsReply expand_args_reply = 3;
}
+
+ message PropertyToSet {
+ optional string name = 1;
+ optional string value = 2;
+ }
+ repeated PropertyToSet properties_to_set = 4;
}
\ No newline at end of file
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index d9eed76..14ae445 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,6 +50,7 @@
"BacktracePtrace.cpp",
"thread_utils.c",
"ThreadEntry.cpp",
+ "UnwindDexFile.cpp",
"UnwindStack.cpp",
"UnwindStackMap.cpp",
]
@@ -92,13 +93,27 @@
"liblog",
"libunwind",
"libunwindstack",
+ "libdexfile",
],
static_libs: ["libcutils"],
+
+ // libdexfile will eventually properly export headers, for now
+ // include these directly.
+ include_dirs: [
+ "art/runtime",
+ ],
+
+ header_libs: [ "jni_headers", ],
},
android: {
static_libs: ["libasync_safe"],
},
+ vendor: {
+ cflags: ["-DNO_LIBDEXFILE"],
+ exclude_srcs: ["UnwindDexFile.cpp"],
+ exclude_shared_libs: ["libdexfile"],
+ },
},
whole_static_libs: ["libdemangle"],
}
@@ -113,39 +128,8 @@
cflags: ["-O0"],
srcs: ["backtrace_testlib.cpp"],
- target: {
- linux: {
- shared_libs: [
- "libunwind",
- "libunwindstack",
- ],
- },
- }
-}
-
-//-------------------------------------------------------------------------
-// The libbacktrace_offline static library.
-//-------------------------------------------------------------------------
-cc_library_static {
- name: "libbacktrace_offline",
- defaults: ["libbacktrace_common"],
- host_supported: true,
- srcs: ["BacktraceOffline.cpp"],
-
- cflags: [
- "-D__STDC_CONSTANT_MACROS",
- "-D__STDC_LIMIT_MACROS",
- "-D__STDC_FORMAT_MACROS",
- ],
-
- header_libs: ["llvm-headers"],
-
- // Use shared libraries so their headers get included during build.
- shared_libs = [
- "libbase",
- "libunwind",
- "libunwindstack",
- "libziparchive",
+ shared_libs: [
+ "libunwindstack",
],
}
@@ -161,6 +145,8 @@
"backtrace_test.cpp",
"GetPss.cpp",
"thread_utils.c",
+
+ "unwind_dex_test.cpp",
],
cflags: [
@@ -172,31 +158,15 @@
shared_libs: [
"libbacktrace_test",
"libbacktrace",
+ "libdexfile",
"libbase",
"libcutils",
"liblog",
- "libunwind",
"libunwindstack",
],
group_static_libs: true,
- // Statically link LLVMlibraries to remove dependency on llvm shared library.
- static_libs = [
- "libbacktrace_offline",
- "libLLVMObject",
- "libLLVMBitReader",
- "libLLVMMC",
- "libLLVMMCParser",
- "libLLVMCore",
- "libLLVMSupport",
-
- "libziparchive",
- "libz",
- ],
-
- header_libs: ["llvm-headers"],
-
target: {
android: {
cflags: ["-DENABLE_PSS_TESTS"],
@@ -205,13 +175,16 @@
],
},
linux_glibc: {
- host_ldlibs: [
- "-lncurses",
- ],
static_libs: ["libutils"],
},
},
+ // libdexfile will eventually properly export headers, for now
+ // include these directly.
+ include_dirs: [
+ "art/runtime",
+ ],
+
data: [
"testdata/arm/*",
"testdata/arm64/*",
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 1195e5f..dec241c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -168,5 +168,9 @@
return "Failed to find a function in debug sections";
case BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED:
return "Failed to execute dwarf instructions in debug sections";
+ case BACKTRACE_UNWIND_ERROR_UNWIND_INFO:
+ return "Failed to unwind due to invalid unwind information";
+ case BACKTRACE_UNWIND_ERROR_REPEATED_FRAME:
+ return "Failed to unwind due to same sp/pc repeating";
}
}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index d61b281..f6f4423 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -64,7 +64,7 @@
return bytes;
}
-bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+bool BacktraceCurrent::Unwind(size_t num_ignore_frames, void* ucontext) {
if (GetMap() == nullptr) {
// Without a map object, we can't do anything.
error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
index 60a9117..48c14ea 100644
--- a/libbacktrace/BacktraceCurrent.h
+++ b/libbacktrace/BacktraceCurrent.h
@@ -19,7 +19,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <ucontext.h>
#include <backtrace/Backtrace.h>
@@ -44,7 +43,7 @@
bool ReadWord(uint64_t ptr, word_t* out_value) override;
- bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
+ bool Unwind(size_t num_ignore_frames, void* ucontext) override;
protected:
bool DiscardFrame(const backtrace_frame_data_t& frame);
@@ -52,7 +51,7 @@
private:
bool UnwindThread(size_t num_ignore_frames);
- virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
+ virtual bool UnwindFromContext(size_t num_ignore_frames, void* ucontext) = 0;
};
#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 2a657b8..c8a500c 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -146,13 +146,3 @@
return map;
}
#endif
-
-BacktraceMap* BacktraceMap::Create(pid_t pid, const std::vector<backtrace_map_t>& maps) {
- BacktraceMap* backtrace_map = new BacktraceMap(pid);
- backtrace_map->maps_.insert(backtrace_map->maps_.begin(), maps.begin(), maps.end());
- std::sort(backtrace_map->maps_.begin(), backtrace_map->maps_.end(),
- [](const backtrace_map_t& map1, const backtrace_map_t& map2) {
- return map1.start < map2.start;
- });
- return backtrace_map;
-}
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
deleted file mode 100644
index a056716..0000000
--- a/libbacktrace/BacktraceOffline.cpp
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BacktraceOffline.h"
-
-extern "C" {
-#define UNW_REMOTE_ONLY
-#include <dwarf.h>
-}
-
-#include <pthread.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-#include <ziparchive/zip_archive.h>
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
-#include <llvm/ADT/StringRef.h>
-#include <llvm/Object/Binary.h>
-#include <llvm/Object/ELFObjectFile.h>
-#include <llvm/Object/ObjectFile.h>
-
-#pragma clang diagnostic pop
-
-#include "BacktraceLog.h"
-
-struct EhFrame {
- uint64_t hdr_vaddr;
- uint64_t vaddr;
- uint64_t fde_table_offset;
- uint64_t min_func_vaddr;
- std::vector<uint8_t> hdr_data;
- std::vector<uint8_t> data;
-};
-
-struct ArmIdxEntry {
- uint32_t func_offset;
- uint32_t value;
-};
-
-struct ArmExidx {
- uint64_t exidx_vaddr;
- uint64_t extab_vaddr;
- std::vector<ArmIdxEntry> exidx_data;
- std::vector<uint8_t> extab_data;
- // There is a one-to-one map from exidx_data.func_offset to func_vaddr_array.
- std::vector<uint32_t> func_vaddr_array;
-};
-
-struct DebugFrameInfo {
- bool has_arm_exidx;
- bool has_eh_frame;
- bool has_debug_frame;
- bool has_gnu_debugdata;
-
- EhFrame eh_frame;
- ArmExidx arm_exidx;
-
- uint64_t min_vaddr;
- uint64_t text_end_vaddr;
-
- DebugFrameInfo() : has_arm_exidx(false), has_eh_frame(false),
- has_debug_frame(false), has_gnu_debugdata(false) { }
-};
-
-void Space::Clear() {
- start = 0;
- end = 0;
- data = nullptr;
-}
-
-size_t Space::Read(uint64_t addr, uint8_t* buffer, size_t size) {
- if (addr >= start && addr < end) {
- size_t read_size = std::min(size, static_cast<size_t>(end - addr));
- memcpy(buffer, data + (addr - start), read_size);
- return read_size;
- }
- return 0;
-}
-
-static int FindProcInfo(unw_addr_space_t addr_space, unw_word_t ip, unw_proc_info* proc_info,
- int need_unwind_info, void* arg) {
- BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
- bool result = backtrace->FindProcInfo(addr_space, ip, proc_info, need_unwind_info);
- return result ? 0 : -UNW_EINVAL;
-}
-
-static void PutUnwindInfo(unw_addr_space_t, unw_proc_info_t*, void*) {
-}
-
-static int GetDynInfoListAddr(unw_addr_space_t, unw_word_t*, void*) {
- return -UNW_ENOINFO;
-}
-
-static int AccessMem(unw_addr_space_t, unw_word_t addr, unw_word_t* value, int write, void* arg) {
- if (write == 1) {
- return -UNW_EINVAL;
- }
- BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
- *value = 0;
- size_t read_size = backtrace->Read(addr, reinterpret_cast<uint8_t*>(value), sizeof(unw_word_t));
- // Strictly we should check if read_size matches sizeof(unw_word_t), but it is possible in
- // .eh_frame_hdr that the section can end at a position not aligned in sizeof(unw_word_t), and
- // we should permit the read at the end of the section.
- return (read_size > 0u ? 0 : -UNW_EINVAL);
-}
-
-static int AccessReg(unw_addr_space_t, unw_regnum_t unwind_reg, unw_word_t* value, int write,
- void* arg) {
- if (write == 1) {
- return -UNW_EINVAL;
- }
- BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
- uint64_t reg_value;
- bool result = backtrace->ReadReg(unwind_reg, ®_value);
- if (result) {
- *value = static_cast<unw_word_t>(reg_value);
- }
- return result ? 0 : -UNW_EINVAL;
-}
-
-static int AccessFpReg(unw_addr_space_t, unw_regnum_t, unw_fpreg_t*, int, void*) {
- return -UNW_EINVAL;
-}
-
-static int Resume(unw_addr_space_t, unw_cursor_t*, void*) {
- return -UNW_EINVAL;
-}
-
-static int GetProcName(unw_addr_space_t, unw_word_t, char*, size_t, unw_word_t*, void*) {
- return -UNW_EINVAL;
-}
-
-static unw_accessors_t accessors = {
- .find_proc_info = FindProcInfo,
- .put_unwind_info = PutUnwindInfo,
- .get_dyn_info_list_addr = GetDynInfoListAddr,
- .access_mem = AccessMem,
- .access_reg = AccessReg,
- .access_fpreg = AccessFpReg,
- .resume = Resume,
- .get_proc_name = GetProcName,
-};
-
-bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
- if (context == nullptr) {
- BACK_LOGW("The context is needed for offline backtracing.");
- error_.error_code = BACKTRACE_UNWIND_ERROR_NO_CONTEXT;
- return false;
- }
- context_ = context;
- error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-
- unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
- unw_cursor_t cursor;
- int ret = unw_init_remote(&cursor, addr_space, this);
- if (ret != 0) {
- BACK_LOGW("unw_init_remote failed %d", ret);
- unw_destroy_addr_space(addr_space);
- error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
- return false;
- }
- size_t num_frames = 0;
- while (true) {
- unw_word_t pc;
- ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
- if (ret < 0) {
- BACK_LOGW("Failed to read IP %d", ret);
- error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
- error_.error_info.regno = UNW_REG_IP;
- break;
- }
- unw_word_t sp;
- ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
- if (ret < 0) {
- BACK_LOGW("Failed to read SP %d", ret);
- error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
- error_.error_info.regno = UNW_REG_SP;
- break;
- }
-
- if (num_ignore_frames == 0) {
- backtrace_map_t map;
- FillInMap(pc, &map);
- if (map.start == 0 || (map.flags & PROT_EXEC) == 0) {
- // .eh_frame and .ARM.exidx doesn't know how to unwind from instructions setting up or
- // destroying stack frames. It can lead to wrong callchains, which may contain pcs outside
- // executable mapping areas. Stop unwinding once this is detected.
- error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
- break;
- }
- frames_.resize(num_frames + 1);
- backtrace_frame_data_t* frame = &frames_[num_frames];
- frame->num = num_frames;
- frame->pc = static_cast<uint64_t>(pc);
- frame->sp = static_cast<uint64_t>(sp);
- frame->stack_size = 0;
-
- if (num_frames > 0) {
- backtrace_frame_data_t* prev = &frames_[num_frames - 1];
- prev->stack_size = frame->sp - prev->sp;
- }
- frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
- frame->map = map;
- num_frames++;
- } else {
- num_ignore_frames--;
- }
- is_debug_frame_used_ = false;
- ret = unw_step(&cursor);
- if (ret <= 0) {
- if (error_.error_code == BACKTRACE_UNWIND_NO_ERROR) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED;
- }
- break;
- }
- if (num_frames == MAX_BACKTRACE_FRAMES) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT;
- break;
- }
- }
- unw_destroy_addr_space(addr_space);
- context_ = nullptr;
- return true;
-}
-
-bool BacktraceOffline::ReadWord(uint64_t ptr, word_t* out_value) {
- size_t bytes_read = Read(ptr, reinterpret_cast<uint8_t*>(out_value), sizeof(word_t));
- return bytes_read == sizeof(word_t);
-}
-
-size_t BacktraceOffline::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
- // Normally, libunwind needs stack information and call frame information to do remote unwinding.
- // If call frame information is stored in .debug_frame, libunwind can read it from file
- // by itself. If call frame information is stored in .eh_frame, we need to provide data in
- // .eh_frame/.eh_frame_hdr sections.
- // The order of readings below doesn't matter, as the spaces don't overlap with each other.
- size_t read_size = eh_frame_hdr_space_.Read(addr, buffer, bytes);
- if (read_size != 0) {
- return read_size;
- }
- read_size = eh_frame_space_.Read(addr, buffer, bytes);
- if (read_size != 0) {
- return read_size;
- }
- read_size = arm_exidx_space_.Read(addr, buffer, bytes);
- if (read_size != 0) {
- return read_size;
- }
- read_size = arm_extab_space_.Read(addr, buffer, bytes);
- if (read_size != 0) {
- return read_size;
- }
- read_size = stack_space_.Read(addr, buffer, bytes);
- if (read_size != 0) {
- return read_size;
- }
- // In some libraries (like /system/lib64/libskia.so), some CIE entries in .eh_frame use
- // augmentation "P", which makes libunwind/libunwindstack try to read personality routine in
- // memory. However, that is not available in offline unwinding. Work around this by returning
- // all zero data.
- error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED;
- error_.error_info.addr = addr;
- memset(buffer, 0, bytes);
- return bytes;
-}
-
-bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip,
- unw_proc_info_t* proc_info, int need_unwind_info) {
- backtrace_map_t map;
- FillInMap(ip, &map);
- if (!BacktraceMap::IsValid(map)) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
- return false;
- }
- const std::string& filename = map.name;
- DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename);
- if (debug_frame == nullptr) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
- return false;
- }
- // Each FindProcInfo() is a new attempt to unwind, so reset the reason.
- error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-
- eh_frame_hdr_space_.Clear();
- eh_frame_space_.Clear();
- arm_exidx_space_.Clear();
- arm_extab_space_.Clear();
-
- // vaddr in the elf file.
- uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
-
- // The unwind info can come from .ARM.exidx or .eh_frame, or .debug_frame/.gnu_debugdata.
- // First check .eh_frame/.debug_frame, then check .ARM.exidx. Because .eh_frame/.debug_frame has
- // function range for each entry, by matching ip address with the function range, we know exactly
- // whether the ip address hits an entry. But .ARM.exidx doesn't have function range for each
- // entry, it thinks that an ip address hits an entry when (entry.addr <= ip < next_entry.addr).
- // To prevent ip addresses hit in .eh_frame/.debug_frame being regarded as addresses hit in
- // .ARM.exidx, we need to check .eh_frame/.debug_frame first.
-
- // Check .debug_frame/.gnu_debugdata before .eh_frame, because .debug_frame can unwind from
- // instructions setting up or destroying stack frames, while .eh_frame can't.
- if (!is_debug_frame_used_ && (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata)) {
- is_debug_frame_used_ = true;
- unw_dyn_info_t di;
- unw_word_t segbase = map.start - debug_frame->min_vaddr;
- // TODO: http://b/32916571
- // TODO: Do it ourselves is more efficient than calling libunwind functions.
- int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end);
- if (found == 1) {
- int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
- if (ret == 0) {
- return true;
- }
- }
- }
- if (debug_frame->has_eh_frame) {
- if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
- ip_vaddr < debug_frame->text_end_vaddr) {
- // Prepare eh_frame_hdr space and eh_frame space.
- eh_frame_hdr_space_.start = ip - ip_vaddr + debug_frame->eh_frame.hdr_vaddr;
- eh_frame_hdr_space_.end =
- eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
- eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
- eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
- eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
- eh_frame_space_.data = debug_frame->eh_frame.data.data();
-
- unw_dyn_info di;
- memset(&di, '\0', sizeof(di));
- di.start_ip = map.start;
- di.end_ip = map.end;
- di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
- di.u.rti.name_ptr = 0;
- di.u.rti.segbase = eh_frame_hdr_space_.start;
- di.u.rti.table_data =
- eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset;
- di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t);
- // TODO: Do it ourselves is more efficient than calling this function.
- int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
- if (ret == 0) {
- return true;
- }
- }
- }
-
- if (debug_frame->has_arm_exidx) {
- auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
- if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
- // Use binary search to find the correct function.
- auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
- static_cast<uint32_t>(ip_vaddr));
- if (it != func_vaddrs.begin()) {
- --it;
- // Found the exidx entry.
- size_t index = it - func_vaddrs.begin();
- proc_info->start_ip = *it;
- proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
- proc_info->unwind_info = reinterpret_cast<void*>(
- static_cast<uint64_t>(index * sizeof(ArmIdxEntry) + debug_frame->arm_exidx.exidx_vaddr +
- debug_frame->min_vaddr));
- eh_frame_hdr_space_.Clear();
- eh_frame_space_.Clear();
- // Prepare arm_exidx space and arm_extab space.
- arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
- arm_exidx_space_.end = arm_exidx_space_.start +
- debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
- arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
- debug_frame->arm_exidx.exidx_data.data());
-
- arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
- arm_extab_space_.end = arm_extab_space_.start +
- debug_frame->arm_exidx.extab_data.size();
- arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
- return true;
- }
- }
- }
- error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
- return false;
-}
-
-bool BacktraceOffline::ReadReg(size_t reg, uint64_t* value) {
- bool result = true;
-#if defined(__arm__)
- switch (reg) {
- case UNW_ARM_R0:
- *value = context_->uc_mcontext.arm_r0;
- break;
- case UNW_ARM_R1:
- *value = context_->uc_mcontext.arm_r1;
- break;
- case UNW_ARM_R2:
- *value = context_->uc_mcontext.arm_r2;
- break;
- case UNW_ARM_R3:
- *value = context_->uc_mcontext.arm_r3;
- break;
- case UNW_ARM_R4:
- *value = context_->uc_mcontext.arm_r4;
- break;
- case UNW_ARM_R5:
- *value = context_->uc_mcontext.arm_r5;
- break;
- case UNW_ARM_R6:
- *value = context_->uc_mcontext.arm_r6;
- break;
- case UNW_ARM_R7:
- *value = context_->uc_mcontext.arm_r7;
- break;
- case UNW_ARM_R8:
- *value = context_->uc_mcontext.arm_r8;
- break;
- case UNW_ARM_R9:
- *value = context_->uc_mcontext.arm_r9;
- break;
- case UNW_ARM_R10:
- *value = context_->uc_mcontext.arm_r10;
- break;
- case UNW_ARM_R11:
- *value = context_->uc_mcontext.arm_fp;
- break;
- case UNW_ARM_R12:
- *value = context_->uc_mcontext.arm_ip;
- break;
- case UNW_ARM_R13:
- *value = context_->uc_mcontext.arm_sp;
- break;
- case UNW_ARM_R14:
- *value = context_->uc_mcontext.arm_lr;
- break;
- case UNW_ARM_R15:
- *value = context_->uc_mcontext.arm_pc;
- break;
- default:
- result = false;
- }
-#elif defined(__aarch64__)
- if (reg <= UNW_AARCH64_PC) {
- *value = context_->uc_mcontext.regs[reg];
- } else {
- result = false;
- }
-#elif defined(__x86_64__)
- switch (reg) {
- case UNW_X86_64_R8:
- *value = context_->uc_mcontext.gregs[REG_R8];
- break;
- case UNW_X86_64_R9:
- *value = context_->uc_mcontext.gregs[REG_R9];
- break;
- case UNW_X86_64_R10:
- *value = context_->uc_mcontext.gregs[REG_R10];
- break;
- case UNW_X86_64_R11:
- *value = context_->uc_mcontext.gregs[REG_R11];
- break;
- case UNW_X86_64_R12:
- *value = context_->uc_mcontext.gregs[REG_R12];
- break;
- case UNW_X86_64_R13:
- *value = context_->uc_mcontext.gregs[REG_R13];
- break;
- case UNW_X86_64_R14:
- *value = context_->uc_mcontext.gregs[REG_R14];
- break;
- case UNW_X86_64_R15:
- *value = context_->uc_mcontext.gregs[REG_R15];
- break;
- case UNW_X86_64_RDI:
- *value = context_->uc_mcontext.gregs[REG_RDI];
- break;
- case UNW_X86_64_RSI:
- *value = context_->uc_mcontext.gregs[REG_RSI];
- break;
- case UNW_X86_64_RBP:
- *value = context_->uc_mcontext.gregs[REG_RBP];
- break;
- case UNW_X86_64_RBX:
- *value = context_->uc_mcontext.gregs[REG_RBX];
- break;
- case UNW_X86_64_RDX:
- *value = context_->uc_mcontext.gregs[REG_RDX];
- break;
- case UNW_X86_64_RAX:
- *value = context_->uc_mcontext.gregs[REG_RAX];
- break;
- case UNW_X86_64_RCX:
- *value = context_->uc_mcontext.gregs[REG_RCX];
- break;
- case UNW_X86_64_RSP:
- *value = context_->uc_mcontext.gregs[REG_RSP];
- break;
- case UNW_X86_64_RIP:
- *value = context_->uc_mcontext.gregs[REG_RIP];
- break;
- default:
- result = false;
- }
-#elif defined(__i386__)
- switch (reg) {
- case UNW_X86_GS:
- *value = context_->uc_mcontext.gregs[REG_GS];
- break;
- case UNW_X86_FS:
- *value = context_->uc_mcontext.gregs[REG_FS];
- break;
- case UNW_X86_ES:
- *value = context_->uc_mcontext.gregs[REG_ES];
- break;
- case UNW_X86_DS:
- *value = context_->uc_mcontext.gregs[REG_DS];
- break;
- case UNW_X86_EAX:
- *value = context_->uc_mcontext.gregs[REG_EAX];
- break;
- case UNW_X86_EBX:
- *value = context_->uc_mcontext.gregs[REG_EBX];
- break;
- case UNW_X86_ECX:
- *value = context_->uc_mcontext.gregs[REG_ECX];
- break;
- case UNW_X86_EDX:
- *value = context_->uc_mcontext.gregs[REG_EDX];
- break;
- case UNW_X86_ESI:
- *value = context_->uc_mcontext.gregs[REG_ESI];
- break;
- case UNW_X86_EDI:
- *value = context_->uc_mcontext.gregs[REG_EDI];
- break;
- case UNW_X86_EBP:
- *value = context_->uc_mcontext.gregs[REG_EBP];
- break;
- case UNW_X86_EIP:
- *value = context_->uc_mcontext.gregs[REG_EIP];
- break;
- case UNW_X86_ESP:
- *value = context_->uc_mcontext.gregs[REG_ESP];
- break;
- case UNW_X86_TRAPNO:
- *value = context_->uc_mcontext.gregs[REG_TRAPNO];
- break;
- case UNW_X86_CS:
- *value = context_->uc_mcontext.gregs[REG_CS];
- break;
- case UNW_X86_EFLAGS:
- *value = context_->uc_mcontext.gregs[REG_EFL];
- break;
- case UNW_X86_SS:
- *value = context_->uc_mcontext.gregs[REG_SS];
- break;
- default:
- result = false;
- }
-#else
- UNUSED(reg);
- UNUSED(value);
- result = false;
-#endif
- if (!result) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
- error_.error_info.regno = reg;
- }
- return result;
-}
-
-std::string BacktraceOffline::GetFunctionNameRaw(uint64_t, uint64_t* offset) {
- // We don't have enough information to support this. And it is expensive.
- *offset = 0;
- return "";
-}
-
-static std::mutex g_lock;
-static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>* g_debug_frames = nullptr;
-
-static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
-
-DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
- if (cache_file_) {
- std::lock_guard<std::mutex> lock(g_lock);
- if (g_debug_frames != nullptr) {
- auto it = g_debug_frames->find(filename);
- if (it != g_debug_frames->end()) {
- return it->second.get();
- }
- }
- }
- DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
- if (cache_file_) {
- std::lock_guard<std::mutex> lock(g_lock);
- if (g_debug_frames == nullptr) {
- g_debug_frames = new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
- }
- auto pair = g_debug_frames->emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
- if (!pair.second) {
- debug_frame = pair.first->second.get();
- }
- }
- return debug_frame;
-}
-
-static bool OmitEncodedValue(uint8_t encode, const uint8_t*& p, bool is_elf64) {
- if (encode == DW_EH_PE_omit) {
- return 0;
- }
- uint8_t format = encode & 0x0f;
- switch (format) {
- case DW_EH_PE_ptr:
- p += is_elf64 ? 8 : 4;
- break;
- case DW_EH_PE_uleb128:
- case DW_EH_PE_sleb128:
- while ((*p & 0x80) != 0) {
- ++p;
- }
- ++p;
- break;
- case DW_EH_PE_udata2:
- case DW_EH_PE_sdata2:
- p += 2;
- break;
- case DW_EH_PE_udata4:
- case DW_EH_PE_sdata4:
- p += 4;
- break;
- case DW_EH_PE_udata8:
- case DW_EH_PE_sdata8:
- p += 8;
- break;
- default:
- return false;
- }
- return true;
-}
-
-static bool GetFdeTableOffsetInEhFrameHdr(const std::vector<uint8_t>& data,
- uint64_t* table_offset_in_eh_frame_hdr, bool is_elf64) {
- const uint8_t* p = data.data();
- const uint8_t* end = p + data.size();
- if (p + 4 > end) {
- return false;
- }
- uint8_t version = *p++;
- if (version != 1) {
- return false;
- }
- uint8_t eh_frame_ptr_encode = *p++;
- uint8_t fde_count_encode = *p++;
- uint8_t fde_table_encode = *p++;
-
- if (fde_table_encode != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
- return false;
- }
-
- if (!OmitEncodedValue(eh_frame_ptr_encode, p, is_elf64) ||
- !OmitEncodedValue(fde_count_encode, p, is_elf64)) {
- return false;
- }
- if (p >= end) {
- return false;
- }
- *table_offset_in_eh_frame_hdr = p - data.data();
- return true;
-}
-
-static uint64_t ReadFromBuffer(const uint8_t*& p, size_t size) {
- uint64_t result = 0;
- int shift = 0;
- while (size-- > 0) {
- uint64_t tmp = *p++;
- result |= tmp << shift;
- shift += 8;
- }
- return result;
-}
-
-static uint64_t ReadSignValueFromBuffer(const uint8_t*& p, size_t size) {
- uint64_t result = 0;
- int shift = 0;
- for (size_t i = 0; i < size; ++i) {
- uint64_t tmp = *p++;
- result |= tmp << shift;
- shift += 8;
- }
- if (*(p - 1) & 0x80) {
- result |= (-1ULL) << (size * 8);
- }
- return result;
-}
-
-static const char* ReadStrFromBuffer(const uint8_t*& p) {
- const char* result = reinterpret_cast<const char*>(p);
- p += strlen(result) + 1;
- return result;
-}
-
-static int64_t ReadLEB128FromBuffer(const uint8_t*& p) {
- int64_t result = 0;
- int64_t tmp;
- int shift = 0;
- while (*p & 0x80) {
- tmp = *p & 0x7f;
- result |= tmp << shift;
- shift += 7;
- p++;
- }
- tmp = *p;
- result |= tmp << shift;
- if (*p & 0x40) {
- result |= -((tmp & 0x40) << shift);
- }
- p++;
- return result;
-}
-
-static uint64_t ReadULEB128FromBuffer(const uint8_t*& p) {
- uint64_t result = 0;
- uint64_t tmp;
- int shift = 0;
- while (*p & 0x80) {
- tmp = *p & 0x7f;
- result |= tmp << shift;
- shift += 7;
- p++;
- }
- tmp = *p;
- result |= tmp << shift;
- p++;
- return result;
-}
-
-static uint64_t ReadEhEncoding(const uint8_t*& p, uint8_t encoding, bool is_elf64,
- uint64_t section_vaddr, const uint8_t* section_begin) {
- const uint8_t* init_addr = p;
- uint64_t result = 0;
- switch (encoding & 0x0f) {
- case DW_EH_PE_absptr:
- result = ReadFromBuffer(p, is_elf64 ? 8 : 4);
- break;
- case DW_EH_PE_omit:
- result = 0;
- break;
- case DW_EH_PE_uleb128:
- result = ReadULEB128FromBuffer(p);
- break;
- case DW_EH_PE_udata2:
- result = ReadFromBuffer(p, 2);
- break;
- case DW_EH_PE_udata4:
- result = ReadFromBuffer(p, 4);
- break;
- case DW_EH_PE_udata8:
- result = ReadFromBuffer(p, 8);
- break;
- case DW_EH_PE_sleb128:
- result = ReadLEB128FromBuffer(p);
- break;
- case DW_EH_PE_sdata2:
- result = ReadSignValueFromBuffer(p, 2);
- break;
- case DW_EH_PE_sdata4:
- result = ReadSignValueFromBuffer(p, 4);
- break;
- case DW_EH_PE_sdata8:
- result = ReadSignValueFromBuffer(p, 8);
- break;
- }
- switch (encoding & 0xf0) {
- case DW_EH_PE_pcrel:
- result += init_addr - section_begin + section_vaddr;
- break;
- case DW_EH_PE_datarel:
- result += section_vaddr;
- break;
- }
- return result;
-}
-
-static bool BuildEhFrameHdr(DebugFrameInfo* info, bool is_elf64) {
- // For each fde entry, collect its (func_vaddr, fde_vaddr) pair.
- std::vector<std::pair<uint64_t, uint64_t>> index_table;
- // Map form cie_offset to fde encoding.
- std::unordered_map<size_t, uint8_t> cie_map;
- const uint8_t* eh_frame_begin = info->eh_frame.data.data();
- const uint8_t* eh_frame_end = eh_frame_begin + info->eh_frame.data.size();
- const uint8_t* p = eh_frame_begin;
- uint64_t eh_frame_vaddr = info->eh_frame.vaddr;
- while (p < eh_frame_end) {
- const uint8_t* unit_begin = p;
- uint64_t unit_len = ReadFromBuffer(p, 4);
- size_t secbytes = 4;
- if (unit_len == 0xffffffff) {
- unit_len = ReadFromBuffer(p, 8);
- secbytes = 8;
- }
- const uint8_t* unit_end = p + unit_len;
- uint64_t cie_id = ReadFromBuffer(p, secbytes);
- if (cie_id == 0) {
- // This is a CIE.
- // Read version
- uint8_t version = *p++;
- // Read augmentation
- const char* augmentation = ReadStrFromBuffer(p);
- if (version >= 4) {
- // Read address size and segment size
- p += 2;
- }
- // Read code alignment factor
- ReadULEB128FromBuffer(p);
- // Read data alignment factor
- ReadLEB128FromBuffer(p);
- // Read return address register
- if (version == 1) {
- p++;
- } else {
- ReadULEB128FromBuffer(p);
- }
- uint8_t fde_pointer_encoding = 0;
- if (augmentation[0] == 'z') {
- // Read augmentation length.
- ReadULEB128FromBuffer(p);
- for (int i = 1; augmentation[i] != '\0'; ++i) {
- char c = augmentation[i];
- if (c == 'R') {
- fde_pointer_encoding = *p++;
- } else if (c == 'P') {
- // Read personality handler
- uint8_t encoding = *p++;
- OmitEncodedValue(encoding, p, is_elf64);
- } else if (c == 'L') {
- // Read lsda encoding
- p++;
- }
- }
- }
- cie_map[unit_begin - eh_frame_begin] = fde_pointer_encoding;
- } else {
- // This is an FDE.
- size_t cie_offset = p - secbytes - eh_frame_begin - cie_id;
- auto it = cie_map.find(cie_offset);
- if (it != cie_map.end()) {
- uint8_t fde_pointer_encoding = it->second;
- uint64_t initial_location =
- ReadEhEncoding(p, fde_pointer_encoding, is_elf64, eh_frame_vaddr, eh_frame_begin);
- uint64_t fde_vaddr = unit_begin - eh_frame_begin + eh_frame_vaddr;
- index_table.push_back(std::make_pair(initial_location, fde_vaddr));
- }
- }
- p = unit_end;
- }
- if (index_table.empty()) {
- return false;
- }
- std::sort(index_table.begin(), index_table.end());
- info->eh_frame.hdr_vaddr = 0;
- info->eh_frame.hdr_data.resize(index_table.size() * 8);
- uint32_t* ptr = reinterpret_cast<uint32_t*>(info->eh_frame.hdr_data.data());
- for (auto& pair : index_table) {
- *ptr++ = static_cast<uint32_t>(pair.first - info->eh_frame.hdr_vaddr);
- *ptr++ = static_cast<uint32_t>(pair.second - info->eh_frame.hdr_vaddr);
- }
- info->eh_frame.fde_table_offset = 0;
- info->eh_frame.min_func_vaddr = index_table[0].first;
- return true;
-}
-
-template <class ELFT>
-DebugFrameInfo* ReadDebugFrameFromELFFile(const llvm::object::ELFFile<ELFT>* elf) {
- DebugFrameInfo* result = new DebugFrameInfo;
- result->eh_frame.hdr_vaddr = 0;
- result->text_end_vaddr = std::numeric_limits<uint64_t>::max();
-
- bool is_elf64 = (elf->getHeader()->getFileClass() == llvm::ELF::ELFCLASS64);
- bool has_eh_frame_hdr = false;
- bool has_eh_frame = false;
-
- for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
- llvm::ErrorOr<llvm::StringRef> name = elf->getSectionName(&*it);
- if (name) {
- std::string s = name.get();
- if (s == ".debug_frame") {
- result->has_debug_frame = true;
- } else if (s == ".gnu_debugdata") {
- result->has_gnu_debugdata = true;
- } else if (s == ".eh_frame_hdr") {
- result->eh_frame.hdr_vaddr = it->sh_addr;
- llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
- if (data) {
- result->eh_frame.hdr_data.insert(result->eh_frame.hdr_data.end(),
- data->data(), data->data() + data->size());
-
- uint64_t fde_table_offset;
- if (GetFdeTableOffsetInEhFrameHdr(result->eh_frame.hdr_data, &fde_table_offset, is_elf64)) {
- result->eh_frame.fde_table_offset = fde_table_offset;
- // Make sure we have at least one entry in fde_table.
- if (fde_table_offset + 2 * sizeof(int32_t) <= data->size()) {
- intptr_t eh_frame_hdr_vaddr = it->sh_addr;
- int32_t sdata;
- uint8_t* p = result->eh_frame.hdr_data.data() + fde_table_offset;
- memcpy(&sdata, p, sizeof(sdata));
- result->eh_frame.min_func_vaddr = eh_frame_hdr_vaddr + sdata;
- has_eh_frame_hdr = true;
- }
- }
- }
- } else if (s == ".eh_frame") {
- result->eh_frame.vaddr = it->sh_addr;
- llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
- if (data) {
- result->eh_frame.data.insert(result->eh_frame.data.end(),
- data->data(), data->data() + data->size());
- has_eh_frame = true;
- }
- } else if (s == ".ARM.exidx") {
- result->arm_exidx.exidx_vaddr = it->sh_addr;
- llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
- if (data) {
- size_t entry_count = data->size() / sizeof(ArmIdxEntry);
- result->arm_exidx.exidx_data.resize(entry_count);
- memcpy(result->arm_exidx.exidx_data.data(), data->data(),
- entry_count * sizeof(ArmIdxEntry));
- if (entry_count > 0u) {
- // Change IdxEntry.func_offset into vaddr.
- result->arm_exidx.func_vaddr_array.reserve(entry_count);
- uint32_t vaddr = it->sh_addr;
- for (auto& entry : result->arm_exidx.exidx_data) {
- uint32_t func_offset = entry.func_offset + vaddr;
- // Clear bit 31 for the prel31 offset.
- // Arm sets bit 0 to mark it as thumb code, remove the flag.
- result->arm_exidx.func_vaddr_array.push_back(
- func_offset & 0x7ffffffe);
- vaddr += 8;
- }
- result->has_arm_exidx = true;
- }
- }
- } else if (s == ".ARM.extab") {
- result->arm_exidx.extab_vaddr = it->sh_addr;
- llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
- if (data) {
- result->arm_exidx.extab_data.insert(result->arm_exidx.extab_data.end(),
- data->data(), data->data() + data->size());
- }
- } else if (s == ".text") {
- result->text_end_vaddr = it->sh_addr + it->sh_size;
- }
- }
- }
-
- if (has_eh_frame) {
- if (!has_eh_frame_hdr) {
- // Some libraries (like /vendor/lib64/egl/eglSubDriverAndroid.so) contain empty
- // .eh_frame_hdr.
- if (BuildEhFrameHdr(result, is_elf64)) {
- has_eh_frame_hdr = true;
- }
- }
- if (has_eh_frame_hdr) {
- result->has_eh_frame = true;
- }
- }
- if (has_eh_frame_hdr && has_eh_frame) {
- result->has_eh_frame = true;
- }
-
- result->min_vaddr = std::numeric_limits<uint64_t>::max();
- for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
- if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
- if (it->p_vaddr < result->min_vaddr) {
- result->min_vaddr = it->p_vaddr;
- }
- }
- }
- if (!result->has_eh_frame && !result->has_arm_exidx && !result->has_debug_frame &&
- !result->has_gnu_debugdata) {
- delete result;
- return nullptr;
- }
- return result;
-}
-
-static bool IsValidElfPath(const std::string& filename) {
- static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
-
- struct stat st;
- if (stat(filename.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
- return false;
- }
- FILE* fp = fopen(filename.c_str(), "reb");
- if (fp == nullptr) {
- return false;
- }
- char buf[4];
- if (fread(buf, 4, 1, fp) != 1) {
- fclose(fp);
- return false;
- }
- fclose(fp);
- return memcmp(buf, elf_magic, 4) == 0;
-}
-
-static bool IsValidApkPath(const std::string& apk_path) {
- static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04};
- struct stat st;
- if (stat(apk_path.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
- return false;
- }
- FILE* fp = fopen(apk_path.c_str(), "reb");
- if (fp == nullptr) {
- return false;
- }
- char buf[4];
- if (fread(buf, 4, 1, fp) != 1) {
- fclose(fp);
- return false;
- }
- fclose(fp);
- return memcmp(buf, zip_preamble, 4) == 0;
-}
-
-class ScopedZiparchiveHandle {
- public:
- explicit ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
- }
-
- ~ScopedZiparchiveHandle() {
- CloseArchive(handle_);
- }
-
- private:
- ZipArchiveHandle handle_;
-};
-
-llvm::object::OwningBinary<llvm::object::Binary> OpenEmbeddedElfFile(const std::string& filename) {
- llvm::object::OwningBinary<llvm::object::Binary> nothing;
- size_t pos = filename.find("!/");
- if (pos == std::string::npos) {
- return nothing;
- }
- std::string apk_file = filename.substr(0, pos);
- std::string elf_file = filename.substr(pos + 2);
- if (!IsValidApkPath(apk_file)) {
- BACK_LOGW("%s is not a valid apk file", apk_file.c_str());
- return nothing;
- }
- ZipArchiveHandle handle;
- int32_t ret_code = OpenArchive(apk_file.c_str(), &handle);
- if (ret_code != 0) {
- CloseArchive(handle);
- BACK_LOGW("failed to open archive %s: %s", apk_file.c_str(), ErrorCodeString(ret_code));
- return nothing;
- }
- ScopedZiparchiveHandle scoped_handle(handle);
- ZipEntry zentry;
- ret_code = FindEntry(handle, ZipString(elf_file.c_str()), &zentry);
- if (ret_code != 0) {
- BACK_LOGW("failed to find %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
- ErrorCodeString(ret_code));
- return nothing;
- }
- if (zentry.method != kCompressStored || zentry.compressed_length != zentry.uncompressed_length) {
- BACK_LOGW("%s is compressed in %s, which doesn't support running directly", elf_file.c_str(),
- apk_file.c_str());
- return nothing;
- }
- auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(GetFileDescriptor(handle), apk_file,
- zentry.uncompressed_length,
- zentry.offset);
- if (!buffer_or_err) {
- BACK_LOGW("failed to read %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
- buffer_or_err.getError().message().c_str());
- return nothing;
- }
- auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
- if (!binary_or_err) {
- BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
- llvm::toString(binary_or_err.takeError()).c_str());
- return nothing;
- }
- return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
- std::move(buffer_or_err.get()));
-}
-
-static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
- llvm::object::OwningBinary<llvm::object::Binary> owning_binary;
- if (filename.find("!/") != std::string::npos) {
- owning_binary = OpenEmbeddedElfFile(filename);
- } else {
- if (!IsValidElfPath(filename)) {
- return nullptr;
- }
- auto binary_or_err = llvm::object::createBinary(llvm::StringRef(filename));
- if (!binary_or_err) {
- return nullptr;
- }
- owning_binary = std::move(binary_or_err.get());
- }
- llvm::object::Binary* binary = owning_binary.getBinary();
- auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
- if (obj == nullptr) {
- return nullptr;
- }
- if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
- return ReadDebugFrameFromELFFile(elf->getELFFile());
- }
- if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
- return ReadDebugFrameFromELFFile(elf->getELFFile());
- }
- return nullptr;
-}
-
-Backtrace* Backtrace::CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map,
- const backtrace_stackinfo_t& stack, bool cache_file) {
- return new BacktraceOffline(pid, tid, map, stack, cache_file);
-}
diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h
deleted file mode 100644
index e028cd8..0000000
--- a/libbacktrace/BacktraceOffline.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBBACKTRACE_UNWIND_OFFLINE_H
-#define _LIBBACKTRACE_UNWIND_OFFLINE_H
-
-#include <libunwind.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-#include <unordered_map>
-#include <unordered_set>
-
-#include <backtrace/Backtrace.h>
-
-struct Space {
- uint64_t start;
- uint64_t end;
- const uint8_t* data;
-
- Space() { Clear(); }
-
- void Clear();
- size_t Read(uint64_t addr, uint8_t* buffer, size_t size);
-};
-
-struct DebugFrameInfo;
-
-class BacktraceOffline : public Backtrace {
- public:
- BacktraceOffline(pid_t pid, pid_t tid, BacktraceMap* map, const backtrace_stackinfo_t& stack,
- bool cache_file)
- : Backtrace(pid, tid, map),
- cache_file_(cache_file),
- context_(nullptr),
- is_debug_frame_used_(false) {
- stack_space_.start = stack.start;
- stack_space_.end = stack.end;
- stack_space_.data = stack.data;
- }
-
- virtual ~BacktraceOffline() = default;
-
- bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
-
- bool ReadWord(uint64_t ptr, word_t* out_value) override;
-
- size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
-
- bool FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info,
- int need_unwind_info);
-
- bool ReadReg(size_t reg_index, uint64_t* value);
-
- protected:
- std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
- DebugFrameInfo* GetDebugFrameInFile(const std::string& filename);
-
- bool cache_file_;
- ucontext_t* context_;
- Space eh_frame_hdr_space_;
- Space eh_frame_space_;
- Space arm_extab_space_;
- Space arm_exidx_space_;
- Space stack_space_;
-
- // is_debug_frame_used_ is to make sure we can try both .debug_frame and .ARM.exidx in
- // FindProcInfo() on ARM. One example is EsxContext::Clear() in
- // vendor/lib/egl/libGLESv2_adreno.so. EsxContext::Clear() appears in both .debug_frame and
- // .ARM.exidx. However, libunwind fails to execute debug_frame instruction
- // "DW_CFA_offset_extended: r265 at cfa-48". So we need to try .ARM.exidx to unwind that
- // function.
- bool is_debug_frame_used_;
-};
-
-#endif // _LIBBACKTRACE_BACKTRACE_OFFLINE_H
diff --git a/libbacktrace/UnwindDexFile.cpp b/libbacktrace/UnwindDexFile.cpp
new file mode 100644
index 0000000..5780fbb
--- /dev/null
+++ b/libbacktrace/UnwindDexFile.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <android-base/unique_fd.h>
+
+#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/compact_dex_file.h>
+#include <dex/dex_file-inl.h>
+#include <dex/dex_file_loader.h>
+#include <dex/standard_dex_file.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include "UnwindDexFile.h"
+
+UnwindDexFile* UnwindDexFile::Create(uint64_t dex_file_offset_in_memory,
+ unwindstack::Memory* memory, unwindstack::MapInfo* info) {
+ if (!info->name.empty()) {
+ std::unique_ptr<UnwindDexFileFromFile> dex_file(new UnwindDexFileFromFile);
+ if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
+ return dex_file.release();
+ }
+ }
+
+ std::unique_ptr<UnwindDexFileFromMemory> dex_file(new UnwindDexFileFromMemory);
+ if (dex_file->Open(dex_file_offset_in_memory, memory)) {
+ return dex_file.release();
+ }
+ return nullptr;
+}
+
+void UnwindDexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+ uint64_t* method_offset) {
+ if (dex_file_ == nullptr) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
+ const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i);
+ const uint8_t* class_data = dex_file_->GetClassData(class_def);
+ if (class_data == nullptr) {
+ continue;
+ }
+ for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) {
+ if (!it.IsAtMethod()) {
+ continue;
+ }
+ const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item == nullptr) {
+ continue;
+ }
+ art::CodeItemInstructionAccessor code(*dex_file_.get(), code_item);
+ if (!code.HasCodeItem()) {
+ continue;
+ }
+
+ uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+ size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
+ if (offset <= dex_offset && dex_offset < offset + size) {
+ *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
+ *method_offset = dex_offset - offset;
+ return;
+ }
+ }
+ }
+}
+
+UnwindDexFileFromFile::~UnwindDexFileFromFile() {
+ if (size_ != 0) {
+ munmap(mapped_memory_, size_);
+ }
+}
+
+bool UnwindDexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ return false;
+ }
+ struct stat buf;
+ if (fstat(fd, &buf) == -1) {
+ return false;
+ }
+ uint64_t length;
+ if (buf.st_size < 0 ||
+ __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
+ static_cast<uint64_t>(buf.st_size) < length) {
+ return false;
+ }
+
+ mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (mapped_memory_ == MAP_FAILED) {
+ return false;
+ }
+ size_ = buf.st_size;
+
+ uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);
+
+ art::DexFile::Header* header =
+ reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
+ if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
+ !art::CompactDexFile::IsMagicValid(header->magic_)) {
+ return false;
+ }
+
+ if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
+ static_cast<uint64_t>(buf.st_size) < length) {
+ return false;
+ }
+
+ art::DexFileLoader loader;
+ std::string error_msg;
+ auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
+ false, false, &error_msg);
+ dex_file_.reset(dex.release());
+ return dex_file_ != nullptr;
+}
+
+bool UnwindDexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory) {
+ art::DexFile::Header header;
+ if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
+ return false;
+ }
+
+ if (!art::StandardDexFile::IsMagicValid(header.magic_) &&
+ !art::CompactDexFile::IsMagicValid(header.magic_)) {
+ return false;
+ }
+
+ memory_.resize(header.file_size_);
+ if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) {
+ return false;
+ }
+
+ art::DexFileLoader loader;
+ std::string error_msg;
+ auto dex =
+ loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg);
+ dex_file_.reset(dex.release());
+ return dex_file_ != nullptr;
+}
diff --git a/libbacktrace/UnwindDexFile.h b/libbacktrace/UnwindDexFile.h
new file mode 100644
index 0000000..dd70aba
--- /dev/null
+++ b/libbacktrace/UnwindDexFile.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_DEX_FILE_H
+#define _LIBBACKTRACE_UNWIND_DEX_FILE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dex/dex_file-inl.h>
+
+namespace unwindstack {
+class Memory;
+struct MapInfo;
+} // namespace unwindstack
+
+class UnwindDexFile {
+ public:
+ UnwindDexFile() = default;
+ virtual ~UnwindDexFile() = default;
+
+ void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+
+ static UnwindDexFile* Create(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory,
+ unwindstack::MapInfo* info);
+
+ protected:
+ std::unique_ptr<const art::DexFile> dex_file_;
+};
+
+class UnwindDexFileFromFile : public UnwindDexFile {
+ public:
+ UnwindDexFileFromFile() = default;
+ virtual ~UnwindDexFileFromFile();
+
+ bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+
+ private:
+ void* mapped_memory_ = nullptr;
+ size_t size_ = 0;
+};
+
+class UnwindDexFileFromMemory : public UnwindDexFile {
+ public:
+ UnwindDexFileFromMemory() = default;
+ virtual ~UnwindDexFileFromMemory() = default;
+
+ bool Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory);
+
+ private:
+ std::vector<uint8_t> memory_;
+};
+
+#endif // _LIBBACKTRACE_UNWIND_DEX_FILE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index bbfbdda..158467e 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -18,7 +18,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <ucontext.h>
#include <memory>
#include <set>
@@ -40,37 +39,154 @@
#include <unwindstack/Unwinder.h>
#include "BacktraceLog.h"
+#ifndef NO_LIBDEXFILE
+#include "UnwindDexFile.h"
+#endif
#include "UnwindStack.h"
#include "UnwindStackMap.h"
+static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc,
+ backtrace_frame_data_t* frame) {
+ // The DEX PC points into the .dex section within an ELF file.
+ // However, this is a BBS section manually mmaped to a .vdex file,
+ // so we need to get the following map to find the ELF data.
+ unwindstack::Maps* maps = stack_map->stack_maps();
+ auto it = maps->begin();
+ uint64_t rel_dex_pc;
+ unwindstack::MapInfo* info;
+ for (; it != maps->end(); ++it) {
+ auto entry = *it;
+ if (dex_pc >= entry->start && dex_pc < entry->end) {
+ info = entry;
+ rel_dex_pc = dex_pc - entry->start;
+ frame->map.start = entry->start;
+ frame->map.end = entry->end;
+ frame->map.offset = entry->offset;
+ frame->map.load_bias = entry->load_bias;
+ frame->map.flags = entry->flags;
+ frame->map.name = entry->name;
+ frame->rel_pc = rel_dex_pc;
+ break;
+ }
+ }
+ if (it == maps->end() || ++it == maps->end()) {
+ return;
+ }
+
+ auto entry = *it;
+ auto process_memory = stack_map->process_memory();
+ unwindstack::Elf* elf = entry->GetElf(process_memory, true);
+ if (!elf->valid()) {
+ return;
+ }
+
+ // Adjust the relative dex by the offset.
+ rel_dex_pc += entry->elf_offset;
+
+ uint64_t dex_offset;
+ if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) {
+ return;
+ }
+ frame->func_offset = dex_offset;
+ if (frame->func_name != "$dexfile") {
+ return;
+ }
+
+#ifndef NO_LIBDEXFILE
+ UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info);
+ if (dex_file != nullptr) {
+ dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset);
+ }
+#endif
+}
+
bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
- std::vector<std::string>* skip_names) {
+ std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
auto process_memory = stack_map->process_memory();
unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
regs, stack_map->process_memory());
- unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+ if (stack_map->GetJitDebug() != nullptr) {
+ unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+ }
unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
+ if (error != nullptr) {
+ switch (unwinder.LastErrorCode()) {
+ case unwindstack::ERROR_NONE:
+ error->error_code = BACKTRACE_UNWIND_NO_ERROR;
+ break;
+
+ case unwindstack::ERROR_MEMORY_INVALID:
+ error->error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED;
+ error->error_info.addr = unwinder.LastErrorAddress();
+ break;
+
+ case unwindstack::ERROR_UNWIND_INFO:
+ error->error_code = BACKTRACE_UNWIND_ERROR_UNWIND_INFO;
+ break;
+
+ case unwindstack::ERROR_UNSUPPORTED:
+ error->error_code = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
+ break;
+
+ case unwindstack::ERROR_INVALID_MAP:
+ error->error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
+ break;
+
+ case unwindstack::ERROR_MAX_FRAMES_EXCEEDED:
+ error->error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT;
+ break;
+
+ case unwindstack::ERROR_REPEATED_FRAME:
+ error->error_code = BACKTRACE_UNWIND_ERROR_REPEATED_FRAME;
+ break;
+ }
+ }
if (num_ignore_frames >= unwinder.NumFrames()) {
frames->resize(0);
return true;
}
- frames->resize(unwinder.NumFrames() - num_ignore_frames);
auto unwinder_frames = unwinder.frames();
+ // Get the real number of frames we'll need.
+ size_t total_frames = 0;
+ for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) {
+ if (unwinder_frames[i].dex_pc != 0) {
+ total_frames++;
+ }
+ }
+ frames->resize(total_frames);
size_t cur_frame = 0;
- for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, cur_frame++) {
+ for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
auto frame = &unwinder_frames[i];
+
+ // Inject extra 'virtual' frame that represents the dex pc data.
+ // The dex pc is magic register defined in the Mterp interpreter,
+ // and thus it will be restored/observed in the frame after it.
+ // Adding the dex frame first here will create something like:
+ // #7 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
+ // #8 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
+ // #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
+ if (frame->dex_pc != 0) {
+ backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
+ dex_frame->num = cur_frame++;
+ dex_frame->pc = frame->dex_pc;
+ dex_frame->rel_pc = frame->dex_pc;
+ dex_frame->sp = frame->sp;
+ dex_frame->stack_size = 0;
+ dex_frame->func_offset = 0;
+ FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
+ }
+
backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
- back_frame->num = frame->num - num_ignore_frames;
+ back_frame->num = cur_frame++;
back_frame->rel_pc = frame->rel_pc;
back_frame->pc = frame->pc;
back_frame->sp = frame->sp;
- back_frame->dex_pc = frame->dex_pc;
back_frame->func_name = demangle(frame->function_name.c_str());
back_frame->func_offset = frame->function_offset;
@@ -93,7 +209,7 @@
return GetMap()->GetFunctionName(pc, offset);
}
-bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
+bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, void* ucontext) {
std::unique_ptr<unwindstack::Regs> regs;
if (ucontext == nullptr) {
regs.reset(unwindstack::Regs::CreateFromLocal());
@@ -104,9 +220,8 @@
regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
}
- error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
- return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names);
+ return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names, &error_);
}
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
@@ -116,7 +231,7 @@
return GetMap()->GetFunctionName(pc, offset);
}
-bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
+bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, void* context) {
std::unique_ptr<unwindstack::Regs> regs;
if (context == nullptr) {
regs.reset(unwindstack::Regs::RemoteGet(Tid()));
@@ -124,10 +239,77 @@
regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context));
}
- error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
- return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
+ return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_);
}
size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
return memory_.Read(addr, buffer, bytes);
}
+
+UnwindStackOffline::UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map,
+ bool map_shared)
+ : Backtrace(pid, tid, map), arch_(arch) {
+ map_shared_ = map_shared;
+}
+
+bool UnwindStackOffline::Unwind(size_t num_ignore_frames, void* ucontext) {
+ if (ucontext == nullptr) {
+ return false;
+ }
+
+ unwindstack::ArchEnum arch;
+ switch (arch_) {
+ case ARCH_ARM:
+ arch = unwindstack::ARCH_ARM;
+ break;
+ case ARCH_ARM64:
+ arch = unwindstack::ARCH_ARM64;
+ break;
+ case ARCH_X86:
+ arch = unwindstack::ARCH_X86;
+ break;
+ case ARCH_X86_64:
+ arch = unwindstack::ARCH_X86_64;
+ break;
+ default:
+ return false;
+ }
+
+ std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
+
+ return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_);
+}
+
+std::string UnwindStackOffline::GetFunctionNameRaw(uint64_t, uint64_t*) {
+ return "";
+}
+
+size_t UnwindStackOffline::Read(uint64_t, uint8_t*, size_t) {
+ return 0;
+}
+
+bool UnwindStackOffline::ReadWord(uint64_t, word_t*) {
+ return false;
+}
+
+Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
+ const std::vector<backtrace_map_t>& maps,
+ const backtrace_stackinfo_t& stack) {
+ BacktraceMap* map = BacktraceMap::CreateOffline(pid, maps, stack);
+ if (map == nullptr) {
+ return nullptr;
+ }
+
+ return new UnwindStackOffline(arch, pid, tid, map, false);
+}
+
+Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map) {
+ if (map == nullptr) {
+ return nullptr;
+ }
+ return new UnwindStackOffline(arch, pid, tid, map, true);
+}
+
+void Backtrace::SetGlobalElfCache(bool enable) {
+ unwindstack::Elf::SetCachingEnabled(enable);
+}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index 498ad4e..33c4282 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -34,7 +34,7 @@
std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
- bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
+ bool UnwindFromContext(size_t num_ignore_frames, void* ucontext) override;
};
class UnwindStackPtrace : public BacktracePtrace {
@@ -42,9 +42,9 @@
UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
virtual ~UnwindStackPtrace() = default;
- bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
+ bool Unwind(size_t num_ignore_frames, void* context) override;
- std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
+ std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
@@ -52,4 +52,20 @@
unwindstack::MemoryRemote memory_;
};
+class UnwindStackOffline : public Backtrace {
+ public:
+ UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map, bool map_shared);
+
+ bool Unwind(size_t num_ignore_frames, void* context) override;
+
+ std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
+
+ size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
+
+ bool ReadWord(uint64_t ptr, word_t* out_value) override;
+
+ private:
+ ArchEnum arch_;
+};
+
#endif // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 60c7952..97f8d78 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -26,11 +26,20 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
+#include "UnwindDexFile.h"
#include "UnwindStackMap.h"
//-------------------------------------------------------------------------
UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
+UnwindStackMap::~UnwindStackMap() {
+#ifndef NO_LIBDEXFILE
+ for (auto& entry : dex_files_) {
+ delete entry.second;
+ }
+#endif
+}
+
bool UnwindStackMap::Build() {
if (pid_ == 0) {
pid_ = getpid();
@@ -118,6 +127,63 @@
return process_memory_;
}
+#ifdef NO_LIBDEXFILE
+UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) {
+ return nullptr;
+}
+#else
+UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) {
+ // Lock while we get the data.
+ std::lock_guard<std::mutex> guard(dex_lock_);
+ UnwindDexFile* dex_file;
+ auto entry = dex_files_.find(dex_file_offset);
+ if (entry == dex_files_.end()) {
+ dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info);
+ dex_files_[dex_file_offset] = dex_file;
+ } else {
+ dex_file = entry->second;
+ }
+ return dex_file;
+}
+#endif
+
+UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
+
+bool UnwindStackOfflineMap::Build() {
+ return false;
+}
+
+bool UnwindStackOfflineMap::Build(const std::vector<backtrace_map_t>& backtrace_maps,
+ const backtrace_stackinfo_t& stack) {
+ if (stack.start >= stack.end) {
+ return false;
+ }
+
+ for (const backtrace_map_t& map : backtrace_maps) {
+ maps_.push_back(map);
+ }
+
+ std::sort(maps_.begin(), maps_.end(),
+ [](const backtrace_map_t& a, const backtrace_map_t& b) { return a.start < b.start; });
+
+ unwindstack::Maps* maps = new unwindstack::Maps;
+ stack_maps_.reset(maps);
+ for (const backtrace_map_t& map : maps_) {
+ maps->Add(map.start, map.end, map.offset, map.flags, map.name, map.load_bias);
+ }
+
+ // Create the process memory from the stack data.
+ uint64_t size = stack.end - stack.start;
+ unwindstack::MemoryBuffer* memory = new unwindstack::MemoryBuffer;
+ memory->Resize(size);
+ memcpy(memory->GetPtr(0), stack.data, size);
+ std::shared_ptr<unwindstack::Memory> shared_memory(memory);
+
+ process_memory_.reset(new unwindstack::MemoryRange(shared_memory, 0, size, stack.start));
+
+ return true;
+}
+
//-------------------------------------------------------------------------
// BacktraceMap create function.
//-------------------------------------------------------------------------
@@ -138,3 +204,16 @@
}
return map;
}
+
+//-------------------------------------------------------------------------
+// BacktraceMap create offline function.
+//-------------------------------------------------------------------------
+BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps,
+ const backtrace_stackinfo_t& stack) {
+ UnwindStackOfflineMap* map = new UnwindStackOfflineMap(pid);
+ if (!map->Build(maps, stack)) {
+ delete map;
+ return nullptr;
+ }
+ return map;
+}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 6b98809..be5c59e 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -21,15 +21,22 @@
#include <sys/types.h>
#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
+// Forward declarations.
+class UnwindDexFile;
+
class UnwindStackMap : public BacktraceMap {
public:
explicit UnwindStackMap(pid_t pid);
- ~UnwindStackMap() = default;
+ ~UnwindStackMap();
bool Build() override;
@@ -44,12 +51,28 @@
unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
+ UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info);
+
protected:
uint64_t GetLoadBias(size_t index) override;
std::unique_ptr<unwindstack::Maps> stack_maps_;
std::shared_ptr<unwindstack::Memory> process_memory_;
std::unique_ptr<unwindstack::JitDebug> jit_debug_;
+#ifndef NO_LIBDEXFILE
+ std::mutex dex_lock_;
+ std::unordered_map<uint64_t, UnwindDexFile*> dex_files_;
+#endif
+};
+
+class UnwindStackOfflineMap : public UnwindStackMap {
+ public:
+ UnwindStackOfflineMap(pid_t pid);
+ ~UnwindStackOfflineMap() = default;
+
+ bool Build() override;
+
+ bool Build(const std::vector<backtrace_map_t>& maps, const backtrace_stackinfo_t& stack);
};
#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index e2a7441..9877f29 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -15,9 +15,9 @@
*/
#include <inttypes.h>
-#include <libunwind.h>
#include <pthread.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
#include <functional>
@@ -44,33 +44,7 @@
int test_level_three(int, int, int, int, void (*)(void*), void*);
int test_level_four(int, int, int, int, void (*)(void*), void*);
int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(unw_context_t* unw_context, volatile int* exit_flag);
-}
-
-static ucontext_t GetUContextFromUnwContext(const unw_context_t& unw_context) {
- ucontext_t ucontext;
- memset(&ucontext, 0, sizeof(ucontext));
-#if defined(__arm__)
- ucontext.uc_mcontext.arm_r0 = unw_context.regs[0];
- ucontext.uc_mcontext.arm_r1 = unw_context.regs[1];
- ucontext.uc_mcontext.arm_r2 = unw_context.regs[2];
- ucontext.uc_mcontext.arm_r3 = unw_context.regs[3];
- ucontext.uc_mcontext.arm_r4 = unw_context.regs[4];
- ucontext.uc_mcontext.arm_r5 = unw_context.regs[5];
- ucontext.uc_mcontext.arm_r6 = unw_context.regs[6];
- ucontext.uc_mcontext.arm_r7 = unw_context.regs[7];
- ucontext.uc_mcontext.arm_r8 = unw_context.regs[8];
- ucontext.uc_mcontext.arm_r9 = unw_context.regs[9];
- ucontext.uc_mcontext.arm_r10 = unw_context.regs[10];
- ucontext.uc_mcontext.arm_fp = unw_context.regs[11];
- ucontext.uc_mcontext.arm_ip = unw_context.regs[12];
- ucontext.uc_mcontext.arm_sp = unw_context.regs[13];
- ucontext.uc_mcontext.arm_lr = unw_context.regs[14];
- ucontext.uc_mcontext.arm_pc = unw_context.regs[15];
-#else
- ucontext.uc_mcontext = unw_context.uc_mcontext;
-#endif
- return ucontext;
+void test_get_context_and_wait(void* context, volatile int* exit_flag);
}
struct FunctionSymbol {
@@ -108,18 +82,17 @@
return s;
}
-static void HexStringToRawData(const char* s, void* data, size_t size) {
- uint8_t* p = static_cast<uint8_t*>(data);
+static void HexStringToRawData(const char* s, std::vector<uint8_t>* data, size_t size) {
for (size_t i = 0; i < size; ++i) {
int value;
sscanf(s, "%02x", &value);
- *p++ = static_cast<uint8_t>(value);
+ data->push_back(value);
s += 2;
}
}
struct OfflineThreadArg {
- unw_context_t unw_context;
+ std::vector<uint8_t> ucontext;
pid_t tid;
volatile int exit_flag;
};
@@ -127,12 +100,12 @@
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
fn_arg->tid = gettid();
- test_get_context_and_wait(&fn_arg->unw_context, &fn_arg->exit_flag);
+ test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
return nullptr;
}
-std::string GetTestPath(std::string path) {
- return android::base::GetExecutableDirectory() + "/testdata/" + ABI_STRING + '/' + path;
+std::string GetTestPath(const std::string& arch, const std::string& path) {
+ return android::base::GetExecutableDirectory() + "/testdata/" + arch + '/' + path;
}
// This test is disable because it is for generating test data.
@@ -149,7 +122,7 @@
OfflineThreadArg arg;
arg.exit_flag = 0;
ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg));
- // Wait for the offline thread to generate the stack and unw_context information.
+ // Wait for the offline thread to generate the stack and context information.
sleep(1);
// Copy the stack information.
std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
@@ -179,9 +152,9 @@
entry->start, entry->end, entry->offset, entry->load_bias,
entry->flags, entry->name.c_str());
}
- // 3. Dump registers
- testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
- testdata += RawDataToHexString(&arg.unw_context, sizeof(arg.unw_context));
+ // 3. Dump ucontext
+ testdata += android::base::StringPrintf("ucontext: %zu ", arg.ucontext.size());
+ testdata += RawDataToHexString(arg.ucontext.data(), arg.ucontext.size());
testdata.push_back('\n');
// 4. Dump stack
@@ -218,7 +191,7 @@
int pid;
int tid;
std::vector<backtrace_map_t> maps;
- unw_context_t unw_context;
+ std::vector<uint8_t> ucontext;
backtrace_stackinfo_t stack_info;
std::vector<uint8_t> stack;
std::vector<FunctionSymbol> symbols;
@@ -231,7 +204,6 @@
}
// Parse offline_testdata.
std::vector<std::string> lines = android::base::Split(s, "\n");
- memset(&testdata->unw_context, 0, sizeof(testdata->unw_context));
for (const auto& line : lines) {
if (android::base::StartsWith(line, "pid:")) {
sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
@@ -244,50 +216,12 @@
" flags: %d name: %n",
&map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
map.name = android::base::Trim(line.substr(pos));
- } else if (android::base::StartsWith(line, "registers:")) {
+ } else if (android::base::StartsWith(line, "ucontext:")) {
size_t size;
int pos;
- sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
- if (sizeof(testdata->unw_context) != size) {
- return false;
- }
- HexStringToRawData(&line[pos], &testdata->unw_context, size);
- } else if (android::base::StartsWith(line, "regs:")) {
- std::vector<std::string> strs = android::base::Split(line.substr(6), " ");
- if (strs.size() % 2 != 0) {
- return false;
- }
- std::vector<std::pair<std::string, uint64_t>> items;
- for (size_t i = 0; i + 1 < strs.size(); i += 2) {
- if (!android::base::EndsWith(strs[i], ":")) {
- return false;
- }
- uint64_t value = std::stoul(strs[i + 1], nullptr, 16);
- items.push_back(std::make_pair(strs[i].substr(0, strs[i].size() - 1), value));
- }
-#if defined(__arm__)
- for (auto& item : items) {
- if (item.first == "sp") {
- testdata->unw_context.regs[13] = item.second;
- } else if (item.first == "pc") {
- testdata->unw_context.regs[15] = item.second;
- } else {
- return false;
- }
- }
-#elif defined(__aarch64__)
- for (auto& item : items) {
- if (item.first == "pc") {
- testdata->unw_context.uc_mcontext.pc = item.second;
- } else if (item.first == "sp") {
- testdata->unw_context.uc_mcontext.sp = item.second;
- } else if (item.first == "x29") {
- testdata->unw_context.uc_mcontext.regs[UNW_AARCH64_X29] = item.second;
- } else {
- return false;
- }
- }
-#endif
+ testdata->ucontext.clear();
+ sscanf(line.c_str(), "ucontext: %zu %n", &size, &pos);
+ HexStringToRawData(&line[pos], &testdata->ucontext, size);
} else if (android::base::StartsWith(line, "stack:")) {
size_t size;
int pos;
@@ -295,8 +229,8 @@
"stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
&testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
CHECK_EQ(testdata->stack_info.end - testdata->stack_info.start, size);
- testdata->stack.resize(size);
- HexStringToRawData(&line[pos], &testdata->stack[0], size);
+ testdata->stack.clear();
+ HexStringToRawData(&line[pos], &testdata->stack, size);
testdata->stack_info.data = testdata->stack.data();
} else if (android::base::StartsWith(line, "function:")) {
testdata->symbols.resize(testdata->symbols.size() + 1);
@@ -310,17 +244,11 @@
return true;
}
-static void BacktraceOfflineTest(const char* arch, const std::string& testlib_name) {
- // TODO: For now, we can only run this on the same arch as the library arch.
- if (std::string(ABI_STRING) != arch) {
- GTEST_LOG_(INFO) << "Ignoring arch " << arch << " for lib " << testlib_name;
- return;
- }
-
- const std::string testlib_path(GetTestPath(testlib_name));
- const std::string offline_testdata_path(GetTestPath("offline_testdata"));
+static void BacktraceOfflineTest(std::string arch_str, const std::string& testlib_name) {
+ const std::string testlib_path(GetTestPath(arch_str, testlib_name));
+ const std::string offline_testdata_path(GetTestPath(arch_str, "offline_testdata"));
OfflineTestData testdata;
- ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+ ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata)) << "Failed " << arch_str;
// Fix path of libbacktrace_testlib.so.
for (auto& map : testdata.maps) {
@@ -329,16 +257,24 @@
}
}
- // Do offline backtrace.
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
- ASSERT_TRUE(map != nullptr);
+ Backtrace::ArchEnum arch;
+ if (arch_str == "arm") {
+ arch = Backtrace::ARCH_ARM;
+ } else if (arch_str == "arm64") {
+ arch = Backtrace::ARCH_ARM64;
+ } else if (arch_str == "x86") {
+ arch = Backtrace::ARCH_X86;
+ } else if (arch_str == "x86_64") {
+ arch = Backtrace::ARCH_X86_64;
+ } else {
+ abort();
+ }
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
- ASSERT_TRUE(backtrace != nullptr);
+ std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
+ arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
+ ASSERT_TRUE(backtrace != nullptr) << "Failed " << arch_str;
- ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
- ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+ ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data())) << "Failed " << arch_str;
// Collect pc values of the call stack frames.
std::vector<uint64_t> pc_values;
@@ -354,14 +290,17 @@
}
}
- ASSERT_GE(test_one_index, 3u);
- ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols));
- ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1],
- testdata.symbols));
- ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2],
- testdata.symbols));
- ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3],
- testdata.symbols));
+ ASSERT_GE(test_one_index, 3u) << "Failed " << arch_str;
+ ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols))
+ << "Failed " << arch_str;
+ ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], testdata.symbols))
+ << "Failed " << arch_str;
+ ASSERT_EQ("test_level_three",
+ FunctionNameForAddress(pc_values[test_one_index - 2], testdata.symbols))
+ << "Failed " << arch_str;
+ ASSERT_EQ("test_level_four",
+ FunctionNameForAddress(pc_values[test_one_index - 3], testdata.symbols))
+ << "Failed " << arch_str;
}
// For now, these tests can only run on the given architectures.
@@ -384,18 +323,13 @@
BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
}
-static void LibUnwindingTest(const std::string& arch, const std::string& testdata_name,
+static void LibUnwindingTest(const std::string& arch_str, const std::string& testdata_name,
const std::string& testlib_name) {
- if (std::string(ABI_STRING) != arch) {
- GTEST_LOG_(INFO) << "Skipping test since offline for arm on " << ABI_STRING
- << " isn't supported.";
- return;
- }
- const std::string testlib_path(GetTestPath(testlib_name));
+ const std::string testlib_path(GetTestPath(arch_str, testlib_name));
struct stat st;
ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
- const std::string offline_testdata_path(GetTestPath(testdata_name));
+ const std::string offline_testdata_path(GetTestPath(arch_str, testdata_name));
OfflineTestData testdata;
ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
@@ -406,26 +340,35 @@
}
}
- // Do offline backtrace.
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
- ASSERT_TRUE(map != nullptr);
+ Backtrace::ArchEnum arch;
+ if (arch_str == "arm") {
+ arch = Backtrace::ARCH_ARM;
+ } else if (arch_str == "arm64") {
+ arch = Backtrace::ARCH_ARM64;
+ } else if (arch_str == "x86") {
+ arch = Backtrace::ARCH_X86;
+ } else if (arch_str == "x86_64") {
+ arch = Backtrace::ARCH_X86_64;
+ } else {
+ ASSERT_TRUE(false) << "Unsupported arch " << arch_str;
+ abort();
+ }
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+ // Do offline backtrace.
+ std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
+ arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
ASSERT_TRUE(backtrace != nullptr);
- ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
- ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+ ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data()));
ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
- uint64_t vaddr_in_file =
- backtrace->GetFrame(i)->pc - testdata.maps[0].start + testdata.maps[0].load_bias;
- std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+ std::string name = FunctionNameForAddress(backtrace->GetFrame(i)->rel_pc, testdata.symbols);
ASSERT_EQ(name, testdata.symbols[i].name);
}
ASSERT_TRUE(backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED ||
- backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING);
+ backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING ||
+ backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_REPEATED_FRAME);
}
// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 10152f7..aab6db9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
+#include <ucontext.h>
#include <unistd.h>
#include <algorithm>
@@ -143,6 +144,17 @@
ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
}
+#if !defined(__ANDROID__) || defined(__arm__)
+// On host and arm target we aren't guaranteed that we will terminate cleanly.
+#define VERIFY_NO_ERROR(error_code) \
+ ASSERT_TRUE(error_code == BACKTRACE_UNWIND_NO_ERROR || \
+ error_code == BACKTRACE_UNWIND_ERROR_UNWIND_INFO || \
+ error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING) \
+ << "Unknown error code " << std::to_string(error_code);
+#else
+#define VERIFY_NO_ERROR(error_code) ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, error_code);
+#endif
+
static bool ReadyLevelBacktrace(Backtrace* backtrace) {
// See if test_level_four is in the backtrace.
bool found = false;
@@ -189,7 +201,7 @@
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
VerifyLevelDump(backtrace.get());
}
@@ -211,7 +223,7 @@
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
VerifyMaxDump(backtrace.get());
}
@@ -241,7 +253,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
ASSERT_TRUE(backtrace->NumFrames() != 0);
for (const auto& frame : *backtrace ) {
@@ -292,19 +304,19 @@
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(all.get() != nullptr);
ASSERT_TRUE(all->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError().error_code);
+ VERIFY_NO_ERROR(all->GetError().error_code);
std::unique_ptr<Backtrace> ign1(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(ign1.get() != nullptr);
ASSERT_TRUE(ign1->Unwind(1));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code);
+ VERIFY_NO_ERROR(ign1->GetError().error_code);
std::unique_ptr<Backtrace> ign2(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(ign2.get() != nullptr);
ASSERT_TRUE(ign2->Unwind(2));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code);
+ VERIFY_NO_ERROR(ign2->GetError().error_code);
VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
}
@@ -340,7 +352,6 @@
std::unique_ptr<Backtrace> backtrace(create_func(pid, tid, map.get()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
if (ReadyFunc(backtrace.get())) {
VerifyFunc(backtrace.get(), create_func, map_create_func);
verified = true;
@@ -389,12 +400,12 @@
std::unique_ptr<Backtrace> ign1(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
ASSERT_TRUE(ign1.get() != nullptr);
ASSERT_TRUE(ign1->Unwind(1));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code);
+ VERIFY_NO_ERROR(ign1->GetError().error_code);
std::unique_ptr<Backtrace> ign2(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
ASSERT_TRUE(ign2.get() != nullptr);
ASSERT_TRUE(ign2->Unwind(2));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code);
+ VERIFY_NO_ERROR(ign2->GetError().error_code);
VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
}
@@ -480,7 +491,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
VerifyLevelDump(backtrace.get());
}
@@ -493,7 +504,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
VerifyMaxDump(backtrace.get());
}
@@ -535,7 +546,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
VerifyLevelDump(backtrace.get());
@@ -575,17 +586,17 @@
std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(all.get() != nullptr);
ASSERT_TRUE(all->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError().error_code);
+ VERIFY_NO_ERROR(all->GetError().error_code);
std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(ign1.get() != nullptr);
ASSERT_TRUE(ign1->Unwind(1));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code);
+ VERIFY_NO_ERROR(ign1->GetError().error_code);
std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(ign2.get() != nullptr);
ASSERT_TRUE(ign2->Unwind(2));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code);
+ VERIFY_NO_ERROR(ign2->GetError().error_code);
VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr);
@@ -616,7 +627,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
VerifyMaxDump(backtrace.get());
@@ -713,21 +724,21 @@
Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
ASSERT_TRUE(back1 != nullptr);
EXPECT_TRUE(back1->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back1->GetError().error_code);
+ VERIFY_NO_ERROR(back1->GetError().error_code);
delete back1;
delete map1;
Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
ASSERT_TRUE(back2 != nullptr);
EXPECT_TRUE(back2->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back2->GetError().error_code);
+ VERIFY_NO_ERROR(back2->GetError().error_code);
delete back2;
delete map2;
Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
ASSERT_TRUE(back3 != nullptr);
EXPECT_TRUE(back3->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back3->GetError().error_code);
+ VERIFY_NO_ERROR(back3->GetError().error_code);
delete back3;
delete map3;
}
@@ -991,7 +1002,7 @@
uint8_t* expected = new uint8_t[pagesize];
InitMemory(expected, pagesize);
- uint8_t* data = new uint8_t[2*pagesize];
+ uint8_t* data = new uint8_t[2 * pagesize];
// Verify that we can only read one page worth of data.
size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
ASSERT_EQ(pagesize, bytes_read);
@@ -1042,8 +1053,10 @@
ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
}
+// The code requires these variables are the same size.
volatile uint64_t g_ready = 0;
volatile uint64_t g_addr = 0;
+static_assert(sizeof(g_ready) == sizeof(g_addr), "g_ready/g_addr must be same size");
static void ForkedReadTest() {
// Create two map pages.
@@ -1091,13 +1104,13 @@
uint64_t read_addr;
size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
- ASSERT_EQ(sizeof(uint64_t), bytes_read);
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_ready));
+ ASSERT_EQ(sizeof(g_ready), bytes_read);
if (read_addr) {
// The forked process is ready to be read.
bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
- ASSERT_EQ(sizeof(uint64_t), bytes_read);
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_addr));
+ ASSERT_EQ(sizeof(g_addr), bytes_read);
RunReadTest(backtrace.get(), read_addr);
@@ -1176,7 +1189,7 @@
int fd = open(tmp_so_name, O_RDONLY);
ASSERT_TRUE(fd != -1);
- void* map = mmap(NULL, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
+ void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
ASSERT_TRUE(map != MAP_FAILED);
close(fd);
ASSERT_TRUE(unlink(tmp_so_name) != -1);
@@ -1225,7 +1238,7 @@
exit(0);
}
- void* map = mmap(NULL, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
+ void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
unlink(tmp_so_name);
@@ -1258,11 +1271,11 @@
ASSERT_TRUE(backtrace.get() != nullptr);
uint64_t read_addr;
- ASSERT_EQ(sizeof(uint64_t),
+ ASSERT_EQ(sizeof(g_ready),
backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_ready)));
if (read_addr) {
- ASSERT_EQ(sizeof(uint64_t),
+ ASSERT_EQ(sizeof(g_addr),
backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
@@ -1328,15 +1341,16 @@
}
static void VerifyUnreadableElfBacktrace(void* func) {
- uint64_t test_func = reinterpret_cast<uint64_t>(func);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
size_t frame_num;
- ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
+ uint64_t test_func = reinterpret_cast<uint64_t>(func);
+ ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num))
+ << DumpFrames(backtrace.get());
VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
}
@@ -1390,7 +1404,7 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
size_t frame_num;
if (FindFuncFrameInBacktrace(backtrace.get(), reinterpret_cast<uint64_t>(test_func),
@@ -1786,7 +1800,7 @@
Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
delete backtrace;
}
size_t stable_pss = GetPssBytes();
@@ -1797,7 +1811,7 @@
Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
+ VERIFY_NO_ERROR(backtrace->GetError().error_code);
delete backtrace;
}
size_t new_pss = GetPssBytes();
diff --git a/libbacktrace/backtrace_testlib.cpp b/libbacktrace/backtrace_testlib.cpp
index 3081d64..fec7d98 100644
--- a/libbacktrace/backtrace_testlib.cpp
+++ b/libbacktrace/backtrace_testlib.cpp
@@ -14,9 +14,15 @@
* limitations under the License.
*/
-#include <libunwind.h>
#include <signal.h>
#include <stdio.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
#include "backtrace_testlib.h"
@@ -66,21 +72,70 @@
}
typedef struct {
- unw_context_t* unw_context;
+ std::vector<uint8_t>* ucontext;
volatile int* exit_flag;
} GetContextArg;
static void GetContextAndExit(void* data) {
- GetContextArg* arg = (GetContextArg*)data;
- unw_getcontext(arg->unw_context);
+ GetContextArg* arg = reinterpret_cast<GetContextArg*>(data);
+
+ std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+ unwindstack::RegsGetLocal(regs.get());
+
+ ucontext_t ucontext;
+ memset(&ucontext, 0, sizeof(ucontext));
+#if defined(__arm__)
+ memcpy(&ucontext.uc_mcontext, regs->RawData(), sizeof(uint32_t) * 16);
+#elif defined(__aarch64__)
+ memcpy(&ucontext.uc_mcontext, regs->RawData(), sizeof(uint64_t) * 33);
+#elif defined(__i386__)
+ uint32_t* reg_data = reinterpret_cast<uint32_t*>(regs->RawData());
+ ucontext.uc_mcontext.gregs[0] = reg_data[15];
+ ucontext.uc_mcontext.gregs[1] = reg_data[14];
+ ucontext.uc_mcontext.gregs[2] = reg_data[13];
+ ucontext.uc_mcontext.gregs[3] = reg_data[12];
+ ucontext.uc_mcontext.gregs[4] = reg_data[7];
+ ucontext.uc_mcontext.gregs[5] = reg_data[6];
+ ucontext.uc_mcontext.gregs[6] = reg_data[5];
+ ucontext.uc_mcontext.gregs[7] = reg_data[4];
+ ucontext.uc_mcontext.gregs[8] = reg_data[3];
+ ucontext.uc_mcontext.gregs[9] = reg_data[2];
+ ucontext.uc_mcontext.gregs[10] = reg_data[1];
+ ucontext.uc_mcontext.gregs[11] = reg_data[0];
+ ucontext.uc_mcontext.gregs[14] = reg_data[8];
+ ucontext.uc_mcontext.gregs[15] = reg_data[10];
+#elif defined(__x86_64__)
+ uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+ ucontext.uc_mcontext.gregs[0] = reg_data[8];
+ ucontext.uc_mcontext.gregs[1] = reg_data[9];
+ ucontext.uc_mcontext.gregs[2] = reg_data[10];
+ ucontext.uc_mcontext.gregs[3] = reg_data[11];
+ ucontext.uc_mcontext.gregs[4] = reg_data[12];
+ ucontext.uc_mcontext.gregs[5] = reg_data[13];
+ ucontext.uc_mcontext.gregs[6] = reg_data[14];
+ ucontext.uc_mcontext.gregs[7] = reg_data[15];
+ ucontext.uc_mcontext.gregs[8] = reg_data[5];
+ ucontext.uc_mcontext.gregs[9] = reg_data[4];
+ ucontext.uc_mcontext.gregs[10] = reg_data[6];
+ ucontext.uc_mcontext.gregs[11] = reg_data[3];
+ ucontext.uc_mcontext.gregs[12] = reg_data[1];
+ ucontext.uc_mcontext.gregs[13] = reg_data[0];
+ ucontext.uc_mcontext.gregs[14] = reg_data[2];
+ ucontext.uc_mcontext.gregs[15] = reg_data[7];
+ ucontext.uc_mcontext.gregs[16] = reg_data[16];
+#endif
+
+ arg->ucontext->resize(sizeof(ucontext));
+ memcpy(arg->ucontext->data(), &ucontext, sizeof(ucontext));
+
// Don't touch the stack anymore.
while (*arg->exit_flag == 0) {
}
}
-void test_get_context_and_wait(unw_context_t* unw_context, volatile int* exit_flag) {
+void test_get_context_and_wait(void* ucontext, volatile int* exit_flag) {
GetContextArg arg;
- arg.unw_context = unw_context;
+ arg.ucontext = reinterpret_cast<std::vector<uint8_t>*>(ucontext);
arg.exit_flag = exit_flag;
test_level_one(1, 2, 3, 4, GetContextAndExit, &arg);
}
diff --git a/libbacktrace/backtrace_testlib.h b/libbacktrace/backtrace_testlib.h
index 16fedc4..9b55e56 100644
--- a/libbacktrace/backtrace_testlib.h
+++ b/libbacktrace/backtrace_testlib.h
@@ -19,8 +19,6 @@
#include <sys/cdefs.h>
-#include <libunwind.h>
-
__BEGIN_DECLS
void test_loop_forever();
@@ -31,7 +29,7 @@
int test_level_two(int, int, int, int, void (*)(void*), void*);
int test_level_one(int, int, int, int, void (*)(void*), void*);
int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(unw_context_t*, volatile int*);
+void test_get_context_and_wait(void*, volatile int*);
__END_DECLS
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 1b8ad19..7a37015 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -60,6 +60,10 @@
BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED,
// Failed to execute dwarf instructions in debug sections.
BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED,
+ // Unwind information is incorrect.
+ BACKTRACE_UNWIND_ERROR_UNWIND_INFO,
+ // Unwind information stopped due to sp/pc repeating.
+ BACKTRACE_UNWIND_ERROR_REPEATED_FRAME,
};
struct BacktraceUnwindError {
@@ -81,21 +85,12 @@
uint64_t rel_pc; // The relative pc.
uint64_t sp; // The top of the stack.
size_t stack_size; // The size of the stack, zero indicate an unknown stack size.
- uint64_t dex_pc; // If non-zero, the Dex PC for the ART interpreter.
backtrace_map_t map; // The map associated with the given pc.
std::string func_name; // The function name associated with this pc, NULL if not found.
uint64_t func_offset; // pc relative to the start of the function, only valid if func_name is not
// NULL.
};
-#if defined(__APPLE__)
-struct __darwin_ucontext;
-typedef __darwin_ucontext ucontext_t;
-#else
-struct ucontext;
-typedef ucontext ucontext_t;
-#endif
-
struct backtrace_stackinfo_t {
uint64_t start;
uint64_t end;
@@ -107,7 +102,16 @@
}
class Backtrace {
-public:
+ public:
+ enum ArchEnum : uint8_t {
+ ARCH_ARM,
+ ARCH_ARM64,
+ ARCH_X86,
+ ARCH_X86_64,
+ };
+
+ static void SetGlobalElfCache(bool enable);
+
// Create the correct Backtrace object based on what is to be unwound.
// If pid < 0 or equals the current pid, then the Backtrace object
// corresponds to the current process.
@@ -121,6 +125,16 @@
static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
// Create an offline Backtrace object that can be used to do an unwind without a process
+ // that is still running. By default, information is only cached in the map
+ // file. If the calling code creates the map, data can be cached between
+ // unwinds. If not, all cached data will be destroyed when the Backtrace
+ // object is destroyed.
+ static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
+ const std::vector<backtrace_map_t>& maps,
+ const backtrace_stackinfo_t& stack);
+ static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map);
+
+ // Create an offline Backtrace object that can be used to do an unwind without a process
// that is still running. If cache_file is set to true, then elf information will be cached
// for this call. The cached information survives until the calling process ends. This means
// that subsequent calls to create offline Backtrace objects will continue to use the same
@@ -131,11 +145,11 @@
virtual ~Backtrace();
// Get the current stack trace and store in the backtrace_ structure.
- virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
+ virtual bool Unwind(size_t num_ignore_frames, void* context = NULL) = 0;
static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
- std::vector<std::string>* skip_names);
+ std::vector<std::string>* skip_names, BacktraceUnwindError* error = nullptr);
// Get the function name and offset into the function given the pc.
// If the string is empty, then no valid function name was found,
@@ -185,7 +199,7 @@
std::string GetErrorString(BacktraceUnwindError error);
-protected:
+ protected:
Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);
// The name returned is not demangled, GetFunctionName() takes care of
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 4d020e6..e19c413 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -34,6 +34,9 @@
#include <string>
#include <vector>
+// Forward declaration.
+struct backtrace_stackinfo_t;
+
// Special flag to indicate a map is in /dev/. However, a map in
// /dev/ashmem/... does not set this flag.
static constexpr int PROT_DEVICE_MAP = 0x8000;
@@ -58,7 +61,8 @@
// is unsupported.
static BacktraceMap* Create(pid_t pid, bool uncached = false);
- static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
+ static BacktraceMap* CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps,
+ const backtrace_stackinfo_t& stack);
virtual ~BacktraceMap();
diff --git a/libbacktrace/testdata/arm/offline_testdata b/libbacktrace/testdata/arm/offline_testdata
index 6acea29..d5b8f47 100644
--- a/libbacktrace/testdata/arm/offline_testdata
+++ b/libbacktrace/testdata/arm/offline_testdata
@@ -93,7 +93,7 @@
map: start: e8813000 end: e8815000 offset: 0 load_bias: 0 flags: 3 name:
map: start: ff886000 end: ff8a9000 offset: 0 load_bias: 0 flags: 3 name: [stack]
map: start: ffff0000 end: ffff1000 offset: 0 load_bias: 0 flags: 5 name: [vectors]
-registers: 64 34868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee7
+ucontext: 104 000000000000000000000000000000000000000000000000000000000000000034868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee70000000000000000
stack: start: e8715000 end: e8719000 size: 16384 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc8871e87dba6ee734868affdc8871e8dc8871e85dba6ee7070000000e000000150000001c000000dc8871e85dba6ee71c000000150000000e00000007000000100000000c0000000800000004000000ddb86ee75dba6ee7dc8871e804000000080000000c00000010000000dc8871e85dba6ee7100000000c000000080000000400000008000000060000000400000002000000288871e835b96ee75dba6ee7dc8871e802000000040000000600000008000000dc8871e85dba6ee70800000006000000040000000200000004000000030000000200000001000000708871e88db96ee75dba6ee7dc8871e801000000020000000300000004000000dc8871e85dba6ee70400000003000000020000000100000004000000208971e8208971e878000000e87d00003dba6ee75dba6ee7dc8871e878000000c5807ce7fc7183e734868aff78868aff78868aff34868aff34868aff78868affe0879437208971e84154d2aa0020000034868aff34868aff34868aff78000000c9b87ee7b1b87ee7a3f47be7288971e8b1b87ee7208971e800000000f83481e800000000e97d0000e87d000000000000005071e82039000000100000000000000000000000000000000000002354d2aa34868aff00000000002071e801000000000000000000000000000000708971e8208971e8000000000000000000000000e0879437000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
function: start: 0 end: e76eb835 name: unknown_start
function: start: e76eb835 end: e76eb88d name: test_level_four
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
index 1f96834..d7c186e 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
@@ -1,6 +1,6 @@
pid: 7288 tid: 31656
-regs: pc: cc416235 sp: cc17f000
+ucontext: 104 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f017cc00000000356241cc0000000000000000
map: start: cc361000 end: cc758000 offset: 0 load_bias: 9000 flags: 5 name: /vendor/lib/egl/libGLESv2_adreno.so
-stack: start: cc17f254 end: cc17f258 size: 4 b36141cc
+stack: start: cc17f234 end: cc17f258 size: 36 0000000000000000000000000000000000000000000000000000000000000000b36141cc
function: start: be1f0 end: be304 name: EsxContext::Clear(unsigned int, unsigned int, unsigned int, EsxClearValues*)
function: start: be058 end: be1f0 name: EsxContext::ClearBuffersForDebug()
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
index a12bc3c..54f3525 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
@@ -1,6 +1,6 @@
pid: 7288 tid: 31656
-regs: pc: f1f6dc49 sp: d8fe6930
+ucontext: 104 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003069fed80000000049dcf6f10000000000000000
map: start: f1f10000 end: f2049000 offset: 0 load_bias: 10000 flags: 5 name: /system/lib/libandroid_runtime.so
-stack: start: d8fe6954 end: d8fe6958 size: 4 e7dcf6f1
+stack: start: d8fe6948 end: d8fe6958 size: 16 000000000000000000000000e7dcf6f1
function: start: 6dbf9 end: 6dce5 name: android::AndroidRuntime::javaThreadShell
function: start: 6dce5 end: 6dd79 name: android::AndroidRuntime::javaCreateThreadEtc
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
index db9bf8d..c1369ff 100644
--- a/libbacktrace/testdata/arm/offline_testdata_for_libart
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -1,5 +1,5 @@
pid: 32232 tid: 32233
-registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
+ucontext: 104 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e90000000000000000
map: start: e9380000 end: e9766000 offset: 0 load_bias: b000 flags: 5 name: /system/lib/libart.so
stack: start: ffd12dc0 end: ffd1306c size: 684 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d89524
function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
diff --git a/libbacktrace/testdata/arm64/offline_testdata b/libbacktrace/testdata/arm64/offline_testdata
index 75a2f12..cee9f72 100644
--- a/libbacktrace/testdata/arm64/offline_testdata
+++ b/libbacktrace/testdata/arm64/offline_testdata
@@ -95,7 +95,7 @@
map: start: 70160e4000 end: 70160e5000 offset: 0 load_bias: 0 flags: 1 name:
map: start: 70160e5000 end: 70160e8000 offset: 0 load_bias: 0 flags: 3 name:
map: start: 7fd8baf000 end: 7fd8be6000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-registers: 4560 679a0b1670000000f3eb6d705500000090f56e7055000000000000000000000000206f705500000014e0677055000000d038bed87f0000004cde67705500000041000000000000001900000000000000c00f241470000000d3aec914588f4bcd0400000000000000e493af157000000090f56e7055000000060000000000000023c00b1670000000b1d1fd15700000003039bed87f000000c898041670000000304cbed87f000000b8130e1670000000303cbed87f000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000003003167000000001000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000033000000000000000300000000000000003303167000000008330316700000000000000006000000f8320316700000005839bed87f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000c84cbed87f000000e84cbed87f000000984dbed87f00000078170e167000000002fd0000000000001400000000000000ff8100000100000000000000000000000000000000000000000000000000000078145700000000000010000000000000902b000000000000bdd04058000000000000000000000000bdd04058000000000000000000000000ccb58a560000000042487408000000000000000000000000cc57041670000000004704167000000010c0fd157000000010c0fd157000000090c0fd15700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000002f48bed87f000000d3aec914588f4bcd2045bed87f0000002045bed87f0000002f48bed87f00000001000000000000002f000080000000005045bed87f0000000045bed87f000000c0a0c315700000006045bed87f0000006045bed87f000000010000000000000001000000000000000344bed87f00000001000000100000009c3fbed87f0000009b3fbed87f0000000344bed87f0000009a3fbed87f0000000100000000000000953fbed87f0000004344bed80100000001000000010000002c48bed87f0000000444bed87f0000004344bed80100000000000000000000000100000000000000b03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd000000000100000000000000000000000100000000000000f03fbed87f000000000000000200000000000000000000000000000000000000d3aec914588f4bcd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03fbed87f0000000000000000000000000000000000000000000000000000000000000000000000d3aec914588f4bcd08226f70550000000000000000000000000000000000000000000000000000001048bed87f0000008047bed87f0000006047bed87f000000e0ffffff80ffffff03000000000000000000000000000000891d6e7055000000d3aec914588f4bcd5047bed87f0000005047bed87f000000861d6e705500000003000000000000002f00008000000000f0a6ca15700000004047bed87f000000c0a0c31570000000891d6e7055000000d3aec914000000000100000000000000a047bed800000000f9006e70550000000100000000000000dc41bed87f000000db41bed87f0000004346bed87f000000da41bed87f0000000100000000000000d541bed87f00000001000000010000000100000001000000861d6e70550000004446bed87f0000002c42bed80300000000000000000000000100000000000000f041bed87f0000009b1e6e700100000000000000000000000000000000000000d3aec914588f4bcd8e1e6e70550000000d000000000000002f00008000000000f0a6ca15700000003048bed87f000000c0a0c31570000000661e6e700100000000000000000000002f000000000000001000000000000000e21e6e7055000000d3aec914588f4bcdb048bed87f000000b048bed87f000000e21e6e70550000002f000000000000002f00008000000000f0a6ca1570000000a048bed87f000000c0a0c315700000008e1e6e7055000000000000000000000022000000000000000000000000000000205827147000000022000000000000003c43bed87f0000003b43bed87f000000a347bed87f0000003a43bed87f00000001000000000000003543bed87f000000f048bed8010000000100000001000000dd1e6e7055000000a447bed87f0000008c43bed82f000000000000000000000001000000000000005043bed87f000000861d6e700300000000000000000000000000000000000000d3aec914588f4bcd721e6e7055000000f447bed87f000000981123141800000000000000000000000100000000000000a043bed87f000000861d6e70030000000000000000000000d042bed87f0000000000000000000000981123147000000098112314700000009811231470000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000504abed87f000000b049bed87f0000008049bed87f00000000000000000000004043bed87f0000000000000000000000991123147000000000000000000000008e1e6e70550000000d00000000000000a04abed87f000000000000000000000000000000000000000000000000000000504abed87f000000e049bed87f000000a049bed87f000000c8ffffff80ffffff591e6e70550000000d0000000000000098112314700000000000000000000000df1e6e7055000000010000000000000020582714700000002200000000000000f049bed87f000000c8ffffff80ffffff9811231470000000980023147000000098112314700000009811231470000000741e6e7055000000060000000000000009f12914700000000c00000000000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b149bed87f000000b149bed87f000000f049be317f000000f049bed87f000000f049bed87f000000b149bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000b049bed87f000000f149bed87f000000f049bed87f000000d3aec914588f4bcdfcb58a56000000006cbb687055000000160000000000000098112314700000009911231470000000991123147000000098112314700000009911231470000000fcb58a5600000000010000000000000000000000000000000100000000000000604a050000000000e845bed87f0000006048bed87f000000a046bed87f00000017000000000000002c48bed87f0000009046bed87f000000ac73c515700000009911231470000000d3aec914588f4bcd1048bed87f0000008047bed87f0000006047bed87f000000e8ffffff80ffffffffffffffffffffff99112314700000006148bed87f000000981123141500000008020000ffffffff6048bed87f000000160000000000000058112314700000001700000000000000a849bed87f0000000000000000000000284abed87f0000001700000000000000284abed87f000000284abed87f000000d249bed87f00000001000000000000009a112314700000001600000000000000284abed87f000000ffffffffffffffff284abed87f000000284abed87f000000284abed87f000000284abed87f0000001700000000000000ffffffffffffffff284abed87f000000284abed87f000000ff49bed87f000000284abed87f00000000000000000000000000000000000000d049bed87f000000d049bed87f000000004abed87f000000d049bed87f0000000100000000000000d049bed87f000000d049bed87f000000d049bed87f00000017000000000000000100000000000000ffffffffffffffff991123147000000001000000000000003448bed87f0000009911231470000000b0ca687055000000ffffffffffffffff010000000000000099112314700000007047bed87f000000d3aec914588f4bcdfcb58a56000000000100000000000000000000000000000050226f70550000000000000000000000b44b05000000000000102a1470000000861d6e70550000000300000000000000f0a6ca1570000000a047bed87f0000006c79c31570000000f048bed87f0000008048bed87f0000004048bed87f000000c8ffffff80ffffff0000000000000000d3aec914588f4bcdf849bed87f000000f0a6ca15700000000200000000000000085b0e1670000000e048bed87f0000002c6fc515700000009048bed87f000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a89912314700000000000000000000000e9216f70550000008991231470000000e449bed87f0000008991231470000000000000000000000000000000000000008891231470000000899123147000000089912314700000008891231470000000170000000000000088912314700000008891231470000000d3aec914588f4bcd899123147000000016000000000000000000000000000000e9216f705500000088912314700000008891231470000000889123147000000088912314700000008891231470000000f0a6ca15700000000049bed87f0000006c79c31570000000889123147000000088912314700000008891231470000000889123147000000088912314700000008891231470000000889123147000000089912314700000008991231470000000085b0e1670000000404abed87f0000002c6fc51570000000c80a6f7055000000d3aec914588f4bcd0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a3b3325736d001b5b6d002c20776865726520002573203d202573000a526570650000000000000000000000000000000000000000000000008891231470000000000000000000000088912314700000008891231470000000889123147000000088912314700000000000000000000000889123147000000088912314700000008891231470000000470000000000000000502a1470000000d3aec914588f4bcdf05727147000000000b2221470000000604abed87f0000005c716c7055000000fcb58a56000000007c706c7055000000fcb58a5600000000ea4b050000000000
+ucontext: 464 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000
stack: start: 7015fd3000 end: 7015fd7000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000004038bed87f000000b863fd1570000000b863fd1570000000b863fd1570000000ec59cf15700000001c000000150000000e000000070000003063fd15700000001c58cf1570000000b863fd1570000000ec59cf1570000000100000000c00000008000000040000006063fd15700000007c58cf1570000000b863fd1570000000ec59cf1570000000080000000600000004000000020000009063fd1570000000dc58cf1570000000b863fd1570000000ec59cf157000000004000000030000000200000001000000d063fd1570000000c459cf15700000000100000000000000144abed87f0000004038bed87f0000004038bed87f000000144abed87f000000d3aec914588f4bcd1064fd157000000074fd6770550000004038bed87f0000004038bed87f000000ec84c41570000000e484c41570000000c484c4157000000000000000000000004064fd15700000004015c01570000000b67e0000000000000000000000000000705a0e1670000000185b0e167000000000000000000000000000000000000000705a0e16700000000000000000000000b77e0000b67e000000000000550000000030fd157000000050340000000000000010000000000000000000000000000000b222147000000000102a14700000000000000000000000000000000000000040fd6770550000004038bed87f000000000000000000000000a0fa1570000000010000000000000000000000000000000000000000000000e864fd15700000005064fd1570000000000000000000000000000000000000000000000000000000d3aec914588f4bcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
function: start: 0 end: 7015cf5760 name: unknown_start
function: start: 7015cf5760 end: 7015cf57cc name: test_level_four
diff --git a/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid b/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
index dfad172..673e30e 100644
--- a/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
+++ b/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
@@ -1,6 +1,6 @@
pid: 12276 tid: 12303
-regs: pc: 7b8c027f64 sp: 7b8c157010 x29: 7b8c157040
map: start: 7b8c01e000 end: 7b8c030000 offset: 0 load_bias: 0 flags: 5 name: /vendor/lib64/egl/eglSubDriverAndroid.so
-stack: start: 7b8c157048 end: 7b8c157050 size: 8 547e028c7b000000
+ucontext: 464 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004070158c7b00000000000000000000001070158c7b000000647f028c7b00000000000000000000000000000000000000
+stack: start: 7b8c157020 end: 7b8c157050 size: 48 00000000000000000000000000000000000000000000000000000000000000000000000000000000547e028c7b000000
function: start: 9ed8 end: a1b0 name: EglAndroidWindowSurface::Initialize(EglAndroidConfig*, int const*)
function: start: 9dcc end: 9ed8 name: EglAndroidWindowSurface::Create(ANativeWindow*, EglAndroidConfig*, EglAndroidWindowSurface**, int const*)
diff --git a/libbacktrace/testdata/arm64/offline_testdata_for_libskia b/libbacktrace/testdata/arm64/offline_testdata_for_libskia
index 1027c55..da820c0 100644
--- a/libbacktrace/testdata/arm64/offline_testdata_for_libskia
+++ b/libbacktrace/testdata/arm64/offline_testdata_for_libskia
@@ -1,6 +1,6 @@
pid: 32232 tid: 32233
-regs: pc: 7c25189a0c sp: 7b8c154b50 x29: 7b8c154bb0
map: start: 7c24c80000 end: 7c25413000 offset: 0 load_bias: 5f000 flags: 5 name: /system/lib64/libskia.so
-stack: start: 7b8c154bb8 end: 7b8c154bc0 size: 8 ec43f2247c000000
+ucontext: 464 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b04b158c7b0000000000000000000000504b158c7b0000000c9a18257c00000000000000000000000000000000000000
+stack: start: 7b8c154b80 end: 7b8c154bc0 size: 64 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ec43f2247c000000
function: start: 568970 end: 568c08 name: SkScalerContext_FreeType::generateImage(SkGlyph const&)
function: start: 30330c end: 3044b0 name: SkScalerContext::getImage(SkGlyph const&)
diff --git a/libbacktrace/testdata/x86/offline_testdata b/libbacktrace/testdata/x86/offline_testdata
index e8b7a99..920b338 100644
--- a/libbacktrace/testdata/x86/offline_testdata
+++ b/libbacktrace/testdata/x86/offline_testdata
@@ -70,7 +70,7 @@
map: start: f77d5000 end: f77d6000 offset: 0 load_bias: 0 flags: 3 name:
map: start: f7ec6000 end: f7ee7000 offset: 0 load_bias: 0 flags: 3 name: [heap]
map: start: ffe4e000 end: ffe70000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-registers: 348 00000000abdae6fff83b7df704000000a6ec77f7abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000008c8decf78c8decf7ceca48f7a8dae6ff8d8decf70a0000000000000014dae6ff8c8decf78c8decf78c8decf78c8decf78c8decf7a9dae6ff06000000c03a23f78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78c8decf78d8decf78d8decf7c03a23f7543b23f7000033f75f5f0ff7c03a23f7503423f77000000098000000020000000f2700006c0000000e00000080000000000000008c8decf7000000008c8decf77f03ffff0000ffffffffffff0000000000000000000000000000ffff040000000f27000008000000003023f78d8decf7f069ec000046bdaa308decf715537df7f83b7df78c8decf74c1c71f78c8decf715537df70000000000000000f069ecf7f83b7df75064ecf792e671f7f069ecf7
+ucontext: 96 0000000000000000000000000000000000000000abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000000000000000000000ceca48f7a8dae6ff000000000000000000000000
stack: start: f732c000 end: f7330000 size: 16384 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009d9d49f761b009f71e382ff7000000000000000000000000000000000000000002000000f6372ff704c82bf70000000000204bf7f0a908f7ceca48f728d9e6fff4a449f70000000020f332f720f332f7d0df48f7f8f132f794c748f720f332f70c144205978142a8d4be08f7d0df48f720f332f7a0ca48f71c000000150000000e000000070000001c000000a0ca48f7d0df48f748f232f739c848f7070000000e000000150000001c000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7100000000c000000080000000400000010000000a0ca48f7d0df48f798f232f7c9c848f704000000080000000c00000010000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f70800000006000000040000000200000008000000a0ca48f7d0df48f7e8f232f759c948f702000000040000000600000008000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7040000000300000002000000010000000046bdaa00000000d0df48f738f332f77cca48f701000000020000000300000004000000a0ca48f720f332f700000000f83b7df7696d4df7d0df48f788dae6ff28d9e6ff28d9e6ff88dae6ff58f332f70046bdaa40fb32f7f83b7df758f332f78d6d4df728d9e6ff88dae6fff83b7df728d9e6ff28d9e6ff009030f728f432f7726f2ff728d9e6ff40fb32f740fb32f740fb32f790f332f700000000000000000000000000000000000000000000000000000000009030f740fb32f7000f3d0028f432f703b12c75032f144e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a06e2ff700000000000f3d00000000008e3f17f740fb32f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03823f7c4fd32f700000000e0341df7e02e1df7e03d1df70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040fb32f7188eecf740fb32f70100000030647cf70046bdaa28658876000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060a705f7a4b130f7f2860000f1860000b0fb32f7ecffffff000000000000000090f332f7000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccfb32f70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c2638cfa7f3e1d0000000000000000000000000000000000406d4df728d9e6ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c032f7004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
function: start: 0 end: f748c740 name: unknown_start
function: start: f748c740 end: f748c7c0 name: test_level_four
diff --git a/libbacktrace/testdata/x86_64/offline_testdata b/libbacktrace/testdata/x86_64/offline_testdata
index f8d0dc0..c6bb241 100644
--- a/libbacktrace/testdata/x86_64/offline_testdata
+++ b/libbacktrace/testdata/x86_64/offline_testdata
@@ -81,7 +81,7 @@
map: start: 7ffcf47ed000 end: 7ffcf480f000 offset: 0 load_bias: 0 flags: 3 name: [stack]
map: start: 7ffcf48d5000 end: 7ffcf48d7000 offset: 0 load_bias: ffffffffff700000 flags: 5 name: [vdso]
map: start: ffffffffff600000 end: ffffffffff601000 offset: 0 load_bias: 0 flags: 5 name: [vsyscall]
-registers: 936 010000000000000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f0000b92455add57f0000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000a0b180f4fc7f000028b480f4fc7f000028b480f4fc7f000028b480f4fc7f000078b480f4fc7f000078b480f4fc7f00007f03ffff0000ffffffffffff000000000000000000000000801f0000fc7f000078b480f4fc7f000060b280f4fc7f000000006a80f3f73cf110b480f4fc7f0000de66d6abd57f00000000000000000000000000000000000000006a80f3f73cf128b480f4fc7f0000782455add57f0000fd96d6abd57f0000092555add57f0000000000000000000057b480f4fc7f0000092555add57f000060b480f4fc7f00006994d6abd57f0000b0e0c6abd57f000071b280f4fc7f000070b280f4fc7f0000256c640000000000a8b180f4fc7f000090b480f4fc7f0000082555add57f0000092555add57f0000092555add57f0000082555add57f00001700000000000000082555add57f0000082555add57f0000f93cfcabd57f0000092555add57f000016000000000000000000000000000000090c07acd57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f000010b380f4fc7f000078b480f4fc7f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000082555add57f0000092555add57f0000092555add57f0000b92455add57f000028b480f4fc7f0000c800000000000000014c7f0b0380ffff0d000000fc7f0000030000000000000033000000d57f000000b480f4fc7f00000000000000000000a0e154ad5b000000000000000000000000000000000000006e000000770000000000000000000000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f0000082555add57f00000000000000000000082555add57f0000082555add57f0000082555add57f00006027b4aad57f0000c800000000000000a0e154add57f0000c0e354add57f0000092555add57f000000006a80f3f73cf1e0e054add57f0000e0e554add57f0000d14df6abd57f0000
+ucontext: 224 00000000000000000000000000000000000000000000000000000000000000000000000000000000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
stack: start: 7fd5abb6b000 end: 7fd5abb6f000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c4eaeabd57f00000000000000000000978142a8000000000f0000000000000012000000000000003888b4abd57f0000e657aeabd57f00000000000000000000a0dcb6abd57f0000307d78aad57f0000b0ddb6abd57f000028d978aad57f0000060aa10200000000a0ddb6abd57f0000000000000000000000000000000000002091b1abd57f0000e094b4abd57f000017008cabd57f0000c84d79aad57f000028e28babd57f00000000000005000000d503000001000000000000000000000068deb6abd57f000040deb6abd57f00002091b1abd57f00000100000000000000e0f3c6abd57f000088f0c6abd57f00006159aeabd57f000000000000000000002091b1abd57f000005000000000000000000000000000000010000000000000088f0c6abd57f00000000000000000000d07bcfabd57f00000000000000000000000000000000000098deb6abd57f000098deb6abd57f0000b0ddb6abd57f00006179cfabd57f000098deb6abd57f0000b07bcfabd57f00001c000000150000000e00000007000000f0ddb6abd57f0000e179cfabd57f00000000000000000000150000001c00000098deb6abd57f0000b07bcfabd57f0000100000000c000000080000000400000030deb6abd57f0000417acfabd57f000000000000000000000c0000001000000098deb6abd57f0000b07bcfabd57f00000800000006000000040000000200000070deb6abd57f0000a17acfabd57f00000000000000000000060000000800000098deb6abd57f0000b07bcfabd57f000004000000030000000200000001000000b0deb6abd57f0000817bcfabd57f0000000000000000000074b480f4fc7f0000c8b080f4fc7f0000c8b080f4fc7f000074b480f4fc7f000000006a80f3f73cf1d0deb6abd57f00002a52d5abd57f0000c8b080f4fc7f0000c8b080f4fc7f0000000000000000000084518cabd57f0000000000000000000000e7b6abd57f000000e7b6abd57f00008f990b1e3bad5a6700000000000000000000000000000000c0e354add57f000000e7b6abd57f00008f99cba356faf1988f9991bc23faf1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f00007de387aad57f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006030b4aad57f0000b8edb6abd57f00000000000000000000000000000000000080b88eaad57f0000000000000000000080b28eaad57f0000000000000000000080c18eaad57f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f0000402555add57f000000e7b6abd57f00000100000000000000000000000000000000006a80f3f73cf1058f9d56adb3c7cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407ab1abd57f000030a3adabd57f00005c64000053640000e0e9b6abd57f0000e0e9b6abd57f0000e0ffffffffffffff00000000000000000000000000000000f0deb6abd57f00000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010eab6abd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c46ad90f52391d00000000000000000000000000000000000000000000000000f051d5abd57f0000c8b080f4fc7f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b6abd57f000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
function: start: 0 end: 7fd5abcf7930 name: unknown_start
function: start: 7fd5abcf7930 end: 7fd5abcf7990 name: test_level_four
diff --git a/libbacktrace/unwind_dex_test.cpp b/libbacktrace/unwind_dex_test.cpp
new file mode 100644
index 0000000..449e662
--- /dev/null
+++ b/libbacktrace/unwind_dex_test.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unordered_map>
+
+#include <android-base/test_utils.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/standard_dex_file.h>
+
+#include <gtest/gtest.h>
+
+#include "UnwindDexFile.h"
+
+class MemoryFake : public unwindstack::Memory {
+ public:
+ MemoryFake() = default;
+ virtual ~MemoryFake() = default;
+
+ size_t Read(uint64_t addr, void* buffer, size_t size) override;
+
+ void SetMemory(uint64_t addr, const void* memory, size_t length);
+
+ void Clear() { data_.clear(); }
+
+ private:
+ std::unordered_map<uint64_t, uint8_t> data_;
+};
+
+void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
+ for (size_t i = 0; i < length; i++, addr++) {
+ auto value = data_.find(addr);
+ if (value != data_.end()) {
+ value->second = src[i];
+ } else {
+ data_.insert({addr, src[i]});
+ }
+ }
+}
+
+size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
+ uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
+ for (size_t i = 0; i < size; i++, addr++) {
+ auto value = data_.find(addr);
+ if (value == data_.end()) {
+ return i;
+ }
+ dst[i] = value->second;
+ }
+ return size;
+}
+
+// Borrowed from art/dex/dex_file_test.cc.
+static constexpr uint32_t kDexData[] = {
+ 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+ 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+ 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+ 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+ 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+ 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+ 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+ 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+ 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+ 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+ 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+ 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+ 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+ 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+ 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+ 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+ 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
+};
+
+TEST(UnwindDexTest, from_file_open_non_exist) {
+ UnwindDexFileFromFile dex_file;
+ ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+}
+
+TEST(UnwindDexTest, from_file_open_too_small) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+ static_cast<size_t>(
+ TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+
+ // Header too small.
+ UnwindDexFileFromFile dex_file;
+ ASSERT_FALSE(dex_file.Open(0, tf.path));
+
+ // Header correct, file too small.
+ ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
+ tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+ ASSERT_FALSE(dex_file.Open(0, tf.path));
+}
+
+TEST(UnwindDexTest, from_file_open) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ UnwindDexFileFromFile dex_file;
+ ASSERT_TRUE(dex_file.Open(0, tf.path));
+}
+
+TEST(UnwindDexTest, from_file_open_non_zero_offset) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ UnwindDexFileFromFile dex_file;
+ ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+}
+
+TEST(UnwindDexTest, from_memory_fail_too_small_for_header) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
+ UnwindDexFileFromMemory dex_file;
+
+ ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(UnwindDexTest, from_memory_fail_too_small_for_data) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
+ UnwindDexFileFromMemory dex_file;
+
+ ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(UnwindDexTest, from_memory_open) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
+ UnwindDexFileFromMemory dex_file;
+
+ ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(UnwindDexTest, create_using_file) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ unwindstack::MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x500, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(UnwindDexTest, create_using_file_non_zero_start) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ unwindstack::MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x600, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(UnwindDexTest, create_using_file_non_zero_offset) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x400, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(UnwindDexTest, create_using_memory_empty_file) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(UnwindDexTest, create_using_memory_file_does_not_exist) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(UnwindDexTest, create_using_memory_file_is_malformed) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(kDexData) - 10,
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
+
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ unwindstack::MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+
+ // Check it came from memory by clearing memory and verifying it fails.
+ memory.Clear();
+ dex_file.reset(UnwindDexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file == nullptr);
+}
+
+TEST(UnwindDexTest, get_method_not_opened) {
+ std::string method("something");
+ uint64_t method_offset = 100;
+ UnwindDexFile dex_file;
+ dex_file.GetMethodInformation(0x100, &method, &method_offset);
+ EXPECT_EQ("something", method);
+ EXPECT_EQ(100U, method_offset);
+}
+
+TEST(UnwindDexTest, get_method) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+ std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+
+ std::string method;
+ uint64_t method_offset;
+ dex_file->GetMethodInformation(0x102, &method, &method_offset);
+ EXPECT_EQ("Main.<init>", method);
+ EXPECT_EQ(2U, method_offset);
+
+ method = "not_in_a_method";
+ method_offset = 0x123;
+ dex_file->GetMethodInformation(0x100000, &method, &method_offset);
+ EXPECT_EQ("not_in_a_method", method);
+ EXPECT_EQ(0x123U, method_offset);
+}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 7c03663..984071c 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -141,6 +141,7 @@
{ 00444, AID_ROOT, AID_ROOT, 0, odm_conf_file + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, oem_conf_dir + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, oem_conf_file + 1 },
+ { 00600, AID_ROOT, AID_ROOT, 0, "product/build.prop" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5753e49..fc354f1 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -125,6 +125,7 @@
#define AID_RESERVED_DISK 1065 /* GID that has access to reserved disk space */
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
+#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 4da8215..27255c2 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -25,6 +25,7 @@
void atrace_set_tracing_enabled(bool enabled)
{
atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
+ atomic_store_explicit(&atrace_is_ready, false, memory_order_release);
atrace_update_tags();
}
@@ -34,18 +35,17 @@
if (atrace_marker_fd == -1) {
ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
atrace_enabled_tags = 0;
- goto done;
+ return;
}
-
atrace_enabled_tags = atrace_get_property();
-
-done:
- atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
}
void atrace_setup()
{
- pthread_once(&atrace_once_control, atrace_init_once);
+ if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+ pthread_once(&atrace_once_control, atrace_init_once);
+ }
+ atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
}
void atrace_begin_body(const char* name)
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 15fba8b..ade2821 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -34,9 +34,11 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-/*
- * Support routines to send messages to the Android in-kernel log buffer,
- * which can later be accessed through the 'logcat' utility.
+/**
+ * \file
+ *
+ * Support routines to send messages to the Android log buffer,
+ * which can later be accessed through the `logcat` utility.
*
* Each log message must have
* - a priority
@@ -47,24 +49,22 @@
* and should be reasonably small.
*
* Log message text may be truncated to less than an implementation-specific
- * limit (e.g. 1023 characters max).
+ * limit (1023 bytes).
*
* Note that a newline character ("\n") will be appended automatically to your
* log message, if not already there. It is not possible to send several
* messages and have them appear on a single line in logcat.
*
- * PLEASE USE LOGS WITH MODERATION:
+ * Please use logging in moderation:
*
* - Sending log messages eats CPU and slow down your application and the
* system.
*
- * - The circular log buffer is pretty small (<64KB), sending many messages
- * might push off other important log messages from the rest of the system.
+ * - The circular log buffer is pretty small, so sending many messages
+ * will hide other important log messages.
*
* - In release builds, only send log messages to account for exceptional
* conditions.
- *
- * NOTE: These functions MUST be implemented by /system/lib/liblog.so
*/
#include <stdarg.h>
@@ -73,28 +73,40 @@
extern "C" {
#endif
-/*
- * Android log priority values, in ascending priority order.
+/**
+ * Android log priority values, in increasing order of priority.
*/
typedef enum android_LogPriority {
+ /** For internal use only. */
ANDROID_LOG_UNKNOWN = 0,
+ /** The default priority, for internal use only. */
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ /** Verbose logging. Should typically be disabled for a release apk. */
ANDROID_LOG_VERBOSE,
+ /** Debug logging. Should typically be disabled for a release apk. */
ANDROID_LOG_DEBUG,
+ /** Informational logging. Should typically be disabled for a release apk. */
ANDROID_LOG_INFO,
+ /** Warning logging. For use with recoverable failures. */
ANDROID_LOG_WARN,
+ /** Error logging. For use with unrecoverable failures. */
ANDROID_LOG_ERROR,
+ /** Fatal logging. For use when aborting. */
ANDROID_LOG_FATAL,
+ /** For internal use only. */
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
-/*
- * Send a simple string to the log.
+/**
+ * Writes the constant string `text` to the log, with priority `prio` and tag
+ * `tag`.
*/
int __android_log_write(int prio, const char* tag, const char* text);
-/*
- * Send a formatted string to the log, used like printf(fmt,...)
+/**
+ * Writes a formatted string to the log, with priority `prio` and tag `tag`.
+ * The details of formatting are the same as for
+ * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
*/
int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#if defined(__GNUC__)
@@ -110,9 +122,9 @@
#endif
;
-/*
- * A variant of __android_log_print() that takes a va_list to list
- * additional parameters.
+/**
+ * Equivalent to `__android_log_print`, but taking a `va_list`.
+ * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
*/
int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
#if defined(__GNUC__)
@@ -128,9 +140,20 @@
#endif
;
-/*
- * Log an assertion failure and abort the process to have a chance
- * to inspect it if a debugger is attached. This uses the FATAL priority.
+/**
+ * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
+ * stderr, before calling
+ * [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
+ *
+ * If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
+ * `Assertion failed: %s` is used with `cond` as the string argument.
+ * If both `fmt` and `cond` are null, a default string is provided.
+ *
+ * Most callers should use
+ * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
+ * `<assert.h>` instead, or the `__assert` and `__assert2` functions provided by
+ * bionic if more control is needed. They support automatically including the
+ * source filename and line number more conveniently than this function.
*/
void __android_log_assert(const char* cond, const char* tag, const char* fmt,
...)
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 6ddec4d..0ebb226 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -236,6 +236,10 @@
// Different name is useful for debugging
namespace_name = kVendorClassloaderNamespaceName;
ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
+ } else if (!oem_public_libraries_.empty()) {
+ // oem_public_libraries are NOT available to vendor apks, otherwise it
+ // would be system->vendor violation.
+ system_exposed_libraries = system_exposed_libraries + ":" + oem_public_libraries_.c_str();
}
NativeLoaderNamespace native_loader_ns;
@@ -353,9 +357,36 @@
"Error reading public native library list from \"%s\": %s",
public_native_libraries_system_config.c_str(), error_msg.c_str());
+ // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+ // variable to add libraries to the list. This is intended for platform tests only.
+ if (is_debuggable()) {
+ const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+ if (additional_libs != nullptr && additional_libs[0] != '\0') {
+ std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
+ std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
+ std::back_inserter(sonames));
+ }
+ }
+
+ // android_init_namespaces() expects all the public libraries
+ // to be loaded so that they can be found by soname alone.
+ //
+ // TODO(dimitry): this is a bit misleading since we do not know
+ // if the vendor public library is going to be opened from /vendor/lib
+ // we might as well end up loading them from /system/lib
+ // For now we rely on CTS test to catch things like this but
+ // it should probably be addressed in the future.
+ for (const auto& soname : sonames) {
+ LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+ "Error preloading public library %s: %s", soname.c_str(), dlerror());
+ }
+
+ system_public_libraries_ = base::Join(sonames, ':');
+
// read /system/etc/public.libraries-<companyname>.txt which contain partner defined
// system libs that are exposed to apps. The libs in the txt files must be
// named as lib<name>.<companyname>.so.
+ sonames.clear();
std::string dirname = base::Dirname(public_native_libraries_system_config);
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir);
if (dir != nullptr) {
@@ -396,39 +427,12 @@
}
}
}
+ oem_public_libraries_ = base::Join(sonames, ':');
// Insert VNDK version to llndk and vndksp config file names.
insert_vndk_version_str(&llndk_native_libraries_system_config);
insert_vndk_version_str(&vndksp_native_libraries_system_config);
- // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
- // variable to add libraries to the list. This is intended for platform tests only.
- if (is_debuggable()) {
- const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
- if (additional_libs != nullptr && additional_libs[0] != '\0') {
- std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
- std::copy(additional_libs_vector.begin(),
- additional_libs_vector.end(),
- std::back_inserter(sonames));
- }
- }
-
- // android_init_namespaces() expects all the public libraries
- // to be loaded so that they can be found by soname alone.
- //
- // TODO(dimitry): this is a bit misleading since we do not know
- // if the vendor public library is going to be opened from /vendor/lib
- // we might as well end up loading them from /system/lib
- // For now we rely on CTS test to catch things like this but
- // it should probably be addressed in the future.
- for (const auto& soname : sonames) {
- LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
- "Error preloading public library %s: %s",
- soname.c_str(), dlerror());
- }
-
- system_public_libraries_ = base::Join(sonames, ':');
-
sonames.clear();
ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
system_llndk_libraries_ = base::Join(sonames, ':');
@@ -554,6 +558,7 @@
std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string system_public_libraries_;
std::string vendor_public_libraries_;
+ std::string oem_public_libraries_;
std::string system_llndk_libraries_;
std::string system_vndksp_libraries_;
diff --git a/libnativeloader/test/Android.mk b/libnativeloader/test/Android.mk
index 4c3da4a..e625454 100644
--- a/libnativeloader/test/Android.mk
+++ b/libnativeloader/test/Android.mk
@@ -28,3 +28,23 @@
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := oemlibrarytest-system
+LOCAL_MODULE_TAGS := tests
+LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := oemlibrarytest-vendor
+LOCAL_MODULE_TAGS := tests
+LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_APPS)
+include $(BUILD_PACKAGE)
diff --git a/libnativeloader/test/runtest.sh b/libnativeloader/test/runtest.sh
new file mode 100755
index 0000000..40beb5b
--- /dev/null
+++ b/libnativeloader/test/runtest.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+adb root
+adb remount
+adb sync
+adb shell stop
+adb shell start
+sleep 5 # wait until device reboots
+adb logcat -c;
+adb shell am start -n android.test.app.system/android.test.app.TestActivity
+adb shell am start -n android.test.app.vendor/android.test.app.TestActivity
+adb logcat | grep android.test.app
diff --git a/libnativeloader/test/src/android/test/app/TestActivity.java b/libnativeloader/test/src/android/test/app/TestActivity.java
new file mode 100644
index 0000000..214892d
--- /dev/null
+++ b/libnativeloader/test/src/android/test/app/TestActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ tryLoadingLib("foo.oem1");
+ tryLoadingLib("bar.oem1");
+ tryLoadingLib("foo.oem2");
+ tryLoadingLib("bar.oem2");
+ }
+
+ private void tryLoadingLib(String name) {
+ try {
+ System.loadLibrary(name);
+ Log.d(getPackageName(), "library " + name + " is successfully loaded");
+ } catch (UnsatisfiedLinkError e) {
+ Log.d(getPackageName(), "failed to load libarary " + name, e);
+ }
+ }
+}
diff --git a/libnativeloader/test/system/AndroidManifest.xml b/libnativeloader/test/system/AndroidManifest.xml
new file mode 100644
index 0000000..c304889
--- /dev/null
+++ b/libnativeloader/test/system/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.test.app.system">
+
+ <application>
+ <activity android:name="android.test.app.TestActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+
diff --git a/libnativeloader/test/vendor/AndroidManifest.xml b/libnativeloader/test/vendor/AndroidManifest.xml
new file mode 100644
index 0000000..c4c1a9c
--- /dev/null
+++ b/libnativeloader/test/vendor/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.test.app.vendor">
+
+ <application>
+ <activity android:name="android.test.app.TestActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
new file mode 100644
index 0000000..aeb160c
--- /dev/null
+++ b/libsystem/OWNERS
@@ -0,0 +1,2 @@
+jessehall@google.com
+olv@google.com
diff --git a/libsystem/include/system/graphics-base-v1.1.h b/libsystem/include/system/graphics-base-v1.1.h
index 3d5c3c0..12d01c1 100644
--- a/libsystem/include/system/graphics-base-v1.1.h
+++ b/libsystem/include/system/graphics-base-v1.1.h
@@ -16,8 +16,16 @@
HAL_PIXEL_FORMAT_DEPTH_32F = 51,
HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 = 52,
HAL_PIXEL_FORMAT_STENCIL_8 = 53,
+ HAL_PIXEL_FORMAT_YCBCR_P010 = 54,
} android_pixel_format_v1_1_t;
+typedef enum {
+ HAL_DATASPACE_BT2020_ITU =
+ 281411584, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+ HAL_DATASPACE_BT2020_ITU_PQ =
+ 298188800, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_LIMITED)
+} android_dataspace_v1_1_t;
+
#ifdef __cplusplus
}
#endif
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 9389b40..28d7e64 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -124,6 +124,7 @@
"tests/DwarfOpTest.cpp",
"tests/DwarfSectionTest.cpp",
"tests/DwarfSectionImplTest.cpp",
+ "tests/ElfCacheTest.cpp",
"tests/ElfFake.cpp",
"tests/ElfInterfaceArmTest.cpp",
"tests/ElfInterfaceTest.cpp",
@@ -170,6 +171,8 @@
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
+ "tests/files/offline/bad_eh_frame_hdr_arm64/*",
+ "tests/files/offline/debug_frame_first_x86/*",
"tests/files/offline/jit_debug_arm32/*",
"tests/files/offline/jit_debug_x86_32/*",
"tests/files/offline/gnu_debugdata_arm32/*",
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index 6b0646f..65638ae 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -57,6 +57,7 @@
uint32_t data;
if (!elf_memory_->Read32(entry_offset + 4, &data)) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = entry_offset + 4;
return false;
}
if (data == 1) {
@@ -97,6 +98,7 @@
uint32_t addr = (entry_offset + 4) + signed_data;
if (!elf_memory_->Read32(addr, &data)) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = addr;
return false;
}
@@ -128,6 +130,7 @@
addr += 4;
if (!elf_memory_->Read32(addr, &data)) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = addr;
return false;
}
num_table_words = (data >> 24) & 0xff;
@@ -145,6 +148,7 @@
for (size_t i = 0; i < num_table_words; i++) {
if (!elf_memory_->Read32(addr, &data)) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = addr;
return false;
}
data_.push_back((data >> 24) & 0xff);
@@ -216,6 +220,7 @@
if (registers & (1 << reg)) {
if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = cfa_;
return false;
}
cfa_ += 4;
@@ -284,6 +289,7 @@
for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = cfa_;
return false;
}
cfa_ += 4;
@@ -291,6 +297,7 @@
if (byte & 0x8) {
if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = cfa_;
return false;
}
cfa_ += 4;
@@ -357,6 +364,7 @@
if (byte & (1 << reg)) {
if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
status_ = ARM_STATUS_READ_FAILED;
+ status_address_ = cfa_;
return false;
}
cfa_ += 4;
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
index f4361d4..96756a0 100644
--- a/libunwindstack/ArmExidx.h
+++ b/libunwindstack/ArmExidx.h
@@ -61,6 +61,7 @@
std::deque<uint8_t>* data() { return &data_; }
ArmStatus status() { return status_; }
+ uint64_t status_address() { return status_address_; }
RegsArm* regs() { return regs_; }
@@ -97,6 +98,7 @@
uint32_t cfa_ = 0;
std::deque<uint8_t> data_;
ArmStatus status_ = ARM_STATUS_NONE;
+ uint64_t status_address_ = 0;
Memory* elf_memory_;
Memory* process_memory_;
diff --git a/libunwindstack/AsmGetRegsX86.S b/libunwindstack/AsmGetRegsX86.S
index 14927a3..021e628 100644
--- a/libunwindstack/AsmGetRegsX86.S
+++ b/libunwindstack/AsmGetRegsX86.S
@@ -50,12 +50,12 @@
movl (%esp), %ecx
movl %ecx, 32(%eax)
- movl %cs, 36(%eax)
- movl %ss, 40(%eax)
- movl %ds, 44(%eax)
- movl %es, 48(%eax)
- movl %fs, 52(%eax)
- movl %gs, 56(%eax)
+ mov %cs, 36(%eax)
+ mov %ss, 40(%eax)
+ mov %ds, 44(%eax)
+ mov %es, 48(%eax)
+ mov %fs, 52(%eax)
+ mov %gs, 56(%eax)
ret
.cfi_endproc
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
index 2d216d7..9643d76 100644
--- a/libunwindstack/Check.h
+++ b/libunwindstack/Check.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_ERROR_H
-#define _LIBUNWINDSTACK_ERROR_H
+#ifndef _LIBUNWINDSTACK_CHECK_H
+#define _LIBUNWINDSTACK_CHECK_H
#include <stdlib.h>
@@ -31,4 +31,4 @@
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_ERROR_H
+#endif // _LIBUNWINDSTACK_CHECK_H
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index b1d55ba..4fc95c7 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -23,12 +23,12 @@
#include <android-base/stringprintf.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/Log.h>
#include "DwarfCfa.h"
#include "DwarfEncoding.h"
-#include "DwarfError.h"
#include "DwarfOp.h"
namespace unwindstack {
@@ -44,7 +44,8 @@
(*loc_regs)[entry.first] = entry.second;
}
}
- last_error_ = DWARF_ERROR_NONE;
+ last_error_.code = DWARF_ERROR_NONE;
+ last_error_.address = 0;
memory_->set_cur_offset(start_offset);
uint64_t cfa_offset;
@@ -54,7 +55,8 @@
// Read the cfa information.
uint8_t cfa_value;
if (!memory_->ReadBytes(&cfa_value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_->cur_offset();
return false;
}
uint8_t cfa_low = cfa_value & 0x3f;
@@ -66,7 +68,8 @@
case 2: {
uint64_t offset;
if (!memory_->ReadULEB128(&offset)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_->cur_offset();
return false;
}
SignedType signed_offset =
@@ -78,7 +81,7 @@
case 3: {
if (cie_loc_regs_ == nullptr) {
log(0, "restore while processing cie");
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -93,7 +96,7 @@
case 0: {
const auto handle_func = DwarfCfa<AddressType>::kCallbackTable[cfa_low];
if (handle_func == nullptr) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
@@ -102,7 +105,8 @@
if (cfa->operands[i] == DW_EH_PE_block) {
uint64_t block_length;
if (!memory_->ReadULEB128(&block_length)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_->cur_offset();
return false;
}
operands_.push_back(block_length);
@@ -111,7 +115,8 @@
}
uint64_t value;
if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_->cur_offset();
return false;
}
operands_.push_back(value);
@@ -334,7 +339,7 @@
AddressType reg = operands_[0];
if (cie_loc_regs_ == nullptr) {
log(0, "restore while processing cie");
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
auto reg_entry = cie_loc_regs_->find(reg);
@@ -396,7 +401,7 @@
auto cfa_location = loc_regs->find(CFA_REG);
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
log(0, "Attempt to set new register, but cfa is not already set to a register.");
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -410,7 +415,7 @@
auto cfa_location = loc_regs->find(CFA_REG);
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
log(0, "Attempt to set offset, but cfa is not set to a register.");
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
cfa_location->second.values[1] = operands_[0];
@@ -454,7 +459,7 @@
auto cfa_location = loc_regs->find(CFA_REG);
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
log(0, "Attempt to set offset, but cfa is not set to a register.");
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index 62b9b7a..16c66e2 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -24,12 +24,11 @@
#include <type_traits>
#include <vector>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
-#include "DwarfError.h"
-
namespace unwindstack {
// DWARF Standard home: http://dwarfstd.org/
@@ -75,7 +74,9 @@
bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset,
uint64_t end_offset);
- DwarfError last_error() { return last_error_; }
+ const DwarfErrorData& last_error() { return last_error_; }
+ DwarfErrorCode LastErrorCode() { return last_error_.code; }
+ uint64_t LastErrorAddress() { return last_error_.address; }
AddressType cur_pc() { return cur_pc_; }
@@ -89,7 +90,7 @@
bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc);
private:
- DwarfError last_error_;
+ DwarfErrorData last_error_;
DwarfMemory* memory_;
const DwarfFde* fde_;
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index 0337dba..a131abe 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -16,12 +16,12 @@
#include <stdint.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfStructs.h>
#include <unwindstack/Memory.h>
#include "Check.h"
#include "DwarfEhFrameWithHdr.h"
-#include "DwarfError.h"
namespace unwindstack {
@@ -36,14 +36,15 @@
// Read the first four bytes all at once.
if (!memory_.ReadBytes(data, 4)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
version_ = data[0];
if (version_ != 1) {
// Unknown version.
- last_error_ = DWARF_ERROR_UNSUPPORTED_VERSION;
+ last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
return false;
}
@@ -54,13 +55,20 @@
memory_.set_pc_offset(memory_.cur_offset());
if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
memory_.set_pc_offset(memory_.cur_offset());
if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (fde_count_ == 0) {
+ last_error_.code = DWARF_ERROR_NO_FDES;
return false;
}
@@ -96,7 +104,8 @@
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
fde_info_.erase(index);
return nullptr;
}
@@ -142,7 +151,9 @@
template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
CHECK(fde_count_ != 0);
- last_error_ = DWARF_ERROR_NONE;
+ last_error_.code = DWARF_ERROR_NONE;
+ last_error_.address = 0;
+
// We can do a binary search if the pc is in the range of the elements
// that have already been cached.
if (!fde_info_.empty()) {
@@ -171,14 +182,16 @@
memory_.set_pc_offset(memory_.cur_offset());
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
FdeInfo* info = &fde_info_[current];
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
fde_info_.erase(current);
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
info->pc = value + 4;
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index 3b3d340..dcf04e6 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -22,12 +22,12 @@
#include <android-base/stringprintf.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/Log.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
-#include "DwarfError.h"
#include "DwarfOp.h"
namespace unwindstack {
@@ -48,7 +48,7 @@
// To protect against a branch that creates an infinite loop,
// terminate if the number of iterations gets too high.
if (iterations++ == 1000) {
- last_error_ = DWARF_ERROR_TOO_MANY_ITERATIONS;
+ last_error_.code = DWARF_ERROR_TOO_MANY_ITERATIONS;
return false;
}
}
@@ -57,28 +57,29 @@
template <typename AddressType>
bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
- last_error_ = DWARF_ERROR_NONE;
+ last_error_.code = DWARF_ERROR_NONE;
if (!memory_->ReadBytes(&cur_op_, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_->cur_offset();
return false;
}
const auto* op = &kCallbackTable[cur_op_];
const auto handle_func = op->handle_func;
if (handle_func == nullptr) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
// Check for an unsupported opcode.
if (dwarf_version < op->supported_version) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
// Make sure that the required number of stack elements is available.
if (stack_.size() < op->num_required_stack_values) {
- last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID;
+ last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
return false;
}
@@ -86,7 +87,8 @@
for (size_t i = 0; i < op->num_operands; i++) {
uint64_t value;
if (!memory_->ReadEncodedValue<AddressType>(op->operands[i], &value)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_->cur_offset();
return false;
}
operands_.push_back(value);
@@ -142,7 +144,8 @@
AddressType addr = StackPop();
AddressType value;
if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = addr;
return false;
}
stack_.push_front(value);
@@ -153,14 +156,15 @@
bool DwarfOp<AddressType>::op_deref_size() {
AddressType bytes_to_read = OperandAt(0);
if (bytes_to_read > sizeof(AddressType) || bytes_to_read == 0) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
// Read the address and dereference it.
AddressType addr = StackPop();
AddressType value = 0;
if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = addr;
return false;
}
stack_.push_front(value);
@@ -198,7 +202,7 @@
bool DwarfOp<AddressType>::op_pick() {
AddressType index = OperandAt(0);
if (index > StackSize()) {
- last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID;
+ last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
return false;
}
stack_.push_front(StackAt(index));
@@ -243,7 +247,7 @@
bool DwarfOp<AddressType>::op_div() {
AddressType top = StackPop();
if (top == 0) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
SignedType signed_divisor = static_cast<SignedType>(top);
@@ -263,7 +267,7 @@
bool DwarfOp<AddressType>::op_mod() {
AddressType top = StackPop();
if (top == 0) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
stack_[0] %= top;
@@ -431,7 +435,7 @@
bool DwarfOp<AddressType>::op_breg() {
uint16_t reg = cur_op() - 0x70;
if (reg >= regs_->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
stack_.push_front((*regs_)[reg] + OperandAt(0));
@@ -442,7 +446,7 @@
bool DwarfOp<AddressType>::op_bregx() {
AddressType reg = OperandAt(0);
if (reg >= regs_->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
stack_.push_front((*regs_)[reg] + OperandAt(1));
@@ -456,7 +460,7 @@
template <typename AddressType>
bool DwarfOp<AddressType>::op_not_implemented() {
- last_error_ = DWARF_ERROR_NOT_IMPLEMENTED;
+ last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
return false;
}
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index c29bf35..40b7b23 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -24,8 +24,9 @@
#include <type_traits>
#include <vector>
+#include <unwindstack/DwarfError.h>
+
#include "DwarfEncoding.h"
-#include "DwarfError.h"
namespace unwindstack {
@@ -72,7 +73,9 @@
void set_regs(RegsImpl<AddressType>* regs) { regs_ = regs; }
- DwarfError last_error() { return last_error_; }
+ const DwarfErrorData& last_error() { return last_error_; }
+ DwarfErrorCode LastErrorCode() { return last_error_.code; }
+ uint64_t LastErrorAddress() { return last_error_.address; }
bool is_register() { return is_register_; }
@@ -96,7 +99,7 @@
RegsImpl<AddressType>* regs_;
bool is_register_ = false;
- DwarfError last_error_ = DWARF_ERROR_NONE;
+ DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
uint8_t cur_op_;
std::vector<AddressType> operands_;
std::deque<AddressType> stack_;
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 91d855b..4e94f88 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -16,6 +16,7 @@
#include <stdint.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfSection.h>
@@ -26,7 +27,6 @@
#include "DwarfCfa.h"
#include "DwarfEncoding.h"
-#include "DwarfError.h"
#include "DwarfOp.h"
#include "DwarfDebugFrame.h"
@@ -36,7 +36,7 @@
constexpr uint64_t DEX_PC_REG = 0x20444558;
-DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
+DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
uint64_t fde_offset;
@@ -52,15 +52,15 @@
if (pc < fde->pc_end) {
return fde;
}
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return nullptr;
}
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- last_error_ = DWARF_ERROR_NONE;
+ last_error_.code = DWARF_ERROR_NONE;
const DwarfFde* fde = GetFdeFromPc(pc);
if (fde == nullptr || fde->cie == nullptr) {
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
@@ -87,12 +87,12 @@
return false;
}
if (op.StackSize() == 0) {
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
return false;
}
// We don't support an expression that evaluates to a register number.
if (op.is_register()) {
- last_error_ = DWARF_ERROR_NOT_IMPLEMENTED;
+ last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
return false;
}
*value = op.StackAt(0);
@@ -119,7 +119,8 @@
switch (loc->type) {
case DWARF_LOCATION_OFFSET:
if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = eval_info->cfa + loc->values[0];
return false;
}
break;
@@ -129,7 +130,7 @@
case DWARF_LOCATION_REGISTER: {
uint32_t cur_reg = loc->values[0];
if (cur_reg >= eval_info->cur_regs->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
@@ -158,7 +159,8 @@
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = value;
return false;
}
} else {
@@ -183,14 +185,14 @@
bool* finished) {
RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs);
if (cie->return_address_register >= cur_regs->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
// Get the cfa value;
auto cfa_entry = loc_regs.find(CFA_REG);
if (cfa_entry == loc_regs.end()) {
- last_error_ = DWARF_ERROR_CFA_NOT_DEFINED;
+ last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED;
return false;
}
@@ -206,7 +208,7 @@
switch (loc->type) {
case DWARF_LOCATION_REGISTER:
if (loc->values[0] >= cur_regs->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
// If the stack pointer register is the CFA, and the stack
@@ -227,7 +229,8 @@
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = value;
return false;
}
} else {
@@ -236,7 +239,7 @@
break;
}
default:
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
@@ -305,7 +308,8 @@
bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
uint32_t length32;
if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
// Set the default for the lsda encoding.
@@ -315,7 +319,8 @@
// 64 bit Cie
uint64_t length64;
if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -324,12 +329,13 @@
uint64_t cie_id;
if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (cie_id != cie64_value_) {
// This is not a Cie, something has gone horribly wrong.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
} else {
@@ -339,24 +345,26 @@
uint32_t cie_id;
if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (cie_id != cie32_value_) {
// This is not a Cie, something has gone horribly wrong.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
}
if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
// Unrecognized version.
- last_error_ = DWARF_ERROR_UNSUPPORTED_VERSION;
+ last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
return false;
}
@@ -364,7 +372,8 @@
char aug_value;
do {
if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
cie->augmentation_string.push_back(aug_value);
@@ -376,20 +385,23 @@
// Segment Size
if (!memory_.ReadBytes(&cie->segment_size, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
}
// Code Alignment Factor
if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
// Data Alignment Factor
if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -397,12 +409,14 @@
// Return Address is a single byte.
uint8_t return_address_register;
if (!memory_.ReadBytes(&return_address_register, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
cie->return_address_register = return_address_register;
} else if (!memory_.ReadULEB128(&cie->return_address_register)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -413,7 +427,8 @@
uint64_t aug_length;
if (!memory_.ReadULEB128(&aug_length)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
@@ -422,24 +437,28 @@
switch (cie->augmentation_string[i]) {
case 'L':
if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
break;
case 'P': {
uint8_t encoding;
if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
} break;
case 'R':
if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
break;
@@ -467,7 +486,8 @@
bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
uint32_t length32;
if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -475,19 +495,21 @@
// 64 bit Fde.
uint64_t length64;
if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
fde->cfa_instructions_end = memory_.cur_offset() + length64;
uint64_t value64;
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (value64 == cie64_value_) {
// This is a Cie, this means something has gone wrong.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
@@ -500,12 +522,13 @@
uint32_t value32;
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (value32 == cie32_value_) {
// This is a Cie, this means something has gone wrong.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
@@ -528,13 +551,15 @@
memory_.set_cur_offset(cur_offset);
if (!memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding & 0xf, &fde->pc_start)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
fde->pc_start = AdjustPcFromFde(fde->pc_start);
if (!memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding & 0xf, &fde->pc_end)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
fde->pc_end += fde->pc_start;
@@ -542,13 +567,15 @@
// Augmentation Size
uint64_t aug_length;
if (!memory_.ReadULEB128(&aug_length)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
uint64_t cur_offset = memory_.cur_offset();
if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -619,7 +646,8 @@
bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
uint8_t version;
if (!memory_.ReadBytes(&version, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
// Read the augmentation string.
@@ -628,7 +656,8 @@
bool get_encoding = false;
do {
if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (aug_value == 'R') {
@@ -643,7 +672,8 @@
// Read the segment size.
if (!memory_.ReadBytes(segment_size, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
} else {
@@ -659,7 +689,8 @@
uint8_t value;
do {
if (!memory_.ReadBytes(&value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
} while (value & 0x80);
@@ -667,7 +698,8 @@
// Skip data alignment factor
do {
if (!memory_.ReadBytes(&value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
} while (value & 0x80);
@@ -679,7 +711,8 @@
// Skip return address register.
do {
if (!memory_.ReadBytes(&value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
} while (value & 0x80);
@@ -688,7 +721,8 @@
// Skip the augmentation length.
do {
if (!memory_.ReadBytes(&value, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
} while (value & 0x80);
@@ -696,7 +730,8 @@
for (size_t i = 1; i < aug_string.size(); i++) {
if (aug_string[i] == 'R') {
if (!memory_.ReadBytes(encoding, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
// Got the encoding, that's all we are looking for.
@@ -706,12 +741,14 @@
} else if (aug_string[i] == 'P') {
uint8_t encoding;
if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
}
@@ -730,14 +767,16 @@
uint64_t start;
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &start)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
start = AdjustPcFromFde(start);
uint64_t length;
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &length)) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
if (length != 0) {
@@ -764,7 +803,8 @@
// Figure out the entry length and type.
uint32_t value32;
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -772,14 +812,16 @@
if (value32 == static_cast<uint32_t>(-1)) {
uint64_t value64;
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
next_entry_offset = memory_.cur_offset() + value64;
// Read the Cie Id of a Cie or the pointer of the Fde.
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -794,7 +836,7 @@
uint64_t last_cie_offset = GetCieOffsetFromFde64(value64);
if (last_cie_offset != cie_offset) {
// This means that this Fde is not following the Cie.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
@@ -808,7 +850,8 @@
// Read the Cie Id of a Cie or the pointer of the Fde.
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
return false;
}
@@ -823,7 +866,7 @@
uint64_t last_cie_offset = GetCieOffsetFromFde32(value32);
if (last_cie_offset != cie_offset) {
// This means that this Fde is not following the Cie.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
@@ -835,9 +878,8 @@
}
if (next_entry_offset < memory_.cur_offset()) {
- // This indicates some kind of corruption, or malformed section data.
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
+ // Simply consider the processing done in this case.
+ break;
}
memory_.set_cur_offset(next_entry_offset);
}
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 220e549..dbf772e 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -35,6 +35,10 @@
namespace unwindstack {
+bool Elf::cache_enabled_;
+std::unordered_map<std::string, std::shared_ptr<Elf>>* Elf::cache_;
+std::mutex* Elf::cache_lock_;
+
bool Elf::Init(bool init_gnu_debugdata) {
load_bias_ = 0;
if (!memory_) {
@@ -134,6 +138,26 @@
return true;
}
+void Elf::GetLastError(ErrorData* data) {
+ if (valid_) {
+ *data = interface_->last_error();
+ }
+}
+
+ErrorCode Elf::GetLastErrorCode() {
+ if (valid_) {
+ return interface_->LastErrorCode();
+ }
+ return ERROR_NONE;
+}
+
+uint64_t Elf::GetLastErrorAddress() {
+ if (valid_) {
+ return interface_->LastErrorAddress();
+ }
+ return 0;
+}
+
// The relative pc is always relative to the start of the map from which it comes.
bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
Memory* process_memory, bool* finished) {
@@ -281,4 +305,42 @@
return 0;
}
+void Elf::SetCachingEnabled(bool enable) {
+ if (!cache_enabled_ && enable) {
+ cache_enabled_ = true;
+ cache_ = new std::unordered_map<std::string, std::shared_ptr<Elf>>;
+ cache_lock_ = new std::mutex;
+ } else if (cache_enabled_ && !enable) {
+ cache_enabled_ = false;
+ delete cache_;
+ delete cache_lock_;
+ }
+}
+
+void Elf::CacheLock() {
+ cache_lock_->lock();
+}
+
+void Elf::CacheUnlock() {
+ cache_lock_->unlock();
+}
+
+void Elf::CacheAdd(MapInfo* info) {
+ if (info->offset == 0) {
+ (*cache_)[info->name] = info->elf;
+ } else {
+ std::string name(info->name + ':' + std::to_string(info->offset));
+ (*cache_)[name] = info->elf;
+ }
+}
+
+bool Elf::CacheGet(const std::string& name, std::shared_ptr<Elf>* elf) {
+ auto entry = cache_->find(name);
+ if (entry != cache_->end()) {
+ *elf = entry->second;
+ return true;
+ }
+ return false;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 0e3ab2c..e413081 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -24,6 +24,7 @@
#include <Xz.h>
#include <XzCrc64.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfSection.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Log.h>
@@ -126,22 +127,26 @@
if (eh_frame_hdr_offset_ != 0) {
eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) {
- // Even if the eh_frame_offset_ is non-zero, do not bother
- // trying to read that since something has gone wrong.
eh_frame_.reset(nullptr);
- eh_frame_hdr_offset_ = 0;
- eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
}
- } else if (eh_frame_offset_ != 0) {
- // If there is a eh_frame section without a eh_frame_hdr section.
+ }
+
+ if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) {
+ // If there is an eh_frame section without an eh_frame_hdr section,
+ // or using the frame hdr object failed to init.
eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
eh_frame_.reset(nullptr);
- eh_frame_offset_ = 0;
- eh_frame_size_ = static_cast<uint64_t>(-1);
}
}
+ if (eh_frame_.get() == nullptr) {
+ eh_frame_hdr_offset_ = 0;
+ eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
+ eh_frame_offset_ = 0;
+ eh_frame_size_ = static_cast<uint64_t>(-1);
+ }
+
if (debug_frame_offset_ != 0) {
debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
@@ -156,6 +161,8 @@
bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
EhdrType ehdr;
if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = 0;
return false;
}
@@ -197,6 +204,9 @@
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address =
+ offset + reinterpret_cast<uintptr_t>(&phdr.p_type) - reinterpret_cast<uintptr_t>(&phdr);
return false;
}
@@ -209,6 +219,9 @@
{
// Get the flags first, if this isn't an executable header, ignore it.
if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_flags) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
if ((phdr.p_flags & PF_X) == 0) {
@@ -216,12 +229,21 @@
}
if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
@@ -234,11 +256,17 @@
case PT_GNU_EH_FRAME:
if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
// This is really the pointer to the .eh_frame_hdr section.
eh_frame_hdr_offset_ = phdr.p_offset;
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
eh_frame_hdr_size_ = phdr.p_memsz;
@@ -246,14 +274,23 @@
case PT_DYNAMIC:
if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
dynamic_offset_ = phdr.p_offset;
if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
dynamic_vaddr_ = phdr.p_vaddr;
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
+ reinterpret_cast<uintptr_t>(&phdr);
return false;
}
dynamic_size_ = phdr.p_memsz;
@@ -286,31 +323,47 @@
offset += ehdr.e_shentsize;
for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address =
+ offset + reinterpret_cast<uintptr_t>(&shdr.sh_type) - reinterpret_cast<uintptr_t>(&shdr);
return false;
}
if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset;
return false;
}
// Need to go get the information about the section that contains
// the string terminated names.
ShdrType str_shdr;
if (shdr.sh_link >= ehdr.e_shnum) {
+ last_error_.code = ERROR_UNWIND_INFO;
return false;
}
uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_type) -
+ reinterpret_cast<uintptr_t>(&str_shdr);
return false;
}
if (str_shdr.sh_type != SHT_STRTAB) {
+ last_error_.code = ERROR_UNWIND_INFO;
return false;
}
if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
sizeof(str_shdr.sh_offset))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_offset) -
+ reinterpret_cast<uintptr_t>(&str_shdr);
return false;
}
if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_size) -
+ reinterpret_cast<uintptr_t>(&str_shdr);
return false;
}
symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
@@ -318,6 +371,9 @@
} else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
// Look for the .debug_frame and .gnu_debugdata.
if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset + reinterpret_cast<uintptr_t>(&shdr.sh_name) -
+ reinterpret_cast<uintptr_t>(&shdr);
return false;
}
if (shdr.sh_name < sec_size) {
@@ -373,6 +429,8 @@
uint64_t max_offset = offset + dynamic_size_;
for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset;
return false;
}
@@ -430,21 +488,26 @@
bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
bool* finished) {
+ last_error_.code = ERROR_NONE;
+ last_error_.address = 0;
+
// Adjust the load bias to get the real relative pc.
if (pc < load_bias) {
+ last_error_.code = ERROR_UNWIND_INFO;
return false;
}
uint64_t adjusted_pc = pc - load_bias;
- // Try the eh_frame first.
- DwarfSection* eh_frame = eh_frame_.get();
- if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
+ // Try the debug_frame first since it contains the most specific unwind
+ // information.
+ DwarfSection* debug_frame = debug_frame_.get();
+ if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
return true;
}
- // Try the debug_frame next.
- DwarfSection* debug_frame = debug_frame_.get();
- if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
+ // Try the eh_frame next.
+ DwarfSection* eh_frame = eh_frame_.get();
+ if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
return true;
}
@@ -453,6 +516,46 @@
gnu_debugdata_interface_->Step(pc, 0, regs, process_memory, finished)) {
return true;
}
+
+ // Set the error code based on the first error encountered.
+ DwarfSection* section = nullptr;
+ if (debug_frame_ != nullptr) {
+ section = debug_frame_.get();
+ } else if (eh_frame_ != nullptr) {
+ section = eh_frame_.get();
+ } else if (gnu_debugdata_interface_ != nullptr) {
+ last_error_ = gnu_debugdata_interface_->last_error();
+ return false;
+ } else {
+ return false;
+ }
+
+ // Convert the DWARF ERROR to an external error.
+ DwarfErrorCode code = section->LastErrorCode();
+ switch (code) {
+ case DWARF_ERROR_NONE:
+ last_error_.code = ERROR_NONE;
+ break;
+
+ case DWARF_ERROR_MEMORY_INVALID:
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = section->LastErrorAddress();
+ break;
+
+ case DWARF_ERROR_ILLEGAL_VALUE:
+ case DWARF_ERROR_ILLEGAL_STATE:
+ case DWARF_ERROR_STACK_INDEX_NOT_VALID:
+ case DWARF_ERROR_TOO_MANY_ITERATIONS:
+ case DWARF_ERROR_CFA_NOT_DEFINED:
+ case DWARF_ERROR_NO_FDES:
+ last_error_.code = ERROR_UNWIND_INFO;
+ break;
+
+ case DWARF_ERROR_NOT_IMPLEMENTED:
+ case DWARF_ERROR_UNSUPPORTED_VERSION:
+ last_error_.code = ERROR_UNSUPPORTED;
+ break;
+ }
return false;
}
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 5d99bd7..616d1b1 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -28,6 +28,7 @@
bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
if (start_offset_ == 0 || total_entries_ == 0) {
+ last_error_.code = ERROR_UNWIND_INFO;
return false;
}
@@ -56,12 +57,15 @@
*entry_offset = start_offset_ + (last - 1) * 8;
return true;
}
+ last_error_.code = ERROR_UNWIND_INFO;
return false;
}
bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) {
uint32_t data;
if (!memory_->Read32(offset, &data)) {
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = offset;
return false;
}
@@ -106,6 +110,7 @@
bool* finished) {
// Adjust the load bias to get the real relative pc.
if (pc < load_bias) {
+ last_error_.code = ERROR_UNWIND_INFO;
return false;
}
pc -= load_bias;
@@ -139,6 +144,30 @@
*finished = true;
return true;
}
+
+ if (!return_value) {
+ switch (arm.status()) {
+ case ARM_STATUS_NONE:
+ case ARM_STATUS_NO_UNWIND:
+ case ARM_STATUS_FINISH:
+ last_error_.code = ERROR_NONE;
+ break;
+
+ case ARM_STATUS_RESERVED:
+ case ARM_STATUS_SPARE:
+ case ARM_STATUS_TRUNCATED:
+ case ARM_STATUS_MALFORMED:
+ case ARM_STATUS_INVALID_ALIGNMENT:
+ case ARM_STATUS_INVALID_PERSONALITY:
+ last_error_.code = ERROR_UNWIND_INFO;
+ break;
+
+ case ARM_STATUS_READ_FAILED:
+ last_error_.code = ERROR_MEMORY_INVALID;
+ last_error_.address = arm.status_address();
+ break;
+ }
+ }
return return_value;
}
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 89fe038..0c15335 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -109,16 +109,46 @@
// Make sure no other thread is trying to add the elf to this map.
std::lock_guard<std::mutex> guard(mutex_);
- if (elf) {
- return elf;
+ if (elf.get() != nullptr) {
+ return elf.get();
}
- elf = new Elf(CreateMemory(process_memory));
- elf->Init(init_gnu_debugdata);
+ bool locked = false;
+ if (Elf::CachingEnabled() && !name.empty()) {
+ Elf::CacheLock();
+ locked = true;
+ if (offset != 0) {
+ std::string hash(name + ':' + std::to_string(offset));
+ if (Elf::CacheGet(hash, &elf)) {
+ Elf::CacheUnlock();
+ return elf.get();
+ }
+ } else if (Elf::CacheGet(name, &elf)) {
+ Elf::CacheUnlock();
+ return elf.get();
+ }
+ }
+ Memory* memory = CreateMemory(process_memory);
+ if (locked && offset != 0 && elf_offset != 0) {
+ // In this case, the whole file is the elf, need to see if the elf
+ // data was cached.
+ if (Elf::CacheGet(name, &elf)) {
+ delete memory;
+ Elf::CacheUnlock();
+ return elf.get();
+ }
+ }
+ elf.reset(new Elf(memory));
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
- return elf;
+ elf->Init(init_gnu_debugdata);
+
+ if (locked) {
+ Elf::CacheAdd(this);
+ Elf::CacheUnlock();
+ }
+ return elf.get();
}
uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index d711772..f70ed7b 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -78,6 +78,8 @@
void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
const std::vector<std::string>* map_suffixes_to_ignore) {
frames_.clear();
+ last_error_.code = ERROR_NONE;
+ last_error_.address = 0;
bool return_address_attempt = false;
bool adjust_pc = false;
@@ -95,6 +97,7 @@
rel_pc = regs_->pc();
adjusted_rel_pc = rel_pc;
adjusted_pc = rel_pc;
+ last_error_.code = ERROR_INVALID_MAP;
} else {
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
@@ -155,6 +158,7 @@
bool finished;
stepped = elf->Step(rel_pc, adjusted_pc, map_info->elf_offset, regs_,
process_memory_.get(), &finished);
+ elf->GetLastError(&last_error_);
if (stepped && finished) {
break;
}
@@ -180,10 +184,14 @@
}
} else {
return_address_attempt = false;
+ if (max_frames_ == frames_.size()) {
+ last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
+ }
}
// If the pc and sp didn't change, then consider everything stopped.
if (cur_pc == regs_->pc() && cur_sp == regs_->sp()) {
+ last_error_.code = ERROR_REPEATED_FRAME;
break;
}
}
diff --git a/libunwindstack/DwarfError.h b/libunwindstack/include/unwindstack/DwarfError.h
similarity index 89%
rename from libunwindstack/DwarfError.h
rename to libunwindstack/include/unwindstack/DwarfError.h
index 54199b8..763e2cb 100644
--- a/libunwindstack/DwarfError.h
+++ b/libunwindstack/include/unwindstack/DwarfError.h
@@ -21,7 +21,7 @@
namespace unwindstack {
-enum DwarfError : uint8_t {
+enum DwarfErrorCode : uint8_t {
DWARF_ERROR_NONE,
DWARF_ERROR_MEMORY_INVALID,
DWARF_ERROR_ILLEGAL_VALUE,
@@ -31,6 +31,12 @@
DWARF_ERROR_TOO_MANY_ITERATIONS,
DWARF_ERROR_CFA_NOT_DEFINED,
DWARF_ERROR_UNSUPPORTED_VERSION,
+ DWARF_ERROR_NO_FDES,
+};
+
+struct DwarfErrorData {
+ DwarfErrorCode code;
+ uint64_t address;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index e0004aa..03f40d6 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -22,6 +22,7 @@
#include <iterator>
#include <unordered_map>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
@@ -29,7 +30,6 @@
namespace unwindstack {
// Forward declarations.
-enum DwarfError : uint8_t;
class Memory;
class Regs;
@@ -72,7 +72,8 @@
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, fde_count_); }
- DwarfError last_error() { return last_error_; }
+ DwarfErrorCode LastErrorCode() { return last_error_.code; }
+ uint64_t LastErrorAddress() { return last_error_.address; }
virtual bool Init(uint64_t offset, uint64_t size) = 0;
@@ -100,7 +101,7 @@
protected:
DwarfMemory memory_;
- DwarfError last_error_;
+ DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
uint32_t cie32_value_ = 0;
uint64_t cie64_value_ = 0;
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 5f34391..a874709 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -22,6 +22,7 @@
#include <memory>
#include <mutex>
#include <string>
+#include <unordered_map>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Memory.h>
@@ -72,6 +73,10 @@
bool IsValidPc(uint64_t pc);
+ void GetLastError(ErrorData* data);
+ ErrorCode GetLastErrorCode();
+ uint64_t GetLastErrorAddress();
+
bool valid() { return valid_; }
uint32_t machine_type() { return machine_type_; }
@@ -92,6 +97,14 @@
static uint64_t GetLoadBias(Memory* memory);
+ static void SetCachingEnabled(bool enable);
+ static bool CachingEnabled() { return cache_enabled_; }
+
+ static void CacheLock();
+ static void CacheUnlock();
+ static void CacheAdd(MapInfo* info);
+ static bool CacheGet(const std::string& name, std::shared_ptr<Elf>* elf);
+
protected:
bool valid_ = false;
uint64_t load_bias_ = 0;
@@ -105,6 +118,10 @@
std::unique_ptr<Memory> gnu_debugdata_memory_;
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
+
+ static bool cache_enabled_;
+ static std::unordered_map<std::string, std::shared_ptr<Elf>>* cache_;
+ static std::mutex* cache_lock_;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index faa61ee..ea9ec9d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -26,6 +26,7 @@
#include <vector>
#include <unwindstack/DwarfSection.h>
+#include <unwindstack/Error.h>
namespace unwindstack {
@@ -90,6 +91,10 @@
DwarfSection* eh_frame() { return eh_frame_.get(); }
DwarfSection* debug_frame() { return debug_frame_.get(); }
+ const ErrorData& last_error() { return last_error_; }
+ ErrorCode LastErrorCode() { return last_error_.code; }
+ uint64_t LastErrorAddress() { return last_error_.address; }
+
template <typename EhdrType, typename PhdrType>
static uint64_t GetLoadBias(Memory* memory);
@@ -144,6 +149,8 @@
uint8_t soname_type_ = SONAME_UNKNOWN;
std::string soname_;
+ ErrorData last_error_{ERROR_NONE, 0};
+
std::unique_ptr<DwarfSection> eh_frame_;
std::unique_ptr<DwarfSection> debug_frame_;
// The Elf object owns the gnu_debugdata interface object.
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
new file mode 100644
index 0000000..6ed0e0f
--- /dev/null
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_ERROR_H
+#define _LIBUNWINDSTACK_ERROR_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+enum ErrorCode : uint8_t {
+ ERROR_NONE, // No error.
+ ERROR_MEMORY_INVALID, // Memory read failed.
+ ERROR_UNWIND_INFO, // Unable to use unwind information to unwind.
+ ERROR_UNSUPPORTED, // Encountered unsupported feature.
+ ERROR_INVALID_MAP, // Unwind in an invalid map.
+ ERROR_MAX_FRAMES_EXCEEDED, // The number of frames exceed the total allowed.
+ ERROR_REPEATED_FRAME, // The last frame has the same pc/sp as the next.
+};
+
+struct ErrorData {
+ ErrorCode code;
+ uint64_t address; // Only valid when code is ERROR_MEMORY_INVALID.
+ // Indicates the failing address.
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 22e48f7..a57fe68 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <atomic>
+#include <memory>
#include <mutex>
#include <string>
@@ -40,14 +41,14 @@
flags(flags),
name(name),
load_bias(static_cast<uint64_t>(-1)) {}
- ~MapInfo() { delete elf; }
+ ~MapInfo() = default;
uint64_t start = 0;
uint64_t end = 0;
uint64_t offset = 0;
uint16_t flags = 0;
std::string name;
- Elf* elf = nullptr;
+ std::shared_ptr<Elf> elf;
// This value is only non-zero if the offset is non-zero but there is
// no elf signature found at that offset. This indicates that the
// entire file is represented by the Memory object returned by CreateMemory,
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 32858ae..a7b57e6 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,6 +24,7 @@
#include <string>
#include <vector>
+#include <unwindstack/Error.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -74,6 +75,9 @@
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+ ErrorCode LastErrorCode() { return last_error_.code; }
+ uint64_t LastErrorAddress() { return last_error_.address; }
+
private:
void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
@@ -83,6 +87,7 @@
std::vector<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
JitDebug* jit_debug_ = nullptr;
+ ErrorData last_error_;
};
} // namespace unwindstack
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
index caad131..8d0f0e5 100644
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ b/libunwindstack/tests/ArmExidxExtractTest.cpp
@@ -257,22 +257,27 @@
TEST_F(ArmExidxExtractTest, read_failures) {
ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+ EXPECT_EQ(0x5004U, exidx_->status_address());
elf_memory_.SetData32(0x5000, 0x100);
ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+ EXPECT_EQ(0x5004U, exidx_->status_address());
elf_memory_.SetData32(0x5004, 0x100);
ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+ EXPECT_EQ(0x5104U, exidx_->status_address());
elf_memory_.SetData32(0x5104, 0x1);
ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+ EXPECT_EQ(0x5108U, exidx_->status_address());
elf_memory_.SetData32(0x5108, 0x01010203);
ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+ EXPECT_EQ(0x510cU, exidx_->status_address());
}
TEST_F(ArmExidxExtractTest, malformed) {
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 73a67ac..68dc30c 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -21,13 +21,13 @@
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>
#include <unwindstack/Log.h>
#include "DwarfCfa.h"
-#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -78,7 +78,7 @@
dwarf_loc_regs_t loc_regs;
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode());
ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
ASSERT_EQ("", GetFakeLogPrint());
@@ -198,7 +198,7 @@
dwarf_loc_regs_t loc_regs;
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
ASSERT_EQ(0U, loc_regs.size());
@@ -227,7 +227,7 @@
dwarf_loc_regs_t loc_regs;
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4000, 0x4002, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
ASSERT_EQ(0x4002U, this->dmem_->cur_offset());
ASSERT_EQ(0U, loc_regs.size());
@@ -594,7 +594,7 @@
// This fails because the cfa is not defined as a register.
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n",
GetFakeLogPrint());
@@ -637,7 +637,7 @@
// This fails because the cfa is not defined as a register.
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
GetFakeLogPrint());
@@ -679,7 +679,7 @@
// This fails because the cfa is not defined as a register.
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
GetFakeLogPrint());
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 07204bc..c28a41e 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -19,9 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
+
#include "DwarfDebugFrame.h"
#include "DwarfEncoding.h"
-#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -142,7 +143,46 @@
this->memory_.SetData32(0x510c, 0x200);
ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
+ // CIE 32 information.
+ this->memory_.SetData32(0x5000, 0xfc);
+ this->memory_.SetData32(0x5004, 0xffffffff);
+ this->memory_.SetData8(0x5008, 1);
+ this->memory_.SetData8(0x5009, '\0');
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x5100, 0xfc);
+ this->memory_.SetData32(0x5104, 0);
+ this->memory_.SetData32(0x5108, 0x1500);
+ this->memory_.SetData32(0x510c, 0x200);
+
+ this->memory_.SetData32(0x5200, 0xfc);
+ this->memory_.SetData32(0x5204, 0);
+ this->memory_.SetData32(0x5208, 0x2500);
+ this->memory_.SetData32(0x520c, 0x300);
+
+ // CIE 32 information.
+ this->memory_.SetData32(0x5300, 0);
+ this->memory_.SetData32(0x5304, 0xffffffff);
+ this->memory_.SetData8(0x5308, 1);
+ this->memory_.SetData8(0x5309, '\0');
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x5400, 0xfc);
+ this->memory_.SetData32(0x5404, 0x300);
+ this->memory_.SetData32(0x5408, 0x3500);
+ this->memory_.SetData32(0x540c, 0x400);
+
+ this->memory_.SetData32(0x5500, 0xfc);
+ this->memory_.SetData32(0x5504, 0x300);
+ this->memory_.SetData32(0x5508, 0x4500);
+ this->memory_.SetData32(0x550c, 0x500);
+
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
+ ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
}
TYPED_TEST_P(DwarfDebugFrameTest, Init64) {
@@ -228,7 +268,52 @@
this->memory_.SetData64(0x511c, 0x200);
ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
+ // CIE 64 information.
+ this->memory_.SetData32(0x5000, 0xffffffff);
+ this->memory_.SetData64(0x5004, 0xf4);
+ this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
+ this->memory_.SetData8(0x5014, 1);
+ this->memory_.SetData8(0x5015, '\0');
+
+ // FDE 64 information.
+ this->memory_.SetData32(0x5100, 0xffffffff);
+ this->memory_.SetData64(0x5104, 0xf4);
+ this->memory_.SetData64(0x510c, 0);
+ this->memory_.SetData64(0x5114, 0x1500);
+ this->memory_.SetData64(0x511c, 0x200);
+
+ this->memory_.SetData32(0x5200, 0xffffffff);
+ this->memory_.SetData64(0x5204, 0xf4);
+ this->memory_.SetData64(0x520c, 0);
+ this->memory_.SetData64(0x5214, 0x2500);
+ this->memory_.SetData64(0x521c, 0x300);
+
+ // CIE 64 information.
+ this->memory_.SetData32(0x5300, 0xffffffff);
+ this->memory_.SetData64(0x5304, 0);
+ this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
+ this->memory_.SetData8(0x5314, 1);
+ this->memory_.SetData8(0x5315, '\0');
+
+ // FDE 64 information.
+ this->memory_.SetData32(0x5400, 0xffffffff);
+ this->memory_.SetData64(0x5404, 0xf4);
+ this->memory_.SetData64(0x540c, 0x300);
+ this->memory_.SetData64(0x5414, 0x3500);
+ this->memory_.SetData64(0x541c, 0x400);
+
+ this->memory_.SetData32(0x5500, 0xffffffff);
+ this->memory_.SetData64(0x5504, 0xf4);
+ this->memory_.SetData64(0x550c, 0x300);
+ this->memory_.SetData64(0x5514, 0x4500);
+ this->memory_.SetData64(0x551c, 0x500);
+
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600));
+ ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
}
TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
@@ -320,11 +405,11 @@
this->debug_frame_->TestSetFdeCount(0);
uint64_t fde_offset;
ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
this->debug_frame_->TestSetFdeCount(9);
ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
// Odd number of elements.
for (size_t i = 0; i < 9; i++) {
TypeParam pc = 0x1000 * (i + 1);
@@ -338,7 +423,7 @@
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
<< "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
}
// Even number of elements.
@@ -360,7 +445,7 @@
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
<< "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
}
}
@@ -450,9 +535,11 @@
EXPECT_EQ(0x20U, fde->cie->return_address_register);
}
-REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie, Init64,
- Init64_fde_not_following_cie, Init_version1, Init_version4,
- GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie,
+ Init32_do_not_fail_on_bad_next_entry, Init64,
+ Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie,
+ Init_version1, Init_version4, GetFdeOffsetFromPc, GetCieFde32,
+ GetCieFde64);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 3a629f8..a73db65 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -19,9 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
+
#include "DwarfEhFrame.h"
#include "DwarfEncoding.h"
-#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -142,7 +143,7 @@
this->memory_.SetData32(0x510c, 0x200);
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameTest, Init64) {
@@ -228,7 +229,7 @@
this->memory_.SetData64(0x511c, 0x200);
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
@@ -320,11 +321,11 @@
this->eh_frame_->TestSetFdeCount(0);
uint64_t fde_offset;
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
this->eh_frame_->TestSetFdeCount(9);
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
// Odd number of elements.
for (size_t i = 0; i < 9; i++) {
TypeParam pc = 0x1000 * (i + 1);
@@ -337,7 +338,7 @@
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
<< "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
}
// Even number of elements.
@@ -358,7 +359,7 @@
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
<< "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
}
}
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 64b325b..a2ae5eb 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -19,9 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
+
#include "DwarfEhFrameWithHdr.h"
#include "DwarfEncoding.h"
-#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -94,22 +95,32 @@
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
+ // Verify a zero fde count fails to init.
+ this->memory_.SetData32(0x1006, 0);
+ ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
+ ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->LastErrorCode());
+
// Verify an unexpected version will cause a fail.
+ this->memory_.SetData32(0x1006, 126);
this->memory_.SetData8(0x1000, 0);
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
- ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
this->memory_.SetData8(0x1000, 2);
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
- ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
+ this->eh_frame_->TestSetEntriesOffset(0x1000);
+
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
+ EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
+ EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
@@ -178,7 +189,7 @@
uint64_t fde_offset;
EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
// Not an error, just not found.
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
// Even number of elements.
for (size_t i = 0; i < 10; i++) {
TypeParam pc = 0x1000 * (i + 1);
@@ -274,7 +285,7 @@
uint64_t fde_offset;
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
@@ -282,7 +293,7 @@
uint64_t fde_offset;
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) {
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index 234d1c9..3f09dd8 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -21,11 +21,11 @@
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/Log.h>
#include <unwindstack/Regs.h>
-#include "DwarfError.h"
#include "DwarfOp.h"
#include "MemoryFake.h"
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 2d5007b..036226d 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -21,10 +21,10 @@
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/Log.h>
-#include "DwarfError.h"
#include "DwarfOp.h"
#include "MemoryFake.h"
@@ -53,13 +53,14 @@
TYPED_TEST_P(DwarfOpTest, decode) {
// Memory error.
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+ EXPECT_EQ(0U, this->op_->LastErrorAddress());
// No error.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x96});
this->mem_->set_cur_offset(0);
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
ASSERT_EQ(0x96U, this->op_->cur_op());
ASSERT_EQ(1U, this->mem_->cur_offset());
}
@@ -67,7 +68,8 @@
TYPED_TEST_P(DwarfOpTest, eval) {
// Memory error.
ASSERT_FALSE(this->op_->Eval(0, 2, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+ EXPECT_EQ(0U, this->op_->LastErrorAddress());
// Register set.
// Do this first, to verify that subsequent calls reset the value.
@@ -84,7 +86,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_TRUE(this->op_->Eval(0, 8, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
ASSERT_FALSE(this->op_->is_register());
ASSERT_EQ(8U, this->mem_->cur_offset());
ASSERT_EQ(4U, this->op_->StackSize());
@@ -96,7 +98,7 @@
// Infinite loop.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x2f, 0xfd, 0xff});
ASSERT_FALSE(this->op_->Eval(0, 4, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->LastErrorCode());
ASSERT_FALSE(this->op_->is_register());
ASSERT_EQ(0U, this->op_->StackSize());
}
@@ -111,7 +113,7 @@
for (size_t i = 0; i < opcode_buffer.size(); i++) {
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
}
}
@@ -122,7 +124,7 @@
for (size_t i = 0; i < opcode_buffer.size(); i++) {
ASSERT_FALSE(this->op_->Decode(2));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
}
}
@@ -133,7 +135,7 @@
for (size_t i = 0; i < opcode_buffer.size(); i++) {
ASSERT_FALSE(this->op_->Decode(3));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
}
}
@@ -178,7 +180,7 @@
while (this->mem_->cur_offset() < opcode_buffer.size()) {
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->LastErrorCode());
}
}
@@ -216,7 +218,7 @@
this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
@@ -226,7 +228,8 @@
ASSERT_EQ(value, this->op_->StackAt(0));
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+ ASSERT_EQ(0x12345678U, this->op_->LastErrorAddress());
}
TYPED_TEST_P(DwarfOpTest, op_deref_size) {
@@ -235,7 +238,7 @@
this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
// Read all byte sizes up to the sizeof the type.
for (size_t i = 1; i < sizeof(TypeParam); i++) {
@@ -252,17 +255,18 @@
// Zero byte read.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, 0x00});
ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
// Read too many bytes.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, sizeof(TypeParam) + 1});
ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
// Force bad memory read.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x40, 0x94, 0x01});
ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+ EXPECT_EQ(0x4010U, this->op_->LastErrorAddress());
}
TYPED_TEST_P(DwarfOpTest, const_unsigned) {
@@ -529,7 +533,7 @@
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(0x12, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
@@ -577,7 +581,7 @@
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(0x13, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_over) {
@@ -612,7 +616,7 @@
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(0x14, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_pick) {
@@ -654,7 +658,7 @@
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(0x15, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_swap) {
@@ -686,7 +690,7 @@
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(0x16, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_rot) {
@@ -703,19 +707,19 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(3U, this->op_->StackSize());
@@ -753,7 +757,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
@@ -805,13 +809,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
// Two positive values.
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
@@ -854,7 +858,7 @@
ASSERT_EQ(5U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_div) {
@@ -871,13 +875,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -902,13 +906,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -935,13 +939,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -957,7 +961,7 @@
ASSERT_EQ(3U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_mul) {
@@ -974,13 +978,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1003,7 +1007,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
@@ -1034,7 +1038,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
@@ -1067,13 +1071,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1098,13 +1102,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1125,7 +1129,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
@@ -1150,13 +1154,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1181,13 +1185,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1216,13 +1220,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1247,13 +1251,13 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
ASSERT_EQ(2U, this->op_->StackSize());
@@ -1280,7 +1284,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
// Push on a non-zero value with a positive branch.
ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
@@ -1342,12 +1346,12 @@
ASSERT_FALSE(this->op_->Eval(0, 1, DWARF_VERSION_MAX));
ASSERT_EQ(opcode, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
ASSERT_FALSE(this->op_->Eval(1, 4, DWARF_VERSION_MAX));
ASSERT_EQ(opcode, this->op_->cur_op());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
}
@@ -1532,7 +1536,7 @@
// Should fail since this references a non-existent register.
ASSERT_FALSE(this->op_->Eval(2, 4, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_bregx) {
@@ -1560,7 +1564,7 @@
ASSERT_EQ(0x90U, this->op_->StackAt(0));
ASSERT_FALSE(this->op_->Eval(7, 12, DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+ ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
TYPED_TEST_P(DwarfOpTest, op_nop) {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index dfd2ce0..7e10935 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -19,10 +19,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfSection.h>
#include "DwarfEncoding.h"
-#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -67,7 +67,7 @@
}
void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
- void TestClearError() { this->last_error_ = DWARF_ERROR_NONE; }
+ void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
};
template <typename TypeParam>
@@ -102,7 +102,8 @@
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x5000U, this->section_->LastErrorAddress());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) {
@@ -118,7 +119,7 @@
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) {
@@ -172,7 +173,7 @@
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) {
@@ -182,7 +183,7 @@
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) {
@@ -192,7 +193,7 @@
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) {
@@ -203,25 +204,25 @@
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}};
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}};
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}};
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) {
@@ -341,7 +342,7 @@
loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) {
@@ -489,10 +490,12 @@
TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
}
TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
@@ -518,24 +521,24 @@
EXPECT_EQ(4U, cie->code_alignment_factor);
EXPECT_EQ(8, cie->data_alignment_factor);
EXPECT_EQ(0x20U, cie->return_address_register);
- EXPECT_EQ(DWARF_ERROR_NONE, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode());
this->section_->TestClearCachedCieEntry();
// Set version to 0, 2, 5 and verify we fail.
this->memory_.SetData8(0x5008, 0x0);
this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
this->memory_.SetData8(0x5008, 0x2);
this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
this->memory_.SetData8(0x5008, 0x5);
this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
}
TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
@@ -681,10 +684,12 @@
TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
this->section_->TestClearError();
ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
}
TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
new file mode 100644
index 0000000..0086c9e
--- /dev/null
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+
+#include "ElfTestUtils.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class ElfCacheTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() { memory_.reset(new MemoryFake); }
+
+ void SetUp() override { Elf::SetCachingEnabled(true); }
+
+ void TearDown() override { Elf::SetCachingEnabled(false); }
+
+ void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
+ ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
+ size_t ehdr_size;
+ Elf32_Ehdr ehdr32;
+ Elf64_Ehdr ehdr64;
+ void* ptr;
+ if (type == EM_ARM || type == EM_386) {
+ ehdr_size = sizeof(ehdr32);
+ ptr = &ehdr32;
+ TestInitEhdr(&ehdr32, ELFCLASS32, type);
+ } else {
+ ehdr_size = sizeof(ehdr64);
+ ptr = &ehdr64;
+ TestInitEhdr(&ehdr64, ELFCLASS64, type);
+ }
+
+ ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
+ ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
+ }
+
+ void VerifyWithinSameMap(bool cache_enabled);
+ void VerifySameMap(bool cache_enabled);
+
+ static std::shared_ptr<Memory> memory_;
+};
+
+std::shared_ptr<Memory> ElfCacheTest::memory_;
+
+void ElfCacheTest::VerifySameMap(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
+
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ close(tf.fd);
+
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ MapInfo info1(start, end, 0, 0x5, tf.path);
+ MapInfo info2(start, end, 0, 0x5, tf.path);
+
+ Elf* elf1 = info1.GetElf(memory_, true);
+ ASSERT_TRUE(elf1->valid());
+ Elf* elf2 = info2.GetElf(memory_, true);
+ ASSERT_TRUE(elf2->valid());
+
+ if (cache_enabled) {
+ EXPECT_EQ(elf1, elf2);
+ } else {
+ EXPECT_NE(elf1, elf2);
+ }
+}
+
+TEST_F(ElfCacheTest, no_caching) {
+ VerifySameMap(false);
+}
+
+TEST_F(ElfCacheTest, caching_invalid_elf) {
+ VerifySameMap(true);
+}
+
+void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
+
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ WriteElfFile(0x100, &tf, EM_386);
+ WriteElfFile(0x200, &tf, EM_X86_64);
+ lseek(tf.fd, 0x500, SEEK_SET);
+ uint8_t value = 0;
+ write(tf.fd, &value, 1);
+ close(tf.fd);
+
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ // Will have an elf at offset 0 in file.
+ MapInfo info0_1(start, end, 0, 0x5, tf.path);
+ MapInfo info0_2(start, end, 0, 0x5, tf.path);
+ // Will have an elf at offset 0x100 in file.
+ MapInfo info100_1(start, end, 0x100, 0x5, tf.path);
+ MapInfo info100_2(start, end, 0x100, 0x5, tf.path);
+ // Will have an elf at offset 0x200 in file.
+ MapInfo info200_1(start, end, 0x200, 0x5, tf.path);
+ MapInfo info200_2(start, end, 0x200, 0x5, tf.path);
+ // Will have an elf at offset 0 in file.
+ MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
+ MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
+
+ Elf* elf0_1 = info0_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf0_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf0_1->arch());
+ Elf* elf0_2 = info0_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf0_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf0_2->arch());
+ EXPECT_EQ(0U, info0_1.elf_offset);
+ EXPECT_EQ(0U, info0_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf0_1, elf0_2);
+ } else {
+ EXPECT_NE(elf0_1, elf0_2);
+ }
+
+ Elf* elf100_1 = info100_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf100_1->valid());
+ EXPECT_EQ(ARCH_X86, elf100_1->arch());
+ Elf* elf100_2 = info100_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf100_2->valid());
+ EXPECT_EQ(ARCH_X86, elf100_2->arch());
+ EXPECT_EQ(0U, info100_1.elf_offset);
+ EXPECT_EQ(0U, info100_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf100_1, elf100_2);
+ } else {
+ EXPECT_NE(elf100_1, elf100_2);
+ }
+
+ Elf* elf200_1 = info200_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf200_1->valid());
+ EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
+ Elf* elf200_2 = info200_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf200_2->valid());
+ EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
+ EXPECT_EQ(0U, info200_1.elf_offset);
+ EXPECT_EQ(0U, info200_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf200_1, elf200_2);
+ } else {
+ EXPECT_NE(elf200_1, elf200_2);
+ }
+
+ Elf* elf300_1 = info300_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf300_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_1->arch());
+ Elf* elf300_2 = info300_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf300_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_2->arch());
+ EXPECT_EQ(0x300U, info300_1.elf_offset);
+ EXPECT_EQ(0x300U, info300_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf300_1, elf300_2);
+ EXPECT_EQ(elf0_1, elf300_1);
+ } else {
+ EXPECT_NE(elf300_1, elf300_2);
+ EXPECT_NE(elf0_1, elf300_1);
+ }
+}
+
+TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
+ VerifyWithinSameMap(false);
+}
+
+TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
+ VerifyWithinSameMap(true);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 099026c..e232986 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -87,6 +87,10 @@
steps_.clear();
}
+ void FakeSetErrorCode(ErrorCode code) { last_error_.code = code; }
+
+ void FakeSetErrorAddress(uint64_t address) { last_error_.address = address; }
+
private:
std::unordered_map<std::string, uint64_t> globals_;
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index e6763ab..31d6a63 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -303,6 +303,7 @@
// FindEntry fails.
bool finished;
ASSERT_FALSE(interface.StepExidx(0x7000, 0, nullptr, nullptr, &finished));
+ EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// ExtractEntry should fail.
interface.FakeSetStartOffset(0x1000);
@@ -316,14 +317,18 @@
regs.set_sp(regs[ARM_REG_SP]);
regs.set_pc(0x1234);
ASSERT_FALSE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_MEMORY_INVALID, interface.LastErrorCode());
+ EXPECT_EQ(0x1004U, interface.LastErrorAddress());
// Eval should fail.
memory_.SetData32(0x1004, 0x81000000);
ASSERT_FALSE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// Everything should pass.
memory_.SetData32(0x1004, 0x80b0b0b0);
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
ASSERT_FALSE(finished);
ASSERT_EQ(0x1000U, regs.sp());
ASSERT_EQ(0x1000U, regs[ARM_REG_SP]);
@@ -332,9 +337,11 @@
// Load bias is non-zero.
ASSERT_TRUE(interface.StepExidx(0x8000, 0x1000, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
// Pc too small.
ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
}
TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
@@ -356,6 +363,7 @@
// Everything should pass.
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_FALSE(finished);
ASSERT_EQ(0x10004U, regs.sp());
ASSERT_EQ(0x10004U, regs[ARM_REG_SP]);
@@ -379,6 +387,7 @@
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0x10000U, regs.sp());
ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
@@ -401,6 +410,7 @@
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0x10000U, regs.sp());
ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
@@ -427,6 +437,7 @@
bool finished;
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0U, regs.pc());
@@ -439,6 +450,7 @@
regs.set_pc(0x1234);
ASSERT_TRUE(interface.StepExidx(0x7000, 0, ®s, &process_memory_, &finished));
+ EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
ASSERT_TRUE(finished);
ASSERT_EQ(0U, regs.pc());
}
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 7e6a62a..eb85033 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -581,4 +581,30 @@
EXPECT_TRUE(elf.IsValidPc(0x1500));
}
+TEST_F(ElfTest, error_code_not_valid) {
+ ElfFake elf(memory_);
+ elf.FakeSetValid(false);
+
+ ErrorData error{ERROR_MEMORY_INVALID, 0x100};
+ elf.GetLastError(&error);
+ EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
+ EXPECT_EQ(0x100U, error.address);
+}
+
+TEST_F(ElfTest, error_code_valid) {
+ ElfFake elf(memory_);
+ elf.FakeSetValid(true);
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+ elf.FakeSetInterface(interface);
+ interface->FakeSetErrorCode(ERROR_MEMORY_INVALID);
+ interface->FakeSetErrorAddress(0x1000);
+
+ ErrorData error{ERROR_NONE, 0};
+ elf.GetLastError(&error);
+ EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
+ EXPECT_EQ(0x1000U, error.address);
+ EXPECT_EQ(ERROR_MEMORY_INVALID, elf.GetLastErrorCode());
+ EXPECT_EQ(0x1000U, elf.GetLastErrorAddress());
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 1a50989..37628f8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -62,7 +62,7 @@
ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
- map_info->elf = elf;
+ map_info->elf.reset(elf);
map_info = maps_->Get(5);
ASSERT_TRUE(map_info != nullptr);
@@ -72,7 +72,7 @@
interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
- map_info->elf = elf;
+ map_info->elf.reset(elf);
map_info = maps_->Get(6);
ASSERT_TRUE(map_info != nullptr);
@@ -82,7 +82,7 @@
interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
- map_info->elf = elf;
+ map_info->elf.reset(elf);
}
template <typename EhdrType, typename ShdrType>
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 948597b..f599503 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -180,16 +180,14 @@
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.end = 0xfff;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Make sure this test is valid.
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.end = 0x2000;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf != nullptr);
@@ -328,8 +326,7 @@
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.flags = PROT_READ;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf->valid());
@@ -352,15 +349,13 @@
ASSERT_FALSE(elf->valid());
// Set the name to nothing to verify that it still fails.
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.name = "";
elf = info.GetElf(process_memory_, false);
ASSERT_FALSE(elf->valid());
// Change the flags and verify the elf is valid now.
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.flags = PROT_READ;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf->valid());
@@ -403,7 +398,7 @@
}
// Now verify that all of the elf files are exactly the same and valid.
- Elf* elf = info.elf;
+ Elf* elf = info.elf.get();
ASSERT_TRUE(elf != nullptr);
EXPECT_TRUE(elf->valid());
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index 631036b..7e64a8a 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -69,7 +69,7 @@
}
TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
- map_info_->elf = elf_container_.release();
+ map_info_->elf.reset(elf_container_.release());
elf_->FakeSetLoadBias(0);
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
@@ -79,7 +79,7 @@
}
TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
- map_info_->elf = elf_container_.release();
+ map_info_->elf.reset(elf_container_.release());
elf_->FakeSetLoadBias(0);
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
@@ -122,7 +122,7 @@
}
TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
- map_info_->elf = elf_container_.release();
+ map_info_->elf.reset(elf_container_.release());
elf_->FakeSetLoadBias(0x1000);
MultipleThreadTest(0x1000);
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 15d5458..7c06373 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -184,7 +184,7 @@
RegsMips64 regs_mips64;
MapInfo map_info(0x1000, 0x2000);
Elf* invalid_elf = new Elf(new MemoryFake);
- map_info.elf = invalid_elf;
+ map_info.elf.reset(invalid_elf);
regs_arm.set_pc(0x1500);
EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 582ac18..09376ab 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -625,4 +625,127 @@
frame_info);
}
+// The eh_frame_hdr data is present but set to zero fdes. This should
+// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
+// No .gnu_debugdata section in the elf file, so no symbols.
+TEST(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
+ std::string dir(TestGetFileDirectory() + "offline/bad_eh_frame_hdr_arm64/");
+
+ MemoryOffline* memory = new MemoryOffline;
+ ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
+
+ FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ RegsArm64 regs;
+ uint64_t reg_value;
+ ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_PC] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_SP] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_LR] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", ®_value));
+ regs[ARM64_REG_R29] = reg_value;
+ regs.SetFromRaw();
+ fclose(fp);
+
+ fp = fopen((dir + "maps.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ // The file is guaranteed to be less than 4096 bytes.
+ std::vector<char> buffer(4096);
+ ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
+ fclose(fp);
+
+ BufferMaps maps(buffer.data());
+ ASSERT_TRUE(maps.Parse());
+
+ ASSERT_EQ(ARCH_ARM64, regs.Arch());
+
+ std::shared_ptr<Memory> process_memory(memory);
+
+ char* cwd = getcwd(nullptr, 0);
+ ASSERT_EQ(0, chdir(dir.c_str()));
+ Unwinder unwinder(128, &maps, ®s, process_memory);
+ unwinder.Unwind();
+ ASSERT_EQ(0, chdir(cwd));
+ free(cwd);
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0000000000000550 waiter64\n"
+ " #01 pc 0000000000000568 waiter64\n"
+ " #02 pc 000000000000057c waiter64\n"
+ " #03 pc 0000000000000590 waiter64\n"
+ " #04 pc 00000000000a8e98 libc.so (__libc_init+88)\n",
+ frame_info);
+}
+
+// The elf has bad eh_frame unwind information for the pcs. If eh_frame
+// is used first, the unwind will not match the expected output.
+TEST(UnwindOfflineTest, debug_frame_first_x86) {
+ std::string dir(TestGetFileDirectory() + "offline/debug_frame_first_x86/");
+
+ MemoryOffline* memory = new MemoryOffline;
+ ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
+
+ FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ RegsX86 regs;
+ uint64_t reg_value;
+ ASSERT_EQ(1, fscanf(fp, "eax: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_EAX] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "ebx: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_EBX] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "ecx: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_ECX] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "edx: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_EDX] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "ebp: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_EBP] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "edi: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_EDI] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "esi: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_ESI] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "esp: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_ESP] = reg_value;
+ ASSERT_EQ(1, fscanf(fp, "eip: %" SCNx64 "\n", ®_value));
+ regs[X86_REG_EIP] = reg_value;
+ regs.SetFromRaw();
+ fclose(fp);
+
+ fp = fopen((dir + "maps.txt").c_str(), "r");
+ ASSERT_TRUE(fp != nullptr);
+ // The file is guaranteed to be less than 4096 bytes.
+ std::vector<char> buffer(4096);
+ ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
+ fclose(fp);
+
+ BufferMaps maps(buffer.data());
+ ASSERT_TRUE(maps.Parse());
+
+ ASSERT_EQ(ARCH_X86, regs.Arch());
+
+ std::shared_ptr<Memory> process_memory(memory);
+
+ char* cwd = getcwd(nullptr, 0);
+ ASSERT_EQ(0, chdir(dir.c_str()));
+ JitDebug jit_debug(process_memory);
+ Unwinder unwinder(128, &maps, ®s, process_memory);
+ unwinder.SetJitDebug(&jit_debug, regs.Arch());
+ unwinder.Unwind();
+ ASSERT_EQ(0, chdir(cwd));
+ free(cwd);
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000685 waiter (call_level3+53)\n"
+ " #01 pc 000006b7 waiter (call_level2+23)\n"
+ " #02 pc 000006d7 waiter (call_level1+23)\n"
+ " #03 pc 000006f7 waiter (main+23)\n"
+ " #04 pc 00018275 libc.so\n",
+ frame_info);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index cd46807..45cf907 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -60,7 +60,7 @@
maps_.FakeClear();
MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
ElfFake* elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
@@ -73,25 +73,25 @@
info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
@@ -129,6 +129,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -184,6 +185,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -218,6 +220,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -248,6 +251,7 @@
Unwinder unwinder(20, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
ASSERT_EQ(20U, unwinder.NumFrames());
@@ -288,6 +292,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
unwinder.Unwind(&skip_libs);
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -346,6 +351,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -392,6 +398,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@@ -410,6 +417,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@@ -423,6 +431,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -457,6 +466,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -517,6 +527,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -552,6 +563,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
std::vector<std::string> suffixes{"oat"};
unwinder.Unwind(nullptr, &suffixes);
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
ASSERT_EQ(2U, unwinder.NumFrames());
// Make sure the elf was not initialized.
@@ -607,6 +619,7 @@
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
unwinder.Unwind();
+ EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
ASSERT_EQ(3U, unwinder.NumFrames());
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
new file mode 100644
index 0000000..78449bf
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
new file mode 100644
index 0000000..7cada15
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
@@ -0,0 +1,2 @@
+60a9fdf000-60a9fe0000 r-xp 0 00:00 0 waiter64
+7542cc0000-7542d8e000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
new file mode 100644
index 0000000..c24adbe
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
@@ -0,0 +1,4 @@
+pc: 60a9fdf550
+sp: 7fdd141990
+lr: 60a9fdf56c
+x29: 7fdd1419a0
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
new file mode 100644
index 0000000..b56d420
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
new file mode 100644
index 0000000..81bda1d
--- /dev/null
+++ b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
new file mode 100644
index 0000000..9c78790
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
new file mode 100644
index 0000000..74fc89f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
@@ -0,0 +1,2 @@
+56598000-56599000 r-xp 0 00:00 0 waiter
+f7432000-f75e3000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
new file mode 100644
index 0000000..48f4440
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
@@ -0,0 +1,9 @@
+eax: 1d88ef8c
+ebx: 56599fe8
+ecx: 3
+edx: ffcf9ea4
+ebp: ffcf9e48
+edi: f75e5000
+esi: 1
+esp: ffcf9e38
+eip: 56598685
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
new file mode 100644
index 0000000..0cf7d55
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
new file mode 100644
index 0000000..b1fc024
--- /dev/null
+++ b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
Binary files differ
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3bca6c8..2be5d98 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -157,6 +157,7 @@
cc_library {
name: "libutilscallstack",
defaults: ["libutils_defaults"],
+ vendor_available: false,
srcs: [
"CallStack.cpp",
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 76d308a..e16db65 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -18,3 +18,15 @@
},
},
}
+
+cc_library_shared {
+ name: "libstatslogc",
+ srcs: ["statslog.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 3230310..838a5f4 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -1112,7 +1112,16 @@
kill_timeout_ms =
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
- if (mlockall(MCL_CURRENT | MCL_FUTURE))
+ // MCL_ONFAULT pins pages as they fault instead of loading
+ // everything immediately all at once. (Which would be bad,
+ // because as of this writing, we have a lot of mapped pages we
+ // never use.) Old kernels will see MCL_ONFAULT and fail with
+ // EINVAL; we ignore this failure.
+ //
+ // N.B. read the man page for mlockall. MCL_CURRENT | MCL_ONFAULT
+ // pins ⊆ MCL_CURRENT, converging to just MCL_CURRENT as we fault
+ // in pages.
+ if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && errno != EINVAL)
ALOGW("mlockall failed: errno=%d", errno);
sched_setscheduler(0, SCHED_FIFO, ¶m);
diff --git a/lmkd/statslog.c b/lmkd/statslog.c
new file mode 100644
index 0000000..db7a76a
--- /dev/null
+++ b/lmkd/statslog.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2018 Google, Inc
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <log/log_event_list.h>
+#include <log/log_id.h>
+
+/**
+ * Logs the change in LMKD state which is used as start/stop boundaries for logging
+ * LMK_KILL_OCCURRED event.
+ * Code: LMK_STATE_CHANGED = 54
+ */
+int
+stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state) {
+ assert(ctx != NULL);
+ int ret = -EINVAL;
+ if (!ctx) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, code)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, state)) < 0) {
+ return ret;
+ }
+ return ret;
+}
+
+/**
+ * Logs the event when LMKD kills a process to reduce memory pressure.
+ * Code: LMK_KILL_OCCURRED = 51
+ */
+int
+stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
+ char const* process_name, int32_t oom_score, int64_t pgfault,
+ int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
+ int64_t swap_in_bytes) {
+ assert(ctx != NULL);
+ int ret = -EINVAL;
+ if (!ctx) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, code)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, uid)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_string8(ctx, (process_name == NULL) ? "" : process_name)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int32(ctx, oom_score)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, pgfault)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, pgmajfault)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, rss_in_bytes)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, cache_in_bytes)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_int64(ctx, swap_in_bytes)) < 0) {
+ return ret;
+ }
+
+ if ((ret = android_log_write_list(ctx, LOG_ID_STATS)) < 0) {
+ return ret;
+ }
+ return ret;
+}
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
new file mode 100644
index 0000000..ea05fa6
--- /dev/null
+++ b/lmkd/statslog.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 Google, Inc
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+
+/**
+ * Logs the change in LMKD state which is used as start/stop boundaries for logging
+ * LMK_KILL_OCCURRED event.
+ * Code: LMK_STATE_CHANGED = 54
+ */
+int
+stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state);
+
+/**
+ * Logs the event when LMKD kills a process to reduce memory pressure.
+ * Code: LMK_KILL_OCCURRED = 51
+ */
+int
+stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
+ char const* process_name, int32_t oom_score, int64_t pgfault,
+ int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
+ int64_t swap_in_bytes);
+__END_DECLS
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index ca992d6..d8163ab 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -88,6 +88,11 @@
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
endif
+ifdef BOARD_USES_PRODUCTIMAGE
+ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product
+else
+ LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product
+endif
ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
else
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index 2a801fa..c8d87c8 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -55,6 +55,9 @@
namespace.default.permitted.paths += /vendor/app
namespace.default.permitted.paths += /vendor/priv-app
namespace.default.permitted.paths += /oem/app
+namespace.default.permitted.paths += /product/framework
+namespace.default.permitted.paths += /product/app
+namespace.default.permitted.paths += /product/priv-app
namespace.default.permitted.paths += /data
namespace.default.permitted.paths += /mnt/expand
@@ -72,6 +75,9 @@
namespace.default.asan.permitted.paths += /vendor/app
namespace.default.asan.permitted.paths += /vendor/priv-app
namespace.default.asan.permitted.paths += /oem/app
+namespace.default.asan.permitted.paths += /product/framework
+namespace.default.asan.permitted.paths += /product/app
+namespace.default.asan.permitted.paths += /product/priv-app
namespace.default.asan.permitted.paths += /mnt/expand
###############################################################################
@@ -285,10 +291,12 @@
# When these NDK libs are required inside this namespace, then it is redirected
# to the system namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = system
+namespace.vndk.links = system,default
namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.vndk.link.default.allow_all_shared_libs = true
+
###############################################################################
# "system" namespace
#
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f1a0cab..6cefde2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -455,6 +455,8 @@
mkdir /data/misc/gcov 0770 root root
mkdir /data/vendor 0771 root root
+ mkdir /data/vendor_ce 0771 root root
+ mkdir /data/vendor_de 0771 root root
mkdir /data/vendor/hardware 0771 root root
# For security reasons, /data/local/tmp should always be empty.
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index 9f7fc3b..ddd95b2 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -6,6 +6,7 @@
"-Wno-unused-parameter",
"-Wno-unused-const-variable",
"-include bsd-compatibility.h",
+ "-D_FILE_OFFSET_BITS=64",
],
local_include_dirs: ["upstream-netbsd/include/"],
}
diff --git a/usbd/usbd.rc b/usbd/usbd.rc
index c7838e8..809044a 100644
--- a/usbd/usbd.rc
+++ b/usbd/usbd.rc
@@ -2,4 +2,4 @@
class late_start
oneshot
user root
- group root usb
+ group root usb system