This is an archive of the discontinued LLVM Phabricator instance.

[llvm-readobj] - Teach llvm-readobj to dump .note.gnu.property sections.
ClosedPublic

Authored by grimar on Mar 14 2018, 7:56 AM.

Details

Summary

NT_GNU_PROPERTY_TYPE_0 is a recently added type of .note.gnu.property
section specified in Linux Extensions to gABI.
(https://github.com/hjl-tools/linux-abi/wiki/Linux-Extensions-to-gABI)

Patch teach tool to print such notes properly.

Diff Detail

Repository
rL LLVM

Event Timeline

grimar created this revision.Mar 14 2018, 7:56 AM
grimar planned changes to this revision.Mar 14 2018, 8:38 AM
grimar updated this revision to Diff 138390.Mar 14 2018, 9:24 AM
  • Fixed padding handling, added comments and test cases.

Have these been found in the wild? If not I would probably wait until
someone wants to use them.

Cheers,
Rafael

George Rimar via Phabricator via llvm-commits
<llvm-commits@lists.llvm.org> writes:

grimar updated this revision to Diff 138390.
grimar added a comment.

  • Fixed padding handling, added comments and test cases.

https://reviews.llvm.org/D44469

Files:

include/llvm/BinaryFormat/ELF.h
test/tools/llvm-readobj/note-gnu-property.s
test/tools/llvm-readobj/note-gnu-property2.s
tools/llvm-readobj/ELFDumper.cpp

Index: tools/llvm-readobj/ELFDumper.cpp

  • tools/llvm-readobj/ELFDumper.cpp

+++ tools/llvm-readobj/ELFDumper.cpp
@@ -2510,13 +2510,13 @@

StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
StringRef Signature = StrTable.data() + Sym->st_name;
  • Ret.push_back({Name,
  • Signature,
  • Sec.sh_name,

+ Ret.push_back({Name,
+ Signature,
+ Sec.sh_name,

I - 1,
Sec.sh_link,
Sec.sh_info,
  • Data[0],

+ Data[0],

               {}});
 
std::vector<GroupMember> &GM = Ret.back().Members;

@@ -3411,6 +3411,7 @@

{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)"},

+ {ELF::NT_GNU_PROPERTY_TYPE_0, "NT_GNU_PROPERTY_TYPE_0 (property note)"},

};
 
for (const auto &Note : Notes)

@@ -3475,8 +3476,40 @@
}

template <typename ELFT>
+static void printGNUProperty(raw_ostream &OS, uint32_t Type, uint32_t DataSize,
+ ArrayRef<uint8_t> Data) {
+ const endianness E = ELFT::TargetEndianness;
+
+ switch (Type) {
+ default:
+ OS << format(" unknown property type: 0x%04x\n", Type);
+ return;
+ case GNU_PROPERTY_STACK_SIZE: {
+ OS << " stack size: ";
+ if (Data.size() >= sizeof(typename ELFT::uint)) {
+ uint64_t StackSize = ELFT::Is64Bits
+ ? support::endian::read64(Data.data(), E)
+ : support::endian::read32(Data.data(), E);
+ OS << format("0x%08x\n", StackSize);
+ } else {
+ OS << format("pr_datasz is corrupted (0x%08x) \n", DataSize);
+ }
+ break;
+ }
+ case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
+ OS << " no copy on protected";
+ if (DataSize)
+ OS << format(": pr_datasz (0x%08x) is corrupted", DataSize);
+ OS << "\n";
+ break;
+ }
+}
+
+template <typename ELFT>
static void printGNUNote(raw_ostream &OS, uint32_t NoteType,

ArrayRef<typename ELFT::Word> Words, size_t Size) {

+ const endianness E = ELFT::TargetEndianness;
+

switch (NoteType) {
default:
  return;

@@ -3508,8 +3541,30 @@

OS << "    Version: "
   << StringRef(reinterpret_cast<const char *>(Words.data()), Size);
break;
  • }

+ case ELF::NT_GNU_PROPERTY_TYPE_0:
+ OS << " Properties:\n";

+ ArrayRef<uint8_t> Arr(reinterpret_cast<const uint8_t *>(Words.data()),
+ Size);
+ while (Arr.size() >= 8) {
+ uint32_t Type = support::endian::read32(Arr.data(), E);
+ uint32_t DataSize = support::endian::read32(Arr.data() + 4, E);
+ Arr = Arr.drop_front(8);
+
+ // Take padding size into account if present.
+ uint64_t PaddedSize = alignTo(DataSize, sizeof(typename ELFT::uint));
+ if (Arr.size() < PaddedSize) {
+ OS << " <unexpected end of property declaration>";
+ break;
+ }
+ printGNUProperty<ELFT>(OS, Type, DataSize, Arr.take_front(PaddedSize));
+ Arr = Arr.drop_front(PaddedSize);
+ }
+
+ if (!Arr.empty())
+ OS << " <corrupted GNU_PROPERTY_TYPE_0>";
+ break;
+ }

OS << '\n';

}

