215 lines · cpp
1//===-- SaveCoreOptions.cpp -------------------------------------*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Symbol/SaveCoreOptions.h"10#include "lldb/Core/PluginManager.h"11#include "lldb/Target/Process.h"12#include "lldb/Target/Thread.h"13 14using namespace lldb;15using namespace lldb_private;16 17Status SaveCoreOptions::SetPluginName(const char *name) {18 Status error;19 if (!name || !name[0]) {20 m_plugin_name = std::nullopt;21 return error;22 }23 24 std::vector<llvm::StringRef> plugin_names =25 PluginManager::GetSaveCorePluginNames();26 if (!llvm::is_contained(plugin_names, name)) {27 StreamString stream;28 stream.Printf("plugin name '%s' is not a valid ObjectFile plugin name.",29 name);30 31 if (!plugin_names.empty()) {32 stream.PutCString(" Valid names are: ");33 std::string plugin_names_str = llvm::join(plugin_names, ", ");34 stream.PutCString(plugin_names_str);35 stream.PutChar('.');36 }37 return Status(stream.GetString().str());38 }39 40 m_plugin_name = name;41 return error;42}43 44void SaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { m_style = style; }45 46void SaveCoreOptions::SetOutputFile(FileSpec file) { m_file = file; }47 48std::optional<std::string> SaveCoreOptions::GetPluginName() const {49 return m_plugin_name;50}51 52lldb::SaveCoreStyle SaveCoreOptions::GetStyle() const {53 return m_style.value_or(lldb::eSaveCoreUnspecified);54}55 56const std::optional<lldb_private::FileSpec>57SaveCoreOptions::GetOutputFile() const {58 return m_file;59}60 61Status SaveCoreOptions::SetProcess(lldb::ProcessSP process_sp) {62 Status error;63 if (!process_sp) {64 ClearProcessSpecificData();65 m_process_sp.reset();66 return error;67 }68 69 if (!process_sp->IsValid()) {70 error = Status::FromErrorString("Cannot assign an invalid process.");71 return error;72 }73 74 // Don't clear any process specific data if the process is the same.75 if (m_process_sp == process_sp)76 return error;77 78 ClearProcessSpecificData();79 m_process_sp = process_sp;80 return error;81}82 83Status SaveCoreOptions::AddThread(lldb::ThreadSP thread_sp) {84 Status error;85 if (!thread_sp) {86 error = Status::FromErrorString("invalid thread");87 return error;88 }89 90 if (m_process_sp) {91 if (m_process_sp != thread_sp->GetProcess()) {92 error = Status::FromErrorString(93 "Cannot add a thread from a different process.");94 return error;95 }96 } else {97 m_process_sp = thread_sp->GetProcess();98 }99 100 m_threads_to_save.insert(thread_sp->GetID());101 return error;102}103 104bool SaveCoreOptions::RemoveThread(lldb::ThreadSP thread_sp) {105 return thread_sp && m_threads_to_save.erase(thread_sp->GetID()) > 0;106}107 108bool SaveCoreOptions::ShouldThreadBeSaved(lldb::tid_t tid) const {109 // If the user specified no threads to save, then we save all threads.110 if (m_threads_to_save.empty())111 return true;112 return m_threads_to_save.count(tid) > 0;113}114 115bool SaveCoreOptions::HasSpecifiedThreads() const {116 return !m_threads_to_save.empty();117}118 119void SaveCoreOptions::AddMemoryRegionToSave(120 const lldb_private::MemoryRegionInfo ®ion) {121 m_regions_to_save.Insert(region.GetRange(), /*combine=*/true);122}123 124const MemoryRanges &SaveCoreOptions::GetCoreFileMemoryRanges() const {125 return m_regions_to_save;126}127Status SaveCoreOptions::EnsureValidConfiguration() const {128 Status error;129 std::string error_str;130 if (!m_threads_to_save.empty() && GetStyle() == lldb::eSaveCoreFull)131 error_str += "Cannot save a full core with a subset of threads\n";132 133 if (!m_process_sp)134 error_str += "Need to assign a valid process\n";135 136 if (!error_str.empty())137 error = Status(error_str);138 139 return error;140}141 142lldb_private::ThreadCollection::collection143SaveCoreOptions::GetThreadsToSave() const {144 lldb_private::ThreadCollection::collection thread_collection;145 // In cases where no process is set, such as when no threads are specified.146 if (!m_process_sp)147 return thread_collection;148 149 ThreadList &thread_list = m_process_sp->GetThreadList();150 for (const auto &tid : m_threads_to_save)151 thread_collection.push_back(thread_list.FindThreadByID(tid));152 153 return thread_collection;154}155 156llvm::Expected<lldb_private::CoreFileMemoryRanges>157SaveCoreOptions::GetMemoryRegionsToSave() {158 Status error;159 if (!m_process_sp)160 return Status::FromErrorString("Requires a process to be set.").takeError();161 162 error = EnsureValidConfiguration();163 if (error.Fail())164 return error.takeError();165 166 CoreFileMemoryRanges ranges;167 error = m_process_sp->CalculateCoreFileSaveRanges(*this, ranges);168 if (error.Fail())169 return error.takeError();170 171 return ranges;172}173 174llvm::Expected<uint64_t> SaveCoreOptions::GetCurrentSizeInBytes() {175 Status error;176 if (!m_process_sp)177 return Status::FromErrorString("Requires a process to be set.").takeError();178 179 error = EnsureValidConfiguration();180 if (error.Fail())181 return error.takeError();182 183 CoreFileMemoryRanges ranges;184 error = m_process_sp->CalculateCoreFileSaveRanges(*this, ranges);185 if (error.Fail())186 return error.takeError();187 188 llvm::Expected<lldb_private::CoreFileMemoryRanges> core_file_ranges_maybe =189 GetMemoryRegionsToSave();190 if (!core_file_ranges_maybe)191 return core_file_ranges_maybe.takeError();192 const lldb_private::CoreFileMemoryRanges &core_file_ranges =193 *core_file_ranges_maybe;194 uint64_t total_in_bytes = 0;195 for (const auto &core_range : core_file_ranges)196 total_in_bytes += core_range.data.range.size();197 198 return total_in_bytes;199}200 201void SaveCoreOptions::ClearProcessSpecificData() {202 // Deliberately not following the formatter style here to indicate that203 // this method will be expanded in the future.204 m_threads_to_save.clear();205}206 207void SaveCoreOptions::Clear() {208 m_file = std::nullopt;209 m_plugin_name = std::nullopt;210 m_style = std::nullopt;211 m_threads_to_save.clear();212 m_process_sp.reset();213 m_regions_to_save.Clear();214}215