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

Commit 82f3bbdc authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Allow calling GetFunctionName before unwinding.

Some extra initialization needs to occur before calling the local/remote
GetFunctioneName.

Also, cleanup the test code a bit:

- Make all local functions static.
- Create a common function to create and finish remote processes.
- Remove unused function.
- Fix the formatting a bit by making it match clang format.

Test: Ran the unit tests.
Change-Id: I998bed1378d582df59fdf9263df6f208db5d795a
parent e87a826a
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -23,12 +23,23 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>

#include <android-base/logging.h>
#include <backtrace/Backtrace.h>

#include "BacktraceLog.h"
#include "UnwindCurrent.h"

std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
  if (!initialized_) {
    // If init local is not called, then trying to get a function name will
    // fail, so try to initialize first.
    std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
    if (unw_init_local(cursor.get(), &context_) < 0) {
      return "";
    }
    initialized_ = true;
  }

  *offset = 0;
  char buf[512];
  unw_word_t value;
@@ -85,6 +96,7 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon
    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
    return false;
  }
  initialized_ = true;

  size_t num_frames = 0;
  do {
@@ -124,6 +136,11 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon
        num_frames++;
      } else {
        num_ignore_frames--;
        // Set the number of frames to zero to remove the frame added
        // above. By definition, if we still have frames to ignore
        // there should only be one frame in the vector.
        CHECK(num_frames == 0);
        frames_.resize(0);
      }
    }
    ret = unw_step (cursor.get());
+4 −2
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ private:
  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;

  unw_context_t context_;

  bool initialized_ = false;
};

#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
+35 −12
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ UnwindPtrace::~UnwindPtrace() {
    _UPT_destroy(upt_info_);
    upt_info_ = nullptr;
  }

  if (addr_space_) {
    // Remove the map from the address space before destroying it.
    // It will be freed in the UnwindMap destructor.
@@ -47,18 +48,14 @@ UnwindPtrace::~UnwindPtrace() {
  }
}

bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (GetMap() == nullptr) {
    // Without a map object, we can't do anything.
    error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
    return false;
bool UnwindPtrace::Init() {
  if (upt_info_) {
    return true;
  }

  error_ = BACKTRACE_UNWIND_NO_ERROR;

  if (ucontext) {
    BACK_LOGW("Unwinding from a specified context not supported yet.");
    error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
  if (addr_space_) {
    // If somehow the addr_space_ gets initialized but upt_info_ doesn't,
    // then that indicates there is some kind of failure.
    return false;
  }

@@ -79,6 +76,28 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
    return false;
  }

  return true;
}

bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (GetMap() == nullptr) {
    // Without a map object, we can't do anything.
    error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
    return false;
  }

  error_ = BACKTRACE_UNWIND_NO_ERROR;

  if (ucontext) {
    BACK_LOGW("Unwinding from a specified context not supported yet.");
    error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
    return false;
  }

  if (!Init()) {
    return false;
  }

  unw_cursor_t cursor;
  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
  if (ret < 0) {
@@ -115,10 +134,10 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
        prev->stack_size = frame->sp - prev->sp;
      }

      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);

      FillInMap(frame->pc, &frame->map);

      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);

      num_frames++;
    } else {
      num_ignore_frames--;
@@ -130,6 +149,10 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
}

std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
  if (!Init()) {
    return "";
  }

  *offset = 0;
  char buf[512];
  unw_word_t value;
+4 −2
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ public:
  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;

 private:
  bool Init();

  unw_addr_space_t addr_space_;
  struct UPT_info* upt_info_;
};
+88 −84
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <backtrace/BacktraceMap.h>

#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/atomic.h>
#include <cutils/threads.h>

@@ -85,13 +86,13 @@ int test_level_one(int, int, int, int, void (*)(void*), void*);
int test_recursive_call(int, void (*)(void*), void*);
}

