Skip to content

Commit

Permalink
[lldb] progressive progress reporting for darwin kernel/firmware (#98845
Browse files Browse the repository at this point in the history
)

When doing firmware/kernel debugging, it is frequent that binaries and
debug info need to be retrieved / downloaded, and the lack of progress
reports made for a poor experience, with lldb seemingly hung while
downloading things over the network. This PR adds progress reports to
the critical sites for these use cases.
  • Loading branch information
jasonmolenda authored Jul 17, 2024
1 parent c736ca8 commit 86ef699
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 32 deletions.
24 changes: 21 additions & 3 deletions lldb/source/Core/DynamicLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Progress.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/MemoryRegionInfo.h"
Expand Down Expand Up @@ -195,20 +196,37 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
Target &target = process->GetTarget();
Status error;

StreamString prog_str;
if (!name.empty()) {
prog_str << name.str() << " ";
}
if (uuid.IsValid())
prog_str << uuid.GetAsString();
if (value_is_offset == 0 && value != LLDB_INVALID_ADDRESS) {
prog_str << "at 0x";
prog_str.PutHex64(value);
}

if (!uuid.IsValid() && !value_is_offset) {
memory_module_sp = ReadUnnamedMemoryModule(process, value, name);

if (memory_module_sp)
if (memory_module_sp) {
uuid = memory_module_sp->GetUUID();
if (uuid.IsValid()) {
prog_str << " ";
prog_str << uuid.GetAsString();
}
}
}
ModuleSpec module_spec;
module_spec.GetUUID() = uuid;
FileSpec name_filespec(name);
if (FileSystem::Instance().Exists(name_filespec))
module_spec.GetFileSpec() = name_filespec;

