blob: 8c20a3b158cd014472d73f31b98a8968626b19a0 [file] [log] [blame]
//===-- 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 <fstream>
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<JSONTraceSessionBase> TraceSessionSaver::BuildProcessesSection(
Process &live_process,
std::function<
llvm::Expected<llvm::Optional<std::vector<uint8_t>>>(lldb::tid_t tid)>
raw_trace_fetcher,
FileSpec directory) {
JSONTraceSessionBase json_session_description;
Expected<std::vector<JSONThread>> json_threads =
BuildThreadsSection(live_process, raw_trace_fetcher, directory);
if (!json_threads)
return json_threads.takeError();
Expected<std::vector<JSONModule>> json_modules =
BuildModulesSection(live_process, directory);
if (!json_modules)
return json_modules.takeError();
json_session_description.processes.push_back(JSONProcess{
static_cast<int64_t>(live_process.GetID()),
live_process.GetTarget().GetArchitecture().GetTriple().getTriple(),
json_threads.get(), json_modules.get()});
return json_session_description;
}
llvm::Expected<std::vector<JSONThread>> TraceSessionSaver::BuildThreadsSection(
Process &live_process,
std::function<
llvm::Expected<llvm::Optional<std::vector<uint8_t>>>(lldb::tid_t tid)>
raw_trace_fetcher,
FileSpec directory) {
std::vector<JSONThread> json_threads;
for (ThreadSP thread_sp : live_process.Threads()) {
// resolve the directory just in case
FileSystem::Instance().Resolve(directory);
FileSpec raw_trace_path = directory;
raw_trace_path.AppendPathComponent(std::to_string(thread_sp->GetID()) +
".trace");
json_threads.push_back(JSONThread{static_cast<int64_t>(thread_sp->GetID()),
raw_trace_path.GetPath().c_str()});
llvm::Expected<llvm::Optional<std::vector<uint8_t>>> raw_trace =
raw_trace_fetcher(thread_sp->GetID());
if (!raw_trace)
return raw_trace.takeError();
if (!raw_trace.get())
continue;
std::basic_fstream<char> raw_trace_fs = std::fstream(
raw_trace_path.GetPath().c_str(), std::ios::out | std::ios::binary);
raw_trace_fs.write(reinterpret_cast<const char *>(&raw_trace.get()->at(0)),
raw_trace.get()->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 json_threads;
}
llvm::Expected<std::vector<JSONModule>>
TraceSessionSaver::BuildModulesSection(Process &live_process,
FileSpec directory) {
std::vector<JSONModule> 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;
}