public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Support AArch64 MTE memory tag dumps in core files
@ 2022-03-31 14:04 Luis Machado
  2022-04-01  1:34 ` Alan Modra
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Luis Machado @ 2022-03-31 14:04 UTC (permalink / raw)
  To: binutils

The Linux kernel can dump memory tag segments to a core file, one segment
per mapped range. The format and documentation can be found in the Linux
kernel tree [1].

The following patch adjusts bfd and binutils see they can handle this new
segment type and display it accordingly. It also adds code required so GDB
can properly read/dump core file data containing memory tags.

Upon reading, each segment that contains memory tags gets mapped to a
.memtag section. These sections will be used by GDB to lookup the tag data.

There is another patch for GDB that enables both reading
and dumping of memory tag segments.

Given sections based on segments are numbered, I had to update the code to
not number the memory tag ones. This simplifies GDB's lookup of the memory
tag sections.

Tested on aarch64-linux Ubuntu 20.04.

[1] Documentation/arm64/memory-tagging-extension.rst (Core Dump Support)
---
 bfd/bfd-in2.h        | 19 +++++++---
 bfd/elf-bfd.h        |  2 ++
 bfd/elf.c            | 82 ++++++++++++++++++++++++++++++++++++++++++++
 bfd/section.c        | 24 +++++++++----
 binutils/readelf.c   |  1 +
 include/elf/common.h |  5 +++
 6 files changed, 123 insertions(+), 10 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index c0b563aec02..0e5e7104555 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1027,6 +1027,9 @@ typedef struct bfd_section
   /* Nonzero if this section uses RELA relocations, rather than REL.  */
   unsigned int use_rela_p:1;
 
+  /* Nonzero if this section contains memory tag data.  Default is 0.  */
+  unsigned int has_memory_tags : 1;
+
   /* Bits used by various backends.  The generic code doesn't touch
      these fields.  */
 
@@ -1070,6 +1073,11 @@ typedef struct bfd_section
   /* The compressed size of the section in octets.  */
   bfd_size_type compressed_size;
 
+  /* If HAS_MEMORY_TAGS is true, MEMORY_TAGS_RANGE_SIZE is the original memory
+     range size, in octets, of the memory that contained the tags stored in this
+     section.  SIZE is the size of the packed tags from that memory range.  */
+  bfd_size_type memory_tags_range_size;
+
   /* Relaxation table. */
   struct relax_table *relax;
 
@@ -1330,14 +1338,17 @@ discarded_section (const asection *sec)
   /* linker_mark, linker_has_input, gc_mark, decompress_status,     */ \
      0,           0,                1,       0,                        \
                                                                        \
-  /* segment_mark, sec_info_type, use_rela_p,                       */ \
-     0,            0,             0,                                   \
+  /* segment_mark, sec_info_type, use_rela_p, has_memory_tags,      */ \
+     0,            0,             0,          0,                       \
                                                                        \
   /* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5,    */ \
      0,        0,        0,        0,        0,        0,              \
                                                                        \
-  /* vma, lma, size, rawsize, compressed_size, relax, relax_count,  */ \
-     0,   0,   0,    0,       0,               0,     0,               \
+  /* vma, lma, size, rawsize, compressed_size,                      */ \
+     0,   0,   0,    0,       0,                                       \
+                                                                       \
+  /* memory_tags_range_size, relax, relax_count,                    */ \
+     0,                      0,     0,                                 \
                                                                        \
   /* output_offset, output_section, alignment_power,                */ \
      0,             &SEC,           0,                                 \
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 5c3985f6e57..dc4c4faea7e 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2227,6 +2227,8 @@ extern bool bfd_elf_mkcorefile
   (bfd *);
 extern bool _bfd_elf_make_section_from_shdr
   (bfd *, Elf_Internal_Shdr *, const char *, int);
+extern bool _bfd_elf_make_memtag_section_from_phdr
+  (bfd *, Elf_Internal_Phdr *);
 extern bool _bfd_elf_make_section_from_phdr
   (bfd *, Elf_Internal_Phdr *, int, const char *);
 extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc
diff --git a/bfd/elf.c b/bfd/elf.c
index 82b53be99f9..422f0f50151 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1629,10 +1629,30 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   return true;
 }
 
+/* Given P_TYPE, return TRUE if it represents a memory tag type.  Otherwise
+   return false.  */
+
+static bool
+is_memory_tag_p_type (unsigned int p_type)
+{
+  switch (p_type)
+    {
+    case PT_ARM_MEMTAG_MTE:
+      return true;
+    default:
+      return false;
+    }
+}
+
 static const char *
 get_segment_type (unsigned int p_type)
 {
   const char *pt;
+
+  /* Handle memory tag p_type's first.  */
+  if (is_memory_tag_p_type (p_type))
+    return "MEMTAG";
+
   switch (p_type)
     {
     case PT_NULL: pt = "NULL"; break;
@@ -2896,6 +2916,47 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
   return _bfd_generic_new_section_hook (abfd, sec);
 }
 
+/* Create a new bfd section for a memory tag ELF segment.
+
+   The name of the section is "memtag" and there can be multiple such
+   sections.  */
+
+bool
+_bfd_elf_make_memtag_section_from_phdr (bfd *abfd,
+					Elf_Internal_Phdr *hdr)
+{
+  asection *newsect;
+  unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+
+  if (!is_memory_tag_p_type (hdr->p_type))
+    return false;
+
+  if (hdr->p_filesz > 0)
+    {
+      /* Sections created from memory tag p_type's are always named
+	 "memtag".  */
+      newsect = bfd_make_section_anyway (abfd, "memtag");
+
+      if (newsect == NULL)
+	return false;
+
+      /* p_vaddr holds the original start address of the tagged memory
+	 range.  */
+      newsect->vma = hdr->p_vaddr / opb;
+
+      /* p_filesz holds the storage size of the packed tags.  */
+      newsect->size = hdr->p_filesz;
+      newsect->filepos = hdr->p_offset;
+
+      /* Set the memory tags range size to the original length of the tagged
+	 memory range.  */
+      newsect->has_memory_tags = 1;
+      newsect->memory_tags_range_size = hdr->p_memsz;
+    }
+
+  return true;
+}
+
 /* Create a new bfd section from an ELF program header.
 
    Since program segments have no names, we generate a synthetic name
@@ -3018,6 +3079,10 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
 {
   const struct elf_backend_data *bed;
 
+  /* Handle memory tag p_type's first.  */
+  if (is_memory_tag_p_type (hdr->p_type))
+    return _bfd_elf_make_memtag_section_from_phdr (abfd, hdr);
+
   switch (hdr->p_type)
     {
     case PT_NULL:
@@ -5896,6 +5961,23 @@ assign_file_positions_for_load_sections (bfd *abfd,
 		p->p_filesz += adjust;
 	    }
 
+	  /* For memory tag sections, the content size is smaller than the
+	     size of the memory range.  Adjust the file size and memory
+	     size accordingly.  */
+	  if (is_memory_tag_p_type (p->p_type)
+	      && bfd_get_format (abfd) == bfd_core)
+	    {
+	      if (m->count > 0)
+		{
+		  /* The storage size of tags in the section is usually much
+		     smaller than the memory range size of the memory the tags
+		     cover, so we need to adjust the file size and memory size
+		     fields.  */
+		  asection *memtag_section = m->sections[0];
+		  p->p_memsz = memtag_section->memory_tags_range_size;
+		}
+	    }
+
 	  if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
 	    {
 	      /* The section at i == 0 is the one that actually contains
diff --git a/bfd/section.c b/bfd/section.c
index 9a1071454f5..e8c7caf9dd4 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -412,6 +412,9 @@ CODE_FRAGMENT
 .  {* Nonzero if this section uses RELA relocations, rather than REL.  *}
 .  unsigned int use_rela_p:1;
 .
+.  {* Nonzero if this section contains memory tag data.  Default is 0.  *}
+.  unsigned int has_memory_tags : 1;
+.
 .  {* Bits used by various backends.  The generic code doesn't touch
 .     these fields.  *}
 .
@@ -455,6 +458,11 @@ CODE_FRAGMENT
 .  {* The compressed size of the section in octets.  *}
 .  bfd_size_type compressed_size;
 .
+.  {* If HAS_MEMORY_TAGS is true, MEMORY_TAGS_RANGE_SIZE is the original memory
+.     range size, in octets, of the memory that contained the tags stored in this
+.     section.  SIZE is the size of the packed tags from that memory range.  *}
+.  bfd_size_type memory_tags_range_size;
+.
 .  {* Relaxation table. *}
 .  struct relax_table *relax;
 .
@@ -715,14 +723,17 @@ CODE_FRAGMENT
 .  {* linker_mark, linker_has_input, gc_mark, decompress_status,     *}	\
 .     0,           0,                1,       0,			\
 .									\
-.  {* segment_mark, sec_info_type, use_rela_p,                       *}	\
-.     0,            0,             0,					\
+.  {* segment_mark, sec_info_type, use_rela_p, has_memory_tags,      *}	\
+.     0,            0,             0,	       0,			\
 .									\
 .  {* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5,    *}	\
 .     0,        0,        0,        0,        0,        0,		\
 .									\
-.  {* vma, lma, size, rawsize, compressed_size, relax, relax_count,  *}	\
-.     0,   0,   0,    0,       0,               0,     0,		\
+.  {* vma, lma, size, rawsize, compressed_size,			     *} \
+.     0,   0,   0,    0,       0,					\
+.									\
+.  {* memory_tags_range_size, relax, relax_count,		     *} \
+.     0,		      0,     0,					\
 .									\
 .  {* output_offset, output_section, alignment_power,                *}	\
 .     0,             &SEC,           0,					\
@@ -1499,7 +1510,8 @@ bfd_set_section_contents (bfd *abfd,
 {
   bfd_size_type sz;
 
-  if (!(bfd_section_flags (section) & SEC_HAS_CONTENTS))
+  if (!section->has_memory_tags
+      && !(bfd_section_flags (section) & SEC_HAS_CONTENTS))
     {
       bfd_set_error (bfd_error_no_contents);
       return false;
@@ -1588,7 +1600,7 @@ bfd_get_section_contents (bfd *abfd,
     /* Don't bother.  */
     return true;
 
-  if ((section->flags & SEC_HAS_CONTENTS) == 0)
+  if (!section->has_memory_tags && (section->flags & SEC_HAS_CONTENTS) == 0)
     {
       memset (location, 0, (size_t) count);
       return true;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index a2dbaa4722e..ae1399c0577 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -4499,6 +4499,7 @@ get_aarch64_segment_type (unsigned long type)
   switch (type)
     {
     case PT_AARCH64_ARCHEXT:  return "AARCH64_ARCHEXT";
+    case PT_ARM_MEMTAG_MTE:   return "ARM_MEMTAG_MTE";
     default:                  return NULL;
     }
 }
diff --git a/include/elf/common.h b/include/elf/common.h
index 70d63e3299c..5a682e3bde7 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -500,6 +500,11 @@
 #define PT_GNU_MBIND_LO (PT_LOOS + 0x474e555)
 #define PT_GNU_MBIND_HI (PT_GNU_MBIND_LO + PT_GNU_MBIND_NUM - 1)
 
+/* ARM memory tag segment types.  */
+
+/* MTE memory tag segment type.  */
+#define PT_ARM_MEMTAG_MTE     (PT_LOPROC + 0x1)
+
 /* Program segment permissions, in program header p_flags field.  */
 
 #define PF_X		(1 << 0)	/* Segment is executable */
-- 
2.25.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-07-19 14:27 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-31 14:04 Support AArch64 MTE memory tag dumps in core files Luis Machado
2022-04-01  1:34 ` Alan Modra
2022-04-01  8:21   ` Luis Machado
2022-04-03 12:04   ` Move microblaze relax info to target specific data Alan Modra
2022-04-21 15:18 ` [PATCH, v2] [AArch64] Support AArch64 MTE memory tag dumps in core files Luis Machado
2022-04-23  0:15   ` Alan Modra
2022-04-23 21:50     ` Fangrui Song
2022-05-03 11:23     ` Luis Machado
2022-05-03 11:33 ` [PATCH] " Luis Machado
2022-05-11 15:13   ` Luis Machado
2022-05-12  0:18     ` Alan Modra
2022-06-02  3:26       ` Fangrui Song
     [not found]       ` <DS7PR12MB57657DCC1DA5A6A4ABD7F813CBDE9@DS7PR12MB5765.namprd12.prod.outlook.com>
2022-06-06  7:05         ` Luis Machado
2022-07-19 14:27           ` Luis Machado

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).