Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) { Status error; std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); FreeBSDThread *thread = static_cast<FreeBSDThread *>( m_thread_list.GetThreadAtIndex(0, false).get()); if (thread) num = thread->NumSupportedHardwareWatchpoints(); else error.SetErrorString("Process does not exist."); return error; }
Status ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) { Status error; if (wp) { user_id_t watchID = wp->GetID(); addr_t addr = wp->GetLoadAddress(); Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); if (log) log->Printf("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 ")", watchID); if (wp->IsEnabled()) { if (log) log->Printf("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr); return error; } // Try to find a vacant watchpoint slot in the inferiors' main thread uint32_t wp_hw_index = LLDB_INVALID_INDEX32; std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); FreeBSDThread *thread = static_cast<FreeBSDThread *>( m_thread_list.GetThreadAtIndex(0, false).get()); if (thread) wp_hw_index = thread->FindVacantWatchpointIndex(); if (wp_hw_index == LLDB_INVALID_INDEX32) { error.SetErrorString("Setting hardware watchpoint failed."); } else { wp->SetHardwareIndex(wp_hw_index); bool wp_enabled = true; uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { thread = static_cast<FreeBSDThread *>( m_thread_list.GetThreadAtIndex(i, false).get()); if (thread) wp_enabled &= thread->EnableHardwareWatchpoint(wp); else wp_enabled = false; } if (wp_enabled) { wp->SetEnabled(true, notify); return error; } else { // Watchpoint enabling failed on at least one of the threads so roll // back all of them DisableWatchpoint(wp, false); error.SetErrorString("Setting hardware watchpoint failed"); } } } else error.SetErrorString("Watchpoint argument was NULL."); return error; }
Status ProcessFreeBSD::SetupSoftwareSingleStepping(lldb::tid_t tid) { std::unique_ptr<EmulateInstruction> emulator_ap( EmulateInstruction::FindPlugin(GetTarget().GetArchitecture(), eInstructionTypePCModifying, nullptr)); if (emulator_ap == nullptr) return Status("Instruction emulator not found!"); FreeBSDThread *thread = static_cast<FreeBSDThread *>( m_thread_list.FindThreadByID(tid, false).get()); if (thread == NULL) return Status("Thread not found not found!"); lldb::RegisterContextSP register_context_sp = thread->GetRegisterContext(); EmulatorBaton baton(this, register_context_sp.get()); emulator_ap->SetBaton(&baton); emulator_ap->SetReadMemCallback(&ReadMemoryCallback); emulator_ap->SetReadRegCallback(&ReadRegisterCallback); emulator_ap->SetWriteMemCallback(&WriteMemoryCallback); emulator_ap->SetWriteRegCallback(&WriteRegisterCallback); if (!emulator_ap->ReadInstruction()) return Status("Read instruction failed!"); bool emulation_result = emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); const RegisterInfo *reg_info_pc = register_context_sp->GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); auto pc_it = baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); lldb::addr_t next_pc; if (emulation_result) { assert(pc_it != baton.m_register_values.end() && "Emulation was successful but PC wasn't updated"); next_pc = pc_it->second.GetAsUInt64(); } else if (pc_it == baton.m_register_values.end()) { // Emulate instruction failed and it haven't changed PC. Advance PC with // the size of the current opcode because the emulation of all // PC modifying instruction should be successful. The failure most // likely caused by a not supported instruction which don't modify PC. next_pc = register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize(); } else { // The instruction emulation failed after it modified the PC. It is an // unknown error where we can't continue because the next instruction is // modifying the PC but we don't know how. return Status("Instruction emulation failed unexpectedly"); } SetSoftwareSingleStepBreakpoint(tid, next_pc); return Status(); }
Error ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) { Error error; Mutex::Locker lock(m_thread_list.GetMutex()); FreeBSDThread *thread = static_cast<FreeBSDThread*>( m_thread_list.GetThreadAtIndex(0, false).get()); if (thread) num = thread->NumSupportedHardwareWatchpoints(); else error.SetErrorString("Process does not exist."); return error; }
Error ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) { Error error; if (wp) { user_id_t watchID = wp->GetID(); addr_t addr = wp->GetLoadAddress(); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); if (log) log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 ")", watchID); if (!wp->IsEnabled()) { if (log) log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", watchID, (uint64_t)addr); // This is needed (for now) to keep watchpoints disabled correctly wp->SetEnabled(false, notify); return error; } if (wp->IsHardware()) { bool wp_disabled = true; Mutex::Locker lock(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { FreeBSDThread *thread = static_cast<FreeBSDThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); if (thread) wp_disabled &= thread->DisableHardwareWatchpoint(wp); else wp_disabled = false; } if (wp_disabled) { wp->SetHardwareIndex(LLDB_INVALID_INDEX32); wp->SetEnabled(false, notify); return error; } else error.SetErrorString("Disabling hardware watchpoint failed"); } } else error.SetErrorString("Watchpoint argument was NULL."); return error; }
bool ProcessFreeBSD::IsAThreadRunning() { bool is_running = false; std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { FreeBSDThread *thread = static_cast<FreeBSDThread *>( m_thread_list.GetThreadAtIndex(i, false).get()); StateType thread_state = thread->GetState(); if (thread_state == eStateRunning || thread_state == eStateStepping) { is_running = true; break; } } return is_running; }
void ProcessFreeBSD::RefreshStateAfterStop() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) log->Printf("ProcessFreeBSD::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size()); std::lock_guard<std::recursive_mutex> guard(m_message_mutex); // This method used to only handle one message. Changing it to loop allows // it to handle the case where we hit a breakpoint while handling a different // breakpoint. while (!m_message_queue.empty()) { ProcessMessage &message = m_message_queue.front(); // Resolve the thread this message corresponds to and pass it along. lldb::tid_t tid = message.GetTID(); if (log) log->Printf( "ProcessFreeBSD::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); m_thread_list.RefreshStateAfterStop(); FreeBSDThread *thread = static_cast<FreeBSDThread *>( GetThreadList().FindThreadByID(tid, false).get()); if (thread) thread->Notify(message); if (message.GetKind() == ProcessMessage::eExitMessage) { // FIXME: We should tell the user about this, but the limbo message is // probably better for that. if (log) log->Printf("ProcessFreeBSD::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid); std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); thread_sp.reset(); m_seen_initial_stop.erase(tid); } m_message_queue.pop(); } }