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