Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
39642 views
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
372