1 //===-- ScriptedThread.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ScriptedThread.h" 10 11 #include "Plugins/Process/Utility/RegisterContextThreadMemory.h" 12 #include "Plugins/Process/Utility/StopInfoMachException.h" 13 #include "lldb/Target/OperatingSystem.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/RegisterContext.h" 16 #include "lldb/Target/StopInfo.h" 17 #include "lldb/Target/Unwind.h" 18 #include "lldb/Utility/DataBufferHeap.h" 19 #include "lldb/Utility/LLDBLog.h" 20 #include <memory> 21 #include <optional> 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 void ScriptedThread::CheckInterpreterAndScriptObject() const { 27 lldbassert(m_script_object_sp && "Invalid Script Object."); 28 lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); 29 } 30 31 llvm::Expected<std::shared_ptr<ScriptedThread>> 32 ScriptedThread::Create(ScriptedProcess &process, 33 StructuredData::Generic *script_object) { 34 if (!process.IsValid()) 35 return llvm::createStringError(llvm::inconvertibleErrorCode(), 36 "Invalid scripted process."); 37 38 process.CheckScriptedInterface(); 39 40 auto scripted_thread_interface = 41 process.GetInterface().CreateScriptedThreadInterface(); 42 if (!scripted_thread_interface) 43 return llvm::createStringError( 44 llvm::inconvertibleErrorCode(), 45 "Failed to create scripted thread interface."); 46 47 llvm::StringRef thread_class_name; 48 if (!script_object) { 49 std::optional<std::string> class_name = 50 process.GetInterface().GetScriptedThreadPluginName(); 51 if (!class_name || class_name->empty()) 52 return llvm::createStringError( 53 llvm::inconvertibleErrorCode(), 54 "Failed to get scripted thread class name."); 55 thread_class_name = *class_name; 56 } 57 58 ExecutionContext exe_ctx(process); 59 auto obj_or_err = scripted_thread_interface->CreatePluginObject( 60 thread_class_name, exe_ctx, process.m_scripted_metadata.GetArgsSP(), 61 script_object); 62 63 if (!obj_or_err) { 64 llvm::consumeError(obj_or_err.takeError()); 65 return llvm::createStringError(llvm::inconvertibleErrorCode(), 66 "Failed to create script object."); 67 } 68 69 StructuredData::GenericSP owned_script_object_sp = *obj_or_err; 70 71 if (!owned_script_object_sp->IsValid()) 72 return llvm::createStringError(llvm::inconvertibleErrorCode(), 73 "Created script object is invalid."); 74 75 lldb::tid_t tid = scripted_thread_interface->GetThreadID(); 76 77 return std::make_shared<ScriptedThread>(process, scripted_thread_interface, 78 tid, owned_script_object_sp); 79 } 80 81 ScriptedThread::ScriptedThread(ScriptedProcess &process, 82 ScriptedThreadInterfaceSP interface_sp, 83 lldb::tid_t tid, 84 StructuredData::GenericSP script_object_sp) 85 : Thread(process, tid), m_scripted_process(process), 86 m_scripted_thread_interface_sp(interface_sp), 87 m_script_object_sp(script_object_sp) {} 88 89 ScriptedThread::~ScriptedThread() { DestroyThread(); } 90 91 const char *ScriptedThread::GetName() { 92 CheckInterpreterAndScriptObject(); 93 std::optional<std::string> thread_name = GetInterface()->GetName(); 94 if (!thread_name) 95 return nullptr; 96 return ConstString(thread_name->c_str()).AsCString(); 97 } 98 99 const char *ScriptedThread::GetQueueName() { 100 CheckInterpreterAndScriptObject(); 101 std::optional<std::string> queue_name = GetInterface()->GetQueue(); 102 if (!queue_name) 103 return nullptr; 104 return ConstString(queue_name->c_str()).AsCString(); 105 } 106 107 void ScriptedThread::WillResume(StateType resume_state) {} 108 109 void ScriptedThread::ClearStackFrames() { Thread::ClearStackFrames(); } 110 111 RegisterContextSP ScriptedThread::GetRegisterContext() { 112 if (!m_reg_context_sp) 113 m_reg_context_sp = CreateRegisterContextForFrame(nullptr); 114 return m_reg_context_sp; 115 } 116 117 RegisterContextSP 118 ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) { 119 const uint32_t concrete_frame_idx = 120 frame ? frame->GetConcreteFrameIndex() : 0; 121 122 if (concrete_frame_idx) 123 return GetUnwinder().CreateRegisterContextForFrame(frame); 124 125 lldb::RegisterContextSP reg_ctx_sp; 126 Status error; 127 128 std::optional<std::string> reg_data = GetInterface()->GetRegisterContext(); 129 if (!reg_data) 130 return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>( 131 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers data.", 132 error, LLDBLog::Thread); 133 134 DataBufferSP data_sp( 135 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size())); 136 137 if (!data_sp->GetByteSize()) 138 return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>( 139 LLVM_PRETTY_FUNCTION, "Failed to copy raw registers data.", error, 140 LLDBLog::Thread); 141 142 std::shared_ptr<RegisterContextMemory> reg_ctx_memory = 143 std::make_shared<RegisterContextMemory>( 144 *this, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); 145 if (!reg_ctx_memory) 146 return ScriptedInterface::ErrorWithMessage<lldb::RegisterContextSP>( 147 LLVM_PRETTY_FUNCTION, "Failed to create a register context.", error, 148 LLDBLog::Thread); 149 150 reg_ctx_memory->SetAllRegisterData(data_sp); 151 m_reg_context_sp = reg_ctx_memory; 152 153 return m_reg_context_sp; 154 } 155 156 bool ScriptedThread::LoadArtificialStackFrames() { 157 StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames(); 158 159 Status error; 160 if (!arr_sp) 161 return ScriptedInterface::ErrorWithMessage<bool>( 162 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.", 163 error, LLDBLog::Thread); 164 165 size_t arr_size = arr_sp->GetSize(); 166 if (arr_size > std::numeric_limits<uint32_t>::max()) 167 return ScriptedInterface::ErrorWithMessage<bool>( 168 LLVM_PRETTY_FUNCTION, 169 llvm::Twine( 170 "StackFrame array size (" + llvm::Twine(arr_size) + 171 llvm::Twine( 172 ") is greater than maximum authorized for a StackFrameList.")) 173 .str(), 174 error, LLDBLog::Thread); 175 176 StackFrameListSP frames = GetStackFrameList(); 177 178 for (size_t idx = 0; idx < arr_size; idx++) { 179 std::optional<StructuredData::Dictionary *> maybe_dict = 180 arr_sp->GetItemAtIndexAsDictionary(idx); 181 if (!maybe_dict) 182 return ScriptedInterface::ErrorWithMessage<bool>( 183 LLVM_PRETTY_FUNCTION, 184 llvm::Twine( 185 "Couldn't get artificial stackframe dictionary at index (" + 186 llvm::Twine(idx) + llvm::Twine(") from stackframe array.")) 187 .str(), 188 error, LLDBLog::Thread); 189 StructuredData::Dictionary *dict = *maybe_dict; 190 191 lldb::addr_t pc; 192 if (!dict->GetValueForKeyAsInteger("pc", pc)) 193 return ScriptedInterface::ErrorWithMessage<bool>( 194 LLVM_PRETTY_FUNCTION, 195 "Couldn't find value for key 'pc' in stackframe dictionary.", error, 196 LLDBLog::Thread); 197 198 Address symbol_addr; 199 symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget()); 200 201 lldb::addr_t cfa = LLDB_INVALID_ADDRESS; 202 bool cfa_is_valid = false; 203 const bool behaves_like_zeroth_frame = false; 204 SymbolContext sc; 205 symbol_addr.CalculateSymbolContext(&sc); 206 207 StackFrameSP synth_frame_sp = std::make_shared<StackFrame>( 208 this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 209 StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc); 210 211 if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp)) 212 return ScriptedInterface::ErrorWithMessage<bool>( 213 LLVM_PRETTY_FUNCTION, 214 llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) + 215 llvm::Twine(") to ScriptedThread StackFrameList.")) 216 .str(), 217 error, LLDBLog::Thread); 218 } 219 220 return true; 221 } 222 223 bool ScriptedThread::CalculateStopInfo() { 224 StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); 225 226 Status error; 227 if (!dict_sp) 228 return ScriptedInterface::ErrorWithMessage<bool>( 229 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error, 230 LLDBLog::Thread); 231 232 lldb::StopInfoSP stop_info_sp; 233 lldb::StopReason stop_reason_type; 234 235 if (!dict_sp->GetValueForKeyAsInteger("type", stop_reason_type)) 236 return ScriptedInterface::ErrorWithMessage<bool>( 237 LLVM_PRETTY_FUNCTION, 238 "Couldn't find value for key 'type' in stop reason dictionary.", error, 239 LLDBLog::Thread); 240 241 StructuredData::Dictionary *data_dict; 242 if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) 243 return ScriptedInterface::ErrorWithMessage<bool>( 244 LLVM_PRETTY_FUNCTION, 245 "Couldn't find value for key 'data' in stop reason dictionary.", error, 246 LLDBLog::Thread); 247 248 switch (stop_reason_type) { 249 case lldb::eStopReasonNone: 250 return true; 251 case lldb::eStopReasonBreakpoint: { 252 lldb::break_id_t break_id; 253 data_dict->GetValueForKeyAsInteger("break_id", break_id, 254 LLDB_INVALID_BREAK_ID); 255 stop_info_sp = 256 StopInfo::CreateStopReasonWithBreakpointSiteID(*this, break_id); 257 } break; 258 case lldb::eStopReasonSignal: { 259 uint32_t signal; 260 llvm::StringRef description; 261 if (!data_dict->GetValueForKeyAsInteger("signal", signal)) { 262 signal = LLDB_INVALID_SIGNAL_NUMBER; 263 return false; 264 } 265 data_dict->GetValueForKeyAsString("desc", description); 266 stop_info_sp = 267 StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); 268 } break; 269 case lldb::eStopReasonTrace: { 270 stop_info_sp = StopInfo::CreateStopReasonToTrace(*this); 271 } break; 272 case lldb::eStopReasonException: { 273 #if defined(__APPLE__) 274 StructuredData::Dictionary *mach_exception; 275 if (data_dict->GetValueForKeyAsDictionary("mach_exception", 276 mach_exception)) { 277 llvm::StringRef value; 278 mach_exception->GetValueForKeyAsString("type", value); 279 auto exc_type = 280 StopInfoMachException::MachException::ExceptionCode(value.data()); 281 282 if (!exc_type) 283 return false; 284 285 uint32_t exc_data_size = 0; 286 llvm::SmallVector<uint64_t, 3> raw_codes; 287 288 StructuredData::Array *exc_rawcodes; 289 mach_exception->GetValueForKeyAsArray("rawCodes", exc_rawcodes); 290 if (exc_rawcodes) { 291 auto fetch_data = [&raw_codes](StructuredData::Object *obj) { 292 if (!obj) 293 return false; 294 raw_codes.push_back(obj->GetUnsignedIntegerValue()); 295 return true; 296 }; 297 298 exc_rawcodes->ForEach(fetch_data); 299 exc_data_size = raw_codes.size(); 300 } 301 302 stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException( 303 *this, *exc_type, exc_data_size, 304 exc_data_size >= 1 ? raw_codes[0] : 0, 305 exc_data_size >= 2 ? raw_codes[1] : 0, 306 exc_data_size >= 3 ? raw_codes[2] : 0); 307 308 break; 309 } 310 #endif 311 stop_info_sp = 312 StopInfo::CreateStopReasonWithException(*this, "EXC_BAD_ACCESS"); 313 } break; 314 default: 315 return ScriptedInterface::ErrorWithMessage<bool>( 316 LLVM_PRETTY_FUNCTION, 317 llvm::Twine("Unsupported stop reason type (" + 318 llvm::Twine(stop_reason_type) + llvm::Twine(").")) 319 .str(), 320 error, LLDBLog::Thread); 321 } 322 323 if (!stop_info_sp) 324 return false; 325 326 SetStopInfo(stop_info_sp); 327 return true; 328 } 329 330 void ScriptedThread::RefreshStateAfterStop() { 331 GetRegisterContext()->InvalidateIfNeeded(/*force=*/false); 332 LoadArtificialStackFrames(); 333 } 334 335 lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { 336 return m_scripted_thread_interface_sp; 337 } 338 339 std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { 340 CheckInterpreterAndScriptObject(); 341 342 if (!m_register_info_sp) { 343 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo(); 344 345 Status error; 346 if (!reg_info) 347 return ScriptedInterface::ErrorWithMessage< 348 std::shared_ptr<DynamicRegisterInfo>>( 349 LLVM_PRETTY_FUNCTION, "Failed to get scripted thread registers info.", 350 error, LLDBLog::Thread); 351 352 m_register_info_sp = DynamicRegisterInfo::Create( 353 *reg_info, m_scripted_process.GetTarget().GetArchitecture()); 354 } 355 356 return m_register_info_sp; 357 } 358 359 StructuredData::ObjectSP ScriptedThread::FetchThreadExtendedInfo() { 360 CheckInterpreterAndScriptObject(); 361 362 Status error; 363 StructuredData::ArraySP extended_info_sp = GetInterface()->GetExtendedInfo(); 364 365 if (!extended_info_sp || !extended_info_sp->GetSize()) 366 return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>( 367 LLVM_PRETTY_FUNCTION, "No extended information found", error); 368 369 return extended_info_sp; 370 } 371