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