1 //===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 #include <errno.h> 12 13 // C++ Includes 14 // Other libraries and framework includes 15 #include "lldb/Core/PluginManager.h" 16 #include "lldb/Core/State.h" 17 #include "lldb/Host/Host.h" 18 #include "lldb/Symbol/ObjectFile.h" 19 #include "lldb/Target/DynamicLoader.h" 20 #include "lldb/Target/Target.h" 21 22 #include "ProcessFreeBSD.h" 23 #include "ProcessPOSIXLog.h" 24 #include "Plugins/Process/Utility/InferiorCallPOSIX.h" 25 #include "ProcessMonitor.h" 26 #include "FreeBSDThread.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 //------------------------------------------------------------------------------ 32 // Static functions. 33 34 lldb::ProcessSP 35 ProcessFreeBSD::CreateInstance(Target& target, 36 Listener &listener, 37 const FileSpec *crash_file_path) 38 { 39 lldb::ProcessSP process_sp; 40 if (crash_file_path == NULL) 41 process_sp.reset(new ProcessFreeBSD (target, listener)); 42 return process_sp; 43 } 44 45 void 46 ProcessFreeBSD::Initialize() 47 { 48 static bool g_initialized = false; 49 50 if (!g_initialized) 51 { 52 PluginManager::RegisterPlugin(GetPluginNameStatic(), 53 GetPluginDescriptionStatic(), 54 CreateInstance); 55 Log::Callbacks log_callbacks = { 56 ProcessPOSIXLog::DisableLog, 57 ProcessPOSIXLog::EnableLog, 58 ProcessPOSIXLog::ListLogCategories 59 }; 60 61 Log::RegisterLogChannel (ProcessFreeBSD::GetPluginNameStatic(), log_callbacks); 62 ProcessPOSIXLog::RegisterPluginName(GetPluginNameStatic()); 63 g_initialized = true; 64 } 65 } 66 67 lldb_private::ConstString 68 ProcessFreeBSD::GetPluginNameStatic() 69 { 70 static ConstString g_name("freebsd"); 71 return g_name; 72 } 73 74 const char * 75 ProcessFreeBSD::GetPluginDescriptionStatic() 76 { 77 return "Process plugin for FreeBSD"; 78 } 79 80 //------------------------------------------------------------------------------ 81 // ProcessInterface protocol. 82 83 lldb_private::ConstString 84 ProcessFreeBSD::GetPluginName() 85 { 86 return GetPluginNameStatic(); 87 } 88 89 uint32_t 90 ProcessFreeBSD::GetPluginVersion() 91 { 92 return 1; 93 } 94 95 void 96 ProcessFreeBSD::GetPluginCommandHelp(const char *command, Stream *strm) 97 { 98 } 99 100 Error 101 ProcessFreeBSD::ExecutePluginCommand(Args &command, Stream *strm) 102 { 103 return Error(1, eErrorTypeGeneric); 104 } 105 106 Log * 107 ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command) 108 { 109 return NULL; 110 } 111 112 //------------------------------------------------------------------------------ 113 // Constructors and destructors. 114 115 ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener) 116 : ProcessPOSIX(target, listener) 117 { 118 } 119 120 void 121 ProcessFreeBSD::Terminate() 122 { 123 } 124 125 Error 126 ProcessFreeBSD::DoDetach(bool keep_stopped) 127 { 128 Error error; 129 if (keep_stopped) 130 { 131 error.SetErrorString("Detaching with keep_stopped true is not currently supported on FreeBSD."); 132 return error; 133 } 134 135 DisableAllBreakpointSites(); 136 137 error = m_monitor->Detach(GetID()); 138 139 if (error.Success()) 140 SetPrivateState(eStateDetached); 141 142 return error; 143 } 144 145 Error 146 ProcessFreeBSD::DoResume() 147 { 148 Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); 149 150 // FreeBSD's ptrace() uses 0 to indicate "no signal is to be sent." 151 int resume_signal = 0; 152 153 SetPrivateState(eStateRunning); 154 155 Mutex::Locker lock(m_thread_list.GetMutex()); 156 bool do_step = false; 157 158 for (tid_collection::const_iterator t_pos = m_run_tids.begin(), t_end = m_run_tids.end(); t_pos != t_end; ++t_pos) 159 { 160 m_monitor->ThreadSuspend(*t_pos, false); 161 } 162 for (tid_collection::const_iterator t_pos = m_step_tids.begin(), t_end = m_step_tids.end(); t_pos != t_end; ++t_pos) 163 { 164 m_monitor->ThreadSuspend(*t_pos, false); 165 do_step = true; 166 } 167 for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), t_end = m_suspend_tids.end(); t_pos != t_end; ++t_pos) 168 { 169 m_monitor->ThreadSuspend(*t_pos, true); 170 // XXX Cannot PT_CONTINUE properly with suspended threads. 171 do_step = true; 172 } 173 174 if (log) 175 log->Printf("process %lu resuming (%s)", GetID(), do_step ? "step" : "continue"); 176 if (do_step) 177 m_monitor->SingleStep(GetID(), resume_signal); 178 else 179 m_monitor->Resume(GetID(), resume_signal); 180 181 return Error(); 182 } 183 184 bool 185 ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) 186 { 187 Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); 188 if (log) 189 log->Printf("ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); 190 191 std::vector<lldb::pid_t> tds; 192 if (!GetMonitor().GetCurrentThreadIDs(tds)) 193 { 194 return false; 195 } 196 197 ThreadList old_thread_list_copy(old_thread_list); 198 for (size_t i = 0; i < tds.size(); ++i) 199 { 200 tid_t tid = tds[i]; 201 ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByID(tid, false)); 202 if (!thread_sp) 203 { 204 thread_sp.reset(new FreeBSDThread(*this, tid)); 205 if (log) 206 log->Printf("ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, tid); 207 } 208 else 209 { 210 if (log) 211 log->Printf("ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, tid); 212 } 213 new_thread_list.AddThread(thread_sp); 214 } 215 for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i) 216 { 217 ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); 218 if (old_thread_sp) 219 { 220 if (log) 221 log->Printf("ProcessFreeBSD::%s remove tid", __FUNCTION__); 222 } 223 } 224 225 return true; 226 } 227 228 Error 229 ProcessFreeBSD::WillResume() 230 { 231 m_suspend_tids.clear(); 232 m_run_tids.clear(); 233 m_step_tids.clear(); 234 return ProcessPOSIX::WillResume(); 235 } 236 237 void 238 ProcessFreeBSD::SendMessage(const ProcessMessage &message) 239 { 240 Mutex::Locker lock(m_message_mutex); 241 242 switch (message.GetKind()) 243 { 244 case ProcessMessage::eInvalidMessage: 245 return; 246 247 case ProcessMessage::eAttachMessage: 248 SetPrivateState(eStateStopped); 249 return; 250 251 case ProcessMessage::eLimboMessage: 252 case ProcessMessage::eExitMessage: 253 m_exit_status = message.GetExitStatus(); 254 SetExitStatus(m_exit_status, NULL); 255 break; 256 257 case ProcessMessage::eSignalMessage: 258 case ProcessMessage::eSignalDeliveredMessage: 259 case ProcessMessage::eBreakpointMessage: 260 case ProcessMessage::eTraceMessage: 261 case ProcessMessage::eWatchpointMessage: 262 case ProcessMessage::eCrashMessage: 263 SetPrivateState(eStateStopped); 264 break; 265 266 case ProcessMessage::eNewThreadMessage: 267 assert(0 && "eNewThreadMessage unexpected on FreeBSD"); 268 break; 269 270 case ProcessMessage::eExecMessage: 271 SetPrivateState(eStateStopped); 272 break; 273 } 274 275 m_message_queue.push(message); 276 } 277 278