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