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-exception
6//
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 if (!PluginManager::IsRegisteredObjectFilePluginName(name)) {
25 return Status::FromErrorStringWithFormat(
26 format: "plugin name '%s' is not a valid ObjectFile plugin name", name);
27 }
28
29 m_plugin_name = name;
30 return error;
31}
32
33void SaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { m_style = style; }
34
35void SaveCoreOptions::SetOutputFile(FileSpec file) { m_file = file; }
36
37std::optional<std::string> SaveCoreOptions::GetPluginName() const {
38 return m_plugin_name;
39}
40
41lldb::SaveCoreStyle SaveCoreOptions::GetStyle() const {
42 return m_style.value_or(u: lldb::eSaveCoreUnspecified);
43}
44
45const std::optional<lldb_private::FileSpec>
46SaveCoreOptions::GetOutputFile() const {
47 return m_file;
48}
49
50Status SaveCoreOptions::SetProcess(lldb::ProcessSP process_sp) {
51 Status error;
52 if (!process_sp) {
53 ClearProcessSpecificData();
54 m_process_sp.reset();
55 return error;
56 }
57
58 if (!process_sp->IsValid()) {
59 error = Status::FromErrorString(str: "Cannot assign an invalid process.");
60 return error;
61 }
62
63 // Don't clear any process specific data if the process is the same.
64 if (m_process_sp == process_sp)
65 return error;
66
67 ClearProcessSpecificData();
68 m_process_sp = process_sp;
69 return error;
70}
71
72Status SaveCoreOptions::AddThread(lldb::ThreadSP thread_sp) {
73 Status error;
74 if (!thread_sp) {
75 error = Status::FromErrorString(str: "invalid thread");
76 return error;
77 }
78
79 if (m_process_sp) {
80 if (m_process_sp != thread_sp->GetProcess()) {
81 error = Status::FromErrorString(
82 str: "Cannot add a thread from a different process.");
83 return error;
84 }
85 } else {
86 m_process_sp = thread_sp->GetProcess();
87 }
88
89 m_threads_to_save.insert(x: thread_sp->GetID());
90 return error;
91}
92
93bool SaveCoreOptions::RemoveThread(lldb::ThreadSP thread_sp) {
94 return thread_sp && m_threads_to_save.erase(x: thread_sp->GetID()) > 0;
95}
96
97bool SaveCoreOptions::ShouldThreadBeSaved(lldb::tid_t tid) const {
98 // If the user specified no threads to save, then we save all threads.
99 if (m_threads_to_save.empty())
100 return true;
101 return m_threads_to_save.count(x: tid) > 0;
102}
103
104bool SaveCoreOptions::HasSpecifiedThreads() const {
105 return !m_threads_to_save.empty();
106}
107
108void SaveCoreOptions::AddMemoryRegionToSave(
109 const lldb_private::MemoryRegionInfo &region) {
110 m_regions_to_save.Insert(entry: region.GetRange(), /*combine=*/true);
111}
112
113const MemoryRanges &SaveCoreOptions::GetCoreFileMemoryRanges() const {
114 return m_regions_to_save;
115}
116Status
117SaveCoreOptions::EnsureValidConfiguration(lldb::ProcessSP process_sp) const {
118 Status error;
119 std::string error_str;
120 if (!m_threads_to_save.empty() && GetStyle() == lldb::eSaveCoreFull)
121 error_str += "Cannot save a full core with a subset of threads\n";
122
123 if (m_process_sp && m_process_sp != process_sp)
124 error_str += "Cannot save core for process using supplied core options. "
125 "Options were constructed targeting a different process. \n";
126
127 if (!error_str.empty())
128 error = Status(error_str);
129
130 return error;
131}
132
133lldb_private::ThreadCollection::collection
134SaveCoreOptions::GetThreadsToSave() const {
135 lldb_private::ThreadCollection::collection thread_collection;
136 // In cases where no process is set, such as when no threads are specified.
137 if (!m_process_sp)
138 return thread_collection;
139
140 ThreadList &thread_list = m_process_sp->GetThreadList();
141 for (const auto &tid : m_threads_to_save)
142 thread_collection.push_back(x: thread_list.FindThreadByID(tid));
143
144 return thread_collection;
145}
146
147llvm::Expected<uint64_t> SaveCoreOptions::GetCurrentSizeInBytes() {
148 Status error;
149 if (!m_process_sp)
150 return Status::FromErrorString(str: "Requires a process to be set.").takeError();
151
152 error = EnsureValidConfiguration(process_sp: m_process_sp);
153 if (error.Fail())
154 return error.takeError();
155
156 CoreFileMemoryRanges ranges;
157 error = m_process_sp->CalculateCoreFileSaveRanges(core_options: *this, ranges);
158 if (error.Fail())
159 return error.takeError();
160
161 uint64_t total_in_bytes = 0;
162 for (auto &core_range : ranges)
163 total_in_bytes += core_range.data.range.size();
164
165 return total_in_bytes;
166}
167
168void SaveCoreOptions::ClearProcessSpecificData() {
169 // Deliberately not following the formatter style here to indicate that
170 // this method will be expanded in the future.
171 m_threads_to_save.clear();
172}
173
174void SaveCoreOptions::Clear() {
175 m_file = std::nullopt;
176 m_plugin_name = std::nullopt;
177 m_style = std::nullopt;
178 m_threads_to_save.clear();
179 m_process_sp.reset();
180 m_regions_to_save.Clear();
181}
182

source code of lldb/source/Symbol/SaveCoreOptions.cpp