11 #include "llvm/Support/Format.h"
39 json::ObjectMapper o(value, path);
40 return o && o.map(
"type", bundle.
type);
51 template <
typename K,
typename V>
52 static Optional<V>
Lookup(DenseMap<K, V> &map, K k) {
53 auto it = map.find(k);
59 template <
typename K,
typename V>
61 auto it = map.find(k);
68 template <
typename K1,
typename K2,
typename V>
69 static Optional<V>
Lookup(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) {
70 auto it = map.find(k1);
73 return Lookup(it->second, k2);
77 template <
typename K1,
typename K2,
typename V>
78 static V *
LookupAsPtr(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) {
79 auto it = map.find(k1);
87 return createStringError(
88 std::errc::invalid_argument,
89 "no trace plug-in matches the specified type: \"%s\"",
93 Expected<lldb::TraceSP>
94 Trace::LoadPostMortemTraceFromFile(
Debugger &debugger,
95 const FileSpec &trace_description_file) {
97 auto buffer_or_error =
98 MemoryBuffer::getFile(trace_description_file.
GetPath());
99 if (!buffer_or_error) {
100 return createStringError(std::errc::invalid_argument,
101 "could not open input file: %s - %s.",
102 trace_description_file.
GetPath().c_str(),
103 buffer_or_error.getError().message().c_str());
106 Expected<json::Value> session_file =
107 json::parse(buffer_or_error.get()->getBuffer().str());
109 return session_file.takeError();
112 return Trace::FindPluginForPostMortemProcess(
113 debugger, *session_file,
117 Expected<lldb::TraceSP> Trace::FindPluginForPostMortemProcess(
118 Debugger &debugger,
const json::Value &trace_bundle_description,
119 StringRef bundle_dir) {
121 json::Path::Root root(
"traceBundle");
123 return root.getError();
125 if (
auto create_callback =
126 PluginManager::GetTraceCreateCallback(json_bundle.
type))
127 return create_callback(trace_bundle_description, bundle_dir, debugger);
132 Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name,
135 return createStringError(inconvertibleErrorCode(),
136 "Can't trace non-live processes");
138 if (
auto create_callback =
139 PluginManager::GetTraceCreateCallbackForLiveProcess(name))
140 return create_callback(process);
145 Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
146 StringRef schema = PluginManager::GetTraceSchema(name);
153 Error Trace::Start(
const llvm::json::Value &request) {
155 return createStringError(
156 inconvertibleErrorCode(),
157 "Attempted to start tracing without a live process.");
158 return m_live_process->TraceStart(request);
163 return createStringError(
164 inconvertibleErrorCode(),
165 "Attempted to stop tracing without a live process.");
169 Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) {
171 return createStringError(
172 inconvertibleErrorCode(),
173 "Attempted to stop tracing without a live process.");
177 Expected<std::string> Trace::GetLiveProcessState() {
179 return createStringError(
180 inconvertibleErrorCode(),
181 "Attempted to fetch live trace information without a live process.");
182 return m_live_process->TraceGetState(GetPluginName());
185 Optional<uint64_t> Trace::GetLiveThreadBinaryDataSize(
lldb::tid_t tid,
186 llvm::StringRef kind) {
187 Storage &storage = GetUpdatedStorage();
192 llvm::StringRef kind) {
193 Storage &storage = GetUpdatedStorage();
197 Optional<uint64_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
198 Storage &storage = GetUpdatedStorage();
202 Expected<std::vector<uint8_t>>
204 uint64_t expected_size) {
206 return createStringError(
207 inconvertibleErrorCode(),
208 formatv(
"Attempted to fetch live trace data without a live process. "
209 "Data kind = {0}, tid = {1}, cpu id = {2}.",
212 Expected<std::vector<uint8_t>> data =
213 m_live_process->TraceGetBinaryData(request);
216 return data.takeError();
218 if (data->size() != expected_size)
219 return createStringError(
220 inconvertibleErrorCode(),
221 formatv(
"Got incomplete live trace data. Data kind = {0}, expected "
222 "size = {1}, actual size = {2}, tid = {3}, cpu id = {4}",
223 request.
kind, expected_size, data->size(), request.
tid,
229 Expected<std::vector<uint8_t>>
230 Trace::GetLiveThreadBinaryData(
lldb::tid_t tid, llvm::StringRef kind) {
231 llvm::Optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind);
233 return createStringError(
234 inconvertibleErrorCode(),
235 "Tracing data \"%s\" is not available for thread %" PRIu64
".",
240 return GetLiveTraceBinaryData(request, *size);
243 Expected<std::vector<uint8_t>>
246 return createStringError(
247 inconvertibleErrorCode(),
248 "Attempted to fetch live cpu data without a live process.");
249 llvm::Optional<uint64_t> size = GetLiveCpuBinaryDataSize(cpu_id, kind);
251 return createStringError(
252 inconvertibleErrorCode(),
253 "Tracing data \"%s\" is not available for cpu_id %" PRIu64
".",
254 kind.data(), cpu_id);
258 return m_live_process->TraceGetBinaryData(request);
261 Expected<std::vector<uint8_t>>
262 Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
263 llvm::Optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind);
265 return createStringError(
266 inconvertibleErrorCode(),
267 "Tracing data \"%s\" is not available for the process.", kind.data());
271 return GetLiveTraceBinaryData(request, *size);
275 RefreshLiveProcessState();
279 const char *Trace::RefreshLiveProcessState() {
283 uint32_t new_stop_id = m_live_process->GetStopID();
284 if (new_stop_id == m_stop_id)
288 LLDB_LOG(log,
"Trace::RefreshLiveProcessState invoked");
290 m_stop_id = new_stop_id;
293 auto do_refresh = [&]() ->
Error {
294 Expected<std::string> json_string = GetLiveProcessState();
296 return json_string.takeError();
298 Expected<TraceGetStateResponse> live_process_state =
299 json::parse<TraceGetStateResponse>(*json_string,
300 "TraceGetStateResponse");
301 if (!live_process_state)
302 return live_process_state.takeError();
304 if (live_process_state->warnings) {
306 LLDB_LOG(log,
"== Warning when fetching the trace state: {0}",
warning);
310 live_process_state->traced_threads) {
312 m_storage.live_thread_data[thread_state.
tid].insert(
316 LLDB_LOG(log,
"== Found {0} threads being traced",
317 live_process_state->traced_threads.size());
319 if (live_process_state->cpus) {
320 m_storage.cpus.emplace();
321 for (
const TraceCpuState &cpu_state : *live_process_state->cpus) {
322 m_storage.cpus->push_back(cpu_state.
id);
324 m_storage.live_cpu_data_sizes[cpu_state.
id].insert(
327 LLDB_LOG(log,
"== Found {0} cpu cpus being traced",
328 live_process_state->cpus->size());
331 for (
const TraceBinaryData &item : live_process_state->process_binary_data)
334 return DoRefreshLiveProcessState(std::move(*live_process_state),
338 if (
Error err = do_refresh()) {
339 m_storage.live_refresh_error =
toString(std::move(err));
340 return m_storage.live_refresh_error->c_str();
346 Trace::Trace(ArrayRef<ProcessSP> postmortem_processes,
347 Optional<std::vector<lldb::cpu_id_t>> postmortem_cpus) {
348 for (ProcessSP process_sp : postmortem_processes)
349 m_storage.postmortem_processes.push_back(process_sp.get());
350 m_storage.cpus = postmortem_cpus;
353 Process *Trace::GetLiveProcess() {
return m_live_process; }
355 ArrayRef<Process *> Trace::GetPostMortemProcesses() {
356 return m_storage.postmortem_processes;
359 std::vector<Process *> Trace::GetAllProcesses() {
360 if (
Process *proc = GetLiveProcess())
362 return GetPostMortemProcesses();
366 RefreshLiveProcessState();
370 llvm::Expected<FileSpec>
371 Trace::GetPostMortemThreadDataFile(
lldb::tid_t tid, llvm::StringRef kind) {
372 Storage &storage = GetUpdatedStorage();
373 if (Optional<FileSpec> file =
377 return createStringError(
378 inconvertibleErrorCode(),
379 formatv(
"The thread with tid={0} doesn't have the tracing data {1}",
384 llvm::StringRef kind) {
385 Storage &storage = GetUpdatedStorage();
386 if (Optional<FileSpec> file =
390 return createStringError(
391 inconvertibleErrorCode(),
392 formatv(
"The cpu with id={0} doesn't have the tracing data {1}", cpu_id,
396 void Trace::SetPostMortemThreadDataFile(
lldb::tid_t tid, llvm::StringRef kind,
398 Storage &storage = GetUpdatedStorage();
403 llvm::StringRef kind,
FileSpec file_spec) {
404 Storage &storage = GetUpdatedStorage();
409 Trace::OnLiveThreadBinaryDataRead(
lldb::tid_t tid, llvm::StringRef kind,
411 Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind);
413 return data.takeError();
414 return callback(*data);
418 llvm::StringRef kind,
420 Storage &storage = GetUpdatedStorage();
421 if (std::vector<uint8_t> *cpu_data =
423 return callback(*cpu_data);
425 Expected<std::vector<uint8_t>> data = GetLiveCpuBinaryData(cpu_id, kind);
427 return data.takeError();
430 return callback(it.first->second);
435 ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
436 MemoryBuffer::getFile(file.
GetPath());
437 if (std::error_code err = trace_or_error.getError())
438 return createStringError(
439 inconvertibleErrorCode(),
"Failed fetching trace-related file %s. %s",
442 MemoryBuffer &data = **trace_or_error;
443 ArrayRef<uint8_t> array_ref(
444 reinterpret_cast<const uint8_t *
>(data.getBufferStart()),
445 data.getBufferSize());
446 return callback(array_ref);
450 Trace::OnPostMortemThreadBinaryDataRead(
lldb::tid_t tid, llvm::StringRef kind,
452 if (Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind))
453 return OnDataFileRead(*file, callback);
455 return file.takeError();
460 llvm::StringRef kind,
462 if (Expected<FileSpec> file = GetPostMortemCpuDataFile(cpu_id, kind))
463 return OnDataFileRead(*file, callback);
465 return file.takeError();
471 return OnLiveThreadBinaryDataRead(tid, kind, callback);
473 return OnPostMortemThreadBinaryDataRead(tid, kind, callback);
477 Trace::OnAllCpusBinaryDataRead(llvm::StringRef kind,
479 DenseMap<cpu_id_t, ArrayRef<uint8_t>> buffers;
480 Storage &storage = GetUpdatedStorage();
482 return Error::success();
484 std::function<
Error(std::vector<cpu_id_t>::iterator)> process_cpu =
485 [&](std::vector<cpu_id_t>::iterator cpu_id) ->
Error {
486 if (cpu_id == storage.
cpus->end())
487 return callback(buffers);
489 return OnCpuBinaryDataRead(*cpu_id, kind,
490 [&](ArrayRef<uint8_t> data) ->
Error {
491 buffers.try_emplace(*cpu_id, data);
492 auto next_id = cpu_id;
494 return process_cpu(next_id);
497 return process_cpu(storage.
cpus->begin());
501 llvm::StringRef kind,
504 return OnLiveCpuBinaryDataRead(cpu_id, kind, callback);
506 return OnPostMortemCpuBinaryDataRead(cpu_id, kind, callback);
509 ArrayRef<lldb::cpu_id_t> Trace::GetTracedCpus() {
510 Storage &storage = GetUpdatedStorage();
512 return *storage.
cpus;
516 std::vector<Process *> Trace::GetTracedProcesses() {
517 std::vector<Process *> processes;
518 Storage &storage = GetUpdatedStorage();
521 processes.push_back(proc);
524 processes.push_back(m_live_process);