1 //===-- LanguageRuntime.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Target/LanguageRuntime.h"
15 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
16 #include "Plugins/Language/ObjC/ObjCLanguage.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Core/SearchFilter.h"
19 #include "lldb/Interpreter/CommandInterpreter.h"
20 #include "lldb/Target/ObjCLanguageRuntime.h"
21 #include "lldb/Target/Target.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 class ExceptionSearchFilter : public SearchFilter {
27 public:
28   ExceptionSearchFilter(const lldb::TargetSP &target_sp,
29                         lldb::LanguageType language,
30                         bool update_module_list = true)
31       : SearchFilter(target_sp), m_language(language),
32         m_language_runtime(nullptr), m_filter_sp() {
33     if (update_module_list)
34       UpdateModuleListIfNeeded();
35   }
36 
37   ~ExceptionSearchFilter() override = default;
38 
39   bool ModulePasses(const lldb::ModuleSP &module_sp) override {
40     UpdateModuleListIfNeeded();
41     if (m_filter_sp)
42       return m_filter_sp->ModulePasses(module_sp);
43     return false;
44   }
45 
46   bool ModulePasses(const FileSpec &spec) override {
47     UpdateModuleListIfNeeded();
48     if (m_filter_sp)
49       return m_filter_sp->ModulePasses(spec);
50     return false;
51   }
52 
53   void Search(Searcher &searcher) override {
54     UpdateModuleListIfNeeded();
55     if (m_filter_sp)
56       m_filter_sp->Search(searcher);
57   }
58 
59   void GetDescription(Stream *s) override {
60     UpdateModuleListIfNeeded();
61     if (m_filter_sp)
62       m_filter_sp->GetDescription(s);
63   }
64 
65 protected:
66   LanguageType m_language;
67   LanguageRuntime *m_language_runtime;
68   SearchFilterSP m_filter_sp;
69 
70   SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override {
71     return SearchFilterSP(
72         new ExceptionSearchFilter(TargetSP(), m_language, false));
73   }
74 
75   void UpdateModuleListIfNeeded() {
76     ProcessSP process_sp(m_target_sp->GetProcessSP());
77     if (process_sp) {
78       bool refreash_filter = !m_filter_sp;
79       if (m_language_runtime == nullptr) {
80         m_language_runtime = process_sp->GetLanguageRuntime(m_language);
81         refreash_filter = true;
82       } else {
83         LanguageRuntime *language_runtime =
84             process_sp->GetLanguageRuntime(m_language);
85         if (m_language_runtime != language_runtime) {
86           m_language_runtime = language_runtime;
87           refreash_filter = true;
88         }
89       }
90 
91       if (refreash_filter && m_language_runtime) {
92         m_filter_sp = m_language_runtime->CreateExceptionSearchFilter();
93       }
94     } else {
95       m_filter_sp.reset();
96       m_language_runtime = nullptr;
97     }
98   }
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   Searcher::Depth GetDepth() override {
126     if (SetActualResolver())
127       return m_actual_resolver_sp->GetDepth();
128     else
129       return eDepthTarget;
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_ap;
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_ap.reset(create_callback(process, language));
215 
216     if (language_runtime_ap)
217       return language_runtime_ap.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
288         // we may create multiple debuggers and need one instance of the command
289         // each - the implementing function
290         // is meant to create a new instance of the command each time it is
291         // invoked
292         parent->LoadSubCommand(command->GetCommandName(), command);
293       }
294     }
295   }
296 }
297 
298 lldb::SearchFilterSP LanguageRuntime::CreateExceptionSearchFilter() {
299   return m_process->GetTarget().GetSearchFilterForModule(nullptr);
300 }
301