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