diff options
author | Yabin Cui <yabinc@google.com> | 2017-12-12 18:04:10 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2017-12-15 13:29:53 -0800 |
commit | f88082811a87e3e088b926d0e0fa90688e02d258 (patch) | |
tree | f338ee9f0e5e0c061fde9e3a39f2f27f9e457958 /libbacktrace | |
parent | 80bfeeef884e08b3a6aa593b1a35217b01e1b855 (diff) | |
download | system_core-f88082811a87e3e088b926d0e0fa90688e02d258.tar.gz system_core-f88082811a87e3e088b926d0e0fa90688e02d258.tar.bz2 system_core-f88082811a87e3e088b926d0e0fa90688e02d258.zip |
libbacktrace: export offline unwinding failures.
This is to help debugging different offline unwiding failures.
Bug: http://b/69383534
Test: run backtrace_test.
Change-Id: I5ed4837027a9f17d032925e97e9f5927161444b3
Diffstat (limited to 'libbacktrace')
-rw-r--r-- | libbacktrace/Backtrace.cpp | 45 | ||||
-rw-r--r-- | libbacktrace/BacktraceCurrent.cpp | 14 | ||||
-rw-r--r-- | libbacktrace/BacktraceOffline.cpp | 36 | ||||
-rw-r--r-- | libbacktrace/BacktraceOffline.h | 4 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.cpp | 4 | ||||
-rw-r--r-- | libbacktrace/UnwindPtrace.cpp | 12 | ||||
-rw-r--r-- | libbacktrace/UnwindStack.cpp | 4 | ||||
-rw-r--r-- | libbacktrace/backtrace_offline_test.cpp | 2 | ||||
-rw-r--r-- | libbacktrace/backtrace_test.cpp | 48 | ||||
-rw-r--r-- | libbacktrace/include/backtrace/Backtrace.h | 25 |
10 files changed, 126 insertions, 68 deletions
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp index e18dbf3db..5bb6edc8f 100644 --- a/libbacktrace/Backtrace.cpp +++ b/libbacktrace/Backtrace.cpp @@ -142,22 +142,33 @@ Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { } std::string Backtrace::GetErrorString(BacktraceUnwindError error) { - switch (error) { - case BACKTRACE_UNWIND_NO_ERROR: - return "No error"; - case BACKTRACE_UNWIND_ERROR_SETUP_FAILED: - return "Setup failed"; - case BACKTRACE_UNWIND_ERROR_MAP_MISSING: - return "No map found"; - case BACKTRACE_UNWIND_ERROR_INTERNAL: - return "Internal libbacktrace error, please submit a bugreport"; - case BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST: - return "Thread doesn't exist"; - case BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT: - return "Thread has not responded to signal in time"; - case BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION: - return "Attempt to use an unsupported feature"; - case BACKTRACE_UNWIND_ERROR_NO_CONTEXT: - return "Attempt to do an offline unwind without a context"; + switch (error.error_code) { + case BACKTRACE_UNWIND_NO_ERROR: + return "No error"; + case BACKTRACE_UNWIND_ERROR_SETUP_FAILED: + return "Setup failed"; + case BACKTRACE_UNWIND_ERROR_MAP_MISSING: + return "No map found"; + case BACKTRACE_UNWIND_ERROR_INTERNAL: + return "Internal libbacktrace error, please submit a bugreport"; + case BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST: + return "Thread doesn't exist"; + case BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT: + return "Thread has not responded to signal in time"; + case BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION: + return "Attempt to use an unsupported feature"; + case BACKTRACE_UNWIND_ERROR_NO_CONTEXT: + return "Attempt to do an offline unwind without a context"; + case BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT: + return "Exceed MAX_BACKTRACE_FRAMES limit"; + case BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED: + return android::base::StringPrintf("Failed to read memory at addr 0x%" PRIx64, + error.error_info.addr); + case BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED: + return android::base::StringPrintf("Failed to read register %" PRIu64, error.error_info.regno); + case BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED: + return "Failed to find a function in debug sections"; + case BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED: + return "Failed to execute dwarf instructions in debug sections"; } } diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp index fb76b858d..474d09924 100644 --- a/libbacktrace/BacktraceCurrent.cpp +++ b/libbacktrace/BacktraceCurrent.cpp @@ -67,11 +67,11 @@ size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { bool BacktraceCurrent::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; + error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING; return false; } - error_ = BACKTRACE_UNWIND_NO_ERROR; + error_.error_code = BACKTRACE_UNWIND_NO_ERROR; if (ucontext) { return UnwindFromContext(num_ignore_frames, ucontext); } @@ -163,7 +163,7 @@ bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) { BACK_ASYNC_SAFE_LOGE("sigaction failed: %s", strerror(errno)); ThreadEntry::Remove(entry); pthread_mutex_unlock(&g_sigaction_mutex); - error_ = BACKTRACE_UNWIND_ERROR_INTERNAL; + error_.error_code = BACKTRACE_UNWIND_ERROR_INTERNAL; return false; } @@ -171,9 +171,9 @@ bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) { // Do not emit an error message, this might be expected. Set the // error and let the caller decide. if (errno == ESRCH) { - error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST; + error_.error_code = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST; } else { - error_ = BACKTRACE_UNWIND_ERROR_INTERNAL; + error_.error_code = BACKTRACE_UNWIND_ERROR_INTERNAL; } sigaction(THREAD_SIGNAL, &oldact, nullptr); @@ -218,9 +218,9 @@ bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) { } else { // Check to see if the thread has disappeared. if (tgkill(Pid(), Tid(), 0) == -1 && errno == ESRCH) { - error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST; + error_.error_code = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST; } else { - error_ = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT; + error_.error_code = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT; BACK_ASYNC_SAFE_LOGE("Timed out waiting for signal handler to get ucontext data."); } } diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp index 641f7123e..e290b8496 100644 --- a/libbacktrace/BacktraceOffline.cpp +++ b/libbacktrace/BacktraceOffline.cpp @@ -174,11 +174,11 @@ static unw_accessors_t accessors = { bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { if (context == nullptr) { BACK_LOGW("The context is needed for offline backtracing."); - error_ = BACKTRACE_UNWIND_ERROR_NO_CONTEXT; + error_.error_code = BACKTRACE_UNWIND_ERROR_NO_CONTEXT; return false; } context_ = context; - error_ = BACKTRACE_UNWIND_NO_ERROR; + error_.error_code = BACKTRACE_UNWIND_NO_ERROR; unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0); unw_cursor_t cursor; @@ -186,11 +186,11 @@ bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { if (ret != 0) { BACK_LOGW("unw_init_remote failed %d", ret); unw_destroy_addr_space(addr_space); - error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; + error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } size_t num_frames = 0; - do { + while (true) { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { @@ -224,7 +224,17 @@ bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { } is_debug_frame_used_ = false; ret = unw_step(&cursor); - } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); + if (ret <= 0) { + if (error_.error_code == BACKTRACE_UNWIND_NO_ERROR) { + error_.error_code = BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED; + } + break; + } + if (num_frames == MAX_BACKTRACE_FRAMES) { + error_.error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT; + break; + } + } unw_destroy_addr_space(addr_space); context_ = nullptr; @@ -259,7 +269,12 @@ size_t BacktraceOffline::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { return read_size; } read_size = stack_space_.Read(addr, buffer, bytes); - return read_size; + if (read_size != 0) { + return read_size; + } + error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED; + error_.error_info.addr = addr; + return 0; } bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, @@ -267,13 +282,17 @@ bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, backtrace_map_t map; FillInMap(ip, &map); if (!BacktraceMap::IsValid(map)) { + error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED; return false; } const std::string& filename = map.name; DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename); if (debug_frame == nullptr) { + error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED; return false; } + // Each FindProcInfo() is a new attempt to unwind, so reset the reason. + error_.error_code = BACKTRACE_UNWIND_NO_ERROR; eh_frame_hdr_space_.Clear(); eh_frame_space_.Clear(); @@ -367,6 +386,7 @@ bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, } } } + error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED; return false; } @@ -548,6 +568,10 @@ bool BacktraceOffline::ReadReg(size_t reg, uint64_t* value) { UNUSED(value); result = false; #endif + if (!result) { + error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED; + error_.error_info.regno = reg; + } return result; } diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h index 70a984265..fcde3796c 100644 --- a/libbacktrace/BacktraceOffline.h +++ b/libbacktrace/BacktraceOffline.h @@ -32,9 +32,7 @@ struct Space { uint64_t end; const uint8_t* data; - Space() { - Clear(); - } + Space() { Clear(); } void Clear(); size_t Read(uint64_t addr, uint8_t* buffer, size_t size); diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index 2c87fa837..3ccf13c77 100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -81,7 +81,7 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon int ret = unw_getcontext(&context_); if (ret < 0) { BACK_LOGW("unw_getcontext failed %d", ret); - error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; + error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } } else { @@ -93,7 +93,7 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon int ret = unw_init_local(cursor.get(), &context_); if (ret < 0) { BACK_LOGW("unw_init_local failed %d", ret); - error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; + error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } initialized_ = true; diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index 87282ef8c..2155b8adc 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -62,7 +62,7 @@ bool UnwindPtrace::Init() { addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); - error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; + error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } @@ -72,7 +72,7 @@ bool UnwindPtrace::Init() { upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); - error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; + error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } @@ -82,15 +82,15 @@ bool UnwindPtrace::Init() { 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; + error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING; return false; } - error_ = BACKTRACE_UNWIND_NO_ERROR; + error_.error_code = BACKTRACE_UNWIND_NO_ERROR; if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); - error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION; + error_.error_code = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION; return false; } @@ -102,7 +102,7 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); - error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; + error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 56a6c6889..2a555afc4 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -102,7 +102,7 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); } - error_ = BACKTRACE_UNWIND_NO_ERROR; + error_.error_code = BACKTRACE_UNWIND_NO_ERROR; std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"}; return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names); } @@ -122,7 +122,7 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context)); } - error_ = BACKTRACE_UNWIND_NO_ERROR; + error_.error_code = BACKTRACE_UNWIND_NO_ERROR; return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr); } diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp index 9ba2b1c80..64172b5e8 100644 --- a/libbacktrace/backtrace_offline_test.cpp +++ b/libbacktrace/backtrace_offline_test.cpp @@ -397,6 +397,8 @@ static void LibUnwindingTest(const std::string& arch, const std::string& testdat std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols); ASSERT_EQ(name, testdata.symbols[i].name); } + ASSERT_EQ(BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED, backtrace->GetError().error_code); + ASSERT_NE(0u, backtrace->GetError().error_info.addr); } // This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index 890ab3f0e..57b755318 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -189,7 +189,7 @@ static void VerifyLevelBacktrace(void*) { Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); VerifyLevelDump(backtrace.get()); } @@ -211,7 +211,7 @@ static void VerifyMaxBacktrace(void*) { Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); VerifyMaxDump(backtrace.get()); } @@ -241,7 +241,7 @@ TEST(libbacktrace, local_no_unwind_frames) { std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid())); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); ASSERT_TRUE(backtrace->NumFrames() != 0); for (const auto& frame : *backtrace ) { @@ -292,19 +292,19 @@ static void VerifyLevelIgnoreFrames(void*) { Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(all.get() != nullptr); ASSERT_TRUE(all->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError().error_code); std::unique_ptr<Backtrace> ign1( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1->Unwind(1)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code); std::unique_ptr<Backtrace> ign2( Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(ign2.get() != nullptr); ASSERT_TRUE(ign2->Unwind(2)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code); VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames"); } @@ -340,7 +340,7 @@ static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*), std::unique_ptr<Backtrace> backtrace(create_func(pid, tid, map.get())); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); if (ReadyFunc(backtrace.get())) { VerifyFunc(backtrace.get(), create_func, map_create_func); verified = true; @@ -389,12 +389,12 @@ static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_fu std::unique_ptr<Backtrace> ign1(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get())); ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1->Unwind(1)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code); std::unique_ptr<Backtrace> ign2(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get())); ASSERT_TRUE(ign2.get() != nullptr); ASSERT_TRUE(ign2->Unwind(2)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code); VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr); } @@ -480,7 +480,7 @@ void VerifyLevelThread(void*) { std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); VerifyLevelDump(backtrace.get()); } @@ -493,7 +493,7 @@ static void VerifyMaxThread(void*) { std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid())); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); VerifyMaxDump(backtrace.get()); } @@ -535,7 +535,7 @@ TEST(libbacktrace, thread_level_trace) { std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); VerifyLevelDump(backtrace.get()); @@ -575,17 +575,17 @@ TEST(libbacktrace, thread_ignore_frames) { std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid)); ASSERT_TRUE(all.get() != nullptr); ASSERT_TRUE(all->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError().error_code); std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid)); ASSERT_TRUE(ign1.get() != nullptr); ASSERT_TRUE(ign1->Unwind(1)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError().error_code); std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid)); ASSERT_TRUE(ign2.get() != nullptr); ASSERT_TRUE(ign2->Unwind(2)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError().error_code); VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr); @@ -616,7 +616,7 @@ TEST(libbacktrace, thread_max_trace) { std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); VerifyMaxDump(backtrace.get()); @@ -713,21 +713,21 @@ TEST(libbacktrace, simultaneous_maps) { Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1); ASSERT_TRUE(back1 != nullptr); EXPECT_TRUE(back1->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back1->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back1->GetError().error_code); delete back1; delete map1; Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2); ASSERT_TRUE(back2 != nullptr); EXPECT_TRUE(back2->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back2->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back2->GetError().error_code); delete back2; delete map2; Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3); ASSERT_TRUE(back3 != nullptr); EXPECT_TRUE(back3->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back3->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back3->GetError().error_code); delete back3; delete map3; } @@ -1331,7 +1331,7 @@ static void VerifyUnreadableElfBacktrace(uintptr_t test_func) { BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); size_t frame_num; ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num)); @@ -1388,7 +1388,7 @@ TEST(libbacktrace, unwind_through_unreadable_elf_remote) { std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); size_t frame_num; if (FindFuncFrameInBacktrace(backtrace.get(), @@ -1417,7 +1417,7 @@ TEST(libbacktrace, unwind_thread_doesnt_exist) { Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999)); ASSERT_TRUE(backtrace.get() != nullptr); ASSERT_FALSE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError().error_code); } TEST(libbacktrace, local_get_function_name_before_unwind) { @@ -1785,7 +1785,7 @@ static void CheckForLeak(pid_t pid, pid_t tid) { Backtrace* backtrace = Backtrace::Create(pid, tid, map.get()); ASSERT_TRUE(backtrace != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); delete backtrace; } size_t stable_pss = GetPssBytes(); @@ -1796,7 +1796,7 @@ static void CheckForLeak(pid_t pid, pid_t tid) { Backtrace* backtrace = Backtrace::Create(pid, tid, map.get()); ASSERT_TRUE(backtrace != nullptr); ASSERT_TRUE(backtrace->Unwind(0)); - ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError()); + ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code); delete backtrace; } size_t new_pss = GetPssBytes(); diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h index e07353346..592266429 100644 --- a/libbacktrace/include/backtrace/Backtrace.h +++ b/libbacktrace/include/backtrace/Backtrace.h @@ -34,7 +34,7 @@ typedef uint64_t word_t; typedef uint32_t word_t; #endif -enum BacktraceUnwindError : uint32_t { +enum BacktraceUnwindErrorCode : uint32_t { BACKTRACE_UNWIND_NO_ERROR, // Something failed while trying to perform the setup to begin the unwind. BACKTRACE_UNWIND_ERROR_SETUP_FAILED, @@ -50,6 +50,29 @@ enum BacktraceUnwindError : uint32_t { BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION, // Attempt to do an offline unwind without a context. BACKTRACE_UNWIND_ERROR_NO_CONTEXT, + // The count of frames exceed MAX_BACKTRACE_FRAMES. + BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, + // Failed to read memory. + BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED, + // Failed to read registers. + BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED, + // Failed to find a function in debug sections. + BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED, + // Failed to execute dwarf instructions in debug sections. + BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED, +}; + +struct BacktraceUnwindError { + enum BacktraceUnwindErrorCode error_code; + + union { + // for BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED + uint64_t addr; + // for BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED + uint64_t regno; + } error_info; + + BacktraceUnwindError() : error_code(BACKTRACE_UNWIND_NO_ERROR) {} }; struct backtrace_frame_data_t { |