bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext) { // Unwind using an already existing ucontext. return impl_->Unwind(num_ignore_frames, ucontext); } // Prevent multiple threads trying to set the trigger action on different // threads at the same time. if (pthread_mutex_lock(&g_sigaction_mutex) < 0) { BACK_LOGW("sigaction failed: %s", strerror(errno)); return false; } ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); entry->Lock(); struct sigaction act, oldact; memset(&act, 0, sizeof(act)); act.sa_sigaction = SignalHandler; act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; sigemptyset(&act.sa_mask); if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { BACK_LOGW("sigaction failed %s", strerror(errno)); entry->Unlock(); ThreadEntry::Remove(entry); pthread_mutex_unlock(&g_sigaction_mutex); return false; } if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); sigaction(THREAD_SIGNAL, &oldact, NULL); entry->Unlock(); ThreadEntry::Remove(entry); pthread_mutex_unlock(&g_sigaction_mutex); return false; } // Wait for the thread to get the ucontext. entry->Wait(0); // After the thread has received the signal, allow other unwinders to // continue. sigaction(THREAD_SIGNAL, &oldact, NULL); pthread_mutex_unlock(&g_sigaction_mutex); bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext()); // Tell the signal handler to exit and release the entry. entry->Wake(); return unwind_done; }
size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { #if defined(__APPLE__) BACK_LOGW("MacOS does not support reading from another pid."); return 0; #else backtrace_map_t map; FillInMap(addr, &map); if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { return 0; } bytes = MIN(map.end - addr, bytes); size_t bytes_read = 0; word_t data_word; size_t align_bytes = addr & (sizeof(word_t) - 1); if (align_bytes != 0) { if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) { return 0; } align_bytes = sizeof(word_t) - align_bytes; memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes, align_bytes); addr += align_bytes; buffer += align_bytes; bytes -= align_bytes; bytes_read += align_bytes; } size_t num_words = bytes / sizeof(word_t); for (size_t i = 0; i < num_words; i++) { if (!PtraceRead(Tid(), addr, &data_word)) { return bytes_read; } memcpy(buffer, &data_word, sizeof(word_t)); buffer += sizeof(word_t); addr += sizeof(word_t); bytes_read += sizeof(word_t); } size_t left_over = bytes & (sizeof(word_t) - 1); if (left_over) { if (!PtraceRead(Tid(), addr, &data_word)) { return bytes_read; } memcpy(buffer, &data_word, left_over); bytes_read += left_over; } return bytes_read; #endif }
bool UnwindPtrace::Init() { if (upt_info_) { return true; } 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; } 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; return false; } UnwindMap* map = static_cast<UnwindMap*>(GetMap()); unw_map_set(addr_space_, map->GetMapCursor()); 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; return false; } return true; }
bool BacktraceThread::Unwind(size_t num_ignore_frames) { ThreadEntry* entry = ThreadEntry::AddThreadToUnwind( thread_intf_, Pid(), Tid(), num_ignore_frames); if (!entry) { return false; } // Prevent multiple threads trying to set the trigger action on different // threads at the same time. bool retval = false; if (pthread_mutex_lock(&g_sigaction_mutex) == 0) { struct sigaction act, oldact; memset(&act, 0, sizeof(act)); act.sa_sigaction = SignalHandler; act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; sigemptyset(&act.sa_mask); if (sigaction(SIGURG, &act, &oldact) == 0) { retval = TriggerUnwindOnThread(entry); sigaction(SIGURG, &oldact, NULL); } else { BACK_LOGW("sigaction failed %s", strerror(errno)); } pthread_mutex_unlock(&g_sigaction_mutex); } else { BACK_LOGW("unable to acquire sigaction mutex."); } if (retval) { FinishUnwind(); } delete entry; return retval; }
bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, void* context) { std::unique_ptr<unwindstack::Regs> regs; if (context == nullptr) { regs.reset(unwindstack::Regs::RemoteGet(Tid())); } else { regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context)); } return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_); }
bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) { if (!VerifyReadWordArgs(ptr, out_value)) { return false; } #if defined(__APPLE__) BACK_LOGW("MacOS does not support reading from another pid."); return false; #else // ptrace() returns -1 and sets errno when the operation fails. // To disambiguate -1 from a valid result, we clear errno beforehand. errno = 0; *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL); if (*out_value == static_cast<uint32_t>(-1) && errno) { BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", reinterpret_cast<void*>(ptr), Tid(), strerror(errno)); return false; } return true; #endif }
bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { std::unique_ptr<unwindstack::Regs> regs; if (context == nullptr) { uint32_t machine_type; regs.reset(unwindstack::Regs::RemoteGet(Tid(), &machine_type)); } else { regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), context)); } error_ = BACKTRACE_UNWIND_NO_ERROR; return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames); }
bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { entry->state = STATE_WAITING; if (tgkill(Pid(), Tid(), SIGURG) != 0) { BACK_LOGW("tgkill failed %s", strerror(errno)); return false; } // Allow up to ten seconds for the dump to start. int wait_millis = 10000; int32_t state; while (true) { state = android_atomic_acquire_load(&entry->state); if (state != STATE_WAITING) { break; } if (wait_millis--) { usleep(1000); } else { break; } } bool cancelled = false; if (state == STATE_WAITING) { if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) { BACK_LOGW("Cancelled dump of thread %d", entry->tid); state = STATE_CANCEL; cancelled = true; } else { state = android_atomic_acquire_load(&entry->state); } } // Wait for at most ten seconds for the cancel or dump to finish. wait_millis = 10000; while (android_atomic_acquire_load(&entry->state) != STATE_DONE) { if (wait_millis--) { usleep(1000); } else { BACK_LOGW("Didn't finish thread unwind in 60 seconds."); break; } } return !cancelled; }
bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { #if defined(__APPLE__) BACK_LOGW("MacOS does not support reading from another pid."); return false; #else if (!VerifyReadWordArgs(ptr, out_value)) { return false; } backtrace_map_t map; FillInMap(ptr, &map); if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { return false; } return PtraceRead(Tid(), ptr, out_value); #endif }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); return false; } addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } UnwindMap* map = static_cast<UnwindMap*>(GetMap()); if (NULL == map) { BACK_LOGW("GetMap before unwinding failed."); return false; } unw_map_set(addr_space_, map->GetMapCursor()); upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } unw_cursor_t cursor; if(num_ignore_frames==0xdeaddead) { cursor.opaque[0]=0xdeaddead; //add for tell libunwind to unwind for kernel unwind userspace backtrace,lhd BACK_LOGW(" K2U_bt call into UnwindPtrace::Unwind."); num_ignore_frames=0; } int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); return false; } std::vector<backtrace_frame_data_t>* frames = GetFrames(); frames->reserve(MAX_BACKTRACE_FRAMES); size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames->resize(num_frames+1); backtrace_frame_data_t* frame = &frames->at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames->at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); frame->map = FindMap(frame->pc); num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); 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. return false; } if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); return false; } addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } UnwindMap* map = static_cast<UnwindMap*>(GetMap()); unw_map_set(addr_space_, map->GetMapCursor()); upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); FillInMap(frame->pc, &frame->map); num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }