1 //===-- AppleObjCSymbolVendor.cpp -------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "AppleObjCTypeVendor.h"
11
12 #include "lldb/Core/Log.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Expression/ASTDumper.h"
15 #include "lldb/Symbol/ClangExternalASTSourceCommon.h"
16 #include "lldb/Target/ObjCLanguageRuntime.h"
17 #include "lldb/Target/Process.h"
18 #include "lldb/Target/Target.h"
19
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/DeclObjC.h"
22
23 using namespace lldb_private;
24
25 class lldb_private::AppleObjCExternalASTSource : public ClangExternalASTSourceCommon
26 {
27 public:
AppleObjCExternalASTSource(AppleObjCTypeVendor & type_vendor)28 AppleObjCExternalASTSource (AppleObjCTypeVendor &type_vendor) :
29 m_type_vendor(type_vendor)
30 {
31 }
32
33 bool
FindExternalVisibleDeclsByName(const clang::DeclContext * decl_ctx,clang::DeclarationName name)34 FindExternalVisibleDeclsByName (const clang::DeclContext *decl_ctx,
35 clang::DeclarationName name)
36 {
37 static unsigned int invocation_id = 0;
38 unsigned int current_id = invocation_id++;
39
40 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
41
42 if (log)
43 {
44 log->Printf("AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
45 current_id,
46 &decl_ctx->getParentASTContext(),
47 name.getAsString().c_str(),
48 decl_ctx->getDeclKindName(),
49 decl_ctx);
50 }
51
52 do
53 {
54 const clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
55
56 if (!interface_decl)
57 break;
58
59 clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl);
60
61 if (!m_type_vendor.FinishDecl(non_const_interface_decl))
62 break;
63
64 clang::DeclContext::lookup_const_result result = non_const_interface_decl->lookup(name);
65
66 return (result.size() != 0);
67 }
68 while(0);
69
70 SetNoExternalVisibleDeclsForName(decl_ctx, name);
71 return false;
72 }
73
74 clang::ExternalLoadResult
FindExternalLexicalDecls(const clang::DeclContext * DC,bool (* isKindWeWant)(clang::Decl::Kind),llvm::SmallVectorImpl<clang::Decl * > & Decls)75 FindExternalLexicalDecls (const clang::DeclContext *DC,
76 bool (*isKindWeWant)(clang::Decl::Kind),
77 llvm::SmallVectorImpl<clang::Decl*> &Decls)
78 {
79 return clang::ELR_Success;
80 }
81
82 void
CompleteType(clang::TagDecl * tag_decl)83 CompleteType (clang::TagDecl *tag_decl)
84 {
85 static unsigned int invocation_id = 0;
86 unsigned int current_id = invocation_id++;
87
88 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
89
90 if (log)
91 {
92 log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
93 current_id,
94 &tag_decl->getASTContext(),
95 tag_decl,
96 tag_decl->getName().str().c_str());
97
98 log->Printf(" AOEAS::CT[%u] Before:", current_id);
99 ASTDumper dumper((clang::Decl*)tag_decl);
100 dumper.ToLog(log, " [CT] ");
101 }
102
103 if (log)
104 {
105 log->Printf(" AOEAS::CT[%u] After:", current_id);
106 ASTDumper dumper((clang::Decl*)tag_decl);
107 dumper.ToLog(log, " [CT] ");
108 }
109 return;
110 }
111
112 void
CompleteType(clang::ObjCInterfaceDecl * interface_decl)113 CompleteType (clang::ObjCInterfaceDecl *interface_decl)
114 {
115 static unsigned int invocation_id = 0;
116 unsigned int current_id = invocation_id++;
117
118 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
119
120 if (log)
121 {
122 log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
123 current_id,
124 &interface_decl->getASTContext(),
125 interface_decl,
126 interface_decl->getName().str().c_str());
127
128 log->Printf(" AOEAS::CT[%u] Before:", current_id);
129 ASTDumper dumper((clang::Decl*)interface_decl);
130 dumper.ToLog(log, " [CT] ");
131 }
132
133 m_type_vendor.FinishDecl(interface_decl);
134
135 if (log)
136 {
137 log->Printf(" [CT] After:");
138 ASTDumper dumper((clang::Decl*)interface_decl);
139 dumper.ToLog(log, " [CT] ");
140 }
141 return;
142 }
143
144 bool
layoutRecordType(const clang::RecordDecl * Record,uint64_t & Size,uint64_t & Alignment,llvm::DenseMap<const clang::FieldDecl *,uint64_t> & FieldOffsets,llvm::DenseMap<const clang::CXXRecordDecl *,clang::CharUnits> & BaseOffsets,llvm::DenseMap<const clang::CXXRecordDecl *,clang::CharUnits> & VirtualBaseOffsets)145 layoutRecordType(const clang::RecordDecl *Record,
146 uint64_t &Size,
147 uint64_t &Alignment,
148 llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
149 llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
150 llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
151 {
152 return false;
153 }
154
StartTranslationUnit(clang::ASTConsumer * Consumer)155 void StartTranslationUnit (clang::ASTConsumer *Consumer)
156 {
157 clang::TranslationUnitDecl *translation_unit_decl = m_type_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl();
158 translation_unit_decl->setHasExternalVisibleStorage();
159 translation_unit_decl->setHasExternalLexicalStorage();
160 }
161 private:
162 AppleObjCTypeVendor &m_type_vendor;
163 };
164
AppleObjCTypeVendor(ObjCLanguageRuntime & runtime)165 AppleObjCTypeVendor::AppleObjCTypeVendor(ObjCLanguageRuntime &runtime) :
166 TypeVendor(),
167 m_runtime(runtime),
168 m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str())
169 {
170 m_external_source = new AppleObjCExternalASTSource (*this);
171 llvm::OwningPtr<clang::ExternalASTSource> external_source_owning_ptr (m_external_source);
172 m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr);
173 }
174
175 clang::ObjCInterfaceDecl*
GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)176 AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
177 {
178 ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
179
180 if (iter != m_isa_to_interface.end())
181 return iter->second;
182
183 clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
184
185 ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(isa);
186
187 if (!descriptor)
188 return NULL;
189
190 const ConstString &name(descriptor->GetClassName());
191
192 clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
193
194 clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
195 ast_ctx->getTranslationUnitDecl(),
196 clang::SourceLocation(),
197 &identifier_info,
198 NULL);
199
200 ClangASTMetadata meta_data;
201 meta_data.SetISAPtr(isa);
202 m_external_source->SetMetadata(new_iface_decl, meta_data);
203
204 new_iface_decl->setHasExternalVisibleStorage();
205 new_iface_decl->setHasExternalLexicalStorage();
206
207 ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
208
209 m_isa_to_interface[isa] = new_iface_decl;
210
211 return new_iface_decl;
212 }
213
214 class ObjCRuntimeMethodType
215 {
216 public:
ObjCRuntimeMethodType(const char * types)217 ObjCRuntimeMethodType (const char *types) : m_is_valid(false)
218 {
219 const char *cursor = types;
220 enum ParserState {
221 Start = 0,
222 InType,
223 InPos
224 } state = Start;
225 const char *type = NULL;
226 int brace_depth = 0;
227
228 uint32_t stepsLeft = 256;
229
230 while (1)
231 {
232 if (--stepsLeft == 0)
233 {
234 m_is_valid = false;
235 return;
236 }
237
238 switch (state)
239 {
240 case Start:
241 {
242 switch (*cursor)
243 {
244 default:
245 state = InType;
246 type = cursor;
247 break;
248 case '\0':
249 m_is_valid = true;
250 return;
251 case '0': case '1': case '2': case '3': case '4':
252 case '5': case '6': case '7': case '8': case '9':
253 m_is_valid = false;
254 return;
255 }
256 }
257 break;
258 case InType:
259 {
260 switch (*cursor)
261 {
262 default:
263 ++cursor;
264 break;
265 case '0': case '1': case '2': case '3': case '4':
266 case '5': case '6': case '7': case '8': case '9':
267 if (!brace_depth)
268 {
269 state = InPos;
270 if (type)
271 {
272 m_type_vector.push_back(std::string(type, (cursor - type)));
273 }
274 else
275 {
276 m_is_valid = false;
277 return;
278 }
279 type = NULL;
280 }
281 else
282 {
283 ++cursor;
284 }
285 break;
286 case '[': case '{': case '(':
287 ++brace_depth;
288 ++cursor;
289 break;
290 case ']': case '}': case ')':
291 if (!brace_depth)
292 {
293 m_is_valid = false;
294 return;
295 }
296 --brace_depth;
297 ++cursor;
298 break;
299 case '\0':
300 m_is_valid = false;
301 return;
302 }
303 }
304 break;
305 case InPos:
306 {
307 switch (*cursor)
308 {
309 default:
310 state = InType;
311 type = cursor;
312 break;
313 case '0': case '1': case '2': case '3': case '4':
314 case '5': case '6': case '7': case '8': case '9':
315 ++cursor;
316 break;
317 case '\0':
318 m_is_valid = true;
319 return;
320 }
321 }
322 break;
323 }
324 }
325 }
326
BuildMethod(clang::ObjCInterfaceDecl * interface_decl,const char * name,bool instance)327 clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance)
328 {
329 if (!m_is_valid || m_type_vector.size() < 3)
330 return NULL;
331
332 clang::ASTContext &ast_ctx(interface_decl->getASTContext());
333
334 clang::QualType return_qual_type;
335
336 const bool isInstance = instance;
337 const bool isVariadic = false;
338 const bool isSynthesized = false;
339 const bool isImplicitlyDeclared = true;
340 const bool isDefined = false;
341 const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None;
342 const bool HasRelatedResultType = false;
343
344 std::vector <clang::IdentifierInfo *> selector_components;
345
346 const char *name_cursor = name;
347 bool is_zero_argument = true;
348
349 while (*name_cursor != '\0')
350 {
351 const char *colon_loc = strchr(name_cursor, ':');
352 if (!colon_loc)
353 {
354 selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
355 break;
356 }
357 else
358 {
359 is_zero_argument = false;
360 selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor, colon_loc - name_cursor)));
361 name_cursor = colon_loc + 1;
362 }
363 }
364
365 clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data());
366
367 clang::QualType ret_type = BuildType(ast_ctx, m_type_vector[0].c_str());
368
369 if (ret_type.isNull())
370 return NULL;
371
372 clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(ast_ctx,
373 clang::SourceLocation(),
374 clang::SourceLocation(),
375 sel,
376 ret_type,
377 NULL,
378 interface_decl,
379 isInstance,
380 isVariadic,
381 isSynthesized,
382 isImplicitlyDeclared,
383 isDefined,
384 impControl,
385 HasRelatedResultType);
386
387 std::vector <clang::ParmVarDecl*> parm_vars;
388
389 for (size_t ai = 3, ae = m_type_vector.size();
390 ai != ae;
391 ++ai)
392 {
393 clang::QualType arg_type = BuildType(ast_ctx, m_type_vector[ai].c_str());
394
395 if (arg_type.isNull())
396 return NULL; // well, we just wasted a bunch of time. Wish we could delete the stuff we'd just made!
397
398 parm_vars.push_back(clang::ParmVarDecl::Create(ast_ctx,
399 ret,
400 clang::SourceLocation(),
401 clang::SourceLocation(),
402 NULL,
403 arg_type,
404 NULL,
405 clang::SC_None,
406 NULL));
407 }
408
409 ret->setMethodParams(ast_ctx, llvm::ArrayRef<clang::ParmVarDecl*>(parm_vars), llvm::ArrayRef<clang::SourceLocation>());
410
411 return ret;
412 }
413 private:
BuildType(clang::ASTContext & ast_ctx,const char * type)414 clang::QualType BuildType (clang::ASTContext &ast_ctx, const char *type)
415 {
416 if (!type)
417 return clang::QualType();
418
419 switch (*type)
420 {
421 default:
422 return ast_ctx.UnknownAnyTy;
423 case 'r':
424 {
425 clang::QualType target_type = BuildType(ast_ctx, type+1);
426 if (target_type.isNull())
427 return clang::QualType();
428 else if (target_type == ast_ctx.UnknownAnyTy)
429 return ast_ctx.UnknownAnyTy;
430 else
431 return ast_ctx.getConstType(target_type);
432 }
433 case '^':
434 {
435 clang::QualType target_type = BuildType(ast_ctx, type+1);
436 if (target_type.isNull())
437 return clang::QualType();
438 else if (target_type == ast_ctx.UnknownAnyTy)
439 return ast_ctx.UnknownAnyTy;
440 else
441 return ast_ctx.getPointerType(target_type);
442 }
443 case 'c':
444 return ast_ctx.CharTy;
445 case 'i':
446 return ast_ctx.IntTy;
447 case 's':
448 return ast_ctx.ShortTy;
449 case 'l':
450 if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
451 return ast_ctx.IntTy;
452 else
453 return ast_ctx.LongTy;
454 case 'q':
455 return ast_ctx.LongLongTy;
456 case 'C':
457 return ast_ctx.UnsignedCharTy;
458 case 'I':
459 return ast_ctx.UnsignedIntTy;
460 case 'S':
461 return ast_ctx.UnsignedShortTy;
462 case 'L':
463 if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
464 return ast_ctx.UnsignedIntTy;
465 else
466 return ast_ctx.UnsignedLongTy;
467 case 'Q':
468 return ast_ctx.UnsignedLongLongTy;
469 case 'f':
470 return ast_ctx.FloatTy;
471 case 'd':
472 return ast_ctx.DoubleTy;
473 case 'B':
474 return ast_ctx.BoolTy;
475 case 'v':
476 return ast_ctx.VoidTy;
477 case '*':
478 return ast_ctx.getPointerType(ast_ctx.CharTy);
479 case '@':
480 return ast_ctx.getObjCIdType();
481 case '#':
482 return ast_ctx.getObjCClassType();
483 case ':':
484 return ast_ctx.getObjCSelType();
485 }
486 return clang::QualType();
487 }
488
489 typedef std::vector <std::string> TypeVector;
490
491 TypeVector m_type_vector;
492 bool m_is_valid;
493 };
494
495 bool
FinishDecl(clang::ObjCInterfaceDecl * interface_decl)496 AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
497 {
498 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
499
500 ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl);
501 ObjCLanguageRuntime::ObjCISA objc_isa = 0;
502 if (metadata)
503 objc_isa = metadata->GetISAPtr();
504
505 if (!objc_isa)
506 return false;
507
508 if (!interface_decl->hasExternalVisibleStorage())
509 return true;
510
511 interface_decl->startDefinition();
512
513 interface_decl->setHasExternalVisibleStorage(false);
514 interface_decl->setHasExternalLexicalStorage(false);
515
516 ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(objc_isa);
517
518 if (!descriptor)
519 return false;
520
521 auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa)
522 {
523 clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
524 if (!superclass_decl)
525 return;
526 interface_decl->setSuperClass(superclass_decl);
527 };
528
529 auto instance_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool
530 {
531 ObjCRuntimeMethodType method_type(types);
532
533 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true);
534
535 if (log)
536 log->Printf("[ AOTV::FD] Instance method [%s] [%s]", name, types);
537
538 if (method_decl)
539 interface_decl->addDecl(method_decl);
540
541 return false;
542 };
543
544 auto class_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool
545 {
546 ObjCRuntimeMethodType method_type(types);
547
548 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false);
549
550 if (log)
551 log->Printf("[ AOTV::FD] Class method [%s] [%s]", name, types);
552
553 if (method_decl)
554 interface_decl->addDecl(method_decl);
555
556 return false;
557 };
558
559 if (log)
560 {
561 ASTDumper method_dumper ((clang::Decl*)interface_decl);
562
563 log->Printf("[AppleObjCTypeVendor::FinishDecl] Finishing Objective-C interface for %s", descriptor->GetClassName().AsCString());
564 }
565
566
567 if (!descriptor->Describe(superclass_func,
568 instance_method_func,
569 class_method_func,
570 std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr)))
571 return false;
572
573 if (log)
574 {
575 ASTDumper method_dumper ((clang::Decl*)interface_decl);
576
577 log->Printf("[AppleObjCTypeVendor::FinishDecl] Finished Objective-C interface");
578
579 method_dumper.ToLog(log, " [AOTV::FD] ");
580 }
581
582 return true;
583 }
584
585 uint32_t
FindTypes(const ConstString & name,bool append,uint32_t max_matches,std::vector<ClangASTType> & types)586 AppleObjCTypeVendor::FindTypes (const ConstString &name,
587 bool append,
588 uint32_t max_matches,
589 std::vector <ClangASTType> &types)
590 {
591 static unsigned int invocation_id = 0;
592 unsigned int current_id = invocation_id++;
593
594 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
595
596 if (log)
597 log->Printf("AppleObjCTypeVendor::FindTypes [%u] ('%s', %s, %u, )",
598 current_id,
599 (const char*)name.AsCString(),
600 append ? "true" : "false",
601 max_matches);
602
603 if (!append)
604 types.clear();
605
606 uint32_t ret = 0;
607
608 do
609 {
610 // See if the type is already in our ASTContext.
611
612 clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
613
614 clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
615 clang::DeclarationName decl_name = ast_ctx->DeclarationNames.getIdentifier(&identifier_info);
616
617 clang::DeclContext::lookup_const_result lookup_result = ast_ctx->getTranslationUnitDecl()->lookup(decl_name);
618
619 if (!lookup_result.empty())
620 {
621 if (const clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0]))
622 {
623 clang::QualType result_iface_type = ast_ctx->getObjCInterfaceType(result_iface_decl);
624
625 if (log)
626 {
627 ASTDumper dumper(result_iface_type);
628
629 uint64_t isa_value = LLDB_INVALID_ADDRESS;
630 ClangASTMetadata *metadata = m_external_source->GetMetadata(result_iface_decl);
631 if (metadata)
632 isa_value = metadata->GetISAPtr();
633
634 log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 ") in the ASTContext",
635 current_id,
636 dumper.GetCString(),
637 isa_value);
638 }
639
640 types.push_back(ClangASTType(ast_ctx, result_iface_type.getAsOpaquePtr()));
641 ret++;
642 break;
643 }
644 else
645 {
646 if (log)
647 log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but it's not something we know about",
648 current_id);
649 break;
650 }
651 }
652 else if(log)
653 {
654 log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext",
655 current_id,
656 name.AsCString());
657 }
658
659 // It's not. If it exists, we have to put it into our ASTContext.
660
661 ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
662
663 if (!isa)
664 {
665 if (log)
666 log->Printf("AOCTV::FT [%u] Couldn't find the isa",
667 current_id);
668
669 break;
670 }
671
672 clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
673
674 if (!iface_decl)
675 {
676 if (log)
677 log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%" PRIx64,
678 current_id,
679 (uint64_t)isa);
680
681 break;
682 }
683
684 clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl);
685
686 if (log)
687 {
688 ASTDumper dumper(new_iface_type);
689 log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")",
690 current_id,
691 dumper.GetCString(),
692 (uint64_t)isa);
693 }
694
695 types.push_back(ClangASTType(ast_ctx, new_iface_type.getAsOpaquePtr()));
696 ret++;
697 break;
698 } while (0);
699
700 return ret;
701 }
702