Index: test/tools/llvm-readobj/note-gnu-property2.s

  • test/tools/llvm-readobj/note-gnu-property2.s

+++ test/tools/llvm-readobj/note-gnu-property2.s
@@ -0,0 +1,22 @@
+ REQUIRES: x86-registered-target
+
RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
+ RUN: llvm-readobj -elf-output-style GNU --notes %t | FileCheck %s
+
+
CHECK: Displaying notes found at file offset 0x00000040 with length 0x00000014:
+ CHECK-NEXT: Owner Data size Description
+
CHECK-NEXT: GNU 0x00000004 NT_GNU_PROPERTY_TYPE_0 (property note)
+ CHECK-NEXT: Properties:
+
CHECK-NEXT: <corrupted GNU_PROPERTY_TYPE_0>
+
+// Section below is broken, check we report that.
+
+.section ".note.gnu.property", "a"
+.align 4
+ .long 4 /* Name length is always 4 ("GNU") */
+ .long end - begin /* Data length */
+ .long 5 /* Type: NT_GNU_PROPERTY_TYPE_0 */
+ .asciz "GNU" /* Name */
+ .p2align 3
+begin:
+ .long 1 /* Type: GNU_PROPERTY_STACK_SIZE */
+end:

Index: test/tools/llvm-readobj/note-gnu-property.s

  • test/tools/llvm-readobj/note-gnu-property.s

+++ test/tools/llvm-readobj/note-gnu-property.s
@@ -0,0 +1,62 @@
+ REQUIRES: x86-registered-target
+
RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
+ RUN: llvm-readobj -elf-output-style GNU --notes %t | FileCheck %s
+
+
CHECK: Displaying notes found at file offset 0x00000040 with length 0x00000060:
+ CHECK-NEXT: Owner Data size Description
+
CHECK-NEXT: GNU 0x00000050 NT_GNU_PROPERTY_TYPE_0 (property note)
+ CHECK-NEXT: Properties:
+
CHECK-NEXT: stack size: 0x00000100
+ CHECK-NEXT: stack size: 0x00000100
+
CHECK-NEXT: no copy on protected
+ CHECK-NEXT: unknown property type: 0xfefefefe
+
CHECK-NEXT: stack size: pr_datasz is corrupted (0x00000000)
+ CHECK-NEXT: no copy on protected: pr_datasz (0x00000001) is corrupted
+
CHECK-NEXT: <unexpected end of property declaration>
+
+.section ".note.gnu.property", "a"
+.align 4
+ .long 4 /* Name length is always 4 ("GNU") */
+ .long end - begin /* Data length */
+ .long 5 /* Type: NT_GNU_PROPERTY_TYPE_0 */
+ .asciz "GNU" /* Name */
+ .p2align 3
+begin:
+ .long 1 /* Type: GNU_PROPERTY_STACK_SIZE */
+ .long 8 /* Data size */
+ .quad 0x100 /* Data (stack size) */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+
+ /* Test we handle alignment properly */
+ .long 1 /* Type: GNU_PROPERTY_STACK_SIZE */
+ .long 4 /* Data size */
+ .long 0x100 /* Data (stack size) */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+
+ .long 2 /* Type: GNU_PROPERTY_NO_COPY_ON_PROTECTED */
+ .long 0 /* Data size */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+
+ /* All notes below are broken. Test we are able to report them. */
+
+ /* Broken note type */
+ .long 0xfefefefe /* Invalid type for testing */
+ .long 0 /* Data size */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+
+ /* GNU_PROPERTY_STACK_SIZE with zero stack size */
+ .long 1 /* Type: GNU_PROPERTY_STACK_SIZE */
+ .long 0 /* Data size */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+
+ /* GNU_PROPERTY_NO_COPY_ON_PROTECTED with pr_datasz and some data */
+ .long 2 /* Type: GNU_PROPERTY_NO_COPY_ON_PROTECTED */
+ .long 1 /* Data size (corrupted) */
+ .byte 1 /* Data */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+
+ /* GNU_PROPERTY_NO_COPY_ON_PROTECTED with pr_datasz and without data */
+ .long 2 /* Type: GNU_PROPERTY_NO_COPY_ON_PROTECTED */
+ .long 1 /* Data size (corrupted) */
+ .p2align 3 /* Align to 8 byte for 64 bit */
+end:

