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