char Padding[4];
};
+struct LoaderSectionHeader32 {
+ support::ubig32_t Version;
+ support::ubig32_t NumberOfSymTabEnt;
+ support::ubig32_t NumberOfRelTabEnt;
+ support::ubig32_t LengthOfImpidStrTbl;
+ support::ubig32_t NumberOfImpid;
+ support::big32_t OffsetToImpid;
+ support::ubig32_t LengthOfStrTbl;
+ support::big32_t OffsetToStrTbl;
+};
+
+struct LoaderSectionHeader64 {
+ support::ubig32_t Version;
+ support::ubig32_t NumberOfSymTabEnt;
+ support::ubig32_t NumberOfRelTabEnt;
+ support::ubig32_t LengthOfImpidStrTbl;
+ support::ubig32_t NumberOfImpid;
+ support::ubig32_t LengthOfStrTbl;
+ support::big64_t OffsetToImpid;
+ support::big64_t OffsetToStrTbl;
+ support::big64_t OffsetToSymTbl;
+ char Padding[16];
+ support::big32_t OffsetToRelEnt;
+};
+
struct XCOFFStringTable {
uint32_t Size;
const char *Data;
const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const;
uintptr_t getSectionHeaderTableAddress() const;
uintptr_t getEndOfSymbolTableAddress() const;
+ Expected<uintptr_t> getLoaderSectionAddress() const;
// This returns a pointer to the start of the storage for the name field of
// the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily
template <typename Shdr, typename Reloc>
Expected<ArrayRef<Reloc>> relocations(const Shdr &Sec) const;
+ // Loader section related interfaces.
+ Expected<StringRef> getImportFileTable() const;
+
// This function returns string table entry.
Expected<StringRef> getStringTableEntry(uint32_t Offset) const;
return Result;
}
+Expected<uintptr_t> XCOFFObjectFile::getLoaderSectionAddress() const {
+ uint64_t OffsetToLoaderSection = 0;
+ uint64_t SizeOfLoaderSection = 0;
+
+ if (is64Bit()) {
+ for (const auto &Sec64 : sections64())
+ if (Sec64.getSectionType() == XCOFF::STYP_LOADER) {
+ OffsetToLoaderSection = Sec64.FileOffsetToRawData;
+ SizeOfLoaderSection = Sec64.SectionSize;
+ break;
+ }
+ } else {
+ for (const auto &Sec32 : sections32())
+ if (Sec32.getSectionType() == XCOFF::STYP_LOADER) {
+ OffsetToLoaderSection = Sec32.FileOffsetToRawData;
+ SizeOfLoaderSection = Sec32.SectionSize;
+ break;
+ }
+ }
+
+ // No loader section is not an error.
+ if (!SizeOfLoaderSection)
+ return 0;
+
+ uintptr_t LoderSectionStart =
+ reinterpret_cast<uintptr_t>(base() + OffsetToLoaderSection);
+ if (Error E =
+ Binary::checkOffset(Data, LoderSectionStart, SizeOfLoaderSection))
+ return std::move(E);
+ return LoderSectionStart;
+}
+
bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
return false;
}
return XCOFFStringTable{Size, StringTablePtr};
}
+// This function returns the import file table. Each entry in the import file
+// table consists of: "path_name\0base_name\0archive_member_name\0".
+Expected<StringRef> XCOFFObjectFile::getImportFileTable() const {
+ Expected<uintptr_t> LoaderSectionAddrOrError = getLoaderSectionAddress();
+ if (!LoaderSectionAddrOrError)
+ return LoaderSectionAddrOrError.takeError();
+
+ uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
+ if (!LoaderSectionAddr)
+ return StringRef();
+
+ uint64_t OffsetToImportFileTable = 0;
+ uint64_t LengthOfImportFileTable = 0;
+ if (is64Bit()) {
+ const LoaderSectionHeader64 *LoaderSec64 =
+ viewAs<LoaderSectionHeader64>(LoaderSectionAddr);
+ OffsetToImportFileTable = LoaderSec64->OffsetToImpid;
+ LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl;
+ } else {
+ const LoaderSectionHeader32 *LoaderSec32 =
+ viewAs<LoaderSectionHeader32>(LoaderSectionAddr);
+ OffsetToImportFileTable = LoaderSec32->OffsetToImpid;
+ LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl;
+ }
+
+ auto ImportTableOrErr = getObject<char>(
+ Data,
+ reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable),
+ LengthOfImportFileTable);
+ if (Error E = ImportTableOrErr.takeError())
+ return std::move(E);
+
+ const char *ImportTablePtr = ImportTableOrErr.get();
+ if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0')
+ return createStringError(
+ object_error::parse_failed,
+ "the import file table must end with a null terminator");
+
+ return StringRef(ImportTablePtr, LengthOfImportFileTable);
+}
+
Expected<std::unique_ptr<XCOFFObjectFile>>
XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
// Can't use std::make_unique because of the private constructor.
--- /dev/null
+## In this test we check the --needed-libs option.
+
+# RUN: llvm-readobj --needed-libs %p/Inputs/needed-libs-32.o \
+# RUN: %p/Inputs/needed-libs-64.o %p/Inputs/needed-libs-empty.o |\
+# RUN: FileCheck %s --strict-whitespace --match-full-lines
+
+## Check 32-bit.
+
+# CHECK:NeededLibraries [
+# CHECK-NEXT: BASE MEMBER
+# CHECK-NEXT: libc.a shr.o
+# CHECK-NEXT: libpthreads.a shr_xpg5.o
+# CHECK-NEXT: libabcdefghijk.a
+# CHECK-NEXT:]
+
+## Check 64-bit.
+
+# CHECK:NeededLibraries [
+# CHECK-NEXT: BASE MEMBER
+# CHECK-NEXT: libc.a shr_64.o
+# CHECK-NEXT: libpthreads.a shr_xpg5_64.o
+# CHECK-NEXT: libabcdefghijk64.a
+# CHECK-NEXT:]
+
+## Check no lib.
+
+# CHECK:NeededLibraries [
+# CHECK-NEXT: BASE MEMBER
+# CHECK-NEXT:]
#include "ObjDumper.h"
#include "llvm-readobj.h"
#include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ScopedPrinter.h"
using namespace llvm;
}
void XCOFFDumper::printNeededLibraries() {
- llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+ ListScope D(W, "NeededLibraries");
+ auto ImportFilesOrError = Obj.getImportFileTable();
+ if (!ImportFilesOrError) {
+ reportUniqueWarning(ImportFilesOrError.takeError());
+ return;
+ }
+
+ StringRef ImportFileTable = ImportFilesOrError.get();
+ const char *CurrentStr = ImportFileTable.data();
+ const char *TableEnd = ImportFileTable.end();
+ // Default column width for names is 13 even if no names are that long.
+ size_t BaseWidth = 13;
+
+ // Get the max width of BASE columns.
+ for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
+ size_t CurrentLen = strlen(CurrentStr);
+ CurrentStr += strlen(CurrentStr) + 1;
+ if (StrIndex % 3 == 1)
+ BaseWidth = std::max(BaseWidth, CurrentLen);
+ }
+
+ auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
+ // Each entry consists of 3 strings: the path_name, base_name and
+ // archive_member_name. The first entry is a default LIBPATH value and other
+ // entries have no path_name. We just dump the base_name and
+ // archive_member_name here.
+ OS << left_justify("BASE", BaseWidth) << " MEMBER\n";
+ CurrentStr = ImportFileTable.data();
+ for (size_t StrIndex = 0; CurrentStr < TableEnd;
+ ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
+ if (StrIndex >= 3 && StrIndex % 3 != 0) {
+ if (StrIndex % 3 == 1)
+ OS << " " << left_justify(CurrentStr, BaseWidth) << " ";
+ else
+ OS << CurrentStr << "\n";
+ }
+ }
}
static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {