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