Merge "libbacktrace: export offline unwinding failures."
This commit is contained in:
commit
742fc190c8
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue