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