Index: llvm/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/include/llvm/BinaryFormat/ELF.h +++ llvm/include/llvm/BinaryFormat/ELF.h @@ -1419,6 +1419,7 @@ // LLVM-specific notes. enum { NT_LLVM_HWASAN_GLOBALS = 3, + NT_LLVM_WATERMARK = 4, }; // GNU note types Index: llvm/test/tools/llvm-readobj/note-llvm.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/note-llvm.test @@ -0,0 +1,74 @@ +## Test tools are able to dump the LLVM Watermark note section. Also test the +## output when the type field is incorrect. + +# RUN: yaml2obj -docnum=1 %s > %t1.o +# RUN: llvm-readobj --notes %t1.o | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf --notes %t1.o | FileCheck %s --check-prefix=GNU + +# LLVM: Notes [ +# LLVM-NEXT: NoteSection { +# LLVM-NEXT: Offset: 0x40 +# LLVM-NEXT: Size: 0x20 +# LLVM-NEXT: Note { +# LLVM-NEXT: Owner: LLVM +# LLVM-NEXT: Data size: 0xC +# LLVM-NEXT: Type: NT_LLVM_WATERMARK (Loadable sections watermark) +# LLVM-NEXT: Version: 01000000 +# LLVM-NEXT: Watermark: 45e69f81a671eaac +# LLVM-NEXT: } +# LLVM-NEXT: } +# LLVM-NEXT: ] + +# GNU: Displaying notes found at file offset 0x00000040 with length 0x00000020: +# GNU-NEXT: Owner Data size Description +# GNU-NEXT: LLVM 0x0000000c NT_LLVM_WATERMARK (Loadable sections watermark) +# GNU-NEXT: LLVM Watermark: 45e69f81a671eaac Version: 0x01000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .note.llvm.watermark + Type: SHT_NOTE + AddressAlign: 0x0000000000000004 + Size: 32 + Flags: [ SHF_ALLOC ] + Content: 050000000c000000040000004c4c564d000000000100000045e69f81a671eaac + + +# RUN: yaml2obj -docnum=2 %s > %t2.o +# RUN: llvm-readobj --notes %t2.o | FileCheck %s --check-prefix=LLVM_UNKNOWNTYPE +# RUN: llvm-readelf --notes %t2.o | FileCheck %s --check-prefix=GNU_UNKNOWNTYPE + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .note.llvm.watermark + Type: SHT_NOTE + AddressAlign: 0x0000000000000004 + Size: 32 + Flags: [ SHF_ALLOC ] + Content: 050000000c000000ff0000004c4c564d000000000100000045e69f81a671eaac + +# LLVM_UNKNOWNTYPE: Notes [ +# LLVM_UNKNOWNTYPE-NEXT: NoteSection { +# LLVM_UNKNOWNTYPE-NEXT: Offset: 0x40 +# LLVM_UNKNOWNTYPE-NEXT: Size: 0x20 +# LLVM_UNKNOWNTYPE-NEXT: Note { +# LLVM_UNKNOWNTYPE-NEXT: Owner: LLVM +# LLVM_UNKNOWNTYPE-NEXT: Data size: 0xC +# LLVM_UNKNOWNTYPE-NEXT: Type: Unknown note type (0x000000ff) +# LLVM_UNKNOWNTYPE-NEXT: } +# LLVM_UNKNOWNTYPE-NEXT: } +# LLVM_UNKNOWNTYPE-NEXT: ] + +# GNU_UNKNOWNTYPE: Displaying notes found at file offset 0x00000040 with length 0x00000020: +# GNU_UNKNOWNTYPE-NEXT: Owner Data size Description +# GNU_UNKNOWNTYPE-NEXT: LLVM 0x0000000c Unknown note type (0x000000ff) Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4236,6 +4236,16 @@ return OS.str(); } +static std::string getLLVMNoteTypeName(const uint32_t NT) { + if (NT == NT_LLVM_WATERMARK) + return std::string("NT_LLVM_WATERMARK (Loadable sections watermark)"); + + std::string string; + raw_string_ostream OS(string); + OS << format("Unknown note type (0x%08x)", NT); + return OS.str(); +} + static std::string getFreeBSDNoteTypeName(const uint32_t NT) { static const struct { uint32_t ID; @@ -4571,6 +4581,39 @@ } } +template +static void printLLVMWatermarkLLVMStyle(uint32_t NoteType, + ArrayRef Desc, + ScopedPrinter &W) { + if (NoteType != NT_LLVM_WATERMARK) + return; + + const size_t HashSize = 8; + const size_t VersionSize = 4; + auto Version = + StringRef(reinterpret_cast(Desc.data()), VersionSize); + auto Hash = StringRef( + reinterpret_cast(Desc.data() + VersionSize), HashSize); + W.printString("Version", toHex(Version, true)); + W.printString("Watermark", toHex(Hash, true)); +} + +template +static void printLLVMWatermark(raw_ostream &OS, uint32_t NoteType, + ArrayRef Desc) { + + if (NoteType != NT_LLVM_WATERMARK) + return; + + const size_t HashSize = 8; + const size_t VersionSize = 4; + auto Hash = StringRef( + reinterpret_cast(Desc.data() + VersionSize), HashSize); + auto Version= StringRef(reinterpret_cast(Desc.data()), VersionSize); + OS << " LLVM Watermark: " << toHex(Hash, true) + << " Version: 0x" << toHex(Version); +} + struct CoreFileMapping { uint64_t Start, End, Offset; StringRef Filename; @@ -4668,6 +4711,8 @@ OS << getAMDNoteTypeName(Type) << '\n'; } else if (Name == "AMDGPU") { OS << getAMDGPUNoteTypeName(Type) << '\n'; + } else if (Name == "LLVM") { + OS << getLLVMNoteTypeName(Type) << '\n'; } else { StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE ? getCoreNoteTypeName(Type) @@ -4701,6 +4746,8 @@ else reportWarning(Note.takeError(), this->FileName); } + } else if (Name == "LLVM") { + printLLVMWatermark(OS, Type, Descriptor); } else if (!Descriptor.empty()) { OS << " description data:"; for (uint8_t B : Descriptor) @@ -5563,7 +5610,8 @@ this->dumper()->printSymbolsHelper(true); } -template void LLVMStyle::printDynamic(const ELFFile *Obj) { +template +void LLVMStyle::printDynamic(const ELFFile *Obj) { Elf_Dyn_Range Table = this->dumper()->dynamic_table(); if (Table.empty()) return; @@ -5941,6 +5989,8 @@ W.printString("Type", getAMDNoteTypeName(Type)); } else if (Name == "AMDGPU") { W.printString("Type", getAMDGPUNoteTypeName(Type)); + } else if (Name == "LLVM") { + W.printString("Type", getLLVMNoteTypeName(Type)); } else { StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE ? getCoreNoteTypeName(Type) @@ -5975,6 +6025,8 @@ else reportWarning(Note.takeError(), this->FileName); } + } else if (Name == "LLVM") { + printLLVMWatermarkLLVMStyle(Type, Descriptor, W); } else if (!Descriptor.empty()) { W.printBinaryBlock("Description data", Descriptor); } @@ -6019,7 +6071,7 @@ ArrayRef Contents = unwrapOrError(this->FileName, Obj->getSectionContents(&Shdr)); - for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) { + for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E;) { StringRef Key = StringRef(reinterpret_cast(P)); StringRef Value = StringRef(reinterpret_cast(P) + Key.size() + 1);