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 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 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 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 * 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 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 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 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 257 AppleObjCRuntime::IsModuleObjCLibrary (const ModuleSP &module_sp) 258 { 259 return AppleIsModuleObjCLibrary(module_sp); 260 } 261 262 bool 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 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 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 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 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 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 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 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