[Lldb-commits] [lldb] [lldb-dap] Creating protocol types for setExceptionBreakpoints. (PR #144153)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 13 12:50:47 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: John Harrison (ashgti)
<details>
<summary>Changes</summary>
This adds new types for setExceptionBreakpoints and adds support for `supportsExceptionFilterOptions`, which allows exception breakpoints to set a condition.
While testing this, I noticed that obj-c exception catch breakpoints may not be working correctly in lldb-dap.
---
Patch is 42.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144153.diff
18 Files Affected:
- (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+5-1)
- (modified) lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py (+4-7)
- (modified) lldb/test/API/tools/lldb-dap/exception/objc/Makefile (+1-1)
- (modified) lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py (+38-1)
- (modified) lldb/test/API/tools/lldb-dap/exception/objc/main.m (+9-3)
- (modified) lldb/tools/lldb-dap/DAP.cpp (+71-85)
- (modified) lldb/tools/lldb-dap/DAP.h (+2-2)
- (modified) lldb/tools/lldb-dap/ExceptionBreakpoint.cpp (+17-8)
- (modified) lldb/tools/lldb-dap/ExceptionBreakpoint.h (+7-3)
- (modified) lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp (-1)
- (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+11-4)
- (modified) lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp (+41-66)
- (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+3)
- (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp (+14)
- (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.h (+50)
- (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+31-13)
- (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+26-7)
- (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+84-25)
``````````diff
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index 9786678aa53f9..c1108da17123b 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -1050,8 +1050,12 @@ def request_setBreakpoints(self, source: Source, line_array, data=None):
self._update_verified_breakpoints(response["body"]["breakpoints"])
return response
- def request_setExceptionBreakpoints(self, filters):
+ def request_setExceptionBreakpoints(
+ self, *, filters: list[str] = [], filter_options: list[dict] = []
+ ):
args_dict = {"filters": filters}
+ if filter_options:
+ args_dict["filterOptions"] = filter_options
command_dict = {
"command": "setExceptionBreakpoints",
"type": "request",
diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py
index 4dc8c5b3c7ded..4ca733a9a59ca 100644
--- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py
+++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py
@@ -1,16 +1,12 @@
"""
-Test lldb-dap setBreakpoints request
+Test lldb-dap setExceptionBreakpoints request
"""
-
-import dap_server
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
import lldbdap_testcase
- at skip("Temporarily disable the breakpoint tests")
class TestDAP_setExceptionBreakpoints(lldbdap_testcase.DAPTestCaseBase):
@skipIfWindows
def test_functionality(self):
@@ -33,8 +29,9 @@ def test_functionality(self):
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
- filters = ["cpp_throw", "cpp_catch"]
- response = self.dap_server.request_setExceptionBreakpoints(filters)
+ response = self.dap_server.request_setExceptionBreakpoints(
+ filters=["cpp_throw", "cpp_catch"],
+ )
if response:
self.assertTrue(response["success"])
diff --git a/lldb/test/API/tools/lldb-dap/exception/objc/Makefile b/lldb/test/API/tools/lldb-dap/exception/objc/Makefile
index 9b6528337cb9d..17e6dc76699ab 100644
--- a/lldb/test/API/tools/lldb-dap/exception/objc/Makefile
+++ b/lldb/test/API/tools/lldb-dap/exception/objc/Makefile
@@ -1,6 +1,6 @@
OBJC_SOURCES := main.m
-CFLAGS_EXTRAS := -w
+CFLAGS_EXTRAS := -w -fobjc-exceptions
USE_SYSTEM_STDLIB := 1
diff --git a/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py b/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py
index 777d55f48e850..ddedf7a6de8c6 100644
--- a/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py
+++ b/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py
@@ -2,7 +2,6 @@
Test exception behavior in DAP with obj-c throw.
"""
-
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
import lldbdap_testcase
@@ -25,3 +24,41 @@ def test_stopped_description(self):
exception_details = exception_info["details"]
self.assertRegex(exception_details["message"], "SomeReason")
self.assertRegex(exception_details["stackTrace"], "main.m")
+
+ @skipUnlessDarwin
+ def test_break_on_throw_and_catch(self):
+ """
+ Test that breakpoints on exceptions work as expected.
+ """
+ program = self.getBuildArtifact("a.out")
+ self.build_and_launch(program)
+
+ response = self.dap_server.request_setExceptionBreakpoints(
+ filter_options=[
+ {
+ "filterId": "objc_throw",
+ "condition": '[[((NSException *)$arg1) name] isEqual:@"ThrownException"]',
+ },
+ ]
+ )
+ if response:
+ self.assertTrue(response["success"])
+
+ self.continue_to_exception_breakpoint("Objective-C Throw")
+
+ # FIXME: Catching objc exceptions do not appear to be working.
+ # Xcode appears to set a breakpoint on '__cxa_begin_catch' for objc
+ # catch, which is different than
+ # SBTarget::BreakpointCreateForException(eLanguageObjectiveC, /*catch_bp=*/true, /*throw_bp=*/false);
+ # self.continue_to_exception_breakpoint("Objective-C Catch")
+
+ self.do_continue()
+
+ self.assertTrue(self.verify_stop_exception_info("signal SIGABRT"))
+ exception_info = self.get_exceptionInfo()
+ self.assertEqual(exception_info["breakMode"], "always")
+ self.assertEqual(exception_info["description"], "signal SIGABRT")
+ self.assertEqual(exception_info["exceptionId"], "signal")
+ exception_details = exception_info["details"]
+ self.assertRegex(exception_details["message"], "SomeReason")
+ self.assertRegex(exception_details["stackTrace"], "main.m")
diff --git a/lldb/test/API/tools/lldb-dap/exception/objc/main.m b/lldb/test/API/tools/lldb-dap/exception/objc/main.m
index e8db04fb40de1..bbfa621992799 100644
--- a/lldb/test/API/tools/lldb-dap/exception/objc/main.m
+++ b/lldb/test/API/tools/lldb-dap/exception/objc/main.m
@@ -1,8 +1,14 @@
#import <Foundation/Foundation.h>
int main(int argc, char const *argv[]) {
- @throw [[NSException alloc] initWithName:@"ThrownException"
- reason:@"SomeReason"
- userInfo:nil];
+ @try {
+ NSException *e = [[NSException alloc] initWithName:@"ThrownException"
+ reason:@"SomeReason"
+ userInfo:nil];
+ @throw e;
+ } @catch (NSException *e) {
+ NSLog(@"Caught %@", e);
+ @throw; // let the process crash...
+ }
return 0;
}
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index b034c967594ba..58e0be64ba5b8 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -128,93 +128,81 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode,
DAP::~DAP() = default;
void DAP::PopulateExceptionBreakpoints() {
- llvm::call_once(init_exception_breakpoints_flag, [this]() {
- exception_breakpoints = std::vector<ExceptionBreakpoint>{};
-
- if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) {
- exception_breakpoints->emplace_back(*this, "cpp_catch", "C++ Catch",
- lldb::eLanguageTypeC_plus_plus);
- exception_breakpoints->emplace_back(*this, "cpp_throw", "C++ Throw",
- lldb::eLanguageTypeC_plus_plus);
- }
- if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) {
- exception_breakpoints->emplace_back(
- *this, "objc_catch", "Objective-C Catch", lldb::eLanguageTypeObjC);
- exception_breakpoints->emplace_back(
- *this, "objc_throw", "Objective-C Throw", lldb::eLanguageTypeObjC);
- }
- if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) {
- exception_breakpoints->emplace_back(*this, "swift_catch", "Swift Catch",
- lldb::eLanguageTypeSwift);
- exception_breakpoints->emplace_back(*this, "swift_throw", "Swift Throw",
- lldb::eLanguageTypeSwift);
+ if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) {
+ exception_breakpoints.emplace_back(*this, "cpp_catch", "C++ Catch",
+ lldb::eLanguageTypeC_plus_plus,
+ /*is_throw=*/false, /*is_catch=*/true);
+ exception_breakpoints.emplace_back(*this, "cpp_throw", "C++ Throw",
+ lldb::eLanguageTypeC_plus_plus,
+ /*is_throw=*/true, /*is_catch=*/false);
+ }
+
+ if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) {
+ exception_breakpoints.emplace_back(*this, "objc_catch", "Objective-C Catch",
+ lldb::eLanguageTypeObjC,
+ /*is_throw=*/false, /*is_catch=*/true);
+ exception_breakpoints.emplace_back(*this, "objc_throw", "Objective-C Throw",
+ lldb::eLanguageTypeObjC,
+ /*is_throw=*/true, /*is_catch=*/false);
+ }
+
+ if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) {
+ exception_breakpoints.emplace_back(*this, "swift_catch", "Swift Catch",
+ lldb::eLanguageTypeSwift,
+ /*is_throw=*/false, /*is_catch=*/true);
+ exception_breakpoints.emplace_back(*this, "swift_throw", "Swift Throw",
+ lldb::eLanguageTypeSwift,
+ /*is_throw=*/true, /*is_catch=*/false);
+ }
+
+ // Besides handling the hardcoded list of languages from above, we try to find
+ // any other languages that support exception breakpoints using the SB API.
+ for (int raw_lang = lldb::eLanguageTypeUnknown;
+ raw_lang < lldb::eNumLanguageTypes; ++raw_lang) {
+ lldb::LanguageType lang = static_cast<lldb::LanguageType>(raw_lang);
+
+ // We first discard any languages already handled above.
+ if (lldb::SBLanguageRuntime::LanguageIsCFamily(lang) ||
+ lang == lldb::eLanguageTypeSwift)
+ continue;
+
+ if (!lldb::SBDebugger::SupportsLanguage(lang))
+ continue;
+
+ const char *name = lldb::SBLanguageRuntime::GetNameForLanguageType(lang);
+ if (!name)
+ continue;
+ std::string raw_lang_name = name;
+ std::string capitalized_lang_name = capitalize(name);
+
+ if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow(lang)) {
+ const char *raw_throw_keyword =
+ lldb::SBLanguageRuntime::GetThrowKeywordForLanguage(lang);
+ std::string throw_keyword =
+ raw_throw_keyword ? raw_throw_keyword : "throw";
+
+ exception_breakpoints.emplace_back(
+ *this, raw_lang_name + "_" + throw_keyword,
+ capitalized_lang_name + " " + capitalize(throw_keyword), lang,
+ /*is_throw=*/true, /*is_catch=*/false);
}
- // Besides handling the hardcoded list of languages from above, we try to
- // find any other languages that support exception breakpoints using the
- // SB API.
- for (int raw_lang = lldb::eLanguageTypeUnknown;
- raw_lang < lldb::eNumLanguageTypes; ++raw_lang) {
- lldb::LanguageType lang = static_cast<lldb::LanguageType>(raw_lang);
-
- // We first discard any languages already handled above.
- if (lldb::SBLanguageRuntime::LanguageIsCFamily(lang) ||
- lang == lldb::eLanguageTypeSwift)
- continue;
-
- if (!lldb::SBDebugger::SupportsLanguage(lang))
- continue;
-
- const char *name = lldb::SBLanguageRuntime::GetNameForLanguageType(lang);
- if (!name)
- continue;
- std::string raw_lang_name = name;
- std::string capitalized_lang_name = capitalize(name);
-
- if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow(lang)) {
- const char *raw_throw_keyword =
- lldb::SBLanguageRuntime::GetThrowKeywordForLanguage(lang);
- std::string throw_keyword =
- raw_throw_keyword ? raw_throw_keyword : "throw";
-
- exception_breakpoints->emplace_back(
- *this, raw_lang_name + "_" + throw_keyword,
- capitalized_lang_name + " " + capitalize(throw_keyword), lang);
- }
- if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch(lang)) {
- const char *raw_catch_keyword =
- lldb::SBLanguageRuntime::GetCatchKeywordForLanguage(lang);
- std::string catch_keyword =
- raw_catch_keyword ? raw_catch_keyword : "catch";
+ if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch(lang)) {
+ const char *raw_catch_keyword =
+ lldb::SBLanguageRuntime::GetCatchKeywordForLanguage(lang);
+ std::string catch_keyword =
+ raw_catch_keyword ? raw_catch_keyword : "catch";
- exception_breakpoints->emplace_back(
- *this, raw_lang_name + "_" + catch_keyword,
- capitalized_lang_name + " " + capitalize(catch_keyword), lang);
- }
+ exception_breakpoints.emplace_back(
+ *this, raw_lang_name + "_" + catch_keyword,
+ capitalized_lang_name + " " + capitalize(catch_keyword), lang,
+ /*is_throw=*/true, /*is_catch=*/false);
}
- assert(!exception_breakpoints->empty() && "should not be empty");
- });
+ }
}
ExceptionBreakpoint *DAP::GetExceptionBreakpoint(llvm::StringRef filter) {
- // 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();
-
- for (auto &bp : *exception_breakpoints) {
+ for (auto &bp : exception_breakpoints) {
if (bp.GetFilter() == filter)
return &bp;
}
@@ -222,10 +210,7 @@ ExceptionBreakpoint *DAP::GetExceptionBreakpoint(llvm::StringRef filter) {
}
ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
- // See comment in the other GetExceptionBreakpoint().
- PopulateExceptionBreakpoints();
-
- for (auto &bp : *exception_breakpoints) {
+ for (auto &bp : exception_breakpoints) {
if (bp.GetID() == bp_id)
return &bp;
}
@@ -1117,8 +1102,9 @@ protocol::Capabilities DAP::GetCapabilities() {
}
// Available filters or options for the setExceptionBreakpoints request.
+ PopulateExceptionBreakpoints();
std::vector<protocol::ExceptionBreakpointsFilter> filters;
- for (const auto &exc_bp : *exception_breakpoints)
+ for (const auto &exc_bp : exception_breakpoints)
filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
capabilities.exceptionBreakpointFilters = std::move(filters);
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 89bc827c1141f..5ca5822f9bced 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -99,7 +99,7 @@ struct DAP {
lldb::SBBroadcaster broadcaster;
FunctionBreakpointMap function_breakpoints;
InstructionBreakpointMap instruction_breakpoints;
- std::optional<std::vector<ExceptionBreakpoint>> exception_breakpoints;
+ std::vector<ExceptionBreakpoint> exception_breakpoints;
llvm::once_flag init_exception_breakpoints_flag;
/// Map step in target id to list of function targets that user can choose.
@@ -320,7 +320,7 @@ struct DAP {
});
}
- /// The set of capablities supported by this adapter.
+ /// The set of capabilities supported by this adapter.
protocol::Capabilities GetCapabilities();
/// Debuggee will continue from stopped state.
diff --git a/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp b/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp
index 9772e7344ced6..2531291fd62cc 100644
--- a/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp
@@ -9,23 +9,32 @@
#include "ExceptionBreakpoint.h"
#include "BreakpointBase.h"
#include "DAP.h"
+#include "Protocol/ProtocolTypes.h"
#include "lldb/API/SBMutex.h"
#include "lldb/API/SBTarget.h"
#include <mutex>
+using namespace llvm;
+using namespace lldb_dap::protocol;
+
namespace lldb_dap {
-void ExceptionBreakpoint::SetBreakpoint() {
+protocol::Breakpoint ExceptionBreakpoint::SetBreakpoint(StringRef condition) {
lldb::SBMutex lock = m_dap.GetAPIMutex();
std::lock_guard<lldb::SBMutex> guard(lock);
- if (m_bp.IsValid())
- return;
- bool catch_value = m_filter.find("_catch") != std::string::npos;
- bool throw_value = m_filter.find("_throw") != std::string::npos;
- m_bp = m_dap.target.BreakpointCreateForException(m_language, catch_value,
- throw_value);
- m_bp.AddName(BreakpointBase::kDAPBreakpointLabel);
+ if (!m_bp.IsValid()) {
+ m_bp = m_dap.target.BreakpointCreateForException(m_language, m_is_catch,
+ m_is_throw);
+ m_bp.AddName(BreakpointBase::kDAPBreakpointLabel);
+ }
+
+ m_bp.SetCondition(condition.data());
+
+ protocol::Breakpoint breakpoint;
+ breakpoint.id = m_bp.GetID();
+ breakpoint.verified = m_bp.IsValid();
+ return breakpoint;
}
void ExceptionBreakpoint::ClearBreakpoint() {
diff --git a/lldb/tools/lldb-dap/ExceptionBreakpoint.h b/lldb/tools/lldb-dap/ExceptionBreakpoint.h
index 319b472a89a34..d453d5fcc4fd3 100644
--- a/lldb/tools/lldb-dap/ExceptionBreakpoint.h
+++ b/lldb/tools/lldb-dap/ExceptionBreakpoint.h
@@ -10,6 +10,7 @@
#define LLDB_TOOLS_LLDB_DAP_EXCEPTIONBREAKPOINT_H
#include "DAPForward.h"
+#include "Protocol/ProtocolTypes.h"
#include "lldb/API/SBBreakpoint.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/StringRef.h"
@@ -21,11 +22,12 @@ namespace lldb_dap {
class ExceptionBreakpoint {
public:
ExceptionBreakpoint(DAP &d, std::string f, std::string l,
- lldb::LanguageType lang)
+ lldb::LanguageType lang, bool is_throw, bool is_catch)
: m_dap(d), m_filter(std::move(f)), m_label(std::move(l)),
- m_language(lang), m_bp() {}
+ m_language(lang), m_is_throw(is_throw), m_is_catch(is_catch), m_bp() {}
- void SetBreakpoint();
+ protocol::Breakpoint SetBreakpoint() { return SetBreakpoint(""); };
+ protocol::Breakpoint SetBreakpoint(llvm::StringRef condition);
void ClearBreakpoint();
lldb::break_id_t GetID() const { return m_bp.GetID(); }
@@ -39,6 +41,8 @@ class ExceptionBreakpoint {
std::string m_filter;
std::string m_label;
lldb::LanguageType m_language;
+ bool m_is_throw;
+ bool m_is_catch;
lldb::SBBreakpoint m_bp;
};
diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
index dcd02d61ca4f4..b499a69876e2c 100644
--- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
@@ -54,7 +54,6 @@ llvm::Expected<InitializeResponse> InitializeRequestHandler::Run(
if (llvm::Error err = dap.RunPreInitCommands())
return err;
- dap.PopulateExceptionBreakpoints();
auto cmd = dap.debugger.GetCommandInterpreter().AddMultiwordCommand(
"lldb-dap", "Commands for managing lldb-dap.");
if (arguments.supportedFeatures.contains(
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index d3f231589b54c..071a44bd002ad 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -386,14 +386,21 @@ class SetBreakpointsRequestHandler
Run(const protocol::SetBreakpointsArguments &args) const override;
};
-class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler {
+class SetExceptionBreakpointsRequestHandler
+ : public RequestHandler<
+ protocol::SetExceptionBreakpointsArguments,
+ llvm::Expected<protocol::SetExceptionBreakpointsResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "setExceptionBreakpoints"; }
FeatureSet GetSupportedFeatures() const override {
- return {protocol::eAdapterFeatureExceptionOptions};
+ /// Prefer the `filterOptions` feature over the `exceptionOptions`.
+ /// exceptionOptions is not supported in VSCode, while `filterOptions` is
+ /// supported.
+ re...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/144153
More information about the lldb-commits
mailing list