Home | History | Annotate | Download | only in Target
      1 //===-- ObjCLanguageRuntime.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 #include "clang/AST/Type.h"
     10 
     11 #include "lldb/Core/Log.h"
     12 #include "lldb/Core/MappedHash.h"
     13 #include "lldb/Core/Module.h"
     14 #include "lldb/Core/PluginManager.h"
     15 #include "lldb/Core/Timer.h"
     16 #include "lldb/Core/ValueObject.h"
     17 #include "lldb/Symbol/ClangASTContext.h"
     18 #include "lldb/Symbol/Type.h"
     19 #include "lldb/Symbol/TypeList.h"
     20 #include "lldb/Target/ObjCLanguageRuntime.h"
     21 #include "lldb/Target/Target.h"
     22 
     23 #include "llvm/ADT/StringRef.h"
     24 
     25 using namespace lldb;
     26 using namespace lldb_private;
     27 
     28 //----------------------------------------------------------------------
     29 // Destructor
     30 //----------------------------------------------------------------------
     31 ObjCLanguageRuntime::~ObjCLanguageRuntime()
     32 {
     33 }
     34 
     35 ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
     36     LanguageRuntime (process),
     37     m_has_new_literals_and_indexing (eLazyBoolCalculate),
     38     m_isa_to_descriptor(),
     39     m_isa_to_descriptor_stop_id (UINT32_MAX)
     40 {
     41 
     42 }
     43 
     44 bool
     45 ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
     46 {
     47     if (isa != 0)
     48     {
     49         m_isa_to_descriptor[isa] = descriptor_sp;
     50         // class_name is assumed to be valid
     51         m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
     52         return true;
     53     }
     54     return false;
     55 }
     56 
     57 void
     58 ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
     59 {
     60     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
     61     if (log)
     62     {
     63         log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr);
     64     }
     65     m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
     66 }
     67 
     68 lldb::addr_t
     69 ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector)
     70 {
     71     MsgImplMap::iterator pos, end = m_impl_cache.end();
     72     pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
     73     if (pos != end)
     74         return (*pos).second;
     75     return LLDB_INVALID_ADDRESS;
     76 }
     77 
     78 
     79 lldb::TypeSP
     80 ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
     81 {
     82     CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
     83 
     84     if (complete_class_iter != m_complete_class_cache.end())
     85     {
     86         // Check the weak pointer to make sure the type hasn't been unloaded
     87         TypeSP complete_type_sp (complete_class_iter->second.lock());
     88 
     89         if (complete_type_sp)
     90             return complete_type_sp;
     91         else
     92             m_complete_class_cache.erase(name);
     93     }
     94 
     95     if (m_negative_complete_class_cache.count(name) > 0)
     96         return TypeSP();
     97 
     98     const ModuleList &modules = m_process->GetTarget().GetImages();
     99 
    100     SymbolContextList sc_list;
    101     const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name,
    102                                                                         eSymbolTypeObjCClass,
    103                                                                         sc_list);
    104 
    105     if (matching_symbols)
    106     {
    107         SymbolContext sc;
    108 
    109         sc_list.GetContextAtIndex(0, sc);
    110 
    111         ModuleSP module_sp(sc.module_sp);
    112 
    113         if (!module_sp)
    114             return TypeSP();
    115 
    116         const SymbolContext null_sc;
    117         const bool exact_match = true;
    118         const uint32_t max_matches = UINT32_MAX;
    119         TypeList types;
    120 
    121         const uint32_t num_types = module_sp->FindTypes (null_sc,
    122                                                          name,
    123                                                          exact_match,
    124                                                          max_matches,
    125                                                          types);
    126 
    127         if (num_types)
    128         {
    129             uint32_t i;
    130             for (i = 0; i < num_types; ++i)
    131             {
    132                 TypeSP type_sp (types.GetTypeAtIndex(i));
    133 
    134                 if (type_sp->GetClangForwardType().IsObjCObjectOrInterfaceType())
    135                 {
    136                     if (type_sp->IsCompleteObjCClass())
    137                     {
    138                         m_complete_class_cache[name] = type_sp;
    139                         return type_sp;
    140                     }
    141                 }
    142             }
    143         }
    144     }
    145     m_negative_complete_class_cache.insert(name);
    146     return TypeSP();
    147 }
    148 
    149 size_t
    150 ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
    151 {
    152     return LLDB_INVALID_IVAR_OFFSET;
    153 }
    154 
    155 void
    156 ObjCLanguageRuntime::MethodName::Clear()
    157 {
    158     m_full.Clear();
    159     m_class.Clear();
    160     m_category.Clear();
    161     m_selector.Clear();
    162     m_type = eTypeUnspecified;
    163     m_category_is_valid = false;
    164 }
    165 
    166 //bool
    167 //ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
    168 //{
    169 //    Clear();
    170 //    if (name && name[0])
    171 //    {
    172 //        // If "strict" is true. then the method must be specified with a
    173 //        // '+' or '-' at the beginning. If "strict" is false, then the '+'
    174 //        // or '-' can be omitted
    175 //        bool valid_prefix = false;
    176 //
    177 //        if (name[0] == '+' || name[0] == '-')
    178 //        {
    179 //            valid_prefix = name[1] == '[';
    180 //        }
    181 //        else if (!strict)
    182 //        {
    183 //            // "strict" is false, the name just needs to start with '['
    184 //            valid_prefix = name[0] == '[';
    185 //        }
    186 //
    187 //        if (valid_prefix)
    188 //        {
    189 //            static RegularExpression g_regex("^([-+]?)\\[([A-Za-z_][A-Za-z_0-9]*)(\\([A-Za-z_][A-Za-z_0-9]*\\))? ([A-Za-z_][A-Za-z_0-9:]*)\\]$");
    190 //            llvm::StringRef matches[4];
    191 //            // Since we are using a global regular expression, we must use the threadsafe version of execute
    192 //            if (g_regex.ExecuteThreadSafe(name, matches, 4))
    193 //            {
    194 //                m_full.SetCString(name);
    195 //                if (matches[0].empty())
    196 //                    m_type = eTypeUnspecified;
    197 //                else if (matches[0][0] == '+')
    198 //                    m_type = eTypeClassMethod;
    199 //                else
    200 //                    m_type = eTypeInstanceMethod;
    201 //                m_class.SetString(matches[1]);
    202 //                m_selector.SetString(matches[3]);
    203 //                if (!matches[2].empty())
    204 //                    m_category.SetString(matches[2]);
    205 //            }
    206 //        }
    207 //    }
    208 //    return IsValid(strict);
    209 //}
    210 
    211 bool
    212 ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
    213 {
    214     Clear();
    215     if (name && name[0])
    216     {
    217         // If "strict" is true. then the method must be specified with a
    218         // '+' or '-' at the beginning. If "strict" is false, then the '+'
    219         // or '-' can be omitted
    220         bool valid_prefix = false;
    221 
    222         if (name[0] == '+' || name[0] == '-')
    223         {
    224             valid_prefix = name[1] == '[';
    225             if (name[0] == '+')
    226                 m_type = eTypeClassMethod;
    227             else
    228                 m_type = eTypeInstanceMethod;
    229         }
    230         else if (!strict)
    231         {
    232             // "strict" is false, the name just needs to start with '['
    233             valid_prefix = name[0] == '[';
    234         }
    235 
    236         if (valid_prefix)
    237         {
    238             int name_len = strlen (name);
    239             // Objective C methods must have at least:
    240             //      "-[" or "+[" prefix
    241             //      One character for a class name
    242             //      One character for the space between the class name
    243             //      One character for the method name
    244             //      "]" suffix
    245             if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']')
    246             {
    247                 m_full.SetCStringWithLength(name, name_len);
    248             }
    249         }
    250     }
    251     return IsValid(strict);
    252 }
    253 
    254 const ConstString &
    255 ObjCLanguageRuntime::MethodName::GetClassName ()
    256 {
    257     if (!m_class)
    258     {
    259         if (IsValid(false))
    260         {
    261             const char *full = m_full.GetCString();
    262             const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
    263             const char *paren_pos = strchr (class_start, '(');
    264             if (paren_pos)
    265             {
    266                 m_class.SetCStringWithLength (class_start, paren_pos - class_start);
    267             }
    268             else
    269             {
    270                 // No '(' was found in the full name, we can definitively say
    271                 // that our category was valid (and empty).
    272                 m_category_is_valid = true;
    273                 const char *space_pos = strchr (full, ' ');
    274                 if (space_pos)
    275                 {
    276                     m_class.SetCStringWithLength (class_start, space_pos - class_start);
    277                     if (!m_class_category)
    278                     {
    279                         // No category in name, so we can also fill in the m_class_category
    280                         m_class_category = m_class;
    281                     }
    282                 }
    283             }
    284         }
    285     }
    286     return m_class;
    287 }
    288 
    289 const ConstString &
    290 ObjCLanguageRuntime::MethodName::GetClassNameWithCategory ()
    291 {
    292     if (!m_class_category)
    293     {
    294         if (IsValid(false))
    295         {
    296             const char *full = m_full.GetCString();
    297             const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
    298             const char *space_pos = strchr (full, ' ');
    299             if (space_pos)
    300             {
    301                 m_class_category.SetCStringWithLength (class_start, space_pos - class_start);
    302                 // If m_class hasn't been filled in and the class with category doesn't
    303                 // contain a '(', then we can also fill in the m_class
    304                 if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL)
    305                 {
    306                     m_class = m_class_category;
    307                     // No '(' was found in the full name, we can definitively say
    308                     // that our category was valid (and empty).
    309                     m_category_is_valid = true;
    310 
    311                 }
    312             }
    313         }
    314     }
    315     return m_class_category;
    316 }
    317 
    318 const ConstString &
    319 ObjCLanguageRuntime::MethodName::GetSelector ()
    320 {
    321     if (!m_selector)
    322     {
    323         if (IsValid(false))
    324         {
    325             const char *full = m_full.GetCString();
    326             const char *space_pos = strchr (full, ' ');
    327             if (space_pos)
    328             {
    329                 ++space_pos; // skip the space
    330                 m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1);
    331             }
    332         }
    333     }
    334     return m_selector;
    335 }
    336 
    337 const ConstString &
    338 ObjCLanguageRuntime::MethodName::GetCategory ()
    339 {
    340     if (!m_category_is_valid && !m_category)
    341     {
    342         if (IsValid(false))
    343         {
    344             m_category_is_valid = true;
    345             const char *full = m_full.GetCString();
    346             const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
    347             const char *open_paren_pos = strchr (class_start, '(');
    348             if (open_paren_pos)
    349             {
    350                 ++open_paren_pos; // Skip the open paren
    351                 const char *close_paren_pos = strchr (open_paren_pos, ')');
    352                 if (close_paren_pos)
    353                     m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos);
    354             }
    355         }
    356     }
    357     return m_category;
    358 }
    359 
    360 ConstString
    361 ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category)
    362 {
    363     if (IsValid(false))
    364     {
    365         if (HasCategory())
    366         {
    367             StreamString strm;
    368             if (m_type == eTypeClassMethod)
    369                 strm.PutChar('+');
    370             else if (m_type == eTypeInstanceMethod)
    371                 strm.PutChar('-');
    372             strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString());
    373             return ConstString(strm.GetString().c_str());
    374         }
    375 
    376         if (!empty_if_no_category)
    377         {
    378             // Just return the full name since it doesn't have a category
    379             return GetFullName();
    380         }
    381     }
    382     return ConstString();
    383 }
    384 
    385 size_t
    386 ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append)
    387 {
    388     if (!append)
    389         names.clear();
    390     if (IsValid(false))
    391     {
    392         StreamString strm;
    393         const bool is_class_method = m_type == eTypeClassMethod;
    394         const bool is_instance_method = m_type == eTypeInstanceMethod;
    395         const ConstString &category = GetCategory();
    396         if (is_class_method || is_instance_method)
    397         {
    398             names.push_back (m_full);
    399             if (category)
    400             {
    401                 strm.Printf("%c[%s %s]",
    402                             is_class_method ? '+' : '-',
    403                             GetClassName().GetCString(),
    404                             GetSelector().GetCString());
    405                 names.push_back(ConstString(strm.GetString().c_str()));
    406             }
    407         }
    408         else
    409         {
    410             const ConstString &class_name = GetClassName();
    411             const ConstString &selector = GetSelector();
    412             strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString());
    413             names.push_back(ConstString(strm.GetString().c_str()));
    414             strm.Clear();
    415             strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString());
    416             names.push_back(ConstString(strm.GetString().c_str()));
    417             strm.Clear();
    418             if (category)
    419             {
    420                 strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
    421                 names.push_back(ConstString(strm.GetString().c_str()));
    422                 strm.Clear();
    423                 strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
    424                 names.push_back(ConstString(strm.GetString().c_str()));
    425             }
    426         }
    427     }
    428     return names.size();
    429 }
    430 
    431 
    432 bool
    433 ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
    434                                                       uint32_t ptr_size,
    435                                                       bool allow_NULLs,
    436                                                       bool allow_tagged,
    437                                                       bool check_version_specific) const
    438 {
    439     if (!value)
    440         return allow_NULLs;
    441     if ( (value % 2) == 1  && allow_tagged)
    442         return true;
    443     if ((value % ptr_size) == 0)
    444         return (check_version_specific ? CheckPointer(value,ptr_size) : true);
    445     else
    446         return false;
    447 }
    448 
    449 ObjCLanguageRuntime::ObjCISA
    450 ObjCLanguageRuntime::GetISA(const ConstString &name)
    451 {
    452     ISAToDescriptorIterator pos = GetDescriptorIterator (name);
    453     if (pos != m_isa_to_descriptor.end())
    454         return pos->first;
    455     return 0;
    456 }
    457 
    458 ObjCLanguageRuntime::ISAToDescriptorIterator
    459 ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
    460 {
    461     ISAToDescriptorIterator end = m_isa_to_descriptor.end();
    462 
    463     if (name)
    464     {
    465         UpdateISAToDescriptorMap();
    466         if (m_hash_to_isa_map.empty())
    467         {
    468             // No name hashes were provided, we need to just linearly power through the
    469             // names and find a match
    470             for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
    471             {
    472                 if (pos->second->GetClassName() == name)
    473                     return pos;
    474             }
    475         }
    476         else
    477         {
    478             // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
    479             const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
    480             std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
    481             for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
    482             {
    483                 ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
    484                 if (pos != m_isa_to_descriptor.end())
    485                 {
    486                     if (pos->second->GetClassName() == name)
    487                         return pos;
    488                 }
    489             }
    490         }
    491     }
    492     return end;
    493 }
    494 
    495 
    496 ObjCLanguageRuntime::ObjCISA
    497 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
    498 {
    499     ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa));
    500     if (objc_class_sp)
    501     {
    502         ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass());
    503         if (objc_super_class_sp)
    504             return objc_super_class_sp->GetISA();
    505     }
    506     return 0;
    507 }
    508 
    509 ConstString
    510 ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
    511 {
    512     ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa));
    513     if (objc_class_sp)
    514         return objc_class_sp->GetClassName();
    515     return ConstString();
    516 }
    517 
    518 ObjCLanguageRuntime::ClassDescriptorSP
    519 ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name)
    520 {
    521     ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
    522     if (pos != m_isa_to_descriptor.end())
    523         return pos->second;
    524     return ClassDescriptorSP();
    525 
    526 }
    527 
    528 ObjCLanguageRuntime::ClassDescriptorSP
    529 ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj)
    530 {
    531     ClassDescriptorSP objc_class_sp;
    532     // if we get an invalid VO (which might still happen when playing around
    533     // with pointers returned by the expression parser, don't consider this
    534     // a valid ObjC object)
    535     if (valobj.GetClangType().IsValid())
    536     {
    537         addr_t isa_pointer = valobj.GetPointerValue();
    538         if (isa_pointer != LLDB_INVALID_ADDRESS)
    539         {
    540             ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
    541 
    542             Process *process = exe_ctx.GetProcessPtr();
    543             if (process)
    544             {
    545                 Error error;
    546                 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
    547                 if (isa != LLDB_INVALID_ADDRESS)
    548                     objc_class_sp = GetClassDescriptorFromISA (isa);
    549             }
    550         }
    551     }
    552     return objc_class_sp;
    553 }
    554 
    555 ObjCLanguageRuntime::ClassDescriptorSP
    556 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj)
    557 {
    558     ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj));
    559     if (objc_class_sp)
    560     {
    561         if (!objc_class_sp->IsKVO())
    562             return objc_class_sp;
    563 
    564         ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
    565         if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
    566             return non_kvo_objc_class_sp;
    567     }
    568     return ClassDescriptorSP();
    569 }
    570 
    571 
    572 ObjCLanguageRuntime::ClassDescriptorSP
    573 ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa)
    574 {
    575     if (isa)
    576     {
    577         UpdateISAToDescriptorMap();
    578         ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
    579         if (pos != m_isa_to_descriptor.end())
    580             return pos->second;
    581     }
    582     return ClassDescriptorSP();
    583 }
    584 
    585 ObjCLanguageRuntime::ClassDescriptorSP
    586 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
    587 {
    588     if (isa)
    589     {
    590         ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa);
    591         if (objc_class_sp && objc_class_sp->IsValid())
    592         {
    593             if (!objc_class_sp->IsKVO())
    594                 return objc_class_sp;
    595 
    596             ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
    597             if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
    598                 return non_kvo_objc_class_sp;
    599         }
    600     }
    601     return ClassDescriptorSP();
    602 }
    603 
    604 
    605 
    606