Commit 282bf213 authored by Antonio Frighetto's avatar Antonio Frighetto
Browse files

[llvm-nm][MachO] Add support for `MH_FILESET`

Support printing of symbols for MachO of `MH_FILESET` type.
This is achieved by extending `dumpSymbolNamesFromObject`
to encompass fileset handling, and including an offset in
`MachOObjectFile` class to locate embedded MachO headers.

Differential Revision: https://reviews.llvm.org/D159294
parent d227c8a1
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -898,12 +898,17 @@ struct linker_option_command {
  uint32_t count;
};

union lc_str {
  uint32_t offset;
};

struct fileset_entry_command {
  uint32_t cmd;
  uint32_t cmdsize;
  uint64_t vmaddr;
  uint64_t fileoff;
  uint32_t entry_id;
  union lc_str entry_id;
  uint32_t reserved;
};

// The symseg_command is obsolete and no longer supported.
@@ -1434,7 +1439,8 @@ inline void swapStruct(fileset_entry_command &C) {
  sys::swapByteOrder(C.cmdsize);
  sys::swapByteOrder(C.vmaddr);
  sys::swapByteOrder(C.fileoff);
  sys::swapByteOrder(C.entry_id);
  sys::swapByteOrder(C.entry_id.offset);
  sys::swapByteOrder(C.reserved);
}

inline void swapStruct(version_min_command &C) {
+9 −2
Original line number Diff line number Diff line
@@ -414,7 +414,8 @@ public:

  static Expected<std::unique_ptr<MachOObjectFile>>
  create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
         uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0);
         uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0,
         size_t MachOFilesetEntryOffset = 0);

  static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch);

@@ -697,6 +698,8 @@ public:
  getRoutinesCommand64(const LoadCommandInfo &L) const;
  MachO::thread_command
  getThreadCommand(const LoadCommandInfo &L) const;
  MachO::fileset_entry_command
  getFilesetEntryLoadCommand(const LoadCommandInfo &L) const;

  MachO::any_relocation_info getRelocation(DataRefImpl Rel) const;
  MachO::data_in_code_entry getDice(DataRefImpl Rel) const;
@@ -760,6 +763,8 @@ public:

  bool hasPageZeroSegment() const { return HasPageZeroSegment; }

  size_t getMachOFilesetEntryOffset() const { return MachOFilesetEntryOffset; }

  static bool classof(const Binary *v) {
    return v->isMachO();
  }
@@ -839,7 +844,8 @@ public:
private:
  MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
                  Error &Err, uint32_t UniversalCputype = 0,
                  uint32_t UniversalIndex = 0);
                  uint32_t UniversalIndex = 0,
                  size_t MachOFilesetEntryOffset = 0);

  uint64_t getSymbolValueImpl(DataRefImpl Symb) const override;

@@ -867,6 +873,7 @@ private:
  const char *DyldExportsTrieLoadCmd = nullptr;
  const char *UuidLoadCmd = nullptr;
  bool HasPageZeroSegment = false;
  size_t MachOFilesetEntryOffset = 0;
};

/// DiceRef
+3 −3
Original line number Diff line number Diff line
@@ -389,9 +389,9 @@ public:
  createELFObjectFile(MemoryBufferRef Object, bool InitContent = true);

  static Expected<std::unique_ptr<MachOObjectFile>>
  createMachOObjectFile(MemoryBufferRef Object,
                        uint32_t UniversalCputype = 0,
                        uint32_t UniversalIndex = 0);
  createMachOObjectFile(MemoryBufferRef Object, uint32_t UniversalCputype = 0,
                        uint32_t UniversalIndex = 0,
                        size_t MachOFilesetEntryOffset = 0);

  static Expected<std::unique_ptr<ObjectFile>>
  createGOFFObjectFile(MemoryBufferRef Object);
+43 −25
Original line number Diff line number Diff line
@@ -108,9 +108,11 @@ getSectionPtr(const MachOObjectFile &O, MachOObjectFile::LoadCommandInfo L,
  return reinterpret_cast<const char*>(SectionAddr);
}

static const char *getPtr(const MachOObjectFile &O, size_t Offset) {
  assert(Offset <= O.getData().size());
  return O.getData().data() + Offset;
static const char *getPtr(const MachOObjectFile &O, size_t Offset,
                          size_t MachOFilesetEntryOffset = 0) {
  assert(Offset <= O.getData().size() &&
         MachOFilesetEntryOffset <= O.getData().size());
  return O.getData().data() + Offset + MachOFilesetEntryOffset;
}

static MachO::nlist_base
@@ -208,7 +210,8 @@ getFirstLoadCommandInfo(const MachOObjectFile &Obj) {
  if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds)
    return malformedError("load command 0 extends past the end all load "
                          "commands in the file");
  return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize), 0);
  return getLoadCommandInfo(
      Obj, getPtr(Obj, HeaderSize, Obj.getMachOFilesetEntryOffset()), 0);
}

static Expected<MachOObjectFile::LoadCommandInfo>
@@ -217,7 +220,8 @@ getNextLoadCommandInfo(const MachOObjectFile &Obj, uint32_t LoadCommandIndex,
  unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
                                      : sizeof(MachO::mach_header);
  if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) >
      Obj.getData().data() + HeaderSize + Obj.getHeader().sizeofcmds)
      Obj.getData().data() + Obj.getMachOFilesetEntryOffset() + HeaderSize +
          Obj.getHeader().sizeofcmds)
    return malformedError("load command " + Twine(LoadCommandIndex + 1) +
                          " extends past the end all load commands in the file");
  return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1);
