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 UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { // The cursor structure is pretty large, do not put it on the stack. unw_cursor_t* cursor = new unw_cursor_t; int ret = unw_init_local(cursor, &context_); if (ret < 0) { BACK_LOGW("unw_init_local failed %d", ret); delete cursor; 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) { // Set the stack size for the previous frame. backtrace_frame_data_t* prev = &frames->at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } if (resolve) { frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); frame->map = FindMap(frame->pc); } else { frame->map = NULL; frame->func_offset = 0; } num_frames++; } else { num_ignore_frames--; } ret = unw_step (cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); delete cursor; return true; }
bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { if (context == nullptr) { BACK_LOGW("The context is needed for offline backtracing."); return false; } context_ = context; unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0); unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space, this); if (ret != 0) { BACK_LOGW("unw_init_remote failed %d", ret); unw_destroy_addr_space(addr_space); 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_[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_[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); unw_destroy_addr_space(addr_space); context_ = nullptr; return true; }
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; }
//------------------------------------------------------------------------- // BacktraceThread functions. //------------------------------------------------------------------------- static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) { if (pthread_mutex_lock(&g_entry_mutex) == 0) { pid_t pid = getpid(); pid_t tid = gettid(); ThreadEntry* cur_entry = g_list; while (cur_entry) { if (cur_entry->Match(pid, tid)) { break; } cur_entry = cur_entry->next; } pthread_mutex_unlock(&g_entry_mutex); if (!cur_entry) { BACK_LOGW("Unable to find pid %d tid %d information", pid, tid); return; } if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) { cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext, cur_entry->num_ignore_frames); } android_atomic_release_store(STATE_DONE, &cur_entry->state); } }
ThreadEntry* ThreadEntry::AddThreadToUnwind( BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) { ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames); pthread_mutex_lock(&g_entry_mutex); ThreadEntry* cur_entry = g_list; while (cur_entry != NULL) { if (cur_entry->Match(pid, tid)) { // There is already an entry for this pid/tid, this is bad. BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid); pthread_mutex_unlock(&g_entry_mutex); return NULL; } cur_entry = cur_entry->next; } // Add the entry to the list. entry->next = g_list; if (g_list) { g_list->prev = entry; } g_list = entry; pthread_mutex_unlock(&g_entry_mutex); return entry; }
bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) { if (ptr & 3) { BACK_LOGW("invalid pointer %p", (void*)ptr); *out_value = (uint32_t)-1; return false; } return true; }
bool UnwindCurrent::Unwind(size_t num_ignore_frames) { int ret = unw_getcontext(&context_); if (ret < 0) { BACK_LOGW("unw_getcontext failed %d", ret); return false; } return UnwindFromContext(num_ignore_frames, true); }
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; }
void ThreadEntry::Wait(int value) { timespec ts; ts.tv_sec = 10; ts.tv_nsec = 0; errno = 0; futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0); if (errno != 0 && errno != EWOULDBLOCK) { BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno)); } }
static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) { // 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*>(addr), nullptr); if (*out_value == static_cast<word_t>(-1) && errno) { BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", reinterpret_cast<void*>(addr), tid, strerror(errno)); return false; } return true; }
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 }
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 BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) { if (!VerifyReadWordArgs(ptr, out_value)) { return false; } const backtrace_map_t* map = FindMap(ptr); if (map && map->flags & PROT_READ) { *out_value = *reinterpret_cast<uint32_t*>(ptr); return true; } else { BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); *out_value = static_cast<uint32_t>(-1); return false; } }
void backtrace_format_frame_data( const backtrace_context_t* context, size_t frame_num, char* buf, size_t buf_size) { if (buf_size == 0 || buf == NULL) { BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size); } else if (context->data) { Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); std::string line = backtrace->FormatFrameData(frame_num); if (line.size() > buf_size) { memcpy(buf, line.c_str(), buf_size-1); buf[buf_size] = '\0'; } else { memcpy(buf, line.c_str(), line.size()+1); } } }
static void SignalHandler(int, siginfo_t*, void* sigcontext) { ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); if (!entry) { BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); return; } entry->CopyUcontext(reinterpret_cast<ucontext_t*>(sigcontext)); // Indicate the ucontext is now valid. entry->Wake(); // Pause the thread until the unwind is complete. This avoids having // the thread run ahead causing problems. entry->Wait(1); ThreadEntry::Remove(entry); }
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 ThreadEntry::Wait(int value) { timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec += 5; bool wait_completed = true; pthread_mutex_lock(&wait_mutex_); while (wait_value_ != value) { int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); if (ret != 0) { BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret)); wait_completed = false; break; } } pthread_mutex_unlock(&wait_mutex_); return wait_completed; }
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext == nullptr) { int ret = unw_getcontext(&context_); if (ret < 0) { BACK_LOGW("unw_getcontext failed %d", ret); return false; } } else { GetUnwContextFromUcontext(ucontext); } // The cursor structure is pretty large, do not put it on the stack. std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t); int ret = unw_init_local(cursor.get(), &context_); if (ret < 0) { BACK_LOGW("unw_init_local failed %d", ret); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(cursor.get(), 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.get(), UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } 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; FillInMap(frame->pc, &frame->map); // Check to see if we should skip this frame because it's coming // from within the library, and we are doing a local unwind. if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { if (num_ignore_frames == 0) { // GetFunctionName is an expensive call, only do it if we are // keeping the frame. frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); if (num_frames > 0) { // Set the stack size for the previous frame. backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } num_frames++; } else { num_ignore_frames--; } } ret = unw_step (cursor.get()); } 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; }
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext == nullptr) { int ret = unw_getcontext(&context_); if (ret < 0) { BACK_LOGW("unw_getcontext failed %d", ret); error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } } else { GetUnwContextFromUcontext(ucontext); } // The cursor structure is pretty large, do not put it on the stack. std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t); 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; return false; } initialized_ = true; size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(cursor.get(), 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.get(), UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } 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; FillInMap(frame->pc, &frame->map); // Check to see if we should skip this frame because it's coming // from within the library, and we are doing a local unwind. if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { if (num_ignore_frames == 0) { // GetFunctionName is an expensive call, only do it if we are // keeping the frame. frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map); if (num_frames > 0) { // Set the stack size for the previous frame. backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } if (BacktraceMap::IsValid(frame->map)) { frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias; } else { frame->rel_pc = frame->pc; } num_frames++; } else { num_ignore_frames--; // Set the number of frames to zero to remove the frame added // above. By definition, if we still have frames to ignore // there should only be one frame in the vector. CHECK(num_frames == 0); frames_.resize(0); } } // If the pc is in a device map, then don't try to step. if (frame->map.flags & PROT_DEVICE_MAP) { break; } // Verify the sp is not in a device map too. backtrace_map_t map; FillInMap(frame->sp, &map); if (map.flags & PROT_DEVICE_MAP) { break; } ret = unw_step (cursor.get()); } 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. error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING; return false; } error_ = BACKTRACE_UNWIND_NO_ERROR; if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION; return false; } if (!Init()) { 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); error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; 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; } FillInMap(frame->pc, &frame->map); if (BacktraceMap::IsValid(frame->map)) { frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias; } else { frame->rel_pc = frame->pc; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map); num_frames++; // If the pc is in a device map, then don't try to step. if (frame->map.flags & PROT_DEVICE_MAP) { break; } } else { // If the pc is in a device map, then don't try to step. backtrace_map_t map; FillInMap(pc, &map); if (map.flags & PROT_DEVICE_MAP) { break; } num_ignore_frames--; } // Verify the sp is not in a device map. backtrace_map_t map; FillInMap(sp, &map); if (map.flags & PROT_DEVICE_MAP) { break; } 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 (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) { addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } backtrace_t* backtrace = GetBacktraceData(); backtrace->num_frames = 0; 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; } 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) { size_t num_frames = backtrace->num_frames; backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; frame->map_name = NULL; frame->map_offset = 0; frame->func_name = NULL; frame->func_offset = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; prev->stack_size = frame->sp - prev->sp; } std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); if (!func_name.empty()) { frame->func_name = strdup(func_name.c_str()); } uintptr_t map_start; frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); if (frame->map_name) { frame->map_offset = frame->pc - map_start; } backtrace->num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); return true; }