11 #include "llvm/Support/Format.h"
40 json::ObjectMapper o(value, path);
41 return o && o.map(
"type", bundle.
type);
52 template <
typename K,
typename V>
53 static std::optional<V>
Lookup(DenseMap<K, V> &map, K k) {
54 auto it = map.find(k);
60 template <
typename K,
typename V>
62 auto it = map.find(k);
69 template <
typename K1,
typename K2,
typename V>
70 static std::optional<V>
Lookup(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1,
72 auto it = map.find(k1);
75 return Lookup(it->second, k2);
79 template <
typename K1,
typename K2,
typename V>
80 static V *
LookupAsPtr(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) {
81 auto it = map.find(k1);
89 return createStringError(
90 std::errc::invalid_argument,
91 "no trace plug-in matches the specified type: \"%s\"",
95 Expected<lldb::TraceSP>
96 Trace::LoadPostMortemTraceFromFile(
Debugger &debugger,
97 const FileSpec &trace_description_file) {
99 auto buffer_or_error =
100 MemoryBuffer::getFile(trace_description_file.
GetPath());
101 if (!buffer_or_error) {
102 return createStringError(std::errc::invalid_argument,
103 "could not open input file: %s - %s.",
104 trace_description_file.
GetPath().c_str(),
105 buffer_or_error.getError().message().c_str());
108 Expected<json::Value> session_file =
109 json::parse(buffer_or_error.get()->getBuffer().str());
111 return session_file.takeError();
114 return Trace::FindPluginForPostMortemProcess(
115 debugger, *session_file,
119 Expected<lldb::TraceSP> Trace::FindPluginForPostMortemProcess(
120 Debugger &debugger,
const json::Value &trace_bundle_description,
121 StringRef bundle_dir) {
123 json::Path::Root root(
"traceBundle");
125 return root.getError();
127 if (
auto create_callback =
128 PluginManager::GetTraceCreateCallback(json_bundle.
type))
129 return create_callback(trace_bundle_description, bundle_dir, debugger);
134 Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name,
137 return createStringError(inconvertibleErrorCode(),
138 "Can't trace non-live processes");
140 if (
auto create_callback =
141 PluginManager::GetTraceCreateCallbackForLiveProcess(name))
142 return create_callback(process);
147 Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
148 StringRef schema = PluginManager::GetTraceSchema(name);
155 Error Trace::Start(
const llvm::json::Value &request) {
157 return createStringError(
158 inconvertibleErrorCode(),
159 "Attempted to start tracing without a live process.");
160 return m_live_process->TraceStart(request);
165 return createStringError(
166 inconvertibleErrorCode(),
167 "Attempted to stop tracing without a live process.");
171 Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) {
173 return createStringError(
174 inconvertibleErrorCode(),
175 "Attempted to stop tracing without a live process.");
179 Expected<std::string> Trace::GetLiveProcessState() {
181 return createStringError(
182 inconvertibleErrorCode(),
183 "Attempted to fetch live trace information without a live process.");
184 return m_live_process->TraceGetState(GetPluginName());
187 std::optional<uint64_t>
188 Trace::GetLiveThreadBinaryDataSize(
lldb::tid_t tid, llvm::StringRef kind) {
189 Storage &storage = GetUpdatedStorage();
194 llvm::StringRef kind) {
195 Storage &storage = GetUpdatedStorage();
199 std::optional<uint64_t>
200 Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
201 Storage &storage = GetUpdatedStorage();
205 Expected<std::vector<uint8_t>>
207 uint64_t expected_size) {
209 return createStringError(
210 inconvertibleErrorCode(),
211 formatv(
"Attempted to fetch live trace data without a live process. "
212 "Data kind = {0}, tid = {1}, cpu id = {2}.",
215 Expected<std::vector<uint8_t>> data =
216 m_live_process->TraceGetBinaryData(request);
219 return data.takeError();
221 if (data->size() != expected_size)
222 return createStringError(
223 inconvertibleErrorCode(),
224 formatv(
"Got incomplete live trace data. Data kind = {0}, expected "
225 "size = {1}, actual size = {2}, tid = {3}, cpu id = {4}",
226 request.
kind, expected_size, data->size(), request.
tid,
232 Expected<std::vector<uint8_t>>
233 Trace::GetLiveThreadBinaryData(
lldb::tid_t tid, llvm::StringRef kind) {
234 std::optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind);
236 return createStringError(
237 inconvertibleErrorCode(),
238 "Tracing data \"%s\" is not available for thread %" PRIu64
".",
243 return GetLiveTraceBinaryData(request, *size);
246 Expected<std::vector<uint8_t>>
249 return createStringError(
250 inconvertibleErrorCode(),
251 "Attempted to fetch live cpu data without a live process.");
252 std::optional<uint64_t> size = GetLiveCpuBinaryDataSize(cpu_id, kind);
254 return createStringError(
255 inconvertibleErrorCode(),
256 "Tracing data \"%s\" is not available for cpu_id %" PRIu64
".",
257 kind.data(), cpu_id);
260 std::nullopt, cpu_id};
261 return m_live_process->TraceGetBinaryData(request);
264 Expected<std::vector<uint8_t>>
265 Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
266 std::optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind);
268 return createStringError(
269 inconvertibleErrorCode(),
270 "Tracing data \"%s\" is not available for the process.", kind.data());
275 return GetLiveTraceBinaryData(request, *size);
279 RefreshLiveProcessState();
283 const char *Trace::RefreshLiveProcessState() {
287 uint32_t new_stop_id = m_live_process->GetStopID();
288 if (new_stop_id == m_stop_id)
292 LLDB_LOG(log,
"Trace::RefreshLiveProcessState invoked");
294 m_stop_id = new_stop_id;
297 auto do_refresh = [&]() ->
Error {
298 Expected<std::string> json_string = GetLiveProcessState();
300 return json_string.takeError();
302 Expected<TraceGetStateResponse> live_process_state =
303 json::parse<TraceGetStateResponse>(*json_string,
304 "TraceGetStateResponse");
305 if (!live_process_state)
306 return live_process_state.takeError();
308 if (live_process_state->warnings) {
310 LLDB_LOG(log,
"== Warning when fetching the trace state: {0}",
warning);
314 live_process_state->traced_threads) {
316 m_storage.live_thread_data[thread_state.
tid].insert(
320 LLDB_LOG(log,
"== Found {0} threads being traced",
321 live_process_state->traced_threads.size());
323 if (live_process_state->cpus) {
324 m_storage.cpus.emplace();
325 for (
const TraceCpuState &cpu_state : *live_process_state->cpus) {
326 m_storage.cpus->push_back(cpu_state.
id);
328 m_storage.live_cpu_data_sizes[cpu_state.
id].insert(
331 LLDB_LOG(log,
"== Found {0} cpu cpus being traced",
332 live_process_state->cpus->size());
335 for (
const TraceBinaryData &item : live_process_state->process_binary_data)
338 return DoRefreshLiveProcessState(std::move(*live_process_state),
342 if (
Error err = do_refresh()) {
343 m_storage.live_refresh_error =
toString(std::move(err));
344 return m_storage.live_refresh_error->c_str();
350 Trace::Trace(ArrayRef<ProcessSP> postmortem_processes,
351 std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus) {
352 for (ProcessSP process_sp : postmortem_processes)
353 m_storage.postmortem_processes.push_back(process_sp.get());
354 m_storage.cpus = postmortem_cpus;
357 Process *Trace::GetLiveProcess() {
return m_live_process; }
359 ArrayRef<Process *> Trace::GetPostMortemProcesses() {
360 return m_storage.postmortem_processes;
363 std::vector<Process *> Trace::GetAllProcesses() {
364 if (
Process *proc = GetLiveProcess())
366 return GetPostMortemProcesses();
370 RefreshLiveProcessState();
374 llvm::Expected<FileSpec>
375 Trace::GetPostMortemThreadDataFile(
lldb::tid_t tid, llvm::StringRef kind) {
376 Storage &storage = GetUpdatedStorage();
377 if (std::optional<FileSpec> file =
381 return createStringError(
382 inconvertibleErrorCode(),
383 formatv(
"The thread with tid={0} doesn't have the tracing data {1}",
388 llvm::StringRef kind) {
389 Storage &storage = GetUpdatedStorage();
390 if (std::optional<FileSpec> file =
394 return createStringError(
395 inconvertibleErrorCode(),
396 formatv(
"The cpu with id={0} doesn't have the tracing data {1}", cpu_id,
400 void Trace::SetPostMortemThreadDataFile(
lldb::tid_t tid, llvm::StringRef kind,
402 Storage &storage = GetUpdatedStorage();
407 llvm::StringRef kind,
FileSpec file_spec) {
408 Storage &storage = GetUpdatedStorage();
413 Trace::OnLiveThreadBinaryDataRead(
lldb::tid_t tid, llvm::StringRef kind,
415 Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind);
417 return data.takeError();
418 return callback(*data);
422 llvm::StringRef kind,
424 Storage &storage = GetUpdatedStorage();
425 if (std::vector<uint8_t> *cpu_data =
427 return callback(*cpu_data);
429 Expected<std::vector<uint8_t>> data = GetLiveCpuBinaryData(cpu_id, kind);
431 return data.takeError();
434 return callback(it.first->second);
439 ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
440 MemoryBuffer::getFile(file.
GetPath());
441 if (std::error_code err = trace_or_error.getError())
442 return createStringError(
443 inconvertibleErrorCode(),
"Failed fetching trace-related file %s. %s",
446 MemoryBuffer &data = **trace_or_error;
447 ArrayRef<uint8_t> array_ref(
448 reinterpret_cast<const uint8_t *
>(data.getBufferStart()),
449 data.getBufferSize());
450 return callback(array_ref);
454 Trace::OnPostMortemThreadBinaryDataRead(
lldb::tid_t tid, llvm::StringRef kind,
456 if (Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind))
457 return OnDataFileRead(*file, callback);
459 return file.takeError();
464 llvm::StringRef kind,
466 if (Expected<FileSpec> file = GetPostMortemCpuDataFile(cpu_id, kind))
467 return OnDataFileRead(*file, callback);
469 return file.takeError();
475 return OnLiveThreadBinaryDataRead(tid, kind, callback);
477 return OnPostMortemThreadBinaryDataRead(tid, kind, callback);
481 Trace::OnAllCpusBinaryDataRead(llvm::StringRef kind,
483 DenseMap<cpu_id_t, ArrayRef<uint8_t>> buffers;
484 Storage &storage = GetUpdatedStorage();
486 return Error::success();
488 std::function<
Error(std::vector<cpu_id_t>::iterator)> process_cpu =
489 [&](std::vector<cpu_id_t>::iterator cpu_id) ->
Error {
490 if (cpu_id == storage.
cpus->end())
491 return callback(buffers);
493 return OnCpuBinaryDataRead(*cpu_id, kind,
494 [&](ArrayRef<uint8_t> data) ->
Error {
495 buffers.try_emplace(*cpu_id, data);
496 auto next_id = cpu_id;
498 return process_cpu(next_id);
501 return process_cpu(storage.
cpus->begin());
505 llvm::StringRef kind,
508 return OnLiveCpuBinaryDataRead(cpu_id, kind, callback);
510 return OnPostMortemCpuBinaryDataRead(cpu_id, kind, callback);
513 ArrayRef<lldb::cpu_id_t> Trace::GetTracedCpus() {
514 Storage &storage = GetUpdatedStorage();
516 return *storage.
cpus;
520 std::vector<Process *> Trace::GetTracedProcesses() {
521 std::vector<Process *> processes;
522 Storage &storage = GetUpdatedStorage();
525 processes.push_back(proc);
528 processes.push_back(m_live_process);