[PATCH,v5][AArch64] MTE corefile support
Luis Machado
luis.machado@linaro.org
Thu Jun 24 14:37:13 GMT 2021
On 6/24/21 11:00 AM, Alan Hayward wrote:
>
>
>> On 1 Jun 2021, at 18:45, Luis Machado <luis.machado@linaro.org> wrote:
>>
>> Updates on v5:
>>
>> - Fixed format warning output.
>>
>> Updates on v4:
>>
>> - Calculate sizes based on individual struct field sizes.
>>
>> Updates on v3:
>>
>> - Addressed review comments.
>> - New files gdbsupport/memtag.h, gdb/memtag.h and gdb/memtag.c.
>> - Updated code documentation.
>> - Removed code duplication.
>>
>> Updates on v2:
>>
>> - Reworked core_target::fetch_memtags to handle cases where address + len runs
>> over the NT_MEMTAG note.
>> - Turned a few magic numbers into constants. There is an unfortunate duplication
>> of a constant (NT_MEMTAG_HEADER_SIZE). It is a generic constant, but there is
>> no file generic enough that gets included by both corelow and linux-tdep.
>> - More sanity checks to make sure the note format is correct.
>> - Documented aarch64_linux_decode_memtag_note a little more.
>>
>> ---
>>
>> Teach GDB how to dump memory tags when using the gcore command and how
>> to read them back from a core file generated via gcore or the kernel.
>>
>> Each tagged memory range (listed in /proc/<pid>/smaps) gets dumped to its
>> own NT_MEMTAG note. A section named ".memtag" is created for each of those
>> when reading the core file back.
>>
>> Dumping memory tags
>> -
>>
>> When using the gcore command to dump a core file, GDB will go through the maps
>> in /proc/<pid>/smaps looking for tagged ranges. Each of those entries gets
>> passed to an arch-specific gdbarch hook that generates a vector of blobs of
>> memory tag data that are blindly put into a NT_MEMTAG note.
>>
>> The vector is used because we may have, in the future, multiple tag types for
>> a particular memory range.
>>
>> Each of the NT_MEMTAG notes have a generic header and a arch-specific header,
>> like so:
>>
>> struct tag_dump_header
>> {
>> uint16_t format; // Only NT_MEMTAG_TYPE_AARCH_MTE at present
>> uint64_t start_vma;
>> uint64_t end_vma;
>> };
>>
>> struct tag_dump_mte
>> {
>> uint16_t granule_byte_size;
>> uint16_t tag_bit_size;
>> uint16_t __unused;
>> };
>>
>> The only bits meant to be generic are the tag_dump_format, start_vma and
>> end_vma fields.
>>
>> The format-specific data is supposed to be opaque and only useful for the
>> arch-specific code.
>>
>> We can extend the format in the future to make room for other memory tag
>> layouts.
>>
>> Reading memory tags
>> -
>>
>> When reading a core file that contains NT_MEMTAG entries, GDB will use
>> a different approach to check for tagged memory range. Rather than looking
>> at /proc/<pid>/smaps, it will now look for ".memtag" sections with the right
>> memory range.
>>
>> When reading tags, GDB will now use the core target's implementation of
>> fetch_memtags (store_memtags doesn't exist for core targets). Then the data
>> is fed into an arch-specific hook that will decode the memory tag format and
>> return a vector of tags.
>>
>> I've added a test to exercise writing and reading of memory tags in core
>> files.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
>>
>> * Makefile.in (COMMON_SFILES): Add memtag.c.
>> * NEWS: Mention core file support for memory tagging.
>> * aarch64-linux-tdep.c: Include elf/common.h.
>> Include gdbsupport/memtag.h.
>> (MAX_TAGS_TO_TRANSFER): New constant.
>> (aarch64_linux_create_memtag_notes_from_range): New function.
>> (aarch64_linux_decode_memtag_note): Likewise.
>> (aarch64_linux_init_abi): Register new core file hooks.
>> (NT_MEMTAG_TOTAL_HEADER_SIZE): New constant.
>> * arch/aarch64-mte-linux.h (tag_dump_mte): New struct.
>> (AARCH64_MTE_TAG_BIT_SIZE): New constant.
>> * corelow.c: Include gdbsupport/memtag.h and memtag.h.
>> (core_target) <supports_memory_tagging, fetch_memtags>: New
>> method overrides.
>> * gdbarch.c: Regenerate.
>> * gdbarch.h: Likewise.
>> * gdbarch.sh (create_memtag_notes_from_range): New hook.
>> (decode_memtag_note): Likewise.
>> * linux-tdep.c: Include gdbsupport/memtag.h and memtag.h.
>> (linux_address_in_memtag_page): Renamed to...
>> (linux_process_address_in_memtag_page): ... this.
>> (linux_core_file_address_in_memtag_page): New function.
>> (linux_address_in_memtag_page): Likewise.
>> (linux_make_memtag_corefile_notes): Likewise.
>> (linux_make_corefile_notes): Handle memory tag notes.
>> * memtag.c: New file.
>> * memtag.h: New file.
>>
>> gdb/doc/ChangeLog:
>>
>> YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
>>
>> * gdb.texinfo (AArch64 Memory Tagging Extension): Mention support
>> for memory tagging in core files.
>>
>> gdb/testsuite/ChangeLog:
>>
>> YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
>>
>> * gdb.arch/aarch64-mte-gcore.c: New file.
>> * gdb.arch/aarch64-mte-gcore.exp: New file.
>>
>> gdbsupport/ChangeLog:
>>
>> YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
>>
>> * memtag.h: New file.
>> ---
>> gdb/Makefile.in | 1 +
>> gdb/NEWS | 4 +
>> gdb/aarch64-linux-tdep.c | 221 +++++++++++++++++++
>> gdb/arch/aarch64-mte-linux.h | 17 ++
>> gdb/corelow.c | 63 ++++++
>> gdb/doc/gdb.texinfo | 4 +
>> gdb/gdbarch.c | 64 ++++++
>> gdb/gdbarch.h | 16 ++
>> gdb/gdbarch.sh | 6 +
>> gdb/linux-tdep.c | 97 +++++++-
>> gdb/memtag.c | 88 ++++++++
>> gdb/memtag.h | 46 ++++
>> gdb/testsuite/gdb.arch/aarch64-mte-gcore.c | 93 ++++++++
>> gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp | 111 ++++++++++
>> gdbsupport/memtag.h | 39 ++++
>> 15 files changed, 867 insertions(+), 3 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
>> create mode 100644 gdbsupport/memtag.h
>>
>
> Note there were a few minor merge conflicts, nothing to worry about though.
I'll check again and will refresh the patch.
>
>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index f664d964536..12fb3b390b1 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -1100,6 +1100,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 ab678acec8b..58b9f739d4f 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -3,6 +3,10 @@
>>
>> *** Changes since GDB 10
>>
>> +* 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.
>> +
>> * GDB now supports general memory tagging functionality if the underlying
>> architecture supports the proper primitives and hooks. Currently this is
>> enabled only for AArch64 MTE.
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index e9761ed2189..04498f3b6c0 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -52,6 +52,9 @@
>> #include "value.h"
>>
>> #include "gdbsupport/selftest.h"
>> +#include "gdbsupport/memtag.h"
>> +
>> +#include "elf/common.h"
>>
>> /* Signal frame handling.
>>
>> @@ -1779,6 +1782,213 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>> }
>> }
>>
>> +/* Memory tag note header size. Includes both the generic and the
>> + arch-specific parts. */
>> +#define NT_MEMTAG_TOTAL_HEADER_SIZE (NT_MEMTAG_GENERIC_HEADER_SIZE \
>> + + NT_MEMTAG_MTE_HEADER_SIZE)
>> +
>> +/* Maximum number of tags to request. */
>> +#define MAX_TAGS_TO_TRANSFER 1024
>> +
>> +/* AArch64 Linux implementation of the aarch64_create_memtag_notes_from_range
>> + gdbarch hook. Create core file notes for memory tags. */
>> +
>> +static std::vector<gdb::byte_vector>
>> +aarch64_linux_create_memtag_notes_from_range (struct gdbarch *gdbarch,
>> + CORE_ADDR start_address,
>> + CORE_ADDR end_address)
>> +{
>> + /* We only handle MTE tags for now. */
>> +
>> + /* Figure out how many tags we need to store in this memory range. */
>> + size_t granules = aarch64_mte_get_tag_granules (start_address,
>> + end_address - start_address,
>> + AARCH64_MTE_GRANULE_SIZE);
>> +
>> + /* Vector of memory tag notes. Add the MTE note (we only have MTE tags
>> + at the moment). */
>> + std::vector<gdb::byte_vector> notes (1);
>> +
>> + /* If there are no tag granules to fetch, just return. */
>> + if (granules == 0)
>> + return notes;
>> +
>> + /* Adjust the MTE note size to hold the header + tags. */
>> + notes[0].resize (NT_MEMTAG_TOTAL_HEADER_SIZE + granules);
>
> Should this be NT_MEMTAG_TOTAL_HEADER_SIZE + (granules * AARCH64_MTE_GRANULE_SIZE)
> Get_granules has already divided by the granule size.
>
We are storing 1 tag per byte. So the number of granules is the number
of tags. If we multiply by AARCH64_MTE_GRANULE_SIZE, we will have 16
times more tags.
>> +
>> + 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)));
>> + notes.resize (0);
>
> If you do the original resize after the while loop, then there would be no need to resize here.
>
I'm not sure I understand. Where do you suggest the resizing to be placed?
More information about the Gdb-patches
mailing list