aboutsummaryrefslogtreecommitdiff
path: root/gdb/memtag.c
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@arm.com>2022-03-31 11:42:35 +0100
committerLuis Machado <luis.machado@arm.com>2022-07-19 15:24:31 +0100
commit68cffbbd4406b4efe1aa6e18460b1d7ca02549f1 (patch)
treef8a61526011db5bf0c60314f38de6fc48cd82ca0 /gdb/memtag.c
parentd0ff5ca959df91dcef16ec57154ff199fad5a4e4 (diff)
downloadgdb-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.zip
gdb-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.tar.gz
gdb-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.tar.bz2
[AArch64] MTE corefile support
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)
Diffstat (limited to 'gdb/memtag.c')
-rw-r--r--gdb/memtag.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/gdb/memtag.c b/gdb/memtag.c
new file mode 100644
index 0000000..ca64569
--- /dev/null
+++ b/gdb/memtag.c
@@ -0,0 +1,68 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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 or empty tag dump should not happen. Warn about
+ it but keep going through the sections. */
+ if (memtag_range_size == 0 || tags_size == 0)
+ {
+ warning (_("Found memtag section with empty memory "
+ "range or empty tag dump"));
+ continue;
+ }
+ else
+ {
+ 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;
+}