clayborg created this revision. clayborg added reviewers: labath, aprantl, JDevlieghere, jingham, jasonmolenda. Herald added subscribers: jfb, mgorny, emaste. clayborg requested review of this revision. Herald added subscribers: lldb-commits, MaskRay. Herald added a project: LLDB.
LLDB can often appear deadlocked to users that use IDEs when it is indexing DWARF, or parsing symbol tables. These long running operations can make a debug session appear to be doing nothing even though a lot of work is going on inside LLDB. This patch adds a public API to install a progress callback that will allow IDEs and other tools to create an activity window that can show users what is going on and keep them informed of expensive operations that are going on inside LLDB. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D97739 Files: lldb/include/lldb/API/SBDebugger.h lldb/include/lldb/Core/Progress.h lldb/include/lldb/lldb-types.h lldb/source/API/SBDebugger.cpp lldb/source/Core/CMakeLists.txt lldb/source/Core/Progress.cpp lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -16,6 +16,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/Core/StreamFile.h" #include "lldb/Core/Value.h" @@ -466,6 +467,10 @@ void SymbolFileDWARF::InitializeObject() { Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + Progress progress( + UINT64_MAX, "Indexing DWARF for %s", + GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>")); + if (!GetGlobalPluginProperties()->IgnoreFileIndexes()) { DWARFDataExtractor apple_names, apple_namespaces, apple_types, apple_objc; LoadSectionData(eSectionTypeDWARFAppleNames, apple_names); Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -17,6 +17,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/Core/StreamFile.h" #include "lldb/Host/Host.h" @@ -1893,9 +1894,9 @@ filename = first_section_sp->GetObjectFile()->GetFileSpec().GetPath(); Host::SystemLog(Host::eSystemLogError, - "error: unable to find section %d for a symbol in %s, corrupt file?\n", - n_sect, - filename.c_str()); + "error: unable to find section %d for a symbol in " + "%s, corrupt file?\n", + n_sect, filename.c_str()); } } if (m_section_infos[n_sect].vm_range.Contains(file_addr)) { @@ -2167,6 +2168,9 @@ if (!module_sp) return 0; + Progress progress(UINT64_MAX, "Parsing symbol table for %s", + m_file.GetFilename().AsCString("<Unknown>")); + struct symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0}; struct linkedit_data_command function_starts_load_command = {0, 0, 0, 0}; struct dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Index: lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -16,6 +16,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/Host/FileSystem.h" #include "lldb/Host/LZMA.h" @@ -1861,7 +1862,7 @@ // unified section list. if (GetType() != eTypeDebugInfo) unified_section_list = *m_sections_up; - + // If there's a .gnu_debugdata section, we'll try to read the .symtab that's // embedded in there and replace the one in the original object file (if any). // If there's none in the orignal object file, we add it to it. @@ -1879,7 +1880,7 @@ unified_section_list.AddSection(symtab_section_sp); } } - } + } } std::shared_ptr<ObjectFileELF> ObjectFileELF::GetGnuDebugDataObjectFile() { @@ -1923,7 +1924,7 @@ ArchSpec spec = m_gnu_debug_data_object_file->GetArchitecture(); if (spec && m_gnu_debug_data_object_file->SetModulesArchitecture(spec)) return m_gnu_debug_data_object_file; - + return nullptr; } @@ -2707,6 +2708,9 @@ if (!module_sp) return nullptr; + Progress progress(UINT64_MAX, "Parsing symbol table for %s", + m_file.GetFilename().AsCString("<Unknown>")); + // We always want to use the main object file so we (hopefully) only have one // cached copy of our symtab, dynamic sections, etc. ObjectFile *module_obj_file = module_sp->GetObjectFile(); Index: lldb/source/Core/Progress.cpp =================================================================== --- /dev/null +++ lldb/source/Core/Progress.cpp @@ -0,0 +1,50 @@ +//===-- Progress.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Progress.h" + +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +Progress::Progress(uint64_t total, const char *format, ...) + : m_message(), m_completed(0), m_total(total) { + StreamString message; + va_list args; + va_start(args, format); + message.PrintfVarArg(format, args); + va_end(args); + m_message = ConstString(message.GetString()); + ReportProgress(m_message, 0, m_total); +} + +Progress::~Progress() { + // Make sure to always report progress completed when this object is + // destructed + ReportProgress(m_message, m_total, m_total); +} + +void Progress::Increment(uint64_t amount) { + m_completed += amount; + ReportProgress(m_message, m_completed, m_total); +} + +lldb::ProgressCallback Progress::g_callback = nullptr; +void *Progress::g_callback_baton = nullptr; + +void Progress::SetProgressCallback(ProgressCallback callback, void *baton) { + g_callback = callback; + g_callback_baton = baton; +} + +void Progress::ReportProgress(ConstString message, uint64_t completed, + uint64_t total) { + if (g_callback) + g_callback(message.GetCString(), completed, total, g_callback_baton); +} Index: lldb/source/Core/CMakeLists.txt =================================================================== --- lldb/source/Core/CMakeLists.txt +++ lldb/source/Core/CMakeLists.txt @@ -44,6 +44,7 @@ ModuleList.cpp Opcode.cpp PluginManager.cpp + Progress.cpp RichManglingContext.cpp SearchFilter.cpp Section.cpp Index: lldb/source/API/SBDebugger.cpp =================================================================== --- lldb/source/API/SBDebugger.cpp +++ lldb/source/API/SBDebugger.cpp @@ -38,6 +38,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/DataFormatters/DataVisualization.h" @@ -251,6 +252,10 @@ ModuleList::RemoveOrphanSharedModules(mandatory); } +void SBDebugger::SetProgressCallback(ProgressCallback callback, void *baton) { + Progress::SetProgressCallback(callback, baton); +} + bool SBDebugger::IsValid() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBDebugger, IsValid); return this->operator bool(); @@ -808,23 +813,25 @@ // The version of CreateTarget that takes an ArchSpec won't accept an // empty ArchSpec, so when the arch hasn't been specified, we need to // call the target triple version. - error = m_opaque_sp->GetTargetList().CreateTarget(*m_opaque_sp, filename, - arch_cstr, eLoadDependentsYes, nullptr, target_sp); + error = m_opaque_sp->GetTargetList().CreateTarget( + *m_opaque_sp, filename, arch_cstr, eLoadDependentsYes, nullptr, + target_sp); } else { PlatformSP platform_sp = m_opaque_sp->GetPlatformList() .GetSelectedPlatform(); - ArchSpec arch = Platform::GetAugmentedArchSpec(platform_sp.get(), - arch_cstr); + ArchSpec arch = + Platform::GetAugmentedArchSpec(platform_sp.get(), arch_cstr); if (arch.IsValid()) - error = m_opaque_sp->GetTargetList().CreateTarget(*m_opaque_sp, filename, - arch, eLoadDependentsYes, platform_sp, target_sp); + error = m_opaque_sp->GetTargetList().CreateTarget( + *m_opaque_sp, filename, arch, eLoadDependentsYes, platform_sp, + target_sp); else error.SetErrorStringWithFormat("invalid arch_cstr: %s", arch_cstr); } if (error.Success()) sb_target.SetSP(target_sp); } - + LLDB_LOGF(log, "SBDebugger(%p)::CreateTargetWithFileAndArch (filename=\"%s\", " "arch=%s) => SBTarget(%p)", Index: lldb/include/lldb/lldb-types.h =================================================================== --- lldb/include/lldb/lldb-types.h +++ lldb/include/lldb/lldb-types.h @@ -73,6 +73,8 @@ void *baton, const char **argv, lldb_private::CommandReturnObject &result); typedef bool (*ExpressionCancelCallback)(ExpressionEvaluationPhase phase, void *baton); +typedef void (*ProgressCallback)(const char *message, uint64_t completed, + uint64_t total, void *baton); } // namespace lldb #define LLDB_INVALID_PROCESS ((lldb::process_t)-1) Index: lldb/include/lldb/Core/Progress.h =================================================================== --- /dev/null +++ lldb/include/lldb/Core/Progress.h @@ -0,0 +1,38 @@ +//===-- Progress.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_CORE_PROGRESS_H +#define LLDB_CORE_PROGRESS_H + +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-types.h" +#include <atomic> + +namespace lldb_private { +class Progress { +public: + Progress(uint64_t total, const char *format, ...) + __attribute__((format(printf, 3, 4))); + ~Progress(); + void Increment(uint64_t amount = 1); + + static void SetProgressCallback(lldb::ProgressCallback callback, void *baton); + +private: + static void ReportProgress(ConstString message, uint64_t completed, + uint64_t total); + static lldb::ProgressCallback g_callback; + static void *g_callback_baton; + ConstString m_message; + std::atomic<uint32_t> m_completed; + const uint64_t m_total; +}; + +} // namespace lldb_private + +#endif // LLDB_CORE_PROGRESS_H Index: lldb/include/lldb/API/SBDebugger.h =================================================================== --- lldb/include/lldb/API/SBDebugger.h +++ lldb/include/lldb/API/SBDebugger.h @@ -62,6 +62,8 @@ static void MemoryPressureDetected(); + static void SetProgressCallback(ProgressCallback callback, void *baton); + explicit operator bool() const; bool IsValid() const;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits