Merge changes I3e6e5a22,I6eb3f066
* changes:
adb: cleanup some portions of client usb interfaces
adb: clang-format for adb.h and client/usb_windows.cpp
diff --git a/base/Android.bp b/base/Android.bp
index 0fd00ea..f4a8411 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -64,16 +64,20 @@
target: {
android: {
srcs: [
- "errors_unix.cpp",
"properties.cpp",
- "chrono_utils.cpp",
],
- cppflags: ["-Wexit-time-destructors"],
sanitize: {
misc_undefined: ["integer"],
},
},
+ linux: {
+ srcs: [
+ "chrono_utils.cpp",
+ "errors_unix.cpp",
+ ],
+ cppflags: ["-Wexit-time-destructors"],
+ },
darwin: {
srcs: [
"chrono_utils.cpp",
@@ -82,20 +86,8 @@
cppflags: ["-Wexit-time-destructors"],
},
linux_bionic: {
- srcs: [
- "chrono_utils.cpp",
- "errors_unix.cpp",
- ],
- cppflags: ["-Wexit-time-destructors"],
enabled: true,
},
- linux_glibc: {
- srcs: [
- "chrono_utils.cpp",
- "errors_unix.cpp",
- ],
- cppflags: ["-Wexit-time-destructors"],
- },
windows: {
srcs: [
"errors_windows.cpp",
@@ -127,15 +119,12 @@
],
target: {
android: {
- srcs: [
- "chrono_utils_test.cpp",
- "properties_test.cpp"
- ],
+ srcs: ["properties_test.cpp"],
sanitize: {
misc_undefined: ["integer"],
},
},
- linux_glibc: {
+ linux: {
srcs: ["chrono_utils_test.cpp"],
},
windows: {
diff --git a/base/logging.cpp b/base/logging.cpp
index 6357b4b..75078e5 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -80,7 +80,9 @@
#if defined(__BIONIC__)
return gettid();
#elif defined(__APPLE__)
- return syscall(SYS_thread_selfid);
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 7a45e4d..209e81b 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -70,6 +70,8 @@
false
else
echo "ERROR: '${TEST}' test requires userdebug build, skipping FAILURE"
+ duration_prefix="~"
+ duration_estimate=1
false
fi >&2
}
@@ -130,6 +132,8 @@
return ${save_ret}
fi
echo "ERROR: '${TEST}' test requires functional pstore, skipping FAILURE"
+ duration_prefix="~"
+ duration_estimate=1
fi >&2
}
@@ -792,7 +796,7 @@
- adb shell getprop sys.boot.reason
- NB: should report shutdown,thermal" ]
test_thermal_shutdown() {
- durtion_test ">60"
+ duration_test ">60"
echo " power on request" >&2
adb shell setprop sys.powerctl shutdown,thermal
sleep 5
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index f8eaa1c..2270133 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -212,6 +212,17 @@
{"hard,hw_reset", 72},
{"shutdown,suspend", 73}, // Suspend to RAM
{"shutdown,hibernate", 74}, // Suspend to DISK
+ {"power_on_key", 75},
+ {"reboot_by_key", 76},
+ {"wdt_by_pass_pwk", 77},
+ {"reboot_longkey", 78},
+ {"powerkey", 79},
+ {"usb", 80},
+ {"wdt", 81},
+ {"tool_by_pass_pwk", 82},
+ {"2sec_reboot", 83},
+ {"reboot,by_key", 84},
+ {"reboot,longkey", 85},
};
// Converts a string value representing the reason the system booted to an
@@ -508,7 +519,6 @@
android::base::ReadFdToString(fileno(fp), &content);
}
android_logcat_pclose(&ctx, fp);
- android_logcat_destroy(&ctx);
static const char logcat_battery[] = "W/healthd ( 0): battery l=";
const char* match = logcat_battery;
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index c76762d..032b214 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -19,7 +19,6 @@
#include <fcntl.h>
#include <inttypes.h>
#include <linux/input.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/init/Android.bp b/init/Android.bp
index e906771..8c4f005 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -89,6 +89,7 @@
whole_static_libs: ["libcap"],
static_libs: [
"libbase",
+ "libhidl-gen-utils",
"libselinux",
"liblog",
"libprocessgroup",
@@ -136,6 +137,7 @@
"libfs_mgr",
"libfec",
"libfec_rs",
+ "libhidl-gen-utils",
"libsquashfs_utils",
"liblogwrap",
"libext4_utils",
@@ -185,6 +187,7 @@
],
static_libs: [
"libinit",
+ "libhidl-gen-utils",
"libselinux",
"libcrypto",
"libprotobuf-cpp-lite",
diff --git a/init/Android.mk b/init/Android.mk
index dd0f1bf..44300f6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -64,6 +64,7 @@
libfs_mgr \
libfec \
libfec_rs \
+ libhidl-gen-utils \
libsquashfs_utils \
liblogwrap \
libext4_utils \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 027b392..20f1450 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1014,7 +1014,7 @@
{"verity_load_state", {0, 0, {false, do_verity_load_state}}},
{"verity_update_state", {0, 0, {false, do_verity_update_state}}},
{"wait", {1, 2, {true, do_wait}}},
- {"wait_for_prop", {2, 2, {true, do_wait_for_prop}}},
+ {"wait_for_prop", {2, 2, {false, do_wait_for_prop}}},
{"write", {2, 2, {true, do_write}}},
};
// clang-format on
diff --git a/init/init.cpp b/init/init.cpp
index 51a98a2..571da7c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -202,24 +202,90 @@
return next_process_restart_time;
}
+static Result<Success> DoControlStart(Service* service) {
+ return service->Start();
+}
+
+static Result<Success> DoControlStop(Service* service) {
+ service->Stop();
+ return Success();
+}
+
+static Result<Success> DoControlRestart(Service* service) {
+ service->Restart();
+ return Success();
+}
+
+enum class ControlTarget {
+ SERVICE, // function gets called for the named service
+ INTERFACE, // action gets called for every service that holds this interface
+};
+
+struct ControlMessageFunction {
+ ControlTarget target;
+ std::function<Result<Success>(Service*)> action;
+};
+
+static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
+ // clang-format off
+ static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+ {"start", {ControlTarget::SERVICE, DoControlStart}},
+ {"stop", {ControlTarget::SERVICE, DoControlStop}},
+ {"restart", {ControlTarget::SERVICE, DoControlRestart}},
+ {"interface_start", {ControlTarget::INTERFACE, DoControlStart}},
+ {"interface_stop", {ControlTarget::INTERFACE, DoControlStop}},
+ {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}},
+ };
+ // clang-format on
+
+ return control_message_functions;
+}
+
void handle_control_message(const std::string& msg, const std::string& name) {
- Service* svc = ServiceList::GetInstance().FindService(name);
- if (svc == nullptr) {
- LOG(ERROR) << "no such service '" << name << "'";
+ const auto& map = get_control_message_map();
+ const auto it = map.find(msg);
+
+ if (it == map.end()) {
+ LOG(ERROR) << "Unknown control msg '" << msg << "'";
return;
}
- if (msg == "start") {
- if (auto result = svc->Start(); !result) {
- LOG(ERROR) << "Could not ctl.start service '" << name << "': " << result.error();
+ const ControlMessageFunction& function = it->second;
+
+ if (function.target == ControlTarget::SERVICE) {
+ Service* svc = ServiceList::GetInstance().FindService(name);
+ if (svc == nullptr) {
+ LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
+ return;
}
- } else if (msg == "stop") {
- svc->Stop();
- } else if (msg == "restart") {
- svc->Restart();
- } else {
- LOG(ERROR) << "unknown control msg '" << msg << "'";
+ if (auto result = function.action(svc); !result) {
+ LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
+ << result.error();
+ }
+
+ return;
}
+
+ if (function.target == ControlTarget::INTERFACE) {
+ for (const auto& svc : ServiceList::GetInstance()) {
+ if (svc->interfaces().count(name) == 0) {
+ continue;
+ }
+
+ if (auto result = function.action(svc.get()); !result) {
+ LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
+ << " with interface " << name << ": " << result.error();
+ }
+
+ return;
+ }
+
+ LOG(ERROR) << "Could not find service hosting interface " << name;
+ return;
+ }
+
+ LOG(ERROR) << "Invalid function target from static map key '" << msg
+ << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
}
static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 223d34e..1a44fe3 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
+#include <wchar.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -160,6 +161,12 @@
return PROP_ERROR_INVALID_VALUE;
}
+ if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
+ LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
+ << "value not a UTF8 encoded string";
+ return PROP_ERROR_INVALID_VALUE;
+ }
+
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
if (pi != nullptr) {
// ro.* properties are actually "write-once".
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index 3a64e02..95dd340 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -21,8 +21,11 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <android-base/properties.h>
#include <gtest/gtest.h>
+using android::base::SetProperty;
+
namespace android {
namespace init {
@@ -50,5 +53,19 @@
ASSERT_EQ(0, close(fd));
}
+TEST(property_service, non_utf8_value) {
+ ASSERT_TRUE(SetProperty("property_service_utf8_test", "base_success"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\x80"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xC2\x01"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xE0\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xE0\xA0\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x01\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\xFF"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "\xF0\x90\x80"));
+ EXPECT_FALSE(SetProperty("property_service_utf8_test", "ab\xF0\x90\x80\x80qe\xF0\x90\x80"));
+ EXPECT_TRUE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\x80"));
+}
+
} // namespace init
} // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index b339bc0..765b61e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -37,6 +37,7 @@
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <hidl-util/FQName.h>
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
#include <system/thread_defs.h>
@@ -418,6 +419,37 @@
return Success();
}
+Result<Success> Service::ParseInterface(const std::vector<std::string>& args) {
+ const std::string& interface_name = args[1];
+ const std::string& instance_name = args[2];
+
+ const FQName fq_name = FQName(interface_name);
+ if (!fq_name.isValid()) {
+ return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
+ }
+
+ if (!fq_name.isFullyQualified()) {
+ return Error() << "Interface name not fully-qualified '" << interface_name << "'";
+ }
+
+ if (fq_name.isValidValueName()) {
+ return Error() << "Interface name must not be a value name '" << interface_name << "'";
+ }
+
+ const std::string fullname = interface_name + "/" + instance_name;
+
+ for (const auto& svc : ServiceList::GetInstance()) {
+ if (svc->interfaces().count(fullname) > 0) {
+ return Error() << "Interface '" << fullname << "' redefined in " << name()
+ << " but is already defined by " << svc->name();
+ }
+ }
+
+ interfaces_.insert(fullname);
+
+ return Success();
+}
+
Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
return Error() << "priority value must be range 0 - 7";
@@ -619,6 +651,7 @@
{"critical", {0, 0, &Service::ParseCritical}},
{"disabled", {0, 0, &Service::ParseDisabled}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
+ {"interface", {2, 2, &Service::ParseInterface}},
{"ioprio", {2, 2, &Service::ParseIoprio}},
{"priority", {1, 1, &Service::ParsePriority}},
{"keycodes", {1, kMax, &Service::ParseKeycodes}},
diff --git a/init/service.h b/init/service.h
index 89dd780..593f782 100644
--- a/init/service.h
+++ b/init/service.h
@@ -108,6 +108,7 @@
void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
IoSchedClass ioprio_class() const { return ioprio_class_; }
int ioprio_pri() const { return ioprio_pri_; }
+ const std::set<std::string>& interfaces() const { return interfaces_; }
int priority() const { return priority_; }
int oom_score_adjust() const { return oom_score_adjust_; }
bool process_cgroup_empty() const { return process_cgroup_empty_; }
@@ -132,6 +133,7 @@
Result<Success> ParseDisabled(const std::vector<std::string>& args);
Result<Success> ParseGroup(const std::vector<std::string>& args);
Result<Success> ParsePriority(const std::vector<std::string>& args);
+ Result<Success> ParseInterface(const std::vector<std::string>& args);
Result<Success> ParseIoprio(const std::vector<std::string>& args);
Result<Success> ParseKeycodes(const std::vector<std::string>& args);
Result<Success> ParseOneshot(const std::vector<std::string>& args);
@@ -181,6 +183,8 @@
std::vector<std::string> writepid_files_;
+ std::set<std::string> interfaces_; // e.g. some.package.foo@1.0::IBaz/instance-name
+
// keycodes for triggering this service via /dev/keychord
std::vector<int> keycodes_;
int keychord_id_;
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 927953d..84feeee 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -28,6 +28,7 @@
#include <selinux/android.h>
#include "action.h"
+#include "selinux.h"
#include "system/core/init/subcontext.pb.h"
#include "util.h"
@@ -165,6 +166,7 @@
auto context = std::string(argv[2]);
auto init_fd = std::atoi(argv[3]);
+ SelabelInitialize();
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
subcontext_process.MainLoop();
return 0;
diff --git a/init/subcontext.h b/init/subcontext.h
index ac77e08..eadabee 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -35,7 +35,7 @@
class Subcontext {
public:
Subcontext(std::string path_prefix, std::string context)
- : path_prefix_(path_prefix), context_(std::move(context)) {
+ : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) {
Fork();
}
@@ -55,21 +55,6 @@
android::base::unique_fd socket_;
};
-// For testing, to kill the subcontext after the test has completed.
-class SubcontextKiller {
- public:
- SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {}
- ~SubcontextKiller() {
- if (subcontext_.pid() > 0) {
- kill(subcontext_.pid(), SIGTERM);
- kill(subcontext_.pid(), SIGKILL);
- }
- }
-
- private:
- const Subcontext& subcontext_;
-};
-
int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map);
std::vector<Subcontext>* InitializeSubcontexts();
bool SubcontextChildReap(pid_t pid);
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index a62b959..6307993 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -17,6 +17,7 @@
#include "subcontext.h"
#include <benchmark/benchmark.h>
+#include <selinux/selinux.h>
#include "test_function_map.h"
@@ -24,12 +25,27 @@
namespace init {
static void BenchmarkSuccess(benchmark::State& state) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ if (getuid() != 0) {
+ state.SkipWithError("Skipping benchmark, must be run as root.");
+ return;
+ }
+ char* context;
+ if (getcon(&context) != 0) {
+ state.SkipWithError("getcon() failed");
+ return;
+ }
+
+ auto subcontext = Subcontext("path", context);
+ free(context);
while (state.KeepRunning()) {
subcontext.Execute(std::vector<std::string>{"return_success"});
}
+
+ if (subcontext.pid() > 0) {
+ kill(subcontext.pid(), SIGTERM);
+ kill(subcontext.pid(), SIGKILL);
+ }
}
BENCHMARK(BenchmarkSuccess);
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 60b45b9..ca45266 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -23,6 +23,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <gtest/gtest.h>
+#include <selinux/selinux.h>
#include "builtin_arguments.h"
#include "test_function_map.h"
@@ -38,88 +39,108 @@
namespace android {
namespace init {
+// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have
+// this test runner.
+template <typename F>
+void RunTest(F&& test_function) {
+ if (getuid() != 0) {
+ GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+ return;
+ }
+
+ char* context;
+ ASSERT_EQ(0, getcon(&context));
+ auto context_string = std::string(context);
+ free(context);
+
+ auto subcontext = Subcontext("dummy_path", context_string);
+ ASSERT_NE(0, subcontext.pid());
+
+ test_function(subcontext, context_string);
+
+ if (subcontext.pid() > 0) {
+ kill(subcontext.pid(), SIGTERM);
+ kill(subcontext.pid(), SIGKILL);
+ }
+}
+
TEST(subcontext, CheckDifferentPid) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
+ ASSERT_FALSE(result);
- auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
- ASSERT_FALSE(result);
-
- auto pids = Split(result.error_string(), " ");
- ASSERT_EQ(2U, pids.size());
- auto our_pid = std::to_string(getpid());
- EXPECT_NE(our_pid, pids[0]);
- EXPECT_EQ(our_pid, pids[1]);
+ auto pids = Split(result.error_string(), " ");
+ ASSERT_EQ(2U, pids.size());
+ auto our_pid = std::to_string(getpid());
+ EXPECT_NE(our_pid, pids[0]);
+ EXPECT_EQ(our_pid, pids[1]);
+ });
}
TEST(subcontext, SetProp) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ RunTest([](auto& subcontext, auto& context_string) {
+ SetProperty("init.test.subcontext", "fail");
+ WaitForProperty("init.test.subcontext", "fail");
- SetProperty("init.test.subcontext", "fail");
- WaitForProperty("init.test.subcontext", "fail");
-
- auto args = std::vector<std::string>{
- "setprop",
- "init.test.subcontext",
- "success",
- };
- auto result = subcontext.Execute(args);
- ASSERT_TRUE(result) << result.error();
-
- EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
-}
-
-TEST(subcontext, MultipleCommands) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
-
- auto first_pid = subcontext.pid();
-
- auto expected_words = std::vector<std::string>{
- "this",
- "is",
- "a",
- "test",
- };
-
- for (const auto& word : expected_words) {
auto args = std::vector<std::string>{
- "add_word",
- word,
+ "setprop",
+ "init.test.subcontext",
+ "success",
};
auto result = subcontext.Execute(args);
ASSERT_TRUE(result) << result.error();
- }
- auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
- ASSERT_FALSE(result);
- EXPECT_EQ(Join(expected_words, " "), result.error_string());
- EXPECT_EQ(first_pid, subcontext.pid());
+ EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
+ });
+}
+
+TEST(subcontext, MultipleCommands) {
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto first_pid = subcontext.pid();
+
+ auto expected_words = std::vector<std::string>{
+ "this",
+ "is",
+ "a",
+ "test",
+ };
+
+ for (const auto& word : expected_words) {
+ auto args = std::vector<std::string>{
+ "add_word",
+ word,
+ };
+ auto result = subcontext.Execute(args);
+ ASSERT_TRUE(result) << result.error();
+ }
+
+ auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
+ ASSERT_FALSE(result);
+ EXPECT_EQ(Join(expected_words, " "), result.error_string());
+ EXPECT_EQ(first_pid, subcontext.pid());
+ });
}
TEST(subcontext, RecoverAfterAbort) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto first_pid = subcontext.pid();
- auto first_pid = subcontext.pid();
+ auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
+ ASSERT_FALSE(result);
- auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
- ASSERT_FALSE(result);
-
- auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
- ASSERT_FALSE(result2);
- EXPECT_EQ("Sane error!", result2.error_string());
- EXPECT_NE(subcontext.pid(), first_pid);
+ auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
+ ASSERT_FALSE(result2);
+ EXPECT_EQ("Sane error!", result2.error_string());
+ EXPECT_NE(subcontext.pid(), first_pid);
+ });
}
TEST(subcontext, ContextString) {
- auto subcontext = Subcontext("path", kVendorContext);
- auto subcontext_killer = SubcontextKiller(subcontext);
-
- auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
- ASSERT_FALSE(result);
- ASSERT_EQ(kVendorContext, result.error_string());
+ RunTest([](auto& subcontext, auto& context_string) {
+ auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
+ ASSERT_FALSE(result);
+ ASSERT_EQ(context_string, result.error_string());
+ });
}
TestFunctionMap BuildTestFunctionMap() {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 2f20684..b2c0c0f 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -65,7 +65,7 @@
cc_library {
name: "libbacktrace",
- vendor_available: true,
+ vendor_available: false,
vndk: {
enabled: true,
support_system_process: true,
@@ -83,20 +83,7 @@
darwin: {
enabled: true,
},
- linux_glibc: {
- srcs: libbacktrace_sources,
-
- shared_libs: [
- "libbase",
- "liblog",
- "libunwind",
- "libunwindstack",
- ],
-
- static_libs: ["libcutils"],
- },
- linux_bionic: {
- enabled: true,
+ linux: {
srcs: libbacktrace_sources,
shared_libs: [
@@ -109,16 +96,7 @@
static_libs: ["libcutils"],
},
android: {
- srcs: libbacktrace_sources,
-
- shared_libs: [
- "libbase",
- "liblog",
- "libunwind",
- "libunwindstack",
- ],
-
- static_libs: ["libasync_safe", "libcutils"],
+ static_libs: ["libasync_safe"],
},
},
whole_static_libs: ["libdemangle"],
@@ -135,13 +113,7 @@
srcs: ["backtrace_testlib.cpp"],
target: {
- linux_glibc: {
- shared_libs: [
- "libunwind",
- "libunwindstack",
- ],
- },
- android: {
+ linux: {
shared_libs: [
"libunwind",
"libunwindstack",
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 81f5e32..afe518c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <assert.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
@@ -30,9 +31,10 @@
#include <demangle.h>
#include "BacktraceLog.h"
-#include "thread_utils.h"
#include "UnwindCurrent.h"
#include "UnwindPtrace.h"
+#include "UnwindStack.h"
+#include "thread_utils.h"
using android::base::StringPrintf;
@@ -140,6 +142,34 @@
}
}
+Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
+ if (pid == BACKTRACE_CURRENT_PROCESS) {
+ pid = getpid();
+ if (tid == BACKTRACE_CURRENT_THREAD) {
+ tid = gettid();
+ }
+ } else if (tid == BACKTRACE_CURRENT_THREAD) {
+ tid = pid;
+ }
+
+ if (map == nullptr) {
+// This would cause the wrong type of map object to be created, so disallow.
+#if defined(__ANDROID__)
+ __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
+ "Backtrace::CreateNew() must be called with a real map pointer.");
+#else
+ BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
+ abort();
+#endif
+ }
+
+ if (pid == getpid()) {
+ return new UnwindStackCurrent(pid, tid, map);
+ } else {
+ return new UnwindStackPtrace(pid, tid, map);
+ }
+}
+
std::string Backtrace::GetErrorString(BacktraceUnwindError error) {
switch (error) {
case BACKTRACE_UNWIND_NO_ERROR:
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 41153ce..73bfdec 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -15,7 +15,6 @@
*/
#define _GNU_SOURCE 1
-#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -93,7 +92,7 @@
back_frame->pc = frame->pc;
back_frame->sp = frame->sp;
- back_frame->func_name = frame->function_name;
+ back_frame->func_name = demangle(frame->function_name.c_str());
back_frame->func_offset = frame->function_offset;
back_frame->map.name = frame->map_name;
@@ -149,31 +148,3 @@
error_ = BACKTRACE_UNWIND_NO_ERROR;
return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
}
-
-Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
- if (pid == BACKTRACE_CURRENT_PROCESS) {
- pid = getpid();
- if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = gettid();
- }
- } else if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = pid;
- }
-
- if (map == nullptr) {
-// This would cause the wrong type of map object to be created, so disallow.
-#if defined(__ANDROID__)
- __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
- "Backtrace::CreateNew() must be called with a real map pointer.");
-#else
- BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
- abort();
-#endif
- }
-
- if (pid == getpid()) {
- return new UnwindStackCurrent(pid, tid, map);
- } else {
- return new UnwindStackPtrace(pid, tid, map);
- }
-}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index bab095e..d54eeae 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -22,7 +22,6 @@
#include <errno.h>
#include <fcntl.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index d2645e6..25ff1a3 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -21,7 +21,6 @@
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 036f8c5..4bae39e 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -35,7 +35,9 @@
#ifndef __ANDROID__
pid_t gettid() {
#if defined(__APPLE__)
- return syscall(SYS_thread_selfid);
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 91d551c..4379635 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -21,7 +21,6 @@
#include <inttypes.h>
#include <fcntl.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index dc6591d..edf7ac2 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -35,7 +35,8 @@
namespace unwindstack {
-bool Elf::Init() {
+bool Elf::Init(bool init_gnu_debugdata) {
+ load_bias_ = 0;
if (!memory_) {
return false;
}
@@ -45,9 +46,14 @@
return false;
}
- valid_ = interface_->Init();
+ valid_ = interface_->Init(&load_bias_);
if (valid_) {
interface_->InitHeaders();
+ if (init_gnu_debugdata) {
+ InitGnuDebugdata();
+ } else {
+ gnu_debugdata_interface_.reset(nullptr);
+ }
} else {
interface_.reset(nullptr);
}
@@ -67,7 +73,11 @@
if (gnu == nullptr) {
return;
}
- if (gnu->Init()) {
+
+ // Ignore the load_bias from the compressed section, the correct load bias
+ // is in the uncompressed data.
+ uint64_t load_bias;
+ if (gnu->Init(&load_bias)) {
gnu->InitHeaders();
} else {
// Free all of the memory associated with the gnu_debugdata section.
@@ -81,38 +91,39 @@
}
uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
- uint64_t load_bias = 0;
- if (valid()) {
- load_bias = interface_->load_bias();
- }
-
- return pc - map_info->start + load_bias + map_info->elf_offset;
+ return pc - map_info->start + load_bias_ + map_info->elf_offset;
}
bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
- (gnu_debugdata_interface_ &&
- gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
+ return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
+ (gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
+ addr, load_bias_, name, func_offset)));
}
-bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
+// 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 elf_offset, Regs* regs, Memory* process_memory,
+ bool* finished) {
if (!valid_) {
return false;
}
- if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
+
+ // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
+ if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
*finished = false;
return true;
}
+
+ // Adjust the load bias to get the real relative pc.
+ if (rel_pc < load_bias_) {
+ return false;
+ }
+ rel_pc -= load_bias_;
+
return interface_->Step(rel_pc, regs, process_memory, finished) ||
(gnu_debugdata_interface_ &&
gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
}
-uint64_t Elf::GetLoadBias() {
- if (!valid_) return 0;
- return interface_->load_bias();
-}
-
bool Elf::IsValidElf(Memory* memory) {
if (memory == nullptr) {
return false;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 46a3f3f..20cc1b0 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -118,13 +118,13 @@
}
template <typename EhdrType, typename PhdrType, typename ShdrType>
-bool ElfInterface::ReadAllHeaders() {
+bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
EhdrType ehdr;
if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
return false;
}
- if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
+ if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
return false;
}
@@ -137,7 +137,7 @@
}
template <typename EhdrType, typename PhdrType>
-bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
+bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
@@ -145,7 +145,7 @@
return false;
}
- if (HandleType(offset, phdr.p_type)) {
+ if (HandleType(offset, phdr.p_type, *load_bias)) {
continue;
}
@@ -172,7 +172,7 @@
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
if (phdr.p_offset == 0) {
- load_bias_ = phdr.p_vaddr;
+ *load_bias = phdr.p_vaddr;
}
break;
}
@@ -334,14 +334,14 @@
}
template <typename SymType>
-bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
+bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
uint64_t* func_offset) {
if (symbols_.empty()) {
return false;
}
for (const auto symbol : symbols_) {
- if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) {
+ if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
return true;
}
}
@@ -349,12 +349,6 @@
}
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- // Need to subtract off the load_bias to get the correct pc.
- if (pc < load_bias_) {
- return false;
- }
- pc -= load_bias_;
-
// Try the eh_frame first.
DwarfSection* eh_frame = eh_frame_.get();
if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
@@ -389,11 +383,11 @@
template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
-template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
-template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
+template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
+template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
-template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
+template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
+template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
@@ -401,9 +395,9 @@
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
+template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
uint64_t*);
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
+template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
uint64_t*);
template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 17364d0..30a1532 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -31,12 +31,6 @@
return false;
}
- // Need to subtract the load_bias from the pc.
- if (pc < load_bias_) {
- return false;
- }
- pc -= load_bias_;
-
size_t first = 0;
size_t last = total_entries_;
while (first < last) {
@@ -81,7 +75,7 @@
#define PT_ARM_EXIDX 0x70000001
#endif
-bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
+bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) {
if (type != PT_ARM_EXIDX) {
return false;
}
@@ -93,8 +87,7 @@
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
return true;
}
- // The load_bias_ should always be set by this time.
- start_offset_ = phdr.p_vaddr - load_bias_;
+ start_offset_ = phdr.p_vaddr - load_bias;
total_entries_ = phdr.p_memsz / 8;
return true;
}
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index bfe7704..eeb2e17 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -68,7 +68,7 @@
bool FindEntry(uint32_t pc, uint64_t* entry_offset);
- bool HandleType(uint64_t offset, uint32_t type) override;
+ bool HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) override;
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
@@ -76,13 +76,9 @@
uint64_t start_offset() { return start_offset_; }
- void set_start_offset(uint64_t start_offset) { start_offset_ = start_offset; }
-
size_t total_entries() { return total_entries_; }
- void set_total_entries(size_t total_entries) { total_entries_ = total_entries; }
-
- private:
+ protected:
uint64_t start_offset_ = 0;
size_t total_entries_ = 0;
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 96f2cb4..140d05a 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -110,9 +110,8 @@
}
elf = new Elf(CreateMemory(process_memory));
- if (elf->Init() && init_gnu_debugdata) {
- elf->InitGnuDebugdata();
- }
+ elf->Init(init_gnu_debugdata);
+
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
return elf;
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 69e6512..cf71e39 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -45,7 +45,7 @@
return rel_pc;
}
- uint64_t load_bias = elf->interface()->load_bias();
+ uint64_t load_bias = elf->GetLoadBias();
if (rel_pc < load_bias) {
return rel_pc;
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index e648927..f1580a4 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -52,7 +52,7 @@
}
frame->map_name = map_info->name;
- frame->map_offset = map_info->elf_offset;
+ frame->map_offset = map_info->offset;
frame->map_start = map_info->start;
frame->map_end = map_info->end;
frame->map_flags = map_info->flags;
@@ -64,7 +64,19 @@
}
}
-void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) {
+static bool ShouldStop(const std::set<std::string>* map_suffixes_to_ignore, std::string& map_name) {
+ if (map_suffixes_to_ignore == nullptr) {
+ return false;
+ }
+ auto pos = map_name.find_last_of('.');
+ if (pos == std::string::npos) {
+ return false;
+ }
+ return map_suffixes_to_ignore->find(map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
+}
+
+void Unwinder::Unwind(const std::set<std::string>* initial_map_names_to_skip,
+ const std::set<std::string>* map_suffixes_to_ignore) {
frames_.clear();
bool return_address_attempt = false;
@@ -77,6 +89,9 @@
if (map_info == nullptr) {
rel_pc = regs_->pc();
} else {
+ if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
+ break;
+ }
elf = map_info->GetElf(process_memory_, true);
rel_pc = elf->GetRelPc(regs_->pc(), map_info);
}
@@ -111,8 +126,7 @@
in_device_map = true;
} else {
bool finished;
- stepped =
- elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished);
+ stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
if (stepped && finished) {
break;
}
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index f246beb..294d742 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -40,7 +40,7 @@
Elf(Memory* memory) : memory_(memory) {}
virtual ~Elf() = default;
- bool Init();
+ bool Init(bool init_gnu_debugdata);
void InitGnuDebugdata();
@@ -50,11 +50,12 @@
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
- bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
+ bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
+ bool* finished);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
- uint64_t GetLoadBias();
+ uint64_t GetLoadBias() { return load_bias_; }
bool valid() { return valid_; }
@@ -74,6 +75,7 @@
protected:
bool valid_ = false;
+ uint64_t load_bias_ = 0;
std::unique_ptr<ElfInterface> interface_;
std::unique_ptr<Memory> memory_;
uint32_t machine_type_;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 4fe966f..319623d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -51,13 +51,14 @@
ElfInterface(Memory* memory) : memory_(memory) {}
virtual ~ElfInterface();
- virtual bool Init() = 0;
+ virtual bool Init(uint64_t* load_bias) = 0;
virtual void InitHeaders() = 0;
virtual bool GetSoname(std::string* name) = 0;
- virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
+ virtual bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* offset) = 0;
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
@@ -66,8 +67,6 @@
Memory* memory() { return memory_; }
const std::unordered_map<uint64_t, LoadInfo>& pt_loads() { return pt_loads_; }
- uint64_t load_bias() { return load_bias_; }
- void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; }
uint64_t dynamic_offset() { return dynamic_offset_; }
uint64_t dynamic_size() { return dynamic_size_; }
@@ -86,10 +85,10 @@
void InitHeadersWithTemplate();
template <typename EhdrType, typename PhdrType, typename ShdrType>
- bool ReadAllHeaders();
+ bool ReadAllHeaders(uint64_t* load_bias);
template <typename EhdrType, typename PhdrType>
- bool ReadProgramHeaders(const EhdrType& ehdr);
+ bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
template <typename EhdrType, typename ShdrType>
bool ReadSectionHeaders(const EhdrType& ehdr);
@@ -98,16 +97,16 @@
bool GetSonameWithTemplate(std::string* soname);
template <typename SymType>
- bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
+ bool GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* func_offset);
- virtual bool HandleType(uint64_t, uint32_t) { return false; }
+ virtual bool HandleType(uint64_t, uint32_t, uint64_t) { return false; }
template <typename EhdrType>
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
Memory* memory_;
std::unordered_map<uint64_t, LoadInfo> pt_loads_;
- uint64_t load_bias_ = 0;
// Stored elf data.
uint64_t dynamic_offset_ = 0;
@@ -136,8 +135,8 @@
ElfInterface32(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterface32() = default;
- bool Init() override {
- return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
+ bool Init(uint64_t* load_bias) override {
+ return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
}
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
@@ -146,8 +145,9 @@
return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname);
}
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
- return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
+ bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* func_offset) override {
+ return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, load_bias, name, func_offset);
}
static void GetMaxSize(Memory* memory, uint64_t* size) {
@@ -160,8 +160,8 @@
ElfInterface64(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterface64() = default;
- bool Init() override {
- return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
+ bool Init(uint64_t* load_bias) override {
+ return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
}
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
@@ -170,8 +170,9 @@
return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname);
}
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
- return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
+ bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+ uint64_t* func_offset) override {
+ return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, load_bias, name, func_offset);
}
static void GetMaxSize(Memory* memory, uint64_t* size) {
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 71703b4..ca5933d 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -60,7 +60,8 @@
}
~Unwinder() = default;
- void Unwind(std::set<std::string>* initial_map_names_to_skip = nullptr);
+ void Unwind(const std::set<std::string>* initial_map_names_to_skip = nullptr,
+ const std::set<std::string>* map_suffixes_to_ignore = nullptr);
size_t NumFrames() { return frames_.size(); }
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp
index 71f7f6b..b94a8a4 100644
--- a/libunwindstack/tests/ElfFake.cpp
+++ b/libunwindstack/tests/ElfFake.cpp
@@ -32,7 +32,7 @@
std::deque<FunctionData> ElfInterfaceFake::functions_;
std::deque<StepData> ElfInterfaceFake::steps_;
-bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) {
+bool ElfInterfaceFake::GetFunctionName(uint64_t, uint64_t, std::string* name, uint64_t* offset) {
if (functions_.empty()) {
return false;
}
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 4359bca..565b13f 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -27,6 +27,8 @@
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
+#include "ElfInterfaceArm.h"
+
namespace unwindstack {
struct StepData {
@@ -48,6 +50,10 @@
ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
virtual ~ElfFake() = default;
+ void FakeSetValid(bool valid) { valid_ = valid; }
+
+ void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
+
void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); }
};
@@ -56,15 +62,14 @@
ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {}
virtual ~ElfInterfaceFake() = default;
- bool Init() override { return false; }
+ bool Init(uint64_t*) override { return false; }
void InitHeaders() override {}
bool GetSoname(std::string*) override { return false; }
- bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
+ bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override;
bool Step(uint64_t, Regs*, Memory*, bool*) override;
- void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); }
static void FakePushStepData(const StepData data) { steps_.push_back(data); }
@@ -79,6 +84,37 @@
static std::deque<StepData> steps_;
};
+class ElfInterface32Fake : public ElfInterface32 {
+ public:
+ ElfInterface32Fake(Memory* memory) : ElfInterface32(memory) {}
+ virtual ~ElfInterface32Fake() = default;
+
+ void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
+ void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
+ void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
+ void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
+};
+
+class ElfInterface64Fake : public ElfInterface64 {
+ public:
+ ElfInterface64Fake(Memory* memory) : ElfInterface64(memory) {}
+ virtual ~ElfInterface64Fake() = default;
+
+ void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
+ void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
+ void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
+ void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
+};
+
+class ElfInterfaceArmFake : public ElfInterfaceArm {
+ public:
+ ElfInterfaceArmFake(Memory* memory) : ElfInterfaceArm(memory) {}
+ virtual ~ElfInterfaceArmFake() = default;
+
+ void FakeSetStartOffset(uint64_t offset) { start_offset_ = offset; }
+ void FakeSetTotalEntries(size_t entries) { total_entries_ = entries; }
+};
+
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 4df7e1c..feb24ce 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -25,6 +25,7 @@
#include "ElfInterfaceArm.h"
#include "Machine.h"
+#include "ElfFake.h"
#include "MemoryFake.h"
namespace unwindstack {
@@ -41,7 +42,7 @@
};
TEST_F(ElfInterfaceArmTest, GetPrel32Addr) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
memory_.SetData32(0x1000, 0x230000);
uint32_t value;
@@ -58,36 +59,36 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_start_zero) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0);
- interface.set_total_entries(10);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0);
+ interface.FakeSetTotalEntries(10);
uint64_t entry_offset;
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
}
TEST_F(ElfInterfaceArmTest, FindEntry_no_entries) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x100);
- interface.set_total_entries(0);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x100);
+ interface.FakeSetTotalEntries(0);
uint64_t entry_offset;
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
}
TEST_F(ElfInterfaceArmTest, FindEntry_no_valid_memory) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x100);
- interface.set_total_entries(2);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x100);
+ interface.FakeSetTotalEntries(2);
uint64_t entry_offset;
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
}
TEST_F(ElfInterfaceArmTest, FindEntry_ip_before_first) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
uint64_t entry_offset;
@@ -95,9 +96,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_single_entry_negative_value) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x8000);
- interface.set_total_entries(1);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x8000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x8000, 0x7fffff00);
uint64_t entry_offset;
@@ -106,9 +107,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_two_entries) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x7000);
@@ -117,11 +118,10 @@
ASSERT_EQ(0x1000U, entry_offset);
}
-
TEST_F(ElfInterfaceArmTest, FindEntry_last_check_single_entry) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
uint64_t entry_offset;
@@ -136,9 +136,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_last_check_multiple_entries) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x8000);
@@ -155,9 +155,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_even) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(4);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(4);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x7000);
memory_.SetData32(0x1010, 0x8000);
@@ -178,9 +178,9 @@
}
TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_odd) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(5);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(5);
memory_.SetData32(0x1000, 0x5000);
memory_.SetData32(0x1008, 0x6000);
memory_.SetData32(0x1010, 0x7000);
@@ -203,9 +203,9 @@
}
TEST_F(ElfInterfaceArmTest, iterate) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(5);
+ ElfInterfaceArmFake interface(&memory_);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(5);
memory_.SetData32(0x1000, 0x5000);
memory_.SetData32(0x1008, 0x6000);
memory_.SetData32(0x1010, 0x7000);
@@ -242,56 +242,36 @@
ASSERT_EQ(0xa020U, entries[4]);
}
-TEST_F(ElfInterfaceArmTest, FindEntry_load_bias) {
- ElfInterfaceArm interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1008, 0x8000);
-
- uint64_t entry_offset;
- interface.set_load_bias(0x2000);
- ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
- ASSERT_FALSE(interface.FindEntry(0x8000, &entry_offset));
- ASSERT_FALSE(interface.FindEntry(0x8fff, &entry_offset));
- ASSERT_TRUE(interface.FindEntry(0x9000, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
- ASSERT_TRUE(interface.FindEntry(0xb007, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
- ASSERT_TRUE(interface.FindEntry(0xb008, &entry_offset));
- ASSERT_EQ(0x1008U, entry_offset);
-}
-
TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME, 0));
+ ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK, 0));
}
TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
Elf32_Phdr phdr;
- interface.set_start_offset(0x1000);
- interface.set_total_entries(100);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(100);
phdr.p_vaddr = 0x2000;
phdr.p_memsz = 0xa00;
// Verify that if reads fail, we don't set the values but still get true.
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(100U, interface.total_entries());
@@ -299,7 +279,7 @@
memory_.SetData32(
0x1000 + reinterpret_cast<uint64_t>(&phdr.p_vaddr) - reinterpret_cast<uint64_t>(&phdr),
phdr.p_vaddr);
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(100U, interface.total_entries());
@@ -307,27 +287,26 @@
memory_.SetData32(
0x1000 + reinterpret_cast<uint64_t>(&phdr.p_memsz) - reinterpret_cast<uint64_t>(&phdr),
phdr.p_memsz);
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
ASSERT_EQ(0x2000U, interface.start_offset());
ASSERT_EQ(320U, interface.total_entries());
// Non-zero load bias.
- interface.set_load_bias(0x1000);
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0x1000));
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(320U, interface.total_entries());
}
TEST_F(ElfInterfaceArmTest, StepExidx) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
// FindEntry fails.
bool finished;
ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
// ExtractEntry should fail.
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1008, 0x8000);
@@ -353,10 +332,10 @@
}
TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(2);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(2);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1004, 0x808800b0);
memory_.SetData32(0x1008, 0x8000);
@@ -379,10 +358,10 @@
}
TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1004, 1);
@@ -401,10 +380,10 @@
}
TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
- ElfInterfaceArm interface(&memory_);
+ ElfInterfaceArmFake interface(&memory_);
- interface.set_start_offset(0x1000);
- interface.set_total_entries(1);
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
memory_.SetData32(0x1000, 0x6000);
memory_.SetData32(0x1004, 0x808000b0);
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index acb7320..2752e99 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -25,6 +25,7 @@
#include "DwarfEncoding.h"
#include "ElfInterfaceArm.h"
+#include "ElfFake.h"
#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
@@ -134,7 +135,9 @@
phdr.p_align = 0x1000;
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -190,7 +193,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(3U, pt_loads.size());
@@ -257,7 +262,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * (sizeof(phdr) + 100), &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(3U, pt_loads.size());
@@ -326,7 +333,9 @@
phdr.p_align = 0x1002;
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -398,7 +407,9 @@
memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
phdr_offset += sizeof(phdr);
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0x2000U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
@@ -438,7 +449,9 @@
memory_.SetData32(0x2000, 0x1000);
memory_.SetData32(0x2008, 0x1000);
- ASSERT_TRUE(elf_arm.Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf_arm.Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
std::vector<uint32_t> entries;
for (auto addr : elf_arm) {
@@ -493,7 +506,10 @@
SetStringMemory(0x10010, "fake_soname.so");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+
std::string name;
ASSERT_TRUE(elf->GetSoname(&name));
ASSERT_STREQ("fake_soname.so", name.c_str());
@@ -549,7 +565,10 @@
SetStringMemory(0x10010, "fake_soname.so");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+
std::string name;
ASSERT_FALSE(elf->GetSoname(&name));
}
@@ -603,7 +622,10 @@
SetStringMemory(0x10010, "fake_soname.so");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
+
std::string name;
ASSERT_FALSE(elf->GetSoname(&name));
}
@@ -616,38 +638,14 @@
SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
}
-class MockElfInterface32 : public ElfInterface32 {
- public:
- MockElfInterface32(Memory* memory) : ElfInterface32(memory) {}
- virtual ~MockElfInterface32() = default;
-
- void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
- void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
-
- void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
- void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
-class MockElfInterface64 : public ElfInterface64 {
- public:
- MockElfInterface64(Memory* memory) : ElfInterface64(memory) {}
- virtual ~MockElfInterface64() = default;
-
- void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
- void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
-
- void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
- void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
template <typename ElfType>
void ElfInterfaceTest::InitHeadersEhFrameTest() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0x10000);
- elf.TestSetEhFrameSize(0);
- elf.TestSetDebugFrameOffset(0);
- elf.TestSetDebugFrameSize(0);
+ elf.FakeSetEhFrameOffset(0x10000);
+ elf.FakeSetEhFrameSize(0);
+ elf.FakeSetDebugFrameOffset(0);
+ elf.FakeSetDebugFrameSize(0);
memory_.SetMemory(0x10000,
std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata2, DW_EH_PE_udata2});
@@ -661,21 +659,21 @@
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame32) {
- InitHeadersEhFrameTest<MockElfInterface32>();
+ InitHeadersEhFrameTest<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame64) {
- InitHeadersEhFrameTest<MockElfInterface64>();
+ InitHeadersEhFrameTest<ElfInterface64Fake>();
}
template <typename ElfType>
void ElfInterfaceTest::InitHeadersDebugFrame() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0);
- elf.TestSetEhFrameSize(0);
- elf.TestSetDebugFrameOffset(0x5000);
- elf.TestSetDebugFrameSize(0x200);
+ elf.FakeSetEhFrameOffset(0);
+ elf.FakeSetEhFrameSize(0);
+ elf.FakeSetDebugFrameOffset(0x5000);
+ elf.FakeSetDebugFrameSize(0x200);
memory_.SetData32(0x5000, 0xfc);
memory_.SetData32(0x5004, 0xffffffff);
@@ -694,21 +692,21 @@
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame32) {
- InitHeadersDebugFrame<MockElfInterface32>();
+ InitHeadersDebugFrame<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame64) {
- InitHeadersDebugFrame<MockElfInterface64>();
+ InitHeadersDebugFrame<ElfInterface64Fake>();
}
template <typename ElfType>
void ElfInterfaceTest::InitHeadersEhFrameFail() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0x1000);
- elf.TestSetEhFrameSize(0x100);
- elf.TestSetDebugFrameOffset(0);
- elf.TestSetDebugFrameSize(0);
+ elf.FakeSetEhFrameOffset(0x1000);
+ elf.FakeSetEhFrameSize(0x100);
+ elf.FakeSetDebugFrameOffset(0);
+ elf.FakeSetDebugFrameSize(0);
elf.InitHeaders();
@@ -719,21 +717,21 @@
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
- InitHeadersEhFrameFail<MockElfInterface32>();
+ InitHeadersEhFrameFail<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
- InitHeadersEhFrameFail<MockElfInterface64>();
+ InitHeadersEhFrameFail<ElfInterface64Fake>();
}
template <typename ElfType>
void ElfInterfaceTest::InitHeadersDebugFrameFail() {
ElfType elf(&memory_);
- elf.TestSetEhFrameOffset(0);
- elf.TestSetEhFrameSize(0);
- elf.TestSetDebugFrameOffset(0x1000);
- elf.TestSetDebugFrameSize(0x100);
+ elf.FakeSetEhFrameOffset(0);
+ elf.FakeSetEhFrameSize(0);
+ elf.FakeSetDebugFrameOffset(0x1000);
+ elf.FakeSetDebugFrameSize(0x100);
elf.InitHeaders();
@@ -744,11 +742,11 @@
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
- InitHeadersDebugFrameFail<MockElfInterface32>();
+ InitHeadersDebugFrameFail<ElfInterface32Fake>();
}
TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
- InitHeadersDebugFrameFail<MockElfInterface64>();
+ InitHeadersDebugFrameFail<ElfInterface64Fake>();
}
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
@@ -762,7 +760,9 @@
ehdr.e_shentsize = sizeof(Shdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
}
TEST_F(ElfInterfaceTest, init_section_headers_malformed32) {
@@ -827,7 +827,9 @@
InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one");
InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two");
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
EXPECT_EQ(0U, elf->debug_frame_offset());
EXPECT_EQ(0U, elf->debug_frame_size());
EXPECT_EQ(0U, elf->gnu_debugdata_offset());
@@ -836,10 +838,10 @@
// Look in the first symbol table.
std::string name;
uint64_t name_offset;
- ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset));
+ ASSERT_TRUE(elf->GetFunctionName(0x90010, 0, &name, &name_offset));
EXPECT_EQ("function_one", name);
EXPECT_EQ(16U, name_offset);
- ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset));
+ ASSERT_TRUE(elf->GetFunctionName(0xd0020, 0, &name, &name_offset));
EXPECT_EQ("function_two", name);
EXPECT_EQ(32U, name_offset);
}
@@ -911,7 +913,9 @@
memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
- ASSERT_TRUE(elf->Init());
+ uint64_t load_bias = 0;
+ ASSERT_TRUE(elf->Init(&load_bias));
+ EXPECT_EQ(0U, load_bias);
EXPECT_EQ(0x6000U, elf->debug_frame_offset());
EXPECT_EQ(0x500U, elf->debug_frame_size());
EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 42a0246..4e48fa1 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -20,11 +20,13 @@
#include <sys/types.h>
#include <unistd.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
+#include "ElfFake.h"
#include "ElfTestUtils.h"
#include "LogFake.h"
#include "MemoryFake.h"
@@ -107,7 +109,7 @@
TEST_F(ElfTest, invalid_memory) {
Elf elf(memory_);
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_FALSE(elf.valid());
}
@@ -119,7 +121,7 @@
// Corrupt the ELF signature.
memory_->SetData32(0, 0x7f000000);
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_FALSE(elf.valid());
ASSERT_TRUE(elf.interface() == nullptr);
@@ -130,7 +132,7 @@
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
bool finished;
- ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
+ ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
}
TEST_F(ElfTest, elf32_invalid_machine) {
@@ -139,7 +141,7 @@
InitElf32(EM_PPC);
ResetLogs();
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_EQ("", GetFakeLogBuf());
ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
@@ -152,7 +154,7 @@
InitElf64(EM_PPC64);
ResetLogs();
- ASSERT_FALSE(elf.Init());
+ ASSERT_FALSE(elf.Init(false));
ASSERT_EQ("", GetFakeLogBuf());
ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
@@ -164,7 +166,7 @@
InitElf32(EM_ARM);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -176,7 +178,7 @@
InitElf32(EM_386);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -188,7 +190,7 @@
InitElf64(EM_AARCH64);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -200,7 +202,7 @@
InitElf64(EM_X86_64);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -214,7 +216,7 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
@@ -228,7 +230,7 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(false));
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
@@ -242,14 +244,11 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(true));
ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
-
- elf.InitGnuDebugdata();
- ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
TEST_F(ElfTest, gnu_debugdata_init64) {
@@ -259,42 +258,109 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.Init(true));
ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
-
- elf.InitGnuDebugdata();
- ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
-class MockElf : public Elf {
- public:
- MockElf(Memory* memory) : Elf(memory) {}
- virtual ~MockElf() = default;
-
- void set_valid(bool valid) { valid_ = valid; }
- void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); }
-};
-
TEST_F(ElfTest, rel_pc) {
- MockElf elf(memory_);
+ ElfFake elf(memory_);
- ElfInterface* interface = new ElfInterface32(memory_);
- elf.set_elf_interface(interface);
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+ elf.FakeSetInterface(interface);
- elf.set_valid(true);
- interface->set_load_bias(0);
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0);
MapInfo map_info{.start = 0x1000, .end = 0x2000};
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
- interface->set_load_bias(0x3000);
+ elf.FakeSetLoadBias(0x3000);
ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
- elf.set_valid(false);
+ elf.FakeSetValid(false);
+ elf.FakeSetLoadBias(0);
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
}
+TEST_F(ElfTest, step_in_signal_map) {
+ ElfFake elf(memory_);
+
+ RegsArm regs;
+ regs[13] = 0x50000;
+ regs[15] = 0x8000;
+ regs.SetFromRaw();
+
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+ elf.FakeSetInterface(interface);
+
+ memory_->SetData32(0x3000, 0xdf0027ad);
+ MemoryFake process_memory;
+ process_memory.SetData32(0x50000, 0);
+ for (size_t i = 0; i < 16; i++) {
+ process_memory.SetData32(0x500a0 + i * sizeof(uint32_t), i);
+ }
+
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0);
+ bool finished;
+ ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+ EXPECT_FALSE(finished);
+ EXPECT_EQ(15U, regs.pc());
+ EXPECT_EQ(13U, regs.sp());
+}
+
+class ElfInterfaceMock : public ElfInterface {
+ public:
+ ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
+ virtual ~ElfInterfaceMock() = default;
+
+ bool Init(uint64_t*) override { return false; }
+ void InitHeaders() override {}
+ bool GetSoname(std::string*) override { return false; }
+ bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override { return false; }
+ MOCK_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
+};
+
+TEST_F(ElfTest, step_in_interface) {
+ ElfFake elf(memory_);
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0);
+
+ RegsArm regs;
+
+ ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+ elf.FakeSetInterface(interface);
+ MemoryFake process_memory;
+
+ bool finished;
+ EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
+ .WillOnce(::testing::Return(true));
+
+ ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+}
+
+TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
+ ElfFake elf(memory_);
+ elf.FakeSetValid(true);
+ elf.FakeSetLoadBias(0x4000);
+
+ RegsArm regs;
+
+ ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+ elf.FakeSetInterface(interface);
+ MemoryFake process_memory;
+
+ // Invalid relative pc given load_bias.
+ bool finished;
+ ASSERT_FALSE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
+
+ EXPECT_CALL(*interface, Step(0x3300, ®s, &process_memory, &finished))
+ .WillOnce(::testing::Return(true));
+
+ ASSERT_TRUE(elf.Step(0x7300, 0x2000, ®s, &process_memory, &finished));
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3b9f92b..2a02669 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -115,7 +115,7 @@
RegsArm arm;
// Check fence posts.
- elf_interface_->FakeSetLoadBias(0);
+ elf_->FakeSetLoadBias(0);
ASSERT_EQ(3U, arm.GetAdjustedPc(0x5, elf_.get()));
ASSERT_EQ(4U, arm.GetAdjustedPc(0x4, elf_.get()));
ASSERT_EQ(3U, arm.GetAdjustedPc(0x3, elf_.get()));
@@ -123,7 +123,7 @@
ASSERT_EQ(1U, arm.GetAdjustedPc(0x1, elf_.get()));
ASSERT_EQ(0U, arm.GetAdjustedPc(0x0, elf_.get()));
- elf_interface_->FakeSetLoadBias(0x100);
+ elf_->FakeSetLoadBias(0x100);
ASSERT_EQ(0xffU, arm.GetAdjustedPc(0xff, elf_.get()));
ASSERT_EQ(0x103U, arm.GetAdjustedPc(0x105, elf_.get()));
ASSERT_EQ(0x104U, arm.GetAdjustedPc(0x104, elf_.get()));
@@ -133,13 +133,13 @@
ASSERT_EQ(0x100U, arm.GetAdjustedPc(0x100, elf_.get()));
// Check thumb instructions handling.
- elf_interface_->FakeSetLoadBias(0);
+ elf_->FakeSetLoadBias(0);
memory_->SetData32(0x2000, 0);
ASSERT_EQ(0x2003U, arm.GetAdjustedPc(0x2005, elf_.get()));
memory_->SetData32(0x2000, 0xe000f000);
ASSERT_EQ(0x2001U, arm.GetAdjustedPc(0x2005, elf_.get()));
- elf_interface_->FakeSetLoadBias(0x400);
+ elf_->FakeSetLoadBias(0x400);
memory_->SetData32(0x2100, 0);
ASSERT_EQ(0x2503U, arm.GetAdjustedPc(0x2505, elf_.get()));
memory_->SetData32(0x2100, 0xf111f111);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 4d0366c..8384473 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -95,6 +95,33 @@
info.elf = elf;
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
+
+ info.name = "/fake/compressed.so";
+ info.start = 0x33000;
+ info.end = 0x34000;
+ info.flags = PROT_READ | PROT_WRITE;
+ elf = new ElfFake(nullptr);
+ info.elf = elf;
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ maps_.FakeAddMapInfo(info);
+
+ info.name = "/fake/fake.apk";
+ info.start = 0x43000;
+ info.end = 0x44000;
+ info.offset = 0x1d000;
+ info.flags = PROT_READ | PROT_WRITE;
+ elf = new ElfFake(nullptr);
+ info.elf = elf;
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ maps_.FakeAddMapInfo(info);
+
+ info.name = "/fake/fake.oat";
+ info.start = 0x53000;
+ info.end = 0x54000;
+ info.offset = 0;
+ info.flags = PROT_READ | PROT_WRITE;
+ info.elf = nullptr;
+ maps_.FakeAddMapInfo(info);
}
void SetUp() override {
@@ -170,6 +197,33 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, non_zero_map_offset) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.FakeSetPc(0x43000);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x43000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.apk", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
// Verify that no attempt to continue after the step indicates it is done.
TEST_F(UnwinderTest, no_frames_after_finished) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
@@ -308,7 +362,7 @@
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
regs_.FakeSetPc(0x1000);
- regs_.FakeSetSp(0x53000);
+ regs_.FakeSetSp(0x63000);
ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
@@ -321,7 +375,7 @@
EXPECT_EQ(0U, frame->num);
EXPECT_EQ(0U, frame->rel_pc);
EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x53000U, frame->sp);
+ EXPECT_EQ(0x63000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
@@ -503,6 +557,59 @@
EXPECT_EQ(0, frame->map_flags);
}
+// Verify that an unwind stops when a frame is in given suffix.
+TEST_F(UnwinderTest, map_ignore_suffixes) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
+
+ // Fake as if code called a nullptr function.
+ regs_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0x43402, 0x10010, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ std::set<std::string> suffixes{"oat"};
+ unwinder.Unwind(nullptr, &suffixes);
+
+ ASSERT_EQ(2U, unwinder.NumFrames());
+ // Make sure the elf was not initialized.
+ MapInfo* map_info = maps_.Find(0x53000);
+ ASSERT_TRUE(map_info != nullptr);
+ EXPECT_TRUE(map_info->elf == nullptr);
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x1000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0x400U, frame->rel_pc);
+ EXPECT_EQ(0x43400U, frame->pc);
+ EXPECT_EQ(0x10010U, frame->sp);
+ EXPECT_EQ("Frame1", frame->function_name);
+ EXPECT_EQ(1U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.apk", frame->map_name);
+ EXPECT_EQ(0x1d000U, frame->map_offset);
+ EXPECT_EQ(0x43000U, frame->map_start);
+ EXPECT_EQ(0x44000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame_static) {
FrameData frame;
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 66a9439..77f3bb2 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -53,7 +53,7 @@
uint64_t func_offset;
uint64_t pc = addr + load_bias;
// This might be a thumb function, so set the low bit.
- if (interface->GetFunctionName(pc | 1, &name, &func_offset) && !name.empty()) {
+ if (interface->GetFunctionName(pc | 1, load_bias, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
@@ -92,8 +92,7 @@
printf("\n PC 0x%" PRIx64, fde->pc_start + load_bias);
std::string name;
uint64_t func_offset;
- if (interface->GetFunctionName(fde->pc_start + load_bias, &name, &func_offset) &&
- !name.empty()) {
+ if (interface->GetFunctionName(fde->pc_start, load_bias, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
@@ -115,7 +114,7 @@
}
Elf elf(memory);
- if (!elf.Init() || !elf.valid()) {
+ if (!elf.Init(true) || !elf.valid()) {
printf("%s is not a valid elf file.\n", file);
return 1;
}
@@ -128,7 +127,7 @@
if (interface->eh_frame() != nullptr) {
printf("eh_frame information:\n");
- DumpDwarfSection(interface, interface->eh_frame(), interface->load_bias());
+ DumpDwarfSection(interface, interface->eh_frame(), elf.GetLoadBias());
printf("\n");
} else {
printf("\nno eh_frame information\n");
@@ -136,7 +135,7 @@
if (interface->debug_frame() != nullptr) {
printf("\ndebug_frame information:\n");
- DumpDwarfSection(interface, interface->debug_frame(), interface->load_bias());
+ DumpDwarfSection(interface, interface->debug_frame(), elf.GetLoadBias());
printf("\n");
} else {
printf("\nno debug_frame information\n");
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index dc9ae5a..697e4cd 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -66,7 +66,7 @@
}
unwindstack::Elf elf(memory);
- if (!elf.Init() || !elf.valid()) {
+ if (!elf.Init(true) || !elf.valid()) {
printf("%s is not a valid elf file.\n", argv[1]);
return 1;
}
@@ -90,7 +90,7 @@
}
std::string name;
- uint64_t load_bias = elf.interface()->load_bias();
+ uint64_t load_bias = elf.GetLoadBias();
if (argc == 3) {
std::string cur_name;
uint64_t func_offset;
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 30e6b49..3589e6f 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -93,8 +93,6 @@
target: {
android: {
srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
"Trace.cpp",
],
@@ -112,6 +110,12 @@
misc_undefined: ["integer"],
},
},
+ linux: {
+ srcs: [
+ "Looper.cpp",
+ "ProcessCallStack.cpp",
+ ],
+ },
host: {
cflags: ["-DLIBUTILS_NATIVE=1"],
@@ -121,18 +125,8 @@
},
},
- linux_glibc: {
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
- },
linux_bionic: {
enabled: true,
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
},
darwin: {
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 6911fc5..a891fca 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -34,8 +34,6 @@
target: {
android: {
srcs: [
- "Looper_test.cpp",
- "RefBase_test.cpp",
"SystemClock_test.cpp",
],
shared_libs: [
@@ -46,7 +44,7 @@
"libbase",
],
},
- linux_glibc: {
+ linux: {
srcs: [
"Looper_test.cpp",
"RefBase_test.cpp",
diff --git a/logcat/getopt_long.cpp b/logcat/getopt_long.cpp
index 5f8dd66..da99906 100644
--- a/logcat/getopt_long.cpp
+++ b/logcat/getopt_long.cpp
@@ -49,7 +49,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3d56472..07981fc 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1831,11 +1831,10 @@
}
android::close_output(context);
android::close_error(context);
+
if (context->fds[1] >= 0) {
- // NB: could be closed by the above fclose(s), ignore error.
- int save_errno = errno;
+ // NB: this should be closed by close_output, but just in case...
close(context->fds[1]);
- errno = save_errno;
context->fds[1] = -1;
}
diff --git a/logcat/logcat_system.cpp b/logcat/logcat_system.cpp
index ea393bd..6dfd110 100644
--- a/logcat/logcat_system.cpp
+++ b/logcat/logcat_system.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -98,8 +99,12 @@
return NULL;
}
- FILE* retval = fdopen(fd, "reb");
- if (!retval) android_logcat_destroy(ctx);
+ int duped = dup(fd);
+ FILE* retval = fdopen(duped, "reb");
+ if (!retval) {
+ close(duped);
+ android_logcat_destroy(ctx);
+ }
return retval;
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e199ed4..fd46251 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -178,8 +178,62 @@
# ld.config.txt
include $(CLEAR_VARS)
+_enforce_vndk_at_runtime := false
+
+ifdef BOARD_VNDK_VERSION
+ifneq ($(BOARD_VNDK_RUNTIME_DISABLE),true)
+ _enforce_vndk_at_runtime := true
+endif
+endif
+
+ifeq ($(_enforce_vndk_at_runtime),true)
LOCAL_MODULE := ld.config.txt
-ifeq ($(PRODUCT_FULL_TREBLE),true)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+include $(BUILD_SYSTEM)/base_rules.mk
+vndk_lib_md5 := $(word 1, $(shell echo $(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) | $(MD5SUM)))
+vndk_lib_dep := $(intermediates)/$(vndk_lib_md5).dep
+$(vndk_lib_dep):
+ $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
+
+llndk_libraries := $(subst $(space),:,$(addsuffix .so,$(LLNDK_LIBRARIES)))
+
+vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_SAMEPROCESS_LIBRARIES)))
+
+vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_CORE_LIBRARIES)))
+
+sanitizer_runtime_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+$(UBSAN_RUNTIME_LIBRARY) \
+$(TSAN_RUNTIME_LIBRARY) \
+$(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+$(2ND_UBSAN_RUNTIME_LIBRARY) \
+$(2ND_TSAN_RUNTIME_LIBRARY)))
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(llndk_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(vndk_sameprocess_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_PRIVATE_LIBRARIES := $(llndk_private_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(vndk_core_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in $(vndk_lib_dep)
+ @echo "Generate: $< -> $@"
+ @mkdir -p $(dir $@)
+ $(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
+ $(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $@
+ $(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $@
+ $(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
+
+vndk_lib_md5 :=
+vndk_lib_dep :=
+llndk_libraries :=
+vndk_sameprocess_libraries :=
+vndk_core_libraries :=
+sanitizer_runtime_libraries :=
+else # if _enforce_vndk_at_runtime is not true
+
+LOCAL_MODULE := ld.config.txt
+ifeq ($(PRODUCT_FULL_TREBLE)|$(SANITIZE_TARGET),true|)
LOCAL_SRC_FILES := etc/ld.config.txt
else
LOCAL_SRC_FILES := etc/ld.config.legacy.txt
@@ -188,3 +242,4 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+endif
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 436589e..ce354f2 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,10 @@
dir.system = /system/bin/
dir.system = /system/xbin/
dir.vendor = /vendor/bin/
+dir.test = /data/nativetest/
+dir.test = /data/nativetest64/
+dir.test = /data/benchmarktest/
+dir.test = /data/benchmarktest64/
[system]
additional.namespaces = sphal,vndk,rs
@@ -50,7 +54,7 @@
namespace.sphal.isolated = true
namespace.sphal.visible = true
namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -105,9 +109,23 @@
namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so
-
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
[vendor]
namespace.default.isolated = false
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+
+###############################################################################
+# Namespace config for tests. No VNDK restriction is enforced for these tests.
+###############################################################################
+[test]
+namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
new file mode 100644
index 0000000..e741a34
--- /dev/null
+++ b/rootdir/etc/ld.config.txt.in
@@ -0,0 +1,152 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Bionic loader config file.
+#
+
+# Don't change the order here. The first pattern that matches with the
+# absolution path of an executable is selected.
+dir.system = /system/bin/
+dir.system = /system/xbin/
+dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
+
+[system]
+additional.namespaces = sphal,vndk,rs
+
+###############################################################################
+# "default" namespace
+#
+# Framework-side code runs in this namespace. Libs from /vendor partition
+# can't be loaded in this namespace.
+###############################################################################
+namespace.default.isolated = true
+# TODO(b/63553457): remove /vendor/lib from the search path. For now, this is
+# required since the classloader namespace for vendor apks should have access
+# vendor libraries in the directory. These search paths are copied to the search
+# paths of the classloader namespace.
+namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}
+# /vendor/app, /vendor/framework were added since libart should be able to dlopen
+# the odex files from the directory.
+namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
+
+namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
+
+###############################################################################
+# "sphal" namespace
+#
+# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
+# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
+# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
+#
+# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
+# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
+# that they should be searched and loaded from this namespace.
+#
+# Note that there is no link from the default namespace to this namespace.
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+
+namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = default,vndk,rs
+
+# WARNING: only NDK libs can be listed here.
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+
+# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
+
+###############################################################################
+# "rs" namespace
+#
+# This namespace is exclusively for Renderscript internal libraries.
+# This namespace has slightly looser restriction than the vndk namespace because
+# of the genuine characteristics of Renderscript; /data is in the permitted path
+# to load the compiled *.so file and libmediandk.so can be used here.
+###############################################################################
+namespace.rs.isolated = true
+namespace.rs.visible = true
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.permitted.paths = /vendor/${LIB}:/data
+
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
+
+namespace.rs.links = default,vndk
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is exclusively for vndk-sp libs.
+###############################################################################
+namespace.vndk.isolated = true
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
+
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the default namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = default
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
+[vendor]
+additional.namespaces = system
+
+###############################################################################
+# "default" namespace
+#
+# Vendor-side code runs in this namespace.
+###############################################################################
+namespace.default.isolated = true
+namespace.default.visible = true
+
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+
+namespace.default.links = system
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:libmedia.so:libandroid_runtime.so
+# libmedia.so must be removed after we have fix for lib-dplmedia.so (b/64427765)
+# libandroid_runtime.so must be removed after we have a fix for qseeproxydaemon (b/64820887)
+
+###############################################################################
+# "system" namespace
+#
+# This is for vendor process to use LL-NDK in system partition.
+###############################################################################
+namespace.system.isolated = false
+namespace.system.search.paths = /system/${LIB}
+namespace.system.permitted.paths = /system/${LIB}
+
+namespace.system.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.system.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 3b6867c..6b9d723 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -33,7 +33,8 @@
shared_libs: [
"libcrypto",
"libcutils",
- "libkeymaster1",
+ "libkeymaster_portable",
+ "libkeymaster_staging",
"libtrusty",
"libkeymaster_messages",
"libsoftkeymasterdevice",
diff --git a/trusty/storage/tests/main.cpp b/trusty/storage/tests/main.cpp
index 1fd6f8d..4529136 100644
--- a/trusty/storage/tests/main.cpp
+++ b/trusty/storage/tests/main.cpp
@@ -16,7 +16,6 @@
#include <assert.h>
#include <stdint.h>
-#include <stdbool.h>
#include <gtest/gtest.h>
#include <trusty/lib/storage.h>