Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LLDB][SBSaveCore] Implement a selectable threadlist for Core Options. #100443

Merged
merged 14 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lldb/include/lldb/API/SBProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ class LLDB_API SBProcess {
friend class SBBreakpointCallbackBaton;
friend class SBBreakpointLocation;
friend class SBCommandInterpreter;
friend class SBSaveCoreOptions;
friend class SBDebugger;
friend class SBExecutionContext;
friend class SBFunction;
Expand Down
24 changes: 24 additions & 0 deletions lldb/include/lldb/API/SBSaveCoreOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_API_SBSAVECOREOPTIONS_H

#include "lldb/API/SBDefines.h"
#include "lldb/API/SBThread.h"
Jlalond marked this conversation as resolved.
Show resolved Hide resolved

namespace lldb {

Expand Down Expand Up @@ -53,6 +54,29 @@ class LLDB_API SBSaveCoreOptions {
/// \return The output file spec.
SBFileSpec GetOutputFile() const;

/// Set the process to save, or unset if supplied with a default constructed
/// process.
///
/// \param process The process to save.
/// \return Success if process was set, otherwise an error
/// \note This will clear all process specific options if a different process
/// is specified than the current set process, either explicitly from this
/// api, or implicitly from any function that requires a process.
SBError SetProcess(lldb::SBProcess process);

/// Add a thread to save in the core file.
///
/// \param thread The thread to save.
/// \note This will set the process if it is not already set, or return
/// and error if the SBThread is not from the set process.
SBError AddThread(lldb::SBThread thread);

/// Remove a thread from the list of threads to save.
///
/// \param thread The thread to remove.
/// \return True if the thread was removed, false if it was not in the list.
bool RemoveThread(lldb::SBThread thread);

/// Reset all options.
void Clear();

Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/API/SBThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ class LLDB_API SBThread {
friend class SBBreakpoint;
friend class SBBreakpointLocation;
friend class SBBreakpointCallbackBaton;
friend class SBSaveCoreOptions;
friend class SBExecutionContext;
friend class SBFrame;
friend class SBProcess;
Expand All @@ -255,6 +256,8 @@ class LLDB_API SBThread {

lldb::ExecutionContextRefSP m_opaque_sp;

lldb::ThreadSP get_sp() const;
Jlalond marked this conversation as resolved.
Show resolved Hide resolved

lldb_private::Thread *operator->();

lldb_private::Thread *get();
Expand Down
13 changes: 13 additions & 0 deletions lldb/include/lldb/Symbol/SaveCoreOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"

#include <map>
#include <optional>
#include <string>

Expand All @@ -32,12 +33,24 @@ class SaveCoreOptions {
void SetOutputFile(lldb_private::FileSpec file);
const std::optional<lldb_private::FileSpec> GetOutputFile() const;

Status SetProcess(lldb::ProcessSP process_sp);

Status AddThread(lldb::ThreadSP thread_sp);
bool RemoveThread(lldb::ThreadSP thread_sp);
bool ShouldThreadBeSaved(lldb::tid_t tid) const;

Status EnsureValidConfiguration(lldb::ProcessSP process_to_save) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "process_sp"


void Clear();

private:
void ClearProcessSpecificData();

std::optional<std::string> m_plugin_name;
std::optional<lldb_private::FileSpec> m_file;
std::optional<lldb::SaveCoreStyle> m_style;
lldb::ProcessSP m_process_sp;
std::map<lldb::tid_t, lldb::ThreadSP> m_threads_to_save;
};
} // namespace lldb_private

Expand Down
8 changes: 7 additions & 1 deletion lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,9 +738,15 @@ class Process : public std::enable_shared_from_this<Process>,
/// Helper function for Process::SaveCore(...) that calculates the address
/// ranges that should be saved. This allows all core file plug-ins to save
/// consistent memory ranges given a \a core_style.
Status CalculateCoreFileSaveRanges(lldb::SaveCoreStyle core_style,
Status CalculateCoreFileSaveRanges(const SaveCoreOptions &core_options,
CoreFileMemoryRanges &ranges);

/// Helper function for Process::SaveCore(...) that calculates the thread list
/// based upon options set within a given \a core_options object.
Jlalond marked this conversation as resolved.
Show resolved Hide resolved
/// \note If there is no thread list defined, all threads will be saved.
std::vector<lldb::ThreadSP>
CalculateCoreFileThreadList(const SaveCoreOptions &core_options);

protected:
virtual JITLoaderList &GetJITLoaders();

Expand Down
14 changes: 14 additions & 0 deletions lldb/source/API/SBSaveCoreOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "lldb/API/SBSaveCoreOptions.h"
#include "lldb/API/SBError.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBThread.h"
Jlalond marked this conversation as resolved.
Show resolved Hide resolved
#include "lldb/Host/FileSystem.h"
#include "lldb/Symbol/SaveCoreOptions.h"
#include "lldb/Utility/Instrumentation.h"
Expand Down Expand Up @@ -75,6 +77,18 @@ lldb::SaveCoreStyle SBSaveCoreOptions::GetStyle() const {
return m_opaque_up->GetStyle();
}

SBError SBSaveCoreOptions::SetProcess(lldb::SBProcess process) {
return m_opaque_up->SetProcess(process.GetSP());
}

SBError SBSaveCoreOptions::AddThread(lldb::SBThread thread) {
return m_opaque_up->AddThread(thread.get_sp());
}

bool SBSaveCoreOptions::RemoveThread(lldb::SBThread thread) {
return m_opaque_up->RemoveThread(thread.get_sp());
}

void SBSaveCoreOptions::Clear() {
LLDB_INSTRUMENT_VA(this);
m_opaque_up->Clear();
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/API/SBThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,8 @@ bool SBThread::SafeToCallFunctions() {
return true;
}

lldb::ThreadSP SBThread::get_sp() const { return m_opaque_sp->GetThreadSP(); }

lldb_private::Thread *SBThread::operator->() {
return get();
}
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Core/PluginManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,10 @@ Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp,
return error;
}

error = options.EnsureValidConfiguration(process_sp);
if (error.Fail())
return error;

if (!options.GetPluginName().has_value()) {
// Try saving core directly from the process plugin first.
llvm::Expected<bool> ret =
Expand Down
23 changes: 12 additions & 11 deletions lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6346,22 +6346,24 @@ struct segment_vmaddr {
// are some multiple passes over the image list while calculating
// everything.

static offset_t CreateAllImageInfosPayload(
const lldb::ProcessSP &process_sp, offset_t initial_file_offset,
StreamString &all_image_infos_payload, SaveCoreStyle core_style) {
static offset_t
CreateAllImageInfosPayload(const lldb::ProcessSP &process_sp,
offset_t initial_file_offset,
StreamString &all_image_infos_payload,
const lldb_private::SaveCoreOptions &options) {
Target &target = process_sp->GetTarget();
ModuleList modules = target.GetImages();

// stack-only corefiles have no reason to include binaries that
// are not executing; we're trying to make the smallest corefile
// we can, so leave the rest out.
if (core_style == SaveCoreStyle::eSaveCoreStackOnly)
if (options.GetStyle() == SaveCoreStyle::eSaveCoreStackOnly)
modules.Clear();

std::set<std::string> executing_uuids;
ThreadList &thread_list(process_sp->GetThreadList());
for (uint32_t i = 0; i < thread_list.GetSize(); i++) {
ThreadSP thread_sp = thread_list.GetThreadAtIndex(i);
std::vector<ThreadSP> thread_list =
process_sp->CalculateCoreFileThreadList(options);
for (const ThreadSP &thread_sp : thread_list) {
uint32_t stack_frame_count = thread_sp->GetStackFrameCount();
for (uint32_t j = 0; j < stack_frame_count; j++) {
StackFrameSP stack_frame_sp = thread_sp->GetStackFrameAtIndex(j);
Expand Down Expand Up @@ -6558,7 +6560,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,

if (make_core) {
Process::CoreFileMemoryRanges core_ranges;
error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
error = process_sp->CalculateCoreFileSaveRanges(options, core_ranges);
if (error.Success()) {
const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
const ByteOrder byte_order = target_arch.GetByteOrder();
Expand Down Expand Up @@ -6729,8 +6731,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
std::make_shared<StructuredData::Dictionary>());
StructuredData::ArraySP threads(
std::make_shared<StructuredData::Array>());
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
for (const ThreadSP &thread_sp : process_sp->CalculateCoreFileThreadList(options)) {
StructuredData::DictionarySP thread(
std::make_shared<StructuredData::Dictionary>());
thread->AddIntegerItem("thread_id", thread_sp->GetID());
Expand All @@ -6753,7 +6754,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
all_image_infos_lcnote_up->payload_file_offset = file_offset;
file_offset = CreateAllImageInfosPayload(
process_sp, file_offset, all_image_infos_lcnote_up->payload,
core_style);
options);
lc_notes.push_back(std::move(all_image_infos_lcnote_up));

// Add LC_NOTE load commands
Expand Down
72 changes: 33 additions & 39 deletions lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() {
m_expected_directories += 9;

// Go through all of the threads and check for exceptions.
lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
const uint32_t num_threads = thread_list.GetSize();
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
std::vector<lldb::ThreadSP> threads =
m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
for (const ThreadSP &thread_sp : threads) {
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
if (stop_info_sp) {
const StopReason &stop_reason = stop_info_sp->GetStopReason();
Expand Down Expand Up @@ -588,12 +587,13 @@ Status MinidumpFileBuilder::FixThreadStacks() {

Status MinidumpFileBuilder::AddThreadList() {
constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
std::vector<ThreadSP> thread_list =
m_process_sp->CalculateCoreFileThreadList(m_save_core_options);

// size of the entire thread stream consists of:
// number of threads and threads array
size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
thread_list.GetSize() * minidump_thread_size;
thread_list.size() * minidump_thread_size;
// save for the ability to set up RVA
size_t size_before = GetCurrentDataEndOffset();
Status error;
Expand All @@ -602,17 +602,15 @@ Status MinidumpFileBuilder::AddThreadList() {
return error;

llvm::support::ulittle32_t thread_count =
static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
static_cast<llvm::support::ulittle32_t>(thread_list.size());
m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));

// Take the offset after the thread count.
m_thread_list_start = GetCurrentDataEndOffset();
DataBufferHeap helper_data;

const uint32_t num_threads = thread_list.GetSize();
Log *log = GetLog(LLDBLog::Object);
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
for (const ThreadSP &thread_sp : thread_list) {
RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());

if (!reg_ctx_sp) {
Expand Down Expand Up @@ -650,7 +648,7 @@ Status MinidumpFileBuilder::AddThreadList() {
m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;

LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
thread_idx, thread_context.size());
thread_sp->GetIndexID(), thread_context.size());
helper_data.AppendData(thread_context.data(), thread_context.size());

llvm::minidump::Thread t;
Expand All @@ -674,11 +672,10 @@ Status MinidumpFileBuilder::AddThreadList() {
}

Status MinidumpFileBuilder::AddExceptions() {
lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
std::vector<ThreadSP> thread_list =
m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
Status error;
const uint32_t num_threads = thread_list.GetSize();
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
for (const ThreadSP &thread_sp : thread_list) {
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
bool add_exception = false;
if (stop_info_sp) {
Expand Down Expand Up @@ -819,7 +816,7 @@ Status MinidumpFileBuilder::AddLinuxFileStreams() {
return error;
}

Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
Status MinidumpFileBuilder::AddMemoryList() {
Status error;

// We first save the thread stacks to ensure they fit in the first UINT32_MAX
Expand All @@ -828,18 +825,26 @@ Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
// in accessible with a 32 bit offset.
Process::CoreFileMemoryRanges ranges_32;
Process::CoreFileMemoryRanges ranges_64;
error = m_process_sp->CalculateCoreFileSaveRanges(
SaveCoreStyle::eSaveCoreStackOnly, ranges_32);
Process::CoreFileMemoryRanges all_core_memory_ranges;
error = m_process_sp->CalculateCoreFileSaveRanges(m_save_core_options,
all_core_memory_ranges);
if (error.Fail())
return error;

// Calculate totalsize including the current offset.
// Start by saving all of the stacks and ensuring they fit under the 32b
// limit.
uint64_t total_size = GetCurrentDataEndOffset();
total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor);
std::unordered_set<addr_t> stack_start_addresses;
for (const auto &core_range : ranges_32) {
stack_start_addresses.insert(core_range.range.start());
total_size += core_range.range.size();
auto iterator = all_core_memory_ranges.begin();
while (iterator != all_core_memory_ranges.end()) {
if (m_saved_stack_ranges.count(iterator->range.start()) > 0) {
// We don't save stacks twice.
ranges_32.push_back(*iterator);
total_size +=
iterator->range.size() + sizeof(llvm::minidump::MemoryDescriptor);
iterator = all_core_memory_ranges.erase(iterator);
} else {
iterator++;
}
}

if (total_size >= UINT32_MAX) {
Expand All @@ -849,31 +854,20 @@ Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
return error;
}

Process::CoreFileMemoryRanges all_core_memory_ranges;
if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {
error = m_process_sp->CalculateCoreFileSaveRanges(core_style,
all_core_memory_ranges);
if (error.Fail())
return error;
}

// After saving the stacks, we start packing as much as we can into 32b.
// We apply a generous padding here so that the Directory, MemoryList and
// Memory64List sections all begin in 32b addressable space.
// Then anything overflow extends into 64b addressable space.
// All core memeroy ranges will either container nothing on stacks only
// or all the memory ranges including stacks
if (!all_core_memory_ranges.empty())
total_size +=
256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) *
sizeof(llvm::minidump::MemoryDescriptor_64);
total_size += 256 + (all_core_memory_ranges.size() *
sizeof(llvm::minidump::MemoryDescriptor_64));

for (const auto &core_range : all_core_memory_ranges) {
const addr_t range_size = core_range.range.size();
if (stack_start_addresses.count(core_range.range.start()) > 0)
// Don't double save stacks.
continue;

// We don't need to check for stacks here because we already removed them
// from all_core_memory_ranges.
if (total_size + range_size < UINT32_MAX) {
ranges_32.push_back(core_range);
total_size += range_size;
Expand Down
Loading
Loading