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 //----------------------------------------------------------------------
~ObjCLanguageRuntime()31 ObjCLanguageRuntime::~ObjCLanguageRuntime()
32 {
33 }
34
ObjCLanguageRuntime(Process * process)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
AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp,const char * class_name)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
AddToMethodCache(lldb::addr_t class_addr,lldb::addr_t selector,lldb::addr_t impl_addr)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
LookupInMethodCache(lldb::addr_t class_addr,lldb::addr_t selector)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
LookupInCompleteClassCache(ConstString & name)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
GetByteOffsetForIvar(ClangASTType & parent_qual_type,const char * ivar_name)150 ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
151 {
152 return LLDB_INVALID_IVAR_OFFSET;
153 }
154
155 void
Clear()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
SetName(const char * name,bool strict)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 &
GetClassName()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 &
GetClassNameWithCategory()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 &
GetSelector()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 &
GetCategory()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
GetFullNameWithoutCategory(bool empty_if_no_category)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
GetFullNames(std::vector<ConstString> & names,bool append)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
IsPointerValid(lldb::addr_t value,uint32_t ptr_size,bool allow_NULLs,bool allow_tagged,bool check_version_specific) const433 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
GetISA(const ConstString & name)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
GetDescriptorIterator(const ConstString & name)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
GetParentClass(ObjCLanguageRuntime::ObjCISA isa)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
GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)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
GetClassDescriptorFromClassName(const ConstString & class_name)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
GetClassDescriptor(ValueObject & valobj)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
GetNonKVOClassDescriptor(ValueObject & valobj)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
GetClassDescriptorFromISA(ObjCISA isa)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
GetNonKVOClassDescriptor(ObjCISA isa)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