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(nullptr),
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 == nullptr)
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 = nullptr;
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(nullptr, BreakpointResolver::ExceptionResolver),
132         m_language(language),
133         m_language_runtime(nullptr),
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 == nullptr)
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 = nullptr;
234             }
235         }
236         else
237         {
238             m_actual_resolver_sp.reset();
239             m_language_runtime = nullptr;
240         }
241         return (bool)m_actual_resolver_sp;
242     }
243 
244     lldb::BreakpointResolverSP m_actual_resolver_sp;
245     lldb::LanguageType m_language;
246     LanguageRuntime *m_language_runtime;
247     bool m_catch_bp;
248     bool m_throw_bp;
249 };
250 
251 LanguageRuntime*
252 LanguageRuntime::FindPlugin (Process *process, lldb::LanguageType language)
253 {
254     std::unique_ptr<LanguageRuntime> language_runtime_ap;
255     LanguageRuntimeCreateInstance create_callback;
256 
257     for (uint32_t idx = 0;
258          (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr;
259          ++idx)
260     {
261         language_runtime_ap.reset (create_callback(process, language));
262 
263         if (language_runtime_ap)
264             return language_runtime_ap.release();
265     }
266 
267     return nullptr;
268 }
269 
270 LanguageRuntime::LanguageRuntime(Process *process) :
271     m_process (process)
272 {
273 }
274 
275 LanguageRuntime::~LanguageRuntime() = default;
276 
277 Breakpoint::BreakpointPreconditionSP
278 LanguageRuntime::CreateExceptionPrecondition (lldb::LanguageType language,
279                                               bool catch_bp,
280                                               bool throw_bp)
281 {
282     switch (language)
283     {
284     case eLanguageTypeObjC:
285         if (throw_bp)
286             return Breakpoint::BreakpointPreconditionSP(new ObjCLanguageRuntime::ObjCExceptionPrecondition ());
287         break;
288     default:
289         break;
290     }
291     return Breakpoint::BreakpointPreconditionSP();
292 }
293 
294 BreakpointSP
295 LanguageRuntime::CreateExceptionBreakpoint (Target &target,
296                                             lldb::LanguageType language,
297                                             bool catch_bp,
298                                             bool throw_bp,
299                                             bool is_internal)
300 {
301     BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
302     SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language));
303     bool hardware = false;
304     bool resolve_indirect_functions = false;
305     BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions));
306     if (exc_breakpt_sp)
307     {
308         Breakpoint::BreakpointPreconditionSP precondition_sp = CreateExceptionPrecondition(language, catch_bp, throw_bp);
309         if (precondition_sp)
310             exc_breakpt_sp->SetPrecondition(precondition_sp);
311 
312         if (is_internal)
313             exc_breakpt_sp->SetBreakpointKind("exception");
314     }
315 
316     return exc_breakpt_sp;
317 }
318 
319 void
320 LanguageRuntime::InitializeCommands (CommandObject* parent)
321 {
322     if (!parent)
323         return;
324 
325     if (!parent->IsMultiwordObject())
326         return;
327 
328     LanguageRuntimeCreateInstance create_callback;
329 
330     for (uint32_t idx = 0;
331          (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr;
332          ++idx)
333     {
334         if (LanguageRuntimeGetCommandObject command_callback =
335                 PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx))
336         {
337             CommandObjectSP command = command_callback(parent->GetCommandInterpreter());
338             if (command)
339             {
340                 // the CommandObject vended by a Language plugin cannot be created once and cached because
341                 // we may create multiple debuggers and need one instance of the command each - the implementing function
342                 // is meant to create a new instance of the command each time it is invoked
343                 parent->LoadSubCommand(command->GetCommandName(), command);
344             }
345         }
346     }
347 }
348 
349 lldb::SearchFilterSP
350 LanguageRuntime::CreateExceptionSearchFilter ()
351 {
352     return m_process->GetTarget().GetSearchFilterForModule(nullptr);
353 }
354