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 6 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
21 changes: 21 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,26 @@ class LLDB_API SBSaveCoreOptions {
/// \return The output file spec.
SBFileSpec GetOutputFile() const;

/// Set the process to save, or unset if supplied with a null process.
Copy link
Collaborator

Choose a reason for hiding this comment

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

change null process to a default constructed SBProcess... though Maybe we should require a valid process here and add a void ClearProcess() API to have this make more sense.

///
/// \param process The process to save.
/// \return Success if process was set, otherwise an error
/// \note This will clear all process specific options if
/// an exisiting process is overriden.
Copy link
Collaborator

Choose a reason for hiding this comment

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

These lines should go up to column 79, these lines are stopping at column 60. Re-wrap.

Maybe reword a bit:

  /// \note This will clear all process specific options if a different process 
  /// is specified from a previous call to this function or to any other 
  /// functions that set the 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

And mention that it will return an error if the process is already set and the SBThread doesn't match the current 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
1 change: 1 addition & 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 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_private::Thread *thread);
bool RemoveThread(lldb_private::Thread *thread);
bool ShouldSaveThread(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;
std::optional<lldb::ProcessSP> m_process_sp;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a shared pointer, it being NULL is enough to say that there is no process set. Switch this to just a ProcessSP m_process_sp;

std::map<lldb::tid_t, lldb::ThreadSP> m_threads_to_save;
};
} // namespace lldb_private

Expand Down
7 changes: 6 additions & 1 deletion lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,9 +738,14 @@ 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
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());
Copy link
Collaborator

Choose a reason for hiding this comment

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

We might want to add a ThreadSP SBThread::get_sp() function to avoid people possibly putting a raw "Thread *" into another shared pointer that isn't the same as the one that constructed it.

Copy link
Member

Choose a reason for hiding this comment

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

+1. Thread also has enable_shared_from_this, so that is an option as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added this, and explicitly kept it lower case for the convention. Should we open an issue to look for casts to pointer and then GetSP() and clean them up?

}

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

void SBSaveCoreOptions::Clear() {
LLDB_INSTRUMENT_VA(this);
m_opaque_up->Clear();
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
11 changes: 6 additions & 5 deletions lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6558,7 +6558,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 @@ -6608,8 +6608,9 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
mach_header.ncmds = segment_load_commands.size();
mach_header.flags = 0;
mach_header.reserved = 0;
ThreadList &thread_list = process_sp->GetThreadList();
const uint32_t num_threads = thread_list.GetSize();
std::vector<ThreadSP> thread_list =
process_sp->CalculateCoreFileThreadList(options);
const uint32_t num_threads = thread_list.size();
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove this as before we needed to use the ThreadList class which didn't have an iterator. Now we have a std::vector<ThreadSP> so we can use the build in iteration. See below.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we need this line as we don't need the num_threads variable anymore?


// Make an array of LC_THREAD data items. Each one contains the
// contents of the LC_THREAD load command. The data doesn't contain
Expand All @@ -6622,7 +6623,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
LC_THREAD_data.SetByteOrder(byte_order);
}
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
ThreadSP thread_sp = thread_list.at(thread_idx);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Replace these three lines with:

for (ThreadSP thread_sp : thread_list) {

No need to use indexes before since we have an STL container which supports iteration.

if (thread_sp) {
switch (mach_header.cputype) {
case llvm::MachO::CPU_TYPE_ARM64:
Expand Down Expand Up @@ -6730,7 +6731,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
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));
ThreadSP thread_sp = thread_list.at(thread_idx);
Copy link
Collaborator

Choose a reason for hiding this comment

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

for (ThreadSP thread_sp : thread_list) {

StructuredData::DictionarySP thread(
std::make_shared<StructuredData::Dictionary>());
thread->AddIntegerItem("thread_id", thread_sp->GetID());
Expand Down
56 changes: 27 additions & 29 deletions lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,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 +603,17 @@ 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();
const uint32_t num_threads = thread_list.size();
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove

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));
ThreadSP thread_sp = thread_list.at(thread_idx);
Copy link
Collaborator

Choose a reason for hiding this comment

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

for (ThreadSP thread_sp : thread_list) {

RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());

if (!reg_ctx_sp) {
Expand Down Expand Up @@ -819,7 +820,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 +829,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 +858,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
10 changes: 7 additions & 3 deletions lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ lldb_private::Status WriteString(const std::string &to_write,
class MinidumpFileBuilder {
public:
MinidumpFileBuilder(lldb::FileUP &&core_file,
const lldb::ProcessSP &process_sp)
: m_process_sp(process_sp), m_core_file(std::move(core_file)){};
const lldb::ProcessSP &process_sp,
const lldb_private::SaveCoreOptions &save_core_options)
: m_process_sp(process_sp), m_core_file(std::move(core_file)),
m_save_core_options(save_core_options){};

MinidumpFileBuilder(const MinidumpFileBuilder &) = delete;
MinidumpFileBuilder &operator=(const MinidumpFileBuilder &) = delete;
Expand All @@ -103,7 +105,7 @@ class MinidumpFileBuilder {
// Add Exception streams for any threads that stopped with exceptions.
lldb_private::Status AddExceptions();
// Add MemoryList stream, containing dumps of important memory segments
lldb_private::Status AddMemoryList(lldb::SaveCoreStyle core_style);
lldb_private::Status AddMemoryList();
// Add MiscInfo stream, mainly providing ProcessId
lldb_private::Status AddMiscInfo();
// Add informative files about a Linux process
Expand Down Expand Up @@ -163,7 +165,9 @@ class MinidumpFileBuilder {
// to duplicate it in the exception data.
std::unordered_map<lldb::tid_t, llvm::minidump::LocationDescriptor>
m_tid_to_reg_ctx;
std::unordered_set<lldb::addr_t> m_saved_stack_ranges;
lldb::FileUP m_core_file;
lldb_private::SaveCoreOptions m_save_core_options;
};

#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,
error = maybe_core_file.takeError();
return false;
}
MinidumpFileBuilder builder(std::move(maybe_core_file.get()), process_sp);
MinidumpFileBuilder builder(std::move(maybe_core_file.get()), process_sp,
options);

Log *log = GetLog(LLDBLog::Object);
error = builder.AddHeaderAndCalculateDirectories();
Expand Down Expand Up @@ -121,7 +122,7 @@ bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp,

// Note: add memory HAS to be the last thing we do. It can overflow into 64b
// land and many RVA's only support 32b
error = builder.AddMemoryList(core_style);
error = builder.AddMemoryList();
if (error.Fail()) {
LLDB_LOGF(log, "AddMemoryList failed: %s", error.AsCString());
return false;
Expand Down
Loading
Loading