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 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 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 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> 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> 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 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 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 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 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 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 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 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>> 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>> 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 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 218 uint32_t Trace::GetStopID() { 219 RefreshLiveProcessState(); 220 return m_stop_id; 221 } 222