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/Target/ObjCLanguageRuntime.h"
18 #include "lldb/Target/Target.h"
19 #include "lldb/Core/PluginManager.h"
20 #include "lldb/Core/SearchFilter.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 class ExceptionSearchFilter : public SearchFilter
27 {
28 public:
29     ExceptionSearchFilter (const lldb::TargetSP &target_sp,
30                            lldb::LanguageType language,
31                            bool update_module_list = true) :
32         SearchFilter (target_sp),
33         m_language (language),
34         m_language_runtime (NULL),
35         m_filter_sp ()
36     {
37         if (update_module_list)
38             UpdateModuleListIfNeeded ();
39     }
40 
41     ~ExceptionSearchFilter() override = default;
42 
43     bool
44     ModulePasses (const lldb::ModuleSP &module_sp) override
45     {
46         UpdateModuleListIfNeeded ();
47         if (m_filter_sp)
48             return m_filter_sp->ModulePasses (module_sp);
49         return false;
50     }
51 
52     bool
53     ModulePasses (const FileSpec &spec) override
54     {
55         UpdateModuleListIfNeeded ();
56         if (m_filter_sp)
57             return m_filter_sp->ModulePasses (spec);
58         return false;
59     }
60 
61     void
62     Search (Searcher &searcher) override
63     {
64         UpdateModuleListIfNeeded ();
65         if (m_filter_sp)
66             m_filter_sp->Search (searcher);
67     }
68 
69     void
70     GetDescription (Stream *s) override
71     {
72         UpdateModuleListIfNeeded ();
73         if (m_filter_sp)
74             m_filter_sp->GetDescription (s);
75     }
76 
77 protected:
78     LanguageType m_language;
79     LanguageRuntime *m_language_runtime;
80     SearchFilterSP m_filter_sp;
81 
82     SearchFilterSP
83     DoCopyForBreakpoint(Breakpoint &breakpoint) override
84     {
85         return SearchFilterSP(new ExceptionSearchFilter(TargetSP(), m_language, false));
86     }
87 
88     void
89     UpdateModuleListIfNeeded ()
90     {
91         ProcessSP process_sp (m_target_sp->GetProcessSP());
92         if (process_sp)
93         {
94             bool refreash_filter = !m_filter_sp;
95             if (m_language_runtime == NULL)
96             {
97                 m_language_runtime = process_sp->GetLanguageRuntime(m_language);
98                 refreash_filter = true;
99             }
100             else
101             {
102                 LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language);
103                 if (m_language_runtime != language_runtime)
104                 {
105                     m_language_runtime = language_runtime;
106                     refreash_filter = true;
107                 }
108             }
109 
110             if (refreash_filter && m_language_runtime)
111             {
112                 m_filter_sp = m_language_runtime->CreateExceptionSearchFilter ();
113             }
114         }
115         else
116         {
117             m_filter_sp.reset();
118             m_language_runtime = NULL;
119         }
120     }
121 };
122 
123 // The Target is the one that knows how to create breakpoints, so this function
124 // is meant to be used either by the target or internally in Set/ClearExceptionBreakpoints.
125 class ExceptionBreakpointResolver : public BreakpointResolver
126 {
127 public:
128     ExceptionBreakpointResolver (lldb::LanguageType language,
129                                  bool catch_bp,
130                                  bool throw_bp) :
131         BreakpointResolver (NULL, BreakpointResolver::ExceptionResolver),
132         m_language (language),
133         m_language_runtime (NULL),
134         m_catch_bp (catch_bp),
135         m_throw_bp (throw_bp)
136     {
137     }
138 
139     ~ExceptionBreakpointResolver() override = default;
140 
141     Searcher::CallbackReturn
142     SearchCallback (SearchFilter &filter,
143                     SymbolContext &context,
144                     Address *addr,
145                     bool containing) override
146     {
147 
148         if (SetActualResolver())
149             return m_actual_resolver_sp->SearchCallback (filter, context, addr, containing);
150         else
151             return eCallbackReturnStop;
152     }
153 
154     Searcher::Depth
155     GetDepth () override
156     {
157         if (SetActualResolver())
158             return m_actual_resolver_sp->GetDepth();
159         else
160             return eDepthTarget;
161     }
162 
163     void
164     GetDescription (Stream *s) override
165     {
166        Language *language_plugin = Language::FindPlugin(m_language);
167        if (language_plugin)
168            language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp, *s);
169        else
170            Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp, *s);
171 
172         SetActualResolver();
173         if (m_actual_resolver_sp)
174         {
175             s->Printf (" using: ");
176             m_actual_resolver_sp->GetDescription (s);
177         }
178         else
179             s->Printf (" the correct runtime exception handler will be determined when you run");
180     }
181 
182     void
183     Dump (Stream *s) const override
184     {
185     }
186 
187     /// Methods for support type inquiry through isa, cast, and dyn_cast:
188     static inline bool classof(const BreakpointResolverName *) { return true; }
189     static inline bool classof(const BreakpointResolver *V) {
190         return V->getResolverID() == BreakpointResolver::ExceptionResolver;
191     }
192 
193 protected:
194     BreakpointResolverSP
195     CopyForBreakpoint (Breakpoint &breakpoint) override
196     {
197         return BreakpointResolverSP(new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
198     }
199 
200     bool
201     SetActualResolver()
202     {
203         ProcessSP process_sp;
204         if (m_breakpoint)
205         {
206             process_sp = m_breakpoint->GetTarget().GetProcessSP();
207             if (process_sp)
208             {
209                 bool refreash_resolver = !m_actual_resolver_sp;
210                 if (m_language_runtime == NULL)
211                 {
212                     m_language_runtime = process_sp->GetLanguageRuntime(m_language);
213                     refreash_resolver = true;
214                 }
215                 else
216                 {
217                     LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language);
218                     if (m_language_runtime != language_runtime)
219                     {
220                         m_language_runtime = language_runtime;
221                         refreash_resolver = true;
222                     }
223                 }
224 
225                 if (refreash_resolver && m_language_runtime)
226                 {
227                     m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver (m_breakpoint, m_catch_bp, m_throw_bp);
228                 }
229             }
230             else
231             {
232                 m_actual_resolver_sp.reset();
233                 m_language_runtime = NULL;
234             }
235         }
236         else
237         {
238             m_actual_resolver_sp.reset();
239             m_language_runtime = NULL;
240         }
241         return (bool)m_actual_resolver_sp;
242     }
243     lldb::BreakpointResolverSP m_actual_resolver_sp;
244     lldb::LanguageType m_language;
245     LanguageRuntime *m_language_runtime;
246     bool m_catch_bp;
247     bool m_throw_bp;
248 };
249 
250 LanguageRuntime*
251 LanguageRuntime::FindPlugin (Process *process, lldb::LanguageType language)
252 {
253     std::unique_ptr<LanguageRuntime> language_runtime_ap;
254     LanguageRuntimeCreateInstance create_callback;
255 
256     for (uint32_t idx = 0;
257          (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != NULL;
258          ++idx)
259     {
260         language_runtime_ap.reset (create_callback(process, language));
261 
262         if (language_runtime_ap.get())
263             return language_runtime_ap.release();
264     }
265 
266     return NULL;
267 }
268 
269 LanguageRuntime::LanguageRuntime(Process *process) :
270     m_process (process)
271 {
272 }
273 
274 LanguageRuntime::~LanguageRuntime() = default;
275 
276 Breakpoint::BreakpointPreconditionSP
277 LanguageRuntime::CreateExceptionPrecondition (lldb::LanguageType language,
278                                               bool catch_bp,
279                                               bool throw_bp)
280 {
281     switch (language)
282     {
283     case eLanguageTypeObjC:
284         if (throw_bp)
285             return Breakpoint::BreakpointPreconditionSP(new ObjCLanguageRuntime::ObjCExceptionPrecondition ());
286         break;
287     default:
288         break;
289     }
290     return Breakpoint::BreakpointPreconditionSP();
291 }
292 
293 BreakpointSP
294 LanguageRuntime::CreateExceptionBreakpoint (Target &target,
295                                             lldb::LanguageType language,
296                                             bool catch_bp,
297                                             bool throw_bp,
298                                             bool is_internal)
299 {
300     BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
301     SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language));
302     bool hardware = false;
303     bool resolve_indirect_functions = false;
304     BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions));
305     if (exc_breakpt_sp)
306     {
307         Breakpoint::BreakpointPreconditionSP precondition_sp = CreateExceptionPrecondition(language, catch_bp, throw_bp);
308         if (precondition_sp)
309             exc_breakpt_sp->SetPrecondition(precondition_sp);
310 
311         if (is_internal)
312             exc_breakpt_sp->SetBreakpointKind("exception");
313     }
314 
315     return exc_breakpt_sp;
316 }
317 
318 void
319 LanguageRuntime::InitializeCommands (CommandObject* parent)
320 {
321     if (!parent)
322         return;
323 
324     if (!parent->IsMultiwordObject())
325         return;
326 
327     LanguageRuntimeCreateInstance create_callback;
328 
329     for (uint32_t idx = 0;
330          (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr;
331          ++idx)
332     {
333         if (LanguageRuntimeGetCommandObject command_callback =
334                 PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx))
335         {
336             CommandObjectSP command = command_callback(parent->GetCommandInterpreter());
337             if (command)
338             {
339                 parent->LoadSubCommand(command->GetCommandName(), command);
340             }
341         }
342     }
343 }
344 
345 lldb::SearchFilterSP
346 LanguageRuntime::CreateExceptionSearchFilter ()
347 {
348     return m_process->GetTarget().GetSearchFilterForModule(NULL);
349 }
350