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 if (auto create_callback = 71 PluginManager::GetTraceCreateCallback(json_session.trace.type)) 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> Trace::FindPluginForLiveProcess(llvm::StringRef name, 78 Process &process) { 79 if (!process.IsLiveDebugSession()) 80 return createStringError(inconvertibleErrorCode(), 81 "Can't trace non-live processes"); 82 83 if (auto create_callback = 84 PluginManager::GetTraceCreateCallbackForLiveProcess(name)) 85 return create_callback(process); 86 87 return createInvalidPlugInError(name); 88 } 89 90 Expected<StringRef> Trace::FindPluginSchema(StringRef name) { 91 StringRef schema = PluginManager::GetTraceSchema(name); 92 if (!schema.empty()) 93 return schema; 94 95 return createInvalidPlugInError(name); 96 } 97 98 Error Trace::Start(const llvm::json::Value &request) { 99 if (!m_live_process) 100 return createStringError(inconvertibleErrorCode(), 101 "Tracing requires a live process."); 102 return m_live_process->TraceStart(request); 103 } 104 105 Error Trace::Stop() { 106 if (!m_live_process) 107 return createStringError(inconvertibleErrorCode(), 108 "Tracing requires a live process."); 109 return m_live_process->TraceStop(TraceStopRequest(GetPluginName())); 110 } 111 112 Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) { 113 if (!m_live_process) 114 return createStringError(inconvertibleErrorCode(), 115 "Tracing requires a live process."); 116 return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids)); 117 } 118 119 Expected<std::string> Trace::GetLiveProcessState() { 120 if (!m_live_process) 121 return createStringError(inconvertibleErrorCode(), 122 "Tracing requires a live process."); 123 return m_live_process->TraceGetState(GetPluginName()); 124 } 125 126 Optional<size_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, 127 llvm::StringRef kind) { 128 auto it = m_live_thread_data.find(tid); 129 if (it == m_live_thread_data.end()) 130 return None; 131 std::unordered_map<std::string, size_t> &single_thread_data = it->second; 132 auto single_thread_data_it = single_thread_data.find(kind.str()); 133 if (single_thread_data_it == single_thread_data.end()) 134 return None; 135 return single_thread_data_it->second; 136 } 137 138 Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { 139 auto data_it = m_live_process_data.find(kind.str()); 140 if (data_it == m_live_process_data.end()) 141 return None; 142 return data_it->second; 143 } 144 145 Expected<ArrayRef<uint8_t>> 146 Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { 147 if (!m_live_process) 148 return createStringError(inconvertibleErrorCode(), 149 "Tracing requires a live process."); 150 llvm::Optional<size_t> size = GetLiveThreadBinaryDataSize(tid, kind); 151 if (!size) 152 return createStringError( 153 inconvertibleErrorCode(), 154 "Tracing data \"%s\" is not available for thread %" PRIu64 ".", 155 kind.data(), tid); 156 157 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), 158 static_cast<int64_t>(tid), 0, 159 static_cast<int64_t>(*size)}; 160 return m_live_process->TraceGetBinaryData(request); 161 } 162 163 Expected<ArrayRef<uint8_t>> 164 Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { 165 if (!m_live_process) 166 return createStringError(inconvertibleErrorCode(), 167 "Tracing requires a live process."); 168 llvm::Optional<size_t> size = GetLiveProcessBinaryDataSize(kind); 169 if (!size) 170 return createStringError( 171 inconvertibleErrorCode(), 172 "Tracing data \"%s\" is not available for the process.", kind.data()); 173 174 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), None, 0, 175 static_cast<int64_t>(*size)}; 176 return m_live_process->TraceGetBinaryData(request); 177 } 178 179 void Trace::RefreshLiveProcessState() { 180 if (!m_live_process) 181 return; 182 183 uint32_t new_stop_id = m_live_process->GetStopID(); 184 if (new_stop_id == m_stop_id) 185 return; 186 187 m_stop_id = new_stop_id; 188 m_live_thread_data.clear(); 189 190 Expected<std::string> json_string = GetLiveProcessState(); 191 if (!json_string) { 192 DoRefreshLiveProcessState(json_string.takeError()); 193 return; 194 } 195 Expected<TraceGetStateResponse> live_process_state = 196 json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse"); 197 if (!live_process_state) { 198 DoRefreshLiveProcessState(live_process_state.takeError()); 199 return; 200 } 201 202 for (const TraceThreadState &thread_state : 203 live_process_state->tracedThreads) { 204 for (const TraceBinaryData &item : thread_state.binaryData) 205 m_live_thread_data[thread_state.tid][item.kind] = item.size; 206 } 207 208 for (const TraceBinaryData &item : live_process_state->processBinaryData) 209 m_live_process_data[item.kind] = item.size; 210 211 DoRefreshLiveProcessState(std::move(live_process_state)); 212 } 213 214 uint32_t Trace::GetStopID() { 215 RefreshLiveProcessState(); 216 return m_stop_id; 217 } 218