1e8d8bef9SDimitry Andric //===-- Trace.cpp ---------------------------------------------------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric 
9e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h"
10e8d8bef9SDimitry Andric 
11e8d8bef9SDimitry Andric #include "llvm/Support/Format.h"
12e8d8bef9SDimitry Andric 
13e8d8bef9SDimitry Andric #include "lldb/Core/Module.h"
14e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h"
15e8d8bef9SDimitry Andric #include "lldb/Symbol/Function.h"
16fe6060f1SDimitry Andric #include "lldb/Target/ExecutionContext.h"
17e8d8bef9SDimitry Andric #include "lldb/Target/Process.h"
18e8d8bef9SDimitry Andric #include "lldb/Target/SectionLoadList.h"
19e8d8bef9SDimitry Andric #include "lldb/Target/Thread.h"
2081ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
21e8d8bef9SDimitry Andric #include "lldb/Utility/Stream.h"
22*bdd1243dSDimitry Andric #include <optional>
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric using namespace lldb;
25e8d8bef9SDimitry Andric using namespace lldb_private;
26e8d8bef9SDimitry Andric using namespace llvm;
27e8d8bef9SDimitry Andric 
2881ad6265SDimitry Andric // Helper structs used to extract the type of a JSON trace bundle description
2981ad6265SDimitry Andric // object without having to parse the entire object.
30e8d8bef9SDimitry Andric 
3181ad6265SDimitry Andric struct JSONSimpleTraceBundleDescription {
32e8d8bef9SDimitry Andric   std::string type;
33e8d8bef9SDimitry Andric };
34e8d8bef9SDimitry Andric 
35e8d8bef9SDimitry Andric namespace llvm {
36e8d8bef9SDimitry Andric namespace json {
37e8d8bef9SDimitry Andric 
fromJSON(const Value & value,JSONSimpleTraceBundleDescription & bundle,Path path)3881ad6265SDimitry Andric bool fromJSON(const Value &value, JSONSimpleTraceBundleDescription &bundle,
39e8d8bef9SDimitry Andric               Path path) {
40e8d8bef9SDimitry Andric   json::ObjectMapper o(value, path);
4181ad6265SDimitry Andric   return o && o.map("type", bundle.type);
42e8d8bef9SDimitry Andric }
43e8d8bef9SDimitry Andric 
44e8d8bef9SDimitry Andric } // namespace json
45e8d8bef9SDimitry Andric } // namespace llvm
46e8d8bef9SDimitry Andric 
4781ad6265SDimitry Andric /// Helper functions for fetching data in maps and returning Optionals or
4881ad6265SDimitry Andric /// pointers instead of iterators for simplicity. It's worth mentioning that the
4981ad6265SDimitry Andric /// Optionals version can't return the inner data by reference because of
5081ad6265SDimitry Andric /// limitations in move constructors.
5181ad6265SDimitry Andric /// \{
5281ad6265SDimitry Andric template <typename K, typename V>
Lookup(DenseMap<K,V> & map,K k)53*bdd1243dSDimitry Andric static std::optional<V> Lookup(DenseMap<K, V> &map, K k) {
5481ad6265SDimitry Andric   auto it = map.find(k);
5581ad6265SDimitry Andric   if (it == map.end())
56*bdd1243dSDimitry Andric     return std::nullopt;
5781ad6265SDimitry Andric   return it->second;
5881ad6265SDimitry Andric }
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric template <typename K, typename V>
LookupAsPtr(DenseMap<K,V> & map,K k)6181ad6265SDimitry Andric static V *LookupAsPtr(DenseMap<K, V> &map, K k) {
6281ad6265SDimitry Andric   auto it = map.find(k);
6381ad6265SDimitry Andric   if (it == map.end())
6481ad6265SDimitry Andric     return nullptr;
6581ad6265SDimitry Andric   return &it->second;
6681ad6265SDimitry Andric }
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric /// Similar to the methods above but it looks for an item in a map of maps.
6981ad6265SDimitry Andric template <typename K1, typename K2, typename V>
Lookup(DenseMap<K1,DenseMap<K2,V>> & map,K1 k1,K2 k2)70*bdd1243dSDimitry Andric static std::optional<V> Lookup(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1,
71*bdd1243dSDimitry Andric                                K2 k2) {
7281ad6265SDimitry Andric   auto it = map.find(k1);
7381ad6265SDimitry Andric   if (it == map.end())
74*bdd1243dSDimitry Andric     return std::nullopt;
7581ad6265SDimitry Andric   return Lookup(it->second, k2);
7681ad6265SDimitry Andric }
7781ad6265SDimitry Andric 
7881ad6265SDimitry Andric /// Similar to the methods above but it looks for an item in a map of maps.
7981ad6265SDimitry Andric template <typename K1, typename K2, typename V>
LookupAsPtr(DenseMap<K1,DenseMap<K2,V>> & map,K1 k1,K2 k2)8081ad6265SDimitry Andric static V *LookupAsPtr(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) {
8181ad6265SDimitry Andric   auto it = map.find(k1);
8281ad6265SDimitry Andric   if (it == map.end())
8381ad6265SDimitry Andric     return nullptr;
8481ad6265SDimitry Andric   return LookupAsPtr(it->second, k2);
8581ad6265SDimitry Andric }
8681ad6265SDimitry Andric /// \}
8781ad6265SDimitry Andric 
createInvalidPlugInError(StringRef plugin_name)88e8d8bef9SDimitry Andric static Error createInvalidPlugInError(StringRef plugin_name) {
89e8d8bef9SDimitry Andric   return createStringError(
90e8d8bef9SDimitry Andric       std::errc::invalid_argument,
91e8d8bef9SDimitry Andric       "no trace plug-in matches the specified type: \"%s\"",
92e8d8bef9SDimitry Andric       plugin_name.data());
93e8d8bef9SDimitry Andric }
94e8d8bef9SDimitry Andric 
95fe6060f1SDimitry Andric Expected<lldb::TraceSP>
LoadPostMortemTraceFromFile(Debugger & debugger,const FileSpec & trace_description_file)9681ad6265SDimitry Andric Trace::LoadPostMortemTraceFromFile(Debugger &debugger,
9781ad6265SDimitry Andric                                    const FileSpec &trace_description_file) {
9881ad6265SDimitry Andric 
9981ad6265SDimitry Andric   auto buffer_or_error =
10081ad6265SDimitry Andric       MemoryBuffer::getFile(trace_description_file.GetPath());
10181ad6265SDimitry Andric   if (!buffer_or_error) {
10281ad6265SDimitry Andric     return createStringError(std::errc::invalid_argument,
10381ad6265SDimitry Andric                              "could not open input file: %s - %s.",
10481ad6265SDimitry Andric                              trace_description_file.GetPath().c_str(),
10581ad6265SDimitry Andric                              buffer_or_error.getError().message().c_str());
10681ad6265SDimitry Andric   }
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   Expected<json::Value> session_file =
10981ad6265SDimitry Andric       json::parse(buffer_or_error.get()->getBuffer().str());
11081ad6265SDimitry Andric   if (!session_file) {
11181ad6265SDimitry Andric     return session_file.takeError();
11281ad6265SDimitry Andric   }
11381ad6265SDimitry Andric 
11481ad6265SDimitry Andric   return Trace::FindPluginForPostMortemProcess(
11581ad6265SDimitry Andric       debugger, *session_file,
11681ad6265SDimitry Andric       trace_description_file.GetDirectory().AsCString());
11781ad6265SDimitry Andric }
11881ad6265SDimitry Andric 
FindPluginForPostMortemProcess(Debugger & debugger,const json::Value & trace_bundle_description,StringRef bundle_dir)11981ad6265SDimitry Andric Expected<lldb::TraceSP> Trace::FindPluginForPostMortemProcess(
12081ad6265SDimitry Andric     Debugger &debugger, const json::Value &trace_bundle_description,
12181ad6265SDimitry Andric     StringRef bundle_dir) {
12281ad6265SDimitry Andric   JSONSimpleTraceBundleDescription json_bundle;
12381ad6265SDimitry Andric   json::Path::Root root("traceBundle");
12481ad6265SDimitry Andric   if (!json::fromJSON(trace_bundle_description, json_bundle, root))
125e8d8bef9SDimitry Andric     return root.getError();
126e8d8bef9SDimitry Andric 
127349cc55cSDimitry Andric   if (auto create_callback =
12881ad6265SDimitry Andric           PluginManager::GetTraceCreateCallback(json_bundle.type))
12981ad6265SDimitry Andric     return create_callback(trace_bundle_description, bundle_dir, debugger);
130e8d8bef9SDimitry Andric 
13181ad6265SDimitry Andric   return createInvalidPlugInError(json_bundle.type);
132e8d8bef9SDimitry Andric }
133e8d8bef9SDimitry Andric 
FindPluginForLiveProcess(llvm::StringRef name,Process & process)134349cc55cSDimitry Andric Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name,
135349cc55cSDimitry Andric                                                         Process &process) {
136fe6060f1SDimitry Andric   if (!process.IsLiveDebugSession())
137fe6060f1SDimitry Andric     return createStringError(inconvertibleErrorCode(),
138fe6060f1SDimitry Andric                              "Can't trace non-live processes");
139fe6060f1SDimitry Andric 
140fe6060f1SDimitry Andric   if (auto create_callback =
141fe6060f1SDimitry Andric           PluginManager::GetTraceCreateCallbackForLiveProcess(name))
142fe6060f1SDimitry Andric     return create_callback(process);
143fe6060f1SDimitry Andric 
144349cc55cSDimitry Andric   return createInvalidPlugInError(name);
145fe6060f1SDimitry Andric }
146fe6060f1SDimitry Andric 
FindPluginSchema(StringRef name)147e8d8bef9SDimitry Andric Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
148349cc55cSDimitry Andric   StringRef schema = PluginManager::GetTraceSchema(name);
149e8d8bef9SDimitry Andric   if (!schema.empty())
150e8d8bef9SDimitry Andric     return schema;
151e8d8bef9SDimitry Andric 
152e8d8bef9SDimitry Andric   return createInvalidPlugInError(name);
153e8d8bef9SDimitry Andric }
154e8d8bef9SDimitry Andric 
Start(const llvm::json::Value & request)155fe6060f1SDimitry Andric Error Trace::Start(const llvm::json::Value &request) {
156fe6060f1SDimitry Andric   if (!m_live_process)
15781ad6265SDimitry Andric     return createStringError(
15881ad6265SDimitry Andric         inconvertibleErrorCode(),
15981ad6265SDimitry Andric         "Attempted to start tracing without a live process.");
160fe6060f1SDimitry Andric   return m_live_process->TraceStart(request);
161e8d8bef9SDimitry Andric }
162e8d8bef9SDimitry Andric 
Stop()163fe6060f1SDimitry Andric Error Trace::Stop() {
164fe6060f1SDimitry Andric   if (!m_live_process)
16581ad6265SDimitry Andric     return createStringError(
16681ad6265SDimitry Andric         inconvertibleErrorCode(),
16781ad6265SDimitry Andric         "Attempted to stop tracing without a live process.");
168349cc55cSDimitry Andric   return m_live_process->TraceStop(TraceStopRequest(GetPluginName()));
169e8d8bef9SDimitry Andric }
170e8d8bef9SDimitry Andric 
Stop(llvm::ArrayRef<lldb::tid_t> tids)171fe6060f1SDimitry Andric Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) {
172fe6060f1SDimitry Andric   if (!m_live_process)
17381ad6265SDimitry Andric     return createStringError(
17481ad6265SDimitry Andric         inconvertibleErrorCode(),
17581ad6265SDimitry Andric         "Attempted to stop tracing without a live process.");
176349cc55cSDimitry Andric   return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids));
177e8d8bef9SDimitry Andric }
178e8d8bef9SDimitry Andric 
GetLiveProcessState()179fe6060f1SDimitry Andric Expected<std::string> Trace::GetLiveProcessState() {
180fe6060f1SDimitry Andric   if (!m_live_process)
18181ad6265SDimitry Andric     return createStringError(
18281ad6265SDimitry Andric         inconvertibleErrorCode(),
18381ad6265SDimitry Andric         "Attempted to fetch live trace information without a live process.");
184349cc55cSDimitry Andric   return m_live_process->TraceGetState(GetPluginName());
185e8d8bef9SDimitry Andric }
186e8d8bef9SDimitry Andric 
187*bdd1243dSDimitry Andric std::optional<uint64_t>
GetLiveThreadBinaryDataSize(lldb::tid_t tid,llvm::StringRef kind)188*bdd1243dSDimitry Andric Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, llvm::StringRef kind) {
18981ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
19081ad6265SDimitry Andric   return Lookup(storage.live_thread_data, tid, ConstString(kind));
191e8d8bef9SDimitry Andric }
192e8d8bef9SDimitry Andric 
GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id,llvm::StringRef kind)193*bdd1243dSDimitry Andric std::optional<uint64_t> Trace::GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id,
19481ad6265SDimitry Andric                                                         llvm::StringRef kind) {
19581ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
19681ad6265SDimitry Andric   return Lookup(storage.live_cpu_data_sizes, cpu_id, ConstString(kind));
197e8d8bef9SDimitry Andric }
198e8d8bef9SDimitry Andric 
199*bdd1243dSDimitry Andric std::optional<uint64_t>
GetLiveProcessBinaryDataSize(llvm::StringRef kind)200*bdd1243dSDimitry Andric Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
20181ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
20281ad6265SDimitry Andric   return Lookup(storage.live_process_data, ConstString(kind));
20381ad6265SDimitry Andric }
20481ad6265SDimitry Andric 
20581ad6265SDimitry Andric Expected<std::vector<uint8_t>>
GetLiveTraceBinaryData(const TraceGetBinaryDataRequest & request,uint64_t expected_size)20681ad6265SDimitry Andric Trace::GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request,
20781ad6265SDimitry Andric                               uint64_t expected_size) {
208fe6060f1SDimitry Andric   if (!m_live_process)
20981ad6265SDimitry Andric     return createStringError(
21081ad6265SDimitry Andric         inconvertibleErrorCode(),
21181ad6265SDimitry Andric         formatv("Attempted to fetch live trace data without a live process. "
21281ad6265SDimitry Andric                 "Data kind = {0}, tid = {1}, cpu id = {2}.",
21381ad6265SDimitry Andric                 request.kind, request.tid, request.cpu_id));
21481ad6265SDimitry Andric 
21581ad6265SDimitry Andric   Expected<std::vector<uint8_t>> data =
21681ad6265SDimitry Andric       m_live_process->TraceGetBinaryData(request);
21781ad6265SDimitry Andric 
21881ad6265SDimitry Andric   if (!data)
21981ad6265SDimitry Andric     return data.takeError();
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric   if (data->size() != expected_size)
22281ad6265SDimitry Andric     return createStringError(
22381ad6265SDimitry Andric         inconvertibleErrorCode(),
22481ad6265SDimitry Andric         formatv("Got incomplete live trace data. Data kind = {0}, expected "
22581ad6265SDimitry Andric                 "size = {1}, actual size = {2}, tid = {3}, cpu id = {4}",
22681ad6265SDimitry Andric                 request.kind, expected_size, data->size(), request.tid,
22781ad6265SDimitry Andric                 request.cpu_id));
22881ad6265SDimitry Andric 
22981ad6265SDimitry Andric   return data;
23081ad6265SDimitry Andric }
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric Expected<std::vector<uint8_t>>
GetLiveThreadBinaryData(lldb::tid_t tid,llvm::StringRef kind)23381ad6265SDimitry Andric Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
234*bdd1243dSDimitry Andric   std::optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind);
235fe6060f1SDimitry Andric   if (!size)
236fe6060f1SDimitry Andric     return createStringError(
237fe6060f1SDimitry Andric         inconvertibleErrorCode(),
238fe6060f1SDimitry Andric         "Tracing data \"%s\" is not available for thread %" PRIu64 ".",
239fe6060f1SDimitry Andric         kind.data(), tid);
240e8d8bef9SDimitry Andric 
24181ad6265SDimitry Andric   TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), tid,
242*bdd1243dSDimitry Andric                                     /*cpu_id=*/std::nullopt};
24381ad6265SDimitry Andric   return GetLiveTraceBinaryData(request, *size);
24481ad6265SDimitry Andric }
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric Expected<std::vector<uint8_t>>
GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id,llvm::StringRef kind)24781ad6265SDimitry Andric Trace::GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind) {
24881ad6265SDimitry Andric   if (!m_live_process)
24981ad6265SDimitry Andric     return createStringError(
25081ad6265SDimitry Andric         inconvertibleErrorCode(),
25181ad6265SDimitry Andric         "Attempted to fetch live cpu data without a live process.");
252*bdd1243dSDimitry Andric   std::optional<uint64_t> size = GetLiveCpuBinaryDataSize(cpu_id, kind);
25381ad6265SDimitry Andric   if (!size)
25481ad6265SDimitry Andric     return createStringError(
25581ad6265SDimitry Andric         inconvertibleErrorCode(),
25681ad6265SDimitry Andric         "Tracing data \"%s\" is not available for cpu_id %" PRIu64 ".",
25781ad6265SDimitry Andric         kind.data(), cpu_id);
25881ad6265SDimitry Andric 
259349cc55cSDimitry Andric   TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(),
260*bdd1243dSDimitry Andric                                     /*tid=*/std::nullopt, cpu_id};
261fe6060f1SDimitry Andric   return m_live_process->TraceGetBinaryData(request);
262fe6060f1SDimitry Andric }
263fe6060f1SDimitry Andric 
26481ad6265SDimitry Andric Expected<std::vector<uint8_t>>
GetLiveProcessBinaryData(llvm::StringRef kind)265fe6060f1SDimitry Andric Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
266*bdd1243dSDimitry Andric   std::optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind);
267fe6060f1SDimitry Andric   if (!size)
268fe6060f1SDimitry Andric     return createStringError(
269fe6060f1SDimitry Andric         inconvertibleErrorCode(),
270fe6060f1SDimitry Andric         "Tracing data \"%s\" is not available for the process.", kind.data());
271fe6060f1SDimitry Andric 
27281ad6265SDimitry Andric   TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(),
273*bdd1243dSDimitry Andric                                     /*tid=*/std::nullopt,
274*bdd1243dSDimitry Andric                                     /*cpu_id*/ std::nullopt};
27581ad6265SDimitry Andric   return GetLiveTraceBinaryData(request, *size);
276fe6060f1SDimitry Andric }
277fe6060f1SDimitry Andric 
GetUpdatedStorage()27881ad6265SDimitry Andric Trace::Storage &Trace::GetUpdatedStorage() {
27981ad6265SDimitry Andric   RefreshLiveProcessState();
28081ad6265SDimitry Andric   return m_storage;
28181ad6265SDimitry Andric }
28281ad6265SDimitry Andric 
RefreshLiveProcessState()28381ad6265SDimitry Andric const char *Trace::RefreshLiveProcessState() {
284fe6060f1SDimitry Andric   if (!m_live_process)
28581ad6265SDimitry Andric     return nullptr;
286e8d8bef9SDimitry Andric 
287fe6060f1SDimitry Andric   uint32_t new_stop_id = m_live_process->GetStopID();
288fe6060f1SDimitry Andric   if (new_stop_id == m_stop_id)
28981ad6265SDimitry Andric     return nullptr;
29081ad6265SDimitry Andric 
29181ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Target);
29281ad6265SDimitry Andric   LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked");
293e8d8bef9SDimitry Andric 
294fe6060f1SDimitry Andric   m_stop_id = new_stop_id;
29581ad6265SDimitry Andric   m_storage = Trace::Storage();
296e8d8bef9SDimitry Andric 
29781ad6265SDimitry Andric   auto do_refresh = [&]() -> Error {
298fe6060f1SDimitry Andric     Expected<std::string> json_string = GetLiveProcessState();
29981ad6265SDimitry Andric     if (!json_string)
30081ad6265SDimitry Andric       return json_string.takeError();
30181ad6265SDimitry Andric 
302fe6060f1SDimitry Andric     Expected<TraceGetStateResponse> live_process_state =
30381ad6265SDimitry Andric         json::parse<TraceGetStateResponse>(*json_string,
30481ad6265SDimitry Andric                                            "TraceGetStateResponse");
30581ad6265SDimitry Andric     if (!live_process_state)
30681ad6265SDimitry Andric       return live_process_state.takeError();
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric     if (live_process_state->warnings) {
30981ad6265SDimitry Andric       for (std::string &warning : *live_process_state->warnings)
31081ad6265SDimitry Andric         LLDB_LOG(log, "== Warning when fetching the trace state: {0}", warning);
311e8d8bef9SDimitry Andric     }
312e8d8bef9SDimitry Andric 
313fe6060f1SDimitry Andric     for (const TraceThreadState &thread_state :
31481ad6265SDimitry Andric          live_process_state->traced_threads) {
31581ad6265SDimitry Andric       for (const TraceBinaryData &item : thread_state.binary_data)
31681ad6265SDimitry Andric         m_storage.live_thread_data[thread_state.tid].insert(
31781ad6265SDimitry Andric             {ConstString(item.kind), item.size});
318e8d8bef9SDimitry Andric     }
319e8d8bef9SDimitry Andric 
32081ad6265SDimitry Andric     LLDB_LOG(log, "== Found {0} threads being traced",
32181ad6265SDimitry Andric              live_process_state->traced_threads.size());
322fe6060f1SDimitry Andric 
32381ad6265SDimitry Andric     if (live_process_state->cpus) {
32481ad6265SDimitry Andric       m_storage.cpus.emplace();
32581ad6265SDimitry Andric       for (const TraceCpuState &cpu_state : *live_process_state->cpus) {
32681ad6265SDimitry Andric         m_storage.cpus->push_back(cpu_state.id);
32781ad6265SDimitry Andric         for (const TraceBinaryData &item : cpu_state.binary_data)
32881ad6265SDimitry Andric           m_storage.live_cpu_data_sizes[cpu_state.id].insert(
32981ad6265SDimitry Andric               {ConstString(item.kind), item.size});
33081ad6265SDimitry Andric       }
33181ad6265SDimitry Andric       LLDB_LOG(log, "== Found {0} cpu cpus being traced",
33281ad6265SDimitry Andric                live_process_state->cpus->size());
33381ad6265SDimitry Andric     }
33481ad6265SDimitry Andric 
33581ad6265SDimitry Andric     for (const TraceBinaryData &item : live_process_state->process_binary_data)
33681ad6265SDimitry Andric       m_storage.live_process_data.insert({ConstString(item.kind), item.size});
33781ad6265SDimitry Andric 
33881ad6265SDimitry Andric     return DoRefreshLiveProcessState(std::move(*live_process_state),
33981ad6265SDimitry Andric                                      *json_string);
34081ad6265SDimitry Andric   };
34181ad6265SDimitry Andric 
34281ad6265SDimitry Andric   if (Error err = do_refresh()) {
34381ad6265SDimitry Andric     m_storage.live_refresh_error = toString(std::move(err));
34481ad6265SDimitry Andric     return m_storage.live_refresh_error->c_str();
34581ad6265SDimitry Andric   }
34681ad6265SDimitry Andric 
34781ad6265SDimitry Andric   return nullptr;
34881ad6265SDimitry Andric }
34981ad6265SDimitry Andric 
Trace(ArrayRef<ProcessSP> postmortem_processes,std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus)35081ad6265SDimitry Andric Trace::Trace(ArrayRef<ProcessSP> postmortem_processes,
351*bdd1243dSDimitry Andric              std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus) {
35281ad6265SDimitry Andric   for (ProcessSP process_sp : postmortem_processes)
35381ad6265SDimitry Andric     m_storage.postmortem_processes.push_back(process_sp.get());
35481ad6265SDimitry Andric   m_storage.cpus = postmortem_cpus;
35581ad6265SDimitry Andric }
35681ad6265SDimitry Andric 
GetLiveProcess()35781ad6265SDimitry Andric Process *Trace::GetLiveProcess() { return m_live_process; }
35881ad6265SDimitry Andric 
GetPostMortemProcesses()35981ad6265SDimitry Andric ArrayRef<Process *> Trace::GetPostMortemProcesses() {
36081ad6265SDimitry Andric   return m_storage.postmortem_processes;
36181ad6265SDimitry Andric }
36281ad6265SDimitry Andric 
GetAllProcesses()36381ad6265SDimitry Andric std::vector<Process *> Trace::GetAllProcesses() {
36481ad6265SDimitry Andric   if (Process *proc = GetLiveProcess())
36581ad6265SDimitry Andric     return {proc};
36681ad6265SDimitry Andric   return GetPostMortemProcesses();
367e8d8bef9SDimitry Andric }
368e8d8bef9SDimitry Andric 
GetStopID()369fe6060f1SDimitry Andric uint32_t Trace::GetStopID() {
370fe6060f1SDimitry Andric   RefreshLiveProcessState();
371fe6060f1SDimitry Andric   return m_stop_id;
372e8d8bef9SDimitry Andric }
37381ad6265SDimitry Andric 
37481ad6265SDimitry Andric llvm::Expected<FileSpec>
GetPostMortemThreadDataFile(lldb::tid_t tid,llvm::StringRef kind)37581ad6265SDimitry Andric Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) {
37681ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
377*bdd1243dSDimitry Andric   if (std::optional<FileSpec> file =
37881ad6265SDimitry Andric           Lookup(storage.postmortem_thread_data, tid, ConstString(kind)))
37981ad6265SDimitry Andric     return *file;
38081ad6265SDimitry Andric   else
38181ad6265SDimitry Andric     return createStringError(
38281ad6265SDimitry Andric         inconvertibleErrorCode(),
38381ad6265SDimitry Andric         formatv("The thread with tid={0} doesn't have the tracing data {1}",
38481ad6265SDimitry Andric                 tid, kind));
38581ad6265SDimitry Andric }
38681ad6265SDimitry Andric 
GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,llvm::StringRef kind)38781ad6265SDimitry Andric llvm::Expected<FileSpec> Trace::GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,
38881ad6265SDimitry Andric                                                          llvm::StringRef kind) {
38981ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
390*bdd1243dSDimitry Andric   if (std::optional<FileSpec> file =
39181ad6265SDimitry Andric           Lookup(storage.postmortem_cpu_data, cpu_id, ConstString(kind)))
39281ad6265SDimitry Andric     return *file;
39381ad6265SDimitry Andric   else
39481ad6265SDimitry Andric     return createStringError(
39581ad6265SDimitry Andric         inconvertibleErrorCode(),
39681ad6265SDimitry Andric         formatv("The cpu with id={0} doesn't have the tracing data {1}", cpu_id,
39781ad6265SDimitry Andric                 kind));
39881ad6265SDimitry Andric }
39981ad6265SDimitry Andric 
SetPostMortemThreadDataFile(lldb::tid_t tid,llvm::StringRef kind,FileSpec file_spec)40081ad6265SDimitry Andric void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind,
40181ad6265SDimitry Andric                                         FileSpec file_spec) {
40281ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
40381ad6265SDimitry Andric   storage.postmortem_thread_data[tid].insert({ConstString(kind), file_spec});
40481ad6265SDimitry Andric }
40581ad6265SDimitry Andric 
SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,llvm::StringRef kind,FileSpec file_spec)40681ad6265SDimitry Andric void Trace::SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,
40781ad6265SDimitry Andric                                      llvm::StringRef kind, FileSpec file_spec) {
40881ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
40981ad6265SDimitry Andric   storage.postmortem_cpu_data[cpu_id].insert({ConstString(kind), file_spec});
41081ad6265SDimitry Andric }
41181ad6265SDimitry Andric 
41281ad6265SDimitry Andric llvm::Error
OnLiveThreadBinaryDataRead(lldb::tid_t tid,llvm::StringRef kind,OnBinaryDataReadCallback callback)41381ad6265SDimitry Andric Trace::OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
41481ad6265SDimitry Andric                                   OnBinaryDataReadCallback callback) {
41581ad6265SDimitry Andric   Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind);
41681ad6265SDimitry Andric   if (!data)
41781ad6265SDimitry Andric     return data.takeError();
41881ad6265SDimitry Andric   return callback(*data);
41981ad6265SDimitry Andric }
42081ad6265SDimitry Andric 
OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu_id,llvm::StringRef kind,OnBinaryDataReadCallback callback)42181ad6265SDimitry Andric llvm::Error Trace::OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
42281ad6265SDimitry Andric                                            llvm::StringRef kind,
42381ad6265SDimitry Andric                                            OnBinaryDataReadCallback callback) {
42481ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
42581ad6265SDimitry Andric   if (std::vector<uint8_t> *cpu_data =
42681ad6265SDimitry Andric           LookupAsPtr(storage.live_cpu_data, cpu_id, ConstString(kind)))
42781ad6265SDimitry Andric     return callback(*cpu_data);
42881ad6265SDimitry Andric 
42981ad6265SDimitry Andric   Expected<std::vector<uint8_t>> data = GetLiveCpuBinaryData(cpu_id, kind);
43081ad6265SDimitry Andric   if (!data)
43181ad6265SDimitry Andric     return data.takeError();
43281ad6265SDimitry Andric   auto it = storage.live_cpu_data[cpu_id].insert(
43381ad6265SDimitry Andric       {ConstString(kind), std::move(*data)});
43481ad6265SDimitry Andric   return callback(it.first->second);
43581ad6265SDimitry Andric }
43681ad6265SDimitry Andric 
OnDataFileRead(FileSpec file,OnBinaryDataReadCallback callback)43781ad6265SDimitry Andric llvm::Error Trace::OnDataFileRead(FileSpec file,
43881ad6265SDimitry Andric                                   OnBinaryDataReadCallback callback) {
43981ad6265SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
44081ad6265SDimitry Andric       MemoryBuffer::getFile(file.GetPath());
44181ad6265SDimitry Andric   if (std::error_code err = trace_or_error.getError())
44281ad6265SDimitry Andric     return createStringError(
44381ad6265SDimitry Andric         inconvertibleErrorCode(), "Failed fetching trace-related file %s. %s",
444*bdd1243dSDimitry Andric         file.GetPath().c_str(), toString(errorCodeToError(err)).c_str());
44581ad6265SDimitry Andric 
44681ad6265SDimitry Andric   MemoryBuffer &data = **trace_or_error;
44781ad6265SDimitry Andric   ArrayRef<uint8_t> array_ref(
44881ad6265SDimitry Andric       reinterpret_cast<const uint8_t *>(data.getBufferStart()),
44981ad6265SDimitry Andric       data.getBufferSize());
45081ad6265SDimitry Andric   return callback(array_ref);
45181ad6265SDimitry Andric }
45281ad6265SDimitry Andric 
45381ad6265SDimitry Andric llvm::Error
OnPostMortemThreadBinaryDataRead(lldb::tid_t tid,llvm::StringRef kind,OnBinaryDataReadCallback callback)45481ad6265SDimitry Andric Trace::OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
45581ad6265SDimitry Andric                                         OnBinaryDataReadCallback callback) {
45681ad6265SDimitry Andric   if (Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind))
45781ad6265SDimitry Andric     return OnDataFileRead(*file, callback);
45881ad6265SDimitry Andric   else
45981ad6265SDimitry Andric     return file.takeError();
46081ad6265SDimitry Andric }
46181ad6265SDimitry Andric 
46281ad6265SDimitry Andric llvm::Error
OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id,llvm::StringRef kind,OnBinaryDataReadCallback callback)46381ad6265SDimitry Andric Trace::OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
46481ad6265SDimitry Andric                                      llvm::StringRef kind,
46581ad6265SDimitry Andric                                      OnBinaryDataReadCallback callback) {
46681ad6265SDimitry Andric   if (Expected<FileSpec> file = GetPostMortemCpuDataFile(cpu_id, kind))
46781ad6265SDimitry Andric     return OnDataFileRead(*file, callback);
46881ad6265SDimitry Andric   else
46981ad6265SDimitry Andric     return file.takeError();
47081ad6265SDimitry Andric }
47181ad6265SDimitry Andric 
OnThreadBinaryDataRead(lldb::tid_t tid,llvm::StringRef kind,OnBinaryDataReadCallback callback)47281ad6265SDimitry Andric llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
47381ad6265SDimitry Andric                                           OnBinaryDataReadCallback callback) {
47481ad6265SDimitry Andric   if (m_live_process)
47581ad6265SDimitry Andric     return OnLiveThreadBinaryDataRead(tid, kind, callback);
47681ad6265SDimitry Andric   else
47781ad6265SDimitry Andric     return OnPostMortemThreadBinaryDataRead(tid, kind, callback);
47881ad6265SDimitry Andric }
47981ad6265SDimitry Andric 
48081ad6265SDimitry Andric llvm::Error
OnAllCpusBinaryDataRead(llvm::StringRef kind,OnCpusBinaryDataReadCallback callback)48181ad6265SDimitry Andric Trace::OnAllCpusBinaryDataRead(llvm::StringRef kind,
48281ad6265SDimitry Andric                                OnCpusBinaryDataReadCallback callback) {
48381ad6265SDimitry Andric   DenseMap<cpu_id_t, ArrayRef<uint8_t>> buffers;
48481ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
48581ad6265SDimitry Andric   if (!storage.cpus)
48681ad6265SDimitry Andric     return Error::success();
48781ad6265SDimitry Andric 
48881ad6265SDimitry Andric   std::function<Error(std::vector<cpu_id_t>::iterator)> process_cpu =
48981ad6265SDimitry Andric       [&](std::vector<cpu_id_t>::iterator cpu_id) -> Error {
49081ad6265SDimitry Andric     if (cpu_id == storage.cpus->end())
49181ad6265SDimitry Andric       return callback(buffers);
49281ad6265SDimitry Andric 
49381ad6265SDimitry Andric     return OnCpuBinaryDataRead(*cpu_id, kind,
49481ad6265SDimitry Andric                                [&](ArrayRef<uint8_t> data) -> Error {
49581ad6265SDimitry Andric                                  buffers.try_emplace(*cpu_id, data);
49681ad6265SDimitry Andric                                  auto next_id = cpu_id;
49781ad6265SDimitry Andric                                  next_id++;
49881ad6265SDimitry Andric                                  return process_cpu(next_id);
49981ad6265SDimitry Andric                                });
50081ad6265SDimitry Andric   };
50181ad6265SDimitry Andric   return process_cpu(storage.cpus->begin());
50281ad6265SDimitry Andric }
50381ad6265SDimitry Andric 
OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id,llvm::StringRef kind,OnBinaryDataReadCallback callback)50481ad6265SDimitry Andric llvm::Error Trace::OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
50581ad6265SDimitry Andric                                        llvm::StringRef kind,
50681ad6265SDimitry Andric                                        OnBinaryDataReadCallback callback) {
50781ad6265SDimitry Andric   if (m_live_process)
50881ad6265SDimitry Andric     return OnLiveCpuBinaryDataRead(cpu_id, kind, callback);
50981ad6265SDimitry Andric   else
51081ad6265SDimitry Andric     return OnPostMortemCpuBinaryDataRead(cpu_id, kind, callback);
51181ad6265SDimitry Andric }
51281ad6265SDimitry Andric 
GetTracedCpus()51381ad6265SDimitry Andric ArrayRef<lldb::cpu_id_t> Trace::GetTracedCpus() {
51481ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
51581ad6265SDimitry Andric   if (storage.cpus)
51681ad6265SDimitry Andric     return *storage.cpus;
51781ad6265SDimitry Andric   return {};
51881ad6265SDimitry Andric }
51981ad6265SDimitry Andric 
GetTracedProcesses()52081ad6265SDimitry Andric std::vector<Process *> Trace::GetTracedProcesses() {
52181ad6265SDimitry Andric   std::vector<Process *> processes;
52281ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
52381ad6265SDimitry Andric 
52481ad6265SDimitry Andric   for (Process *proc : storage.postmortem_processes)
52581ad6265SDimitry Andric     processes.push_back(proc);
52681ad6265SDimitry Andric 
52781ad6265SDimitry Andric   if (m_live_process)
52881ad6265SDimitry Andric     processes.push_back(m_live_process);
52981ad6265SDimitry Andric   return processes;
53081ad6265SDimitry Andric }
531