1 //===-- LanguageRuntime.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Target/LanguageRuntime.h"
10 #include "lldb/Core/PluginManager.h"
11 #include "lldb/Core/SearchFilter.h"
12 #include "lldb/Interpreter/CommandInterpreter.h"
13 #include "lldb/Target/Language.h"
14 #include "lldb/Target/ObjCLanguageRuntime.h"
15 #include "lldb/Target/Target.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 char LanguageRuntime::ID = 0;
21 
22 ExceptionSearchFilter::ExceptionSearchFilter(const lldb::TargetSP &target_sp,
23                                              lldb::LanguageType language,
24                                              bool update_module_list)
25     : SearchFilter(target_sp, FilterTy::Exception), m_language(language),
26       m_language_runtime(nullptr), m_filter_sp() {
27   if (update_module_list)
28     UpdateModuleListIfNeeded();
29 }
30 
31 bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) {
32   UpdateModuleListIfNeeded();
33   if (m_filter_sp)
34     return m_filter_sp->ModulePasses(module_sp);
35   return false;
36 }
37 
38 bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) {
39   UpdateModuleListIfNeeded();
40   if (m_filter_sp)
41     return m_filter_sp->ModulePasses(spec);
42   return false;
43 }
44 
45 void ExceptionSearchFilter::Search(Searcher &searcher) {
46   UpdateModuleListIfNeeded();
47   if (m_filter_sp)
48     m_filter_sp->Search(searcher);
49 }
50 
51 void ExceptionSearchFilter::GetDescription(Stream *s) {
52   UpdateModuleListIfNeeded();
53   if (m_filter_sp)
54     m_filter_sp->GetDescription(s);
55 }
56 
57 void ExceptionSearchFilter::UpdateModuleListIfNeeded() {
58   ProcessSP process_sp(m_target_sp->GetProcessSP());
59   if (process_sp) {
60     bool refreash_filter = !m_filter_sp;
61     if (m_language_runtime == nullptr) {
62       m_language_runtime = process_sp->GetLanguageRuntime(m_language);
63       refreash_filter = true;
64     } else {
65       LanguageRuntime *language_runtime =
66           process_sp->GetLanguageRuntime(m_language);
67       if (m_language_runtime != language_runtime) {
68         m_language_runtime = language_runtime;
69         refreash_filter = true;
70       }
71     }
72 
73     if (refreash_filter && m_language_runtime) {
74       m_filter_sp = m_language_runtime->CreateExceptionSearchFilter();
75     }
76   } else {
77     m_filter_sp.reset();
78     m_language_runtime = nullptr;
79   }
80 }
81 
82 SearchFilterSP
83 ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) {
84   return SearchFilterSP(
85       new ExceptionSearchFilter(TargetSP(), m_language, false));
86 }
87 
88 SearchFilter *ExceptionSearchFilter::CreateFromStructuredData(
89     Target &target, const StructuredData::Dictionary &data_dict,
90     Status &error) {
91   SearchFilter *result = nullptr;
92   return result;
93 }
94 
95 StructuredData::ObjectSP ExceptionSearchFilter::SerializeToStructuredData() {
96   StructuredData::ObjectSP result_sp;
97 
98   return result_sp;
99 }
100 
101 // The Target is the one that knows how to create breakpoints, so this function
102 // is meant to be used either by the target or internally in
103 // Set/ClearExceptionBreakpoints.
104 class ExceptionBreakpointResolver : public BreakpointResolver {
105 public:
106   ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp,
107                               bool throw_bp)
108       : BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver),
109         m_language(language), m_language_runtime(nullptr), m_catch_bp(catch_bp),
110         m_throw_bp(throw_bp) {}
111 
112   ~ExceptionBreakpointResolver() override = default;
113 
114   Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
115                                           SymbolContext &context, Address *addr,
116                                           bool containing) override {
117 
118     if (SetActualResolver())
119       return m_actual_resolver_sp->SearchCallback(filter, context, addr,
120                                                   containing);
121     else
122       return eCallbackReturnStop;
123   }
124 
125   lldb::SearchDepth GetDepth() override {
126     if (SetActualResolver())
127       return m_actual_resolver_sp->GetDepth();
128     else
129       return lldb::eSearchDepthTarget;
130   }
131 
132   void GetDescription(Stream *s) override {
133     Language *language_plugin = Language::FindPlugin(m_language);
134     if (language_plugin)
135       language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp,
136                                                        *s);
137     else
138       Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp,
139                                                        *s);
140 
141     SetActualResolver();
142     if (m_actual_resolver_sp) {
143       s->Printf(" using: ");
144       m_actual_resolver_sp->GetDescription(s);
145     } else
146       s->Printf(" the correct runtime exception handler will be determined "
147                 "when you run");
148   }
149 
150   void Dump(Stream *s) const override {}
151 
152   /// Methods for support type inquiry through isa, cast, and dyn_cast:
153   static inline bool classof(const BreakpointResolverName *) { return true; }
154   static inline bool classof(const BreakpointResolver *V) {
155     return V->getResolverID() == BreakpointResolver::ExceptionResolver;
156   }
157 
158 protected:
159   BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override {
160     return BreakpointResolverSP(
161         new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
162   }
163 
164   bool SetActualResolver() {
165     ProcessSP process_sp;
166     if (m_breakpoint) {
167       process_sp = m_breakpoint->GetTarget().GetProcessSP();
168       if (process_sp) {
169         bool refreash_resolver = !m_actual_resolver_sp;
170         if (m_language_runtime == nullptr) {
171           m_language_runtime = process_sp->GetLanguageRuntime(m_language);
172           refreash_resolver = true;
173         } else {
174           LanguageRuntime *language_runtime =
175               process_sp->GetLanguageRuntime(m_language);
176           if (m_language_runtime != language_runtime) {
177             m_language_runtime = language_runtime;
178             refreash_resolver = true;
179           }
180         }
181 
182         if (refreash_resolver && m_language_runtime) {
183           m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver(
184               m_breakpoint, m_catch_bp, m_throw_bp);
185         }
186       } else {
187         m_actual_resolver_sp.reset();
188         m_language_runtime = nullptr;
189       }
190     } else {
191       m_actual_resolver_sp.reset();
192       m_language_runtime = nullptr;
193     }
194     return (bool)m_actual_resolver_sp;
195   }
196 
197   lldb::BreakpointResolverSP m_actual_resolver_sp;
198   lldb::LanguageType m_language;
199   LanguageRuntime *m_language_runtime;
200   bool m_catch_bp;
201   bool m_throw_bp;
202 };
203 
204 LanguageRuntime *LanguageRuntime::FindPlugin(Process *process,
205                                              lldb::LanguageType language) {
206   std::unique_ptr<LanguageRuntime> language_runtime_up;
207   LanguageRuntimeCreateInstance create_callback;
208 
209   for (uint32_t idx = 0;
210        (create_callback =
211             PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
212        nullptr;
213        ++idx) {
214     language_runtime_up.reset(create_callback(process, language));
215 
216     if (language_runtime_up)
217       return language_runtime_up.release();
218   }
219 
220   return nullptr;
221 }
222 
223 LanguageRuntime::LanguageRuntime(Process *process) : m_process(process) {}
224 
225 LanguageRuntime::~LanguageRuntime() = default;
226 
227 Breakpoint::BreakpointPreconditionSP
228 LanguageRuntime::CreateExceptionPrecondition(lldb::LanguageType language,
229                                              bool catch_bp, bool throw_bp) {
230   switch (language) {
231   case eLanguageTypeObjC:
232     if (throw_bp)
233       return Breakpoint::BreakpointPreconditionSP(
234           new ObjCLanguageRuntime::ObjCExceptionPrecondition());
235     break;
236   default:
237     break;
238   }
239   return Breakpoint::BreakpointPreconditionSP();
240 }
241 
242 BreakpointSP LanguageRuntime::CreateExceptionBreakpoint(
243     Target &target, lldb::LanguageType language, bool catch_bp, bool throw_bp,
244     bool is_internal) {
245   BreakpointResolverSP resolver_sp(
246       new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
247   SearchFilterSP filter_sp(
248       new ExceptionSearchFilter(target.shared_from_this(), language));
249   bool hardware = false;
250   bool resolve_indirect_functions = false;
251   BreakpointSP exc_breakpt_sp(
252       target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware,
253                               resolve_indirect_functions));
254   if (exc_breakpt_sp) {
255     Breakpoint::BreakpointPreconditionSP precondition_sp =
256         CreateExceptionPrecondition(language, catch_bp, throw_bp);
257     if (precondition_sp)
258       exc_breakpt_sp->SetPrecondition(precondition_sp);
259 
260     if (is_internal)
261       exc_breakpt_sp->SetBreakpointKind("exception");
262   }
263 
264   return exc_breakpt_sp;
265 }
266 
267 void LanguageRuntime::InitializeCommands(CommandObject *parent) {
268   if (!parent)
269     return;
270 
271   if (!parent->IsMultiwordObject())
272     return;
273 
274   LanguageRuntimeCreateInstance create_callback;
275 
276   for (uint32_t idx = 0;
277        (create_callback =
278             PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
279        nullptr;
280        ++idx) {
281     if (LanguageRuntimeGetCommandObject command_callback =
282             PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) {
283       CommandObjectSP command =
284           command_callback(parent->GetCommandInterpreter());
285       if (command) {
286         // the CommandObject vended by a Language plugin cannot be created once
287         // and cached because we may create multiple debuggers and need one
288         // instance of the command each - the implementing function is meant to
289         // create a new instance of the command each time it is invoked.
290         parent->LoadSubCommand(command->GetCommandName().str().c_str(), command);
291       }
292     }
293   }
294 }
295 
296