1dda28197Spatrick //===-- LanguageRuntime.cpp -----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Target/LanguageRuntime.h"
10061da546Spatrick #include "lldb/Core/PluginManager.h"
11061da546Spatrick #include "lldb/Core/SearchFilter.h"
12061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
13061da546Spatrick #include "lldb/Target/Language.h"
14061da546Spatrick #include "lldb/Target/Target.h"
15061da546Spatrick
16061da546Spatrick using namespace lldb;
17061da546Spatrick using namespace lldb_private;
18061da546Spatrick
19061da546Spatrick char LanguageRuntime::ID = 0;
20061da546Spatrick
ExceptionSearchFilter(const lldb::TargetSP & target_sp,lldb::LanguageType language,bool update_module_list)21061da546Spatrick ExceptionSearchFilter::ExceptionSearchFilter(const lldb::TargetSP &target_sp,
22061da546Spatrick lldb::LanguageType language,
23061da546Spatrick bool update_module_list)
24061da546Spatrick : SearchFilter(target_sp, FilterTy::Exception), m_language(language),
25061da546Spatrick m_language_runtime(nullptr), m_filter_sp() {
26061da546Spatrick if (update_module_list)
27061da546Spatrick UpdateModuleListIfNeeded();
28061da546Spatrick }
29061da546Spatrick
ModulePasses(const lldb::ModuleSP & module_sp)30061da546Spatrick bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) {
31061da546Spatrick UpdateModuleListIfNeeded();
32061da546Spatrick if (m_filter_sp)
33061da546Spatrick return m_filter_sp->ModulePasses(module_sp);
34061da546Spatrick return false;
35061da546Spatrick }
36061da546Spatrick
ModulePasses(const FileSpec & spec)37061da546Spatrick bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) {
38061da546Spatrick UpdateModuleListIfNeeded();
39061da546Spatrick if (m_filter_sp)
40061da546Spatrick return m_filter_sp->ModulePasses(spec);
41061da546Spatrick return false;
42061da546Spatrick }
43061da546Spatrick
Search(Searcher & searcher)44061da546Spatrick void ExceptionSearchFilter::Search(Searcher &searcher) {
45061da546Spatrick UpdateModuleListIfNeeded();
46061da546Spatrick if (m_filter_sp)
47061da546Spatrick m_filter_sp->Search(searcher);
48061da546Spatrick }
49061da546Spatrick
GetDescription(Stream * s)50061da546Spatrick void ExceptionSearchFilter::GetDescription(Stream *s) {
51061da546Spatrick UpdateModuleListIfNeeded();
52061da546Spatrick if (m_filter_sp)
53061da546Spatrick m_filter_sp->GetDescription(s);
54061da546Spatrick }
55061da546Spatrick
UpdateModuleListIfNeeded()56061da546Spatrick void ExceptionSearchFilter::UpdateModuleListIfNeeded() {
57061da546Spatrick ProcessSP process_sp(m_target_sp->GetProcessSP());
58061da546Spatrick if (process_sp) {
59061da546Spatrick bool refreash_filter = !m_filter_sp;
60061da546Spatrick if (m_language_runtime == nullptr) {
61061da546Spatrick m_language_runtime = process_sp->GetLanguageRuntime(m_language);
62061da546Spatrick refreash_filter = true;
63061da546Spatrick } else {
64061da546Spatrick LanguageRuntime *language_runtime =
65061da546Spatrick process_sp->GetLanguageRuntime(m_language);
66061da546Spatrick if (m_language_runtime != language_runtime) {
67061da546Spatrick m_language_runtime = language_runtime;
68061da546Spatrick refreash_filter = true;
69061da546Spatrick }
70061da546Spatrick }
71061da546Spatrick
72061da546Spatrick if (refreash_filter && m_language_runtime) {
73061da546Spatrick m_filter_sp = m_language_runtime->CreateExceptionSearchFilter();
74061da546Spatrick }
75061da546Spatrick } else {
76061da546Spatrick m_filter_sp.reset();
77061da546Spatrick m_language_runtime = nullptr;
78061da546Spatrick }
79061da546Spatrick }
80061da546Spatrick
DoCreateCopy()81dda28197Spatrick SearchFilterSP ExceptionSearchFilter::DoCreateCopy() {
82061da546Spatrick return SearchFilterSP(
83061da546Spatrick new ExceptionSearchFilter(TargetSP(), m_language, false));
84061da546Spatrick }
85061da546Spatrick
CreateFromStructuredData(Target & target,const StructuredData::Dictionary & data_dict,Status & error)86061da546Spatrick SearchFilter *ExceptionSearchFilter::CreateFromStructuredData(
87061da546Spatrick Target &target, const StructuredData::Dictionary &data_dict,
88061da546Spatrick Status &error) {
89061da546Spatrick SearchFilter *result = nullptr;
90061da546Spatrick return result;
91061da546Spatrick }
92061da546Spatrick
SerializeToStructuredData()93061da546Spatrick StructuredData::ObjectSP ExceptionSearchFilter::SerializeToStructuredData() {
94061da546Spatrick StructuredData::ObjectSP result_sp;
95061da546Spatrick
96061da546Spatrick return result_sp;
97061da546Spatrick }
98061da546Spatrick
99061da546Spatrick // The Target is the one that knows how to create breakpoints, so this function
100061da546Spatrick // is meant to be used either by the target or internally in
101061da546Spatrick // Set/ClearExceptionBreakpoints.
102061da546Spatrick class ExceptionBreakpointResolver : public BreakpointResolver {
103061da546Spatrick public:
ExceptionBreakpointResolver(lldb::LanguageType language,bool catch_bp,bool throw_bp)104061da546Spatrick ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp,
105061da546Spatrick bool throw_bp)
106061da546Spatrick : BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver),
107*f6aab3d8Srobert m_language(language), m_catch_bp(catch_bp), m_throw_bp(throw_bp) {}
108061da546Spatrick
109061da546Spatrick ~ExceptionBreakpointResolver() override = default;
110061da546Spatrick
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)111061da546Spatrick Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
112061da546Spatrick SymbolContext &context,
113061da546Spatrick Address *addr) override {
114061da546Spatrick
115061da546Spatrick if (SetActualResolver())
116061da546Spatrick return m_actual_resolver_sp->SearchCallback(filter, context, addr);
117061da546Spatrick else
118061da546Spatrick return eCallbackReturnStop;
119061da546Spatrick }
120061da546Spatrick
GetDepth()121061da546Spatrick lldb::SearchDepth GetDepth() override {
122061da546Spatrick if (SetActualResolver())
123061da546Spatrick return m_actual_resolver_sp->GetDepth();
124061da546Spatrick else
125061da546Spatrick return lldb::eSearchDepthTarget;
126061da546Spatrick }
127061da546Spatrick
GetDescription(Stream * s)128061da546Spatrick void GetDescription(Stream *s) override {
129061da546Spatrick Language *language_plugin = Language::FindPlugin(m_language);
130061da546Spatrick if (language_plugin)
131061da546Spatrick language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp,
132061da546Spatrick *s);
133061da546Spatrick else
134061da546Spatrick Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp,
135061da546Spatrick *s);
136061da546Spatrick
137061da546Spatrick SetActualResolver();
138061da546Spatrick if (m_actual_resolver_sp) {
139061da546Spatrick s->Printf(" using: ");
140061da546Spatrick m_actual_resolver_sp->GetDescription(s);
141061da546Spatrick } else
142061da546Spatrick s->Printf(" the correct runtime exception handler will be determined "
143061da546Spatrick "when you run");
144061da546Spatrick }
145061da546Spatrick
Dump(Stream * s) const146061da546Spatrick void Dump(Stream *s) const override {}
147061da546Spatrick
148061da546Spatrick /// Methods for support type inquiry through isa, cast, and dyn_cast:
classof(const BreakpointResolverName *)149061da546Spatrick static inline bool classof(const BreakpointResolverName *) { return true; }
classof(const BreakpointResolver * V)150061da546Spatrick static inline bool classof(const BreakpointResolver *V) {
151061da546Spatrick return V->getResolverID() == BreakpointResolver::ExceptionResolver;
152061da546Spatrick }
153061da546Spatrick
154061da546Spatrick protected:
CopyForBreakpoint(BreakpointSP & breakpoint)155dda28197Spatrick BreakpointResolverSP CopyForBreakpoint(BreakpointSP &breakpoint) override {
156061da546Spatrick BreakpointResolverSP ret_sp(
157061da546Spatrick new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
158dda28197Spatrick ret_sp->SetBreakpoint(breakpoint);
159061da546Spatrick return ret_sp;
160061da546Spatrick }
161061da546Spatrick
SetActualResolver()162061da546Spatrick bool SetActualResolver() {
163dda28197Spatrick BreakpointSP breakpoint_sp = GetBreakpoint();
164dda28197Spatrick if (breakpoint_sp) {
165dda28197Spatrick ProcessSP process_sp = breakpoint_sp->GetTarget().GetProcessSP();
166061da546Spatrick if (process_sp) {
167061da546Spatrick bool refreash_resolver = !m_actual_resolver_sp;
168061da546Spatrick if (m_language_runtime == nullptr) {
169061da546Spatrick m_language_runtime = process_sp->GetLanguageRuntime(m_language);
170061da546Spatrick refreash_resolver = true;
171061da546Spatrick } else {
172061da546Spatrick LanguageRuntime *language_runtime =
173061da546Spatrick process_sp->GetLanguageRuntime(m_language);
174061da546Spatrick if (m_language_runtime != language_runtime) {
175061da546Spatrick m_language_runtime = language_runtime;
176061da546Spatrick refreash_resolver = true;
177061da546Spatrick }
178061da546Spatrick }
179061da546Spatrick
180061da546Spatrick if (refreash_resolver && m_language_runtime) {
181061da546Spatrick m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver(
182dda28197Spatrick breakpoint_sp, m_catch_bp, m_throw_bp);
183061da546Spatrick }
184061da546Spatrick } else {
185061da546Spatrick m_actual_resolver_sp.reset();
186061da546Spatrick m_language_runtime = nullptr;
187061da546Spatrick }
188061da546Spatrick } else {
189061da546Spatrick m_actual_resolver_sp.reset();
190061da546Spatrick m_language_runtime = nullptr;
191061da546Spatrick }
192061da546Spatrick return (bool)m_actual_resolver_sp;
193061da546Spatrick }
194061da546Spatrick
195061da546Spatrick lldb::BreakpointResolverSP m_actual_resolver_sp;
196061da546Spatrick lldb::LanguageType m_language;
197*f6aab3d8Srobert LanguageRuntime *m_language_runtime = nullptr;
198061da546Spatrick bool m_catch_bp;
199061da546Spatrick bool m_throw_bp;
200061da546Spatrick };
201061da546Spatrick
FindPlugin(Process * process,lldb::LanguageType language)202061da546Spatrick LanguageRuntime *LanguageRuntime::FindPlugin(Process *process,
203061da546Spatrick lldb::LanguageType language) {
204061da546Spatrick LanguageRuntimeCreateInstance create_callback;
205061da546Spatrick for (uint32_t idx = 0;
206061da546Spatrick (create_callback =
207061da546Spatrick PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
208061da546Spatrick nullptr;
209061da546Spatrick ++idx) {
210be691f3bSpatrick if (LanguageRuntime *runtime = create_callback(process, language))
211be691f3bSpatrick return runtime;
212061da546Spatrick }
213061da546Spatrick return nullptr;
214061da546Spatrick }
215061da546Spatrick
LanguageRuntime(Process * process)216be691f3bSpatrick LanguageRuntime::LanguageRuntime(Process *process) : Runtime(process) {}
217061da546Spatrick
218061da546Spatrick BreakpointPreconditionSP
GetExceptionPrecondition(LanguageType language,bool throw_bp)219061da546Spatrick LanguageRuntime::GetExceptionPrecondition(LanguageType language,
220061da546Spatrick bool throw_bp) {
221061da546Spatrick LanguageRuntimeCreateInstance create_callback;
222061da546Spatrick for (uint32_t idx = 0;
223061da546Spatrick (create_callback =
224061da546Spatrick PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
225061da546Spatrick nullptr;
226061da546Spatrick idx++) {
227061da546Spatrick if (auto precondition_callback =
228061da546Spatrick PluginManager::GetLanguageRuntimeGetExceptionPreconditionAtIndex(
229061da546Spatrick idx)) {
230061da546Spatrick if (BreakpointPreconditionSP precond =
231061da546Spatrick precondition_callback(language, throw_bp))
232061da546Spatrick return precond;
233061da546Spatrick }
234061da546Spatrick }
235061da546Spatrick return BreakpointPreconditionSP();
236061da546Spatrick }
237061da546Spatrick
CreateExceptionBreakpoint(Target & target,lldb::LanguageType language,bool catch_bp,bool throw_bp,bool is_internal)238061da546Spatrick BreakpointSP LanguageRuntime::CreateExceptionBreakpoint(
239061da546Spatrick Target &target, lldb::LanguageType language, bool catch_bp, bool throw_bp,
240061da546Spatrick bool is_internal) {
241061da546Spatrick BreakpointResolverSP resolver_sp(
242061da546Spatrick new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
243061da546Spatrick SearchFilterSP filter_sp(
244061da546Spatrick new ExceptionSearchFilter(target.shared_from_this(), language));
245061da546Spatrick bool hardware = false;
246061da546Spatrick bool resolve_indirect_functions = false;
247061da546Spatrick BreakpointSP exc_breakpt_sp(
248061da546Spatrick target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware,
249061da546Spatrick resolve_indirect_functions));
250061da546Spatrick if (exc_breakpt_sp) {
251061da546Spatrick if (auto precond = GetExceptionPrecondition(language, throw_bp))
252061da546Spatrick exc_breakpt_sp->SetPrecondition(precond);
253061da546Spatrick
254061da546Spatrick if (is_internal)
255061da546Spatrick exc_breakpt_sp->SetBreakpointKind("exception");
256061da546Spatrick }
257061da546Spatrick
258061da546Spatrick return exc_breakpt_sp;
259061da546Spatrick }
260061da546Spatrick
261be691f3bSpatrick UnwindPlanSP
GetRuntimeUnwindPlan(Thread & thread,RegisterContext * regctx,bool & behaves_like_zeroth_frame)262be691f3bSpatrick LanguageRuntime::GetRuntimeUnwindPlan(Thread &thread, RegisterContext *regctx,
263be691f3bSpatrick bool &behaves_like_zeroth_frame) {
264be691f3bSpatrick ProcessSP process_sp = thread.GetProcess();
265be691f3bSpatrick if (!process_sp.get())
266be691f3bSpatrick return UnwindPlanSP();
267be691f3bSpatrick if (process_sp->GetDisableLangRuntimeUnwindPlans() == true)
268be691f3bSpatrick return UnwindPlanSP();
269be691f3bSpatrick for (const lldb::LanguageType lang_type : Language::GetSupportedLanguages()) {
270be691f3bSpatrick if (LanguageRuntime *runtime = process_sp->GetLanguageRuntime(lang_type)) {
271be691f3bSpatrick UnwindPlanSP plan_sp = runtime->GetRuntimeUnwindPlan(
272be691f3bSpatrick process_sp, regctx, behaves_like_zeroth_frame);
273be691f3bSpatrick if (plan_sp.get())
274be691f3bSpatrick return plan_sp;
275be691f3bSpatrick }
276be691f3bSpatrick }
277be691f3bSpatrick return UnwindPlanSP();
278be691f3bSpatrick }
279be691f3bSpatrick
InitializeCommands(CommandObject * parent)280061da546Spatrick void LanguageRuntime::InitializeCommands(CommandObject *parent) {
281061da546Spatrick if (!parent)
282061da546Spatrick return;
283061da546Spatrick
284061da546Spatrick if (!parent->IsMultiwordObject())
285061da546Spatrick return;
286061da546Spatrick
287061da546Spatrick LanguageRuntimeCreateInstance create_callback;
288061da546Spatrick
289061da546Spatrick for (uint32_t idx = 0;
290061da546Spatrick (create_callback =
291061da546Spatrick PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
292061da546Spatrick nullptr;
293061da546Spatrick ++idx) {
294061da546Spatrick if (LanguageRuntimeGetCommandObject command_callback =
295061da546Spatrick PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) {
296061da546Spatrick CommandObjectSP command =
297061da546Spatrick command_callback(parent->GetCommandInterpreter());
298061da546Spatrick if (command) {
299061da546Spatrick // the CommandObject vended by a Language plugin cannot be created once
300061da546Spatrick // and cached because we may create multiple debuggers and need one
301061da546Spatrick // instance of the command each - the implementing function is meant to
302061da546Spatrick // create a new instance of the command each time it is invoked.
303061da546Spatrick parent->LoadSubCommand(command->GetCommandName().str().c_str(), command);
304061da546Spatrick }
305061da546Spatrick }
306061da546Spatrick }
307061da546Spatrick }
308