Home | History | Annotate | Download | only in AppleObjCRuntime
      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