uint64_t NanoTime() {
static uint64_t NanoTime() {
  struct timespec t = { 0, 0 };
  clock_gettime(CLOCK_MONOTONIC, &t);
  return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
}

std::string DumpFrames(Backtrace* backtrace) {
static std::string DumpFrames(Backtrace* backtrace) {
  if (backtrace->NumFrames() == 0) {
    return "   No frames to dump.\n";
  }
@@ -103,7 +104,7 @@ std::string DumpFrames(Backtrace* backtrace) {
  return frame;
}

void WaitForStop(pid_t pid) {
static void WaitForStop(pid_t pid) {
  uint64_t start = NanoTime();

  siginfo_t si;
@@ -116,7 +117,28 @@ void WaitForStop(pid_t pid) {
  }
}

bool ReadyLevelBacktrace(Backtrace* backtrace) {
static void CreateRemoteProcess(pid_t* pid) {
  if ((*pid = fork()) == 0) {
    while (true)
      ;
    _exit(0);
  }
  ASSERT_NE(-1, *pid);

  ASSERT_TRUE(ptrace(PTRACE_ATTACH, *pid, 0, 0) == 0);

  // Wait for the process to get to a stopping point.
  WaitForStop(*pid);
}

static void FinishRemoteProcess(pid_t pid) {
  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);

  kill(pid, SIGKILL);
  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
}

static bool ReadyLevelBacktrace(Backtrace* backtrace) {
  // See if test_level_four is in the backtrace.
  bool found = false;
  for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
@@ -129,7 +151,7 @@ bool ReadyLevelBacktrace(Backtrace* backtrace) {
  return found;
}

void VerifyLevelDump(Backtrace* backtrace) {
static void VerifyLevelDump(Backtrace* backtrace) {
  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
    << DumpFrames(backtrace);
  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
@@ -157,7 +179,7 @@ void VerifyLevelDump(Backtrace* backtrace) {
    << DumpFrames(backtrace);
}

void VerifyLevelBacktrace(void*) {
static void VerifyLevelBacktrace(void*) {
  std::unique_ptr<Backtrace> backtrace(
      Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
  ASSERT_TRUE(backtrace.get() != nullptr);
@@ -167,11 +189,11 @@ void VerifyLevelBacktrace(void*) {
  VerifyLevelDump(backtrace.get());
}

bool ReadyMaxBacktrace(Backtrace* backtrace) {
static bool ReadyMaxBacktrace(Backtrace* backtrace) {
  return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES);
}

void VerifyMaxDump(Backtrace* backtrace) {
static void VerifyMaxDump(Backtrace* backtrace) {
  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
    << DumpFrames(backtrace);
  // Verify that the last frame is our recursive call.
@@ -179,7 +201,7 @@ void VerifyMaxDump(Backtrace* backtrace) {
    << DumpFrames(backtrace);
}

void VerifyMaxBacktrace(void*) {
static void VerifyMaxBacktrace(void*) {
  std::unique_ptr<Backtrace> backtrace(
      Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
  ASSERT_TRUE(backtrace.get() != nullptr);
@@ -189,7 +211,7 @@ void VerifyMaxBacktrace(void*) {
  VerifyMaxDump(backtrace.get());
}

void ThreadSetState(void* data) {
static void ThreadSetState(void* data) {
  thread_t* thread = reinterpret_cast<thread_t*>(data);
  android_atomic_acquire_store(1, &thread->state);
  volatile int i = 0;
@@ -198,16 +220,7 @@ void ThreadSetState(void* data) {
  }
}

void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) {
  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
  ASSERT_TRUE(backtrace.get() != nullptr);
  ASSERT_TRUE(backtrace->Unwind(0));
  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());

  VerifyFunc(backtrace.get());
}

bool WaitForNonZero(int32_t* value, uint64_t seconds) {
static bool WaitForNonZero(int32_t* value, uint64_t seconds) {
  uint64_t start = NanoTime();
  do {
    if (android_atomic_acquire_load(value)) {
@@ -240,9 +253,8 @@ TEST(libbacktrace, local_trace) {
  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
}

void VerifyIgnoreFrames(
    Backtrace* bt_all, Backtrace* bt_ign1,
    Backtrace* bt_ign2, const char* cur_proc) {
static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
                               const char* cur_proc) {
  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1)
    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1);
  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2)
@@ -266,7 +278,7 @@ void VerifyIgnoreFrames(
  }
}

void VerifyLevelIgnoreFrames(void*) {
static void VerifyLevelIgnoreFrames(void*) {
  std::unique_ptr<Backtrace> all(
      Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
  ASSERT_TRUE(all.get() != nullptr);
@@ -296,8 +308,7 @@ TEST(libbacktrace, local_max_trace) {
  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
}

void VerifyProcTest(pid_t pid, pid_t tid, bool share_map,
                    bool (*ReadyFunc)(Backtrace*),
static void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, bool (*ReadyFunc)(Backtrace*),
                           void (*VerifyFunc)(Backtrace*)) {
  pid_t ptrace_tid;
  if (tid < 0) {
@@ -376,7 +387,7 @@ TEST(libbacktrace, ptrace_max_trace) {
  ASSERT_EQ(waitpid(pid, &status, 0), pid);
}

void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
static void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
  std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
  ASSERT_TRUE(ign1.get() != nullptr);
  ASSERT_TRUE(ign1->Unwind(1));
@@ -404,12 +415,12 @@ TEST(libbacktrace, ptrace_ignore_frames) {
}

// Create a process with multiple threads and dump all of the threads.
void* PtraceThreadLevelRun(void*) {
static void* PtraceThreadLevelRun(void*) {
  EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
  return nullptr;
}

void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
static void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
  // Get the list of tasks.
  char task_path[128];
  snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
@@ -461,11 +472,8 @@ TEST(libbacktrace, ptrace_threads) {
    }
    VerifyProcTest(pid, *it, false, ReadyLevelBacktrace, VerifyLevelDump);
  }
  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);

  kill(pid, SIGKILL);
  int status;
  ASSERT_EQ(waitpid(pid, &status, 0), pid);
  FinishRemoteProcess(pid);
}

void VerifyLevelThread(void*) {
@@ -481,7 +489,7 @@ TEST(libbacktrace, thread_current_level) {
  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
}

void VerifyMaxThread(void*) {
static void VerifyMaxThread(void*) {
  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
  ASSERT_TRUE(backtrace.get() != nullptr);
  ASSERT_TRUE(backtrace->Unwind(0));
@@ -494,7 +502,7 @@ TEST(libbacktrace, thread_current_max) {
  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
}

void* ThreadLevelRun(void* data) {
static void* ThreadLevelRun(void* data) {
  thread_t* thread = reinterpret_cast<thread_t*>(data);

  thread->tid = gettid();
@@ -585,7 +593,7 @@ TEST(libbacktrace, thread_ignore_frames) {
  android_atomic_acquire_store(0, &thread_data.state);
}

void* ThreadMaxRun(void* data) {
static void* ThreadMaxRun(void* data) {
  thread_t* thread = reinterpret_cast<thread_t*>(data);

  thread->tid = gettid();
@@ -616,7 +624,7 @@ TEST(libbacktrace, thread_max_trace) {
  android_atomic_acquire_store(0, &thread_data.state);
}

void* ThreadDump(void* data) {
static void* ThreadDump(void* data) {
  dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data);
  while (true) {
    if (android_atomic_acquire_load(dump->now)) {
@@ -873,11 +881,9 @@ struct map_test_t {
  uintptr_t end;
};

bool map_sort(map_test_t i, map_test_t j) {
  return i.start < j.start;
}
static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }

void VerifyMap(pid_t pid) {
static void VerifyMap(pid_t pid) {
  char buffer[4096];
  snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);

@@ -908,29 +914,15 @@ void VerifyMap(pid_t pid) {

TEST(libbacktrace, verify_map_remote) {
  pid_t pid;

  if ((pid = fork()) == 0) {
    while (true) {
    }
    _exit(0);
  }
  ASSERT_LT(0, pid);

  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);

  // Wait for the process to get to a stopping point.
  WaitForStop(pid);
  CreateRemoteProcess(&pid);

  // The maps should match exactly since the forked process has been paused.
  VerifyMap(pid);

  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);

  kill(pid, SIGKILL);
  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
  FinishRemoteProcess(pid);
}

void InitMemory(uint8_t* memory, size_t bytes) {
static void InitMemory(uint8_t* memory, size_t bytes) {
  for (size_t i = 0; i < bytes; i++) {
    memory[i] = i;
    if (memory[i] == '\0') {
@@ -941,7 +933,7 @@ void InitMemory(uint8_t* memory, size_t bytes) {
  }
}

void* ThreadReadTest(void* data) {
static void* ThreadReadTest(void* data) {
  thread_t* thread_data = reinterpret_cast<thread_t*>(data);

  thread_data->tid = gettid();
@@ -982,7 +974,7 @@ void* ThreadReadTest(void* data) {
  return nullptr;
}

void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
static void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));

  // Create a page of data to use to do quick compares.
@@ -1043,7 +1035,7 @@ TEST(libbacktrace, thread_read) {
volatile uintptr_t g_ready = 0;
volatile uintptr_t g_addr = 0;

void ForkedReadTest() {
static void ForkedReadTest() {
  // Create two map pages.
  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
  uint8_t* memory;
@@ -1117,7 +1109,7 @@ TEST(libbacktrace, process_read) {
  ASSERT_TRUE(test_executed);
}

void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
static void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
  // We expect to find these functions in libbacktrace_test. If we don't
  // find them, that's a bug in the memory read handling code in libunwind.
  std::list<std::string> expected_functions;
@@ -1137,7 +1129,7 @@ void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
  ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
}

const char* CopySharedLibrary() {
static const char* CopySharedLibrary() {
#if defined(__LP64__)
  const char* lib_name = "lib64";
#else
@@ -1293,7 +1285,7 @@ TEST(libbacktrace, check_unreadable_elf_remote) {
  VerifyFunctionsFound(found_functions);
}

bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
  backtrace_map_t map;
  backtrace->FillInMap(test_func, &map);
  if (!BacktraceMap::IsValid(map)) {
@@ -1312,7 +1304,7 @@ bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t*
  return false;
}

void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
static void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
    << DumpFrames(backtrace);

@@ -1324,7 +1316,7 @@ void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t
  ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
}

void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
static void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
                                                         BACKTRACE_CURRENT_THREAD));
  ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1418,12 +1410,38 @@ TEST(libbacktrace, unwind_thread_doesnt_exist) {
  ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError());
}

TEST(libbacktrace, 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.
  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
  size_t offset;
  ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
}

TEST(libbacktrace, remote_get_function_name_before_unwind) {
  pid_t pid;
  CreateRemoteProcess(&pid);

  // Now create an unwind object.
  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));

  // Verify that trying to get a function name before doing an unwind works.
  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
  size_t offset;
  ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));

  FinishRemoteProcess(pid);
}

#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"

#define MAX_LEAK_BYTES (32*1024UL)

void CheckForLeak(pid_t pid, pid_t tid) {
static void CheckForLeak(pid_t pid, pid_t tid) {
  // Do a few runs to get the PSS stable.
  for (size_t i = 0; i < 100; i++) {
    Backtrace* backtrace = Backtrace::Create(pid, tid);
@@ -1472,24 +1490,10 @@ TEST(libbacktrace, check_for_leak_local_thread) {

TEST(libbacktrace, check_for_leak_remote) {
  pid_t pid;

  if ((pid = fork()) == 0) {
    while (true) {
    }
    _exit(0);
  }
  ASSERT_LT(0, pid);

  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);

  // Wait for the process to get to a stopping point.
  WaitForStop(pid);
  CreateRemoteProcess(&pid);

  CheckForLeak(pid, BACKTRACE_CURRENT_THREAD);

  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);

  kill(pid, SIGKILL);
  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
  FinishRemoteProcess(pid);
}
#endif
+3 −3

File changed.

Contains only whitespace changes.

+1 −1

File changed.

Contains only whitespace changes.

+2 −2

File changed.

Contains only whitespace changes.

+6 −6

File changed.

Contains only whitespace changes.

Loading