From: Luis Machado <luis.machado@arm.com>
To: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>,
"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: Re: [PATCH, v4] [AArch64] MTE corefile support
Date: Mon, 6 Jun 2022 10:47:13 +0100 [thread overview]
Message-ID: <fd1bfc2a-7ba5-59df-867f-bb3960a90435@arm.com> (raw)
In-Reply-To: <04febcab961d9ae834ffdea960a7469a3a309b13.camel@mediatek.com>
On 6/6/22 10:42, Kuan-Ying Lee wrote:
> On Mon, 2022-06-06 at 17:28 +0800, Luis Machado via Gdb-patches wrote:
>> Ping?
>>
>
> Hi Luis,
>
> I don't see PT_AARCH64_MEMTAG_MTE in include/elf/common.h.
>
> I think we need to add below in include/elf/common.h.
Based on binutils@ feedback, this constant was moved to include/elf/aarch64.h, and is
part of the binutils patch.
>
> #define PT_AARCH64_MEMTAG_MTE (PT_LOPROC + 0x2)
>
> Or do I miss something?
>
> Best regards,
> Kuan-Ying Lee
>
>> On 5/3/22 22:56, Luis Machado via Gdb-patches wrote:
>>> v4:
>>>
>>> - Updated documentation (added cross-references).
>>> - Updated the segment name from PT_ARM_MEMTAG_MTE to
>>> PT_AARCH64_MEMTAG_MTE.
>>>
>>> v3:
>>>
>>> - Updated NEWS and documentation to be more thorough.
>>>
>>> v2:
>>>
>>> - Rework memory tag section handling to use generic section fields.
>>>
>>> --
>>>
>>> Teach GDB how to dump memory tags for AArch64 when using the gcore
>>> command
>>> and how to read memory tag data back from a core file generated by
>>> GDB
>>> (via gcore) or by the Linux kernel.
>>>
>>> The format is documented in the Linux Kernel documentation [1].
>>>
>>> Each tagged memory range (listed in /proc/<pid>/smaps) gets dumped
>>> to its
>>> own PT_AARCH64_MEMTAG_MTE segment. A section named ".memtag" is
>>> created for each
>>> of those segments when reading the core file back.
>>>
>>> To save a little bit of space, given MTE tags only take 4 bits, the
>>> memory tags
>>> are stored packed as 2 tags per byte.
>>>
>>> When reading the data back, the tags are unpacked.
>>>
>>> I've added a new testcase to exercise the feature.
>>>
>>> Build-tested with --enable-targets=all and regression tested on
>>> aarch64-linux
>>> Ubuntu 20.04.
>>>
>>> [1] Documentation/arm64/memory-tagging-extension.rst (Core Dump
>>> Support)
>>> ---
>>> gdb/Makefile.in | 1 +
>>> gdb/NEWS | 10 ++
>>> gdb/aarch64-linux-tdep.c | 167
>>> +++++++++++++++++++
>>> gdb/arch/aarch64-mte-linux.c | 56 +++++++
>>> gdb/arch/aarch64-mte-linux.h | 10 ++
>>> gdb/corelow.c | 62 +++++++
>>> gdb/defs.h | 3 +-
>>> gdb/doc/gdb.texinfo | 19 +++
>>> gdb/gcore.c | 83 ++++++++-
>>> gdb/gdbarch-components.py | 35 ++++
>>> gdb/gdbarch-gen.h | 26 +++
>>> gdb/gdbarch.c | 96 +++++++++++
>>> gdb/linux-tdep.c | 39 ++++-
>>> gdb/memtag.c | 61 +++++++
>>> gdb/memtag.h | 50 ++++++
>>> gdb/testsuite/gdb.arch/aarch64-mte-gcore.c | 93 +++++++++++
>>> gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp | 107 ++++++++++++
>>> 17 files changed, 910 insertions(+), 8 deletions(-)
>>> create mode 100644 gdb/memtag.c
>>> create mode 100644 gdb/memtag.h
>>> create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
>>> create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
>>>
>>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>>> index 418094775a5..fac9364bea4 100644
>>> --- a/gdb/Makefile.in
>>> +++ b/gdb/Makefile.in
>>> @@ -1120,6 +1120,7 @@ COMMON_SFILES = \
>>> memattr.c \
>>> memory-map.c \
>>> memrange.c \
>>> + memtag.c \
>>> minidebug.c \
>>> minsyms.c \
>>> mipsread.c \
>>> diff --git a/gdb/NEWS b/gdb/NEWS
>>> index 982f4a1a18c..3d925dc3663 100644
>>> --- a/gdb/NEWS
>>> +++ b/gdb/NEWS
>>> @@ -3,6 +3,16 @@
>>>
>>> *** Changes since GDB 12
>>>
>>> +* GDB now supports dumping memory tag data for AArch64 MTE. It
>>> also supports
>>> + reading memory tag data for AArch64 MTE from core files
>>> generated by
>>> + the gcore command or the Linux kernel.
>>> +
>>> + When a process uses memory-mapped pages protected by memory tags
>>> (for
>>> + example, AArch64 MTE), this additional information will be
>>> recorded in
>>> + the core file in the event of a crash or if GDB generates a core
>>> file
>>> + from the current process state. GDB will show this additional
>>> information
>>> + automatically, or through one of the memory-tag subcommands.
>>> +
>>> * GDB now supports hardware watchpoints on FreeBSD/Aarch64.
>>>
>>> * Remove support for building against Python 2, it is now only
>>> possible to
>>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>>> index 55094b3d88b..12d98e71796 100644
>>> --- a/gdb/aarch64-linux-tdep.c
>>> +++ b/gdb/aarch64-linux-tdep.c
>>> @@ -53,6 +53,9 @@
>>>
>>> #include "gdbsupport/selftest.h"
>>>
>>> +#include "elf/common.h"
>>> +#include "elf/aarch64.h"
>>> +
>>> /* Signal frame handling.
>>>
>>> +------------+ ^
>>> @@ -1781,6 +1784,155 @@ aarch64_linux_report_signal_info (struct
>>> gdbarch *gdbarch,
>>> }
>>> }
>>>
>>> +/* AArch64 Linux implementation of the
>>> gdbarch_create_memtag_section hook. */
>>> +
>>> +static asection *
>>> +aarch64_linux_create_memtag_section (struct gdbarch *gdbarch, bfd
>>> *obfd,
>>> + CORE_ADDR address, size_t size)
>>> +{
>>> + gdb_assert (obfd != nullptr);
>>> + gdb_assert (size > 0);
>>> +
>>> + /* Create the section and associated program header. */
>>> + asection *mte_section = bfd_make_section_anyway (obfd,
>>> "memtag");
>>> +
>>> + if (mte_section == nullptr)
>>> + return nullptr;
>>> +
>>> + bfd_set_section_vma (mte_section, address);
>>> + /* The size of the memory range covered by the memory tags. We
>>> reuse the
>>> + section's rawsize field for this purpose. */
>>> + mte_section->rawsize = size;
>>> + /* Tags are stored packed as 2 tags per byte. */
>>> + bfd_set_section_size (mte_section, (size /
>>> AARCH64_MTE_GRANULE_SIZE) / 2);
>>> + /* Make sure the section's flags has SEC_HAS_CONTENTS, otherwise
>>> BFD will
>>> + refuse to write data to this section. */
>>> + bfd_set_section_flags (mte_section, SEC_HAS_CONTENTS);
>>> +
>>> + /* Store program header information. */
>>> + bfd_record_phdr (obfd, PT_AARCH64_MEMTAG_MTE, 1, 0, 0, 0, 0, 0,
>>> 1,
>>> + &mte_section);
>>> +
>>> + return mte_section;
>>> +}
>>> +
>>> +/* Maximum number of tags to request. */
>>> +#define MAX_TAGS_TO_TRANSFER 1024
>>> +
>>> +/* AArch64 Linux implementation of the gdbarch_fill_memtag_section
>>> hook. */
>>> +
>>> +static bool
>>> +aarch64_linux_fill_memtag_section (struct gdbarch *gdbarch,
>>> asection *osec)
>>> +{
>>> + /* We only handle MTE tags for now. */
>>> +
>>> + size_t segment_size = osec->rawsize;
>>> + CORE_ADDR start_address = bfd_section_vma (osec);
>>> + CORE_ADDR end_address = start_address + segment_size;
>>> +
>>> + /* Figure out how many tags we need to store in this memory
>>> range. */
>>> + size_t granules = aarch64_mte_get_tag_granules (start_address,
>>> segment_size,
>>> + AARCH64_MTE_GRANULE_S
>>> IZE);
>>> +
>>> + /* If there are no tag granules to fetch, just return. */
>>> + if (granules == 0)
>>> + return true;
>>> +
>>> + CORE_ADDR address = start_address;
>>> +
>>> + /* Vector of tags. */
>>> + gdb::byte_vector tags;
>>> +
>>> + while (granules > 0)
>>> + {
>>> + /* Transfer tags in chunks. */
>>> + gdb::byte_vector tags_read;
>>> + size_t xfer_len
>>> + = (granules >= MAX_TAGS_TO_TRANSFER)?
>>> + MAX_TAGS_TO_TRANSFER * AARCH64_MTE_GRANULE_SIZE :
>>> + granules * AARCH64_MTE_GRANULE_SIZE;
>>> +
>>> + if (!target_fetch_memtags (address, xfer_len, tags_read,
>>> + static_cast<int>
>>> (memtag_type::allocation)))
>>> + {
>>> + warning (_("Failed to read MTE tags from memory range
>>> [%s,%s)."),
>>> + phex_nz (start_address, sizeof (start_address)),
>>> + phex_nz (end_address, sizeof (end_address)));
>>> + return false;
>>> + }
>>> +
>>> + /* Transfer over the tags that have been read. */
>>> + tags.insert (tags.end (), tags_read.begin (), tags_read.end
>>> ());
>>> +
>>> + /* Adjust the remaining granules and starting address. */
>>> + granules -= tags_read.size ();
>>> + address += tags_read.size () * AARCH64_MTE_GRANULE_SIZE;
>>> + }
>>> +
>>> + /* Pack the MTE tag bits. */
>>> + aarch64_mte_pack_tags (tags);
>>> +
>>> + if (!bfd_set_section_contents (osec->owner, osec, tags.data (),
>>> + 0, tags.size ()))
>>> + {
>>> + warning (_("Failed to write %s bytes of corefile memory "
>>> + "tag content (%s)."),
>>> + pulongest (tags.size ()),
>>> + bfd_errmsg (bfd_get_error ()));
>>> + }
>>> + return true;
>>> +}
>>> +
>>> +/* AArch64 Linux implementation of the
>>> gdbarch_decode_memtag_section
>>> + hook. Decode a memory tag section and return the requested
>>> tags.
>>> +
>>> + The section is guaranteed to cover the [ADDRESS, ADDRESS +
>>> length)
>>> + range. */
>>> +
>>> +static gdb::byte_vector
>>> +aarch64_linux_decode_memtag_section (struct gdbarch *gdbarch,
>>> + bfd_section *section,
>>> + int type,
>>> + CORE_ADDR address, size_t length)
>>> +{
>>> + gdb_assert (section != nullptr);
>>> +
>>> + /* The requested address must not be less than section->vma. */
>>> + gdb_assert (section->vma <= address);
>>> +
>>> + /* Figure out how many tags we need to fetch in this memory
>>> range. */
>>> + size_t granules = aarch64_mte_get_tag_granules (address, length,
>>> + AARCH64_MTE_GRANULE_S
>>> IZE);
>>> + /* Sanity check. */
>>> + gdb_assert (granules > 0);
>>> +
>>> + /* Fetch the total number of tags in the range [VMA, address +
>>> length). */
>>> + size_t granules_from_vma
>>> + = aarch64_mte_get_tag_granules (section->vma,
>>> + address - section->vma + length,
>>> + AARCH64_MTE_GRANULE_SIZE);
>>> +
>>> + /* Adjust the tags vector to contain the exact number of packed
>>> bytes. */
>>> + gdb::byte_vector tags (((granules - 1) >> 1) + 1);
>>> +
>>> + /* Figure out the starting offset into the packed tags data. */
>>> + file_ptr offset = ((granules_from_vma - granules) >> 1);
>>> +
>>> + if (!bfd_get_section_contents (section->owner, section,
>>> tags.data (),
>>> + offset, tags.size ()))
>>> + error (_("Couldn't read contents from memtag section."));
>>> +
>>> + /* At this point, the tags are packed 2 per byte. Unpack them
>>> before
>>> + returning. */
>>> + bool skip_first = ((granules_from_vma - granules) % 2) != 0;
>>> + aarch64_mte_unpack_tags (tags, skip_first);
>>> +
>>> + /* Resize to the exact number of tags that was requested. */
>>> + tags.resize (granules);
>>> +
>>> + return tags;
>>> +}
>>> +
>>> static void
>>> aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch
>>> *gdbarch)
>>> {
>>> @@ -1864,6 +2016,21 @@ aarch64_linux_init_abi (struct gdbarch_info
>>> info, struct gdbarch *gdbarch)
>>>
>>> set_gdbarch_report_signal_info (gdbarch,
>>> aarch64_linux_report_signal_info)
>>> ;
>>> +
>>> + /* Core file helpers. */
>>> +
>>> + /* Core file helper to create a memory tag section for a
>>> particular
>>> + PT_LOAD segment. */
>>> + set_gdbarch_create_memtag_section
>>> + (gdbarch, aarch64_linux_create_memtag_section);
>>> +
>>> + /* Core file helper to fill a memory tag section with tag
>>> data. */
>>> + set_gdbarch_fill_memtag_section
>>> + (gdbarch, aarch64_linux_fill_memtag_section);
>>> +
>>> + /* Core file helper to decode a memory tag section. */
>>> + set_gdbarch_decode_memtag_section (gdbarch,
>>> + aarch64_linux_decode_memtag_se
>>> ction);
>>> }
>>>
>>> /* Initialize the aarch64_linux_record_tdep. */
>>> diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-
>>> linux.c
>>> index fc7a8cc00f7..3af6f364e91 100644
>>> --- a/gdb/arch/aarch64-mte-linux.c
>>> +++ b/gdb/arch/aarch64-mte-linux.c
>>> @@ -21,6 +21,62 @@
>>>
>>> /* See arch/aarch64-mte-linux.h */
>>>
>>> +void
>>> +aarch64_mte_pack_tags (gdb::byte_vector &tags)
>>> +{
>>> + /* Nothing to pack? */
>>> + if (tags.empty ())
>>> + return;
>>> +
>>> + /* If the tags vector has an odd number of elements, add another
>>> + zeroed-out element to make it even. This facilitates
>>> packing. */
>>> + if ((tags.size () % 2) != 0)
>>> + tags.emplace_back (0);
>>> +
>>> + for (int unpacked = 0, packed = 0; unpacked < tags.size ();
>>> + unpacked += 2, packed++)
>>> + tags[packed] = (tags[unpacked + 1] << 4) | tags[unpacked];
>>> +
>>> + /* Now we have half the size. */
>>> + tags.resize (tags.size () / 2);
>>> +}
>>> +
>>> +/* See arch/aarch64-mte-linux.h */
>>> +
>>> +void
>>> +aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first)
>>> +{
>>> + /* Nothing to unpack? */
>>> + if (tags.empty ())
>>> + return;
>>> +
>>> + /* An unpacked MTE tags vector will have twice the number of
>>> elements
>>> + compared to an unpacked one. */
>>> + gdb::byte_vector unpacked_tags (tags.size () * 2);
>>> +
>>> + int unpacked = 0, packed = 0;
>>> +
>>> + if (skip_first)
>>> + {
>>> + /* We are not interested in the first unpacked element, just
>>> discard
>>> + it. */
>>> + unpacked_tags[unpacked] = (tags[packed] >> 4) & 0xf;
>>> + unpacked++;
>>> + packed++;
>>> + }
>>> +
>>> + for (; packed < tags.size (); unpacked += 2, packed++)
>>> + {
>>> + unpacked_tags[unpacked] = tags[packed] & 0xf;
>>> + unpacked_tags[unpacked + 1] = (tags[packed] >> 4) & 0xf;
>>> + }
>>> +
>>> + /* Update the original tags vector. */
>>> + tags = std::move (unpacked_tags);
>>> +}
>>> +
>>> +/* See arch/aarch64-mte-linux.h */
>>> +
>>> size_t
>>> aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t
>>> granule_size)
>>> {
>>> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-
>>> linux.h
>>> index d158926feff..8a145b447aa 100644
>>> --- a/gdb/arch/aarch64-mte-linux.h
>>> +++ b/gdb/arch/aarch64-mte-linux.h
>>> @@ -32,6 +32,7 @@
>>>
>>> /* We have one tag per 16 bytes of memory. */
>>> #define AARCH64_MTE_GRANULE_SIZE 16
>>> +#define AARCH64_MTE_TAG_BIT_SIZE 4
>>> #define AARCH64_MTE_LOGICAL_TAG_START_BIT 56
>>> #define AARCH64_MTE_LOGICAL_MAX_VALUE 0xf
>>>
>>> @@ -71,4 +72,13 @@ extern CORE_ADDR aarch64_mte_set_ltag (CORE_ADDR
>>> address, CORE_ADDR tag);
>>> It is always possible to get the logical tag. */
>>> extern CORE_ADDR aarch64_mte_get_ltag (CORE_ADDR address);
>>>
>>> +/* Given a TAGS vector containing 1 MTE tag per byte, pack the
>>> data as
>>> + 2 tags per byte and resize the vector. */
>>> +void aarch64_mte_pack_tags (gdb::byte_vector &tags);
>>> +
>>> +/* Given a TAGS vector containing 2 MTE tags per byte, unpack the
>>> data as
>>> + 1 tag per byte and resize the vector. If SKIP_FIRST is TRUE,
>>> skip the
>>> + first unpacked element. Otherwise leave it in the unpacked
>>> vector. */
>>> +void aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool
>>> skip_first);
>>> +
>>> #endif /* ARCH_AARCH64_LINUX_H */
>>> diff --git a/gdb/corelow.c b/gdb/corelow.c
>>> index 8c33fb7ebb2..8b8994f80db 100644
>>> --- a/gdb/corelow.c
>>> +++ b/gdb/corelow.c
>>> @@ -52,6 +52,7 @@
>>> #include <unordered_set>
>>> #include "gdbcmd.h"
>>> #include "xml-tdesc.h"
>>> +#include "memtag.h"
>>>
>>> #ifndef O_LARGEFILE
>>> #define O_LARGEFILE 0
>>> @@ -101,6 +102,13 @@ class core_target final : public
>>> process_stratum_target
>>>
>>> bool info_proc (const char *, enum info_proc_what) override;
>>>
>>> + bool supports_memory_tagging () override;
>>> +
>>> + /* Core file implementation of fetch_memtags. Fetch the memory
>>> tags from
>>> + core file notes. */
>>> + bool fetch_memtags (CORE_ADDR address, size_t len,
>>> + gdb::byte_vector &tags, int type) override;
>>> +
>>> /* A few helpers. */
>>>
>>> /* Getter, see variable definition. */
>>> @@ -1162,6 +1170,60 @@ core_target::info_proc (const char *args,
>>> enum info_proc_what request)
>>> return true;
>>> }
>>>
>>> +/* Implementation of the "supports_memory_tagging" target_ops
>>> method. */
>>> +
>>> +bool
>>> +core_target::supports_memory_tagging ()
>>> +{
>>> + /* Look for memory tag sections. If they exist, that means this
>>> core file
>>> + supports memory tagging. */
>>> +
>>> + return (bfd_get_section_by_name (core_bfd, "memtag") !=
>>> nullptr);
>>> +}
>>> +
>>> +/* Implementation of the "fetch_memtags" target_ops method. */
>>> +
>>> +bool
>>> +core_target::fetch_memtags (CORE_ADDR address, size_t len,
>>> + gdb::byte_vector &tags, int type)
>>> +{
>>> + struct gdbarch *gdbarch = target_gdbarch ();
>>> +
>>> + /* Make sure we have a way to decode the memory tag notes. */
>>> + if (!gdbarch_decode_memtag_section_p (gdbarch))
>>> + error (_("gdbarch_decode_memtag_section not implemented for
>>> this "
>>> + "architecture."));
>>> +
>>> + memtag_section_info info;
>>> + info.memtag_section = nullptr;
>>> +
>>> + while (get_next_core_memtag_section (core_bfd,
>>> info.memtag_section,
>>> + address, info))
>>> + {
>>> + size_t adjusted_length
>>> + = (address + len < info.end_address)? len :
>>> (info.end_address - address);
>>> +
>>> + /* Decode the memory tag note and return the tags. */
>>> + gdb::byte_vector tags_read
>>> + = gdbarch_decode_memtag_section (gdbarch,
>>> info.memtag_section, type,
>>> + address, adjusted_length);
>>> +
>>> + /* Transfer over the tags that have been read. */
>>> + tags.insert (tags.end (), tags_read.begin (), tags_read.end
>>> ());
>>> +
>>> + /* ADDRESS + LEN may cross the boundaries of a particular
>>> memory tag
>>> + segment. Check if we need to fetch tags from a different
>>> section. */
>>> + if (!tags_read.empty () && (address + len) < info.end_address)
>>> + return true;
>>> +
>>> + /* There are more tags to fetch. Update ADDRESS and LEN. */
>>> + len -= (info.end_address - address);
>>> + address = info.end_address;
>>> + }
>>> +
>>> + return false;
>>> +}
>>> +
>>> /* Get a pointer to the current core target. If not connected to
>>> a
>>> core target, return NULL. */
>>>
>>> diff --git a/gdb/defs.h b/gdb/defs.h
>>> index 99bfdd526ff..51a7576a56a 100644
>>> --- a/gdb/defs.h
>>> +++ b/gdb/defs.h
>>> @@ -344,7 +344,8 @@ extern const char *pc_prefix (CORE_ADDR);
>>>
>>> typedef int (*find_memory_region_ftype) (CORE_ADDR addr, unsigned
>>> long size,
>>> int read, int write, int exec,
>>> - int modified, void *data);
>>> + int modified, bool
>>> memory_tagged,
>>> + void *data);
>>>
>>> /* * Possible lvalue types. Like enum language, this should be
>>> in
>>> value.h, but needs to be here for the same reason. */
>>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>>> index 38ad2ac32b0..36f10f20cfb 100644
>>> --- a/gdb/doc/gdb.texinfo
>>> +++ b/gdb/doc/gdb.texinfo
>>> @@ -25555,6 +25555,25 @@ options that can be controlled at runtime
>>> and emulates the @code{prctl}
>>> option @code{PR_SET_TAGGED_ADDR_CTRL}. For further information,
>>> see the
>>> documentation in the Linux kernel.
>>>
>>> +@value{GDBN} supports dumping memory tag data to core files
>>> through the
>>> +@command{gcore} command and reading memory tag data from core
>>> files generated
>>> +by the @command{gcore} command or the Linux kernel.
>>> +
>>> +When a process uses memory-mapped pages protected by memory tags
>>> (for
>>> +example, AArch64 MTE), this additional information will be
>>> recorded in
>>> +the core file in the event of a crash or if @value{GDBN} generates
>>> a core file
>>> +from the current process state.
>>> +
>>> +The memory tag data will be used so developers can display the
>>> memory
>>> +tags from a particular memory region (using the @samp{m} modifier
>>> to the
>>> +@command{x} command, using the @command{print} command or using
>>> the various
>>> +@command{memory-tag} subcommands.
>>> +
>>> +In the case of a crash, @value{GDBN} will attempt to retrieve the
>>> memory tag
>>> +information automatically from the core file, and will show one of
>>> the above
>>> +messages depending on whether the synchronous or asynchronous mode
>>> is selected.
>>> +@xref{Memory Tagging}. @xref{Memory}.
>>> +
>>> @node i386
>>> @subsection x86 Architecture-specific Issues
>>>
>>> diff --git a/gdb/gcore.c b/gdb/gcore.c
>>> index fdb22b72a07..b81ef81ab84 100644
>>> --- a/gdb/gcore.c
>>> +++ b/gdb/gcore.c
>>> @@ -349,6 +349,12 @@ make_output_phdrs (bfd *obfd, asection *osec)
>>> int p_flags = 0;
>>> int p_type = 0;
>>>
>>> + /* Memory tag segments have already been handled by the
>>> architecture, as
>>> + those contain arch-specific information. If we have one of
>>> those, just
>>> + return. */
>>> + if (startswith (bfd_section_name (osec), "memtag"))
>>> + return;
>>> +
>>> /* FIXME: these constants may only be applicable for ELF. */
>>> if (startswith (bfd_section_name (osec), "load"))
>>> p_type = PT_LOAD;
>>> @@ -371,7 +377,8 @@ make_output_phdrs (bfd *obfd, asection *osec)
>>>
>>> static int
>>> gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int
>>> read,
>>> - int write, int exec, int modified, void *data)
>>> + int write, int exec, int modified, bool
>>> memory_tagged,
>>> + void *data)
>>> {
>>> bfd *obfd = (bfd *) data;
>>> asection *osec;
>>> @@ -454,6 +461,45 @@ gcore_create_callback (CORE_ADDR vaddr,
>>> unsigned long size, int read,
>>> return 0;
>>> }
>>>
>>> +/* gdbarch_find_memory_region callback for creating a memory tag
>>> section.
>>> + DATA is 'bfd *' for the core file GDB is creating. */
>>> +
>>> +static int
>>> +gcore_create_memtag_section_callback (CORE_ADDR vaddr, unsigned
>>> long size,
>>> + int read, int write, int exec,
>>> + int modified, bool memory_tagged,
>>> + void *data)
>>> +{
>>> + /* Are there memory tags in this particular memory map
>>> entry? */
>>> + if (!memory_tagged)
>>> + return 0;
>>> +
>>> + bfd *obfd = (bfd *) data;
>>> +
>>> + /* Ask the architecture to create a memory tag section for this
>>> particular
>>> + memory map entry. It will be populated with contents later,
>>> as we can't
>>> + start writing the contents before we have all the sections
>>> sorted out. */
>>> + asection *memtag_section
>>> + = gdbarch_create_memtag_section (target_gdbarch (), obfd,
>>> vaddr, size);
>>> +
>>> + if (memtag_section == nullptr)
>>> + {
>>> + warning (_("Couldn't make gcore memory tag segment: %s"),
>>> + bfd_errmsg (bfd_get_error ()));
>>> + return 1;
>>> + }
>>> +
>>> + if (info_verbose)
>>> + {
>>> + gdb_printf (gdb_stdout, "Saved memory tag segment, %s bytes
>>> "
>>> + "at %s\n",
>>> + plongest (bfd_section_size (memtag_section)),
>>> + paddress (target_gdbarch (), vaddr));
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> int
>>> objfile_find_memory_regions (struct target_ops *self,
>>> find_memory_region_ftype func, void *obfd)
>>> @@ -483,6 +529,7 @@ objfile_find_memory_regions (struct target_ops
>>> *self,
>>> (flags & SEC_READONLY) == 0, /*
>>> Writable. */
>>> (flags & SEC_CODE) != 0, /* Executable. */
>>> 1, /* MODIFIED is unknown, pass it as
>>> true. */
>>> + false, /* No memory tags in the object
>>> file. */
>>> obfd);
>>> if (ret != 0)
>>> return ret;
>>> @@ -496,6 +543,7 @@ objfile_find_memory_regions (struct target_ops
>>> *self,
>>> 1, /* Stack section will be writable. */
>>> 0, /* Stack section will not be executable. */
>>> 1, /* Stack section will be modified. */
>>> + false, /* No memory tags in the object file. */
>>> obfd);
>>>
>>> /* Make a heap segment. */
>>> @@ -506,6 +554,7 @@ objfile_find_memory_regions (struct target_ops
>>> *self,
>>> 1, /* Heap section will be writable. */
>>> 0, /* Heap section will not be executable. */
>>> 1, /* Heap section will be modified. */
>>> + false, /* No memory tags in the object file. */
>>> obfd);
>>>
>>> return 0;
>>> @@ -555,6 +604,20 @@ gcore_copy_callback (bfd *obfd, asection
>>> *osec)
>>> }
>>> }
>>>
>>> +/* Callback to copy contents to a particular memory tag
>>> section. */
>>> +
>>> +static void
>>> +gcore_copy_memtag_section_callback (bfd *obfd, asection *osec)
>>> +{
>>> + /* We are only interested in "memtag" sections. */
>>> + if (!startswith (bfd_section_name (osec), "memtag"))
>>> + return;
>>> +
>>> + /* Fill the section with memory tag contents. */
>>> + if (!gdbarch_fill_memtag_section (target_gdbarch (), osec))
>>> + error (_("Failed to fill memory tag section for core file."));
>>> +}
>>> +
>>> static int
>>> gcore_memory_sections (bfd *obfd)
>>> {
>>> @@ -567,13 +630,27 @@ gcore_memory_sections (bfd *obfd)
>>> return 0; /* FIXME: error return/msg? */
>>> }
>>>
>>> + /* Take care of dumping memory tags, if there are any. */
>>> + if (!gdbarch_find_memory_regions_p (target_gdbarch ())
>>> + || gdbarch_find_memory_regions (target_gdbarch (),
>>> + gcore_create_memtag_section_callb
>>> ack,
>>> + obfd) != 0)
>>> + {
>>> + if (target_find_memory_regions
>>> (gcore_create_memtag_section_callback,
>>> + obfd) != 0)
>>> + return 0;
>>> + }
>>> +
>>> /* Record phdrs for section-to-segment mapping. */
>>> for (asection *sect : gdb_bfd_sections (obfd))
>>> make_output_phdrs (obfd, sect);
>>>
>>> - /* Copy memory region contents. */
>>> + /* Copy memory region and memory tag contents. */
>>> for (asection *sect : gdb_bfd_sections (obfd))
>>> - gcore_copy_callback (obfd, sect);
>>> + {
>>> + gcore_copy_callback (obfd, sect);
>>> + gcore_copy_memtag_section_callback (obfd, sect);
>>> + }
>>>
>>> return 1;
>>> }
>>> diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py
>>> index e8f20c83ff0..6fa1b7591db 100644
>>> --- a/gdb/gdbarch-components.py
>>> +++ b/gdb/gdbarch-components.py
>>> @@ -1522,6 +1522,41 @@ Find core file memory regions
>>> invalid=True,
>>> )
>>>
>>> +Method(
>>> + comment="""
>>> +Given a bfd OBFD, segment ADDRESS and SIZE, create a memory tag
>>> section to be dumped to a core file
>>> +""",
>>> + type="asection *",
>>> + name="create_memtag_section",
>>> + params=[("bfd *", "obfd"), ("CORE_ADDR", "address"),
>>> ("size_t", "size")],
>>> + predicate=True,
>>> + invalid=True,
>>> +)
>>> +
>>> +Method(
>>> + comment="""
>>> +Given a memory tag section OSEC, fill OSEC's contents with the
>>> appropriate tag data
>>> +""",
>>> + type="bool",
>>> + name="fill_memtag_section",
>>> + params=[("asection *", "osec")],
>>> + predicate=True,
>>> + invalid=True,
>>> +)
>>> +
>>> +Method(
>>> + comment="""
>>> +Decode a memory tag SECTION and return the tags of type TYPE
>>> contained in
>>> +the memory range [ADDRESS, ADDRESS + LENGTH).
>>> +If no tags were found, return an empty vector.
>>> +""",
>>> + type="gdb::byte_vector",
>>> + name="decode_memtag_section",
>>> + params=[("bfd_section *", "section"), ("int", "type"),
>>> ("CORE_ADDR", "address"), ("size_t", "length")],
>>> + predicate=True,
>>> + invalid=True,
>>> +)
>>> +
>>> Method(
>>> comment="""
>>> Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared
>>> libraries list from
>>> diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
>>> index 882b9057b1a..1d19f51f21d 100644
>>> --- a/gdb/gdbarch-gen.h
>>> +++ b/gdb/gdbarch-gen.h
>>> @@ -874,6 +874,32 @@ typedef int
>>> (gdbarch_find_memory_regions_ftype) (struct gdbarch *gdbarch,
>>> find_m
>>> extern int gdbarch_find_memory_regions (struct gdbarch *gdbarch,
>>> find_memory_region_ftype func, void *data);
>>> extern void set_gdbarch_find_memory_regions (struct gdbarch
>>> *gdbarch, gdbarch_find_memory_regions_ftype *find_memory_regions);
>>>
>>> +/* Given a bfd OBFD, segment ADDRESS and SIZE, create a memory tag
>>> section to be dumped to a core file */
>>> +
>>> +extern bool gdbarch_create_memtag_section_p (struct gdbarch
>>> *gdbarch);
>>> +
>>> +typedef asection * (gdbarch_create_memtag_section_ftype) (struct
>>> gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size);
>>> +extern asection * gdbarch_create_memtag_section (struct gdbarch
>>> *gdbarch, bfd *obfd, CORE_ADDR address, size_t size);
>>> +extern void set_gdbarch_create_memtag_section (struct gdbarch
>>> *gdbarch, gdbarch_create_memtag_section_ftype
>>> *create_memtag_section);
>>> +
>>> +/* Given a memory tag section OSEC, fill OSEC's contents with the
>>> appropriate tag data */
>>> +
>>> +extern bool gdbarch_fill_memtag_section_p (struct gdbarch
>>> *gdbarch);
>>> +
>>> +typedef bool (gdbarch_fill_memtag_section_ftype) (struct gdbarch
>>> *gdbarch, asection *osec);
>>> +extern bool gdbarch_fill_memtag_section (struct gdbarch *gdbarch,
>>> asection *osec);
>>> +extern void set_gdbarch_fill_memtag_section (struct gdbarch
>>> *gdbarch, gdbarch_fill_memtag_section_ftype *fill_memtag_section);
>>> +
>>> +/* Decode a memory tag SECTION and return the tags of type TYPE
>>> contained in
>>> + the memory range [ADDRESS, ADDRESS + LENGTH).
>>> + If no tags were found, return an empty vector. */
>>> +
>>> +extern bool gdbarch_decode_memtag_section_p (struct gdbarch
>>> *gdbarch);
>>> +
>>> +typedef gdb::byte_vector (gdbarch_decode_memtag_section_ftype)
>>> (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR
>>> address, size_t length);
>>> +extern gdb::byte_vector gdbarch_decode_memtag_section (struct
>>> gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR
>>> address, size_t length);
>>> +extern void set_gdbarch_decode_memtag_section (struct gdbarch
>>> *gdbarch, gdbarch_decode_memtag_section_ftype
>>> *decode_memtag_section);
>>> +
>>> /* Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared
>>> libraries list from
>>> core file into buffer READBUF with length LEN. Return the
>>> number of bytes read
>>> (zero indicates failure).
>>> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
>>> index a588bdef61a..f5dbacb14e7 100644
>>> --- a/gdb/gdbarch.c
>>> +++ b/gdb/gdbarch.c
>>> @@ -171,6 +171,9 @@ struct gdbarch
>>> gdbarch_iterate_over_regset_sections_ftype
>>> *iterate_over_regset_sections;
>>> gdbarch_make_corefile_notes_ftype *make_corefile_notes;
>>> gdbarch_find_memory_regions_ftype *find_memory_regions;
>>> + gdbarch_create_memtag_section_ftype *create_memtag_section;
>>> + gdbarch_fill_memtag_section_ftype *fill_memtag_section;
>>> + gdbarch_decode_memtag_section_ftype *decode_memtag_section;
>>> gdbarch_core_xfer_shared_libraries_ftype
>>> *core_xfer_shared_libraries;
>>> gdbarch_core_xfer_shared_libraries_aix_ftype
>>> *core_xfer_shared_libraries_aix;
>>> gdbarch_core_pid_to_str_ftype *core_pid_to_str;
>>> @@ -527,6 +530,9 @@ verify_gdbarch (struct gdbarch *gdbarch)
>>> /* Skip verify of iterate_over_regset_sections, has
>>> predicate. */
>>> /* Skip verify of make_corefile_notes, has predicate. */
>>> /* Skip verify of find_memory_regions, has predicate. */
>>> + /* Skip verify of create_memtag_section, has predicate. */
>>> + /* Skip verify of fill_memtag_section, has predicate. */
>>> + /* Skip verify of decode_memtag_section, has predicate. */
>>> /* Skip verify of core_xfer_shared_libraries, has
>>> predicate. */
>>> /* Skip verify of core_xfer_shared_libraries_aix, has
>>> predicate. */
>>> /* Skip verify of core_pid_to_str, has predicate. */
>>> @@ -1096,6 +1102,24 @@ gdbarch_dump (struct gdbarch *gdbarch,
>>> struct ui_file *file)
>>> gdb_printf (file,
>>> "gdbarch_dump: find_memory_regions =
>>> <%s>\n",
>>> host_address_to_string (gdbarch-
>>>> find_memory_regions));
>>> + gdb_printf (file,
>>> + "gdbarch_dump:
>>> gdbarch_create_memtag_section_p() = %d\n",
>>> + gdbarch_create_memtag_section_p (gdbarch));
>>> + gdb_printf (file,
>>> + "gdbarch_dump: create_memtag_section =
>>> <%s>\n",
>>> + host_address_to_string (gdbarch-
>>>> create_memtag_section));
>>> + gdb_printf (file,
>>> + "gdbarch_dump:
>>> gdbarch_fill_memtag_section_p() = %d\n",
>>> + gdbarch_fill_memtag_section_p (gdbarch));
>>> + gdb_printf (file,
>>> + "gdbarch_dump: fill_memtag_section =
>>> <%s>\n",
>>> + host_address_to_string (gdbarch-
>>>> fill_memtag_section));
>>> + gdb_printf (file,
>>> + "gdbarch_dump:
>>> gdbarch_decode_memtag_section_p() = %d\n",
>>> + gdbarch_decode_memtag_section_p (gdbarch));
>>> + gdb_printf (file,
>>> + "gdbarch_dump: decode_memtag_section =
>>> <%s>\n",
>>> + host_address_to_string (gdbarch-
>>>> decode_memtag_section));
>>> gdb_printf (file,
>>> "gdbarch_dump:
>>> gdbarch_core_xfer_shared_libraries_p() = %d\n",
>>> gdbarch_core_xfer_shared_libraries_p
>>> (gdbarch));
>>> @@ -3744,6 +3768,78 @@ set_gdbarch_find_memory_regions (struct
>>> gdbarch *gdbarch,
>>> gdbarch->find_memory_regions = find_memory_regions;
>>> }
>>>
>>> +bool
>>> +gdbarch_create_memtag_section_p (struct gdbarch *gdbarch)
>>> +{
>>> + gdb_assert (gdbarch != NULL);
>>> + return gdbarch->create_memtag_section != NULL;
>>> +}
>>> +
>>> +asection *
>>> +gdbarch_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd,
>>> CORE_ADDR address, size_t size)
>>> +{
>>> + gdb_assert (gdbarch != NULL);
>>> + gdb_assert (gdbarch->create_memtag_section != NULL);
>>> + if (gdbarch_debug >= 2)
>>> + gdb_printf (gdb_stdlog, "gdbarch_create_memtag_section
>>> called\n");
>>> + return gdbarch->create_memtag_section (gdbarch, obfd, address,
>>> size);
>>> +}
>>> +
>>> +void
>>> +set_gdbarch_create_memtag_section (struct gdbarch *gdbarch,
>>> + gdbarch_create_memtag_section_f
>>> type create_memtag_section)
>>> +{
>>> + gdbarch->create_memtag_section = create_memtag_section;
>>> +}
>>> +
>>> +bool
>>> +gdbarch_fill_memtag_section_p (struct gdbarch *gdbarch)
>>> +{
>>> + gdb_assert (gdbarch != NULL);
>>> + return gdbarch->fill_memtag_section != NULL;
>>> +}
>>> +
>>> +bool
>>> +gdbarch_fill_memtag_section (struct gdbarch *gdbarch, asection
>>> *osec)
>>> +{
>>> + gdb_assert (gdbarch != NULL);
>>> + gdb_assert (gdbarch->fill_memtag_section != NULL);
>>> + if (gdbarch_debug >= 2)
>>> + gdb_printf (gdb_stdlog, "gdbarch_fill_memtag_section
>>> called\n");
>>> + return gdbarch->fill_memtag_section (gdbarch, osec);
>>> +}
>>> +
>>> +void
>>> +set_gdbarch_fill_memtag_section (struct gdbarch *gdbarch,
>>> + gdbarch_fill_memtag_section_ftype
>>> fill_memtag_section)
>>> +{
>>> + gdbarch->fill_memtag_section = fill_memtag_section;
>>> +}
>>> +
>>> +bool
>>> +gdbarch_decode_memtag_section_p (struct gdbarch *gdbarch)
>>> +{
>>> + gdb_assert (gdbarch != NULL);
>>> + return gdbarch->decode_memtag_section != NULL;
>>> +}
>>> +
>>> +gdb::byte_vector
>>> +gdbarch_decode_memtag_section (struct gdbarch *gdbarch,
>>> bfd_section *section, int type, CORE_ADDR address, size_t length)
>>> +{
>>> + gdb_assert (gdbarch != NULL);
>>> + gdb_assert (gdbarch->decode_memtag_section != NULL);
>>> + if (gdbarch_debug >= 2)
>>> + gdb_printf (gdb_stdlog, "gdbarch_decode_memtag_section
>>> called\n");
>>> + return gdbarch->decode_memtag_section (gdbarch, section, type,
>>> address, length);
>>> +}
>>> +
>>> +void
>>> +set_gdbarch_decode_memtag_section (struct gdbarch *gdbarch,
>>> + gdbarch_decode_memtag_section_f
>>> type decode_memtag_section)
>>> +{
>>> + gdbarch->decode_memtag_section = decode_memtag_section;
>>> +}
>>> +
>>> bool
>>> gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch)
>>> {
>>> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
>>> index 4e728a06e7e..8a83ed320cf 100644
>>> --- a/gdb/linux-tdep.c
>>> +++ b/gdb/linux-tdep.c
>>> @@ -42,6 +42,7 @@
>>> #include "gcore.h"
>>> #include "gcore-elf.h"
>>> #include "solib-svr4.h"
>>> +#include "memtag.h"
>>>
>>> #include <ctype.h>
>>> #include <unordered_map>
>>> @@ -1320,6 +1321,7 @@ typedef int linux_find_memory_region_ftype
>>> (ULONGEST vaddr, ULONGEST size,
>>> ULONGEST offset, ULONGEST
>>> inode,
>>> int read, int write,
>>> int exec, int modified,
>>> + bool memory_tagged,
>>> const char *filename,
>>> void *data);
>>>
>>> @@ -1470,10 +1472,11 @@ parse_smaps_data (const char *data,
>>> return smaps;
>>> }
>>>
>>> -/* See linux-tdep.h. */
>>> +/* Helper that checks if an address is in a memory tag page for a
>>> live
>>> + process. */
>>>
>>> -bool
>>> -linux_address_in_memtag_page (CORE_ADDR address)
>>> +static bool
>>> +linux_process_address_in_memtag_page (CORE_ADDR address)
>>> {
>>> if (current_inferior ()->fake_pid_p)
>>> return false;
>>> @@ -1505,6 +1508,30 @@ linux_address_in_memtag_page (CORE_ADDR
>>> address)
>>> return false;
>>> }
>>>
>>> +/* Helper that checks if an address is in a memory tag page for a
>>> core file
>>> + process. */
>>> +
>>> +static bool
>>> +linux_core_file_address_in_memtag_page (CORE_ADDR address)
>>> +{
>>> + if (core_bfd == nullptr)
>>> + return false;
>>> +
>>> + memtag_section_info info;
>>> + return get_next_core_memtag_section (core_bfd, nullptr, address,
>>> info);
>>> +}
>>> +
>>> +/* See linux-tdep.h. */
>>> +
>>> +bool
>>> +linux_address_in_memtag_page (CORE_ADDR address)
>>> +{
>>> + if (!target_has_execution ())
>>> + return linux_core_file_address_in_memtag_page (address);
>>> +
>>> + return linux_process_address_in_memtag_page (address);
>>> +}
>>> +
>>> /* List memory regions in the inferior for a corefile. */
>>>
>>> static int
>>> @@ -1593,6 +1620,7 @@ linux_find_memory_regions_full (struct
>>> gdbarch *gdbarch,
>>> map.offset, map.inode, map.read, map.write, map.exec,
>>> 1, /* MODIFIED is true because we want to dump
>>> the mapping. */
>>> + map.vmflags.memory_tagging != 0,
>>> map.filename.c_str (), obfd);
>>> }
>>> }
>>> @@ -1621,12 +1649,14 @@ static int
>>> linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
>>> ULONGEST offset, ULONGEST inode,
>>> int read, int write, int exec, int
>>> modified,
>>> + bool memory_tagged,
>>> const char *filename, void *arg)
>>> {
>>> struct linux_find_memory_regions_data *data
>>> = (struct linux_find_memory_regions_data *) arg;
>>>
>>> - return data->func (vaddr, size, read, write, exec, modified,
>>> data->obfd);
>>> + return data->func (vaddr, size, read, write, exec, modified,
>>> memory_tagged,
>>> + data->obfd);
>>> }
>>>
>>> /* A variant of linux_find_memory_regions_full that is suitable
>>> as the
>>> @@ -1675,6 +1705,7 @@ static int
>>> linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
>>> ULONGEST offset, ULONGEST inode,
>>> int read, int write, int exec, int
>>> modified,
>>> + bool memory_tagged,
>>> const char *filename, void *data)
>>> {
>>> struct linux_make_mappings_data *map_data
>>> diff --git a/gdb/memtag.c b/gdb/memtag.c
>>> new file mode 100644
>>> index 00000000000..af86137c49d
>>> --- /dev/null
>>> +++ b/gdb/memtag.c
>>> @@ -0,0 +1,61 @@
>>> +/* GDB generic memory tagging functions.
>>> +
>>> + Copyright (C) 2022 Free Software Foundation, Inc.
>>> +
>>> + This file is part of GDB.
>>> +
>>> + This program is free software; you can redistribute it and/or
>>> modify
>>> + it under the terms of the GNU General Public License as
>>> published by
>>> + the Free Software Foundation; either version 3 of the License,
>>> or
>>> + (at your option) any later version.
>>> +
>>> + This program is distributed in the hope that it will be useful,
>>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + GNU General Public License for more details.
>>> +
>>> + You should have received a copy of the GNU General Public
>>> License
>>> + along with this program. If not, see <
>>> https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$
>>> >. */
>>> +
>>> +#include "defs.h"
>>> +#include "memtag.h"
>>> +#include "bfd.h"
>>> +
>>> +/* See memtag.h */
>>> +
>>> +bool
>>> +get_next_core_memtag_section (bfd *abfd, asection *section,
>>> + CORE_ADDR address, memtag_section_info
>>> &info)
>>> +{
>>> + /* If the caller provided no SECTION to start from, search from
>>> the
>>> + beginning. */
>>> + if (section == nullptr)
>>> + section = bfd_get_section_by_name (abfd, "memtag");
>>> +
>>> + /* Go through all the memtag sections and figure out if ADDRESS
>>> + falls within one of the memory ranges that contain tags. */
>>> + while (section != nullptr)
>>> + {
>>> + size_t memtag_range_size = section->rawsize;
>>> + size_t tags_size = bfd_section_size (section);
>>> +
>>> + /* Empty memory range and empty tag dump should not
>>> happen. */
>>> + gdb_assert (memtag_range_size != 0);
>>> + gdb_assert (tags_size != 0);
>>> +
>>> + CORE_ADDR start_address = bfd_section_vma (section);
>>> + CORE_ADDR end_address = start_address + memtag_range_size;
>>> +
>>> + /* Is the address within [start_address, end_address)? */
>>> + if (address >= start_address
>>> + && address < end_address)
>>> + {
>>> + info.start_address = start_address;
>>> + info.end_address = end_address;
>>> + info.memtag_section = section;
>>> + return true;
>>> + }
>>> + section = bfd_get_next_section_by_name (abfd, section);
>>> + }
>>> + return false;
>>> +}
>>> diff --git a/gdb/memtag.h b/gdb/memtag.h
>>> new file mode 100644
>>> index 00000000000..fe908c1e5e3
>>> --- /dev/null
>>> +++ b/gdb/memtag.h
>>> @@ -0,0 +1,50 @@
>>> +/* GDB generic memory tagging definitions.
>>> + Copyright (C) 2022 Free Software Foundation, Inc.
>>> +
>>> + This file is part of GDB.
>>> +
>>> + This program is free software; you can redistribute it and/or
>>> modify
>>> + it under the terms of the GNU General Public License as
>>> published by
>>> + the Free Software Foundation; either version 3 of the License,
>>> or
>>> + (at your option) any later version.
>>> +
>>> + This program is distributed in the hope that it will be useful,
>>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + GNU General Public License for more details.
>>> +
>>> + You should have received a copy of the GNU General Public
>>> License
>>> + along with this program. If not, see <
>>> https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$
>>> >. */
>>> +
>>> +#ifndef MEMTAG_H
>>> +#define MEMTAG_H
>>> +
>>> +#include "bfd.h"
>>> +
>>> +struct memtag_section_info
>>> +{
>>> + /* The start address of the tagged memory range. */
>>> + CORE_ADDR start_address;
>>> + /* The final address of the tagged memory range. */
>>> + CORE_ADDR end_address;
>>> + /* The section containing tags for the memory range
>>> + [start_address, end_address). */
>>> + asection *memtag_section;
>>> +};
>>> +
>>> +/* Helper function to walk through memory tag sections in a core
>>> file.
>>> +
>>> + Return TRUE if there is a "memtag" section containing
>>> ADDRESS. Return FALSE
>>> + otherwise.
>>> +
>>> + If SECTION is provided, search from that section onwards. If
>>> SECTION is
>>> + nullptr, then start a new search.
>>> +
>>> + If a "memtag" section containing ADDRESS is found, fill INFO
>>> with data
>>> + about such section. Otherwise leave it unchanged. */
>>> +
>>> +bool get_next_core_memtag_section (bfd *abfd, asection *section,
>>> + CORE_ADDR address,
>>> + memtag_section_info &info);
>>> +
>>> +#endif /* MEMTAG_H */
>>> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
>>> b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
>>> new file mode 100644
>>> index 00000000000..b20ebcff424
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
>>> @@ -0,0 +1,93 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> + Copyright 2021 Free Software Foundation, Inc.
>>> +
>>> + This program is free software; you can redistribute it and/or
>>> modify
>>> + it under the terms of the GNU General Public License as
>>> published by
>>> + the Free Software Foundation; either version 3 of the License,
>>> or
>>> + (at your option) any later version.
>>> +
>>> + This program is distributed in the hope that it will be useful,
>>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + GNU General Public License for more details.
>>> +
>>> + You should have received a copy of the GNU General Public
>>> License
>>> + along with this program. If not, see <
>>> https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$
>>> >. */
>>> +
>>> +/* Exercise AArch64's Memory Tagging Extension with tagged
>>> pointers. */
>>> +
>>> +/* This test was based on the documentation for the AArch64 Memory
>>> Tagging
>>> + Extension from the Linux Kernel, found in the sources in
>>> + Documentation/arm64/memory-tagging-extension.rst. */
>>> +
>>> +#include <errno.h>
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <unistd.h>
>>> +#include <sys/auxv.h>
>>> +#include <sys/mman.h>
>>> +#include <sys/prctl.h>
>>> +
>>> +/* From arch/arm64/include/uapi/asm/hwcap.h */
>>> +#define HWCAP2_MTE (1 << 18)
>>> +
>>> +/* From arch/arm64/include/uapi/asm/mman.h */
>>> +#define PROT_MTE 0x20
>>> +
>>> +/* From include/uapi/linux/prctl.h */
>>> +#define PR_SET_TAGGED_ADDR_CTRL 55
>>> +#define PR_GET_TAGGED_ADDR_CTRL 56
>>> +#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
>>> +#define PR_MTE_TCF_SHIFT 1
>>> +#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
>>> +#define PR_MTE_TAG_SHIFT 3
>>> +
>>> +void
>>> +access_memory (unsigned char *tagged_ptr)
>>> +{
>>> + tagged_ptr[0] = 'a';
>>> +}
>>> +
>>> +int
>>> +main (int argc, char **argv)
>>> +{
>>> + unsigned char *tagged_ptr;
>>> + unsigned long page_sz = sysconf (_SC_PAGESIZE);
>>> + unsigned long hwcap2 = getauxval(AT_HWCAP2);
>>> +
>>> + /* Bail out if MTE is not supported. */
>>> + if (!(hwcap2 & HWCAP2_MTE))
>>> + return 1;
>>> +
>>> + /* Enable the tagged address ABI, synchronous MTE tag check
>>> faults and
>>> + allow all non-zero tags in the randomly generated set. */
>>> + if (prctl (PR_SET_TAGGED_ADDR_CTRL,
>>> + PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
>>> + | (0xfffe << PR_MTE_TAG_SHIFT),
>>> + 0, 0, 0))
>>> + {
>>> + perror ("prctl () failed");
>>> + return 1;
>>> + }
>>> +
>>> + /* Create a mapping that will have PROT_MTE set. */
>>> + tagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
>>> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
>>> + if (tagged_ptr == MAP_FAILED)
>>> + {
>>> + perror ("mmap () failed");
>>> + return 1;
>>> + }
>>> +
>>> + /* Enable MTE on the above anonymous mmap. */
>>> + if (mprotect (tagged_ptr, page_sz, PROT_READ | PROT_WRITE |
>>> PROT_MTE))
>>> + {
>>> + perror ("mprotect () failed");
>>> + return 1;
>>> + }
>>> +
>>> + access_memory (tagged_ptr);
>>> +
>>> + return 0;
>>> +}
>>> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
>>> b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
>>> new file mode 100644
>>> index 00000000000..8a19c4b449e
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
>>> @@ -0,0 +1,107 @@
>>> +# Copyright (C) 2018-2021 Free Software Foundation, Inc.
>>> +#
>>> +# This program is free software; you can redistribute it and/or
>>> modify
>>> +# it under the terms of the GNU General Public License as
>>> published by
>>> +# the Free Software Foundation; either version 3 of the License,
>>> or
>>> +# (at your option) any later version.
>>> +#
>>> +# This program is distributed in the hope that it will be useful,
>>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> +# GNU General Public License for more details.
>>> +#
>>> +# You should have received a copy of the GNU General Public
>>> License
>>> +# along with this program. If not, see <
>>> https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$
>>> >.
>>> +
>>> +# This file is part of the gdb testsuite.
>>> +
>>> +# Test generating and reading a core file with MTE memory tags.
>>> +
>>> +if {![is_aarch64_target]} {
>>> + verbose "Skipping ${gdb_test_file_name}."
>>> + return
>>> +}
>>> +
>>> +standard_testfile
>>> +if { [prepare_for_testing "failed to prepare" ${testfile}
>>> ${srcfile}] } {
>>> + return -1
>>> +}
>>> +
>>> +if ![runto_main] {
>>> + untested "could not run to main"
>>> + return -1
>>> +}
>>> +
>>> +# Targets that don't support memory tagging should not execute the
>>> +# runtime memory tagging tests.
>>> +if {![supports_memtag]} {
>>> + unsupported "memory tagging unsupported"
>>> + return -1
>>> +}
>>> +
>>> +gdb_breakpoint "access_memory"
>>> +
>>> +if [gdb_continue "access_memory"] {
>>> + return -1
>>> +}
>>> +
>>> +# Set each tag granule to a different tag value, from 0x0 to 0xf.
>>> +set atag_msg "Allocation tag\\(s\\) updated successfully\."
>>> +for {set i 15} {$i >= 0} {incr i -1} {
>>> + set index [expr [expr 15 - $i] * 16]
>>> + set tag [format "%02x" $i]
>>> + gdb_test "memory-tag set-allocation-tag &tagged_ptr\[$index\]
>>> 1 $tag" \
>>> + $atag_msg \
>>> + "set memory tag of &tagged_ptr\[$index\] to $tag"
>>> +}
>>> +
>>> +# Run until a crash and confirm GDB displays memory tag violation
>>> +# information.
>>> +gdb_test "continue" \
>>> + [multi_line \
>>> + "Program received signal SIGSEGV, Segmentation fault" \
>>> + "Memory tag violation while accessing address $hex" \
>>> + "Allocation tag $hex" \
>>> + "Logical tag $hex\." \
>>> + "$hex in access_memory \\(.*\\) at .*" \
>>> + ".*tagged_ptr\\\[0\\\] = 'a';"] \
>>> + "display tag violation information for live process"
>>> +
>>> +# Generate the core file.
>>> +set core_filename [standard_output_file "$testfile.core"]
>>> +set core_generated [gdb_gcore_cmd "$core_filename" "generate core
>>> file"]
>>> +
>>> +if { !$core_generated } {
>>> + return -1
>>> +}
>>> +
>>> +clean_restart $binfile
>>> +
>>> +# Load the core file and make sure we see the tag violation fault
>>> +# information.
>>> +gdb_test "core $core_filename" \
>>> + [multi_line \
>>> + "Core was generated by.*\." \
>>> + "Program terminated with signal SIGSEGV, Segmentation fault" \
>>> + "Memory tag violation while accessing address $hex" \
>>> + "Allocation tag 0xf" \
>>> + "Logical tag 0x0\." \
>>> + "#0.*$hex in access_memory \\(.*\\) at .*" \
>>> + ".*tagged_ptr\\\[0\\\] = 'a';"] \
>>> + "core file shows tag violation information"
>>> +
>>> +# Make sure we have the tag_ctl register.
>>> +gdb_test "info register tag_ctl" \
>>> + "tag_ctl.*$hex.*${::decimal}" \
>>> + "tag_ctl is available"
>>> +
>>> +# Check if the tag granules have the expected values. If they do,
>>> that
>>> +# means the core file saved the tags properly and GDB has read
>>> them
>>> +# correctly.
>>> +for {set i 15} {$i >= 0} {incr i -1} {
>>> + set index [expr [expr 15 - $i] * 16]
>>> + set tag [format "%x" $i]
>>> + gdb_test "memory-tag print-allocation-tag
>>> &tagged_ptr\[$index\]" \
>>> + "= 0x$tag" \
>>> + "memory tag of &tagged_ptr\[$index\] is correct"
>>> +}
>
next prev parent reply other threads:[~2022-06-06 9:47 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-31 14:03 Luis Machado
2022-04-21 15:20 ` [PATCH, v2] " Luis Machado
2022-04-21 15:52 ` Eli Zaretskii
2022-04-22 8:12 ` Luis Machado
2022-04-22 8:30 ` Eli Zaretskii
2022-04-22 8:37 ` Luis Machado
2022-04-22 8:43 ` Eli Zaretskii
2022-04-22 8:44 ` Luis Machado
2022-04-22 13:27 ` [PATCH 1/2] " Luis Machado
2022-04-22 13:33 ` Eli Zaretskii
2022-04-22 13:30 ` [PATCH, v3] " Luis Machado
2022-05-03 21:56 ` [PATCH, v4] " Luis Machado
2022-05-12 10:36 ` Luis Machado
2022-05-18 12:46 ` Luis Machado
2022-05-18 13:58 ` John Baldwin
2022-05-23 9:50 ` Luis Machado
2022-05-23 9:49 ` Luis Machado
2022-06-06 9:28 ` Luis Machado
2022-06-06 9:42 ` Kuan-Ying Lee
2022-06-06 9:47 ` Luis Machado [this message]
2022-06-06 9:54 ` Kuan-Ying Lee
2022-06-06 10:49 ` Eli Zaretskii
2022-06-22 9:04 ` Luis Machado
2022-06-27 14:51 ` Pedro Alves
2022-07-11 10:13 ` Luis Machado
2022-07-11 10:57 ` [PATCH] [AArch64,v5] " Luis Machado
2022-07-18 13:54 ` Pedro Alves
2022-07-19 14:25 ` Luis Machado
-- strict thread matches above, loose matches on Subject: below --
2021-05-18 20:20 [PATCH] [AArch64] " Luis Machado
2021-05-31 16:44 ` [PATCH,v4][AArch64] " Luis Machado
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fd1bfc2a-7ba5-59df-867f-bb3960a90435@arm.com \
--to=luis.machado@arm.com \
--cc=Kuan-Ying.Lee@mediatek.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).