Merge "Load libbacktrace_test.so explicitly."

This commit is contained in:
Christopher Ferris 2018-10-03 21:09:25 +00:00 committed by Gerrit Code Review
commit 15a5c9c44f
6 changed files with 215 additions and 260 deletions

View File

@ -27,15 +27,6 @@ cc_defaults {
enabled: false,
},
},
multilib: {
lib32: {
suffix: "32",
},
lib64: {
suffix: "64",
},
},
}
libbacktrace_sources = [
@ -108,7 +99,7 @@ cc_library {
whole_static_libs: ["libdemangle"],
}
cc_library_shared {
cc_test_library {
name: "libbacktrace_test",
defaults: ["libbacktrace_common"],
host_supported: true,
@ -121,6 +112,21 @@ cc_library_shared {
shared_libs: [
"libunwindstack",
],
relative_install_path: "backtrace_test_libs",
target: {
linux_glibc: {
// The host uses rosegment, which isn't supported yet.
ldflags: [
"-Wl,--no-rosegment",
],
// This forces the creation of eh_frame with unwind information
// for host.
cflags: [
"-fcxx-exceptions"
],
},
},
}
//-------------------------------------------------------------------------
@ -128,12 +134,12 @@ cc_library_shared {
//-------------------------------------------------------------------------
cc_test {
name: "backtrace_test",
isolated: true,
defaults: ["libbacktrace_common"],
host_supported: true,
srcs: [
"backtrace_offline_test.cpp",
"backtrace_test.cpp",
"GetPss.cpp",
],
cflags: [
@ -143,7 +149,6 @@ cc_test {
],
shared_libs: [
"libbacktrace_test",
"libbacktrace",
"libbase",
"liblog",
@ -152,17 +157,10 @@ cc_test {
group_static_libs: true,
target: {
android: {
cflags: ["-DENABLE_PSS_TESTS"],
shared_libs: [
"libutils",
],
},
linux_glibc: {
static_libs: ["libutils"],
},
},
// So that the dlopen can find the libbacktrace_test.so.
ldflags: [
"-Wl,--rpath,${ORIGIN}/../backtrace_test_libs",
],
test_suites: ["device-tests"],
data: [

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_BACKTRACE_TEST_H
#define _LIBBACKTRACE_BACKTRACE_TEST_H
#include <dlfcn.h>
#include <gtest/gtest.h>
class BacktraceTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
dl_handle_ = dlopen("libbacktrace_test.so", RTLD_NOW | RTLD_LOCAL);
test_level_one_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
dlsym(dl_handle_, "test_level_one"));
test_level_two_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
dlsym(dl_handle_, "test_level_two"));
test_level_three_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
dlsym(dl_handle_, "test_level_three"));
test_level_four_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
dlsym(dl_handle_, "test_level_four"));
test_recursive_call_ = reinterpret_cast<int (*)(int, void (*)(void*), void*)>(
dlsym(dl_handle_, "test_recursive_call"));
test_get_context_and_wait_ = reinterpret_cast<void (*)(void*, volatile int*)>(
dlsym(dl_handle_, "test_get_context_and_wait"));
test_signal_action_ =
reinterpret_cast<void (*)(int, siginfo_t*, void*)>(dlsym(dl_handle_, "test_signal_action"));
test_signal_handler_ =
reinterpret_cast<void (*)(int)>(dlsym(dl_handle_, "test_signal_handler"));
}
void SetUp() override {
ASSERT_TRUE(dl_handle_ != nullptr);
ASSERT_TRUE(test_level_one_ != nullptr);
ASSERT_TRUE(test_level_two_ != nullptr);
ASSERT_TRUE(test_level_three_ != nullptr);
ASSERT_TRUE(test_level_four_ != nullptr);
ASSERT_TRUE(test_recursive_call_ != nullptr);
ASSERT_TRUE(test_get_context_and_wait_ != nullptr);
ASSERT_TRUE(test_signal_action_ != nullptr);
ASSERT_TRUE(test_signal_handler_ != nullptr);
}
public:
static void* dl_handle_;
static int (*test_level_one_)(int, int, int, int, void (*)(void*), void*);
static int (*test_level_two_)(int, int, int, int, void (*)(void*), void*);
static int (*test_level_three_)(int, int, int, int, void (*)(void*), void*);
static int (*test_level_four_)(int, int, int, int, void (*)(void*), void*);
static int (*test_recursive_call_)(int, void (*)(void*), void*);
static void (*test_get_context_and_wait_)(void*, volatile int*);
static void (*test_signal_action_)(int, siginfo_t*, void*);
static void (*test_signal_handler_)(int);
};
#endif // _LIBBACKTRACE_BACKTRACE_TEST_H

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
// This is an extremely simplified version of libpagemap.
#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1))
#define PAGEMAP_SHIFT(x) (_BITS(x, 55, 6))
#define PAGEMAP_PFN(x) (_BITS(x, 0, 55))
#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
static bool ReadData(int fd, off_t place, uint64_t *data) {
if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
return false;
}
if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
return false;
}
return true;
}
size_t GetPssBytes() {
FILE* maps = fopen("/proc/self/maps", "r");
if (maps == nullptr) {
return 0;
}
int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
if (pagecount_fd == -1) {
fclose(maps);
return 0;
}
int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
if (pagemap_fd == -1) {
fclose(maps);
close(pagecount_fd);
return 0;
}
char line[4096];
size_t total_pss = 0;
int pagesize = getpagesize();
while (fgets(line, sizeof(line), maps)) {
uintptr_t start, end;
if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
total_pss = 0;
break;
}
for (off_t page = static_cast<off_t>(start/pagesize);
page < static_cast<off_t>(end/pagesize); page++) {
uint64_t data;
if (ReadData(pagemap_fd, page, &data)) {
if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
uint64_t count;
if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
total_pss += (count >= 1) ? pagesize / count : 0;
}
}
}
}
}
fclose(maps);
close(pagecount_fd);
close(pagemap_fd);
return total_pss;
}