Index: include/llvm/BinaryFormat/ELF.h

  • include/llvm/BinaryFormat/ELF.h

+++ include/llvm/BinaryFormat/ELF.h
@@ -1440,6 +1440,13 @@

NT_GNU_HWCAP = 2,
NT_GNU_BUILD_ID = 3,
NT_GNU_GOLD_VERSION = 4,

+ NT_GNU_PROPERTY_TYPE_0 = 5,
+};
+
+// Property types used in GNU_PROPERTY_TYPE_0 notes.
+enum {
+ GNU_PROPERTY_STACK_SIZE = 1,
+ GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2,
};

// AMDGPU specific notes.


llvm-commits mailing list
llvm-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits

Have these been found in the wild? If not I would probably wait until
someone wants to use them.

Cheers,
Rafael

I know about 2 possible relative use cases we might want to support in LLD in future:

  1. We might want to support Intel CET (https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf)

It is a relatively new thing and supported by bfd, but not by gold yet: https://sourceware.org/bugzilla/show_bug.cgi?id=22915
BFD commit: https://sourceware.org/ml/binutils/2017-06/msg00270.html

  1. GNU_PROPERTY_STACK_SIZE. ("Linker should select the maximum value

among all input relocatable objects and copy this property to the output. Run-time loader should raise the stack limit to the value specified in this property.")
(https://sourceware.org/bugzilla/show_bug.cgi?id=22914)

Both of these require linker to know about .note.gnu.property. Second because is a part of System V ABI now
(and so I supposed we might want to support it in LLD anyways or at least to teach llvm-readobj to parse it for now
and error out on .note.gnu.property section, hence this patch).

About using in the wild I found Linux kernel discussion about that feature (NT_GNU_PROPERTY_TYPE_0):
https://lkml.org/lkml/2017/8/9/529
Looks like they plan to use it, though there are no patches yet AFAIK.

George.

Second because is a part of System V ABI now

It supposed to be "Second is a part of System V ABI now"

George.

espindola added inline comments.Mar 15 2018, 2:23 PM
tools/llvm-readobj/ELFDumper.cpp
3490 ↗(On Diff #138390)

Since this function is templated on ELFT I think you can just used ELFT::Addr:

uint64_t StackSize = *(ELFT::Addr*)Data.data();

grimar updated this revision to Diff 138674.Mar 16 2018, 3:06 AM
  • Addressed review comment.
tools/llvm-readobj/ELFDumper.cpp
3490 ↗(On Diff #138390)

Yes, you're right, thanks.

espindola added inline comments.Mar 19 2018, 9:26 AM
test/tools/llvm-readobj/note-gnu-property.s
15 ↗(On Diff #138674)

Shouldn't this cause llvm-readobj to exit with a non-0 value?

grimar updated this revision to Diff 139099.Mar 20 2018, 4:02 AM
  • Adjusted output format to match readelf.
test/tools/llvm-readobj/note-gnu-property.s
15 ↗(On Diff #138674)

I think no, because Binutils readelf return 0 in this case.

Though it reports things in a slightly different format:

      Properties: stack size: 0x100
	stack size: <corrupt length: 0x4> 
	no copy on protected 
	<application-specific type 0xfefefefe data: >
	stack size: <corrupt length: 0> 
	no copy on protected <corrupt length: 0x1> 
	<corrupt type (0x2) datasz: 0x1>

I updated the patch to follow.

espindola accepted this revision.Mar 20 2018, 3:54 PM

LGTM with a nit since this is just dumping something that gnu tools are now producing.

tools/llvm-readobj/ELFDumper.cpp
3547 ↗(On Diff #139099)

This is templated, so use ELFT::Word.

This revision is now accepted and ready to land.Mar 20 2018, 3:54 PM
This revision was automatically updated to reflect the committed changes.