summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/test/tools/llvm-readobj/gnu-notes.test76
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp138
-rw-r--r--llvm/tools/llvm-readobj/ObjDumper.h1
-rw-r--r--llvm/tools/llvm-readobj/llvm-readobj.cpp6
4 files changed, 221 insertions, 0 deletions
diff --git a/llvm/test/tools/llvm-readobj/gnu-notes.test b/llvm/test/tools/llvm-readobj/gnu-notes.test
new file mode 100644
index 00000000000..1a9c7e304b1
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/gnu-notes.test
@@ -0,0 +1,76 @@
+# RUN: yaml2obj %s > %t.so
+# RUN: llvm-readobj -elf-output-style GNU --notes %t.so | FileCheck %s
+
+# CHECK: Displaying notes found at file offset 0x00000300 with length 0x00000020:
+# CHECK: Owner Data size Description
+# CHECK: GNU 0x00000010 NT_GNU_BUILD_ID (unique build ID bitstring)
+# CHECK: Build ID: 4fcb712aa6387724a9f465a32cd8c14b
+
+# CHECK: Displaying notes found at file offset 0x0000036c with length 0x0000001c:
+# CHECK: Owner Data size Description
+# CHECK: GNU 0x00000009 NT_GNU_GOLD_VERSION (gold version)
+# CHECK: Version: gold 1.11
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .note.gnu.build-id
+ Type: SHT_NOTE
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0000000000400120
+ AddressAlign: 0x0000000000000004
+ Content: 040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0000000000400140
+ AddressAlign: 0x0000000000000001
+ Content: 31C0C3
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0000000000400148
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000017A5200017810011B0C070890010000140000001C000000D8FFFFFF030000000000000000000000
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000401000
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000401000
+ AddressAlign: 0x0000000000000001
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 004743433A2028474E552920352E342E3000
+ - Name: .note.gnu.gold-version
+ Type: SHT_NOTE
+ AddressAlign: 0x0000000000000004
+ Content: 040000000900000004000000474E5500676F6C6420312E3131000000
+Symbols:
+ Local:
+ - Name: reduced.c
+ Type: STT_FILE
+ - Type: STT_FILE
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000400140
+ Size: 0x0000000000000003
+ - Name: _edata
+ Value: 0x0000000000401000
+ - Name: __bss_start
+ Value: 0x0000000000401000
+ - Name: _end
+ Value: 0x0000000000401000
+...
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 1ed10932e69..7e3394ba2fd 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -126,6 +126,8 @@ public:
void printHashHistogram() override;
+ void printNotes() override;
+
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
typedef ELFFile<ELFT> ELFO;
@@ -292,6 +294,7 @@ public:
bool IsDynamic) = 0;
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
private:
const ELFDumper<ELFT> *Dumper;
@@ -314,6 +317,7 @@ public:
size_t Offset) override;
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
+ void printNotes(const ELFFile<ELFT> *Obj) override;
private:
struct Field {
@@ -367,6 +371,7 @@ public:
void printDynamicRelocations(const ELFO *Obj) override;
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
+ void printNotes(const ELFFile<ELFT> *Obj) override;
private:
void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
@@ -1491,6 +1496,11 @@ void ELFDumper<ELFT>::printDynamicSymbols() {
template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
ELFDumperStyle->printHashHistogram(Obj);
}
+
+template <class ELFT> void ELFDumper<ELFT>::printNotes() {
+ ELFDumperStyle->printNotes(Obj);
+}
+
#define LLVM_READOBJ_TYPE_CASE(name) \
case DT_##name: return #name
@@ -3161,6 +3171,127 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
}
}
+static std::string getGNUNoteTypeName(const uint32_t NT) {
+ static const struct {
+ uint32_t ID;
+ const char *Name;
+ } Notes[] = {
+ {ELF::NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG (ABI version tag)"},
+ {ELF::NT_GNU_HWCAP, "NT_GNU_HWCAP (DSO-supplied software HWCAP info)"},
+ {ELF::NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID (unique build ID bitstring)"},
+ {ELF::NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION (gold version)"},
+ };
+
+ for (const auto &Note : Notes)
+ if (Note.ID == NT)
+ return std::string(Note.Name);
+
+ std::string string;
+ raw_string_ostream OS(string);
+ OS << format("Unknown note type (0x%08x)", NT);
+ return string;
+}
+
+template <typename ELFT>
+static void printGNUNote(raw_ostream &OS, uint32_t NoteType,
+ ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words) {
+ switch (NoteType) {
+ default:
+ return;
+ case ELF::NT_GNU_ABI_TAG: {
+ static const char *OSNames[] = {
+ "Linux", "Hurd", "Solaris", "FreeBSD", "NetBSD", "Syllable", "NaCl",
+ };
+
+ StringRef OSName = "Unknown";
+ if (Words[0] < array_lengthof(OSNames))
+ OSName = OSNames[Words[0]];
+ uint32_t Major = Words[1], Minor = Words[2], Patch = Words[3];
+
+ if (Words.size() < 4)
+ OS << " <corrupt GNU_ABI_TAG>";
+ else
+ OS << " OS: " << OSName << ", ABI: " << Major << "." << Minor << "."
+ << Patch;
+ break;
+ }
+ case ELF::NT_GNU_BUILD_ID: {
+ OS << " Build ID: ";
+ ArrayRef<uint8_t> ID(reinterpret_cast<const uint8_t *>(Words.data()),
+ Words.size() * 4);
+ for (const auto &B : ID)
+ OS << format_hex_no_prefix(B, 2);
+ break;
+ }
+ case ELF::NT_GNU_GOLD_VERSION:
+ OS << " Version: "
+ << StringRef(reinterpret_cast<const char *>(Words.data()),
+ Words.size() * 4);
+ break;
+ }
+
+ OS << '\n';
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
+ const Elf_Ehdr *e = Obj->getHeader();
+ bool IsCore = e->e_type == ELF::ET_CORE;
+
+ auto process = [&](const typename ELFFile<ELFT>::Elf_Off Offset,
+ const typename ELFFile<ELFT>::Elf_Addr Size) {
+ using Word = typename ELFFile<ELFT>::Elf_Word;
+
+ if (Size <= 0)
+ return;
+
+ const auto *P = static_cast<const uint8_t *>(Obj->base() + Offset);
+ const auto *E = P + Size;
+
+ OS << "Displaying notes found at file offset " << format_hex(Offset, 10)
+ << " with length " << format_hex(Size, 10) << ":\n"
+ << " Owner Data size\tDescription\n";
+
+ while (P < E) {
+ const Word *Words = reinterpret_cast<const Word *>(&P[0]);
+
+ uint32_t NameSize = Words[0];
+ uint32_t DescriptorSize = Words[1];
+ uint32_t Type = Words[2];
+
+ ArrayRef<Word> Descriptor(&Words[3 + (alignTo<4>(NameSize) / 4)],
+ alignTo<4>(DescriptorSize) / 4);
+
+ StringRef Name;
+ if (NameSize)
+ Name =
+ StringRef(reinterpret_cast<const char *>(&Words[3]), NameSize - 1);
+
+ OS << " " << Name << std::string(22 - NameSize, ' ')
+ << format_hex(DescriptorSize, 10) << '\t';
+
+ if (Name == "GNU") {
+ OS << getGNUNoteTypeName(Type) << '\n';
+ printGNUNote<ELFT>(OS, Type, Descriptor);
+ }
+ OS << '\n';
+
+ P = P + 3 * sizeof(Word) * alignTo<4>(NameSize) +
+ alignTo<4>(DescriptorSize);
+ }
+ };
+
+ if (IsCore) {
+ for (const auto &P : Obj->program_headers())
+ if (P.p_type == PT_NOTE)
+ process(P.p_offset, P.p_filesz);
+ } else {
+ for (const auto &S : Obj->sections())
+ if (S.sh_type == SHT_NOTE)
+ process(S.sh_offset, S.sh_size);
+ }
+}
+
template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
const Elf_Ehdr *e = Obj->getHeader();
{
@@ -3526,7 +3657,14 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
W.printNumber("Alignment", Phdr.p_align);
}
}
+
template <class ELFT>
void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
W.startLine() << "Hash Histogram not implemented!\n";
}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
+ W.startLine() << "printNotes not implemented!\n";
+}
+
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index a39fc260b54..9368cc562fe 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -47,6 +47,7 @@ public:
virtual void printVersionInfo() {}
virtual void printGroupSections() {}
virtual void printHashHistogram() {}
+ virtual void printNotes() {}
// Only implemented for ARM ELF at this time.
virtual void printAttributes() { }
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index d811ea995ba..53d6782a671 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -92,6 +92,10 @@ namespace opts {
cl::desc("Alias for --relocations"),
cl::aliasopt(Relocations));
+ // -notes, -n
+ cl::opt<bool> Notes("notes", cl::desc("Display the ELF notes in the file"));
+ cl::alias NotesShort("n", cl::desc("Alias for --notes"), cl::aliasopt(Notes));
+
// -dyn-relocations
cl::opt<bool> DynRelocs("dyn-relocations",
cl::desc("Display the dynamic relocation entries in the file"));
@@ -408,6 +412,8 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printGroupSections();
if (opts::HashHistogram)
Dumper->printHashHistogram();
+ if (opts::Notes)
+ Dumper->printNotes();
}
if (Obj->isCOFF()) {
if (opts::COFFImports)
OpenPOWER on IntegriCloud