Update the tests.

- Change all load_base to load_bias in the test files.
- Add the test files to the backtrace_test.
- Add a function to get the path to the test libraries.
- Change aarch64 to arm64 for offline test code.
- Modify the offline tests so that they can be easily updated when
  unwinding on any arch for any other arch is possible.
- Add tests of CreateNew for remote debugging.

Test: Ran unit tests on host and angler.
Change-Id: Id6c5afe73aeb2ac22463dd81f061799fcb1c178b
This commit is contained in:
Christopher Ferris 2017-08-28 16:31:18 -07:00
parent 9f38e19b88
commit 458cc66b07
9 changed files with 485 additions and 404 deletions

View File

@ -243,6 +243,13 @@ cc_test {
static_libs: ["libutils"],
},
},
data: [
"testdata/arm/*",
"testdata/arm64/*",
"testdata/x86/*",
"testdata/x86_64/*",
],
}
cc_benchmark {

View File

@ -27,6 +27,7 @@
#include <vector>
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <backtrace/Backtrace.h>
@ -129,6 +130,10 @@ static void* OfflineThreadFunc(void* arg) {
return nullptr;
}
std::string GetTestPath(std::string path) {
return android::base::GetExecutableDirectory() + "/testdata/" + ABI_STRING + '/' + path;
}
// This test is disable because it is for generating test data.
TEST(libbacktrace, DISABLED_generate_offline_testdata) {
// Create a thread to generate the needed stack and registers information.
@ -206,20 +211,6 @@ static std::string FunctionNameForAddress(uintptr_t addr,
return "";
}
static std::string GetArch() {
#if defined(__arm__)
return "arm";
#elif defined(__aarch64__)
return "aarch64";
#elif defined(__i386__)
return "x86";
#elif defined(__x86_64__)
return "x86_64";
#else
return "";
#endif
}
struct OfflineTestData {
int pid;
int tid;
@ -280,20 +271,15 @@ bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestDat
return true;
}
static void BacktraceOfflineTest(const std::string& testlib_name) {
const std::string arch = GetArch();
if (arch.empty()) {
GTEST_LOG_(INFO) << "This test does nothing on current arch.";
return;
}
const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
struct stat st;
if (stat(testlib_path.c_str(), &st) == -1) {
GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
static void BacktraceOfflineTest(const char* arch, const std::string& testlib_name) {
// TODO: For now, we can only run this on the same arch as the library arch.
if (std::string(ABI_STRING) != arch) {
GTEST_LOG_(INFO) << "Ignoring arch " << arch << " for lib " << testlib_name;
return;
}
const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
const std::string testlib_path(GetTestPath(testlib_name));
const std::string offline_testdata_path(GetTestPath("offline_testdata"));
OfflineTestData testdata;
ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
@ -339,35 +325,40 @@ static void BacktraceOfflineTest(const std::string& testlib_name) {
testdata.symbols));
}
// For now, these tests can only run on the given architectures.
TEST(libbacktrace, offline_eh_frame) {
BacktraceOfflineTest("libbacktrace_test_eh_frame.so");
BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
}
TEST(libbacktrace, offline_debug_frame) {
BacktraceOfflineTest("libbacktrace_test_debug_frame.so");
BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
}
TEST(libbacktrace, offline_gnu_debugdata) {
BacktraceOfflineTest("libbacktrace_test_gnu_debugdata.so");
BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
}
TEST(libbacktrace, offline_arm_exidx) {
BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
}
// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
// overlap with each other, which appears in /system/lib/libart.so.
TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
const std::string arch = GetArch();
if (arch.empty() || arch != "arm") {
GTEST_LOG_(INFO) << "This test does nothing on current arch.";
// TODO: For now, only run on the given arch.
if (std::string(ABI_STRING) != "arm") {
GTEST_LOG_(INFO) << "Skipping test since offline for arm on " << ABI_STRING
<< " isn't supported.";
return;
}
const std::string testlib_path = "testdata/" + arch + "/libart.so";
const std::string testlib_path(GetTestPath("libart.so"));
struct stat st;
ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata_for_libart";
const std::string offline_testdata_path(GetTestPath("offline_testdata_for_libart"));
OfflineTestData testdata;
ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));

View File

@ -304,8 +304,10 @@ TEST(libbacktrace, local_max_trace) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
}
static void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFunc)(Backtrace*),
void (*VerifyFunc)(Backtrace*)) {
static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
void (*VerifyFunc)(Backtrace*),
Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*),
BacktraceMap* (*map_func)(pid_t, bool)) {
pid_t ptrace_tid;
if (tid < 0) {
ptrace_tid = pid;
@ -322,10 +324,8 @@ static void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFun
WaitForStop(ptrace_tid);
std::unique_ptr<BacktraceMap> map;
if (share_map) {
map.reset(BacktraceMap::Create(pid));
}
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
map.reset(map_func(pid, false));
std::unique_ptr<Backtrace> backtrace(back_func(pid, tid, map.get()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
@ -349,21 +349,22 @@ TEST(libbacktrace, ptrace_trace) {
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump);
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
Backtrace::Create, BacktraceMap::Create);
kill(pid, SIGKILL);
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
TEST(libbacktrace, ptrace_trace_shared_map) {
TEST(libbacktrace, ptrace_trace_new) {
pid_t pid;
if ((pid = fork()) == 0) {
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, true, ReadyLevelBacktrace, VerifyLevelDump);
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
Backtrace::CreateNew, BacktraceMap::CreateNew);
kill(pid, SIGKILL);
int status;
@ -376,7 +377,22 @@ TEST(libbacktrace, ptrace_max_trace) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
BacktraceMap::Create);
kill(pid, SIGKILL);
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
TEST(libbacktrace, ptrace_max_trace_new) {
pid_t pid;
if ((pid = fork()) == 0) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump,
Backtrace::CreateNew, BacktraceMap::CreateNew);
kill(pid, SIGKILL);
int status;
@ -403,7 +419,22 @@ TEST(libbacktrace, ptrace_ignore_frames) {
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
Backtrace::Create, BacktraceMap::Create);
kill(pid, SIGKILL);
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
TEST(libbacktrace, ptrace_ignore_frames_new) {
pid_t pid;
if ((pid = fork()) == 0) {
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
Backtrace::CreateNew, BacktraceMap::CreateNew);
kill(pid, SIGKILL);
int status;
@ -466,7 +497,47 @@ TEST(libbacktrace, ptrace_threads) {
if (pid == *it) {
continue;
}
VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump);
VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::Create,
BacktraceMap::Create);
}
FinishRemoteProcess(pid);
}
TEST(libbacktrace, ptrace_threads_new) {
pid_t pid;
if ((pid = fork()) == 0) {
for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
}
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
// Check to see that all of the threads are running before unwinding.
std::vector<pid_t> threads;
uint64_t start = NanoTime();
do {
usleep(US_PER_MSEC);
threads.clear();
GetThreads(pid, &threads);
} while ((threads.size() != NUM_PTRACE_THREADS + 1) && ((NanoTime() - start) <= 5 * NS_PER_SEC));
ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
WaitForStop(pid);
for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
// Skip the current forked process, we only care about the threads.
if (pid == *it) {
continue;
}
VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::CreateNew,
BacktraceMap::CreateNew);
}
FinishRemoteProcess(pid);
@ -1579,7 +1650,7 @@ TEST(libbacktrace, unwind_disallow_device_map_local) {
munmap(device_map, DEVICE_MAP_SIZE);
}
TEST(libbacktrace, unwind_disallow_device_map_remote) {
TEST(libbacktrace, unwind_disallow_device_map_remote_new) {
void* device_map;
SetupDeviceMap(&device_map);
@ -1588,13 +1659,11 @@ TEST(libbacktrace, unwind_disallow_device_map_remote) {
CreateRemoteProcess(&pid);
// Now create an unwind object.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
std::unique_ptr<BacktraceMap> map(BacktraceMap::CreateNew(pid));
ASSERT_TRUE(map.get() != nullptr);
std::unique_ptr<Backtrace> backtrace(Backtrace::CreateNew(pid, pid, map.get()));
// TODO: Currently unwind from context doesn't work on remote
// unwind. Keep this test because the new unwinder should support
// this eventually, or we can delete this test.
// properly with unwind from context.
// UnwindFromDevice(backtrace.get(), device_map);
UnwindFromDevice(backtrace.get(), device_map);
FinishRemoteProcess(pid);
@ -1633,7 +1702,9 @@ static void SetValueAndLoop(void* data) {
;
}
static void UnwindThroughSignal(bool use_action) {
static void UnwindThroughSignal(bool use_action,
Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*),
BacktraceMap* (*map_func)(pid_t, bool)) {
volatile int value = 0;
pid_t pid;
if ((pid = fork()) == 0) {
@ -1659,7 +1730,8 @@ static void UnwindThroughSignal(bool use_action) {
WaitForStop(pid);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
std::unique_ptr<BacktraceMap> map(map_func(pid, false));
std::unique_ptr<Backtrace> backtrace(back_func(pid, pid, map.get()));
size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)),
reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value));
@ -1677,6 +1749,7 @@ static void UnwindThroughSignal(bool use_action) {
// Wait for the process to get to the signal handler loop.
Backtrace::const_iterator frame_iter;
start = NanoTime();
std::unique_ptr<BacktraceMap> map;
std::unique_ptr<Backtrace> backtrace;
while (true) {
usleep(1000);
@ -1685,7 +1758,9 @@ static void UnwindThroughSignal(bool use_action) {
WaitForStop(pid);
backtrace.reset(Backtrace::Create(pid, pid));
map.reset(map_func(pid, false));
ASSERT_TRUE(map.get() != nullptr);
backtrace.reset(back_func(pid, pid, map.get()));
ASSERT_TRUE(backtrace->Unwind(0));
bool found = false;
for (frame_iter = backtrace->begin(); frame_iter != backtrace->end(); ++frame_iter) {
@ -1742,11 +1817,19 @@ static void UnwindThroughSignal(bool use_action) {
}
TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
UnwindThroughSignal(false);
UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
}
TEST(libbacktrace, unwind_remote_through_signal_using_handler_new) {
UnwindThroughSignal(false, Backtrace::CreateNew, BacktraceMap::CreateNew);
}
TEST(libbacktrace, unwind_remote_through_signal_using_action) {
UnwindThroughSignal(true);
UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
}
TEST(libbacktrace, unwind_remote_through_signal_using_action_new) {
UnwindThroughSignal(true, Backtrace::CreateNew, BacktraceMap::CreateNew);
}
#if defined(ENABLE_PSS_TESTS)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long