Yabin Cui | 9e402bb | 2015-09-22 04:46:57 +0000 | [diff] [blame] | 1 | #include <libunwind.h> |
| 2 | #include <pthread.h> |
| 3 | #include <stdint.h> |
| 4 | #include <string.h> |
| 5 | |
| 6 | #include <functional> |
| 7 | #include <memory> |
| 8 | #include <string> |
| 9 | #include <utility> |
| 10 | #include <vector> |
| 11 | |
| 12 | #include <backtrace/Backtrace.h> |
| 13 | #include <backtrace/BacktraceMap.h> |
| 14 | #include <cutils/threads.h> |
| 15 | |
| 16 | #include <gtest/gtest.h> |
| 17 | |
| 18 | extern "C" { |
| 19 | // Prototypes for functions in the test library. |
| 20 | int test_level_one(int, int, int, int, void (*)(void*), void*); |
| 21 | int test_level_two(int, int, int, int, void (*)(void*), void*); |
| 22 | int test_level_three(int, int, int, int, void (*)(void*), void*); |
| 23 | int test_level_four(int, int, int, int, void (*)(void*), void*); |
| 24 | int test_recursive_call(int, void (*)(void*), void*); |
| 25 | } |
| 26 | |
| 27 | static volatile bool g_exit_flag = false; |
| 28 | |
| 29 | static void GetContextAndExit(void* arg) { |
| 30 | unw_context_t* unw_context = reinterpret_cast<unw_context_t*>(arg); |
| 31 | unw_getcontext(unw_context); |
| 32 | // Don't touch the stack anymore. |
| 33 | while (!g_exit_flag) { |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | struct OfflineThreadArg { |
| 38 | unw_context_t unw_context; |
| 39 | pid_t tid; |
| 40 | std::function<int(void (*)(void*), void*)> function; |
| 41 | }; |
| 42 | |
| 43 | static void* OfflineThreadFunc(void* arg) { |
| 44 | OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg); |
| 45 | fn_arg->tid = gettid(); |
| 46 | fn_arg->function(GetContextAndExit, &fn_arg->unw_context); |
| 47 | return nullptr; |
| 48 | } |
| 49 | |
| 50 | static ucontext_t GetUContextFromUnwContext(const unw_context_t& unw_context) { |
| 51 | ucontext_t ucontext; |
| 52 | memset(&ucontext, 0, sizeof(ucontext)); |
| 53 | #if defined(__arm__) |
| 54 | ucontext.uc_mcontext.arm_r0 = unw_context.regs[0]; |
| 55 | ucontext.uc_mcontext.arm_r1 = unw_context.regs[1]; |
| 56 | ucontext.uc_mcontext.arm_r2 = unw_context.regs[2]; |
| 57 | ucontext.uc_mcontext.arm_r3 = unw_context.regs[3]; |
| 58 | ucontext.uc_mcontext.arm_r4 = unw_context.regs[4]; |
| 59 | ucontext.uc_mcontext.arm_r5 = unw_context.regs[5]; |
| 60 | ucontext.uc_mcontext.arm_r6 = unw_context.regs[6]; |
| 61 | ucontext.uc_mcontext.arm_r7 = unw_context.regs[7]; |
| 62 | ucontext.uc_mcontext.arm_r8 = unw_context.regs[8]; |
| 63 | ucontext.uc_mcontext.arm_r9 = unw_context.regs[9]; |
| 64 | ucontext.uc_mcontext.arm_r10 = unw_context.regs[10]; |
| 65 | ucontext.uc_mcontext.arm_fp = unw_context.regs[11]; |
| 66 | ucontext.uc_mcontext.arm_ip = unw_context.regs[12]; |
| 67 | ucontext.uc_mcontext.arm_sp = unw_context.regs[13]; |
| 68 | ucontext.uc_mcontext.arm_lr = unw_context.regs[14]; |
| 69 | ucontext.uc_mcontext.arm_pc = unw_context.regs[15]; |
| 70 | #else |
| 71 | ucontext.uc_mcontext = unw_context.uc_mcontext; |
| 72 | #endif |
| 73 | return ucontext; |
| 74 | } |
| 75 | |
| 76 | static void OfflineBacktraceFunctionCall(std::function<int(void (*)(void*), void*)> function, |
| 77 | std::vector<uintptr_t>* pc_values) { |
| 78 | // Create a thread to generate the needed stack and registers information. |
| 79 | g_exit_flag = false; |
| 80 | const size_t stack_size = 1024 * 1024; |
| 81 | void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 82 | ASSERT_NE(MAP_FAILED, stack); |
| 83 | uintptr_t stack_addr = reinterpret_cast<uintptr_t>(stack); |
| 84 | pthread_attr_t attr; |
| 85 | ASSERT_EQ(0, pthread_attr_init(&attr)); |
| 86 | ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size)); |
| 87 | pthread_t thread; |
| 88 | OfflineThreadArg arg; |
| 89 | arg.function = function; |
| 90 | ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg)); |
| 91 | // Wait for the offline thread to generate the stack and unw_context information. |
| 92 | sleep(1); |
| 93 | // Copy the stack information. |
| 94 | std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack), |
| 95 | reinterpret_cast<uint8_t*>(stack) + stack_size); |
| 96 | g_exit_flag = true; |
| 97 | ASSERT_EQ(0, pthread_join(thread, nullptr)); |
| 98 | ASSERT_EQ(0, munmap(stack, stack_size)); |
| 99 | |
| 100 | // Do offline backtrace. |
| 101 | std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid())); |
| 102 | ASSERT_TRUE(map != nullptr); |
| 103 | |
| 104 | backtrace_stackinfo_t stack_info; |
| 105 | stack_info.start = stack_addr; |
| 106 | stack_info.end = stack_addr + stack_size; |
| 107 | stack_info.data = stack_data.data(); |
| 108 | |
| 109 | std::unique_ptr<Backtrace> backtrace( |
| 110 | Backtrace::CreateOffline(getpid(), arg.tid, map.get(), stack_info)); |
| 111 | ASSERT_TRUE(backtrace != nullptr); |
| 112 | |
| 113 | ucontext_t ucontext = GetUContextFromUnwContext(arg.unw_context); |
| 114 | ASSERT_TRUE(backtrace->Unwind(0, &ucontext)); |
| 115 | |
| 116 | // Collect pc values of the call stack frames. |
| 117 | for (size_t i = 0; i < backtrace->NumFrames(); ++i) { |
| 118 | pc_values->push_back(backtrace->GetFrame(i)->pc); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // Return the name of the function which matches the address. Although we don't know the |
| 123 | // exact end of each function, it is accurate enough for the tests. |
| 124 | static std::string FunctionNameForAddress(uintptr_t addr) { |
| 125 | struct FunctionSymbol { |
| 126 | std::string name; |
| 127 | uintptr_t start; |
| 128 | uintptr_t end; |
| 129 | }; |
| 130 | |
| 131 | static std::vector<FunctionSymbol> symbols; |
| 132 | if (symbols.empty()) { |
| 133 | symbols = std::vector<FunctionSymbol>{ |
| 134 | {"unknown_start", 0, 0}, |
| 135 | {"test_level_one", reinterpret_cast<uintptr_t>(&test_level_one), 0}, |
| 136 | {"test_level_two", reinterpret_cast<uintptr_t>(&test_level_two), 0}, |
| 137 | {"test_level_three", reinterpret_cast<uintptr_t>(&test_level_three), 0}, |
| 138 | {"test_level_four", reinterpret_cast<uintptr_t>(&test_level_four), 0}, |
| 139 | {"test_recursive_call", reinterpret_cast<uintptr_t>(&test_recursive_call), 0}, |
| 140 | {"GetContextAndExit", reinterpret_cast<uintptr_t>(&GetContextAndExit), 0}, |
| 141 | {"unknown_end", static_cast<uintptr_t>(-1), static_cast<uintptr_t>(-1)}, |
| 142 | }; |
| 143 | std::sort( |
| 144 | symbols.begin(), symbols.end(), |
| 145 | [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; }); |
| 146 | for (size_t i = 0; i + 1 < symbols.size(); ++i) { |
| 147 | symbols[i].end = symbols[i + 1].start; |
| 148 | } |
| 149 | } |
| 150 | for (auto& symbol : symbols) { |
| 151 | if (addr >= symbol.start && addr < symbol.end) { |
| 152 | return symbol.name; |
| 153 | } |
| 154 | } |
| 155 | return ""; |
| 156 | } |
| 157 | |
| 158 | TEST(libbacktrace, offline) { |
| 159 | std::function<int(void (*)(void*), void*)> function = |
| 160 | std::bind(test_level_one, 1, 2, 3, 4, std::placeholders::_1, std::placeholders::_2); |
| 161 | std::vector<uintptr_t> pc_values; |
| 162 | OfflineBacktraceFunctionCall(function, &pc_values); |
| 163 | ASSERT_FALSE(pc_values.empty()); |
| 164 | ASSERT_LE(pc_values.size(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)); |
| 165 | |
| 166 | size_t test_one_index = 0; |
| 167 | for (size_t i = 0; i < pc_values.size(); ++i) { |
| 168 | if (FunctionNameForAddress(pc_values[i]) == "test_level_one") { |
| 169 | test_one_index = i; |
| 170 | break; |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | ASSERT_GE(test_one_index, 3u); |
| 175 | ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index])); |
| 176 | ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1])); |
| 177 | ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2])); |
| 178 | ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3])); |
| 179 | } |
| 180 | |
| 181 | TEST(libbacktrace, offline_max_trace) { |
| 182 | std::function<int(void (*)(void*), void*)> function = std::bind( |
| 183 | test_recursive_call, MAX_BACKTRACE_FRAMES + 10, std::placeholders::_1, std::placeholders::_2); |
| 184 | std::vector<uintptr_t> pc_values; |
| 185 | OfflineBacktraceFunctionCall(function, &pc_values); |
| 186 | ASSERT_FALSE(pc_values.empty()); |
| 187 | ASSERT_EQ(static_cast<size_t>(MAX_BACKTRACE_FRAMES), pc_values.size()); |
| 188 | ASSERT_EQ("test_recursive_call", FunctionNameForAddress(pc_values.back())); |
| 189 | } |