//===-- TraceSessionSaver.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "TraceSessionSaver.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/lldb-types.h" #include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" #include using namespace lldb; using namespace lldb_private; using namespace llvm; llvm::Error TraceSessionSaver::WriteSessionToFile( const llvm::json::Value &trace_session_description, FileSpec directory) { FileSpec trace_path = directory; trace_path.AppendPathComponent("trace.json"); std::ofstream os(trace_path.GetPath()); os << std::string(formatv("{0:2}", trace_session_description)); os.close(); if (!os) return createStringError(inconvertibleErrorCode(), formatv("couldn't write to the file {0}", trace_path.GetPath().c_str())); return Error::success(); } llvm::Expected TraceSessionSaver::BuildProcessesSection( Process &live_process, llvm::StringRef raw_thread_trace_data_kind, FileSpec directory) { JSONTraceSessionBase json_session_description; Expected> json_threads = BuildThreadsSection(live_process, raw_thread_trace_data_kind, directory); if (!json_threads) return json_threads.takeError(); Expected> json_modules = BuildModulesSection(live_process, directory); if (!json_modules) return json_modules.takeError(); json_session_description.processes.push_back(JSONProcess{ static_cast(live_process.GetID()), live_process.GetTarget().GetArchitecture().GetTriple().getTriple(), json_threads.get(), json_modules.get()}); return json_session_description; } llvm::Expected> TraceSessionSaver::BuildThreadsSection( Process &live_process, llvm::StringRef raw_thread_trace_data_kind, FileSpec directory) { std::vector json_threads; for (ThreadSP thread_sp : live_process.Threads()) { TraceSP trace_sp = live_process.GetTarget().GetTrace(); lldb::tid_t tid = thread_sp->GetID(); if (!trace_sp->IsTraced(tid)) continue; // resolve the directory just in case FileSystem::Instance().Resolve(directory); FileSpec raw_trace_path = directory; raw_trace_path.AppendPathComponent(std::to_string(tid) + ".trace"); json_threads.push_back(JSONThread{static_cast(tid), raw_trace_path.GetPath().c_str()}); llvm::Error err = live_process.GetTarget().GetTrace()->OnThreadBinaryDataRead( tid, raw_thread_trace_data_kind, [&](llvm::ArrayRef data) -> llvm::Error { std::basic_fstream raw_trace_fs = std::fstream(raw_trace_path.GetPath().c_str(), std::ios::out | std::ios::binary); raw_trace_fs.write(reinterpret_cast(&data[0]), data.size() * sizeof(uint8_t)); raw_trace_fs.close(); if (!raw_trace_fs) return createStringError( inconvertibleErrorCode(), formatv("couldn't write to the file {0}", raw_trace_path.GetPath().c_str())); return Error::success(); }); if (err) return std::move(err); } return json_threads; } llvm::Expected> TraceSessionSaver::BuildModulesSection(Process &live_process, FileSpec directory) { std::vector json_modules; ModuleList module_list = live_process.GetTarget().GetImages(); for (size_t i = 0; i < module_list.GetSize(); ++i) { ModuleSP module_sp(module_list.GetModuleAtIndex(i)); if (!module_sp) continue; std::string system_path = module_sp->GetPlatformFileSpec().GetPath(); // TODO: support memory-only libraries like [vdso] if (!module_sp->GetFileSpec().IsAbsolute()) continue; std::string file = module_sp->GetFileSpec().GetPath(); ObjectFile *objfile = module_sp->GetObjectFile(); if (objfile == nullptr) continue; lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; Address base_addr(objfile->GetBaseAddress()); if (base_addr.IsValid() && !live_process.GetTarget().GetSectionLoadList().IsEmpty()) load_addr = base_addr.GetLoadAddress(&live_process.GetTarget()); if (load_addr == LLDB_INVALID_ADDRESS) continue; FileSystem::Instance().Resolve(directory); FileSpec path_to_copy_module = directory; path_to_copy_module.AppendPathComponent("modules"); path_to_copy_module.AppendPathComponent(system_path); sys::fs::create_directories(path_to_copy_module.GetDirectory().AsCString()); if (std::error_code ec = llvm::sys::fs::copy_file( system_path, path_to_copy_module.GetPath())) return createStringError( inconvertibleErrorCode(), formatv("couldn't write to the file. {0}", ec.message())); json_modules.push_back( JSONModule{system_path, path_to_copy_module.GetPath(), JSONAddress{load_addr}, module_sp->GetUUID().GetAsString()}); } return json_modules; }