Home | History | Annotate | Download | only in libbacktrace
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <inttypes.h>
     18 #include <pthread.h>
     19 #include <stdint.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 
     23 #include <functional>
     24 #include <memory>
     25 #include <string>
     26 #include <utility>
     27 #include <vector>
     28 
     29 #include <android-base/file.h>
     30 #include <android-base/logging.h>
     31 #include <android-base/macros.h>
     32 #include <android-base/stringprintf.h>
     33 #include <android-base/strings.h>
     34 #include <backtrace/Backtrace.h>
     35 #include <backtrace/BacktraceMap.h>
     36 #include <cutils/threads.h>
     37 
     38 #include <gtest/gtest.h>
     39 
     40 extern "C" {
     41 // Prototypes for functions in the test library.
     42 int test_level_one(int, int, int, int, void (*)(void*), void*);
     43 int test_level_two(int, int, int, int, void (*)(void*), void*);
     44 int test_level_three(int, int, int, int, void (*)(void*), void*);
     45 int test_level_four(int, int, int, int, void (*)(void*), void*);
     46 int test_recursive_call(int, void (*)(void*), void*);
     47 void test_get_context_and_wait(void* context, volatile int* exit_flag);
     48 }
     49 
     50 struct FunctionSymbol {
     51   std::string name;
     52   uint64_t start;
     53   uint64_t end;
     54 };
     55 
     56 static std::vector<FunctionSymbol> GetFunctionSymbols() {
     57   std::vector<FunctionSymbol> symbols = {
     58       {"unknown_start", 0, 0},
     59       {"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
     60       {"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
     61       {"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
     62       {"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
     63       {"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
     64       {"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
     65       {"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
     66   };
     67   std::sort(
     68       symbols.begin(), symbols.end(),
     69       [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; });
     70   for (size_t i = 0; i + 1 < symbols.size(); ++i) {
     71     symbols[i].end = symbols[i + 1].start;
     72   }
     73   return symbols;
     74 }
     75 
     76 static std::string RawDataToHexString(const void* data, size_t size) {
     77   const uint8_t* p = static_cast<const uint8_t*>(data);
     78   std::string s;
     79   for (size_t i = 0; i < size; ++i) {
     80     s += android::base::StringPrintf("%02x", p[i]);
     81   }
     82   return s;
     83 }
     84 
     85 static void HexStringToRawData(const char* s, std::vector<uint8_t>* data, size_t size) {
     86   for (size_t i = 0; i < size; ++i) {
     87     int value;
     88     sscanf(s, "%02x", &value);
     89     data->push_back(value);
     90     s += 2;
     91   }
     92 }
     93 
     94 struct OfflineThreadArg {
     95   std::vector<uint8_t> ucontext;
     96   pid_t tid;
     97   volatile int exit_flag;
     98 };
     99 
    100 static void* OfflineThreadFunc(void* arg) {
    101   OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
    102   fn_arg->tid = gettid();
    103   test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
    104   return nullptr;
    105 }
    106 
    107 std::string GetTestPath(const std::string& arch, const std::string& path) {
    108   return android::base::GetExecutableDirectory() + "/testdata/" + arch + '/' + path;
    109 }
    110 
    111 // This test is disable because it is for generating test data.
    112 TEST(libbacktrace, DISABLED_generate_offline_testdata) {
    113   // Create a thread to generate the needed stack and registers information.
    114   const size_t stack_size = 16 * 1024;
    115   void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    116   ASSERT_NE(MAP_FAILED, stack);
    117   uint64_t stack_addr = reinterpret_cast<uint64_t>(stack);
    118   pthread_attr_t attr;
    119   ASSERT_EQ(0, pthread_attr_init(&attr));
    120   ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size));
    121   pthread_t thread;
    122   OfflineThreadArg arg;
    123   arg.exit_flag = 0;
    124   ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg));
    125   // Wait for the offline thread to generate the stack and context information.
    126   sleep(1);
    127   // Copy the stack information.
    128   std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
    129                                   reinterpret_cast<uint8_t*>(stack) + stack_size);
    130   arg.exit_flag = 1;
    131   ASSERT_EQ(0, pthread_join(thread, nullptr));
    132   ASSERT_EQ(0, munmap(stack, stack_size));
    133 
    134   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
    135   ASSERT_TRUE(map != nullptr);
    136 
    137   backtrace_stackinfo_t stack_info;
    138   stack_info.start = stack_addr;
    139   stack_info.end = stack_addr + stack_size;
    140   stack_info.data = stack_data.data();
    141 
    142   // Generate offline testdata.
    143   std::string testdata;
    144   // 1. Dump pid, tid
    145   testdata += android::base::StringPrintf("pid: %d tid: %d\n", getpid(), arg.tid);
    146   // 2. Dump maps
    147   for (auto it = map->begin(); it != map->end(); ++it) {
    148     const backtrace_map_t* entry = *it;
    149     testdata +=
    150         android::base::StringPrintf("map: start: %" PRIx64 " end: %" PRIx64 " offset: %" PRIx64
    151                                     " load_bias: %" PRIx64 " flags: %d name: %s\n",
    152                                     entry->start, entry->end, entry->offset, entry->load_bias,
    153                                     entry->flags, entry->name.c_str());
    154   }
    155   // 3. Dump ucontext
    156   testdata += android::base::StringPrintf("ucontext: %zu ", arg.ucontext.size());
    157   testdata += RawDataToHexString(arg.ucontext.data(), arg.ucontext.size());
    158   testdata.push_back('\n');
    159 
    160   // 4. Dump stack
    161   testdata += android::base::StringPrintf(
    162       "stack: start: %" PRIx64 " end: %" PRIx64 " size: %zu ",
    163       stack_info.start, stack_info.end, stack_data.size());
    164   testdata += RawDataToHexString(stack_data.data(), stack_data.size());
    165   testdata.push_back('\n');
    166 
    167   // 5. Dump function symbols
    168   std::vector<FunctionSymbol> function_symbols = GetFunctionSymbols();
    169   for (const auto& symbol : function_symbols) {
    170     testdata +=
    171         android::base::StringPrintf("function: start: %" PRIx64 " end: %" PRIx64 " name: %s\n",
    172                                     symbol.start, symbol.end, symbol.name.c_str());
    173   }
    174 
    175   ASSERT_TRUE(android::base::WriteStringToFile(testdata, "offline_testdata"));
    176 }
    177 
    178 // Return the name of the function which matches the address. Although we don't know the
    179 // exact end of each function, it is accurate enough for the tests.
    180 static std::string FunctionNameForAddress(uint64_t addr,
    181                                           const std::vector<FunctionSymbol>& symbols) {
    182   for (auto& symbol : symbols) {
    183     if (addr >= symbol.start && addr < symbol.end) {
    184       return symbol.name;
    185     }
    186   }
    187   return "";
    188 }
    189 
    190 struct OfflineTestData {
    191   int pid;
    192   int tid;
    193   std::vector<backtrace_map_t> maps;
    194   std::vector<uint8_t> ucontext;
    195   backtrace_stackinfo_t stack_info;
    196   std::vector<uint8_t> stack;
    197   std::vector<FunctionSymbol> symbols;
    198 };
    199 
    200 bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) {
    201   std::string s;
    202   if (!android::base::ReadFileToString(offline_testdata_path, &s)) {
    203     return false;
    204   }
    205   // Parse offline_testdata.
    206   std::vector<std::string> lines = android::base::Split(s, "\n");
    207   for (const auto& line : lines) {
    208     if (android::base::StartsWith(line, "pid:")) {
    209       sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
    210     } else if (android::base::StartsWith(line, "map:")) {
    211       testdata->maps.resize(testdata->maps.size() + 1);
    212       backtrace_map_t& map = testdata->maps.back();
    213       int pos;
    214       sscanf(line.c_str(),
    215              "map: start: %" SCNx64 " end: %" SCNx64 " offset: %" SCNx64 " load_bias: %" SCNx64
    216              " flags: %d name: %n",
    217              &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
    218       map.name = android::base::Trim(line.substr(pos));
    219     } else if (android::base::StartsWith(line, "ucontext:")) {
    220       size_t size;
    221       int pos;
    222       testdata->ucontext.clear();
    223       sscanf(line.c_str(), "ucontext: %zu %n", &size, &pos);
    224       HexStringToRawData(&line[pos], &testdata->ucontext, size);
    225     } else if (android::base::StartsWith(line, "stack:")) {
    226       size_t size;
    227       int pos;
    228       sscanf(line.c_str(),
    229              "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
    230              &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
    231       CHECK_EQ(testdata->stack_info.end - testdata->stack_info.start, size);
    232       testdata->stack.clear();
    233       HexStringToRawData(&line[pos], &testdata->stack, size);
    234       testdata->stack_info.data = testdata->stack.data();
    235     } else if (android::base::StartsWith(line, "function:")) {
    236       testdata->symbols.resize(testdata->symbols.size() + 1);
    237       FunctionSymbol& symbol = testdata->symbols.back();
    238       int pos;
    239       sscanf(line.c_str(), "function: start: %" SCNx64 " end: %" SCNx64 " name: %n", &symbol.start,
    240              &symbol.end, &pos);
    241       symbol.name = line.substr(pos);
    242     }
    243   }
    244   return true;
    245 }
    246 
    247 static void BacktraceOfflineTest(std::string arch_str, const std::string& testlib_name) {
    248   const std::string testlib_path(GetTestPath(arch_str, testlib_name));
    249   const std::string offline_testdata_path(GetTestPath(arch_str, "offline_testdata"));
    250   OfflineTestData testdata;
    251   ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata)) << "Failed " << arch_str;
    252 
    253   // Fix path of libbacktrace_testlib.so.
    254   for (auto& map : testdata.maps) {
    255     if (map.name.find("libbacktrace_test.so") != std::string::npos) {
    256       map.name = testlib_path;
    257     }
    258   }
    259 
    260   Backtrace::ArchEnum arch;
    261   if (arch_str == "arm") {
    262     arch = Backtrace::ARCH_ARM;
    263   } else if (arch_str == "arm64") {
    264     arch = Backtrace::ARCH_ARM64;
    265   } else if (arch_str == "x86") {
    266     arch = Backtrace::ARCH_X86;
    267   } else if (arch_str == "x86_64") {
    268     arch = Backtrace::ARCH_X86_64;
    269   } else {
    270     abort();
    271   }
    272 
    273   std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
    274       arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
    275   ASSERT_TRUE(backtrace != nullptr) << "Failed " << arch_str;
    276 
    277   ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data())) << "Failed " << arch_str;
    278 
    279   // Collect pc values of the call stack frames.
    280   std::vector<uint64_t> pc_values;
    281   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
    282     pc_values.push_back(backtrace->GetFrame(i)->pc);
    283   }
    284 
    285   size_t test_one_index = 0;
    286   for (size_t i = 0; i < pc_values.size(); ++i) {
    287     if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") {
    288       test_one_index = i;
    289       break;
    290     }
    291   }
    292 
    293   ASSERT_GE(test_one_index, 3u) << "Failed " << arch_str;
    294   ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols))
    295       << "Failed " << arch_str;
    296   ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], testdata.symbols))
    297       << "Failed " << arch_str;
    298   ASSERT_EQ("test_level_three",
    299             FunctionNameForAddress(pc_values[test_one_index - 2], testdata.symbols))
    300       << "Failed " << arch_str;
    301   ASSERT_EQ("test_level_four",
    302             FunctionNameForAddress(pc_values[test_one_index - 3], testdata.symbols))
    303       << "Failed " << arch_str;
    304 }
    305 
    306 // For now, these tests can only run on the given architectures.
    307 TEST(libbacktrace, offline_eh_frame) {
    308   BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
    309   BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
    310 }
    311 
    312 TEST(libbacktrace, offline_debug_frame) {
    313   BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
    314   BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
    315 }
    316 
    317 TEST(libbacktrace, offline_gnu_debugdata) {
    318   BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
    319   BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
    320 }
    321 
    322 TEST(libbacktrace, offline_arm_exidx) {
    323   BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
    324 }
    325 
    326 static void LibUnwindingTest(const std::string& arch_str, const std::string& testdata_name,
    327                              const std::string& testlib_name) {
    328   const std::string testlib_path(GetTestPath(arch_str, testlib_name));
    329   struct stat st;
    330   ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
    331 
    332   const std::string offline_testdata_path(GetTestPath(arch_str, testdata_name));
    333   OfflineTestData testdata;
    334   ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
    335 
    336   // Fix path of the testlib.
    337   for (auto& map : testdata.maps) {
    338     if (map.name.find(testlib_name) != std::string::npos) {
    339       map.name = testlib_path;
    340     }
    341   }
    342 
    343   Backtrace::ArchEnum arch;
    344   if (arch_str == "arm") {
    345     arch = Backtrace::ARCH_ARM;
    346   } else if (arch_str == "arm64") {
    347     arch = Backtrace::ARCH_ARM64;
    348   } else if (arch_str == "x86") {
    349     arch = Backtrace::ARCH_X86;
    350   } else if (arch_str == "x86_64") {
    351     arch = Backtrace::ARCH_X86_64;
    352   } else {
    353     ASSERT_TRUE(false) << "Unsupported arch " << arch_str;
    354     abort();
    355   }
    356 
    357   // Do offline backtrace.
    358   std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
    359       arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
    360   ASSERT_TRUE(backtrace != nullptr);
    361 
    362   ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data()));
    363 
    364   ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
    365   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
    366     std::string name = FunctionNameForAddress(backtrace->GetFrame(i)->rel_pc, testdata.symbols);
    367     ASSERT_EQ(name, testdata.symbols[i].name);
    368   }
    369   ASSERT_TRUE(backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED ||
    370               backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING ||
    371               backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_REPEATED_FRAME);
    372 }
    373 
    374 // This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
    375 // overlap with each other, which appears in /system/lib/libart.so.
    376 TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
    377   LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
    378 }
    379 
    380 TEST(libbacktrace, offline_debug_frame_with_load_bias) {
    381   LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
    382 }
    383 
    384 TEST(libbacktrace, offline_try_armexidx_after_debug_frame) {
    385   LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
    386 }
    387 
    388 TEST(libbacktrace, offline_cie_with_P_augmentation) {
    389   // Make sure we can unwind through functions with CIE entry containing P augmentation, which
    390   // makes unwinding library reading personality handler from memory. One example is
    391   // /system/lib64/libskia.so.
    392   LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so");
    393 }
    394 
    395 TEST(libbacktrace, offline_empty_eh_frame_hdr) {
    396   // Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is
    397   // /vendor/lib64/egl/eglSubDriverAndroid.so.
    398   LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so");
    399 }
    400 
    401 TEST(libbacktrace, offline_max_frames_limit) {
    402   // The length of callchain can reach 256 when recording an application.
    403   ASSERT_GE(MAX_BACKTRACE_FRAMES, 256);
    404 }
    405