mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-30 08:56:40 +00:00
llvm-readobj: add support for printing GNU Notes
Add support for printing the GNU Notes. This allows an easy way to view the build id for a binary built with the build id. Currently, this only handles the GNU notes, though it would be easy to extend for other note types (default, FreeBSD, NetBSD, etc). Only the GNU style is supported currently. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280131 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a2a31ca57f
commit
b899d1987d
76
test/tools/llvm-readobj/gnu-notes.test
Normal file
76
test/tools/llvm-readobj/gnu-notes.test
Normal file
@ -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
|
||||
...
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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() { }
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user