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         s->Printf ("Exception breakpoint (catch: %s throw: %s)",
167                    m_catch_bp ? "on" : "off",
168                    m_throw_bp ? "on" : "off");
169 
170         SetActualResolver();
171         if (m_actual_resolver_sp)
172         {
173             s->Printf (" using: ");
174             m_actual_resolver_sp->GetDescription (s);
175         }
176         else
177             s->Printf (" the correct runtime exception handler will be determined when you run");
178     }
179 
180     void
181     Dump (Stream *s) const override
182     {
183     }
184 
185     /// Methods for support type inquiry through isa, cast, and dyn_cast:
186     static inline bool classof(const BreakpointResolverName *) { return true; }
187     static inline bool classof(const BreakpointResolver *V) {
188         return V->getResolverID() == BreakpointResolver::ExceptionResolver;
189     }
190 
191 protected:
192     BreakpointResolverSP
193     CopyForBreakpoint (Breakpoint &breakpoint) override
194     {
195         return BreakpointResolverSP(new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
196     }
197 
198     bool
199     SetActualResolver()
200     {
201         ProcessSP process_sp;
202         if (m_breakpoint)
203         {
204             process_sp = m_breakpoint->GetTarget().GetProcessSP();
205             if (process_sp)
206             {
207                 bool refreash_resolver = !m_actual_resolver_sp;
208                 if (m_language_runtime == NULL)
209                 {
210                     m_language_runtime = process_sp->GetLanguageRuntime(m_language);
211                     refreash_resolver = true;
212                 }
213                 else
214                 {
215                     LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language);
216                     if (m_language_runtime != language_runtime)
217                     {
218                         m_language_runtime = language_runtime;
219                         refreash_resolver = true;
220                     }
221                 }
222 
223                 if (refreash_resolver && m_language_runtime)
224                 {
225                     m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver (m_breakpoint, m_catch_bp, m_throw_bp);
226                 }
227             }
228             else
229             {
230                 m_actual_resolver_sp.reset();
231                 m_language_runtime = NULL;
232             }
233         }
234         else
235         {
236             m_actual_resolver_sp.reset();
237             m_language_runtime = NULL;
238         }
239         return (bool)m_actual_resolver_sp;
240     }
241     lldb::BreakpointResolverSP m_actual_resolver_sp;
242     lldb::LanguageType m_language;
243     LanguageRuntime *m_language_runtime;
244     bool m_catch_bp;
245     bool m_throw_bp;
246 };
247 
248 LanguageRuntime*
249 LanguageRuntime::FindPlugin (Process *process, lldb::LanguageType language)
250 {
251     std::unique_ptr<LanguageRuntime> language_runtime_ap;
252     LanguageRuntimeCreateInstance create_callback;
253 
254     for (uint32_t idx = 0;
255          (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != NULL;
256          ++idx)
257     {
258         language_runtime_ap.reset (create_callback(process, language));
259 
260         if (language_runtime_ap.get())
261             return language_runtime_ap.release();
262     }
263 
264     return NULL;
265 }
266 
267 LanguageRuntime::LanguageRuntime(Process *process) :
268     m_process (process)
269 {
270 }
271 
272 LanguageRuntime::~LanguageRuntime() = default;
273 
274 Breakpoint::BreakpointPreconditionSP
275 LanguageRuntime::CreateExceptionPrecondition (lldb::LanguageType language,
276                                               bool catch_bp,
277                                               bool throw_bp)
278 {
279     switch (language)
280     {
281     case eLanguageTypeObjC:
282         if (throw_bp)
283             return Breakpoint::BreakpointPreconditionSP(new ObjCLanguageRuntime::ObjCExceptionPrecondition ());
284         break;
285     default:
286         break;
287     }
288     return Breakpoint::BreakpointPreconditionSP();
289 }
290 
291 BreakpointSP
292 LanguageRuntime::CreateExceptionBreakpoint (Target &target,
293                                             lldb::LanguageType language,
294                                             bool catch_bp,
295                                             bool throw_bp,
296                                             bool is_internal)
297 {
298     BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
299     SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language));
300     bool hardware = false;
301     bool resolve_indirect_functions = false;
302     BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions));
303     if (exc_breakpt_sp)
304     {
305         Breakpoint::BreakpointPreconditionSP precondition_sp = CreateExceptionPrecondition(language, catch_bp, throw_bp);
306         if (precondition_sp)
307             exc_breakpt_sp->SetPrecondition(precondition_sp);
308 
309         if (is_internal)
310             exc_breakpt_sp->SetBreakpointKind("exception");
311     }
312 
313     return exc_breakpt_sp;
314 }
315 
316 void
317 LanguageRuntime::InitializeCommands (CommandObject* parent)
318 {
319     if (!parent)
320         return;
321 
322     if (!parent->IsMultiwordObject())
323         return;
324 
325     LanguageRuntimeCreateInstance create_callback;
326 
327     for (uint32_t idx = 0;
328          (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr;
329          ++idx)
330     {
331         if (LanguageRuntimeGetCommandObject command_callback =
332                 PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx))
333         {
334             CommandObjectSP command = command_callback(parent->GetCommandInterpreter());
335             if (command)
336             {
337                 parent->LoadSubCommand(command->GetCommandName(), command);
338             }
339         }
340     }
341 }
342 
343 lldb::SearchFilterSP
344 LanguageRuntime::CreateExceptionSearchFilter ()
345 {
346     return m_process->GetTarget().GetSearchFilterForModule(NULL);
347 }
348 
349 lldb::LanguageType
350 LanguageRuntime::GetLanguageForSymbolByName (Target &target, const char *symbol_name)
351 {
352     // This is not the right way to do this.  Different targets could have different ways of mangling names
353     // from a given language.  So we should ask the various LanguageRuntime plugin instances for this target
354     // to recognize the name.  But right now the plugin instances depend on the process, not the target.
355     // That is unfortunate, because I want to use this for filtering breakpoints by language, and so I need to know
356     // the "language for symbol-name" prior to running.  So we'd have to make a "LanguageRuntimeTarget" and
357     // "LanguageRuntimeProcess", and direct the questions that don't need a running process to the former, and that
358     // do to the latter.
359     //
360     // That's more work than I want to do for this feature.
361     if (CPlusPlusLanguage::IsCPPMangledName (symbol_name))
362         return eLanguageTypeC_plus_plus;
363     else if (ObjCLanguage::IsPossibleObjCMethodName (symbol_name))
364         return eLanguageTypeObjC;
365     else
366         return eLanguageTypeUnknown;
367 }
368