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