From patchwork Tue Jul 30 14:39:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gustavo Romero X-Patchwork-Id: 815305 Delivered-To: patch@linaro.org Received: by 2002:a05:6504:504d:b0:273:6c53:9181 with SMTP id d13csp456291ltm; Tue, 30 Jul 2024 07:40:38 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXDDSYfOGNUC/HGTdKYifbjyOZi+qesjKkJg3btmDtiwWnLZWTjxsxWiFuBJxomgIBKM4mwu4k9WM+EA+1SMFzK X-Google-Smtp-Source: AGHT+IEaWndYjiAOnd5B92Bi7/diYFrfw0/q98rmVz0zofpJvohhParx+okjCg5PZ8cyR7i2K16g X-Received: by 2002:a05:6102:390e:b0:493:ba76:a496 with SMTP id ada2fe7eead31-493fa4371damr11870074137.19.1722350438247; Tue, 30 Jul 2024 07:40:38 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1722350438; cv=pass; d=google.com; s=arc-20160816; b=096eHtLJhAo3wOIPF5wugzCPZ9fe4MOnxyRiR8oC2iWM6x/QHUuFdNMHEhin/nlE1t f8F616pTurNo03xJimvBqoWUXKUCXISMIQ0MrdwVWRHsWksTrVb06YHpZA4IwHm8UdUV bbLE2KOROc0+3dpihQw5J+Jm9oYJt5KTiI+QbjolBwV7onyQ7wrCva4uH8PJqpavviO9 BuEsueTcC6eDNyQ9UiHB/WqMa6POdw8mir7jjajjbeptB/rsZpUtQWOQJdO+gPWFcf1t 1x6rlqcAE04A5CZ6S/p7IxFjhGtZ1yLdtE00h7Gz+gYQIwV5cw6yLpsdHyew/B/8SynJ j8sA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :arc-filter:dmarc-filter:delivered-to; bh=MLqivGI/OrsoZfFBssyvWB/mfWMXX+3JNBox116R45w=; fh=ROv2ZqWcukhbpgiPwZmtHmCLjnsSLt0hnV/huNA06EE=; b=KHwuJOYNkINc3wK0KTzN9YYsNAn3L6c2Qaf5a9glc7QPuFbNQQFCLsGJiqrd8c8ELP mFb3Jw7vL70arNDZ1mojGW/QE9SH15SFSKUqiHvS1IDeVu5xyMS0bN3vI5AMnlxKNjdf DORNuSLLmUzO0o8/5dyGcLOgQeeY2Dz234LL/tTbIZ4oqkmp5cLlGdVkG7/ip5AsoP7T pZIV7NQPCMQR7xNTJeq2YAHcmfy2dUOQSBl9krX0I4Ko1kKOJJEp73HbQ/VdstRW+Nrh i8RhdWDFIx8GeWuUAifh0Ruc5Lv/tz4r5RawCBuVNgsEhfXrtGA/E4aQnei7saq8rGQ1 tK2w==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=WD034giz; arc=pass (i=1); spf=pass (google.com: domain of gdb-patches-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gdb-patches-bounces~patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id af79cd13be357-7a1d74600f1si1313636985a.388.2024.07.30.07.40.38 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jul 2024 07:40:38 -0700 (PDT) Received-SPF: pass (google.com: domain of gdb-patches-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=WD034giz; arc=pass (i=1); spf=pass (google.com: domain of gdb-patches-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gdb-patches-bounces~patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D29403858420 for ; Tue, 30 Jul 2024 14:40:37 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-pf1-x42c.google.com (mail-pf1-x42c.google.com [IPv6:2607:f8b0:4864:20::42c]) by sourceware.org (Postfix) with ESMTPS id 0ADBC3858C56 for ; Tue, 30 Jul 2024 14:40:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0ADBC3858C56 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0ADBC3858C56 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::42c ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722350415; cv=none; b=Zzwxw7enxzowcqLc300D3BmKl97kIr9KFEPRpXwlVUualA8msO+l99jul3L19qUabViMDCqooqrgx+cOdgxYfuOBPFUBxVmRPa1IHNEMnhaKI5XAito+A6UzBLqub3xoMK2l8/Fzw+i8iVZP2PEa9YI0tgfZPSixFJ5Xy9aDVtI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722350415; c=relaxed/simple; bh=x4LMR9mLFB08qbGioSKkvf8fij/SUoI6oQ6HGy1szg0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=m8WUyCa+ciTkf2IDLiWhUOsZ3p83yhFv5wmSN3cMezgJ/J1EURLTe5Taq/L4nPwkndMJOqEp078g7ARb03e9MdOqZUetoLhgdi/OoAoEXbC6yZSYHYI9VCHRN1g4sVkmIazgdQSlXHG5Mp8MC1ZSLW+g9BSRwKaR9F8R84D7QAc= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pf1-x42c.google.com with SMTP id d2e1a72fcca58-70d1d818c42so2848308b3a.1 for ; Tue, 30 Jul 2024 07:40:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1722350409; x=1722955209; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=MLqivGI/OrsoZfFBssyvWB/mfWMXX+3JNBox116R45w=; b=WD034gizDBC4ZOPrcmvA9JUd8Gs8pMtCH6XKZEUpxMR+1RAYeLFk1vSdr87hEDUolJ cZ9QHL8njB58mciUNshPlXsne+/VX59YeICugaXoWyG+Ch7Uez6WghW94NbxkKXaqc6g ebU2lXMl6rii9gi+ChhAFRcdbYCYKWreQ6z724wmnpnGKYFze8KJLXnD8tfPd4m0vMLV HnUmAV49AFrTZRWFDECWeRi/fVSHB4MalEZ2kUkigfgDt19mGzVhoOxJ01l7f1YrRmgW 12Ue9zxmQz+CBOfXybz4oSTYIS+atc1Z+h6+IITEPRIKvohXwTZJ61Lkr/2qpnSXNUPq H9dA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722350409; x=1722955209; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=MLqivGI/OrsoZfFBssyvWB/mfWMXX+3JNBox116R45w=; b=MbfLWVAQJQuKYPNAHrwkoRHQ0yYaDOpHVwFujw63d1IQB3dLxfkUXJ7euFevmZEd3w qTv7kg2RvzstSKNGWqsAjRf23U2yfUnJ0GE5AclgBV62Re7LeGtoyNFsGSAdmaCzhuom fZogfYwqWknxoUqu779Wvwtf+gCOLYE7Fjl/zyuH4wp9R0/wHZOuU/kr4ZHaThGfk7cD KyKlrSSlAX2F6VO/mA6oL0CROQRWH9XASxTH42hfnkVcLReU3o428wFrsyJY+j4zr7iS uBaYlKgNxEUuGBmNR8mv7yu6h+KWFNPrAZ+gB0CzoGrIZp5H8WT75jClHGk4qFsUs974 MrKA== X-Gm-Message-State: AOJu0YwPn2s4Z+/KIHziLqn2OEb0+pf84lV9B3SPWr4RasVzKo0SEbev p8CMn8jIul4P6au6MtWTpmjmyy3G4p0jzRHsBc40cvRqnHUvzmSU5KfCnMriDw384tv87X6jnBJ p X-Received: by 2002:a05:6a21:33a4:b0:1c2:911f:4d30 with SMTP id adf61e73a8af0-1c4a117c574mr9722066637.3.1722350409138; Tue, 30 Jul 2024 07:40:09 -0700 (PDT) Received: from amd.. ([2804:7f0:b403:1a23:3e7c:3fff:fe7a:e83b]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-70ead81273asm8423665b3a.125.2024.07.30.07.40.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jul 2024 07:40:08 -0700 (PDT) From: Gustavo Romero To: gdb-patches@sourceware.org, luis.machado@arm.com Cc: thiago.bauermann@linaro.org, gustavo.romero@linaro.org Subject: [PATCH v4] gdb: aarch64: Support MTE on baremetal Date: Tue, 30 Jul 2024 14:39:36 +0000 Message-Id: <20240730143936.2428794-1-gustavo.romero@linaro.org> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patch=linaro.org@sourceware.org This commit moves aarch64_linux_memtag_matches_p, aarch64_linux_set_memtags, aarch64_linux_get_memtag, and aarch64_linux_memtag_to_string hooks (plus aarch64_mte_get_atag function used by them), along with the setting of the memtag granule size, from aarch64-linux-tdep.c to aarch64-tdep.c, making MTE available on baremetal targets. Since the aarch64-linux-tdep.c layer inherits these hooks from aarch64-tdep.c, there is no effective change for aarch64-linux targets. Helpers used both by aarch64-tdep.c and by aarch64-linux-tdep.c were moved from arch/aarch64-mte-linux.{c,h} to new arch/aarch64-mte.{c,h} files. Signed-off-by: Gustavo Romero Tested-By: Luis Machado Approved-By: Luis Machado Reviewed-By: Eli Zaretskii --- gdb/Makefile.in | 3 + gdb/NEWS | 3 + gdb/aarch64-linux-tdep.c | 168 +---------------------------- gdb/aarch64-tdep.c | 168 +++++++++++++++++++++++++++++ gdb/aarch64-tdep.h | 2 + gdb/arch/aarch64-mte-linux.c | 56 ---------- gdb/arch/aarch64-mte-linux.h | 27 ----- gdb/arch/aarch64-mte.c | 77 +++++++++++++ gdb/arch/aarch64-mte.h | 51 +++++++++ gdb/configure.tgt | 3 +- gdb/nat/aarch64-mte-linux-ptrace.c | 1 + gdbserver/configure.srv | 1 + 12 files changed, 309 insertions(+), 251 deletions(-) create mode 100644 gdb/arch/aarch64-mte.c create mode 100644 gdb/arch/aarch64-mte.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 1c697bf0ab1..6744b8218ec 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -746,6 +746,7 @@ ALL_64_TARGET_OBS = \ amd64-windows-tdep.o \ arch/aarch64.o \ arch/aarch64-insn.o \ + arch/aarch64-mte.o \ arch/aarch64-mte-linux.o \ arch/aarch64-scalable-linux.o \ arch/amd64-linux-tdesc.o \ @@ -1551,6 +1552,7 @@ HFILES_NO_SRCDIR = \ arch/aarch32.h \ arch/aarch64.h \ arch/aarch64-insn.h \ + arch/aarch64-mte.h \ arch/aarch64-mte-linux.h \ arch/aarch64-scalable-linux.h \ arch/amd64-linux-tdesc.h \ @@ -1664,6 +1666,7 @@ ALLDEPFILES = \ arch/aarch32.c \ arch/aarch64.c \ arch/aarch64-insn.c \ + arch/aarch64-mte.c \ arch/aarch64-mte-linux.c \ arch/aarch64-scalable-linux.c \ arch/amd64.c \ diff --git a/gdb/NEWS b/gdb/NEWS index b56ba9b36ce..7ce62a6911d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -13,6 +13,9 @@ This may cause breakage when using an incompatible libc, like uclibc or newlib, or an older glibc. +* MTE (Memory Tagging Extension) debugging is now supported on Aarch64 baremetal + targets. + *** Changes in GDB 15 * The MPX commands "show/set mpx bound" have been deprecated, as Intel diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index a1296a8f0c7..ada9614673e 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -48,6 +48,7 @@ #include "record-full.h" #include "linux-record.h" +#include "arch/aarch64-mte.h" #include "arch/aarch64-mte-linux.h" #include "arch/aarch64-scalable-linux.h" @@ -2427,29 +2428,6 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch) return {}; } -/* Helper to get the allocation tag from a 64-bit ADDRESS. - - Return the allocation tag if successful and nullopt otherwise. */ - -static std::optional -aarch64_mte_get_atag (CORE_ADDR address) -{ - gdb::byte_vector tags; - - /* Attempt to fetch the allocation tag. */ - if (!target_fetch_memtags (address, 1, tags, - static_cast (memtag_type::allocation))) - return {}; - - /* Only one tag should've been returned. Make sure we got exactly that. */ - if (tags.size () != 1) - error (_("Target returned an unexpected number of tags.")); - - /* Although our tags are 4 bits in size, they are stored in a - byte. */ - return tags[0]; -} - /* Implement the tagged_address_p gdbarch method. */ static bool @@ -2466,132 +2444,6 @@ aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, CORE_ADDR address) return true; } -/* Implement the memtag_matches_p gdbarch method. */ - -static bool -aarch64_linux_memtag_matches_p (struct gdbarch *gdbarch, - struct value *address) -{ - gdb_assert (address != nullptr); - - CORE_ADDR addr = value_as_address (address); - - /* Fetch the allocation tag for ADDRESS. */ - std::optional atag - = aarch64_mte_get_atag (gdbarch_remove_non_address_bits (gdbarch, addr)); - - if (!atag.has_value ()) - return true; - - /* Fetch the logical tag for ADDRESS. */ - gdb_byte ltag = aarch64_mte_get_ltag (addr); - - /* Are the tags the same? */ - return ltag == *atag; -} - -/* Implement the set_memtags gdbarch method. */ - -static bool -aarch64_linux_set_memtags (struct gdbarch *gdbarch, struct value *address, - size_t length, const gdb::byte_vector &tags, - memtag_type tag_type) -{ - gdb_assert (!tags.empty ()); - gdb_assert (address != nullptr); - - CORE_ADDR addr = value_as_address (address); - - /* Set the logical tag or the allocation tag. */ - if (tag_type == memtag_type::logical) - { - /* When setting logical tags, we don't care about the length, since - we are only setting a single logical tag. */ - addr = aarch64_mte_set_ltag (addr, tags[0]); - - /* Update the value's content with the tag. */ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - gdb_byte *srcbuf = address->contents_raw ().data (); - store_unsigned_integer (srcbuf, sizeof (addr), byte_order, addr); - } - else - { - /* Remove the top byte. */ - addr = gdbarch_remove_non_address_bits (gdbarch, addr); - - /* With G being the number of tag granules and N the number of tags - passed in, we can have the following cases: - - 1 - G == N: Store all the N tags to memory. - - 2 - G < N : Warn about having more tags than granules, but write G - tags. - - 3 - G > N : This is a "fill tags" operation. We should use the tags - as a pattern to fill the granules repeatedly until we have - written G tags to memory. - */ - - size_t g = aarch64_mte_get_tag_granules (addr, length, - AARCH64_MTE_GRANULE_SIZE); - size_t n = tags.size (); - - if (g < n) - warning (_("Got more tags than memory granules. Tags will be " - "truncated.")); - else if (g > n) - warning (_("Using tag pattern to fill memory range.")); - - if (!target_store_memtags (addr, length, tags, - static_cast (memtag_type::allocation))) - return false; - } - return true; -} - -/* Implement the get_memtag gdbarch method. */ - -static struct value * -aarch64_linux_get_memtag (struct gdbarch *gdbarch, struct value *address, - memtag_type tag_type) -{ - gdb_assert (address != nullptr); - - CORE_ADDR addr = value_as_address (address); - CORE_ADDR tag = 0; - - /* Get the logical tag or the allocation tag. */ - if (tag_type == memtag_type::logical) - tag = aarch64_mte_get_ltag (addr); - else - { - /* Remove the top byte. */ - addr = gdbarch_remove_non_address_bits (gdbarch, addr); - std::optional atag = aarch64_mte_get_atag (addr); - - if (!atag.has_value ()) - return nullptr; - - tag = *atag; - } - - /* Convert the tag to a value. */ - return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int, - tag); -} - -/* Implement the memtag_to_string gdbarch method. */ - -static std::string -aarch64_linux_memtag_to_string (struct gdbarch *gdbarch, struct value *tag_value) -{ - if (tag_value == nullptr) - return ""; - - CORE_ADDR tag = value_as_address (tag_value); - - return string_printf ("0x%s", phex_nz (tag, sizeof (tag))); -} /* AArch64 Linux implementation of the report_signal_info gdbarch hook. Displays information about possible memory tag violations. */ @@ -2900,24 +2752,6 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Register a hook for checking if an address is tagged or not. */ set_gdbarch_tagged_address_p (gdbarch, aarch64_linux_tagged_address_p); - /* Register a hook for checking if there is a memory tag match. */ - set_gdbarch_memtag_matches_p (gdbarch, - aarch64_linux_memtag_matches_p); - - /* Register a hook for setting the logical/allocation tags for - a range of addresses. */ - set_gdbarch_set_memtags (gdbarch, aarch64_linux_set_memtags); - - /* Register a hook for extracting the logical/allocation tag from an - address. */ - set_gdbarch_get_memtag (gdbarch, aarch64_linux_get_memtag); - - /* Set the allocation tag granule size to 16 bytes. */ - set_gdbarch_memtag_granule_size (gdbarch, AARCH64_MTE_GRANULE_SIZE); - - /* Register a hook for converting a memory tag to a string. */ - set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string); - set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info); diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index e4bca6c6632..865b1c0b13b 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -45,6 +45,7 @@ #include "aarch64-tdep.h" #include "aarch64-ravenscar-thread.h" +#include "arch/aarch64-mte.h" #include "record.h" #include "record-full.h" @@ -4088,6 +4089,156 @@ aarch64_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) return streq (inst.opcode->name, "ret"); } +/* Helper to get the allocation tag from a 64-bit ADDRESS. + + Return the allocation tag if successful and nullopt otherwise. */ + +std::optional +aarch64_mte_get_atag (CORE_ADDR address) +{ + gdb::byte_vector tags; + + /* Attempt to fetch the allocation tag. */ + if (!target_fetch_memtags (address, 1, tags, + static_cast (memtag_type::allocation))) + return {}; + + /* Only one tag should've been returned. Make sure we got exactly that. */ + if (tags.size () != 1) + error (_("Target returned an unexpected number of tags.")); + + /* Although our tags are 4 bits in size, they are stored in a + byte. */ + return tags[0]; +} + +/* Implement the memtag_matches_p gdbarch method. */ + +static bool +aarch64_memtag_matches_p (struct gdbarch *gdbarch, + struct value *address) +{ + gdb_assert (address != nullptr); + + CORE_ADDR addr = value_as_address (address); + + /* Fetch the allocation tag for ADDRESS. */ + std::optional atag + = aarch64_mte_get_atag (gdbarch_remove_non_address_bits (gdbarch, addr)); + + if (!atag.has_value ()) + return true; + + /* Fetch the logical tag for ADDRESS. */ + gdb_byte ltag = aarch64_mte_get_ltag (addr); + + /* Are the tags the same? */ + return ltag == *atag; +} + +/* Implement the set_memtags gdbarch method. */ + +static bool +aarch64_set_memtags (struct gdbarch *gdbarch, struct value *address, + size_t length, const gdb::byte_vector &tags, + memtag_type tag_type) +{ + gdb_assert (!tags.empty ()); + gdb_assert (address != nullptr); + + CORE_ADDR addr = value_as_address (address); + + /* Set the logical tag or the allocation tag. */ + if (tag_type == memtag_type::logical) + { + /* When setting logical tags, we don't care about the length, since + we are only setting a single logical tag. */ + addr = aarch64_mte_set_ltag (addr, tags[0]); + + /* Update the value's content with the tag. */ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte *srcbuf = address->contents_raw ().data (); + store_unsigned_integer (srcbuf, sizeof (addr), byte_order, addr); + } + else + { + /* Remove the top byte. */ + addr = gdbarch_remove_non_address_bits (gdbarch, addr); + + /* With G being the number of tag granules and N the number of tags + passed in, we can have the following cases: + + 1 - G == N: Store all the N tags to memory. + + 2 - G < N : Warn about having more tags than granules, but write G + tags. + + 3 - G > N : This is a "fill tags" operation. We should use the tags + as a pattern to fill the granules repeatedly until we have + written G tags to memory. + */ + + size_t g = aarch64_mte_get_tag_granules (addr, length, + AARCH64_MTE_GRANULE_SIZE); + size_t n = tags.size (); + + if (g < n) + warning (_("Got more tags than memory granules. Tags will be " + "truncated.")); + else if (g > n) + warning (_("Using tag pattern to fill memory range.")); + + if (!target_store_memtags (addr, length, tags, + static_cast (memtag_type::allocation))) + return false; + } + return true; +} + +/* Implement the get_memtag gdbarch method. */ + +static struct value * +aarch64_get_memtag (struct gdbarch *gdbarch, struct value *address, + memtag_type tag_type) +{ + gdb_assert (address != nullptr); + + CORE_ADDR addr = value_as_address (address); + CORE_ADDR tag = 0; + + /* Get the logical tag or the allocation tag. */ + if (tag_type == memtag_type::logical) + tag = aarch64_mte_get_ltag (addr); + else + { + /* Remove the top byte. */ + addr = gdbarch_remove_non_address_bits (gdbarch, addr); + std::optional atag = aarch64_mte_get_atag (addr); + + if (!atag.has_value ()) + return nullptr; + + tag = *atag; + } + + /* Convert the tag to a value. */ + return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int, + tag); +} + +/* Implement the memtag_to_string gdbarch method. */ + +static std::string +aarch64_memtag_to_string (struct gdbarch *gdbarch, struct value *tag_value) +{ + if (tag_value == nullptr) + return ""; + + CORE_ADDR tag = value_as_address (tag_value); + + return string_printf ("0x%s", phex_nz (tag, sizeof (tag))); +} + /* AArch64 implementation of the remove_non_address_bits gdbarch hook. Remove non address bits from a pointer value. */ @@ -4504,6 +4655,23 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) aarch64_pseudo_register_reggroup_p); set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register); + /* Set the allocation tag granule size to 16 bytes. */ + set_gdbarch_memtag_granule_size (gdbarch, AARCH64_MTE_GRANULE_SIZE); + + /* Register a hook for checking if there is a memory tag match. */ + set_gdbarch_memtag_matches_p (gdbarch, aarch64_memtag_matches_p); + + /* Register a hook for setting the logical/allocation tags for + a range of addresses. */ + set_gdbarch_set_memtags (gdbarch, aarch64_set_memtags); + + /* Register a hook for extracting the logical/allocation tag from an + address. */ + set_gdbarch_get_memtag (gdbarch, aarch64_get_memtag); + + /* Register a hook for converting a memory tag to a string. */ + set_gdbarch_memtag_to_string (gdbarch, aarch64_memtag_to_string); + /* ABI */ set_gdbarch_short_bit (gdbarch, 16); set_gdbarch_int_bit (gdbarch, 32); diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 0e6024bfcbc..50166fb4f24 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -203,4 +203,6 @@ void aarch64_displaced_step_fixup (struct gdbarch *gdbarch, bool aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch); +std::optional aarch64_mte_get_atag (CORE_ADDR address); + #endif /* aarch64-tdep.h */ diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c index e0b441e3859..49426d7751c 100644 --- a/gdb/arch/aarch64-mte-linux.c +++ b/gdb/arch/aarch64-mte-linux.c @@ -75,59 +75,3 @@ aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first) 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) -{ - /* An empty range has 0 tag granules. */ - if (len == 0) - return 0; - - /* Start address */ - CORE_ADDR s_addr = align_down (addr, granule_size); - /* End address */ - CORE_ADDR e_addr = align_down (addr + len - 1, granule_size); - - /* We always have at least 1 granule because len is non-zero at this - point. */ - return 1 + (e_addr - s_addr) / granule_size; -} - -/* See arch/aarch64-mte-linux.h */ - -CORE_ADDR -aarch64_mte_make_ltag_bits (CORE_ADDR value) -{ - return value & AARCH64_MTE_LOGICAL_MAX_VALUE; -} - -/* See arch/aarch64-mte-linux.h */ - -CORE_ADDR -aarch64_mte_make_ltag (CORE_ADDR value) -{ - return (aarch64_mte_make_ltag_bits (value) - << AARCH64_MTE_LOGICAL_TAG_START_BIT); -} - -/* See arch/aarch64-mte-linux.h */ - -CORE_ADDR -aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag) -{ - /* Remove the existing tag. */ - address &= ~aarch64_mte_make_ltag (AARCH64_MTE_LOGICAL_MAX_VALUE); - - /* Return the new tagged address. */ - return address | aarch64_mte_make_ltag (tag); -} - -/* See arch/aarch64-mte-linux.h */ - -CORE_ADDR -aarch64_mte_get_ltag (CORE_ADDR address) -{ - CORE_ADDR ltag_addr = address >> AARCH64_MTE_LOGICAL_TAG_START_BIT; - return aarch64_mte_make_ltag_bits (ltag_addr); -} diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h index 460b10e05c9..686749f547a 100644 --- a/gdb/arch/aarch64-mte-linux.h +++ b/gdb/arch/aarch64-mte-linux.h @@ -29,12 +29,6 @@ /* 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 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 - /* Memory tagging definitions. */ #ifndef SEGV_MTEAERR # define SEGV_MTEAERR 8 @@ -50,27 +44,6 @@ enum class aarch64_memtag_type mte_allocation }; -/* Return the number of tag granules in the memory range - [ADDR, ADDR + LEN) given GRANULE_SIZE. */ -extern size_t aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, - size_t granule_size); - -/* Return the 4-bit tag made from VALUE. */ -extern CORE_ADDR aarch64_mte_make_ltag_bits (CORE_ADDR value); - -/* Return the 4-bit tag that can be OR-ed to an address. */ -extern CORE_ADDR aarch64_mte_make_ltag (CORE_ADDR value); - -/* Helper to set the logical TAG for a 64-bit ADDRESS. - - It is always possible to set the logical tag. */ -extern CORE_ADDR aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag); - -/* Helper to get the logical tag from a 64-bit ADDRESS. - - 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. */ extern void aarch64_mte_pack_tags (gdb::byte_vector &tags); diff --git a/gdb/arch/aarch64-mte.c b/gdb/arch/aarch64-mte.c new file mode 100644 index 00000000000..908e12cdf3b --- /dev/null +++ b/gdb/arch/aarch64-mte.c @@ -0,0 +1,77 @@ +/* Common AArch64 functionality for MTE + + Copyright (C) 2021-2024 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.h" + +/* See arch/aarch64-mte.h */ + +size_t +aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size) +{ + /* An empty range has 0 tag granules. */ + if (len == 0) + return 0; + + /* Start address */ + CORE_ADDR s_addr = align_down (addr, granule_size); + /* End address */ + CORE_ADDR e_addr = align_down (addr + len - 1, granule_size); + + /* We always have at least 1 granule because len is non-zero at this + point. */ + return 1 + (e_addr - s_addr) / granule_size; +} + +/* See arch/aarch64-mte.h */ + +CORE_ADDR +aarch64_mte_make_ltag_bits (CORE_ADDR value) +{ + return value & AARCH64_MTE_LOGICAL_MAX_VALUE; +} + +/* See arch/aarch64-mte.h */ + +CORE_ADDR +aarch64_mte_make_ltag (CORE_ADDR value) +{ + return (aarch64_mte_make_ltag_bits (value) + << AARCH64_MTE_LOGICAL_TAG_START_BIT); +} + +/* See arch/aarch64-mte.h */ + +CORE_ADDR +aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag) +{ + /* Remove the existing tag. */ + address &= ~aarch64_mte_make_ltag (AARCH64_MTE_LOGICAL_MAX_VALUE); + + /* Return the new tagged address. */ + return address | aarch64_mte_make_ltag (tag); +} + +/* See arch/aarch64-mte.h */ + +CORE_ADDR +aarch64_mte_get_ltag (CORE_ADDR address) +{ + CORE_ADDR ltag_addr = address >> AARCH64_MTE_LOGICAL_TAG_START_BIT; + return aarch64_mte_make_ltag_bits (ltag_addr); +} diff --git a/gdb/arch/aarch64-mte.h b/gdb/arch/aarch64-mte.h new file mode 100644 index 00000000000..7d8445ee89f --- /dev/null +++ b/gdb/arch/aarch64-mte.h @@ -0,0 +1,51 @@ +/* Common AArch64 definitions for MTE + + Copyright (C) 2021-2024 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 . */ + +#ifndef ARCH_AARCH64_MTE_H +#define ARCH_AARCH64_MTE_H + + +/* 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 + +/* Return the number of tag granules in the memory range + [ADDR, ADDR + LEN) given GRANULE_SIZE. */ +extern size_t aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, + size_t granule_size); + +/* Return the 4-bit tag made from VALUE. */ +extern CORE_ADDR aarch64_mte_make_ltag_bits (CORE_ADDR value); + +/* Return the 4-bit tag that can be OR-ed to an address. */ +extern CORE_ADDR aarch64_mte_make_ltag (CORE_ADDR value); + +/* Helper to set the logical TAG for a 64-bit ADDRESS. + + It is always possible to set the logical tag. */ +extern CORE_ADDR aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag); + +/* Helper to get the logical tag from a 64-bit ADDRESS. + + It is always possible to get the logical tag. */ +extern CORE_ADDR aarch64_mte_get_ltag (CORE_ADDR address); + +#endif /* ARCH_AARCH64_MTE_H */ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 8326c458eb1..5fb14b65426 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -59,7 +59,8 @@ amd64_tobjs="ravenscar-thread.o amd64-ravenscar-thread.o \ case "${targ}" in aarch64*-*-*) cpu_obs="aarch32-tdep.o aarch64-tdep.o arch/aarch32.o \ - arch/aarch64-insn.o arch/aarch64.o ravenscar-thread.o \ + arch/aarch64-insn.o arch/aarch64.o arch/aarch64-mte.o \ + ravenscar-thread.o \ aarch64-ravenscar-thread.o";; alpha*-*-*) diff --git a/gdb/nat/aarch64-mte-linux-ptrace.c b/gdb/nat/aarch64-mte-linux-ptrace.c index 9e2a2ce1ab5..c2e70293a69 100644 --- a/gdb/nat/aarch64-mte-linux-ptrace.c +++ b/gdb/nat/aarch64-mte-linux-ptrace.c @@ -22,6 +22,7 @@ #include "linux-ptrace.h" #include "arch/aarch64.h" +#include "arch/aarch64-mte.h" #include "arch/aarch64-mte-linux.h" #include "nat/aarch64-linux.h" #include "nat/aarch64-mte-linux-ptrace.h" diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv index e24e40e85c1..95359137f4f 100644 --- a/gdbserver/configure.srv +++ b/gdbserver/configure.srv @@ -48,6 +48,7 @@ case "${gdbserver_host}" in srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o" srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o" srv_tgtobj="$srv_tgtobj arch/aarch64.o" + srv_tgtobj="$srv_tgtobj arch/aarch64-mte.o" srv_tgtobj="$srv_tgtobj arch/aarch64-mte-linux.o" srv_tgtobj="$srv_tgtobj arch/aarch64-scalable-linux.o" srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o"