@@ -231,7 +235,8 @@ static void parseHeader(const MachOObjectFile &Obj, T &Header,
                         "file");
    return;
  }
  if (auto HeaderOrErr = getStructOrErr<T>(Obj, getPtr(Obj, 0)))
  if (auto HeaderOrErr = getStructOrErr<T>(
          Obj, getPtr(Obj, 0, Obj.getMachOFilesetEntryOffset())))
    Header = *HeaderOrErr;
  else
    Err = HeaderOrErr.takeError();
@@ -1247,12 +1252,12 @@ static bool isLoadCommandObsolete(uint32_t cmd) {
Expected<std::unique_ptr<MachOObjectFile>>
MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
                        bool Is64Bits, uint32_t UniversalCputype,
                        uint32_t UniversalIndex) {
                        uint32_t UniversalIndex,
                        size_t MachOFilesetEntryOffset) {
  Error Err = Error::success();
  std::unique_ptr<MachOObjectFile> Obj(
      new MachOObjectFile(std::move(Object), IsLittleEndian,
                          Is64Bits, Err, UniversalCputype,
                          UniversalIndex));
  std::unique_ptr<MachOObjectFile> Obj(new MachOObjectFile(
      std::move(Object), IsLittleEndian, Is64Bits, Err, UniversalCputype,
      UniversalIndex, MachOFilesetEntryOffset));
  if (Err)
    return std::move(Err);
  return std::move(Obj);
@@ -1261,8 +1266,10 @@ MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
                                 bool Is64bits, Error &Err,
                                 uint32_t UniversalCputype,
                                 uint32_t UniversalIndex)
    : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object) {
                                 uint32_t UniversalIndex,
                                 size_t MachOFilesetEntryOffset)
    : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),
      MachOFilesetEntryOffset(MachOFilesetEntryOffset) {
  ErrorAsOutParameter ErrAsOutParam(&Err);
  uint64_t SizeOfHeaders;
  uint32_t cputype;
@@ -4761,6 +4768,11 @@ MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const {
  return getStruct<MachO::thread_command>(*this, L.Ptr);
}

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

MachO::any_relocation_info
MachOObjectFile::getRelocation(DataRefImpl Rel) const {
  uint32_t Offset;
@@ -5300,23 +5312,29 @@ bool MachOObjectFile::isRelocatableObject() const {
  return getHeader().filetype == MachO::MH_OBJECT;
}

Expected<std::unique_ptr<MachOObjectFile>>
ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer,
                                  uint32_t UniversalCputype,
                                  uint32_t UniversalIndex) {
/// Create a MachOObjectFile instance from a given buffer.
///
/// \param Buffer Memory buffer containing the MachO binary data.
/// \param UniversalCputype CPU type when the MachO part of a universal binary.
/// \param UniversalIndex Index of the MachO within a universal binary.
/// \param MachOFilesetEntryOffset Offset of the MachO entry in a fileset MachO.
/// \returns A std::unique_ptr to a MachOObjectFile instance on success.
Expected<std::unique_ptr<MachOObjectFile>> ObjectFile::createMachOObjectFile(
    MemoryBufferRef Buffer, uint32_t UniversalCputype, uint32_t UniversalIndex,
    size_t MachOFilesetEntryOffset) {
  StringRef Magic = Buffer.getBuffer().slice(0, 4);
  if (Magic == "\xFE\xED\xFA\xCE")
    return MachOObjectFile::create(Buffer, false, false,
                                   UniversalCputype, UniversalIndex);
    return MachOObjectFile::create(Buffer, false, false, UniversalCputype,
                                   UniversalIndex, MachOFilesetEntryOffset);
  if (Magic == "\xCE\xFA\xED\xFE")
    return MachOObjectFile::create(Buffer, true, false,
                                   UniversalCputype, UniversalIndex);
    return MachOObjectFile::create(Buffer, true, false, UniversalCputype,
                                   UniversalIndex, MachOFilesetEntryOffset);
  if (Magic == "\xFE\xED\xFA\xCF")
    return MachOObjectFile::create(Buffer, false, true,
                                   UniversalCputype, UniversalIndex);
    return MachOObjectFile::create(Buffer, false, true, UniversalCputype,
                                   UniversalIndex, MachOFilesetEntryOffset);
  if (Magic == "\xCF\xFA\xED\xFE")
    return MachOObjectFile::create(Buffer, true, true,
                                   UniversalCputype, UniversalIndex);
    return MachOObjectFile::create(Buffer, true, true, UniversalCputype,
                                   UniversalIndex, MachOFilesetEntryOffset);
  return make_error<GenericBinaryError>("Unrecognized MachO magic number",
                                        object_error::invalid_file_type);
}
+2 −1
Original line number Diff line number Diff line
@@ -627,7 +627,8 @@ void MappingTraits<MachO::fileset_entry_command>::mapping(
    IO &IO, MachO::fileset_entry_command &LoadCommand) {
  IO.mapRequired("vmaddr", LoadCommand.vmaddr);
  IO.mapRequired("fileoff", LoadCommand.fileoff);
  IO.mapRequired("id", LoadCommand.entry_id);
  IO.mapRequired("id", LoadCommand.entry_id.offset);
  IO.mapOptional("reserved", LoadCommand.reserved);
}

} // end namespace yaml
Loading