llvm.org GIT mirror llvm / 6d5a027
Add LC_BUILD_VERSION load command Summary: Add a new load command LC_BUILD_VERSION. It is a generic version of LC_*_VERSION_MIN load_command used on Apple platforms. Instead of having a seperate load command for each platform, LC_BUILD_VERSION is recording platform info as an enum. It also records SDK version, min_os, and tools that used to build the binary. rdar://problem/29781291 Reviewers: enderby Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29044 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292824 91177308-0d34-0410-b5e6-96231b3b80d8 Steven Wu 2 years ago
14 changed file(s) with 407 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
352352 getVersionMinLoadCommand(const LoadCommandInfo &L) const;
353353 MachO::note_command
354354 getNoteLoadCommand(const LoadCommandInfo &L) const;
355 MachO::build_version_command
356 getBuildVersionLoadCommand(const LoadCommandInfo &L) const;
357 MachO::build_tool_version
358 getBuildToolVersion(unsigned index) const;
355359 MachO::dylib_command
356360 getDylibIDLoadCommand(const LoadCommandInfo &L) const;
357361 MachO::dyld_info_command
445449 return VersionOrSDK & 0xff;
446450 }
447451
452 static std::string getBuildPlatform(uint32_t platform) {
453 switch (platform) {
454 case MachO::PLATFORM_MACOS: return "macos";
455 case MachO::PLATFORM_IOS: return "ios";
456 case MachO::PLATFORM_TVOS: return "tvos";
457 case MachO::PLATFORM_WATCHOS: return "watchos";
458 case MachO::PLATFORM_BRIDGEOS: return "bridgeos";
459 default:
460 std::string ret;
461 llvm::raw_string_ostream ss(ret);
462 ss << format_hex(platform, 8, true);
463 return ss.str();
464 }
465 }
466
467 static std::string getBuildTool(uint32_t tools) {
468 switch (tools) {
469 case MachO::TOOL_CLANG: return "clang";
470 case MachO::TOOL_SWIFT: return "swift";
471 case MachO::TOOL_LD: return "ld";
472 default:
473 std::string ret;
474 llvm::raw_string_ostream ss(ret);
475 ss << format_hex(tools, 8, true);
476 return ss.str();
477 }
478 }
479
480 static std::string getVersionString(uint32_t version) {
481 uint32_t major = (version >> 16) & 0xffff;
482 uint32_t minor = (version >> 8) & 0xff;
483 uint32_t update = version & 0xff;
484
485 SmallString<32> Version;
486 Version = utostr(major) + "." + utostr(minor);
487 if (update != 0)
488 Version += "." + utostr(update);
489 return Version.str();
490 }
491
448492 private:
449493
450494 MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
463507 LibraryList Libraries;
464508 LoadCommandList LoadCommands;
465509 typedef SmallVector LibraryShortName;
510 using BuildToolList = SmallVector;
511 BuildToolList BuildTools;
466512 mutable LibraryShortName LibrariesShortNames;
467513 const char *SymtabLoadCmd;
468514 const char *DysymtabLoadCmd;
5252 virtual ~LoadCommand();
5353 llvm::MachO::macho_load_command Data;
5454 std::vector
Sections;
55 std::vector Tools;
5556 std::vector PayloadBytes;
5657 std::string PayloadString;
5758 uint64_t ZeroPadBytes;
145146 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry)
146147 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object)
147148 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch)
149 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachO::build_tool_version)
148150
149151 namespace llvm {
150152 namespace yaml {
195197
196198 template <> struct MappingTraits {
197199 static void mapping(IO &IO, MachOYAML::NListEntry &NListEntry);
200 };
201
202 template <> struct MappingTraits {
203 static void mapping(IO &IO, MachO::build_tool_version &tool);
198204 };
199205
200206 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
7373 HANDLE_LOAD_COMMAND(LC_VERSION_MIN_TVOS, 0x0000002Fu, version_min_command)
7474 HANDLE_LOAD_COMMAND(LC_VERSION_MIN_WATCHOS, 0x00000030u, version_min_command)
7575 HANDLE_LOAD_COMMAND(LC_NOTE, 0x00000031u, note_command)
76 HANDLE_LOAD_COMMAND(LC_BUILD_VERSION, 0x00000032u, build_version_command)
7677
7778 #endif
7879
110111 LOAD_COMMAND_STRUCT(uuid_command)
111112 LOAD_COMMAND_STRUCT(version_min_command)
112113 LOAD_COMMAND_STRUCT(note_command)
114 LOAD_COMMAND_STRUCT(build_version_command)
113115
114116 #endif
115117
486486 VM_PROT_EXECUTE = 0x4
487487 };
488488
489 // Values for platform field in build_version_command.
490 enum {
491 PLATFORM_MACOS = 1,
492 PLATFORM_IOS = 2,
493 PLATFORM_TVOS = 3,
494 PLATFORM_WATCHOS = 4,
495 PLATFORM_BRIDGEOS = 5
496 };
497
498 // Values for tools enum in build_tool_version.
499 enum {
500 TOOL_CLANG = 1,
501 TOOL_SWIFT = 2,
502 TOOL_LD = 3
503 };
504
489505 // Structs from
490506
491507 struct mach_header {
824840 char data_owner[16]; // owner name for this LC_NOTE
825841 uint64_t offset; // file offset of this data
826842 uint64_t size; // length of data region
843 };
844
845 struct build_tool_version {
846 uint32_t tool; // enum for the tool
847 uint32_t version; // version of the tool
848 };
849
850 struct build_version_command {
851 uint32_t cmd; // LC_BUILD_VERSION
852 uint32_t cmdsize; // sizeof(struct build_version_command) +
853 // ntools * sizeof(struct build_tool_version)
854 uint32_t platform; // platform
855 uint32_t minos; // X.Y.Z is encoded in nibbles xxxx.yy.zz
856 uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
857 uint32_t ntools; // number of tool entries following this
827858 };
828859
829860 struct dyld_info_command {
12781309 sys::swapByteOrder(C.cmdsize);
12791310 sys::swapByteOrder(C.offset);
12801311 sys::swapByteOrder(C.size);
1312 }
1313
1314 inline void swapStruct(build_version_command&C) {
1315 sys::swapByteOrder(C.cmd);
1316 sys::swapByteOrder(C.cmdsize);
1317 sys::swapByteOrder(C.platform);
1318 sys::swapByteOrder(C.minos);
1319 sys::swapByteOrder(C.sdk);
1320 sys::swapByteOrder(C.ntools);
1321 }
1322
1323 inline void swapStruct(build_tool_version&C) {
1324 sys::swapByteOrder(C.tool);
1325 sys::swapByteOrder(C.version);
12811326 }
12821327
12831328 inline void swapStruct(data_in_code_entry &C) {
808808 return Error::success();
809809 }
810810
811 static Error
812 parseBuildVersionCommand(const MachOObjectFile &Obj,
813 const MachOObjectFile::LoadCommandInfo &Load,
814 SmallVectorImpl &BuildTools,
815 uint32_t LoadCommandIndex) {
816 MachO::build_version_command BVC =
817 getStruct(Obj, Load.Ptr);
818 if (Load.C.cmdsize !=
819 sizeof(MachO::build_version_command) +
820 BVC.ntools * sizeof(MachO::build_tool_version))
821 return malformedError("load command " + Twine(LoadCommandIndex) +
822 " LC_BUILD_VERSION_COMMAND has incorrect cmdsize");
823
824 auto Start = Load.Ptr + sizeof(MachO::build_version_command);
825 BuildTools.resize(BVC.ntools);
826 for (unsigned i = 0; i < BVC.ntools; ++i)
827 BuildTools[i] = Start + i * sizeof(MachO::build_tool_version);
828
829 return Error::success();
830 }
831
811832 static Error checkRpathCommand(const MachOObjectFile &Obj,
812833 const MachOObjectFile::LoadCommandInfo &Load,
813834 uint32_t LoadCommandIndex) {
13061327 return;
13071328 } else if (Load.C.cmd == MachO::LC_NOTE) {
13081329 if ((Err = checkNoteCommand(*this, Load, I, Elements)))
1330 return;
1331 } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
1332 if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I)))
13091333 return;
13101334 } else if (Load.C.cmd == MachO::LC_RPATH) {
13111335 if ((Err = checkRpathCommand(*this, Load, I)))
33213345 return getStruct(*this, L.Ptr);
33223346 }
33233347
3348 MachO::build_version_command
3349 MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const {
3350 return getStruct(*this, L.Ptr);
3351 }
3352
3353 MachO::build_tool_version
3354 MachOObjectFile::getBuildToolVersion(unsigned index) const {
3355 return getStruct(*this, BuildTools[index]);
3356 }
3357
33243358 MachO::dylib_command
33253359 MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {
33263360 return getStruct(*this, L.Ptr);
229229 IO.mapOptional("PayloadString", LoadCommand.PayloadString);
230230 }
231231
232 template <>
233 void mapLoadCommandData(
234 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
235 IO.mapOptional("Tools", LoadCommand.Tools);
236 }
237
232238 void MappingTraits::mapping(
233239 IO &IO, MachOYAML::LoadCommand &LoadCommand) {
234240 MachO::LoadCommandType TempCmd = static_cast(
279285 IO.mapRequired("reserved1", Section.reserved1);
280286 IO.mapRequired("reserved2", Section.reserved2);
281287 IO.mapOptional("reserved3", Section.reserved3);
288 }
289
290 void MappingTraits::mapping(
291 IO &IO, MachO::build_tool_version &tool) {
292 IO.mapRequired("tool", tool.tool);
293 IO.mapRequired("version", tool.version);
282294 }
283295
284296 void MappingTraits::mapping(IO &IO, MachO::dylib &DylibStruct) {
565577 IO.mapRequired("size", LoadCommand.size);
566578 }
567579
580 void MappingTraits::mapping(
581 IO &IO, MachO::build_version_command &LoadCommand) {
582
583 IO.mapRequired("platform", LoadCommand.platform);
584 IO.mapRequired("minos", LoadCommand.minos);
585 IO.mapRequired("sdk", LoadCommand.sdk);
586 IO.mapRequired("ntools", LoadCommand.ntools);
587 }
588
568589 } // namespace llvm::yaml
569590
570591 } // namespace llvm
2525 // CHECK-TVOS: cmd LC_VERSION_MIN_TVOS
2626 // CHECK-TVOS-NEXT: cmdsize 16
2727 // CHECK-TVOS-NEXT: version 8.0
28
29 // CHECK-BRIDGEOS: cmd LC_BUILD_VERSION
30 // CHECK-BRIDGEOS-NEXT: cmdsize 24
31 // CHECK-BRIDGEOS-NEXT: platform bridgeos
32 // CHECK-BRIDGEOS-NEXT: sdk n/a
33 // CHECK-BRIDGEOS-NEXT: minos 2.0
34 // CHECK-BRIDGEOS-NEXT: ntools 0
0 # RUN: yaml2obj %s | obj2yaml | FileCheck %s
1
2 --- !mach-o
3 FileHeader:
4 magic: 0xFEEDFACE
5 cputype: 0x00000007
6 cpusubtype: 0x00000003
7 filetype: 0x00000004
8 ncmds: 2
9 sizeofcmds: 192
10 flags: 0x00000000
11 LoadCommands:
12 - cmd: LC_SEGMENT_64
13 cmdsize: 152
14 segname: __TEXT
15 vmaddr: 4294967296
16 vmsize: 8192
17 fileoff: 0
18 filesize: 3099
19 maxprot: 7
20 initprot: 5
21 nsects: 1
22 flags: 0
23 Sections:
24 - sectname: __text
25 segname: __TEXT
26 addr: 0x0000000100001160
27 size: 3099
28 offset: 0x00001160
29 align: 4
30 reloff: 0x00000000
31 nreloc: 0
32 flags: 0x80000400
33 reserved1: 0x00000000
34 reserved2: 0x00000000
35 reserved3: 0x00000000
36 - cmd: LC_BUILD_VERSION
37 cmdsize: 32
38 platform: 2
39 minos: 0x00080000
40 sdk: 0x00090000
41 ntools: 1
42 Tools:
43 - tool: 1
44 version: 0x00000000
45 ...
46
47
48 CHECK: LoadCommands:
49 CHECK: - cmd: LC_BUILD_VERSION
50 CHECK-NEXT: cmdsize: 32
51 CHECK-NEXT: platform: 2
52 CHECK-NEXT: minos: 524288
53 CHECK-NEXT: sdk: 589824
54 CHECK-NEXT: ntools: 1
55 CHECK-NEXT: Tools:
56 CHECK-NEXT: - tool: 1
57 CHECK-NEXT: version: 0
0 # RUN: yaml2obj %s | not llvm-objdump -macho -private-headers -
1
2 --- !mach-o
3 FileHeader:
4 magic: 0xFEEDFACF
5 cputype: 0x01000007
6 cpusubtype: 0x00000003
7 filetype: 0x00000004
8 ncmds: 2
9 sizeofcmds: 192
10 flags: 0x00000000
11 reserved: 0
12 LoadCommands:
13 - cmd: LC_SEGMENT_64
14 cmdsize: 152
15 segname: __TEXT
16 vmaddr: 4294967296
17 vmsize: 8192
18 fileoff: 0
19 filesize: 3099
20 maxprot: 7
21 initprot: 5
22 nsects: 1
23 flags: 0
24 Sections:
25 - sectname: __text
26 segname: __TEXT
27 addr: 0x0000000100001160
28 size: 3099
29 offset: 0x00001160
30 align: 4
31 reloff: 0x00000000
32 nreloc: 0
33 flags: 0x80000400
34 reserved1: 0x00000000
35 reserved2: 0x00000000
36 reserved3: 0x00000000
37 - cmd: LC_BUILD_VERSION
38 cmdsize: 80
39 platform: 2
40 minos: 0x00080000
41 sdk: 0x00090000
42 ntools: 0
43 ...
0 # RUN: yaml2obj %s | llvm-objdump -macho -private-headers - | FileCheck %s
1
2 --- !mach-o
3 FileHeader:
4 magic: 0xFEEDFACF
5 cputype: 0x01000007
6 cpusubtype: 0x00000003
7 filetype: 0x00000004
8 ncmds: 2
9 sizeofcmds: 192
10 flags: 0x00000000
11 reserved: 0
12 LoadCommands:
13 - cmd: LC_SEGMENT_64
14 cmdsize: 152
15 segname: __TEXT
16 vmaddr: 4294967296
17 vmsize: 8192
18 fileoff: 0
19 filesize: 3099
20 maxprot: 7
21 initprot: 5
22 nsects: 1
23 flags: 0
24 Sections:
25 - sectname: __text
26 segname: __TEXT
27 addr: 0x0000000100001160
28 size: 3099
29 offset: 0x00001160
30 align: 4
31 reloff: 0x00000000
32 nreloc: 0
33 flags: 0x80000400
34 reserved1: 0x00000000
35 reserved2: 0x00000000
36 reserved3: 0x00000000
37 - cmd: LC_BUILD_VERSION
38 cmdsize: 32
39 platform: 2
40 minos: 0x00080000
41 sdk: 0x00090000
42 ntools: 1
43 Tools:
44 - tool: 1
45 version: 0x00000000
46 ...
47
48 CHECK: Load command 1
49 CHECK-NEXT: cmd LC_BUILD_VERSION
50 CHECK-NEXT: cmdsize 32
51 CHECK-NEXT: platform ios
52 CHECK-NEXT: sdk 9.0
53 CHECK-NEXT: minos 8.0
54 CHECK-NEXT: ntools 1
55 CHECK-NEXT: tool clang
56 CHECK-NEXT: version n/a
81798179 outs() << "data_owner " << format("%.16s\n", d);
81808180 outs() << " offset " << Nt.offset << "\n";
81818181 outs() << " size " << Nt.size << "\n";
8182 }
8183
8184 static void PrintBuildToolVersion(MachO::build_tool_version bv) {
8185 outs() << " tool " << MachOObjectFile::getBuildTool(bv.tool) << "\n";
8186 outs() << " version " << MachOObjectFile::getVersionString(bv.version)
8187 << "\n";
8188 }
8189
8190 static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
8191 MachO::build_version_command bd) {
8192 outs() << " cmd LC_BUILD_VERSION\n";
8193 outs() << " cmdsize " << bd.cmdsize;
8194 if (bd.cmdsize !=
8195 sizeof(struct MachO::build_version_command) +
8196 bd.ntools * sizeof(struct MachO::build_tool_version))
8197 outs() << " Incorrect size\n";
8198 else
8199 outs() << "\n";
8200 outs() << " platform " << MachOObjectFile::getBuildPlatform(bd.platform)
8201 << "\n";
8202 if (bd.sdk)
8203 outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)
8204 << "\n";
8205 else
8206 outs() << " sdk n/a\n";
8207 outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)
8208 << "\n";
8209 outs() << " ntools " << bd.ntools << "\n";
8210 for (unsigned i = 0; i < bd.ntools; ++i) {
8211 MachO::build_tool_version bv = obj->getBuildToolVersion(i);
8212 PrintBuildToolVersion(bv);
8213 }
81828214 }
81838215
81848216 static void PrintSourceVersionCommand(MachO::source_version_command sd) {
90299061 } else if (Command.C.cmd == MachO::LC_NOTE) {
90309062 MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
90319063 PrintNoteLoadCommand(Nt);
9064 } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
9065 MachO::build_version_command Bv =
9066 Obj->getBuildVersionLoadCommand(Command);
9067 PrintBuildVersionLoadCommand(Obj, Bv);
90329068 } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
90339069 MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
90349070 PrintSourceVersionCommand(Sd);
712712 case MachO::LC_VERSION_MIN_WATCHOS:
713713 Cmd = "LC_VERSION_MIN_WATCHOS";
714714 break;
715 case MachO::LC_BUILD_VERSION:
716 Cmd = "LC_BUILD_VERSION";
717 break;
715718 default:
716719 continue;
717720 }
718721
722 DictScope Group(W, "MinVersion");
723 // Handle LC_BUILD_VERSION.
724 if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
725 MachO::build_version_command BVC = Obj->getBuildVersionLoadCommand(Load);
726 W.printString("Cmd", Cmd);
727 W.printNumber("Size", BVC.cmdsize);
728 W.printString("Platform",
729 MachOObjectFile::getBuildPlatform(BVC.platform));
730 W.printString("Version", MachOObjectFile::getVersionString(BVC.minos));
731 if (BVC.sdk)
732 W.printString("SDK", MachOObjectFile::getVersionString(BVC.sdk));
733 else
734 W.printString("SDK", StringRef("n/a"));
735 continue;
736 }
737
719738 MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load);
720 DictScope Group(W, "MinVersion");
721739 W.printString("Cmd", Cmd);
722740 W.printNumber("Size", VMC.cmdsize);
723741 SmallString<32> Version;
160160 MachOYAML::LoadCommand &LC,
161161 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
162162 return readString(LC, LoadCmd);
163 }
164
165 template <>
166 const char *MachODumper::processLoadCommandData(
167 MachOYAML::LoadCommand &LC,
168 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
169 auto Start = LoadCmd.Ptr + sizeof(MachO::build_version_command);
170 auto NTools = LC.Data.build_version_command_data.ntools;
171 for (unsigned i = 0; i < NTools; ++i) {
172 auto Curr = Start + i * sizeof(MachO::build_tool_version);
173 MachO::build_tool_version BV;
174 memcpy((void *)&BV, Curr, sizeof(MachO::build_tool_version));
175 if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
176 MachO::swapStruct(BV);
177 LC.Tools.push_back(BV);
178 }
179 return Start + NTools * sizeof(MachO::build_tool_version);
163180 }
164181
165182 Expected> MachODumper::dump() {
177177 raw_ostream &OS,
178178 bool IsLittleEndian) {
179179 return writePayloadString(LC, OS);
180 }
181
182 template <>
183 size_t writeLoadCommandData(
184 MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
185 size_t BytesWritten = 0;
186 for (const auto &T : LC.Tools) {
187 struct MachO::build_tool_version tool = T;
188 if (IsLittleEndian != sys::IsLittleEndianHost)
189 MachO::swapStruct(tool);
190 OS.write(reinterpret_cast(&tool),
191 sizeof(MachO::build_tool_version));
192 BytesWritten += sizeof(MachO::build_tool_version);
193 }
194 return BytesWritten;
180195 }
181196
182197 void ZeroFillBytes(raw_ostream &OS, size_t Size) {