Reapply PR/87550 (#94625)

Re-apply https://github.com/llvm/llvm-project/pull/87550 with fixes.

Details:
Some tests in fuchsia failed because of the newly added assertion.
This was because `GetExceptionBreakpoint()` could be called before
`g_dap.debugger` was initted.

The fix here is to just lazily populate the list in
GetExceptionBreakpoint() rather than assuming it's already been initted.
(There is some nuisance here because we can't simply just populate it in
DAP::DAP(), which is a global ctor and is called before
`SBDebugger::Initialize()` is called. )
This commit is contained in:
Vy Nguyen
2024-06-07 11:27:52 -04:00
committed by GitHub
parent e9adcc488f
commit 35fa2ded2a
7 changed files with 77 additions and 13 deletions

View File

@@ -57,6 +57,8 @@ public:
static const char *GetBroadcasterClass();
static bool SupportsLanguage(lldb::LanguageType language);
lldb::SBBroadcaster GetBroadcaster();
/// Get progress data from a SBEvent whose type is eBroadcastBitProgress.

View File

@@ -209,6 +209,7 @@ public:
// TypeSystems can support more than one language
virtual bool SupportsLanguage(lldb::LanguageType language) = 0;
static bool SupportsLanguageStatic(lldb::LanguageType language);
// Type Completion
virtual bool GetCompleteType(lldb::opaque_compiler_type_t type) = 0;

View File

@@ -1742,3 +1742,7 @@ bool SBDebugger::InterruptRequested() {
return m_opaque_sp->InterruptRequested();
return false;
}
bool SBDebugger::SupportsLanguage(lldb::LanguageType language) {
return TypeSystem::SupportsLanguageStatic(language);
}

View File

@@ -335,3 +335,14 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
}
return GetTypeSystemForLanguage(language);
}
bool TypeSystem::SupportsLanguageStatic(lldb::LanguageType language) {
if (language == eLanguageTypeUnknown)
return false;
LanguageSet languages =
PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
if (languages.Empty())
return false;
return languages[language];
}

View File

@@ -32,14 +32,7 @@ namespace lldb_dap {
DAP g_dap;
DAP::DAP()
: broadcaster("lldb-dap"),
exception_breakpoints(
{{"cpp_catch", "C++ Catch", lldb::eLanguageTypeC_plus_plus},
{"cpp_throw", "C++ Throw", lldb::eLanguageTypeC_plus_plus},
{"objc_catch", "Objective-C Catch", lldb::eLanguageTypeObjC},
{"objc_throw", "Objective-C Throw", lldb::eLanguageTypeObjC},
{"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift},
{"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}),
: broadcaster("lldb-dap"), exception_breakpoints(),
focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
enable_auto_variable_summaries(false),
enable_synthetic_child_debugging(false),
@@ -65,8 +58,51 @@ DAP::DAP()
DAP::~DAP() = default;
void DAP::PopulateExceptionBreakpoints() {
llvm::call_once(initExceptionBreakpoints, [this]() {
exception_breakpoints = {};
if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) {
exception_breakpoints->emplace_back("cpp_catch", "C++ Catch",
lldb::eLanguageTypeC_plus_plus);
exception_breakpoints->emplace_back("cpp_throw", "C++ Throw",
lldb::eLanguageTypeC_plus_plus);
}
if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) {
exception_breakpoints->emplace_back("objc_catch", "Objective-C Catch",
lldb::eLanguageTypeObjC);
exception_breakpoints->emplace_back("objc_throw", "Objective-C Throw",
lldb::eLanguageTypeObjC);
}
if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) {
exception_breakpoints->emplace_back("swift_catch", "Swift Catch",
lldb::eLanguageTypeSwift);
exception_breakpoints->emplace_back("swift_throw", "Swift Throw",
lldb::eLanguageTypeSwift);
}
});
}
ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const std::string &filter) {
for (auto &bp : exception_breakpoints) {
// PopulateExceptionBreakpoints() is called after g_dap.debugger is created
// in a request-initialize.
//
// But this GetExceptionBreakpoint() method may be called before attaching, in
// which case, we may not have populated the filter yet.
//
// We also cannot call PopulateExceptionBreakpoints() in DAP::DAP() because
// we need SBDebugger::Initialize() to have been called before this.
//
// So just calling PopulateExceptionBreakoints(),which does lazy-populating
// seems easiest. Two other options include:
// + call g_dap.PopulateExceptionBreakpoints() in lldb-dap.cpp::main()
// right after the call to SBDebugger::Initialize()
// + Just call PopulateExceptionBreakpoints() to get a fresh list everytime
// we query (a bit overkill since it's not likely to change?)
PopulateExceptionBreakpoints();
assert(exception_breakpoints.has_value() &&
"exception_breakpoints must have been populated");
for (auto &bp : *exception_breakpoints) {
if (bp.filter == filter)
return &bp;
}
@@ -74,7 +110,12 @@ ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const std::string &filter) {
}
ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
for (auto &bp : exception_breakpoints) {
// See comment in the other GetExceptionBreakpoint().
PopulateExceptionBreakpoints();
assert(exception_breakpoints.has_value() &&
"exception_breakpoints must have been populated");
for (auto &bp : *exception_breakpoints) {
if (bp.bp.GetID() == bp_id)
return &bp;
}

View File

@@ -156,7 +156,8 @@ struct DAP {
std::unique_ptr<std::ofstream> log;
llvm::StringMap<SourceBreakpointMap> source_breakpoints;
FunctionBreakpointMap function_breakpoints;
std::vector<ExceptionBreakpoint> exception_breakpoints;
std::optional<std::vector<ExceptionBreakpoint>> exception_breakpoints;
llvm::once_flag initExceptionBreakpoints;
std::vector<std::string> init_commands;
std::vector<std::string> pre_run_commands;
std::vector<std::string> post_run_commands;
@@ -228,6 +229,8 @@ struct DAP {
llvm::json::Value CreateTopLevelScopes();
void PopulateExceptionBreakpoints();
/// \return
/// Attempt to determine if an expression is a variable expression or
/// lldb command using a hueristic based on the first term of the

View File

@@ -16,6 +16,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(_WIN32)
@@ -1586,6 +1587,7 @@ void request_initialize(const llvm::json::Object &request) {
bool source_init_file = GetBoolean(arguments, "sourceInitFile", true);
g_dap.debugger = lldb::SBDebugger::Create(source_init_file, log_cb, nullptr);
g_dap.PopulateExceptionBreakpoints();
auto cmd = g_dap.debugger.GetCommandInterpreter().AddMultiwordCommand(
"lldb-dap", "Commands for managing lldb-dap.");
if (GetBoolean(arguments, "supportsStartDebuggingRequest", false)) {
@@ -1621,7 +1623,7 @@ void request_initialize(const llvm::json::Object &request) {
body.try_emplace("supportsEvaluateForHovers", true);
// Available filters or options for the setExceptionBreakpoints request.
llvm::json::Array filters;
for (const auto &exc_bp : g_dap.exception_breakpoints) {
for (const auto &exc_bp : *g_dap.exception_breakpoints) {
filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
}
body.try_emplace("exceptionBreakpointFilters", std::move(filters));
@@ -2476,7 +2478,7 @@ void request_setExceptionBreakpoints(const llvm::json::Object &request) {
// Keep a list of any exception breakpoint filter names that weren't set
// so we can clear any exception breakpoints if needed.
std::set<std::string> unset_filters;
for (const auto &bp : g_dap.exception_breakpoints)
for (const auto &bp : *g_dap.exception_breakpoints)
unset_filters.insert(bp.filter);
for (const auto &value : *filters) {