xref: /openbsd-src/gnu/llvm/lldb/source/Target/Trace.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1be691f3bSpatrick //===-- Trace.cpp ---------------------------------------------------------===//
2be691f3bSpatrick //
3be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information.
5be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6be691f3bSpatrick //
7be691f3bSpatrick //===----------------------------------------------------------------------===//
8be691f3bSpatrick 
9be691f3bSpatrick #include "lldb/Target/Trace.h"
10be691f3bSpatrick 
11be691f3bSpatrick #include "llvm/Support/Format.h"
12be691f3bSpatrick 
13be691f3bSpatrick #include "lldb/Core/Module.h"
14be691f3bSpatrick #include "lldb/Core/PluginManager.h"
15be691f3bSpatrick #include "lldb/Symbol/Function.h"
16be691f3bSpatrick #include "lldb/Target/ExecutionContext.h"
17be691f3bSpatrick #include "lldb/Target/Process.h"
18be691f3bSpatrick #include "lldb/Target/SectionLoadList.h"
19be691f3bSpatrick #include "lldb/Target/Thread.h"
20*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
21be691f3bSpatrick #include "lldb/Utility/Stream.h"
22*f6aab3d8Srobert #include <optional>
23be691f3bSpatrick 
24be691f3bSpatrick using namespace lldb;
25be691f3bSpatrick using namespace lldb_private;
26be691f3bSpatrick using namespace llvm;
27be691f3bSpatrick 
28*f6aab3d8Srobert // Helper structs used to extract the type of a JSON trace bundle description
29*f6aab3d8Srobert // object without having to parse the entire object.
30be691f3bSpatrick 
31*f6aab3d8Srobert struct JSONSimpleTraceBundleDescription {
32be691f3bSpatrick   std::string type;
33be691f3bSpatrick };
34be691f3bSpatrick 
35be691f3bSpatrick namespace llvm {
36be691f3bSpatrick namespace json {
37be691f3bSpatrick 
fromJSON(const Value & value,JSONSimpleTraceBundleDescription & bundle,Path path)38*f6aab3d8Srobert bool fromJSON(const Value &value, JSONSimpleTraceBundleDescription &bundle,
39be691f3bSpatrick               Path path) {
40be691f3bSpatrick   json::ObjectMapper o(value, path);
41*f6aab3d8Srobert   return o && o.map("type", bundle.type);
42be691f3bSpatrick }
43be691f3bSpatrick 
44be691f3bSpatrick } // namespace json
45be691f3bSpatrick } // namespace llvm
46be691f3bSpatrick 
47*f6aab3d8Srobert /// Helper functions for fetching data in maps and returning Optionals or
48*f6aab3d8Srobert /// pointers instead of iterators for simplicity. It's worth mentioning that the
49*f6aab3d8Srobert /// Optionals version can't return the inner data by reference because of
50*f6aab3d8Srobert /// limitations in move constructors.
51*f6aab3d8Srobert /// \{
52*f6aab3d8Srobert template <typename K, typename V>
Lookup(DenseMap<K,V> & map,K k)53*f6aab3d8Srobert static std::optional<V> Lookup(DenseMap<K, V> &map, K k) {
54*f6aab3d8Srobert   auto it = map.find(k);
55*f6aab3d8Srobert   if (it == map.end())
56*f6aab3d8Srobert     return std::nullopt;
57*f6aab3d8Srobert   return it->second;
58*f6aab3d8Srobert }
59*f6aab3d8Srobert 
60*f6aab3d8Srobert template <typename K, typename V>
LookupAsPtr(DenseMap<K,V> & map,K k)61*f6aab3d8Srobert static V *LookupAsPtr(DenseMap<K, V> &map, K k) {
62*f6aab3d8Srobert   auto it = map.find(k);
63*f6aab3d8Srobert   if (it == map.end())
64*f6aab3d8Srobert     return nullptr;
65*f6aab3d8Srobert   return &it->second;
66*f6aab3d8Srobert }
67*f6aab3d8Srobert 
68*f6aab3d8Srobert /// Similar to the methods above but it looks for an item in a map of maps.
69*f6aab3d8Srobert template <typename K1, typename K2, typename V>
Lookup(DenseMap<K1,DenseMap<K2,V>> & map,K1 k1,K2 k2)70*f6aab3d8Srobert static std::optional<V> Lookup(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1,
71*f6aab3d8Srobert                                K2 k2) {
72*f6aab3d8Srobert   auto it = map.find(k1);
73*f6aab3d8Srobert   if (it == map.end())
74*f6aab3d8Srobert     return std::nullopt;
75*f6aab3d8Srobert   return Lookup(it->second, k2);
76*f6aab3d8Srobert }
77*f6aab3d8Srobert 
78*f6aab3d8Srobert /// Similar to the methods above but it looks for an item in a map of maps.
79*f6aab3d8Srobert template <typename K1, typename K2, typename V>
LookupAsPtr(DenseMap<K1,DenseMap<K2,V>> & map,K1 k1,K2 k2)80*f6aab3d8Srobert static V *LookupAsPtr(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) {
81*f6aab3d8Srobert   auto it = map.find(k1);
82*f6aab3d8Srobert   if (it == map.end())
83*f6aab3d8Srobert     return nullptr;
84*f6aab3d8Srobert   return LookupAsPtr(it->second, k2);
85*f6aab3d8Srobert }
86*f6aab3d8Srobert /// \}
87*f6aab3d8Srobert 
createInvalidPlugInError(StringRef plugin_name)88be691f3bSpatrick static Error createInvalidPlugInError(StringRef plugin_name) {
89be691f3bSpatrick   return createStringError(
90be691f3bSpatrick       std::errc::invalid_argument,
91be691f3bSpatrick       "no trace plug-in matches the specified type: \"%s\"",
92be691f3bSpatrick       plugin_name.data());
93be691f3bSpatrick }
94be691f3bSpatrick 
95be691f3bSpatrick Expected<lldb::TraceSP>
LoadPostMortemTraceFromFile(Debugger & debugger,const FileSpec & trace_description_file)96*f6aab3d8Srobert Trace::LoadPostMortemTraceFromFile(Debugger &debugger,
97*f6aab3d8Srobert                                    const FileSpec &trace_description_file) {
98be691f3bSpatrick 
99*f6aab3d8Srobert   auto buffer_or_error =
100*f6aab3d8Srobert       MemoryBuffer::getFile(trace_description_file.GetPath());
101*f6aab3d8Srobert   if (!buffer_or_error) {
102*f6aab3d8Srobert     return createStringError(std::errc::invalid_argument,
103*f6aab3d8Srobert                              "could not open input file: %s - %s.",
104*f6aab3d8Srobert                              trace_description_file.GetPath().c_str(),
105*f6aab3d8Srobert                              buffer_or_error.getError().message().c_str());
106be691f3bSpatrick   }
107be691f3bSpatrick 
108*f6aab3d8Srobert   Expected<json::Value> session_file =
109*f6aab3d8Srobert       json::parse(buffer_or_error.get()->getBuffer().str());
110*f6aab3d8Srobert   if (!session_file) {
111*f6aab3d8Srobert     return session_file.takeError();
112*f6aab3d8Srobert   }
113*f6aab3d8Srobert 
114*f6aab3d8Srobert   return Trace::FindPluginForPostMortemProcess(
115*f6aab3d8Srobert       debugger, *session_file,
116*f6aab3d8Srobert       trace_description_file.GetDirectory().AsCString());
117*f6aab3d8Srobert }
118*f6aab3d8Srobert 
FindPluginForPostMortemProcess(Debugger & debugger,const json::Value & trace_bundle_description,StringRef bundle_dir)119*f6aab3d8Srobert Expected<lldb::TraceSP> Trace::FindPluginForPostMortemProcess(
120*f6aab3d8Srobert     Debugger &debugger, const json::Value &trace_bundle_description,
121*f6aab3d8Srobert     StringRef bundle_dir) {
122*f6aab3d8Srobert   JSONSimpleTraceBundleDescription json_bundle;
123*f6aab3d8Srobert   json::Path::Root root("traceBundle");
124*f6aab3d8Srobert   if (!json::fromJSON(trace_bundle_description, json_bundle, root))
125*f6aab3d8Srobert     return root.getError();
126*f6aab3d8Srobert 
127*f6aab3d8Srobert   if (auto create_callback =
128*f6aab3d8Srobert           PluginManager::GetTraceCreateCallback(json_bundle.type))
129*f6aab3d8Srobert     return create_callback(trace_bundle_description, bundle_dir, debugger);
130*f6aab3d8Srobert 
131*f6aab3d8Srobert   return createInvalidPlugInError(json_bundle.type);
132*f6aab3d8Srobert }
133*f6aab3d8Srobert 
FindPluginForLiveProcess(llvm::StringRef name,Process & process)134*f6aab3d8Srobert Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name,
135*f6aab3d8Srobert                                                         Process &process) {
136be691f3bSpatrick   if (!process.IsLiveDebugSession())
137be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
138be691f3bSpatrick                              "Can't trace non-live processes");
139be691f3bSpatrick 
140be691f3bSpatrick   if (auto create_callback =
141be691f3bSpatrick           PluginManager::GetTraceCreateCallbackForLiveProcess(name))
142be691f3bSpatrick     return create_callback(process);
143be691f3bSpatrick 
144*f6aab3d8Srobert   return createInvalidPlugInError(name);
145be691f3bSpatrick }
146be691f3bSpatrick 
FindPluginSchema(StringRef name)147be691f3bSpatrick Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
148*f6aab3d8Srobert   StringRef schema = PluginManager::GetTraceSchema(name);
149be691f3bSpatrick   if (!schema.empty())
150be691f3bSpatrick     return schema;
151be691f3bSpatrick 
152be691f3bSpatrick   return createInvalidPlugInError(name);
153be691f3bSpatrick }
154be691f3bSpatrick 
Start(const llvm::json::Value & request)155be691f3bSpatrick Error Trace::Start(const llvm::json::Value &request) {
156be691f3bSpatrick   if (!m_live_process)
157*f6aab3d8Srobert     return createStringError(
158*f6aab3d8Srobert         inconvertibleErrorCode(),
159*f6aab3d8Srobert         "Attempted to start tracing without a live process.");
160be691f3bSpatrick   return m_live_process->TraceStart(request);
161be691f3bSpatrick }
162be691f3bSpatrick 
Stop()163be691f3bSpatrick Error Trace::Stop() {
164be691f3bSpatrick   if (!m_live_process)
165*f6aab3d8Srobert     return createStringError(
166*f6aab3d8Srobert         inconvertibleErrorCode(),
167*f6aab3d8Srobert         "Attempted to stop tracing without a live process.");
168*f6aab3d8Srobert   return m_live_process->TraceStop(TraceStopRequest(GetPluginName()));
169be691f3bSpatrick }
170be691f3bSpatrick 
Stop(llvm::ArrayRef<lldb::tid_t> tids)171be691f3bSpatrick Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) {
172be691f3bSpatrick   if (!m_live_process)
173*f6aab3d8Srobert     return createStringError(
174*f6aab3d8Srobert         inconvertibleErrorCode(),
175*f6aab3d8Srobert         "Attempted to stop tracing without a live process.");
176*f6aab3d8Srobert   return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids));
177be691f3bSpatrick }
178be691f3bSpatrick 
GetLiveProcessState()179be691f3bSpatrick Expected<std::string> Trace::GetLiveProcessState() {
180be691f3bSpatrick   if (!m_live_process)
181*f6aab3d8Srobert     return createStringError(
182*f6aab3d8Srobert         inconvertibleErrorCode(),
183*f6aab3d8Srobert         "Attempted to fetch live trace information without a live process.");
184*f6aab3d8Srobert   return m_live_process->TraceGetState(GetPluginName());
185be691f3bSpatrick }
186be691f3bSpatrick 
187*f6aab3d8Srobert std::optional<uint64_t>
GetLiveThreadBinaryDataSize(lldb::tid_t tid,llvm::StringRef kind)188*f6aab3d8Srobert Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, llvm::StringRef kind) {
189*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
190*f6aab3d8Srobert   return Lookup(storage.live_thread_data, tid, ConstString(kind));
191*f6aab3d8Srobert }
192*f6aab3d8Srobert 
GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id,llvm::StringRef kind)193*f6aab3d8Srobert std::optional<uint64_t> Trace::GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id,
194be691f3bSpatrick                                                         llvm::StringRef kind) {
195*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
196*f6aab3d8Srobert   return Lookup(storage.live_cpu_data_sizes, cpu_id, ConstString(kind));
197be691f3bSpatrick }
198be691f3bSpatrick 
199*f6aab3d8Srobert std::optional<uint64_t>
GetLiveProcessBinaryDataSize(llvm::StringRef kind)200*f6aab3d8Srobert Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
201*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
202*f6aab3d8Srobert   return Lookup(storage.live_process_data, ConstString(kind));
203be691f3bSpatrick }
204be691f3bSpatrick 
205*f6aab3d8Srobert Expected<std::vector<uint8_t>>
GetLiveTraceBinaryData(const TraceGetBinaryDataRequest & request,uint64_t expected_size)206*f6aab3d8Srobert Trace::GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request,
207*f6aab3d8Srobert                               uint64_t expected_size) {
208be691f3bSpatrick   if (!m_live_process)
209*f6aab3d8Srobert     return createStringError(
210*f6aab3d8Srobert         inconvertibleErrorCode(),
211*f6aab3d8Srobert         formatv("Attempted to fetch live trace data without a live process. "
212*f6aab3d8Srobert                 "Data kind = {0}, tid = {1}, cpu id = {2}.",
213*f6aab3d8Srobert                 request.kind, request.tid, request.cpu_id));
214*f6aab3d8Srobert 
215*f6aab3d8Srobert   Expected<std::vector<uint8_t>> data =
216*f6aab3d8Srobert       m_live_process->TraceGetBinaryData(request);
217*f6aab3d8Srobert 
218*f6aab3d8Srobert   if (!data)
219*f6aab3d8Srobert     return data.takeError();
220*f6aab3d8Srobert 
221*f6aab3d8Srobert   if (data->size() != expected_size)
222*f6aab3d8Srobert     return createStringError(
223*f6aab3d8Srobert         inconvertibleErrorCode(),
224*f6aab3d8Srobert         formatv("Got incomplete live trace data. Data kind = {0}, expected "
225*f6aab3d8Srobert                 "size = {1}, actual size = {2}, tid = {3}, cpu id = {4}",
226*f6aab3d8Srobert                 request.kind, expected_size, data->size(), request.tid,
227*f6aab3d8Srobert                 request.cpu_id));
228*f6aab3d8Srobert 
229*f6aab3d8Srobert   return data;
230*f6aab3d8Srobert }
231*f6aab3d8Srobert 
232*f6aab3d8Srobert Expected<std::vector<uint8_t>>
GetLiveThreadBinaryData(lldb::tid_t tid,llvm::StringRef kind)233*f6aab3d8Srobert Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
234*f6aab3d8Srobert   std::optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind);
235be691f3bSpatrick   if (!size)
236be691f3bSpatrick     return createStringError(
237be691f3bSpatrick         inconvertibleErrorCode(),
238be691f3bSpatrick         "Tracing data \"%s\" is not available for thread %" PRIu64 ".",
239be691f3bSpatrick         kind.data(), tid);
240be691f3bSpatrick 
241*f6aab3d8Srobert   TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), tid,
242*f6aab3d8Srobert                                     /*cpu_id=*/std::nullopt};
243*f6aab3d8Srobert   return GetLiveTraceBinaryData(request, *size);
244*f6aab3d8Srobert }
245*f6aab3d8Srobert 
246*f6aab3d8Srobert Expected<std::vector<uint8_t>>
GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id,llvm::StringRef kind)247*f6aab3d8Srobert Trace::GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind) {
248*f6aab3d8Srobert   if (!m_live_process)
249*f6aab3d8Srobert     return createStringError(
250*f6aab3d8Srobert         inconvertibleErrorCode(),
251*f6aab3d8Srobert         "Attempted to fetch live cpu data without a live process.");
252*f6aab3d8Srobert   std::optional<uint64_t> size = GetLiveCpuBinaryDataSize(cpu_id, kind);
253*f6aab3d8Srobert   if (!size)
254*f6aab3d8Srobert     return createStringError(
255*f6aab3d8Srobert         inconvertibleErrorCode(),
256*f6aab3d8Srobert         "Tracing data \"%s\" is not available for cpu_id %" PRIu64 ".",
257*f6aab3d8Srobert         kind.data(), cpu_id);
258*f6aab3d8Srobert 
259*f6aab3d8Srobert   TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(),
260*f6aab3d8Srobert                                     /*tid=*/std::nullopt, cpu_id};
261be691f3bSpatrick   return m_live_process->TraceGetBinaryData(request);
262be691f3bSpatrick }
263be691f3bSpatrick 
264*f6aab3d8Srobert Expected<std::vector<uint8_t>>
GetLiveProcessBinaryData(llvm::StringRef kind)265be691f3bSpatrick Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
266*f6aab3d8Srobert   std::optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind);
267be691f3bSpatrick   if (!size)
268be691f3bSpatrick     return createStringError(
269be691f3bSpatrick         inconvertibleErrorCode(),
270be691f3bSpatrick         "Tracing data \"%s\" is not available for the process.", kind.data());
271be691f3bSpatrick 
272*f6aab3d8Srobert   TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(),
273*f6aab3d8Srobert                                     /*tid=*/std::nullopt,
274*f6aab3d8Srobert                                     /*cpu_id*/ std::nullopt};
275*f6aab3d8Srobert   return GetLiveTraceBinaryData(request, *size);
276be691f3bSpatrick }
277be691f3bSpatrick 
GetUpdatedStorage()278*f6aab3d8Srobert Trace::Storage &Trace::GetUpdatedStorage() {
279*f6aab3d8Srobert   RefreshLiveProcessState();
280*f6aab3d8Srobert   return m_storage;
281*f6aab3d8Srobert }
282*f6aab3d8Srobert 
RefreshLiveProcessState()283*f6aab3d8Srobert const char *Trace::RefreshLiveProcessState() {
284be691f3bSpatrick   if (!m_live_process)
285*f6aab3d8Srobert     return nullptr;
286be691f3bSpatrick 
287be691f3bSpatrick   uint32_t new_stop_id = m_live_process->GetStopID();
288be691f3bSpatrick   if (new_stop_id == m_stop_id)
289*f6aab3d8Srobert     return nullptr;
290*f6aab3d8Srobert 
291*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Target);
292*f6aab3d8Srobert   LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked");
293be691f3bSpatrick 
294be691f3bSpatrick   m_stop_id = new_stop_id;
295*f6aab3d8Srobert   m_storage = Trace::Storage();
296be691f3bSpatrick 
297*f6aab3d8Srobert   auto do_refresh = [&]() -> Error {
298be691f3bSpatrick     Expected<std::string> json_string = GetLiveProcessState();
299*f6aab3d8Srobert     if (!json_string)
300*f6aab3d8Srobert       return json_string.takeError();
301*f6aab3d8Srobert 
302be691f3bSpatrick     Expected<TraceGetStateResponse> live_process_state =
303*f6aab3d8Srobert         json::parse<TraceGetStateResponse>(*json_string,
304*f6aab3d8Srobert                                            "TraceGetStateResponse");
305*f6aab3d8Srobert     if (!live_process_state)
306*f6aab3d8Srobert       return live_process_state.takeError();
307*f6aab3d8Srobert 
308*f6aab3d8Srobert     if (live_process_state->warnings) {
309*f6aab3d8Srobert       for (std::string &warning : *live_process_state->warnings)
310*f6aab3d8Srobert         LLDB_LOG(log, "== Warning when fetching the trace state: {0}", warning);
311be691f3bSpatrick     }
312be691f3bSpatrick 
313be691f3bSpatrick     for (const TraceThreadState &thread_state :
314*f6aab3d8Srobert          live_process_state->traced_threads) {
315*f6aab3d8Srobert       for (const TraceBinaryData &item : thread_state.binary_data)
316*f6aab3d8Srobert         m_storage.live_thread_data[thread_state.tid].insert(
317*f6aab3d8Srobert             {ConstString(item.kind), item.size});
318be691f3bSpatrick     }
319be691f3bSpatrick 
320*f6aab3d8Srobert     LLDB_LOG(log, "== Found {0} threads being traced",
321*f6aab3d8Srobert              live_process_state->traced_threads.size());
322be691f3bSpatrick 
323*f6aab3d8Srobert     if (live_process_state->cpus) {
324*f6aab3d8Srobert       m_storage.cpus.emplace();
325*f6aab3d8Srobert       for (const TraceCpuState &cpu_state : *live_process_state->cpus) {
326*f6aab3d8Srobert         m_storage.cpus->push_back(cpu_state.id);
327*f6aab3d8Srobert         for (const TraceBinaryData &item : cpu_state.binary_data)
328*f6aab3d8Srobert           m_storage.live_cpu_data_sizes[cpu_state.id].insert(
329*f6aab3d8Srobert               {ConstString(item.kind), item.size});
330*f6aab3d8Srobert       }
331*f6aab3d8Srobert       LLDB_LOG(log, "== Found {0} cpu cpus being traced",
332*f6aab3d8Srobert                live_process_state->cpus->size());
333*f6aab3d8Srobert     }
334*f6aab3d8Srobert 
335*f6aab3d8Srobert     for (const TraceBinaryData &item : live_process_state->process_binary_data)
336*f6aab3d8Srobert       m_storage.live_process_data.insert({ConstString(item.kind), item.size});
337*f6aab3d8Srobert 
338*f6aab3d8Srobert     return DoRefreshLiveProcessState(std::move(*live_process_state),
339*f6aab3d8Srobert                                      *json_string);
340*f6aab3d8Srobert   };
341*f6aab3d8Srobert 
342*f6aab3d8Srobert   if (Error err = do_refresh()) {
343*f6aab3d8Srobert     m_storage.live_refresh_error = toString(std::move(err));
344*f6aab3d8Srobert     return m_storage.live_refresh_error->c_str();
345*f6aab3d8Srobert   }
346*f6aab3d8Srobert 
347*f6aab3d8Srobert   return nullptr;
348*f6aab3d8Srobert }
349*f6aab3d8Srobert 
Trace(ArrayRef<ProcessSP> postmortem_processes,std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus)350*f6aab3d8Srobert Trace::Trace(ArrayRef<ProcessSP> postmortem_processes,
351*f6aab3d8Srobert              std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus) {
352*f6aab3d8Srobert   for (ProcessSP process_sp : postmortem_processes)
353*f6aab3d8Srobert     m_storage.postmortem_processes.push_back(process_sp.get());
354*f6aab3d8Srobert   m_storage.cpus = postmortem_cpus;
355*f6aab3d8Srobert }
356*f6aab3d8Srobert 
GetLiveProcess()357*f6aab3d8Srobert Process *Trace::GetLiveProcess() { return m_live_process; }
358*f6aab3d8Srobert 
GetPostMortemProcesses()359*f6aab3d8Srobert ArrayRef<Process *> Trace::GetPostMortemProcesses() {
360*f6aab3d8Srobert   return m_storage.postmortem_processes;
361*f6aab3d8Srobert }
362*f6aab3d8Srobert 
GetAllProcesses()363*f6aab3d8Srobert std::vector<Process *> Trace::GetAllProcesses() {
364*f6aab3d8Srobert   if (Process *proc = GetLiveProcess())
365*f6aab3d8Srobert     return {proc};
366*f6aab3d8Srobert   return GetPostMortemProcesses();
367be691f3bSpatrick }
368be691f3bSpatrick 
GetStopID()369be691f3bSpatrick uint32_t Trace::GetStopID() {
370be691f3bSpatrick   RefreshLiveProcessState();
371be691f3bSpatrick   return m_stop_id;
372be691f3bSpatrick }
373*f6aab3d8Srobert 
374*f6aab3d8Srobert llvm::Expected<FileSpec>
GetPostMortemThreadDataFile(lldb::tid_t tid,llvm::StringRef kind)375*f6aab3d8Srobert Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) {
376*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
377*f6aab3d8Srobert   if (std::optional<FileSpec> file =
378*f6aab3d8Srobert           Lookup(storage.postmortem_thread_data, tid, ConstString(kind)))
379*f6aab3d8Srobert     return *file;
380*f6aab3d8Srobert   else
381*f6aab3d8Srobert     return createStringError(
382*f6aab3d8Srobert         inconvertibleErrorCode(),
383*f6aab3d8Srobert         formatv("The thread with tid={0} doesn't have the tracing data {1}",
384*f6aab3d8Srobert                 tid, kind));
385*f6aab3d8Srobert }
386*f6aab3d8Srobert 
GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,llvm::StringRef kind)387*f6aab3d8Srobert llvm::Expected<FileSpec> Trace::GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,
388*f6aab3d8Srobert                                                          llvm::StringRef kind) {
389*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
390*f6aab3d8Srobert   if (std::optional<FileSpec> file =
391*f6aab3d8Srobert           Lookup(storage.postmortem_cpu_data, cpu_id, ConstString(kind)))
392*f6aab3d8Srobert     return *file;
393*f6aab3d8Srobert   else
394*f6aab3d8Srobert     return createStringError(
395*f6aab3d8Srobert         inconvertibleErrorCode(),
396*f6aab3d8Srobert         formatv("The cpu with id={0} doesn't have the tracing data {1}", cpu_id,
397*f6aab3d8Srobert                 kind));
398*f6aab3d8Srobert }
399*f6aab3d8Srobert 
SetPostMortemThreadDataFile(lldb::tid_t tid,llvm::StringRef kind,FileSpec file_spec)400*f6aab3d8Srobert void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind,
401*f6aab3d8Srobert                                         FileSpec file_spec) {
402*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
403*f6aab3d8Srobert   storage.postmortem_thread_data[tid].insert({ConstString(kind), file_spec});
404*f6aab3d8Srobert }
405*f6aab3d8Srobert 
SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,llvm::StringRef kind,FileSpec file_spec)406*f6aab3d8Srobert void Trace::SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,
407*f6aab3d8Srobert                                      llvm::StringRef kind, FileSpec file_spec) {
408*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
409*f6aab3d8Srobert   storage.postmortem_cpu_data[cpu_id].insert({ConstString(kind), file_spec});
410*f6aab3d8Srobert }
411*f6aab3d8Srobert 
412*f6aab3d8Srobert llvm::Error
OnLiveThreadBinaryDataRead(lldb::tid_t tid,llvm::StringRef kind,OnBinaryDataReadCallback callback)413*f6aab3d8Srobert Trace::OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
414*f6aab3d8Srobert                                   OnBinaryDataReadCallback callback) {
415*f6aab3d8Srobert   Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind);
416*f6aab3d8Srobert   if (!data)
417*f6aab3d8Srobert     return data.takeError();
418*f6aab3d8Srobert   return callback(*data);
419*f6aab3d8Srobert }
420*f6aab3d8Srobert 
OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu_id,llvm::StringRef kind,OnBinaryDataReadCallback callback)421*f6aab3d8Srobert llvm::Error Trace::OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
422*f6aab3d8Srobert                                            llvm::StringRef kind,
423*f6aab3d8Srobert                                            OnBinaryDataReadCallback callback) {
424*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
425*f6aab3d8Srobert   if (std::vector<uint8_t> *cpu_data =
426*f6aab3d8Srobert           LookupAsPtr(storage.live_cpu_data, cpu_id, ConstString(kind)))
427*f6aab3d8Srobert     return callback(*cpu_data);
428*f6aab3d8Srobert 
429*f6aab3d8Srobert   Expected<std::vector<uint8_t>> data = GetLiveCpuBinaryData(cpu_id, kind);
430*f6aab3d8Srobert   if (!data)
431*f6aab3d8Srobert     return data.takeError();
432*f6aab3d8Srobert   auto it = storage.live_cpu_data[cpu_id].insert(
433*f6aab3d8Srobert       {ConstString(kind), std::move(*data)});
434*f6aab3d8Srobert   return callback(it.first->second);
435*f6aab3d8Srobert }
436*f6aab3d8Srobert 
OnDataFileRead(FileSpec file,OnBinaryDataReadCallback callback)437*f6aab3d8Srobert llvm::Error Trace::OnDataFileRead(FileSpec file,
438*f6aab3d8Srobert                                   OnBinaryDataReadCallback callback) {
439*f6aab3d8Srobert   ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
440*f6aab3d8Srobert       MemoryBuffer::getFile(file.GetPath());
441*f6aab3d8Srobert   if (std::error_code err = trace_or_error.getError())
442*f6aab3d8Srobert     return createStringError(
443*f6aab3d8Srobert         inconvertibleErrorCode(), "Failed fetching trace-related file %s. %s",
444*f6aab3d8Srobert         file.GetPath().c_str(), toString(errorCodeToError(err)).c_str());
445*f6aab3d8Srobert 
446*f6aab3d8Srobert   MemoryBuffer &data = **trace_or_error;
447*f6aab3d8Srobert   ArrayRef<uint8_t> array_ref(
448*f6aab3d8Srobert       reinterpret_cast<const uint8_t *>(data.getBufferStart()),
449*f6aab3d8Srobert       data.getBufferSize());
450*f6aab3d8Srobert   return callback(array_ref);
451*f6aab3d8Srobert }
452*f6aab3d8Srobert 
453*f6aab3d8Srobert llvm::Error
OnPostMortemThreadBinaryDataRead(lldb::tid_t tid,llvm::StringRef kind,OnBinaryDataReadCallback callback)454*f6aab3d8Srobert Trace::OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
455*f6aab3d8Srobert                                         OnBinaryDataReadCallback callback) {
456*f6aab3d8Srobert   if (Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind))
457*f6aab3d8Srobert     return OnDataFileRead(*file, callback);
458*f6aab3d8Srobert   else
459*f6aab3d8Srobert     return file.takeError();
460*f6aab3d8Srobert }
461*f6aab3d8Srobert 
462*f6aab3d8Srobert llvm::Error
OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id,llvm::StringRef kind,OnBinaryDataReadCallback callback)463*f6aab3d8Srobert Trace::OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
464*f6aab3d8Srobert                                      llvm::StringRef kind,
465*f6aab3d8Srobert                                      OnBinaryDataReadCallback callback) {
466*f6aab3d8Srobert   if (Expected<FileSpec> file = GetPostMortemCpuDataFile(cpu_id, kind))
467*f6aab3d8Srobert     return OnDataFileRead(*file, callback);
468*f6aab3d8Srobert   else
469*f6aab3d8Srobert     return file.takeError();
470*f6aab3d8Srobert }
471*f6aab3d8Srobert 
OnThreadBinaryDataRead(lldb::tid_t tid,llvm::StringRef kind,OnBinaryDataReadCallback callback)472*f6aab3d8Srobert llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
473*f6aab3d8Srobert                                           OnBinaryDataReadCallback callback) {
474*f6aab3d8Srobert   if (m_live_process)
475*f6aab3d8Srobert     return OnLiveThreadBinaryDataRead(tid, kind, callback);
476*f6aab3d8Srobert   else
477*f6aab3d8Srobert     return OnPostMortemThreadBinaryDataRead(tid, kind, callback);
478*f6aab3d8Srobert }
479*f6aab3d8Srobert 
480*f6aab3d8Srobert llvm::Error
OnAllCpusBinaryDataRead(llvm::StringRef kind,OnCpusBinaryDataReadCallback callback)481*f6aab3d8Srobert Trace::OnAllCpusBinaryDataRead(llvm::StringRef kind,
482*f6aab3d8Srobert                                OnCpusBinaryDataReadCallback callback) {
483*f6aab3d8Srobert   DenseMap<cpu_id_t, ArrayRef<uint8_t>> buffers;
484*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
485*f6aab3d8Srobert   if (!storage.cpus)
486*f6aab3d8Srobert     return Error::success();
487*f6aab3d8Srobert 
488*f6aab3d8Srobert   std::function<Error(std::vector<cpu_id_t>::iterator)> process_cpu =
489*f6aab3d8Srobert       [&](std::vector<cpu_id_t>::iterator cpu_id) -> Error {
490*f6aab3d8Srobert     if (cpu_id == storage.cpus->end())
491*f6aab3d8Srobert       return callback(buffers);
492*f6aab3d8Srobert 
493*f6aab3d8Srobert     return OnCpuBinaryDataRead(*cpu_id, kind,
494*f6aab3d8Srobert                                [&](ArrayRef<uint8_t> data) -> Error {
495*f6aab3d8Srobert                                  buffers.try_emplace(*cpu_id, data);
496*f6aab3d8Srobert                                  auto next_id = cpu_id;
497*f6aab3d8Srobert                                  next_id++;
498*f6aab3d8Srobert                                  return process_cpu(next_id);
499*f6aab3d8Srobert                                });
500*f6aab3d8Srobert   };
501*f6aab3d8Srobert   return process_cpu(storage.cpus->begin());
502*f6aab3d8Srobert }
503*f6aab3d8Srobert 
OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id,llvm::StringRef kind,OnBinaryDataReadCallback callback)504*f6aab3d8Srobert llvm::Error Trace::OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
505*f6aab3d8Srobert                                        llvm::StringRef kind,
506*f6aab3d8Srobert                                        OnBinaryDataReadCallback callback) {
507*f6aab3d8Srobert   if (m_live_process)
508*f6aab3d8Srobert     return OnLiveCpuBinaryDataRead(cpu_id, kind, callback);
509*f6aab3d8Srobert   else
510*f6aab3d8Srobert     return OnPostMortemCpuBinaryDataRead(cpu_id, kind, callback);
511*f6aab3d8Srobert }
512*f6aab3d8Srobert 
GetTracedCpus()513*f6aab3d8Srobert ArrayRef<lldb::cpu_id_t> Trace::GetTracedCpus() {
514*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
515*f6aab3d8Srobert   if (storage.cpus)
516*f6aab3d8Srobert     return *storage.cpus;
517*f6aab3d8Srobert   return {};
518*f6aab3d8Srobert }
519*f6aab3d8Srobert 
GetTracedProcesses()520*f6aab3d8Srobert std::vector<Process *> Trace::GetTracedProcesses() {
521*f6aab3d8Srobert   std::vector<Process *> processes;
522*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
523*f6aab3d8Srobert 
524*f6aab3d8Srobert   for (Process *proc : storage.postmortem_processes)
525*f6aab3d8Srobert     processes.push_back(proc);
526*f6aab3d8Srobert 
527*f6aab3d8Srobert   if (m_live_process)
528*f6aab3d8Srobert     processes.push_back(m_live_process);
529*f6aab3d8Srobert   return processes;
530*f6aab3d8Srobert }
531