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