-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb-dap] Creating protocol types for setExceptionBreakpoints. #144153
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
Conversation
This adds new types for setExceptionBreakpoints and adds support for `supportsExceptionFilterOptions`, which allows exception breakpoints to set a condition.
@llvm/pr-subscribers-lldb Author: John Harrison (ashgti) ChangesThis adds new types for setExceptionBreakpoints and adds support for 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:
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
-@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]
|
bool m_is_throw; | ||
bool m_is_catch; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about an enum value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, created an enum. Thats hopefully more clear than the set of bools.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢 it
…#144153) 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.
…#144153) 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.
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.