View File

@ -1,22 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_GET_PSS_H
#define _LIBBACKTRACE_GET_PSS_H
size_t GetPssBytes();
#endif // _LIBBACKTRACE_GET_PSS_H

View File

@ -37,15 +37,7 @@
#include <gtest/gtest.h>
extern "C" {
// Prototypes for functions in the test library.
int test_level_one(int, int, int, int, void (*)(void*), void*);
int test_level_two(int, int, int, int, void (*)(void*), void*);
int test_level_three(int, int, int, int, void (*)(void*), void*);
int test_level_four(int, int, int, int, void (*)(void*), void*);
int test_recursive_call(int, void (*)(void*), void*);
void test_get_context_and_wait(void* context, volatile int* exit_flag);
}
#include "BacktraceTest.h"
struct FunctionSymbol {
std::string name;
@ -56,12 +48,13 @@ struct FunctionSymbol {
static std::vector<FunctionSymbol> GetFunctionSymbols() {
std::vector<FunctionSymbol> symbols = {
{"unknown_start", 0, 0},
{"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
{"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
{"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
{"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
{"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
{"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
{"test_level_one", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_one_), 0},
{"test_level_two", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_two_), 0},
{"test_level_three", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_three_), 0},
{"test_level_four", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_four_), 0},
{"test_recursive_call", reinterpret_cast<uint64_t>(&BacktraceTest::test_recursive_call_), 0},
{"test_get_context_and_wait",
reinterpret_cast<uint64_t>(&BacktraceTest::test_get_context_and_wait_), 0},
{"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
};
std::sort(
@ -100,7 +93,7 @@ struct OfflineThreadArg {
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
fn_arg->tid = android::base::GetThreadId();
test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
BacktraceTest::test_get_context_and_wait_(&fn_arg->ucontext, &fn_arg->exit_flag);
return nullptr;
}
@ -109,7 +102,7 @@ std::string GetTestPath(const std::string& arch, const std::string& path) {
}
// This test is disable because it is for generating test data.
TEST(libbacktrace, DISABLED_generate_offline_testdata) {
TEST_F(BacktraceTest, DISABLED_generate_offline_testdata) {
// Create a thread to generate the needed stack and registers information.
const size_t stack_size = 16 * 1024;
void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@ -304,22 +297,22 @@ static void BacktraceOfflineTest(std::string arch_str, const std::string& testli
}
// For now, these tests can only run on the given architectures.
TEST(libbacktrace, offline_eh_frame) {
TEST_F(BacktraceTest, offline_eh_frame) {
BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
}
TEST(libbacktrace, offline_debug_frame) {
TEST_F(BacktraceTest, offline_debug_frame) {
BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
}
TEST(libbacktrace, offline_gnu_debugdata) {
TEST_F(BacktraceTest, offline_gnu_debugdata) {
BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
}
TEST(libbacktrace, offline_arm_exidx) {
TEST_F(BacktraceTest, offline_arm_exidx) {
BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
}
@ -373,32 +366,32 @@ static void LibUnwindingTest(const std::string& arch_str, const std::string& tes
// 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) {
TEST_F(BacktraceTest, offline_unwind_mix_eh_frame_and_arm_exidx) {
LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
}
TEST(libbacktrace, offline_debug_frame_with_load_bias) {
TEST_F(BacktraceTest, offline_debug_frame_with_load_bias) {
LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
}
TEST(libbacktrace, offline_try_armexidx_after_debug_frame) {
TEST_F(BacktraceTest, offline_try_armexidx_after_debug_frame) {
LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
}
TEST(libbacktrace, offline_cie_with_P_augmentation) {
TEST_F(BacktraceTest, offline_cie_with_P_augmentation) {
// Make sure we can unwind through functions with CIE entry containing P augmentation, which
// makes unwinding library reading personality handler from memory. One example is
// /system/lib64/libskia.so.
LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so");
}
TEST(libbacktrace, offline_empty_eh_frame_hdr) {
TEST_F(BacktraceTest, offline_empty_eh_frame_hdr) {
// Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is
// /vendor/lib64/egl/eglSubDriverAndroid.so.
LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so");
}
TEST(libbacktrace, offline_max_frames_limit) {
TEST_F(BacktraceTest, offline_max_frames_limit) {
// The length of callchain can reach 256 when recording an application.
ASSERT_GE(MAX_BACKTRACE_FRAMES, 256);
}

View File

@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <malloc.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
@ -55,6 +56,7 @@
// For the THREAD_SIGNAL definition.
#include "BacktraceCurrent.h"
#include "BacktraceTest.h"
#include "backtrace_testlib.h"
// Number of microseconds per milliseconds.
@ -95,6 +97,23 @@ static void VerifyLevelDump(Backtrace* backtrace, create_func_t create_func = nu
static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr,
map_create_func_t map_func = nullptr);
void* BacktraceTest::dl_handle_;
int (*BacktraceTest::test_level_one_)(int, int, int, int, void (*)(void*), void*);
int (*BacktraceTest::test_level_two_)(int, int, int, int, void (*)(void*), void*);
int (*BacktraceTest::test_level_three_)(int, int, int, int, void (*)(void*), void*);
int (*BacktraceTest::test_level_four_)(int, int, int, int, void (*)(void*), void*);
int (*BacktraceTest::test_recursive_call_)(int, void (*)(void*), void*);
void (*BacktraceTest::test_get_context_and_wait_)(void*, volatile int*);
void (*BacktraceTest::test_signal_action_)(int, siginfo_t*, void*);
void (*BacktraceTest::test_signal_handler_)(int);
extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
static const char* initial_args[] = {"--slow_threshold_ms=8000", "--deadline_threshold_ms=15000"};
*args = initial_args;
*num_args = 2;
return true;
}
static uint64_t NanoTime() {
struct timespec t = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, &t);
@ -250,7 +269,7 @@ static bool WaitForNonZero(int32_t* value, uint64_t seconds) {
return false;
}
TEST(libbacktrace, local_no_unwind_frames) {
TEST_F(BacktraceTest, local_no_unwind_frames) {
// Verify that a local unwind does not include any frames within
// libunwind or libbacktrace.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@ -270,7 +289,7 @@ TEST(libbacktrace, local_no_unwind_frames) {
}
}
TEST(libbacktrace, local_unwind_frames) {
TEST_F(BacktraceTest, local_unwind_frames) {
// Verify that a local unwind with the skip frames disabled does include
// frames within the backtrace libraries.
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
@ -302,8 +321,8 @@ TEST(libbacktrace, local_unwind_frames) {
<< DumpFrames(backtrace.get());
}
TEST(libbacktrace, local_trace) {
ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
TEST_F(BacktraceTest, local_trace) {
ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
}
static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
@ -357,12 +376,12 @@ static void VerifyLevelIgnoreFrames(void*) {
VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
}
TEST(libbacktrace, local_trace_ignore_frames) {
ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
TEST_F(BacktraceTest, local_trace_ignore_frames) {
ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
}
TEST(libbacktrace, local_max_trace) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
TEST_F(BacktraceTest, 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 (*ReadyFunc)(Backtrace*),
@ -402,10 +421,10 @@ static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
}
TEST(libbacktrace, ptrace_trace) {
TEST_F(BacktraceTest, ptrace_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
@ -416,10 +435,10 @@ TEST(libbacktrace, ptrace_trace) {
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
TEST(libbacktrace, ptrace_max_trace) {
TEST_F(BacktraceTest, ptrace_max_trace) {
pid_t pid;
if ((pid = fork()) == 0) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
@ -446,10 +465,10 @@ static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_fu
VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
}
TEST(libbacktrace, ptrace_ignore_frames) {
TEST_F(BacktraceTest, ptrace_ignore_frames) {
pid_t pid;
if ((pid = fork()) == 0) {
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
@ -462,7 +481,7 @@ TEST(libbacktrace, ptrace_ignore_frames) {
// Create a process with multiple threads and dump all of the threads.
static void* PtraceThreadLevelRun(void*) {
EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
return nullptr;
}
@ -483,7 +502,7 @@ static void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
}
}
TEST(libbacktrace, ptrace_threads) {
TEST_F(BacktraceTest, ptrace_threads) {
pid_t pid;
if ((pid = fork()) == 0) {
for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
@ -494,7 +513,7 @@ TEST(libbacktrace, ptrace_threads) {
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
}
ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
_exit(1);
}
@ -532,8 +551,8 @@ void VerifyLevelThread(void*) {
VerifyLevelDump(backtrace.get());
}
TEST(libbacktrace, thread_current_level) {
ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
TEST_F(BacktraceTest, thread_current_level) {
ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
}
static void VerifyMaxThread(void*) {
@ -545,19 +564,19 @@ static void VerifyMaxThread(void*) {
VerifyMaxDump(backtrace.get());
}
TEST(libbacktrace, thread_current_max) {
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
TEST_F(BacktraceTest, thread_current_max) {
ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxThread, nullptr), 0);
}
static void* ThreadLevelRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = android::base::GetThreadId();
EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, ThreadSetState, data), 0);
return nullptr;
}
TEST(libbacktrace, thread_level_trace) {
TEST_F(BacktraceTest, thread_level_trace) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@ -607,7 +626,7 @@ TEST(libbacktrace, thread_level_trace) {
EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
}
TEST(libbacktrace, thread_ignore_frames) {
TEST_F(BacktraceTest, thread_ignore_frames) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@ -644,11 +663,12 @@ static void* ThreadMaxRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
thread->tid = android::base::GetThreadId();
EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
EXPECT_NE(BacktraceTest::test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, ThreadSetState, data),
0);
return nullptr;
}
TEST(libbacktrace, thread_max_trace) {
TEST_F(BacktraceTest, thread_max_trace) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@ -742,17 +762,17 @@ static void MultipleThreadDumpTest(bool share_map) {
}
}
TEST(libbacktrace, thread_multiple_dump) {
TEST_F(BacktraceTest, thread_multiple_dump) {
MultipleThreadDumpTest(false);
}
TEST(libbacktrace, thread_multiple_dump_same_map) {
TEST_F(BacktraceTest, thread_multiple_dump_same_map) {
MultipleThreadDumpTest(true);
}
// This test is for UnwindMaps that should share the same map cursor when
// multiple maps are created for the current process at the same time.
TEST(libbacktrace, simultaneous_maps) {
TEST_F(BacktraceTest, simultaneous_maps) {
BacktraceMap* map1 = BacktraceMap::Create(getpid());
BacktraceMap* map2 = BacktraceMap::Create(getpid());
BacktraceMap* map3 = BacktraceMap::Create(getpid());
@ -779,7 +799,7 @@ TEST(libbacktrace, simultaneous_maps) {
delete map3;
}
TEST(libbacktrace, fillin_erases) {
TEST_F(BacktraceTest, fillin_erases) {
BacktraceMap* back_map = BacktraceMap::Create(getpid());
backtrace_map_t map;
@ -798,7 +818,7 @@ TEST(libbacktrace, fillin_erases) {
ASSERT_EQ("", map.name);
}
TEST(libbacktrace, format_test) {
TEST_F(BacktraceTest, format_test) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
@ -969,7 +989,7 @@ static void VerifyMap(pid_t pid) {
ASSERT_TRUE(test_it == test_maps.end());
}
TEST(libbacktrace, verify_map_remote) {
TEST_F(BacktraceTest, verify_map_remote) {
pid_t pid;
CreateRemoteProcess(&pid);
@ -1069,7 +1089,7 @@ static void RunReadTest(Backtrace* backtrace, uint64_t read_addr) {
delete[] expected;
}
TEST(libbacktrace, thread_read) {
TEST_F(BacktraceTest, thread_read) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@ -1120,7 +1140,7 @@ static void ForkedReadTest() {
}
}
TEST(libbacktrace, process_read) {
TEST_F(BacktraceTest, process_read) {
g_ready = 0;
pid_t pid;
if ((pid = fork()) == 0) {
@ -1187,29 +1207,23 @@ static void VerifyFunctionsFound(const std::vector<std::string>& found_functions
}
static void CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
std::string system_dir;
#if defined(__BIONIC__)
system_dir = "/system/lib";
#else
const char* host_out_env = getenv("ANDROID_HOST_OUT");
ASSERT_TRUE(host_out_env != nullptr);
system_dir = std::string(host_out_env) + "/lib";
#endif
#if defined(__LP64__)
system_dir += "64";
#endif
std::string test_lib(testing::internal::GetArgvs()[0]);
auto const value = test_lib.find_last_of('/');
if (value == std::string::npos) {
test_lib = "../backtrace_test_libs/";
} else {
test_lib = test_lib.substr(0, value + 1) + "../backtrace_test_libs/";
}
test_lib += "libbacktrace_test.so";
*tmp_so_name = std::string(tmp_dir) + "/libbacktrace_test.so";
std::string cp_cmd =
android::base::StringPrintf("cp %s/libbacktrace_test.so %s", system_dir.c_str(), tmp_dir);
std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
// Copy the shared so to a tempory directory.
ASSERT_EQ(0, system(cp_cmd.c_str()));
}
TEST(libbacktrace, check_unreadable_elf_local) {
TEST_F(BacktraceTest, check_unreadable_elf_local) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@ -1251,7 +1265,7 @@ TEST(libbacktrace, check_unreadable_elf_local) {
VerifyFunctionsFound(found_functions);
}
TEST(libbacktrace, check_unreadable_elf_remote) {
TEST_F(BacktraceTest, check_unreadable_elf_remote) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@ -1390,7 +1404,7 @@ static void VerifyUnreadableElfBacktrace(void* func) {
typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
TEST(libbacktrace, unwind_through_unreadable_elf_local) {
TEST_F(BacktraceTest, unwind_through_unreadable_elf_local) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@ -1405,11 +1419,9 @@ TEST(libbacktrace, unwind_through_unreadable_elf_local) {
ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
0);
ASSERT_TRUE(dlclose(lib_handle) == 0);
}
TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
TEST_F(BacktraceTest, unwind_through_unreadable_elf_remote) {
TemporaryDir td;
std::string tmp_so_name;
ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
@ -1428,7 +1440,6 @@ TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
exit(0);
}
ASSERT_TRUE(pid > 0);
ASSERT_TRUE(dlclose(lib_handle) == 0);
uint64_t start = NanoTime();
bool done = false;
@ -1465,7 +1476,7 @@ TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
ASSERT_TRUE(done) << "Test function never found in unwind.";
}
TEST(libbacktrace, unwind_thread_doesnt_exist) {
TEST_F(BacktraceTest, unwind_thread_doesnt_exist) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999));
ASSERT_TRUE(backtrace.get() != nullptr);
@ -1473,18 +1484,18 @@ TEST(libbacktrace, unwind_thread_doesnt_exist) {
ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError().error_code);
}
TEST(libbacktrace, local_get_function_name_before_unwind) {
TEST_F(BacktraceTest, local_get_function_name_before_unwind) {
std::unique_ptr<Backtrace> backtrace(
Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
// Verify that trying to get a function name before doing an unwind works.
uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
}
TEST(libbacktrace, remote_get_function_name_before_unwind) {
TEST_F(BacktraceTest, remote_get_function_name_before_unwind) {
pid_t pid;
CreateRemoteProcess(&pid);
@ -1492,7 +1503,7 @@ TEST(libbacktrace, remote_get_function_name_before_unwind) {
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
// Verify that trying to get a function name before doing an unwind works.
uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
@ -1579,7 +1590,7 @@ static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
uint64_t cur_func_offset = reinterpret_cast<uint64_t>(BacktraceTest::test_level_one_) + 1;
// Now verify the device map flag actually causes the function name to be empty.
backtrace->FillInMap(cur_func_offset, &map);
ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
@ -1628,7 +1639,7 @@ static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
ASSERT_EQ(0U, backtrace->NumFrames());
}
TEST(libbacktrace, unwind_disallow_device_map_local) {
TEST_F(BacktraceTest, unwind_disallow_device_map_local) {
void* device_map;
SetupDeviceMap(&device_map);
@ -1642,7 +1653,7 @@ TEST(libbacktrace, unwind_disallow_device_map_local) {
munmap(device_map, DEVICE_MAP_SIZE);
}
TEST(libbacktrace, unwind_disallow_device_map_remote) {
TEST_F(BacktraceTest, unwind_disallow_device_map_remote) {
void* device_map;
SetupDeviceMap(&device_map);
@ -1698,13 +1709,13 @@ static void UnwindThroughSignal(bool use_action, create_func_t create_func,
pid_t pid;
if ((pid = fork()) == 0) {
if (use_action) {
ScopedSignalHandler ssh(SIGUSR1, test_signal_action);
ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_action_);
test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
} else {
ScopedSignalHandler ssh(SIGUSR1, test_signal_handler);
ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_handler_);
test_level_one(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
}
}
ASSERT_NE(-1, pid);
@ -1805,11 +1816,11 @@ static void UnwindThroughSignal(bool use_action, create_func_t create_func,
FinishRemoteProcess(pid);
}
TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
TEST_F(BacktraceTest, unwind_remote_through_signal_using_handler) {
UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
}
TEST(libbacktrace, unwind_remote_through_signal_using_action) {
TEST_F(BacktraceTest, unwind_remote_through_signal_using_action) {
UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
}
@ -1822,49 +1833,41 @@ static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t
ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
}
TEST(libbacktrace, unwind_frame_skip_numbering) {
TEST_F(BacktraceTest, unwind_frame_skip_numbering) {
TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
}
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
#define MAX_LEAK_BYTES (32*1024UL)
static void CheckForLeak(pid_t pid, pid_t tid) {
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
// Do a few runs to get the PSS stable.
for (size_t i = 0; i < 100; i++) {
Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
VERIFY_NO_ERROR(backtrace->GetError().error_code);
delete backtrace;
}
size_t stable_pss = GetPssBytes();
ASSERT_TRUE(stable_pss != 0);
// Loop enough that even a small leak should be detectable.
size_t first_allocated_bytes = 0;
size_t last_allocated_bytes = 0;
for (size_t i = 0; i < 4096; i++) {
Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
ASSERT_TRUE(backtrace != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
VERIFY_NO_ERROR(backtrace->GetError().error_code);
delete backtrace;
}
size_t new_pss = GetPssBytes();
ASSERT_TRUE(new_pss != 0);
if (new_pss > stable_pss) {
ASSERT_LE(new_pss - stable_pss, MAX_LEAK_BYTES);
size_t allocated_bytes = mallinfo().uordblks;
if (first_allocated_bytes == 0) {
first_allocated_bytes = allocated_bytes;
} else if (last_allocated_bytes > first_allocated_bytes) {
// Check that the memory did not increase too much over the first loop.
ASSERT_LE(last_allocated_bytes - first_allocated_bytes, MAX_LEAK_BYTES);
}
last_allocated_bytes = allocated_bytes;
}
}
TEST(libbacktrace, check_for_leak_local) {
TEST_F(BacktraceTest, check_for_leak_local) {
CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
}
TEST(libbacktrace, check_for_leak_local_thread) {
TEST_F(BacktraceTest, check_for_leak_local_thread) {
thread_t thread_data = { 0, 0, 0, nullptr };
pthread_t thread;
ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
@ -1880,7 +1883,7 @@ TEST(libbacktrace, check_for_leak_local_thread) {
ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
}
TEST(libbacktrace, check_for_leak_remote) {
TEST_F(BacktraceTest, check_for_leak_remote) {
pid_t pid;
CreateRemoteProcess(&pid);
@ -1888,4 +1891,3 @@ TEST(libbacktrace, check_for_leak_remote) {
FinishRemoteProcess(pid);
}
#endif