summaryrefslogtreecommitdiff
path: root/gdb/corelow.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/corelow.c
parentd0ff5ca959df91dcef16ec57154ff199fad5a4e4 (diff)
downloadbinutils-gdb-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.tar.gz
[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/corelow.c')
-rw-r--r--gdb/corelow.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 2037ef3dc89..293bc8d4f59 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 @@ public:
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. */
@@ -1177,6 +1185,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. */