Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 50d81acd authored by Christopher Ferris's avatar Christopher Ferris
Browse files

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
parent 4eb864bf
Loading
Loading
Loading
Loading
+21 −23
Original line number Diff line number Diff line
@@ -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",
    // So that the dlopen can find the libbacktrace_test.so.
    ldflags: [
        "-Wl,--rpath,${ORIGIN}/../backtrace_test_libs",
    ],
        },
        linux_glibc: {
            static_libs: ["libutils"],
        },
    },

    test_suites: ["device-tests"],
    data: [
+78 −0
Original line number Diff line number Diff line
/*
 * 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

libbacktrace/GetPss.cpp

deleted100644 → 0
+0 −94
Original line number Diff line number Diff line
/*
 * 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;
}

libbacktrace/GetPss.h

deleted100644 → 0
+0 −22
Original line number Diff line number Diff line
/*
 * 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
+20 −27
Original line number Diff line number Diff line
@@ -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);
}
Loading