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(TraceStopRequest(GetPluginName())); 112 } 113 114 Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) { 115 if (!m_live_process) 116 return createStringError(inconvertibleErrorCode(), 117 "Tracing requires a live process."); 118 return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids)); 119 } 120 121 Expected<std::string> Trace::GetLiveProcessState() { 122 if (!m_live_process) 123 return createStringError(inconvertibleErrorCode(), 124 "Tracing requires a live process."); 125 return m_live_process->TraceGetState(GetPluginName()); 126 } 127 128 Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, 129 llvm::StringRef kind) { 130 auto it = m_live_thread_data.find(tid); 131 if (it == m_live_thread_data.end()) 132 return None; 133 std::unordered_map<std::string, size_t> &single_thread_data = it->second; 134 auto single_thread_data_it = single_thread_data.find(kind.str()); 135 if (single_thread_data_it == single_thread_data.end()) 136 return None; 137 return single_thread_data_it->second; 138 } 139 140 Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { 141 auto data_it = m_live_process_data.find(kind.str()); 142 if (data_it == m_live_process_data.end()) 143 return None; 144 return data_it->second; 145 } 146 147 Expected<ArrayRef<uint8_t>> 148 Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { 149 if (!m_live_process) 150 return createStringError(inconvertibleErrorCode(), 151 "Tracing requires a live process."); 152 llvm::Optional<size_t> size = GetLiveThreadBinaryDataSize(tid, kind); 153 if (!size) 154 return createStringError( 155 inconvertibleErrorCode(), 156 "Tracing data \"%s\" is not available for thread %" PRIu64 ".", 157 kind.data(), tid); 158 159 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), 160 static_cast<int64_t>(tid), 0, 161 static_cast<int64_t>(*size)}; 162 return m_live_process->TraceGetBinaryData(request); 163 } 164 165 Expected<ArrayRef<uint8_t>> 166 Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { 167 if (!m_live_process) 168 return createStringError(inconvertibleErrorCode(), 169 "Tracing requires a live process."); 170 llvm::Optional<size_t> size = GetLiveProcessBinaryDataSize(kind); 171 if (!size) 172 return createStringError( 173 inconvertibleErrorCode(), 174 "Tracing data \"%s\" is not available for the process.", kind.data()); 175 176 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), None, 0, 177 static_cast<int64_t>(*size)}; 178 return m_live_process->TraceGetBinaryData(request); 179 } 180 181 void Trace::RefreshLiveProcessState() { 182 if (!m_live_process) 183 return; 184 185 uint32_t new_stop_id = m_live_process->GetStopID(); 186 if (new_stop_id == m_stop_id) 187 return; 188 189 m_stop_id = new_stop_id; 190 m_live_thread_data.clear(); 191 192 Expected<std::string> json_string = GetLiveProcessState(); 193 if (!json_string) { 194 DoRefreshLiveProcessState(json_string.takeError()); 195 return; 196 } 197 Expected<TraceGetStateResponse> live_process_state = 198 json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse"); 199 if (!live_process_state) { 200 DoRefreshLiveProcessState(live_process_state.takeError()); 201 return; 202 } 203 204 for (const TraceThreadState &thread_state : 205 live_process_state->tracedThreads) { 206 for (const TraceBinaryData &item : thread_state.binaryData) 207 m_live_thread_data[thread_state.tid][item.kind] = item.size; 208 } 209 210 for (const TraceBinaryData &item : live_process_state->processBinaryData) 211 m_live_process_data[item.kind] = item.size; 212 213 DoRefreshLiveProcessState(std::move(live_process_state)); 214 } 215 216 uint32_t Trace::GetStopID() { 217 RefreshLiveProcessState(); 218 return m_stop_id; 219 } 220