Merge "Load libbacktrace_test.so explicitly."
This commit is contained in:
commit
15a5c9c44f
|
@ -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: [
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue