Load libbacktrace_test.so explicitly.
This guarantees that the shared library is loaded separately. It allows this test to be run without depending on the shared library being somewhere in the system path since the library is now treated as a file to be dlopen'd. This also fixes some bugs in the deleted shared library test code. The previous test was passing when it was really failing. This new test no longer passes incorrectly. Specifically, the original testlib library only had a debug_frame on 32 bit host, which is not mapped into memory. Adding the exceptions option causes a full eh_frame to be generated. Due to the new dlopen code, also, switching to the new isolated test runner. Also, changing the memory leak checker to use mallinfo since the new unwinder allocates everything using the normal allocator. The use of the isolated runner causes the PSS checker to fail because processes come and go which changes the PSS distribution to the process doing the PSS check. Bug: 109876814 Test: All unit tests pass. Change-Id: I1b77a783979a8beaae0c0b12823267f363e07977
This commit is contained in:
parent
4eb864bf7d
commit
50d81acdc9
6 changed files with 215 additions and 260 deletions
|
@ -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: [
|
||||
|
|
78
libbacktrace/BacktraceTest.h
Normal file
78
libbacktrace/BacktraceTest.h
Normal 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
|
|
@ -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 a new issue