xref: /openbsd-src/gnu/llvm/lldb/source/Target/Trace.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1*be691f3bSpatrick //===-- Trace.cpp ---------------------------------------------------------===//
2*be691f3bSpatrick //
3*be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information.
5*be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*be691f3bSpatrick //
7*be691f3bSpatrick //===----------------------------------------------------------------------===//
8*be691f3bSpatrick 
9*be691f3bSpatrick #include "lldb/Target/Trace.h"
10*be691f3bSpatrick 
11*be691f3bSpatrick #include "llvm/Support/Format.h"
12*be691f3bSpatrick 
13*be691f3bSpatrick #include "lldb/Core/Module.h"
14*be691f3bSpatrick #include "lldb/Core/PluginManager.h"
15*be691f3bSpatrick #include "lldb/Symbol/Function.h"
16*be691f3bSpatrick #include "lldb/Target/ExecutionContext.h"
17*be691f3bSpatrick #include "lldb/Target/Process.h"
18*be691f3bSpatrick #include "lldb/Target/SectionLoadList.h"
19*be691f3bSpatrick #include "lldb/Target/Thread.h"
20*be691f3bSpatrick #include "lldb/Utility/Stream.h"
21*be691f3bSpatrick 
22*be691f3bSpatrick using namespace lldb;
23*be691f3bSpatrick using namespace lldb_private;
24*be691f3bSpatrick using namespace llvm;
25*be691f3bSpatrick 
26*be691f3bSpatrick // Helper structs used to extract the type of a trace session json without
27*be691f3bSpatrick // having to parse the entire object.
28*be691f3bSpatrick 
29*be691f3bSpatrick struct JSONSimplePluginSettings {
30*be691f3bSpatrick   std::string type;
31*be691f3bSpatrick };
32*be691f3bSpatrick 
33*be691f3bSpatrick struct JSONSimpleTraceSession {
34*be691f3bSpatrick   JSONSimplePluginSettings trace;
35*be691f3bSpatrick };
36*be691f3bSpatrick 
37*be691f3bSpatrick namespace llvm {
38*be691f3bSpatrick namespace json {
39*be691f3bSpatrick 
40*be691f3bSpatrick bool fromJSON(const Value &value, JSONSimplePluginSettings &plugin_settings,
41*be691f3bSpatrick               Path path) {
42*be691f3bSpatrick   json::ObjectMapper o(value, path);
43*be691f3bSpatrick   return o && o.map("type", plugin_settings.type);
44*be691f3bSpatrick }
45*be691f3bSpatrick 
46*be691f3bSpatrick bool fromJSON(const Value &value, JSONSimpleTraceSession &session, Path path) {
47*be691f3bSpatrick   json::ObjectMapper o(value, path);
48*be691f3bSpatrick   return o && o.map("trace", session.trace);
49*be691f3bSpatrick }
50*be691f3bSpatrick 
51*be691f3bSpatrick } // namespace json
52*be691f3bSpatrick } // namespace llvm
53*be691f3bSpatrick 
54*be691f3bSpatrick static Error createInvalidPlugInError(StringRef plugin_name) {
55*be691f3bSpatrick   return createStringError(
56*be691f3bSpatrick       std::errc::invalid_argument,
57*be691f3bSpatrick       "no trace plug-in matches the specified type: \"%s\"",
58*be691f3bSpatrick       plugin_name.data());
59*be691f3bSpatrick }
60*be691f3bSpatrick 
61*be691f3bSpatrick Expected<lldb::TraceSP>
62*be691f3bSpatrick Trace::FindPluginForPostMortemProcess(Debugger &debugger,
63*be691f3bSpatrick                                       const json::Value &trace_session_file,
64*be691f3bSpatrick                                       StringRef session_file_dir) {
65*be691f3bSpatrick   JSONSimpleTraceSession json_session;
66*be691f3bSpatrick   json::Path::Root root("traceSession");
67*be691f3bSpatrick   if (!json::fromJSON(trace_session_file, json_session, root))
68*be691f3bSpatrick     return root.getError();
69*be691f3bSpatrick 
70*be691f3bSpatrick   ConstString plugin_name(json_session.trace.type);
71*be691f3bSpatrick   if (auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name))
72*be691f3bSpatrick     return create_callback(trace_session_file, session_file_dir, debugger);
73*be691f3bSpatrick 
74*be691f3bSpatrick   return createInvalidPlugInError(json_session.trace.type);
75*be691f3bSpatrick }
76*be691f3bSpatrick 
77*be691f3bSpatrick Expected<lldb::TraceSP>
78*be691f3bSpatrick Trace::FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process) {
79*be691f3bSpatrick   if (!process.IsLiveDebugSession())
80*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
81*be691f3bSpatrick                              "Can't trace non-live processes");
82*be691f3bSpatrick 
83*be691f3bSpatrick   ConstString name(plugin_name);
84*be691f3bSpatrick   if (auto create_callback =
85*be691f3bSpatrick           PluginManager::GetTraceCreateCallbackForLiveProcess(name))
86*be691f3bSpatrick     return create_callback(process);
87*be691f3bSpatrick 
88*be691f3bSpatrick   return createInvalidPlugInError(plugin_name);
89*be691f3bSpatrick }
90*be691f3bSpatrick 
91*be691f3bSpatrick Expected<StringRef> Trace::FindPluginSchema(StringRef name) {
92*be691f3bSpatrick   ConstString plugin_name(name);
93*be691f3bSpatrick   StringRef schema = PluginManager::GetTraceSchema(plugin_name);
94*be691f3bSpatrick   if (!schema.empty())
95*be691f3bSpatrick     return schema;
96*be691f3bSpatrick 
97*be691f3bSpatrick   return createInvalidPlugInError(name);
98*be691f3bSpatrick }
99*be691f3bSpatrick 
100*be691f3bSpatrick Error Trace::Start(const llvm::json::Value &request) {
101*be691f3bSpatrick   if (!m_live_process)
102*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
103*be691f3bSpatrick                              "Tracing requires a live process.");
104*be691f3bSpatrick   return m_live_process->TraceStart(request);
105*be691f3bSpatrick }
106*be691f3bSpatrick 
107*be691f3bSpatrick Error Trace::Stop() {
108*be691f3bSpatrick   if (!m_live_process)
109*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
110*be691f3bSpatrick                              "Tracing requires a live process.");
111*be691f3bSpatrick   return m_live_process->TraceStop(
112*be691f3bSpatrick       TraceStopRequest(GetPluginName().AsCString()));
113*be691f3bSpatrick }
114*be691f3bSpatrick 
115*be691f3bSpatrick Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) {
116*be691f3bSpatrick   if (!m_live_process)
117*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
118*be691f3bSpatrick                              "Tracing requires a live process.");
119*be691f3bSpatrick   return m_live_process->TraceStop(
120*be691f3bSpatrick       TraceStopRequest(GetPluginName().AsCString(), tids));
121*be691f3bSpatrick }
122*be691f3bSpatrick 
123*be691f3bSpatrick Expected<std::string> Trace::GetLiveProcessState() {
124*be691f3bSpatrick   if (!m_live_process)
125*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
126*be691f3bSpatrick                              "Tracing requires a live process.");
127*be691f3bSpatrick   return m_live_process->TraceGetState(GetPluginName().AsCString());
128*be691f3bSpatrick }
129*be691f3bSpatrick 
130*be691f3bSpatrick Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid,
131*be691f3bSpatrick                                                     llvm::StringRef kind) {
132*be691f3bSpatrick   auto it = m_live_thread_data.find(tid);
133*be691f3bSpatrick   if (it == m_live_thread_data.end())
134*be691f3bSpatrick     return None;
135*be691f3bSpatrick   std::unordered_map<std::string, size_t> &single_thread_data = it->second;
136*be691f3bSpatrick   auto single_thread_data_it = single_thread_data.find(kind.str());
137*be691f3bSpatrick   if (single_thread_data_it == single_thread_data.end())
138*be691f3bSpatrick     return None;
139*be691f3bSpatrick   return single_thread_data_it->second;
140*be691f3bSpatrick }
141*be691f3bSpatrick 
142*be691f3bSpatrick Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
143*be691f3bSpatrick   auto data_it = m_live_process_data.find(kind.str());
144*be691f3bSpatrick   if (data_it == m_live_process_data.end())
145*be691f3bSpatrick     return None;
146*be691f3bSpatrick   return data_it->second;
147*be691f3bSpatrick }
148*be691f3bSpatrick 
149*be691f3bSpatrick Expected<ArrayRef<uint8_t>>
150*be691f3bSpatrick Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
151*be691f3bSpatrick   if (!m_live_process)
152*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
153*be691f3bSpatrick                              "Tracing requires a live process.");
154*be691f3bSpatrick   llvm::Optional<size_t> size = GetLiveThreadBinaryDataSize(tid, kind);
155*be691f3bSpatrick   if (!size)
156*be691f3bSpatrick     return createStringError(
157*be691f3bSpatrick         inconvertibleErrorCode(),
158*be691f3bSpatrick         "Tracing data \"%s\" is not available for thread %" PRIu64 ".",
159*be691f3bSpatrick         kind.data(), tid);
160*be691f3bSpatrick 
161*be691f3bSpatrick   TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
162*be691f3bSpatrick                                     static_cast<int64_t>(tid), 0,
163*be691f3bSpatrick                                     static_cast<int64_t>(*size)};
164*be691f3bSpatrick   return m_live_process->TraceGetBinaryData(request);
165*be691f3bSpatrick }
166*be691f3bSpatrick 
167*be691f3bSpatrick Expected<ArrayRef<uint8_t>>
168*be691f3bSpatrick Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
169*be691f3bSpatrick   if (!m_live_process)
170*be691f3bSpatrick     return createStringError(inconvertibleErrorCode(),
171*be691f3bSpatrick                              "Tracing requires a live process.");
172*be691f3bSpatrick   llvm::Optional<size_t> size = GetLiveProcessBinaryDataSize(kind);
173*be691f3bSpatrick   if (!size)
174*be691f3bSpatrick     return createStringError(
175*be691f3bSpatrick         inconvertibleErrorCode(),
176*be691f3bSpatrick         "Tracing data \"%s\" is not available for the process.", kind.data());
177*be691f3bSpatrick 
178*be691f3bSpatrick   TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(),
179*be691f3bSpatrick                                     None, 0, static_cast<int64_t>(*size)};
180*be691f3bSpatrick   return m_live_process->TraceGetBinaryData(request);
181*be691f3bSpatrick }
182*be691f3bSpatrick 
183*be691f3bSpatrick void Trace::RefreshLiveProcessState() {
184*be691f3bSpatrick   if (!m_live_process)
185*be691f3bSpatrick     return;
186*be691f3bSpatrick 
187*be691f3bSpatrick   uint32_t new_stop_id = m_live_process->GetStopID();
188*be691f3bSpatrick   if (new_stop_id == m_stop_id)
189*be691f3bSpatrick     return;
190*be691f3bSpatrick 
191*be691f3bSpatrick   m_stop_id = new_stop_id;
192*be691f3bSpatrick   m_live_thread_data.clear();
193*be691f3bSpatrick 
194*be691f3bSpatrick   Expected<std::string> json_string = GetLiveProcessState();
195*be691f3bSpatrick   if (!json_string) {
196*be691f3bSpatrick     DoRefreshLiveProcessState(json_string.takeError());
197*be691f3bSpatrick     return;
198*be691f3bSpatrick   }
199*be691f3bSpatrick   Expected<TraceGetStateResponse> live_process_state =
200*be691f3bSpatrick       json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse");
201*be691f3bSpatrick   if (!live_process_state) {
202*be691f3bSpatrick     DoRefreshLiveProcessState(live_process_state.takeError());
203*be691f3bSpatrick     return;
204*be691f3bSpatrick   }
205*be691f3bSpatrick 
206*be691f3bSpatrick   for (const TraceThreadState &thread_state :
207*be691f3bSpatrick        live_process_state->tracedThreads) {
208*be691f3bSpatrick     for (const TraceBinaryData &item : thread_state.binaryData)
209*be691f3bSpatrick       m_live_thread_data[thread_state.tid][item.kind] = item.size;
210*be691f3bSpatrick   }
211*be691f3bSpatrick 
212*be691f3bSpatrick   for (const TraceBinaryData &item : live_process_state->processBinaryData)
213*be691f3bSpatrick     m_live_process_data[item.kind] = item.size;
214*be691f3bSpatrick 
215*be691f3bSpatrick   DoRefreshLiveProcessState(std::move(live_process_state));
216*be691f3bSpatrick }
217*be691f3bSpatrick 
218*be691f3bSpatrick uint32_t Trace::GetStopID() {
219*be691f3bSpatrick   RefreshLiveProcessState();
220*be691f3bSpatrick   return m_stop_id;
221*be691f3bSpatrick }
222