• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- AppleObjCRuntime.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 #include "AppleObjCRuntime.h"
11 #include "AppleObjCTrampolineHandler.h"
12 
13 #include "llvm/Support/MachO.h"
14 #include "clang/AST/Type.h"
15 
16 #include "lldb/Breakpoint/BreakpointLocation.h"
17 #include "lldb/Core/ConstString.h"
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/ModuleList.h"
22 #include "lldb/Core/PluginManager.h"
23 #include "lldb/Core/Scalar.h"
24 #include "lldb/Core/Section.h"
25 #include "lldb/Core/StreamString.h"
26 #include "lldb/Expression/ClangFunction.h"
27 #include "lldb/Symbol/ClangASTContext.h"
28 #include "lldb/Symbol/ObjectFile.h"
29 #include "lldb/Target/ExecutionContext.h"
30 #include "lldb/Target/Process.h"
31 #include "lldb/Target/RegisterContext.h"
32 #include "lldb/Target/StopInfo.h"
33 #include "lldb/Target/Target.h"
34 #include "lldb/Target/Thread.h"
35 
36 #include <vector>
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 
41 #define PO_FUNCTION_TIMEOUT_USEC 15*1000*1000
42 
43 bool
GetObjectDescription(Stream & str,ValueObject & valobj)44 AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj)
45 {
46     bool is_signed;
47     // ObjC objects can only be pointers, but we extend this to integer types because an expression might just
48     // result in an address, and we should try that to see if the address is an ObjC object.
49 
50     if (!(valobj.IsPointerType() || valobj.IsIntegerType(is_signed)))
51         return false;
52 
53     // Make the argument list: we pass one arg, the address of our pointer, to the print function.
54     Value val;
55 
56     if (!valobj.ResolveValue(val.GetScalar()))
57         return false;
58 
59     ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
60     return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope());
61 
62 }
63 bool
GetObjectDescription(Stream & strm,Value & value,ExecutionContextScope * exe_scope)64 AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionContextScope *exe_scope)
65 {
66     if (!m_read_objc_library)
67         return false;
68 
69     ExecutionContext exe_ctx;
70     exe_scope->CalculateExecutionContext(exe_ctx);
71     Process *process = exe_ctx.GetProcessPtr();
72     if (!process)
73         return false;
74 
75     // We need other parts of the exe_ctx, but the processes have to match.
76     assert (m_process == process);
77 
78     // Get the function address for the print function.
79     const Address *function_address = GetPrintForDebuggerAddr();
80     if (!function_address)
81         return false;
82 
83     Target *target = exe_ctx.GetTargetPtr();
84     ClangASTType clang_type = value.GetClangType();
85     if (clang_type)
86     {
87         if (!clang_type.IsObjCObjectPointerType())
88         {
89             strm.Printf ("Value doesn't point to an ObjC object.\n");
90             return false;
91         }
92     }
93     else
94     {
95         // If it is not a pointer, see if we can make it into a pointer.
96         ClangASTContext *ast_context = target->GetScratchClangASTContext();
97         ClangASTType opaque_type = ast_context->GetBasicType(eBasicTypeObjCID);
98         if (!opaque_type)
99             opaque_type = ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
100         //value.SetContext(Value::eContextTypeClangType, opaque_type_ptr);
101         value.SetClangType (opaque_type);
102     }
103 
104     ValueList arg_value_list;
105     arg_value_list.PushValue(value);
106 
107     // This is the return value:
108     ClangASTContext *ast_context = target->GetScratchClangASTContext();
109 
110     ClangASTType return_clang_type = ast_context->GetCStringType(true);
111     Value ret;
112 //    ret.SetContext(Value::eContextTypeClangType, return_clang_type);
113     ret.SetClangType (return_clang_type);
114 
115     if (exe_ctx.GetFramePtr() == NULL)
116     {
117         Thread *thread = exe_ctx.GetThreadPtr();
118         if (thread == NULL)
119         {
120             exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread());
121             thread = exe_ctx.GetThreadPtr();
122         }
123         if (thread)
124         {
125             exe_ctx.SetFrameSP(thread->GetSelectedFrame());
126         }
127     }
128 
129     // Now we're ready to call the function:
130     ClangFunction func (*exe_ctx.GetBestExecutionContextScope(),
131                         return_clang_type,
132                         *function_address,
133                         arg_value_list);
134 
135     StreamString error_stream;
136 
137     lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
138     func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream);
139 
140     const bool unwind_on_error = true;
141     const bool try_all_threads = true;
142     const bool stop_others = true;
143     const bool ignore_breakpoints = true;
144 
145     ExecutionResults results = func.ExecuteFunction (exe_ctx,
146                                                      &wrapper_struct_addr,
147                                                      error_stream,
148                                                      stop_others,
149                                                      PO_FUNCTION_TIMEOUT_USEC /* 15 secs timeout */,
150                                                      try_all_threads,
151                                                      unwind_on_error,
152                                                      ignore_breakpoints,
153                                                      ret);
154     if (results != eExecutionCompleted)
155     {
156         strm.Printf("Error evaluating Print Object function: %d.\n", results);
157         return false;
158     }
159 
160     addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
161 
162     char buf[512];
163     size_t cstr_len = 0;
164     size_t full_buffer_len = sizeof (buf) - 1;
165     size_t curr_len = full_buffer_len;
166     while (curr_len == full_buffer_len)
167     {
168         Error error;
169         curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf, sizeof(buf), error);
170         strm.Write (buf, curr_len);
171         cstr_len += curr_len;
172     }
173     return cstr_len > 0;
174 }
175 
176 lldb::ModuleSP
GetObjCModule()177 AppleObjCRuntime::GetObjCModule ()
178 {
179     ModuleSP module_sp (m_objc_module_wp.lock());
180     if (module_sp)
181         return module_sp;
182 
183     Process *process = GetProcess();
184     if (process)
185     {
186         const ModuleList& modules = process->GetTarget().GetImages();
187         for (uint32_t idx = 0; idx < modules.GetSize(); idx++)
188         {
189             module_sp = modules.GetModuleAtIndex(idx);
190             if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp))
191             {
192                 m_objc_module_wp = module_sp;
193                 return module_sp;
194             }
195         }
196     }
197     return ModuleSP();
198 }
199 
200 Address *
GetPrintForDebuggerAddr()201 AppleObjCRuntime::GetPrintForDebuggerAddr()
202 {
203     if (!m_PrintForDebugger_addr.get())
204     {
205         const ModuleList &modules = m_process->GetTarget().GetImages();
206 
207         SymbolContextList contexts;
208         SymbolContext context;
209 
210         if ((!modules.FindSymbolsWithNameAndType(ConstString ("_NSPrintForDebugger"), eSymbolTypeCode, contexts)) &&
211            (!modules.FindSymbolsWithNameAndType(ConstString ("_CFPrintForDebugger"), eSymbolTypeCode, contexts)))
212             return NULL;
213 
214         contexts.GetContextAtIndex(0, context);
215 
216         m_PrintForDebugger_addr.reset(new Address(context.symbol->GetAddress()));
217     }
218 
219     return m_PrintForDebugger_addr.get();
220 }
221 
222 bool
CouldHaveDynamicValue(ValueObject & in_value)223 AppleObjCRuntime::CouldHaveDynamicValue (ValueObject &in_value)
224 {
225     return in_value.GetClangType().IsPossibleDynamicType (NULL,
226                                                           false, // do not check C++
227                                                           true); // check ObjC
228 }
229 
230 bool
GetDynamicTypeAndAddress(ValueObject & in_value,lldb::DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address)231 AppleObjCRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
232                                             lldb::DynamicValueType use_dynamic,
233                                             TypeAndOrName &class_type_or_name,
234                                             Address &address)
235 {
236     return false;
237 }
238 
239 bool
AppleIsModuleObjCLibrary(const ModuleSP & module_sp)240 AppleObjCRuntime::AppleIsModuleObjCLibrary (const ModuleSP &module_sp)
241 {
242     if (module_sp)
243     {
244         const FileSpec &module_file_spec = module_sp->GetFileSpec();
245         static ConstString ObjCName ("libobjc.A.dylib");
246 
247         if (module_file_spec)
248         {
249             if (module_file_spec.GetFilename() == ObjCName)
250                 return true;
251         }
252     }
253     return false;
254 }
255 
256 bool
IsModuleObjCLibrary(const ModuleSP & module_sp)257 AppleObjCRuntime::IsModuleObjCLibrary (const ModuleSP &module_sp)
258 {
259     return AppleIsModuleObjCLibrary(module_sp);
260 }
261 
262 bool
ReadObjCLibrary(const ModuleSP & module_sp)263 AppleObjCRuntime::ReadObjCLibrary (const ModuleSP &module_sp)
264 {
265     // Maybe check here and if we have a handler already, and the UUID of this module is the same as the one in the
266     // current module, then we don't have to reread it?
267     m_objc_trampoline_handler_ap.reset(new AppleObjCTrampolineHandler (m_process->shared_from_this(), module_sp));
268     if (m_objc_trampoline_handler_ap.get() != NULL)
269     {
270         m_read_objc_library = true;
271         return true;
272     }
273     else
274         return false;
275 }
276 
277 ThreadPlanSP
GetStepThroughTrampolinePlan(Thread & thread,bool stop_others)278 AppleObjCRuntime::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
279 {
280     ThreadPlanSP thread_plan_sp;
281     if (m_objc_trampoline_handler_ap.get())
282         thread_plan_sp = m_objc_trampoline_handler_ap->GetStepThroughDispatchPlan (thread, stop_others);
283     return thread_plan_sp;
284 }
285 
286 //------------------------------------------------------------------
287 // Static Functions
288 //------------------------------------------------------------------
289 enum ObjCRuntimeVersions
GetObjCVersion(Process * process,ModuleSP & objc_module_sp)290 AppleObjCRuntime::GetObjCVersion (Process *process, ModuleSP &objc_module_sp)
291 {
292     if (!process)
293         return eObjC_VersionUnknown;
294 
295     Target &target = process->GetTarget();
296     const ModuleList &target_modules = target.GetImages();
297     Mutex::Locker modules_locker(target_modules.GetMutex());
298 
299     size_t num_images = target_modules.GetSize();
300     for (size_t i = 0; i < num_images; i++)
301     {
302         ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i);
303         // One tricky bit here is that we might get called as part of the initial module loading, but
304         // before all the pre-run libraries get winnowed from the module list.  So there might actually
305         // be an old and incorrect ObjC library sitting around in the list, and we don't want to look at that.
306         // That's why we call IsLoadedInTarget.
307 
308         if (AppleIsModuleObjCLibrary (module_sp) && module_sp->IsLoadedInTarget(&target))
309         {
310             objc_module_sp = module_sp;
311             ObjectFile *ofile = module_sp->GetObjectFile();
312             if (!ofile)
313                 return eObjC_VersionUnknown;
314 
315             SectionList *sections = module_sp->GetSectionList();
316             if (!sections)
317                 return eObjC_VersionUnknown;
318             SectionSP v1_telltale_section_sp = sections->FindSectionByName(ConstString ("__OBJC"));
319             if (v1_telltale_section_sp)
320             {
321                 return eAppleObjC_V1;
322             }
323             return eAppleObjC_V2;
324         }
325     }
326 
327     return eObjC_VersionUnknown;
328 }
329 
330 void
SetExceptionBreakpoints()331 AppleObjCRuntime::SetExceptionBreakpoints ()
332 {
333     const bool catch_bp = false;
334     const bool throw_bp = true;
335     const bool is_internal = true;
336 
337     if (!m_objc_exception_bp_sp)
338     {
339         m_objc_exception_bp_sp = LanguageRuntime::CreateExceptionBreakpoint (m_process->GetTarget(),
340                                                                             GetLanguageType(),
341                                                                             catch_bp,
342                                                                             throw_bp,
343                                                                             is_internal);
344         if (m_objc_exception_bp_sp)
345             m_objc_exception_bp_sp->SetBreakpointKind("ObjC exception");
346     }
347     else
348         m_objc_exception_bp_sp->SetEnabled(true);
349 }
350 
351 
352 void
ClearExceptionBreakpoints()353 AppleObjCRuntime::ClearExceptionBreakpoints ()
354 {
355     if (!m_process)
356         return;
357 
358     if (m_objc_exception_bp_sp.get())
359     {
360         m_objc_exception_bp_sp->SetEnabled (false);
361     }
362 }
363 
364 bool
ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason)365 AppleObjCRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
366 {
367     if (!m_process)
368         return false;
369 
370     if (!stop_reason ||
371         stop_reason->GetStopReason() != eStopReasonBreakpoint)
372         return false;
373 
374     uint64_t break_site_id = stop_reason->GetValue();
375     return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint (break_site_id,
376                                                                                 m_objc_exception_bp_sp->GetID());
377 }
378 
379 bool
CalculateHasNewLiteralsAndIndexing()380 AppleObjCRuntime::CalculateHasNewLiteralsAndIndexing()
381 {
382     if (!m_process)
383         return false;
384 
385     Target &target(m_process->GetTarget());
386 
387     static ConstString s_method_signature("-[NSDictionary objectForKeyedSubscript:]");
388     static ConstString s_arclite_method_signature("__arclite_objectForKeyedSubscript");
389 
390     SymbolContextList sc_list;
391 
392     if (target.GetImages().FindSymbolsWithNameAndType(s_method_signature, eSymbolTypeCode, sc_list) ||
393         target.GetImages().FindSymbolsWithNameAndType(s_arclite_method_signature, eSymbolTypeCode, sc_list))
394         return true;
395     else
396         return false;
397 }
398 
399 lldb::SearchFilterSP
CreateExceptionSearchFilter()400 AppleObjCRuntime::CreateExceptionSearchFilter ()
401 {
402     Target &target = m_process->GetTarget();
403 
404     if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple)
405     {
406         FileSpecList filter_modules;
407         filter_modules.Append(FileSpec("libobjc.A.dylib", false));
408         return target.GetSearchFilterForModuleList(&filter_modules);
409     }
410     else
411     {
412         return LanguageRuntime::CreateExceptionSearchFilter();
413     }
414 }
415 
416