xref: /llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp (revision b852fb1ec5fa15f0b913cc4988cbd09239b19904)
180814287SRaphael Isemann //===-- ObjCLanguageRuntime.cpp -------------------------------------------===//
2b5701710SAlex Langford //
3b5701710SAlex Langford // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b5701710SAlex Langford // See https://llvm.org/LICENSE.txt for license information.
5b5701710SAlex Langford // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b5701710SAlex Langford //
7b5701710SAlex Langford //===----------------------------------------------------------------------===//
8b5701710SAlex Langford #include "clang/AST/Type.h"
9b5701710SAlex Langford 
10b5701710SAlex Langford #include "ObjCLanguageRuntime.h"
11b5701710SAlex Langford 
128be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13b5701710SAlex Langford #include "lldb/Core/Module.h"
14b5701710SAlex Langford #include "lldb/Core/PluginManager.h"
15b5701710SAlex Langford #include "lldb/Symbol/SymbolContext.h"
16b5701710SAlex Langford #include "lldb/Symbol/SymbolFile.h"
17b5701710SAlex Langford #include "lldb/Symbol/Type.h"
18b5701710SAlex Langford #include "lldb/Symbol/TypeList.h"
19b5701710SAlex Langford #include "lldb/Symbol/Variable.h"
208bac9e36SJonas Devlieghere #include "lldb/Target/ABI.h"
21c34698a8SPavel Labath #include "lldb/Target/Target.h"
22c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
23b5701710SAlex Langford #include "lldb/Utility/Log.h"
24b5701710SAlex Langford #include "lldb/Utility/Timer.h"
25*b852fb1eSJonas Devlieghere #include "lldb/ValueObject/ValueObject.h"
26b5701710SAlex Langford 
27b5701710SAlex Langford #include "llvm/ADT/StringRef.h"
28b5701710SAlex Langford #include "llvm/Support/DJB.h"
29f190ce62SKazu Hirata #include <optional>
30b5701710SAlex Langford 
31b5701710SAlex Langford using namespace lldb;
32b5701710SAlex Langford using namespace lldb_private;
33b5701710SAlex Langford 
34b5701710SAlex Langford char ObjCLanguageRuntime::ID = 0;
35b5701710SAlex Langford 
36b5701710SAlex Langford // Destructor
37fd2433e1SJonas Devlieghere ObjCLanguageRuntime::~ObjCLanguageRuntime() = default;
38b5701710SAlex Langford 
39b5701710SAlex Langford ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process)
40833882b3SJim Ingham     : LanguageRuntime(process), m_impl_cache(), m_impl_str_cache(),
41b5701710SAlex Langford       m_has_new_literals_and_indexing(eLazyBoolCalculate),
42b5701710SAlex Langford       m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(),
43b5701710SAlex Langford       m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(),
44b5701710SAlex Langford       m_negative_complete_class_cache() {}
45b5701710SAlex Langford 
46efb328f6SEric Christopher bool ObjCLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
47b5701710SAlex Langford   static ConstString g_self = ConstString("self");
48b5701710SAlex Langford   static ConstString g_cmd = ConstString("_cmd");
49b5701710SAlex Langford   return name == g_self || name == g_cmd;
50b5701710SAlex Langford }
51b5701710SAlex Langford 
52b5701710SAlex Langford bool ObjCLanguageRuntime::AddClass(ObjCISA isa,
53b5701710SAlex Langford                                    const ClassDescriptorSP &descriptor_sp,
54b5701710SAlex Langford                                    const char *class_name) {
55b5701710SAlex Langford   if (isa != 0) {
56b5701710SAlex Langford     m_isa_to_descriptor[isa] = descriptor_sp;
57b5701710SAlex Langford     // class_name is assumed to be valid
58b5701710SAlex Langford     m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa));
59b5701710SAlex Langford     return true;
60b5701710SAlex Langford   }
61b5701710SAlex Langford   return false;
62b5701710SAlex Langford }
63b5701710SAlex Langford 
64b5701710SAlex Langford void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr,
65b5701710SAlex Langford                                            lldb::addr_t selector,
66b5701710SAlex Langford                                            lldb::addr_t impl_addr) {
67a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Step);
68b5701710SAlex Langford   if (log) {
6963e5fb76SJonas Devlieghere     LLDB_LOGF(log,
7063e5fb76SJonas Devlieghere               "Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
71b5701710SAlex Langford               " implementation 0x%" PRIx64 ".",
72b5701710SAlex Langford               class_addr, selector, impl_addr);
73b5701710SAlex Langford   }
74b5701710SAlex Langford   m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
75b5701710SAlex Langford       ClassAndSel(class_addr, selector), impl_addr));
76b5701710SAlex Langford }
77b5701710SAlex Langford 
78833882b3SJim Ingham void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr,
79833882b3SJim Ingham                                            llvm::StringRef sel_str,
80833882b3SJim Ingham                                            lldb::addr_t impl_addr) {
81833882b3SJim Ingham   Log *log = GetLog(LLDBLog::Step);
82833882b3SJim Ingham 
83833882b3SJim Ingham   LLDB_LOG(log, "Caching: class {0} selector {1} implementation {2}.",
84833882b3SJim Ingham            class_addr, sel_str, impl_addr);
85833882b3SJim Ingham 
86833882b3SJim Ingham   m_impl_str_cache.insert(std::pair<ClassAndSelStr, lldb::addr_t>(
87833882b3SJim Ingham       ClassAndSelStr(class_addr, sel_str), impl_addr));
88833882b3SJim Ingham }
89833882b3SJim Ingham 
90b5701710SAlex Langford lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr,
91b5701710SAlex Langford                                                       lldb::addr_t selector) {
92b5701710SAlex Langford   MsgImplMap::iterator pos, end = m_impl_cache.end();
93b5701710SAlex Langford   pos = m_impl_cache.find(ClassAndSel(class_addr, selector));
94b5701710SAlex Langford   if (pos != end)
95b5701710SAlex Langford     return (*pos).second;
96b5701710SAlex Langford   return LLDB_INVALID_ADDRESS;
97b5701710SAlex Langford }
98b5701710SAlex Langford 
99833882b3SJim Ingham lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr,
100833882b3SJim Ingham                                                       llvm::StringRef sel_str) {
101833882b3SJim Ingham   MsgImplStrMap::iterator pos, end = m_impl_str_cache.end();
102833882b3SJim Ingham   pos = m_impl_str_cache.find(ClassAndSelStr(class_addr, sel_str));
103833882b3SJim Ingham   if (pos != end)
104833882b3SJim Ingham     return (*pos).second;
105833882b3SJim Ingham   return LLDB_INVALID_ADDRESS;
106833882b3SJim Ingham }
107833882b3SJim Ingham 
108b5701710SAlex Langford lldb::TypeSP
109b5701710SAlex Langford ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) {
110b5701710SAlex Langford   CompleteClassMap::iterator complete_class_iter =
111b5701710SAlex Langford       m_complete_class_cache.find(name);
112b5701710SAlex Langford 
113b5701710SAlex Langford   if (complete_class_iter != m_complete_class_cache.end()) {
114b5701710SAlex Langford     // Check the weak pointer to make sure the type hasn't been unloaded
115b5701710SAlex Langford     TypeSP complete_type_sp(complete_class_iter->second.lock());
116b5701710SAlex Langford 
117b5701710SAlex Langford     if (complete_type_sp)
118b5701710SAlex Langford       return complete_type_sp;
119b5701710SAlex Langford     else
120b5701710SAlex Langford       m_complete_class_cache.erase(name);
121b5701710SAlex Langford   }
122b5701710SAlex Langford 
123b5701710SAlex Langford   if (m_negative_complete_class_cache.count(name) > 0)
124b5701710SAlex Langford     return TypeSP();
125b5701710SAlex Langford 
126b5701710SAlex Langford   const ModuleList &modules = m_process->GetTarget().GetImages();
127b5701710SAlex Langford 
128b5701710SAlex Langford   SymbolContextList sc_list;
129b5701710SAlex Langford   modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
1301ad655e2SAdrian Prantl   const size_t matching_symbols = sc_list.GetSize();
131b5701710SAlex Langford 
132b5701710SAlex Langford   if (matching_symbols) {
133b5701710SAlex Langford     SymbolContext sc;
134b5701710SAlex Langford 
135b5701710SAlex Langford     sc_list.GetContextAtIndex(0, sc);
136b5701710SAlex Langford 
137b5701710SAlex Langford     ModuleSP module_sp(sc.module_sp);
138b5701710SAlex Langford 
139b5701710SAlex Langford     if (!module_sp)
140b5701710SAlex Langford       return TypeSP();
141b5701710SAlex Langford 
142dd958779SGreg Clayton     TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match);
143dd958779SGreg Clayton     TypeResults results;
144dd958779SGreg Clayton     module_sp->FindTypes(query, results);
145dd958779SGreg Clayton     for (const TypeSP &type_sp : results.GetTypeMap().Types()) {
1466e3b0cc2SRaphael Isemann       if (TypeSystemClang::IsObjCObjectOrInterfaceType(
147b5701710SAlex Langford               type_sp->GetForwardCompilerType())) {
1487b06cb45SAdrian Prantl         if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) {
149b5701710SAlex Langford           m_complete_class_cache[name] = type_sp;
150b5701710SAlex Langford           return type_sp;
151b5701710SAlex Langford         }
152b5701710SAlex Langford       }
153b5701710SAlex Langford     }
154b5701710SAlex Langford   }
155b5701710SAlex Langford   m_negative_complete_class_cache.insert(name);
156b5701710SAlex Langford   return TypeSP();
157b5701710SAlex Langford }
158b5701710SAlex Langford 
159b5701710SAlex Langford size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,
160b5701710SAlex Langford                                                  const char *ivar_name) {
161b5701710SAlex Langford   return LLDB_INVALID_IVAR_OFFSET;
162b5701710SAlex Langford }
163b5701710SAlex Langford 
164b5701710SAlex Langford bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid(
165b5701710SAlex Langford     lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged,
166b5701710SAlex Langford     bool check_version_specific) const {
167b5701710SAlex Langford   if (!value)
168b5701710SAlex Langford     return allow_NULLs;
169b5701710SAlex Langford   if ((value % 2) == 1 && allow_tagged)
170b5701710SAlex Langford     return true;
171b5701710SAlex Langford   if ((value % ptr_size) == 0)
172b5701710SAlex Langford     return (check_version_specific ? CheckPointer(value, ptr_size) : true);
173b5701710SAlex Langford   else
174b5701710SAlex Langford     return false;
175b5701710SAlex Langford }
176b5701710SAlex Langford 
177b5701710SAlex Langford ObjCLanguageRuntime::ObjCISA
178b5701710SAlex Langford ObjCLanguageRuntime::GetISA(ConstString name) {
179b5701710SAlex Langford   ISAToDescriptorIterator pos = GetDescriptorIterator(name);
180b5701710SAlex Langford   if (pos != m_isa_to_descriptor.end())
181b5701710SAlex Langford     return pos->first;
182b5701710SAlex Langford   return 0;
183b5701710SAlex Langford }
184b5701710SAlex Langford 
185b5701710SAlex Langford ObjCLanguageRuntime::ISAToDescriptorIterator
186b5701710SAlex Langford ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) {
187b5701710SAlex Langford   ISAToDescriptorIterator end = m_isa_to_descriptor.end();
188b5701710SAlex Langford 
189b5701710SAlex Langford   if (name) {
190b5701710SAlex Langford     UpdateISAToDescriptorMap();
191b5701710SAlex Langford     if (m_hash_to_isa_map.empty()) {
192b5701710SAlex Langford       // No name hashes were provided, we need to just linearly power through
193b5701710SAlex Langford       // the names and find a match
194b5701710SAlex Langford       for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin();
195b5701710SAlex Langford            pos != end; ++pos) {
196b5701710SAlex Langford         if (pos->second->GetClassName() == name)
197b5701710SAlex Langford           return pos;
198b5701710SAlex Langford       }
199b5701710SAlex Langford     } else {
200b5701710SAlex Langford       // Name hashes were provided, so use them to efficiently lookup name to
201b5701710SAlex Langford       // isa/descriptor
202b5701710SAlex Langford       const uint32_t name_hash = llvm::djbHash(name.GetStringRef());
203b5701710SAlex Langford       std::pair<HashToISAIterator, HashToISAIterator> range =
204b5701710SAlex Langford           m_hash_to_isa_map.equal_range(name_hash);
205b5701710SAlex Langford       for (HashToISAIterator range_pos = range.first; range_pos != range.second;
206b5701710SAlex Langford            ++range_pos) {
207b5701710SAlex Langford         ISAToDescriptorIterator pos =
208b5701710SAlex Langford             m_isa_to_descriptor.find(range_pos->second);
209b5701710SAlex Langford         if (pos != m_isa_to_descriptor.end()) {
210b5701710SAlex Langford           if (pos->second->GetClassName() == name)
211b5701710SAlex Langford             return pos;
212b5701710SAlex Langford         }
213b5701710SAlex Langford       }
214b5701710SAlex Langford     }
215b5701710SAlex Langford   }
216b5701710SAlex Langford   return end;
217b5701710SAlex Langford }
218b5701710SAlex Langford 
219b5701710SAlex Langford std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
220b5701710SAlex Langford           ObjCLanguageRuntime::ISAToDescriptorIterator>
221b5701710SAlex Langford ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
222b5701710SAlex Langford   if (update_if_needed)
223b5701710SAlex Langford     UpdateISAToDescriptorMapIfNeeded();
224b5701710SAlex Langford 
225b5701710SAlex Langford   return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
226b5701710SAlex Langford                    ObjCLanguageRuntime::ISAToDescriptorIterator>(
227b5701710SAlex Langford       m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
228b5701710SAlex Langford }
229b5701710SAlex Langford 
2300b626473SStefan Gränitz void ObjCLanguageRuntime::ReadObjCLibraryIfNeeded(
2310b626473SStefan Gränitz     const ModuleList &module_list) {
2320b626473SStefan Gränitz   if (!HasReadObjCLibrary()) {
2330b626473SStefan Gränitz     std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
2340b626473SStefan Gränitz 
2350b626473SStefan Gränitz     size_t num_modules = module_list.GetSize();
2360b626473SStefan Gränitz     for (size_t i = 0; i < num_modules; i++) {
2370b626473SStefan Gränitz       auto mod = module_list.GetModuleAtIndex(i);
2380b626473SStefan Gränitz       if (IsModuleObjCLibrary(mod)) {
2390b626473SStefan Gränitz         ReadObjCLibrary(mod);
2400b626473SStefan Gränitz         break;
2410b626473SStefan Gränitz       }
2420b626473SStefan Gränitz     }
2430b626473SStefan Gränitz   }
2440b626473SStefan Gränitz }
2450b626473SStefan Gränitz 
246b5701710SAlex Langford ObjCLanguageRuntime::ObjCISA
247b5701710SAlex Langford ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) {
248b5701710SAlex Langford   ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa));
249b5701710SAlex Langford   if (objc_class_sp) {
250b5701710SAlex Langford     ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass());
251b5701710SAlex Langford     if (objc_super_class_sp)
252b5701710SAlex Langford       return objc_super_class_sp->GetISA();
253b5701710SAlex Langford   }
254b5701710SAlex Langford   return 0;
255b5701710SAlex Langford }
256b5701710SAlex Langford 
257b5701710SAlex Langford ObjCLanguageRuntime::ClassDescriptorSP
258b5701710SAlex Langford ObjCLanguageRuntime::GetClassDescriptorFromClassName(
259b5701710SAlex Langford     ConstString class_name) {
260b5701710SAlex Langford   ISAToDescriptorIterator pos = GetDescriptorIterator(class_name);
261b5701710SAlex Langford   if (pos != m_isa_to_descriptor.end())
262b5701710SAlex Langford     return pos->second;
263b5701710SAlex Langford   return ClassDescriptorSP();
264b5701710SAlex Langford }
265b5701710SAlex Langford 
266b5701710SAlex Langford ObjCLanguageRuntime::ClassDescriptorSP
267b5701710SAlex Langford ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {
268b5701710SAlex Langford   ClassDescriptorSP objc_class_sp;
269b5701710SAlex Langford   // if we get an invalid VO (which might still happen when playing around with
270b5701710SAlex Langford   // pointers returned by the expression parser, don't consider this a valid
271b5701710SAlex Langford   // ObjC object)
272b5701710SAlex Langford   if (valobj.GetCompilerType().IsValid()) {
273b5701710SAlex Langford     addr_t isa_pointer = valobj.GetPointerValue();
274b5701710SAlex Langford     if (isa_pointer != LLDB_INVALID_ADDRESS) {
275b5701710SAlex Langford       ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
276b5701710SAlex Langford 
277b5701710SAlex Langford       Process *process = exe_ctx.GetProcessPtr();
278b5701710SAlex Langford       if (process) {
279b5701710SAlex Langford         Status error;
280b5701710SAlex Langford         ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
281b5701710SAlex Langford         if (isa != LLDB_INVALID_ADDRESS)
282b5701710SAlex Langford           objc_class_sp = GetClassDescriptorFromISA(isa);
283b5701710SAlex Langford       }
284b5701710SAlex Langford     }
285b5701710SAlex Langford   }
286b5701710SAlex Langford   return objc_class_sp;
287b5701710SAlex Langford }
288b5701710SAlex Langford 
289b5701710SAlex Langford ObjCLanguageRuntime::ClassDescriptorSP
290b5701710SAlex Langford ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) {
291b5701710SAlex Langford   ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
292b5701710SAlex Langford       GetClassDescriptor(valobj));
293b5701710SAlex Langford   if (objc_class_sp) {
294b5701710SAlex Langford     if (!objc_class_sp->IsKVO())
295b5701710SAlex Langford       return objc_class_sp;
296b5701710SAlex Langford 
297b5701710SAlex Langford     ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
298b5701710SAlex Langford     if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
299b5701710SAlex Langford       return non_kvo_objc_class_sp;
300b5701710SAlex Langford   }
301b5701710SAlex Langford   return ClassDescriptorSP();
302b5701710SAlex Langford }
303b5701710SAlex Langford 
304b5701710SAlex Langford ObjCLanguageRuntime::ClassDescriptorSP
305b5701710SAlex Langford ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) {
306b5701710SAlex Langford   if (isa) {
307b5701710SAlex Langford     UpdateISAToDescriptorMap();
3088bac9e36SJonas Devlieghere 
309b5701710SAlex Langford     ObjCLanguageRuntime::ISAToDescriptorIterator pos =
310b5701710SAlex Langford         m_isa_to_descriptor.find(isa);
311b5701710SAlex Langford     if (pos != m_isa_to_descriptor.end())
312b5701710SAlex Langford       return pos->second;
3138bac9e36SJonas Devlieghere 
3148bac9e36SJonas Devlieghere     if (ABISP abi_sp = m_process->GetABI()) {
3158bac9e36SJonas Devlieghere       pos = m_isa_to_descriptor.find(abi_sp->FixCodeAddress(isa));
3168bac9e36SJonas Devlieghere       if (pos != m_isa_to_descriptor.end())
3178bac9e36SJonas Devlieghere         return pos->second;
3188bac9e36SJonas Devlieghere     }
319b5701710SAlex Langford   }
320b5701710SAlex Langford   return ClassDescriptorSP();
321b5701710SAlex Langford }
322b5701710SAlex Langford 
323b5701710SAlex Langford ObjCLanguageRuntime::ClassDescriptorSP
324b5701710SAlex Langford ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) {
325b5701710SAlex Langford   if (isa) {
326b5701710SAlex Langford     ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa);
327b5701710SAlex Langford     if (objc_class_sp && objc_class_sp->IsValid()) {
328b5701710SAlex Langford       if (!objc_class_sp->IsKVO())
329b5701710SAlex Langford         return objc_class_sp;
330b5701710SAlex Langford 
331b5701710SAlex Langford       ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
332b5701710SAlex Langford       if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
333b5701710SAlex Langford         return non_kvo_objc_class_sp;
334b5701710SAlex Langford     }
335b5701710SAlex Langford   }
336b5701710SAlex Langford   return ClassDescriptorSP();
337b5701710SAlex Langford }
338b5701710SAlex Langford 
339b5701710SAlex Langford CompilerType
340b5701710SAlex Langford ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name,
341b5701710SAlex Langford                                                  bool for_expression) {
3426eaedbb5SAdrian Prantl   if (m_scratch_ast_ctx_sp)
3436eaedbb5SAdrian Prantl     return RealizeType(*m_scratch_ast_ctx_sp, name, for_expression);
344b5701710SAlex Langford   return CompilerType();
345b5701710SAlex Langford }
346b5701710SAlex Langford 
347fd2433e1SJonas Devlieghere ObjCLanguageRuntime::EncodingToType::~EncodingToType() = default;
348b5701710SAlex Langford 
349b5701710SAlex Langford ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
350b5701710SAlex Langford   return nullptr;
351b5701710SAlex Langford }
352b5701710SAlex Langford 
3535e9f247cSJonas Devlieghere std::optional<uint64_t>
3545e9f247cSJonas Devlieghere ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type) {
355b5701710SAlex Langford   void *opaque_ptr = compiler_type.GetOpaqueQualType();
3565e9f247cSJonas Devlieghere   uint64_t cached_size = m_type_size_cache.Lookup(opaque_ptr);
3575e9f247cSJonas Devlieghere   if (cached_size > 0)
3585e9f247cSJonas Devlieghere     return cached_size;
359b5701710SAlex Langford 
360b5701710SAlex Langford   ClassDescriptorSP class_descriptor_sp =
361b5701710SAlex Langford       GetClassDescriptorFromClassName(compiler_type.GetTypeName());
362b5701710SAlex Langford   if (!class_descriptor_sp)
3635e9f247cSJonas Devlieghere     return {};
364b5701710SAlex Langford 
365b5701710SAlex Langford   int32_t max_offset = INT32_MIN;
366b5701710SAlex Langford   uint64_t sizeof_max = 0;
367b5701710SAlex Langford   bool found = false;
368b5701710SAlex Langford 
369b5701710SAlex Langford   for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) {
370b5701710SAlex Langford     const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx);
371b5701710SAlex Langford     int32_t cur_offset = ivar.m_offset;
372b5701710SAlex Langford     if (cur_offset > max_offset) {
373b5701710SAlex Langford       max_offset = cur_offset;
374b5701710SAlex Langford       sizeof_max = ivar.m_size;
375b5701710SAlex Langford       found = true;
376b5701710SAlex Langford     }
377b5701710SAlex Langford   }
378b5701710SAlex Langford 
3795e9f247cSJonas Devlieghere   uint64_t size = 8 * (max_offset + sizeof_max);
3805e9f247cSJonas Devlieghere   if (found && size > 0) {
381b5701710SAlex Langford     m_type_size_cache.Insert(opaque_ptr, size);
3825e9f247cSJonas Devlieghere     return size;
3835e9f247cSJonas Devlieghere   }
384b5701710SAlex Langford 
3855e9f247cSJonas Devlieghere   return {};
386b5701710SAlex Langford }
387b5701710SAlex Langford 
388b5701710SAlex Langford lldb::BreakpointPreconditionSP
389b5701710SAlex Langford ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language,
390b5701710SAlex Langford                                                         bool throw_bp) {
391b5701710SAlex Langford   if (language != eLanguageTypeObjC)
392b5701710SAlex Langford     return lldb::BreakpointPreconditionSP();
393b5701710SAlex Langford   if (!throw_bp)
394b5701710SAlex Langford     return lldb::BreakpointPreconditionSP();
395b5701710SAlex Langford   BreakpointPreconditionSP precondition_sp(
396b5701710SAlex Langford       new ObjCLanguageRuntime::ObjCExceptionPrecondition());
397b5701710SAlex Langford   return precondition_sp;
398b5701710SAlex Langford }
399b5701710SAlex Langford 
400b5701710SAlex Langford // Exception breakpoint Precondition class for ObjC:
401b5701710SAlex Langford void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
402b5701710SAlex Langford     const char *class_name) {
403b5701710SAlex Langford   m_class_names.insert(class_name);
404b5701710SAlex Langford }
405b5701710SAlex Langford 
406fd2433e1SJonas Devlieghere ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() =
407fd2433e1SJonas Devlieghere     default;
408b5701710SAlex Langford 
409b5701710SAlex Langford bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
410b5701710SAlex Langford     StoppointCallbackContext &context) {
411b5701710SAlex Langford   return true;
412b5701710SAlex Langford }
413b5701710SAlex Langford 
414b5701710SAlex Langford void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
415b5701710SAlex Langford     Stream &stream, lldb::DescriptionLevel level) {}
416b5701710SAlex Langford 
417b5701710SAlex Langford Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
418b5701710SAlex Langford     Args &args) {
419b5701710SAlex Langford   Status error;
420b5701710SAlex Langford   if (args.GetArgumentCount() > 0)
4210642cd76SAdrian Prantl     error = Status::FromErrorString(
422b5701710SAlex Langford         "The ObjC Exception breakpoint doesn't support extra options.");
423b5701710SAlex Langford   return error;
424b5701710SAlex Langford }
425b5701710SAlex Langford 
4262fe83274SKazu Hirata std::optional<CompilerType>
427b5701710SAlex Langford ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) {
428b5701710SAlex Langford   CompilerType class_type;
429b5701710SAlex Langford   bool is_pointer_type = false;
430b5701710SAlex Langford 
4316e3b0cc2SRaphael Isemann   if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type))
432b5701710SAlex Langford     is_pointer_type = true;
4336e3b0cc2SRaphael Isemann   else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type))
434b5701710SAlex Langford     class_type = base_type;
435b5701710SAlex Langford   else
436343523d0SKazu Hirata     return std::nullopt;
437b5701710SAlex Langford 
438b5701710SAlex Langford   if (!class_type)
439343523d0SKazu Hirata     return std::nullopt;
440b5701710SAlex Langford 
44130ce956aSRaphael Isemann   ConstString class_name(class_type.GetTypeName());
442b5701710SAlex Langford   if (!class_name)
443343523d0SKazu Hirata     return std::nullopt;
444b5701710SAlex Langford 
445b5701710SAlex Langford   TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name);
446b5701710SAlex Langford   if (!complete_objc_class_type_sp)
447343523d0SKazu Hirata     return std::nullopt;
448b5701710SAlex Langford 
449b5701710SAlex Langford   CompilerType complete_class(
450b5701710SAlex Langford       complete_objc_class_type_sp->GetFullCompilerType());
451b5701710SAlex Langford   if (complete_class.GetCompleteType()) {
452b5701710SAlex Langford     if (is_pointer_type)
453b5701710SAlex Langford       return complete_class.GetPointerType();
454b5701710SAlex Langford     else
455b5701710SAlex Langford       return complete_class;
456b5701710SAlex Langford   }
457b5701710SAlex Langford 
458343523d0SKazu Hirata   return std::nullopt;
459b5701710SAlex Langford }
460