From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id MMDQOSPlkV9pSAAAWB0awg (envelope-from ) for ; Thu, 22 Oct 2020 16:01:39 -0400 Received: by simark.ca (Postfix, from userid 112) id EAB8D1E89B; Thu, 22 Oct 2020 16:01:39 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 7A1BD1E552 for ; Thu, 22 Oct 2020 16:01:38 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 25A0239874C4; Thu, 22 Oct 2020 20:01:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 25A0239874C4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603396898; bh=ptPv9zERW4hpU1QMhTx5xYQ48g+d64LPnOZLsNR5278=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=k95+NVokx4SPJabTmQg8wGQrcF8xaLIWNB5+qCNfIuimU4hFU0CwJPM6cWomXZY9x LEuREpqrBCh+ab10lY0c6+oaz6B/pOkk5y8Ret/45F0SVFBX/RLlVx/j4qOsg717Wg n726DjmZFuBSVWrw9uPM5Wvs9tTB/N/QsE0DCW2s= Received: from mail-qt1-x841.google.com (mail-qt1-x841.google.com [IPv6:2607:f8b0:4864:20::841]) by sourceware.org (Postfix) with ESMTPS id F22013987477 for ; Thu, 22 Oct 2020 20:01:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org F22013987477 Received: by mail-qt1-x841.google.com with SMTP id c15so2262581qtc.2 for ; Thu, 22 Oct 2020 13:01:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ptPv9zERW4hpU1QMhTx5xYQ48g+d64LPnOZLsNR5278=; b=K1uWhBzt/r4l9RUTe7EpUOMjyLnDkrlwYCJe5wiaFAxe+mbHBa87rwqC6SGxfeqA+X NzG7ptTfObECUsbtU2osLBkR/Z8Y67ReJd6/+MIX+oxBK2Sq7GALFyH2mgFLhR9XRRND iox/p4spSPefW8psKDS7xVO5D772arbJ52GywbHF0ntcPYy5Qk12FvWx5Zwf6ElanDYs /VNIjiboIdDsNnIFhIb61MYuK9wvrvnMnvOWfC8qr7JiOeiGSZQCQfqltnT28o2UOhd1 1X6qc317BHgTvvNCR8XzqYBQ7deLAJz6ZYJB0q9OtWtI7tPvdpk6+IZ6/k66jr783Co5 0d+A== X-Gm-Message-State: AOAM5311tNzh36vWkxWfHjkDC96vSzS4zAxK3UCD77PmJOeAypIwbpBV ztONYRm+ZejNg4IqeFHpJwMmQFd4qjCuxQ== X-Google-Smtp-Source: ABdhPJzfNlAE8cSKU71lsOH7uh5W+458sAjBjOouKkpglpopBbroYMIWZ3dy5Y8AAufDsXrCJKTAtA== X-Received: by 2002:aed:3804:: with SMTP id j4mr3908537qte.232.1603396893817; Thu, 22 Oct 2020 13:01:33 -0700 (PDT) Received: from localhost.localdomain ([2804:7f0:8284:1487:b9b1:f72a:8f1:600]) by smtp.gmail.com with ESMTPSA id a21sm1711208qkk.98.2020.10.22.13.01.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 22 Oct 2020 13:01:33 -0700 (PDT) To: gdb-patches@sourceware.org Subject: [PATCH v2 12/24] AArch64: Implement memory tagging target methods for AArch64 Date: Thu, 22 Oct 2020 17:00:02 -0300 Message-Id: <20201022200014.5189-13-luis.machado@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201022200014.5189-1-luis.machado@linaro.org> References: <20201022200014.5189-1-luis.machado@linaro.org> X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Luis Machado via Gdb-patches Reply-To: Luis Machado Cc: david.spickett@linaro.org Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" Updates on v2: - Added type parameter to the target method implementations. -- The patch implements the memory tagging target hooks for AArch64, so we can handle MTE. gdb/ChangeLog: YYYY-MM-DD Luis Machado * Makefile.in (ALL_64_TARGET_OBS): Add arch/aarch64-mte-linux.o. (HFILES_NO_SRCDIR): Add arch/aarch64-mte-linux.h and nat/aarch64-mte-linux-ptrace.h. * aarch64-linux-nat.c: Include nat/aarch64-mte-linux-ptrace.h. (aarch64_linux_nat_target) : New method override. : New method override. : New method override. (aarch64_linux_nat_target::supports_memory_tagging): New method. (aarch64_linux_nat_target::fetch_memtags): New method. (aarch64_linux_nat_target::store_memtags): New method. * arch/aarch64-mte-linux.c: New file. * arch/aarch64-mte-linux.h: Include gdbsupport/common-defs.h. (MTE_GRANULE_SIZE): Define. (get_tag_granules): New prototype. * configure.nat (NATDEPFILES): Add nat/aarch64-mte-linux-ptrace.o. * configure.tgt (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o. * nat/aarch64-mte-linux-ptrace.c: New file. * nat/aarch64-mte-linux-ptrace.h: New file. --- gdb/Makefile.in | 1 + gdb/aarch64-linux-nat.c | 50 ++++++++ gdb/arch/aarch64-mte-linux.c | 34 +++++ gdb/arch/aarch64-mte-linux.h | 10 ++ gdb/configure.nat | 3 +- gdb/configure.tgt | 1 + gdb/nat/aarch64-mte-linux-ptrace.c | 200 +++++++++++++++++++++++++++++ gdb/nat/aarch64-mte-linux-ptrace.h | 17 +++ 8 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 gdb/arch/aarch64-mte-linux.c create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8c9e6c9f6c..33a08a2288 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -692,6 +692,7 @@ ALL_64_TARGET_OBS = \ amd64-windows-tdep.o \ arch/aarch64.o \ arch/aarch64-insn.o \ + arch/aarch64-mte-linux.o \ arch/amd64.o \ ia64-linux-tdep.o \ ia64-tdep.o \ diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index dea34da669..4edf5a0454 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -52,6 +52,8 @@ #include "arch/aarch64-mte-linux.h" +#include "nat/aarch64-mte-linux-ptrace.h" + #ifndef TRAP_HWBKPT #define TRAP_HWBKPT 0x0004 #endif @@ -102,6 +104,16 @@ class aarch64_linux_nat_target final : public linux_nat_target override; struct gdbarch *thread_architecture (ptid_t) override; + + bool supports_memory_tagging () override; + + /* Read memory allocation tags from memory via PTRACE. */ + int fetch_memtags (CORE_ADDR address, size_t len, + gdb::byte_vector &tags, int type) override; + + /* Write allocation tags to memory via PTRACE. */ + int store_memtags (CORE_ADDR address, size_t len, + const gdb::byte_vector &tags, int type) override; }; static aarch64_linux_nat_target the_aarch64_linux_nat_target; @@ -1050,6 +1062,44 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid) return gdbarch_find_by_info (info); } +/* Implement the "supports_memory_tagging" target_ops method. */ + +bool +aarch64_linux_nat_target::supports_memory_tagging () +{ + return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0; +} + +/* Implement the "fetch_memtags" target_ops method. */ + +int +aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len, + gdb::byte_vector &tags, int type) +{ + int tid = inferior_ptid.lwp (); + + /* Allocation tags? */ + if (type == 1) + return aarch64_mte_fetch_memtags (tid, address, len, tags); + + return 1; +} + +/* Implement the "store_memtags" target_ops method. */ + +int +aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len, + const gdb::byte_vector &tags, int type) +{ + int tid = inferior_ptid.lwp (); + + /* Allocation tags? */ + if (type == 1) + return aarch64_mte_store_memtags (tid, address, len, tags); + + return 1; +} + /* Define AArch64 maintenance commands. */ static void diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c new file mode 100644 index 0000000000..ee162aef19 --- /dev/null +++ b/gdb/arch/aarch64-mte-linux.c @@ -0,0 +1,34 @@ +/* Common Linux target-dependent functionality for AArch64 MTE + + Copyright (C) 2020 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 . */ + +#include "arch/aarch64-mte-linux.h" + +/* See arch/aarch64-mte-linux.h */ + +size_t +get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size) +{ + /* Start address */ + CORE_ADDR s_addr = align_down (addr, granule_size); + /* End address */ + CORE_ADDR e_addr = align_down (addr + len, granule_size); + + /* We always have at least 1 granule. */ + return 1 + (e_addr - s_addr) / granule_size; +} diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h index 4124e80543..e555f0af19 100644 --- a/gdb/arch/aarch64-mte-linux.h +++ b/gdb/arch/aarch64-mte-linux.h @@ -20,6 +20,8 @@ #ifndef ARCH_AARCH64_LINUX_H #define ARCH_AARCH64_LINUX_H +#include "gdbsupport/common-defs.h" + /* Feature check for Memory Tagging Extension. */ #ifndef HWCAP2_MTE #define HWCAP2_MTE (1 << 18) @@ -28,4 +30,12 @@ /* The MTE regset consists of a single 64-bit register. */ #define AARCH64_LINUX_SIZEOF_MTE 8 +/* We have one tag per 16 bytes of memory. */ +#define MTE_GRANULE_SIZE 16 + +/* Return the number of tag granules in the memory range + [ADDR, ADDR + LEN) given GRANULE_SIZE. */ +extern size_t get_tag_granules (CORE_ADDR addr, size_t len, + size_t granule_size); + #endif /* ARCH_AARCH64_LINUX_H */ diff --git a/gdb/configure.nat b/gdb/configure.nat index ef2218f0b8..f973cc7f9b 100644 --- a/gdb/configure.nat +++ b/gdb/configure.nat @@ -236,7 +236,8 @@ case ${gdb_host} in NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \ aarch32-linux-nat.o nat/aarch64-linux-hw-point.o \ nat/aarch64-linux.o \ - nat/aarch64-sve-linux-ptrace.o" + nat/aarch64-sve-linux-ptrace.o \ + nat/aarch64-mte-linux-ptrace.o" ;; arm) # Host: ARM based machine running GNU/Linux diff --git a/gdb/configure.tgt b/gdb/configure.tgt index d865ecdcb6..11a26b8551 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -124,6 +124,7 @@ aarch64*-*-freebsd*) aarch64*-*-linux*) # Target: AArch64 linux gdb_target_obs="aarch64-linux-tdep.o arch/aarch64.o\ + arch/aarch64-mte-linux.o \ arch/arm.o arch/arm-linux.o arch/arm-get-next-pcs.o \ arm-tdep.o arm-linux-tdep.o \ glibc-tdep.o linux-tdep.o solib-svr4.o \ diff --git a/gdb/nat/aarch64-mte-linux-ptrace.c b/gdb/nat/aarch64-mte-linux-ptrace.c new file mode 100644 index 0000000000..f92028176d --- /dev/null +++ b/gdb/nat/aarch64-mte-linux-ptrace.c @@ -0,0 +1,200 @@ +/* Common Linux native ptrace code for AArch64 MTE. + + Copyright (C) 2020 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 . */ + +#include "gdbsupport/common-defs.h" +#include "gdbsupport/byte-vector.h" + +#include "arch/aarch64.h" +#include "arch/aarch64-mte-linux.h" +#include "nat/aarch64-linux.h" +#include "nat/aarch64-mte-linux-ptrace.h" + +#include "linux-ptrace.h" +#include + +/* Helper function to display various possible errors when reading + MTE tags. */ + +static void +aarch64_mte_linux_peek_error (int error) +{ + switch (error) + { + case EIO: + perror_with_name (_("PEEKMTETAGS not supported")); + break; + case EFAULT: + perror_with_name (_("Couldn't fetch allocation tags")); + break; + case EOPNOTSUPP: + perror_with_name (_("PROT_ME not enabled for requested address")); + default: + perror_with_name (_("Unknown MTE error")); + break; + } +} + +/* Helper function to display various possible errors when writing + MTE tags. */ + +static void +aarch64_mte_linux_poke_error (int error) +{ + switch (error) + { + case EIO: + perror_with_name (_("POKEMTETAGS not supported")); + break; + case EFAULT: + perror_with_name (_("Couldn't store allocation tags")); + break; + case EOPNOTSUPP: + perror_with_name (_("PROT_ME not enabled for requested address")); + default: + perror_with_name (_("Unknown MTE error")); + break; + } +} + +/* Helper to prepare a vector of tags to be passed on to the kernel. The + main purpose of this function is to optimize the number of calls to + ptrace if we're writing too many tags at once, like a pattern fill + request. + + Return a vector of tags of up to MAX_SIZE size, containing the tags that + must be passed on to the kernel, extracted from TAGS, starting at POS. + GRANULES is the number of tag granules to be modified. */ + +static gdb::byte_vector +prepare_tag_vector (size_t granules, const gdb::byte_vector &tags, size_t pos, + size_t max_size) +{ + gdb::byte_vector t; + + if (granules == 0) + { + t.clear (); + return t; + } + + gdb_assert (tags.size () > 0 && max_size > 0); + + if (granules > TAGS_MAX_SIZE) + t.resize (TAGS_MAX_SIZE); + else + t.resize (granules); + + size_t tag_count = tags.size (); + + for (size_t i = 0; i < t.size (); i++) + t[i] = tags[(pos + i) % tag_count]; + + return t; +} + +/* See nat/aarch64-mte-linux-ptrace.h */ + +int +aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len, + gdb::byte_vector &tags) +{ + size_t ntags = get_tag_granules (address, len, MTE_GRANULE_SIZE); + gdb_byte tagbuf[ntags]; + + struct iovec iovec; + iovec.iov_base = tagbuf; + iovec.iov_len = ntags; + + tags.clear (); + bool done_reading = false; + + /* The kernel may return less tags than we requested. Loop until we've read + all the requested tags or until we get an error. */ + while (!done_reading) + { + /* Attempt to read ntags allocation tags from the kernel. */ + if (ptrace (PTRACE_PEEKMTETAGS, tid, address, &iovec) < 0) + aarch64_mte_linux_peek_error (errno); + + /* Make sure the kernel returned at least one tag. */ + if (iovec.iov_len <= 0) + { + tags.clear (); + return 1; + } + + /* Copy the tags the kernel returned. */ + for (size_t i = 0; i < iovec.iov_len; i++) + tags.push_back (tagbuf[i]); + + /* Are we done reading tags? */ + if (tags.size () == ntags) + done_reading = true; + else + { + address += iovec.iov_len * MTE_GRANULE_SIZE; + iovec.iov_len = ntags - iovec.iov_len; + } + } + return 0; +} + +/* See nat/aarch64-mte-linux-ptrace.h */ + +int +aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len, + const gdb::byte_vector &tags) +{ + if (tags.size () == 0) + return 0; + + /* Get the number of tags we need to write. */ + size_t ntags = get_tag_granules (address, len, MTE_GRANULE_SIZE); + bool done_writing = false; + size_t tags_written = 0; + + /* Write all the tags, TAGS_MAX_SIZE blocks at a time. */ + while (!done_writing) + { + gdb::byte_vector t = prepare_tag_vector (ntags - tags_written, tags, + tags_written, TAGS_MAX_SIZE); + + struct iovec iovec; + iovec.iov_base = t.data (); + iovec.iov_len = t.size (); + + /* Request the kernel to update the allocation tags. */ + if (ptrace (PTRACE_POKEMTETAGS, tid, address, &iovec) < 0) + aarch64_mte_linux_poke_error (errno); + + /* Make sure the kernel wrote at least one tag. */ + if (iovec.iov_len <= 0) + return 1; + + tags_written += iovec.iov_len; + + /* Are we done writing tags? */ + if (tags_written == ntags) + done_writing = true; + else + address += iovec.iov_len * MTE_GRANULE_SIZE; + } + + return 0; +} diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h index 099b6440ca..7ba6f014f6 100644 --- a/gdb/nat/aarch64-mte-linux-ptrace.h +++ b/gdb/nat/aarch64-mte-linux-ptrace.h @@ -30,4 +30,21 @@ #define PTRACE_POKEMTETAGS 34 #endif +/* Maximum number of tags to pass at once to the kernel. */ +#define TAGS_MAX_SIZE 4096 + +/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN) + into TAGS. + + Return 0 if successful and non-zero otherwise. */ +extern int aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len, + gdb::byte_vector &tags); + +/* Write the TAGS allocation tags to the memory range + [ADDRESS, ADDRESS + LEN). + + Return 0 if successful and non-zero otherwise. */ +extern int aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len, + const gdb::byte_vector &tags); + #endif /* NAT_AARCH64_MTE_LINUX_PTRACE_H */ -- 2.17.1