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