Skip to content

Commit

Permalink
Add LC_BUILD_VERSION load command
Browse files Browse the repository at this point in the history
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

llvm-svn: 292824
  • Loading branch information
cachemeifyoucan committed Jan 23, 2017
1 parent cddeb75 commit 5b54a42
Show file tree
Hide file tree
Showing 14 changed files with 407 additions and 1 deletion.
46 changes: 46 additions & 0 deletions llvm/include/llvm/Object/MachO.h
Expand Up @@ -353,6 +353,10 @@ class MachOObjectFile : public ObjectFile {
getVersionMinLoadCommand(const LoadCommandInfo &L) const;
MachO::note_command
getNoteLoadCommand(const LoadCommandInfo &L) const;
MachO::build_version_command
getBuildVersionLoadCommand(const LoadCommandInfo &L) const;
MachO::build_tool_version
getBuildToolVersion(unsigned index) const;
MachO::dylib_command
getDylibIDLoadCommand(const LoadCommandInfo &L) const;
MachO::dyld_info_command
Expand Down Expand Up @@ -446,6 +450,46 @@ class MachOObjectFile : public ObjectFile {
return VersionOrSDK & 0xff;
}

static std::string getBuildPlatform(uint32_t platform) {
switch (platform) {
case MachO::PLATFORM_MACOS: return "macos";
case MachO::PLATFORM_IOS: return "ios";
case MachO::PLATFORM_TVOS: return "tvos";
case MachO::PLATFORM_WATCHOS: return "watchos";
case MachO::PLATFORM_BRIDGEOS: return "bridgeos";
default:
std::string ret;
llvm::raw_string_ostream ss(ret);
ss << format_hex(platform, 8, true);
return ss.str();
}
}

static std::string getBuildTool(uint32_t tools) {
switch (tools) {
case MachO::TOOL_CLANG: return "clang";
case MachO::TOOL_SWIFT: return "swift";
case MachO::TOOL_LD: return "ld";
default:
std::string ret;
llvm::raw_string_ostream ss(ret);
ss << format_hex(tools, 8, true);
return ss.str();
}
}

static std::string getVersionString(uint32_t version) {
uint32_t major = (version >> 16) & 0xffff;
uint32_t minor = (version >> 8) & 0xff;
uint32_t update = version & 0xff;

SmallString<32> Version;
Version = utostr(major) + "." + utostr(minor);
if (update != 0)
Version += "." + utostr(update);
return Version.str();
}

private:

MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
Expand All @@ -464,6 +508,8 @@ class MachOObjectFile : public ObjectFile {
LibraryList Libraries;
LoadCommandList LoadCommands;
typedef SmallVector<StringRef, 1> LibraryShortName;
using BuildToolList = SmallVector<const char*, 1>;
BuildToolList BuildTools;
mutable LibraryShortName LibrariesShortNames;
const char *SymtabLoadCmd;
const char *DysymtabLoadCmd;
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/ObjectYAML/MachOYAML.h
Expand Up @@ -53,6 +53,7 @@ struct LoadCommand {
virtual ~LoadCommand();
llvm::MachO::macho_load_command Data;
std::vector<Section> Sections;
std::vector<MachO::build_tool_version> Tools;
std::vector<llvm::yaml::Hex8> PayloadBytes;
std::string PayloadString;
uint64_t ZeroPadBytes;
Expand Down Expand Up @@ -146,6 +147,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::ExportEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachO::build_tool_version)

namespace llvm {
namespace yaml {
Expand Down Expand Up @@ -198,6 +200,10 @@ template <> struct MappingTraits<MachOYAML::NListEntry> {
static void mapping(IO &IO, MachOYAML::NListEntry &NListEntry);
};

template <> struct MappingTraits<MachO::build_tool_version> {
static void mapping(IO &IO, MachO::build_tool_version &tool);
};

#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
io.enumCase(value, #LCName, MachO::LCName);

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Support/MachO.def
Expand Up @@ -74,6 +74,7 @@ HANDLE_LOAD_COMMAND(LC_LINKER_OPTIMIZATION_HINT, 0x0000002Eu, linkedit_data_comm
HANDLE_LOAD_COMMAND(LC_VERSION_MIN_TVOS, 0x0000002Fu, version_min_command)
HANDLE_LOAD_COMMAND(LC_VERSION_MIN_WATCHOS, 0x00000030u, version_min_command)
HANDLE_LOAD_COMMAND(LC_NOTE, 0x00000031u, note_command)
HANDLE_LOAD_COMMAND(LC_BUILD_VERSION, 0x00000032u, build_version_command)

#endif

Expand Down Expand Up @@ -111,6 +112,7 @@ LOAD_COMMAND_STRUCT(twolevel_hints_command)
LOAD_COMMAND_STRUCT(uuid_command)
LOAD_COMMAND_STRUCT(version_min_command)
LOAD_COMMAND_STRUCT(note_command)
LOAD_COMMAND_STRUCT(build_version_command)

#endif

Expand Down
45 changes: 45 additions & 0 deletions llvm/include/llvm/Support/MachO.h
Expand Up @@ -487,6 +487,22 @@ namespace llvm {
VM_PROT_EXECUTE = 0x4
};

// Values for platform field in build_version_command.
enum {
PLATFORM_MACOS = 1,
PLATFORM_IOS = 2,
PLATFORM_TVOS = 3,
PLATFORM_WATCHOS = 4,
PLATFORM_BRIDGEOS = 5
};

// Values for tools enum in build_tool_version.
enum {
TOOL_CLANG = 1,
TOOL_SWIFT = 2,
TOOL_LD = 3
};

// Structs from <mach-o/loader.h>

struct mach_header {
Expand Down Expand Up @@ -827,6 +843,21 @@ namespace llvm {
uint64_t size; // length of data region
};

struct build_tool_version {
uint32_t tool; // enum for the tool
uint32_t version; // version of the tool
};

struct build_version_command {
uint32_t cmd; // LC_BUILD_VERSION
uint32_t cmdsize; // sizeof(struct build_version_command) +
// ntools * sizeof(struct build_tool_version)
uint32_t platform; // platform
uint32_t minos; // X.Y.Z is encoded in nibbles xxxx.yy.zz
uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
uint32_t ntools; // number of tool entries following this
};

struct dyld_info_command {
uint32_t cmd;
uint32_t cmdsize;
Expand Down Expand Up @@ -1281,6 +1312,20 @@ namespace llvm {
sys::swapByteOrder(C.size);
}

inline void swapStruct(build_version_command&C) {
sys::swapByteOrder(C.cmd);
sys::swapByteOrder(C.cmdsize);
sys::swapByteOrder(C.platform);
sys::swapByteOrder(C.minos);
sys::swapByteOrder(C.sdk);
sys::swapByteOrder(C.ntools);
}

inline void swapStruct(build_tool_version&C) {
sys::swapByteOrder(C.tool);
sys::swapByteOrder(C.version);
}

inline void swapStruct(data_in_code_entry &C) {
sys::swapByteOrder(C.offset);
sys::swapByteOrder(C.length);
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Object/MachOObjectFile.cpp
Expand Up @@ -809,6 +809,27 @@ static Error checkNoteCommand(const MachOObjectFile &Obj,
return Error::success();
}

static Error
parseBuildVersionCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &Load,
SmallVectorImpl<const char*> &BuildTools,
uint32_t LoadCommandIndex) {
MachO::build_version_command BVC =
getStruct<MachO::build_version_command>(Obj, Load.Ptr);
if (Load.C.cmdsize !=
sizeof(MachO::build_version_command) +
BVC.ntools * sizeof(MachO::build_tool_version))
return malformedError("load command " + Twine(LoadCommandIndex) +
" LC_BUILD_VERSION_COMMAND has incorrect cmdsize");

auto Start = Load.Ptr + sizeof(MachO::build_version_command);
BuildTools.resize(BVC.ntools);
for (unsigned i = 0; i < BVC.ntools; ++i)
BuildTools[i] = Start + i * sizeof(MachO::build_tool_version);

return Error::success();
}

static Error checkRpathCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &Load,
uint32_t LoadCommandIndex) {
Expand Down Expand Up @@ -1308,6 +1329,9 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
} else if (Load.C.cmd == MachO::LC_NOTE) {
if ((Err = checkNoteCommand(*this, Load, I, Elements)))
return;
} else if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I)))
return;
} else if (Load.C.cmd == MachO::LC_RPATH) {
if ((Err = checkRpathCommand(*this, Load, I)))
return;
Expand Down Expand Up @@ -3322,6 +3346,16 @@ MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const {
return getStruct<MachO::note_command>(*this, L.Ptr);
}

MachO::build_version_command
MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const {
return getStruct<MachO::build_version_command>(*this, L.Ptr);
}

MachO::build_tool_version
MachOObjectFile::getBuildToolVersion(unsigned index) const {
return getStruct<MachO::build_tool_version>(*this, BuildTools[index]);
}

MachO::dylib_command
MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {
return getStruct<MachO::dylib_command>(*this, L.Ptr);
Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/ObjectYAML/MachOYAML.cpp
Expand Up @@ -230,6 +230,12 @@ void mapLoadCommandData<MachO::dylinker_command>(
IO.mapOptional("PayloadString", LoadCommand.PayloadString);
}

template <>
void mapLoadCommandData<MachO::build_version_command>(
IO &IO, MachOYAML::LoadCommand &LoadCommand) {
IO.mapOptional("Tools", LoadCommand.Tools);
}

void MappingTraits<MachOYAML::LoadCommand>::mapping(
IO &IO, MachOYAML::LoadCommand &LoadCommand) {
MachO::LoadCommandType TempCmd = static_cast<MachO::LoadCommandType>(
Expand Down Expand Up @@ -282,6 +288,12 @@ void MappingTraits<MachOYAML::Section>::mapping(IO &IO,
IO.mapOptional("reserved3", Section.reserved3);
}

void MappingTraits<MachO::build_tool_version>::mapping(
IO &IO, MachO::build_tool_version &tool) {
IO.mapRequired("tool", tool.tool);
IO.mapRequired("version", tool.version);
}

void MappingTraits<MachO::dylib>::mapping(IO &IO, MachO::dylib &DylibStruct) {
IO.mapRequired("name", DylibStruct.name);
IO.mapRequired("timestamp", DylibStruct.timestamp);
Expand Down Expand Up @@ -566,6 +578,15 @@ void MappingTraits<MachO::note_command>::mapping(
IO.mapRequired("size", LoadCommand.size);
}

void MappingTraits<MachO::build_version_command>::mapping(
IO &IO, MachO::build_version_command &LoadCommand) {

IO.mapRequired("platform", LoadCommand.platform);
IO.mapRequired("minos", LoadCommand.minos);
IO.mapRequired("sdk", LoadCommand.sdk);
IO.mapRequired("ntools", LoadCommand.ntools);
}

} // namespace llvm::yaml

} // namespace llvm
7 changes: 7 additions & 0 deletions llvm/test/MC/MachO/darwin-version-min-load-command.s
Expand Up @@ -26,3 +26,10 @@
// CHECK-TVOS: cmd LC_VERSION_MIN_TVOS
// CHECK-TVOS-NEXT: cmdsize 16
// CHECK-TVOS-NEXT: version 8.0

// CHECK-BRIDGEOS: cmd LC_BUILD_VERSION
// CHECK-BRIDGEOS-NEXT: cmdsize 24
// CHECK-BRIDGEOS-NEXT: platform bridgeos
// CHECK-BRIDGEOS-NEXT: sdk n/a
// CHECK-BRIDGEOS-NEXT: minos 2.0
// CHECK-BRIDGEOS-NEXT: ntools 0
58 changes: 58 additions & 0 deletions llvm/test/ObjectYAML/MachO/build_version_command.yaml
@@ -0,0 +1,58 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s

--- !mach-o
FileHeader:
magic: 0xFEEDFACE
cputype: 0x00000007
cpusubtype: 0x00000003
filetype: 0x00000004
ncmds: 2
sizeofcmds: 192
flags: 0x00000000
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 152
segname: __TEXT
vmaddr: 4294967296
vmsize: 8192
fileoff: 0
filesize: 3099
maxprot: 7
initprot: 5
nsects: 1
flags: 0
Sections:
- sectname: __text
segname: __TEXT
addr: 0x0000000100001160
size: 3099
offset: 0x00001160
align: 4
reloff: 0x00000000
nreloc: 0
flags: 0x80000400
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
- cmd: LC_BUILD_VERSION
cmdsize: 32
platform: 2
minos: 0x00080000
sdk: 0x00090000
ntools: 1
Tools:
- tool: 1
version: 0x00000000
...


CHECK: LoadCommands:
CHECK: - cmd: LC_BUILD_VERSION
CHECK-NEXT: cmdsize: 32
CHECK-NEXT: platform: 2
CHECK-NEXT: minos: 524288
CHECK-NEXT: sdk: 589824
CHECK-NEXT: ntools: 1
CHECK-NEXT: Tools:
CHECK-NEXT: - tool: 1
CHECK-NEXT: version: 0
44 changes: 44 additions & 0 deletions llvm/test/tools/llvm-objdump/X86/invalid-macho-build-version.yaml
@@ -0,0 +1,44 @@
# RUN: yaml2obj %s | not llvm-objdump -macho -private-headers -

--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x01000007
cpusubtype: 0x00000003
filetype: 0x00000004
ncmds: 2
sizeofcmds: 192
flags: 0x00000000
reserved: 0
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 152
segname: __TEXT
vmaddr: 4294967296
vmsize: 8192
fileoff: 0
filesize: 3099
maxprot: 7
initprot: 5
nsects: 1
flags: 0
Sections:
- sectname: __text
segname: __TEXT
addr: 0x0000000100001160
size: 3099
offset: 0x00001160
align: 4
reloff: 0x00000000
nreloc: 0
flags: 0x80000400
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
- cmd: LC_BUILD_VERSION
cmdsize: 80
platform: 2
minos: 0x00080000
sdk: 0x00090000
ntools: 0
...

0 comments on commit 5b54a42

Please sign in to comment.