1e8d8bef9SDimitry Andric //===-- Trace.cpp ---------------------------------------------------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h" 10e8d8bef9SDimitry Andric 11e8d8bef9SDimitry Andric #include "llvm/Support/Format.h" 12e8d8bef9SDimitry Andric 13e8d8bef9SDimitry Andric #include "lldb/Core/Module.h" 14e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h" 15e8d8bef9SDimitry Andric #include "lldb/Symbol/Function.h" 16fe6060f1SDimitry Andric #include "lldb/Target/ExecutionContext.h" 17e8d8bef9SDimitry Andric #include "lldb/Target/Process.h" 18e8d8bef9SDimitry Andric #include "lldb/Target/SectionLoadList.h" 19e8d8bef9SDimitry Andric #include "lldb/Target/Thread.h" 20*81ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 21e8d8bef9SDimitry Andric #include "lldb/Utility/Stream.h" 22e8d8bef9SDimitry Andric 23e8d8bef9SDimitry Andric using namespace lldb; 24e8d8bef9SDimitry Andric using namespace lldb_private; 25e8d8bef9SDimitry Andric using namespace llvm; 26e8d8bef9SDimitry Andric 27*81ad6265SDimitry Andric // Helper structs used to extract the type of a JSON trace bundle description 28*81ad6265SDimitry Andric // object without having to parse the entire object. 29e8d8bef9SDimitry Andric 30*81ad6265SDimitry Andric struct JSONSimpleTraceBundleDescription { 31e8d8bef9SDimitry Andric std::string type; 32e8d8bef9SDimitry Andric }; 33e8d8bef9SDimitry Andric 34e8d8bef9SDimitry Andric namespace llvm { 35e8d8bef9SDimitry Andric namespace json { 36e8d8bef9SDimitry Andric 37*81ad6265SDimitry Andric bool fromJSON(const Value &value, JSONSimpleTraceBundleDescription &bundle, 38e8d8bef9SDimitry Andric Path path) { 39e8d8bef9SDimitry Andric json::ObjectMapper o(value, path); 40*81ad6265SDimitry Andric return o && o.map("type", bundle.type); 41e8d8bef9SDimitry Andric } 42e8d8bef9SDimitry Andric 43e8d8bef9SDimitry Andric } // namespace json 44e8d8bef9SDimitry Andric } // namespace llvm 45e8d8bef9SDimitry Andric 46*81ad6265SDimitry Andric /// Helper functions for fetching data in maps and returning Optionals or 47*81ad6265SDimitry Andric /// pointers instead of iterators for simplicity. It's worth mentioning that the 48*81ad6265SDimitry Andric /// Optionals version can't return the inner data by reference because of 49*81ad6265SDimitry Andric /// limitations in move constructors. 50*81ad6265SDimitry Andric /// \{ 51*81ad6265SDimitry Andric template <typename K, typename V> 52*81ad6265SDimitry Andric static Optional<V> Lookup(DenseMap<K, V> &map, K k) { 53*81ad6265SDimitry Andric auto it = map.find(k); 54*81ad6265SDimitry Andric if (it == map.end()) 55*81ad6265SDimitry Andric return None; 56*81ad6265SDimitry Andric return it->second; 57*81ad6265SDimitry Andric } 58*81ad6265SDimitry Andric 59*81ad6265SDimitry Andric template <typename K, typename V> 60*81ad6265SDimitry Andric static V *LookupAsPtr(DenseMap<K, V> &map, K k) { 61*81ad6265SDimitry Andric auto it = map.find(k); 62*81ad6265SDimitry Andric if (it == map.end()) 63*81ad6265SDimitry Andric return nullptr; 64*81ad6265SDimitry Andric return &it->second; 65*81ad6265SDimitry Andric } 66*81ad6265SDimitry Andric 67*81ad6265SDimitry Andric /// Similar to the methods above but it looks for an item in a map of maps. 68*81ad6265SDimitry Andric template <typename K1, typename K2, typename V> 69*81ad6265SDimitry Andric static Optional<V> Lookup(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) { 70*81ad6265SDimitry Andric auto it = map.find(k1); 71*81ad6265SDimitry Andric if (it == map.end()) 72*81ad6265SDimitry Andric return None; 73*81ad6265SDimitry Andric return Lookup(it->second, k2); 74*81ad6265SDimitry Andric } 75*81ad6265SDimitry Andric 76*81ad6265SDimitry Andric /// Similar to the methods above but it looks for an item in a map of maps. 77*81ad6265SDimitry Andric template <typename K1, typename K2, typename V> 78*81ad6265SDimitry Andric static V *LookupAsPtr(DenseMap<K1, DenseMap<K2, V>> &map, K1 k1, K2 k2) { 79*81ad6265SDimitry Andric auto it = map.find(k1); 80*81ad6265SDimitry Andric if (it == map.end()) 81*81ad6265SDimitry Andric return nullptr; 82*81ad6265SDimitry Andric return LookupAsPtr(it->second, k2); 83*81ad6265SDimitry Andric } 84*81ad6265SDimitry Andric /// \} 85*81ad6265SDimitry Andric 86e8d8bef9SDimitry Andric static Error createInvalidPlugInError(StringRef plugin_name) { 87e8d8bef9SDimitry Andric return createStringError( 88e8d8bef9SDimitry Andric std::errc::invalid_argument, 89e8d8bef9SDimitry Andric "no trace plug-in matches the specified type: \"%s\"", 90e8d8bef9SDimitry Andric plugin_name.data()); 91e8d8bef9SDimitry Andric } 92e8d8bef9SDimitry Andric 93fe6060f1SDimitry Andric Expected<lldb::TraceSP> 94*81ad6265SDimitry Andric Trace::LoadPostMortemTraceFromFile(Debugger &debugger, 95*81ad6265SDimitry Andric const FileSpec &trace_description_file) { 96*81ad6265SDimitry Andric 97*81ad6265SDimitry Andric auto buffer_or_error = 98*81ad6265SDimitry Andric MemoryBuffer::getFile(trace_description_file.GetPath()); 99*81ad6265SDimitry Andric if (!buffer_or_error) { 100*81ad6265SDimitry Andric return createStringError(std::errc::invalid_argument, 101*81ad6265SDimitry Andric "could not open input file: %s - %s.", 102*81ad6265SDimitry Andric trace_description_file.GetPath().c_str(), 103*81ad6265SDimitry Andric buffer_or_error.getError().message().c_str()); 104*81ad6265SDimitry Andric } 105*81ad6265SDimitry Andric 106*81ad6265SDimitry Andric Expected<json::Value> session_file = 107*81ad6265SDimitry Andric json::parse(buffer_or_error.get()->getBuffer().str()); 108*81ad6265SDimitry Andric if (!session_file) { 109*81ad6265SDimitry Andric return session_file.takeError(); 110*81ad6265SDimitry Andric } 111*81ad6265SDimitry Andric 112*81ad6265SDimitry Andric return Trace::FindPluginForPostMortemProcess( 113*81ad6265SDimitry Andric debugger, *session_file, 114*81ad6265SDimitry Andric trace_description_file.GetDirectory().AsCString()); 115*81ad6265SDimitry Andric } 116*81ad6265SDimitry Andric 117*81ad6265SDimitry Andric Expected<lldb::TraceSP> Trace::FindPluginForPostMortemProcess( 118*81ad6265SDimitry Andric Debugger &debugger, const json::Value &trace_bundle_description, 119*81ad6265SDimitry Andric StringRef bundle_dir) { 120*81ad6265SDimitry Andric JSONSimpleTraceBundleDescription json_bundle; 121*81ad6265SDimitry Andric json::Path::Root root("traceBundle"); 122*81ad6265SDimitry Andric if (!json::fromJSON(trace_bundle_description, json_bundle, root)) 123e8d8bef9SDimitry Andric return root.getError(); 124e8d8bef9SDimitry Andric 125349cc55cSDimitry Andric if (auto create_callback = 126*81ad6265SDimitry Andric PluginManager::GetTraceCreateCallback(json_bundle.type)) 127*81ad6265SDimitry Andric return create_callback(trace_bundle_description, bundle_dir, debugger); 128e8d8bef9SDimitry Andric 129*81ad6265SDimitry Andric return createInvalidPlugInError(json_bundle.type); 130e8d8bef9SDimitry Andric } 131e8d8bef9SDimitry Andric 132349cc55cSDimitry Andric Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name, 133349cc55cSDimitry Andric Process &process) { 134fe6060f1SDimitry Andric if (!process.IsLiveDebugSession()) 135fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 136fe6060f1SDimitry Andric "Can't trace non-live processes"); 137fe6060f1SDimitry Andric 138fe6060f1SDimitry Andric if (auto create_callback = 139fe6060f1SDimitry Andric PluginManager::GetTraceCreateCallbackForLiveProcess(name)) 140fe6060f1SDimitry Andric return create_callback(process); 141fe6060f1SDimitry Andric 142349cc55cSDimitry Andric return createInvalidPlugInError(name); 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145e8d8bef9SDimitry Andric Expected<StringRef> Trace::FindPluginSchema(StringRef name) { 146349cc55cSDimitry Andric StringRef schema = PluginManager::GetTraceSchema(name); 147e8d8bef9SDimitry Andric if (!schema.empty()) 148e8d8bef9SDimitry Andric return schema; 149e8d8bef9SDimitry Andric 150e8d8bef9SDimitry Andric return createInvalidPlugInError(name); 151e8d8bef9SDimitry Andric } 152e8d8bef9SDimitry Andric 153fe6060f1SDimitry Andric Error Trace::Start(const llvm::json::Value &request) { 154fe6060f1SDimitry Andric if (!m_live_process) 155*81ad6265SDimitry Andric return createStringError( 156*81ad6265SDimitry Andric inconvertibleErrorCode(), 157*81ad6265SDimitry Andric "Attempted to start tracing without a live process."); 158fe6060f1SDimitry Andric return m_live_process->TraceStart(request); 159e8d8bef9SDimitry Andric } 160e8d8bef9SDimitry Andric 161fe6060f1SDimitry Andric Error Trace::Stop() { 162fe6060f1SDimitry Andric if (!m_live_process) 163*81ad6265SDimitry Andric return createStringError( 164*81ad6265SDimitry Andric inconvertibleErrorCode(), 165*81ad6265SDimitry Andric "Attempted to stop tracing without a live process."); 166349cc55cSDimitry Andric return m_live_process->TraceStop(TraceStopRequest(GetPluginName())); 167e8d8bef9SDimitry Andric } 168e8d8bef9SDimitry Andric 169fe6060f1SDimitry Andric Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) { 170fe6060f1SDimitry Andric if (!m_live_process) 171*81ad6265SDimitry Andric return createStringError( 172*81ad6265SDimitry Andric inconvertibleErrorCode(), 173*81ad6265SDimitry Andric "Attempted to stop tracing without a live process."); 174349cc55cSDimitry Andric return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids)); 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric 177fe6060f1SDimitry Andric Expected<std::string> Trace::GetLiveProcessState() { 178fe6060f1SDimitry Andric if (!m_live_process) 179*81ad6265SDimitry Andric return createStringError( 180*81ad6265SDimitry Andric inconvertibleErrorCode(), 181*81ad6265SDimitry Andric "Attempted to fetch live trace information without a live process."); 182349cc55cSDimitry Andric return m_live_process->TraceGetState(GetPluginName()); 183e8d8bef9SDimitry Andric } 184e8d8bef9SDimitry Andric 185*81ad6265SDimitry Andric Optional<uint64_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, 186fe6060f1SDimitry Andric llvm::StringRef kind) { 187*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 188*81ad6265SDimitry Andric return Lookup(storage.live_thread_data, tid, ConstString(kind)); 189e8d8bef9SDimitry Andric } 190e8d8bef9SDimitry Andric 191*81ad6265SDimitry Andric Optional<uint64_t> Trace::GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id, 192*81ad6265SDimitry Andric llvm::StringRef kind) { 193*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 194*81ad6265SDimitry Andric return Lookup(storage.live_cpu_data_sizes, cpu_id, ConstString(kind)); 195e8d8bef9SDimitry Andric } 196e8d8bef9SDimitry Andric 197*81ad6265SDimitry Andric Optional<uint64_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { 198*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 199*81ad6265SDimitry Andric return Lookup(storage.live_process_data, ConstString(kind)); 200*81ad6265SDimitry Andric } 201*81ad6265SDimitry Andric 202*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> 203*81ad6265SDimitry Andric Trace::GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request, 204*81ad6265SDimitry Andric uint64_t expected_size) { 205fe6060f1SDimitry Andric if (!m_live_process) 206*81ad6265SDimitry Andric return createStringError( 207*81ad6265SDimitry Andric inconvertibleErrorCode(), 208*81ad6265SDimitry Andric formatv("Attempted to fetch live trace data without a live process. " 209*81ad6265SDimitry Andric "Data kind = {0}, tid = {1}, cpu id = {2}.", 210*81ad6265SDimitry Andric request.kind, request.tid, request.cpu_id)); 211*81ad6265SDimitry Andric 212*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> data = 213*81ad6265SDimitry Andric m_live_process->TraceGetBinaryData(request); 214*81ad6265SDimitry Andric 215*81ad6265SDimitry Andric if (!data) 216*81ad6265SDimitry Andric return data.takeError(); 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric if (data->size() != expected_size) 219*81ad6265SDimitry Andric return createStringError( 220*81ad6265SDimitry Andric inconvertibleErrorCode(), 221*81ad6265SDimitry Andric formatv("Got incomplete live trace data. Data kind = {0}, expected " 222*81ad6265SDimitry Andric "size = {1}, actual size = {2}, tid = {3}, cpu id = {4}", 223*81ad6265SDimitry Andric request.kind, expected_size, data->size(), request.tid, 224*81ad6265SDimitry Andric request.cpu_id)); 225*81ad6265SDimitry Andric 226*81ad6265SDimitry Andric return data; 227*81ad6265SDimitry Andric } 228*81ad6265SDimitry Andric 229*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> 230*81ad6265SDimitry Andric Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { 231*81ad6265SDimitry Andric llvm::Optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind); 232fe6060f1SDimitry Andric if (!size) 233fe6060f1SDimitry Andric return createStringError( 234fe6060f1SDimitry Andric inconvertibleErrorCode(), 235fe6060f1SDimitry Andric "Tracing data \"%s\" is not available for thread %" PRIu64 ".", 236fe6060f1SDimitry Andric kind.data(), tid); 237e8d8bef9SDimitry Andric 238*81ad6265SDimitry Andric TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), tid, 239*81ad6265SDimitry Andric /*cpu_id=*/None}; 240*81ad6265SDimitry Andric return GetLiveTraceBinaryData(request, *size); 241*81ad6265SDimitry Andric } 242*81ad6265SDimitry Andric 243*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> 244*81ad6265SDimitry Andric Trace::GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind) { 245*81ad6265SDimitry Andric if (!m_live_process) 246*81ad6265SDimitry Andric return createStringError( 247*81ad6265SDimitry Andric inconvertibleErrorCode(), 248*81ad6265SDimitry Andric "Attempted to fetch live cpu data without a live process."); 249*81ad6265SDimitry Andric llvm::Optional<uint64_t> size = GetLiveCpuBinaryDataSize(cpu_id, kind); 250*81ad6265SDimitry Andric if (!size) 251*81ad6265SDimitry Andric return createStringError( 252*81ad6265SDimitry Andric inconvertibleErrorCode(), 253*81ad6265SDimitry Andric "Tracing data \"%s\" is not available for cpu_id %" PRIu64 ".", 254*81ad6265SDimitry Andric kind.data(), cpu_id); 255*81ad6265SDimitry Andric 256349cc55cSDimitry Andric TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), 257*81ad6265SDimitry Andric /*tid=*/None, cpu_id}; 258fe6060f1SDimitry Andric return m_live_process->TraceGetBinaryData(request); 259fe6060f1SDimitry Andric } 260fe6060f1SDimitry Andric 261*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> 262fe6060f1SDimitry Andric Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { 263*81ad6265SDimitry Andric llvm::Optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind); 264fe6060f1SDimitry Andric if (!size) 265fe6060f1SDimitry Andric return createStringError( 266fe6060f1SDimitry Andric inconvertibleErrorCode(), 267fe6060f1SDimitry Andric "Tracing data \"%s\" is not available for the process.", kind.data()); 268fe6060f1SDimitry Andric 269*81ad6265SDimitry Andric TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), 270*81ad6265SDimitry Andric /*tid=*/None, /*cpu_id*/ None}; 271*81ad6265SDimitry Andric return GetLiveTraceBinaryData(request, *size); 272fe6060f1SDimitry Andric } 273fe6060f1SDimitry Andric 274*81ad6265SDimitry Andric Trace::Storage &Trace::GetUpdatedStorage() { 275*81ad6265SDimitry Andric RefreshLiveProcessState(); 276*81ad6265SDimitry Andric return m_storage; 277*81ad6265SDimitry Andric } 278*81ad6265SDimitry Andric 279*81ad6265SDimitry Andric const char *Trace::RefreshLiveProcessState() { 280fe6060f1SDimitry Andric if (!m_live_process) 281*81ad6265SDimitry Andric return nullptr; 282e8d8bef9SDimitry Andric 283fe6060f1SDimitry Andric uint32_t new_stop_id = m_live_process->GetStopID(); 284fe6060f1SDimitry Andric if (new_stop_id == m_stop_id) 285*81ad6265SDimitry Andric return nullptr; 286*81ad6265SDimitry Andric 287*81ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Target); 288*81ad6265SDimitry Andric LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked"); 289e8d8bef9SDimitry Andric 290fe6060f1SDimitry Andric m_stop_id = new_stop_id; 291*81ad6265SDimitry Andric m_storage = Trace::Storage(); 292e8d8bef9SDimitry Andric 293*81ad6265SDimitry Andric auto do_refresh = [&]() -> Error { 294fe6060f1SDimitry Andric Expected<std::string> json_string = GetLiveProcessState(); 295*81ad6265SDimitry Andric if (!json_string) 296*81ad6265SDimitry Andric return json_string.takeError(); 297*81ad6265SDimitry Andric 298fe6060f1SDimitry Andric Expected<TraceGetStateResponse> live_process_state = 299*81ad6265SDimitry Andric json::parse<TraceGetStateResponse>(*json_string, 300*81ad6265SDimitry Andric "TraceGetStateResponse"); 301*81ad6265SDimitry Andric if (!live_process_state) 302*81ad6265SDimitry Andric return live_process_state.takeError(); 303*81ad6265SDimitry Andric 304*81ad6265SDimitry Andric if (live_process_state->warnings) { 305*81ad6265SDimitry Andric for (std::string &warning : *live_process_state->warnings) 306*81ad6265SDimitry Andric LLDB_LOG(log, "== Warning when fetching the trace state: {0}", warning); 307e8d8bef9SDimitry Andric } 308e8d8bef9SDimitry Andric 309fe6060f1SDimitry Andric for (const TraceThreadState &thread_state : 310*81ad6265SDimitry Andric live_process_state->traced_threads) { 311*81ad6265SDimitry Andric for (const TraceBinaryData &item : thread_state.binary_data) 312*81ad6265SDimitry Andric m_storage.live_thread_data[thread_state.tid].insert( 313*81ad6265SDimitry Andric {ConstString(item.kind), item.size}); 314e8d8bef9SDimitry Andric } 315e8d8bef9SDimitry Andric 316*81ad6265SDimitry Andric LLDB_LOG(log, "== Found {0} threads being traced", 317*81ad6265SDimitry Andric live_process_state->traced_threads.size()); 318fe6060f1SDimitry Andric 319*81ad6265SDimitry Andric if (live_process_state->cpus) { 320*81ad6265SDimitry Andric m_storage.cpus.emplace(); 321*81ad6265SDimitry Andric for (const TraceCpuState &cpu_state : *live_process_state->cpus) { 322*81ad6265SDimitry Andric m_storage.cpus->push_back(cpu_state.id); 323*81ad6265SDimitry Andric for (const TraceBinaryData &item : cpu_state.binary_data) 324*81ad6265SDimitry Andric m_storage.live_cpu_data_sizes[cpu_state.id].insert( 325*81ad6265SDimitry Andric {ConstString(item.kind), item.size}); 326*81ad6265SDimitry Andric } 327*81ad6265SDimitry Andric LLDB_LOG(log, "== Found {0} cpu cpus being traced", 328*81ad6265SDimitry Andric live_process_state->cpus->size()); 329*81ad6265SDimitry Andric } 330*81ad6265SDimitry Andric 331*81ad6265SDimitry Andric for (const TraceBinaryData &item : live_process_state->process_binary_data) 332*81ad6265SDimitry Andric m_storage.live_process_data.insert({ConstString(item.kind), item.size}); 333*81ad6265SDimitry Andric 334*81ad6265SDimitry Andric return DoRefreshLiveProcessState(std::move(*live_process_state), 335*81ad6265SDimitry Andric *json_string); 336*81ad6265SDimitry Andric }; 337*81ad6265SDimitry Andric 338*81ad6265SDimitry Andric if (Error err = do_refresh()) { 339*81ad6265SDimitry Andric m_storage.live_refresh_error = toString(std::move(err)); 340*81ad6265SDimitry Andric return m_storage.live_refresh_error->c_str(); 341*81ad6265SDimitry Andric } 342*81ad6265SDimitry Andric 343*81ad6265SDimitry Andric return nullptr; 344*81ad6265SDimitry Andric } 345*81ad6265SDimitry Andric 346*81ad6265SDimitry Andric Trace::Trace(ArrayRef<ProcessSP> postmortem_processes, 347*81ad6265SDimitry Andric Optional<std::vector<lldb::cpu_id_t>> postmortem_cpus) { 348*81ad6265SDimitry Andric for (ProcessSP process_sp : postmortem_processes) 349*81ad6265SDimitry Andric m_storage.postmortem_processes.push_back(process_sp.get()); 350*81ad6265SDimitry Andric m_storage.cpus = postmortem_cpus; 351*81ad6265SDimitry Andric } 352*81ad6265SDimitry Andric 353*81ad6265SDimitry Andric Process *Trace::GetLiveProcess() { return m_live_process; } 354*81ad6265SDimitry Andric 355*81ad6265SDimitry Andric ArrayRef<Process *> Trace::GetPostMortemProcesses() { 356*81ad6265SDimitry Andric return m_storage.postmortem_processes; 357*81ad6265SDimitry Andric } 358*81ad6265SDimitry Andric 359*81ad6265SDimitry Andric std::vector<Process *> Trace::GetAllProcesses() { 360*81ad6265SDimitry Andric if (Process *proc = GetLiveProcess()) 361*81ad6265SDimitry Andric return {proc}; 362*81ad6265SDimitry Andric return GetPostMortemProcesses(); 363e8d8bef9SDimitry Andric } 364e8d8bef9SDimitry Andric 365fe6060f1SDimitry Andric uint32_t Trace::GetStopID() { 366fe6060f1SDimitry Andric RefreshLiveProcessState(); 367fe6060f1SDimitry Andric return m_stop_id; 368e8d8bef9SDimitry Andric } 369*81ad6265SDimitry Andric 370*81ad6265SDimitry Andric llvm::Expected<FileSpec> 371*81ad6265SDimitry Andric Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) { 372*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 373*81ad6265SDimitry Andric if (Optional<FileSpec> file = 374*81ad6265SDimitry Andric Lookup(storage.postmortem_thread_data, tid, ConstString(kind))) 375*81ad6265SDimitry Andric return *file; 376*81ad6265SDimitry Andric else 377*81ad6265SDimitry Andric return createStringError( 378*81ad6265SDimitry Andric inconvertibleErrorCode(), 379*81ad6265SDimitry Andric formatv("The thread with tid={0} doesn't have the tracing data {1}", 380*81ad6265SDimitry Andric tid, kind)); 381*81ad6265SDimitry Andric } 382*81ad6265SDimitry Andric 383*81ad6265SDimitry Andric llvm::Expected<FileSpec> Trace::GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, 384*81ad6265SDimitry Andric llvm::StringRef kind) { 385*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 386*81ad6265SDimitry Andric if (Optional<FileSpec> file = 387*81ad6265SDimitry Andric Lookup(storage.postmortem_cpu_data, cpu_id, ConstString(kind))) 388*81ad6265SDimitry Andric return *file; 389*81ad6265SDimitry Andric else 390*81ad6265SDimitry Andric return createStringError( 391*81ad6265SDimitry Andric inconvertibleErrorCode(), 392*81ad6265SDimitry Andric formatv("The cpu with id={0} doesn't have the tracing data {1}", cpu_id, 393*81ad6265SDimitry Andric kind)); 394*81ad6265SDimitry Andric } 395*81ad6265SDimitry Andric 396*81ad6265SDimitry Andric void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind, 397*81ad6265SDimitry Andric FileSpec file_spec) { 398*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 399*81ad6265SDimitry Andric storage.postmortem_thread_data[tid].insert({ConstString(kind), file_spec}); 400*81ad6265SDimitry Andric } 401*81ad6265SDimitry Andric 402*81ad6265SDimitry Andric void Trace::SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, 403*81ad6265SDimitry Andric llvm::StringRef kind, FileSpec file_spec) { 404*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 405*81ad6265SDimitry Andric storage.postmortem_cpu_data[cpu_id].insert({ConstString(kind), file_spec}); 406*81ad6265SDimitry Andric } 407*81ad6265SDimitry Andric 408*81ad6265SDimitry Andric llvm::Error 409*81ad6265SDimitry Andric Trace::OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 410*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 411*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind); 412*81ad6265SDimitry Andric if (!data) 413*81ad6265SDimitry Andric return data.takeError(); 414*81ad6265SDimitry Andric return callback(*data); 415*81ad6265SDimitry Andric } 416*81ad6265SDimitry Andric 417*81ad6265SDimitry Andric llvm::Error Trace::OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu_id, 418*81ad6265SDimitry Andric llvm::StringRef kind, 419*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 420*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 421*81ad6265SDimitry Andric if (std::vector<uint8_t> *cpu_data = 422*81ad6265SDimitry Andric LookupAsPtr(storage.live_cpu_data, cpu_id, ConstString(kind))) 423*81ad6265SDimitry Andric return callback(*cpu_data); 424*81ad6265SDimitry Andric 425*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> data = GetLiveCpuBinaryData(cpu_id, kind); 426*81ad6265SDimitry Andric if (!data) 427*81ad6265SDimitry Andric return data.takeError(); 428*81ad6265SDimitry Andric auto it = storage.live_cpu_data[cpu_id].insert( 429*81ad6265SDimitry Andric {ConstString(kind), std::move(*data)}); 430*81ad6265SDimitry Andric return callback(it.first->second); 431*81ad6265SDimitry Andric } 432*81ad6265SDimitry Andric 433*81ad6265SDimitry Andric llvm::Error Trace::OnDataFileRead(FileSpec file, 434*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 435*81ad6265SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error = 436*81ad6265SDimitry Andric MemoryBuffer::getFile(file.GetPath()); 437*81ad6265SDimitry Andric if (std::error_code err = trace_or_error.getError()) 438*81ad6265SDimitry Andric return createStringError( 439*81ad6265SDimitry Andric inconvertibleErrorCode(), "Failed fetching trace-related file %s. %s", 440*81ad6265SDimitry Andric file.GetCString(), toString(errorCodeToError(err)).c_str()); 441*81ad6265SDimitry Andric 442*81ad6265SDimitry Andric MemoryBuffer &data = **trace_or_error; 443*81ad6265SDimitry Andric ArrayRef<uint8_t> array_ref( 444*81ad6265SDimitry Andric reinterpret_cast<const uint8_t *>(data.getBufferStart()), 445*81ad6265SDimitry Andric data.getBufferSize()); 446*81ad6265SDimitry Andric return callback(array_ref); 447*81ad6265SDimitry Andric } 448*81ad6265SDimitry Andric 449*81ad6265SDimitry Andric llvm::Error 450*81ad6265SDimitry Andric Trace::OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 451*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 452*81ad6265SDimitry Andric if (Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind)) 453*81ad6265SDimitry Andric return OnDataFileRead(*file, callback); 454*81ad6265SDimitry Andric else 455*81ad6265SDimitry Andric return file.takeError(); 456*81ad6265SDimitry Andric } 457*81ad6265SDimitry Andric 458*81ad6265SDimitry Andric llvm::Error 459*81ad6265SDimitry Andric Trace::OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id, 460*81ad6265SDimitry Andric llvm::StringRef kind, 461*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 462*81ad6265SDimitry Andric if (Expected<FileSpec> file = GetPostMortemCpuDataFile(cpu_id, kind)) 463*81ad6265SDimitry Andric return OnDataFileRead(*file, callback); 464*81ad6265SDimitry Andric else 465*81ad6265SDimitry Andric return file.takeError(); 466*81ad6265SDimitry Andric } 467*81ad6265SDimitry Andric 468*81ad6265SDimitry Andric llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 469*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 470*81ad6265SDimitry Andric if (m_live_process) 471*81ad6265SDimitry Andric return OnLiveThreadBinaryDataRead(tid, kind, callback); 472*81ad6265SDimitry Andric else 473*81ad6265SDimitry Andric return OnPostMortemThreadBinaryDataRead(tid, kind, callback); 474*81ad6265SDimitry Andric } 475*81ad6265SDimitry Andric 476*81ad6265SDimitry Andric llvm::Error 477*81ad6265SDimitry Andric Trace::OnAllCpusBinaryDataRead(llvm::StringRef kind, 478*81ad6265SDimitry Andric OnCpusBinaryDataReadCallback callback) { 479*81ad6265SDimitry Andric DenseMap<cpu_id_t, ArrayRef<uint8_t>> buffers; 480*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 481*81ad6265SDimitry Andric if (!storage.cpus) 482*81ad6265SDimitry Andric return Error::success(); 483*81ad6265SDimitry Andric 484*81ad6265SDimitry Andric std::function<Error(std::vector<cpu_id_t>::iterator)> process_cpu = 485*81ad6265SDimitry Andric [&](std::vector<cpu_id_t>::iterator cpu_id) -> Error { 486*81ad6265SDimitry Andric if (cpu_id == storage.cpus->end()) 487*81ad6265SDimitry Andric return callback(buffers); 488*81ad6265SDimitry Andric 489*81ad6265SDimitry Andric return OnCpuBinaryDataRead(*cpu_id, kind, 490*81ad6265SDimitry Andric [&](ArrayRef<uint8_t> data) -> Error { 491*81ad6265SDimitry Andric buffers.try_emplace(*cpu_id, data); 492*81ad6265SDimitry Andric auto next_id = cpu_id; 493*81ad6265SDimitry Andric next_id++; 494*81ad6265SDimitry Andric return process_cpu(next_id); 495*81ad6265SDimitry Andric }); 496*81ad6265SDimitry Andric }; 497*81ad6265SDimitry Andric return process_cpu(storage.cpus->begin()); 498*81ad6265SDimitry Andric } 499*81ad6265SDimitry Andric 500*81ad6265SDimitry Andric llvm::Error Trace::OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id, 501*81ad6265SDimitry Andric llvm::StringRef kind, 502*81ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 503*81ad6265SDimitry Andric if (m_live_process) 504*81ad6265SDimitry Andric return OnLiveCpuBinaryDataRead(cpu_id, kind, callback); 505*81ad6265SDimitry Andric else 506*81ad6265SDimitry Andric return OnPostMortemCpuBinaryDataRead(cpu_id, kind, callback); 507*81ad6265SDimitry Andric } 508*81ad6265SDimitry Andric 509*81ad6265SDimitry Andric ArrayRef<lldb::cpu_id_t> Trace::GetTracedCpus() { 510*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 511*81ad6265SDimitry Andric if (storage.cpus) 512*81ad6265SDimitry Andric return *storage.cpus; 513*81ad6265SDimitry Andric return {}; 514*81ad6265SDimitry Andric } 515*81ad6265SDimitry Andric 516*81ad6265SDimitry Andric std::vector<Process *> Trace::GetTracedProcesses() { 517*81ad6265SDimitry Andric std::vector<Process *> processes; 518*81ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 519*81ad6265SDimitry Andric 520*81ad6265SDimitry Andric for (Process *proc : storage.postmortem_processes) 521*81ad6265SDimitry Andric processes.push_back(proc); 522*81ad6265SDimitry Andric 523*81ad6265SDimitry Andric if (m_live_process) 524*81ad6265SDimitry Andric processes.push_back(m_live_process); 525*81ad6265SDimitry Andric return processes; 526*81ad6265SDimitry Andric } 527