llvm.org GIT mirror llvm / 45e997d
Add a libLTO API to query a memory buffer and check if it contains ObjC categories The linker supports a feature to force load an object from a static archive if it defines an Objective-C category. This API supports this feature by looking at every section in the module to find if a category is defined in the module. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275125 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 3 years ago
8 changed file(s) with 250 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
5858 /// returns "".
5959 std::string getBitcodeTargetTriple(MemoryBufferRef Buffer,
6060 LLVMContext &Context);
61
62 /// Return true if \p Buffer contains a bitcode file with ObjC code (category
63 /// or class) in it.
64 bool isBitcodeContainingObjCCategory(MemoryBufferRef Buffer,
65 LLVMContext &Context);
6166
6267 /// Read the header of the specified bitcode buffer and extract just the
6368 /// producer string information. If successful, this returns a string. On
4343 * @{
4444 */
4545
46 #define LTO_API_VERSION 19
46 #define LTO_API_VERSION 20
4747
4848 /**
4949 * \since prior to LTO_API_VERSION=3
135135 const char* target_triple_prefix);
136136
137137 /**
138 * Checks if a buffer is a loadable object file.
139 *
140 * \since prior to LTO_API_VERSION=3
141 */
142 extern lto_bool_t
143 lto_module_is_object_file_in_memory(const void* mem, size_t length);
138 * Return true if \p Buffer contains a bitcode file with ObjC code (category
139 * or class) in it.
140 *
141 * \since LTO_API_VERSION=20
142 */
143 bool lto_module_has_objc_category(const void *mem, size_t length);
144
145 /**
146 * Checks if a buffer is a loadable object file.
147 *
148 * \since prior to LTO_API_VERSION=3
149 */
150 extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem,
151 size_t length);
144152
145153 /**
146154 * Checks if a buffer is a loadable object compiled for requested target.
312312 /// Cheap mechanism to just extract the identification block out of bitcode.
313313 ErrorOr parseIdentificationBlock();
314314
315 /// Peak at the module content and return true if any ObjC category or class
316 /// is found.
317 ErrorOr hasObjCCategory();
318
315319 static uint64_t decodeSignRotatedValue(uint64_t V);
316320
317321 /// Materialize any deferred Metadata block.
449453 ArrayRef Record);
450454 std::error_code parseMetadataAttachment(Function &F);
451455 ErrorOr parseModuleTriple();
456 ErrorOr hasObjCCategoryInModule();
452457 std::error_code parseUseLists();
453458 std::error_code initStream(std::unique_ptr Streamer);
454459 std::error_code initStreamFromBuffer();
41944199 return std::error_code();
41954200 }
41964201
4202 ErrorOr BitcodeReader::hasObjCCategory() {
4203 if (std::error_code EC = initStream(nullptr))
4204 return EC;
4205
4206 // Sniff for the signature.
4207 if (!hasValidBitcodeHeader(Stream))
4208 return error("Invalid bitcode signature");
4209
4210 // We expect a number of well-defined blocks, though we don't necessarily
4211 // need to understand them all.
4212 while (1) {
4213 BitstreamEntry Entry = Stream.advance();
4214
4215 switch (Entry.Kind) {
4216 case BitstreamEntry::Error:
4217 return error("Malformed block");
4218 case BitstreamEntry::EndBlock:
4219 return std::error_code();
4220
4221 case BitstreamEntry::SubBlock:
4222 if (Entry.ID == bitc::MODULE_BLOCK_ID)
4223 return hasObjCCategoryInModule();
4224
4225 // Ignore other sub-blocks.
4226 if (Stream.SkipBlock())
4227 return error("Malformed block");
4228 continue;
4229
4230 case BitstreamEntry::Record:
4231 Stream.skipRecord(Entry.ID);
4232 continue;
4233 }
4234 }
4235 }
4236
4237 ErrorOr BitcodeReader::hasObjCCategoryInModule() {
4238 if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
4239 return error("Invalid record");
4240
4241 SmallVector Record;
4242 // Read all the records for this module.
4243 while (1) {
4244 BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
4245
4246 switch (Entry.Kind) {
4247 case BitstreamEntry::SubBlock: // Handled for us already.
4248 case BitstreamEntry::Error:
4249 return error("Malformed block");
4250 case BitstreamEntry::EndBlock:
4251 return false;
4252 case BitstreamEntry::Record:
4253 // The interesting case.
4254 break;
4255 }
4256
4257 // Read a record.
4258 switch (Stream.readRecord(Entry.ID, Record)) {
4259 default:
4260 break; // Default behavior, ignore unknown content.
4261 case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N]
4262 std::string S;
4263 if (convertToString(Record, 0, S))
4264 return error("Invalid record");
4265 // Check for the i386 and other (x86_64, ARM) conventions
4266 if (S.find("__DATA, __objc_catlist") != std::string::npos ||
4267 S.find("__OBJC,__category") != std::string::npos)
4268 return true;
4269 break;
4270 }
4271 }
4272 Record.clear();
4273 }
4274 llvm_unreachable("Exit infinite loop");
4275 }
4276
41974277 /// Parse metadata attachments.
41984278 std::error_code BitcodeReader::parseMetadataAttachment(Function &F) {
41994279 if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
65476627 return Triple.get();
65486628 }
65496629
6630 bool llvm::isBitcodeContainingObjCCategory(MemoryBufferRef Buffer,
6631 LLVMContext &Context) {
6632 std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false);
6633 auto R = llvm::make_unique(Buf.release(), Context);
6634 ErrorOr hasObjCCategory = R->hasObjCCategory();
6635 if (hasObjCCategory.getError())
6636 return false;
6637 return hasObjCCategory.get();
6638 }
6639
65506640 std::string llvm::getBitcodeProducerString(MemoryBufferRef Buffer,
65516641 LLVMContext &Context) {
65526642 std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false);
0 ; RUN: llvm-as < %s -o %t
1 ; RUN: llvm-lto -check-for-objc %t | FileCheck %s
2
3 ; CHECK: contains ObjC
4
5
6 target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
7 target triple = "i386-apple-macosx10.12.0"
8
9 module asm "\09.lazy_reference .objc_class_name_A"
10 module asm "\09.objc_category_name_A_foo=0"
11 module asm "\09.globl .objc_category_name_A_foo"
12
13 %0 = type opaque
14 %struct._objc_method = type { i8*, i8*, i8* }
15 %struct._objc_category = type { i8*, i8*, %struct._objc_method_list*, %struct._objc_method_list*, %struct._objc_protocol_list*, i32, %struct._prop_list_t*, %struct._prop_list_t* }
16 %struct._objc_method_list = type opaque
17 %struct._objc_protocol_list = type { %struct._objc_protocol_list*, i32, [0 x %struct._objc_protocol] }
18 %struct._objc_protocol = type { %struct._objc_protocol_extension*, i8*, %struct._objc_protocol_list*, %struct._objc_method_description_list*, %struct._objc_method_description_list* }
19 %struct._objc_protocol_extension = type { i32, %struct._objc_method_description_list*, %struct._objc_method_description_list*, %struct._prop_list_t*, i8**, %struct._prop_list_t* }
20 %struct._objc_method_description_list = type { i32, [0 x %struct._objc_method_description] }
21 %struct._objc_method_description = type { i8*, i8* }
22 %struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
23 %struct._prop_t = type { i8*, i8* }
24 %struct._objc_module = type { i32, i32, i8*, %struct._objc_symtab* }
25 %struct._objc_symtab = type { i32, i8*, i16, i16, [0 x i8*] }
26
27 @OBJC_METH_VAR_NAME_ = private global [12 x i8] c"foo_myStuff\00", section "__TEXT,__cstring,cstring_literals", align 1
28 @OBJC_METH_VAR_TYPE_ = private global [7 x i8] c"v8@0:4\00", section "__TEXT,__cstring,cstring_literals", align 1
29 @OBJC_CLASS_NAME_ = private global [4 x i8] c"foo\00", section "__TEXT,__cstring,cstring_literals", align 1
30 @OBJC_CLASS_NAME_.1 = private global [2 x i8] c"A\00", section "__TEXT,__cstring,cstring_literals", align 1
31 @OBJC_CATEGORY_INSTANCE_METHODS_A_foo = private global { i8*, i32, [1 x %struct._objc_method] } { i8* null, i32 1, [1 x %struct._objc_method] [%struct._objc_method { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast (void (%0*, i8*)* @"\01-[A(foo) foo_myStuff]" to i8*) }] }, section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4
32 @OBJC_CATEGORY_A_foo = private global %struct._objc_category { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @OBJC_CLASS_NAME_.1, i32 0, i32 0), %struct._objc_method_list* bitcast ({ i8*, i32, [1 x %struct._objc_method] }* @OBJC_CATEGORY_INSTANCE_METHODS_A_foo to %struct._objc_method_list*), %struct._objc_method_list* null, %struct._objc_protocol_list* null, i32 32, %struct._prop_list_t* null, %struct._prop_list_t* null }, section "__OBJC,__category,regular,no_dead_strip", align 4
33 @OBJC_CLASS_NAME_.2 = private global [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1
34 @OBJC_SYMBOLS = private global { i32, i8*, i16, i16, [1 x i8*] } { i32 0, i8* null, i16 0, i16 1, [1 x i8*] [i8* bitcast (%struct._objc_category* @OBJC_CATEGORY_A_foo to i8*)] }, section "__OBJC,__symbols,regular,no_dead_strip", align 4
35 @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @OBJC_CLASS_NAME_.2, i32 0, i32 0), %struct._objc_symtab* bitcast ({ i32, i8*, i16, i16, [1 x i8*] }* @OBJC_SYMBOLS to %struct._objc_symtab*) }, section "__OBJC,__module_info,regular,no_dead_strip", align 4
36 @llvm.compiler.used = appending global [9 x i8*] [i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @OBJC_CLASS_NAME_.1, i32 0, i32 0), i8* bitcast ({ i8*, i32, [1 x %struct._objc_method] }* @OBJC_CATEGORY_INSTANCE_METHODS_A_foo to i8*), i8* bitcast (%struct._objc_category* @OBJC_CATEGORY_A_foo to i8*), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @OBJC_CLASS_NAME_.2, i32 0, i32 0), i8* bitcast ({ i32, i8*, i16, i16, [1 x i8*] }* @OBJC_SYMBOLS to i8*), i8* bitcast (%struct._objc_module* @OBJC_MODULES to i8*)], section "llvm.metadata"
37
38 ; Function Attrs: nounwind ssp
39 define internal void @"\01-[A(foo) foo_myStuff]"(%0*, i8*) #0 {
40 %3 = alloca %0*, align 4
41 %4 = alloca i8*, align 4
42 store %0* %0, %0** %3, align 4
43 store i8* %1, i8** %4, align 4
44 ret void
45 }
46
47 attributes #0 = { nounwind ssp "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
48
49 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
50 !llvm.ident = !{!6}
51
52 !0 = !{i32 1, !"Objective-C Version", i32 1}
53 !1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
54 !2 = !{i32 1, !"Objective-C Image Info Section", !"__OBJC, __image_info,regular"}
55 !3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
56 !4 = !{i32 1, !"Objective-C Class Properties", i32 64}
57 !5 = !{i32 1, !"PIC Level", i32 2}
58 !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.24.1)"}
0 ; RUN: llvm-as < %s -o %t
1 ; RUN: llvm-lto -check-for-objc %t | FileCheck %s
2
3 ; CHECK: contains ObjC
4
5 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
6 target triple = "x86_64-apple-macosx10.12.0"
7
8 %0 = type opaque
9 %struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* }
10 %struct._objc_cache = type opaque
11 %struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* }
12 %struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }
13 %struct._objc_method = type { i8*, i8*, i8* }
14 %struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] }
15 %struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8*, %struct._prop_list_t* }
16 %struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }
17 %struct._ivar_t = type { i64*, i8*, i8*, i32, i32 }
18 %struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
19 %struct._prop_t = type { i8*, i8* }
20 %struct._category_t = type { i8*, %struct._class_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._prop_list_t*, %struct._prop_list_t*, i32 }
21
22 @OBJC_CLASS_NAME_ = private global [4 x i8] c"foo\00", section "__TEXT,__objc_classname,cstring_literals", align 1
23 @"OBJC_CLASS_$_A" = external global %struct._class_t
24 @OBJC_METH_VAR_NAME_ = private global [12 x i8] c"foo_myStuff\00", section "__TEXT,__objc_methname,cstring_literals", align 1
25 @OBJC_METH_VAR_TYPE_ = private global [8 x i8] c"v16@0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
26 @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_foo" = private global { i32, i32, [1 x %struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] [%struct._objc_method { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast (void (%0*, i8*)* @"\01-[A(foo) foo_myStuff]" to i8*) }] }, section "__DATA, __objc_const", align 8
27 @"\01l_OBJC_$_CATEGORY_A_$_foo" = private global %struct._category_t { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), %struct._class_t* @"OBJC_CLASS_$_A", %struct.__method_list_t* bitcast ({ i32, i32, [1 x %struct._objc_method] }* @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_foo" to %struct.__method_list_t*), %struct.__method_list_t* null, %struct._objc_protocol_list* null, %struct._prop_list_t* null, %struct._prop_list_t* null, i32 64 }, section "__DATA, __objc_const", align 8
28 @"OBJC_LABEL_CATEGORY_$" = private global [1 x i8*] [i8* bitcast (%struct._category_t* @"\01l_OBJC_$_CATEGORY_A_$_foo" to i8*)], section "__DATA, __objc_catlist, regular, no_dead_strip", align 8
29 @llvm.compiler.used = appending global [6 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast ({ i32, i32, [1 x %struct._objc_method] }* @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_foo" to i8*), i8* bitcast (%struct._category_t* @"\01l_OBJC_$_CATEGORY_A_$_foo" to i8*), i8* bitcast ([1 x i8*]* @"OBJC_LABEL_CATEGORY_$" to i8*)], section "llvm.metadata"
30
31 ; Function Attrs: ssp uwtable
32 define internal void @"\01-[A(foo) foo_myStuff]"(%0*, i8*) #0 {
33 %3 = alloca %0*, align 8
34 %4 = alloca i8*, align 8
35 store %0* %0, %0** %3, align 8
36 store i8* %1, i8** %4, align 8
37 ret void
38 }
39
40 attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
41
42 !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
43 !llvm.ident = !{!6}
44
45 !0 = !{i32 1, !"Objective-C Version", i32 2}
46 !1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
47 !2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
48 !3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
49 !4 = !{i32 1, !"Objective-C Class Properties", i32 64}
50 !5 = !{i32 1, !"PIC Level", i32 2}
51 !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.24.1)"}
155155 "restore-linkage", cl::init(false),
156156 cl::desc("Restore original linkage of globals prior to CodeGen"));
157157
158 static cl::opt CheckHasObjC(
159 "check-for-objc", cl::init(false),
160 cl::desc("Only check if the module has objective-C defined in it"));
161
158162 namespace {
159163 struct ModuleInfo {
160164 std::vector CanBeHidden;
713717 return 0;
714718 }
715719
720 if (CheckHasObjC) {
721 for (auto &Filename : InputFilenames) {
722 ErrorOr> BufferOrErr =
723 MemoryBuffer::getFile(Filename);
724 error(BufferOrErr, "error loading file '" + Filename + "'");
725 auto Buffer = std::move(BufferOrErr.get());
726 LLVMContext Ctx;
727 if (llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx))
728 outs() << "Bitcode " << Filename << " contains ObjC\n";
729 else
730 outs() << "Bitcode " << Filename << " does not contain ObjC\n";
731 }
732 return 0;
733 }
734
716735 if (ThinLTOMode.getNumOccurrences()) {
717736 if (ThinLTOMode.getNumOccurrences() > 1)
718737 report_fatal_error("You can't specify more than one -thinlto-action");
1313
1414 #include "llvm-c/lto.h"
1515 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Bitcode/ReaderWriter.h"
1617 #include "llvm/CodeGen/CommandFlags.h"
1718 #include "llvm/IR/DiagnosticInfo.h"
1819 #include "llvm/IR/DiagnosticPrinter.h"
179180 return LTOModule::isBitcodeForTarget(Buffer->get(), target_triplet_prefix);
180181 }
181182
183 bool lto_module_has_objc_category(const void *mem, size_t length) {
184 std::unique_ptr Buffer(LTOModule::makeBuffer(mem, length));
185 if (!Buffer)
186 return false;
187 LLVMContext Ctx;
188 return llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx);
189 }
190
182191 bool lto_module_is_object_file_in_memory(const void* mem, size_t length) {
183192 return LTOModule::isBitcodeFile(mem, length);
184193 }
1717 lto_module_is_object_file_for_target
1818 lto_module_is_object_file_in_memory
1919 lto_module_is_object_file_in_memory_for_target
20 lto_module_has_objc_category
2021 lto_module_dispose
2122 lto_api_version
2223 lto_codegen_set_diagnostic_handler