if (uuid.IsValid()) {
Progress progress("Locating binary", prog_str.GetString().str());

// Has lldb already seen a module with this UUID?
// Or have external lookup enabled in DebugSymbols on macOS.
if (!module_sp)
error = ModuleList::GetSharedModule(module_spec, module_sp, nullptr,
nullptr, nullptr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Progress.h"
#include "lldb/Core/Section.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Symbol/ObjectFile.h"
Expand Down Expand Up @@ -714,7 +715,7 @@ void DynamicLoaderDarwinKernel::KextImageInfo::SetIsKernel(bool is_kernel) {
}

bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
Process *process) {
Process *process, Progress *progress) {
Log *log = GetLog(LLDBLog::DynamicLoader);
if (IsLoaded())
return true;
Expand Down Expand Up @@ -757,11 +758,37 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
const ModuleList &target_images = target.GetImages();
m_module_sp = target_images.FindModule(m_uuid);

StreamString prog_str;
// 'mach_kernel' is a fake name we make up to find kernels
// that were located by the local filesystem scan.
if (GetName() != "mach_kernel")
prog_str << GetName() << " ";
if (GetUUID().IsValid())
prog_str << GetUUID().GetAsString() << " ";
if (GetLoadAddress() != LLDB_INVALID_ADDRESS) {
prog_str << "at 0x";
prog_str.PutHex64(GetLoadAddress());
}

std::unique_ptr<Progress> progress_up;
if (progress)
progress->Increment(1, prog_str.GetString().str());
else {
if (IsKernel())
progress_up = std::make_unique<Progress>("Loading kernel",
prog_str.GetString().str());
else
progress_up = std::make_unique<Progress>("Loading kext",
prog_str.GetString().str());
}

// Search for the kext on the local filesystem via the UUID
if (!m_module_sp && m_uuid.IsValid()) {
ModuleSpec module_spec;
module_spec.GetUUID() = m_uuid;
module_spec.GetArchitecture() = target.GetArchitecture();
if (!m_uuid.IsValid())
module_spec.GetArchitecture() = target.GetArchitecture();
module_spec.GetFileSpec() = FileSpec(m_name);

// If the current platform is PlatformDarwinKernel, create a ModuleSpec
// with the filename set to be the bundle ID for this kext, e.g.
Expand All @@ -770,17 +797,9 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
// system.
PlatformSP platform_sp(target.GetPlatform());
if (platform_sp) {
static ConstString g_platform_name(
PlatformDarwinKernel::GetPluginNameStatic());
if (platform_sp->GetPluginName() == g_platform_name.GetStringRef()) {
ModuleSpec kext_bundle_module_spec(module_spec);
FileSpec kext_filespec(m_name.c_str());
FileSpecList search_paths = target.GetExecutableSearchPaths();
kext_bundle_module_spec.GetFileSpec() = kext_filespec;
platform_sp->GetSharedModule(kext_bundle_module_spec, process,
m_module_sp, &search_paths, nullptr,
nullptr);
}
FileSpecList search_paths = target.GetExecutableSearchPaths();
platform_sp->GetSharedModule(module_spec, process, m_module_sp,
&search_paths, nullptr, nullptr);
}

// Ask the Target to find this file on the local system, if possible.
Expand Down Expand Up @@ -1058,12 +1077,9 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() {
}
}
}

if (m_kernel.GetLoadAddress() != LLDB_INVALID_ADDRESS) {
if (!m_kernel.LoadImageUsingMemoryModule(m_process)) {
if (m_kernel.GetLoadAddress() != LLDB_INVALID_ADDRESS)
if (!m_kernel.LoadImageUsingMemoryModule(m_process))
m_kernel.LoadImageAtFileAddress(m_process);
}
}

// The operating system plugin gets loaded and initialized in
// LoadImageUsingMemoryModule when we discover the kernel dSYM. For a core
Expand Down Expand Up @@ -1347,19 +1363,18 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries(
std::vector<std::pair<std::string, UUID>> kexts_failed_to_load;
if (number_of_new_kexts_being_added > 0) {
ModuleList loaded_module_list;
Progress progress("Loading kext", "", number_of_new_kexts_being_added);

const uint32_t num_of_new_kexts = kext_summaries.size();
for (uint32_t new_kext = 0; new_kext < num_of_new_kexts; new_kext++) {
if (to_be_added[new_kext]) {
KextImageInfo &image_info = kext_summaries[new_kext];
bool kext_successfully_added = true;
if (load_kexts) {
if (!image_info.LoadImageUsingMemoryModule(m_process)) {
if (!image_info.LoadImageUsingMemoryModule(m_process, &progress)) {
kexts_failed_to_load.push_back(std::pair<std::string, UUID>(
kext_summaries[new_kext].GetName(),
kext_summaries[new_kext].GetUUID()));
image_info.LoadImageAtFileAddress(m_process);
kext_successfully_added = false;
}
}

Expand All @@ -1369,13 +1384,6 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries(
m_process->GetStopID() == image_info.GetProcessStopId())
loaded_module_list.AppendIfNeeded(image_info.GetModule());

if (load_kexts) {
if (kext_successfully_added)
s.Printf(".");
else
s.Printf("-");
}

if (log)
kext_summaries[new_kext].PutToLog(log);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "lldb/Host/SafeMachO.h"

#include "lldb/Core/Progress.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/FileSpec.h"
Expand Down Expand Up @@ -137,7 +138,8 @@ class DynamicLoaderDarwinKernel : public lldb_private::DynamicLoader {

bool LoadImageAtFileAddress(lldb_private::Process *process);

bool LoadImageUsingMemoryModule(lldb_private::Process *process);
bool LoadImageUsingMemoryModule(lldb_private::Process *process,
lldb_private::Progress *progress = nullptr);

bool IsLoaded() { return m_load_process_stop_id != UINT32_MAX; }

Expand Down
9 changes: 9 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Progress.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/DynamicCheckerFunctions.h"
#include "lldb/Expression/UserExpression.h"
Expand Down Expand Up @@ -2550,6 +2551,14 @@ ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec,
ModuleSP module_sp(new Module(file_spec, ArchSpec()));
if (module_sp) {
Status error;
std::unique_ptr<Progress> progress_up;
// Reading an ObjectFile from a local corefile is very fast,
// only print a progress update if we're reading from a
// live session which might go over gdb remote serial protocol.
if (IsLiveDebugSession())
progress_up = std::make_unique<Progress>(
"Reading binary from memory", file_spec.GetFilename().GetString());

ObjectFile *objfile = module_sp->GetMemoryObjectFile(
shared_from_this(), header_addr, error, size_to_read);
if (objfile)
Expand Down

0 comments on commit 86ef699

Please sign in to comment.