From patchwork Thu Jul 4 10:17:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 93339 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 40D6E384A4B6 for ; Thu, 4 Jul 2024 10:19:20 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) by sourceware.org (Postfix) with ESMTPS id F3CF2384A49B for ; Thu, 4 Jul 2024 10:18:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F3CF2384A49B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F3CF2384A49B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720088326; cv=none; b=LKk8jB+qtAC7zmmz3uFtY6Gm1jm+KHYyMe/bX2xbUhlaJESuodaPy0ATPHg0rrvNsnWs05+fdgYU1VEtIqw697WRILdA3J8BjitNSv5zhl+p/TK1Vbh1c8MebSs/Fmj45CZXb6q+L3XP5p2nYSEMEJlOKw7cjWCFtsAfSbU4Q5Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720088326; c=relaxed/simple; bh=iK61BgRrlbWrpv4BHlLLcKaGTHI9LI0vbg+NNQy69fY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=i/QCC6//bORyHlj8zqW/bsOWObSjb5L1Y7GUJQD/sUQeHXq2t7eCfZe/hva+hnTBQuQo5gmU/IbFYcQ85OQBTW1/hZ0BYcJG/ai4sPEbDjC7dcRBFyrIJ/B378mAF3i1fJRT6vF4Pk31OAS2rBvw1M8wsrxMh9jbNU+rxeKUbR0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720088323; x=1751624323; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iK61BgRrlbWrpv4BHlLLcKaGTHI9LI0vbg+NNQy69fY=; b=Tvyelww48SzaHthGC+mH0u89tGRLOnhY48FaOjmGZ8UCJ1nLL8PmD+6p 8FK9rofgOyrjJURoBWnW2S3KV74O5KGdvvUx6NrdsrB5rlzYs2MDAsq+R um0ecKHHmnEL1u6LOGJ2Tyl2xjrHjovZJYp+nI3WPb9K7sWqDL1wHiGc2 UQ7rv3AmVEujzz2xlKqkuDJd54Usu1ifGMUyZXpv34kQP/d9b6DG/AVTT 1JScUhInTR0L+2e5rkanGdxmXnfL4dtr4YmUVp6W3mCGK4YGAuGAKNamE gpE9bJRpafQeMvxM5TOmEMR2VbYCbIgv8qSxyKhJJUYBDfJ5bBs3M/8ST g==; X-CSE-ConnectionGUID: QGBXnX2mQZCVH0AkQNMA6A== X-CSE-MsgGUID: VTceFe+IR+SwEdfmbb6IsQ== X-IronPort-AV: E=McAfee;i="6700,10204,11122"; a="17501293" X-IronPort-AV: E=Sophos;i="6.09,183,1716274800"; d="scan'208";a="17501293" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Jul 2024 03:18:41 -0700 X-CSE-ConnectionGUID: r1uy5/pLR2WSfxum7MBDFQ== X-CSE-MsgGUID: l4eVW4eiRwKJfbWDyzMF6A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,183,1716274800"; d="scan'208";a="50999791" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Jul 2024 03:18:39 -0700 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Cc: felix.willgerodt@intel.com, luis.machado@arm.com Subject: [PATCH v4 1/2] gdb: Make tagged pointer support configurable. Date: Thu, 4 Jul 2024 10:17:35 +0000 Message-Id: <20240704101736.3074236-2-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240704101736.3074236-1-christina.schimpe@intel.com> References: <20240704101736.3074236-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, 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~patchwork=sourceware.org@sourceware.org From: Christina Schimpe The gdbarch function gdbarch_remove_non_address_bits adjusts addresses to enable debugging of programs with tagged pointers on Linux, for instance for ARM's feature top byte ignore (TBI). Once the function is implemented for an architecture, it adjusts addresses for memory access, breakpoints and watchpoints. Linear address masking (LAM) is Intel's (R) implementation of tagged pointer support. It requires certain adaptions to GDB's tagged pointer support due to the following: - LAM supports address tagging for data accesses only. Thus, specifying breakpoints on tagged addresses is not a valid use case. - In contrast to the implementation for ARM's TBI, the Linux kernel supports tagged pointers for memory access. This patch makes GDB's tagged pointer support configurable such that it is possible to enable the address adjustment for a specific feature only (e.g memory access, breakpoints or watchpoints). This way, one can make sure that addresses are only adjusted when necessary. In case of LAM, this avoids unnecessary parsing of the /proc//status file to get the untag mask. Reviewed-By: Felix Willgerodt --- gdb/aarch64-linux-nat.c | 2 +- gdb/aarch64-linux-tdep.c | 13 ++++---- gdb/aarch64-tdep.c | 17 ++++++---- gdb/aarch64-tdep.h | 6 ++++ gdb/breakpoint.c | 5 +-- gdb/gdbarch-gen.h | 49 ++++++++++++++++++++++------- gdb/gdbarch.c | 66 ++++++++++++++++++++++++++++++++------- gdb/gdbarch_components.py | 53 ++++++++++++++++++++++++++----- gdb/target.c | 3 +- 9 files changed, 168 insertions(+), 46 deletions(-) diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 2e6541f53c3..dac42b4f48b 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -945,7 +945,7 @@ aarch64_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p) kernel can potentially be tagged addresses. */ struct gdbarch *gdbarch = thread_architecture (inferior_ptid); const CORE_ADDR addr_trap - = gdbarch_remove_non_address_bits (gdbarch, (CORE_ADDR) siginfo.si_addr); + = aarch64_remove_non_address_bits (gdbarch, (CORE_ADDR) siginfo.si_addr); /* Check if the address matches any watched address. */ state = aarch64_get_debug_reg_state (inferior_ptid.pid ()); diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index a1296a8f0c7..bf5ce72aa5f 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -2456,7 +2456,7 @@ static bool aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, CORE_ADDR address) { /* Remove the top byte for the memory range check. */ - address = gdbarch_remove_non_address_bits (gdbarch, address); + address = aarch64_remove_non_address_bits (gdbarch, address); /* Check if the page that contains ADDRESS is mapped with PROT_MTE. */ if (!linux_address_in_memtag_page (address)) @@ -2478,7 +2478,7 @@ aarch64_linux_memtag_matches_p (struct gdbarch *gdbarch, /* Fetch the allocation tag for ADDRESS. */ std::optional atag - = aarch64_mte_get_atag (gdbarch_remove_non_address_bits (gdbarch, addr)); + = aarch64_mte_get_atag (aarch64_remove_non_address_bits (gdbarch, addr)); if (!atag.has_value ()) return true; @@ -2517,7 +2517,7 @@ aarch64_linux_set_memtags (struct gdbarch *gdbarch, struct value *address, else { /* Remove the top byte. */ - addr = gdbarch_remove_non_address_bits (gdbarch, addr); + addr = aarch64_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: @@ -2566,7 +2566,7 @@ aarch64_linux_get_memtag (struct gdbarch *gdbarch, struct value *address, else { /* Remove the top byte. */ - addr = gdbarch_remove_non_address_bits (gdbarch, addr); + addr = aarch64_remove_non_address_bits (gdbarch, addr); std::optional atag = aarch64_mte_get_atag (addr); if (!atag.has_value ()) @@ -2640,8 +2640,9 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, uiout->text ("\n"); std::optional atag - = aarch64_mte_get_atag (gdbarch_remove_non_address_bits (gdbarch, - fault_addr)); + = aarch64_mte_get_atag ( + aarch64_remove_non_address_bits (gdbarch, fault_addr)); + gdb_byte ltag = aarch64_mte_get_ltag (fault_addr); if (!atag.has_value ()) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index e4bca6c6632..ba1dc3d5844 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -4088,10 +4088,9 @@ aarch64_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) return streq (inst.opcode->name, "ret"); } -/* AArch64 implementation of the remove_non_address_bits gdbarch hook. Remove - non address bits from a pointer value. */ +/* See aarch64-tdep.h. */ -static CORE_ADDR +CORE_ADDR aarch64_remove_non_address_bits (struct gdbarch *gdbarch, CORE_ADDR pointer) { /* By default, we assume TBI and discard the top 8 bits plus the VA range @@ -4585,9 +4584,15 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->ra_sign_state_regnum = ra_sign_state_offset + num_regs; /* Architecture hook to remove bits of a pointer that are not part of the - address, like memory tags (MTE) and pointer authentication signatures. */ - set_gdbarch_remove_non_address_bits (gdbarch, - aarch64_remove_non_address_bits); + address, like memory tags (MTE) and pointer authentication signatures. + Configure address adjustment for watch-, breakpoints and memory + transfer. */ + set_gdbarch_remove_non_address_bits_watchpoint + (gdbarch, aarch64_remove_non_address_bits); + set_gdbarch_remove_non_address_bits_breakpoint + (gdbarch, aarch64_remove_non_address_bits); + set_gdbarch_remove_non_address_bits_memory + (gdbarch, aarch64_remove_non_address_bits); /* SME pseudo-registers. */ if (tdep->has_sme ()) diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 0e6024bfcbc..a9c8815f8be 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -203,4 +203,10 @@ void aarch64_displaced_step_fixup (struct gdbarch *gdbarch, bool aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch); +/* AArch64 implementation of the remove_non_address_bits gdbarch hooks. + Remove non address bits from a pointer value. */ + +CORE_ADDR aarch64_remove_non_address_bits (struct gdbarch *gdbarch, + CORE_ADDR pointer); + #endif /* aarch64-tdep.h */ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index a973518ac5f..8c2d9d247ec 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -2238,7 +2238,8 @@ update_watchpoint (struct watchpoint *b, bool reparse) loc->gdbarch = v->type ()->arch (); loc->pspace = wp_pspace; loc->address - = gdbarch_remove_non_address_bits (loc->gdbarch, addr); + = gdbarch_remove_non_address_bits_watchpoint (loc->gdbarch, + addr); b->add_location (*loc); if (bitsize != 0) @@ -7477,7 +7478,7 @@ adjust_breakpoint_address (struct gdbarch *gdbarch, } adjusted_bpaddr - = gdbarch_remove_non_address_bits (gdbarch, adjusted_bpaddr); + = gdbarch_remove_non_address_bits_breakpoint (gdbarch, adjusted_bpaddr); /* An adjusted breakpoint address can significantly alter a user's expectations. Print a warning if an adjustment diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index b982fd7cd09..9fda85f860f 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -684,19 +684,46 @@ extern CORE_ADDR gdbarch_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR ad extern void set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, gdbarch_addr_bits_remove_ftype *addr_bits_remove); /* On some architectures, not all bits of a pointer are significant. - On AArch64, for example, the top bits of a pointer may carry a "tag", which - can be ignored by the kernel and the hardware. The "tag" can be regarded as - additional data associated with the pointer, but it is not part of the address. + On AArch64 and amd64, for example, the top bits of a pointer may carry a + "tag", which can be ignored by the kernel and the hardware. The "tag" can be + regarded as additional data associated with the pointer, but it is not part + of the address. Given a pointer for the architecture, this hook removes all the - non-significant bits and sign-extends things as needed. It gets used to remove - non-address bits from data pointers (for example, removing the AArch64 MTE tag - bits from a pointer) and from code pointers (removing the AArch64 PAC signature - from a pointer containing the return address). */ - -typedef CORE_ADDR (gdbarch_remove_non_address_bits_ftype) (struct gdbarch *gdbarch, CORE_ADDR pointer); -extern CORE_ADDR gdbarch_remove_non_address_bits (struct gdbarch *gdbarch, CORE_ADDR pointer); -extern void set_gdbarch_remove_non_address_bits (struct gdbarch *gdbarch, gdbarch_remove_non_address_bits_ftype *remove_non_address_bits); + non-significant bits and sign-extends things as needed. It gets used to + remove non-address bits from pointers used for watchpoints. */ + +typedef CORE_ADDR (gdbarch_remove_non_address_bits_watchpoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR pointer); +extern CORE_ADDR gdbarch_remove_non_address_bits_watchpoint (struct gdbarch *gdbarch, CORE_ADDR pointer); +extern void set_gdbarch_remove_non_address_bits_watchpoint (struct gdbarch *gdbarch, gdbarch_remove_non_address_bits_watchpoint_ftype *remove_non_address_bits_watchpoint); + +/* On some architectures, not all bits of a pointer are significant. + On AArch64 and amd64, for example, the top bits of a pointer may carry a + "tag", which can be ignored by the kernel and the hardware. The "tag" can be + regarded as additional data associated with the pointer, but it is not part + of the address. + + Given a pointer for the architecture, this hook removes all the + non-significant bits and sign-extends things as needed. It gets used to + remove non-address bits from pointers used for breakpoints. */ + +typedef CORE_ADDR (gdbarch_remove_non_address_bits_breakpoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR pointer); +extern CORE_ADDR gdbarch_remove_non_address_bits_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pointer); +extern void set_gdbarch_remove_non_address_bits_breakpoint (struct gdbarch *gdbarch, gdbarch_remove_non_address_bits_breakpoint_ftype *remove_non_address_bits_breakpoint); + +/* On some architectures, not all bits of a pointer are significant. + On AArch64 and amd64, for example, the top bits of a pointer may carry a + "tag", which can be ignored by the kernel and the hardware. The "tag" can be + regarded as additional data associated with the pointer, but it is not part + of the address. + + Given a pointer for the architecture, this hook removes all the + non-significant bits and sign-extends things as needed. It gets used to + remove non-address bits from any pointer used to access memory. */ + +typedef CORE_ADDR (gdbarch_remove_non_address_bits_memory_ftype) (struct gdbarch *gdbarch, CORE_ADDR pointer); +extern CORE_ADDR gdbarch_remove_non_address_bits_memory (struct gdbarch *gdbarch, CORE_ADDR pointer); +extern void set_gdbarch_remove_non_address_bits_memory (struct gdbarch *gdbarch, gdbarch_remove_non_address_bits_memory_ftype *remove_non_address_bits_memory); /* Return a string representation of the memory tag TAG. */ diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 58e9ebbdc59..99a54a38d61 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -143,7 +143,9 @@ struct gdbarch int frame_red_zone_size = 0; gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity; gdbarch_addr_bits_remove_ftype *addr_bits_remove = core_addr_identity; - gdbarch_remove_non_address_bits_ftype *remove_non_address_bits = default_remove_non_address_bits; + gdbarch_remove_non_address_bits_watchpoint_ftype *remove_non_address_bits_watchpoint = default_remove_non_address_bits; + gdbarch_remove_non_address_bits_breakpoint_ftype *remove_non_address_bits_breakpoint = default_remove_non_address_bits; + gdbarch_remove_non_address_bits_memory_ftype *remove_non_address_bits_memory = default_remove_non_address_bits; gdbarch_memtag_to_string_ftype *memtag_to_string = default_memtag_to_string; gdbarch_tagged_address_p_ftype *tagged_address_p = default_tagged_address_p; gdbarch_memtag_matches_p_ftype *memtag_matches_p = default_memtag_matches_p; @@ -407,7 +409,9 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of frame_red_zone_size, invalid_p == 0 */ /* Skip verify of convert_from_func_ptr_addr, invalid_p == 0 */ /* Skip verify of addr_bits_remove, invalid_p == 0 */ - /* Skip verify of remove_non_address_bits, invalid_p == 0 */ + /* Skip verify of remove_non_address_bits_watchpoint, invalid_p == 0 */ + /* Skip verify of remove_non_address_bits_breakpoint, invalid_p == 0 */ + /* Skip verify of remove_non_address_bits_memory, invalid_p == 0 */ /* Skip verify of memtag_to_string, invalid_p == 0 */ /* Skip verify of tagged_address_p, invalid_p == 0 */ /* Skip verify of memtag_matches_p, invalid_p == 0 */ @@ -910,8 +914,14 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: addr_bits_remove = <%s>\n", host_address_to_string (gdbarch->addr_bits_remove)); gdb_printf (file, - "gdbarch_dump: remove_non_address_bits = <%s>\n", - host_address_to_string (gdbarch->remove_non_address_bits)); + "gdbarch_dump: remove_non_address_bits_watchpoint = <%s>\n", + host_address_to_string (gdbarch->remove_non_address_bits_watchpoint)); + gdb_printf (file, + "gdbarch_dump: remove_non_address_bits_breakpoint = <%s>\n", + host_address_to_string (gdbarch->remove_non_address_bits_breakpoint)); + gdb_printf (file, + "gdbarch_dump: remove_non_address_bits_memory = <%s>\n", + host_address_to_string (gdbarch->remove_non_address_bits_memory)); gdb_printf (file, "gdbarch_dump: memtag_to_string = <%s>\n", host_address_to_string (gdbarch->memtag_to_string)); @@ -3198,20 +3208,54 @@ set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, } CORE_ADDR -gdbarch_remove_non_address_bits (struct gdbarch *gdbarch, CORE_ADDR pointer) +gdbarch_remove_non_address_bits_watchpoint (struct gdbarch *gdbarch, CORE_ADDR pointer) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->remove_non_address_bits_watchpoint != NULL); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_remove_non_address_bits_watchpoint called\n"); + return gdbarch->remove_non_address_bits_watchpoint (gdbarch, pointer); +} + +void +set_gdbarch_remove_non_address_bits_watchpoint (struct gdbarch *gdbarch, + gdbarch_remove_non_address_bits_watchpoint_ftype remove_non_address_bits_watchpoint) +{ + gdbarch->remove_non_address_bits_watchpoint = remove_non_address_bits_watchpoint; +} + +CORE_ADDR +gdbarch_remove_non_address_bits_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pointer) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->remove_non_address_bits_breakpoint != NULL); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_remove_non_address_bits_breakpoint called\n"); + return gdbarch->remove_non_address_bits_breakpoint (gdbarch, pointer); +} + +void +set_gdbarch_remove_non_address_bits_breakpoint (struct gdbarch *gdbarch, + gdbarch_remove_non_address_bits_breakpoint_ftype remove_non_address_bits_breakpoint) +{ + gdbarch->remove_non_address_bits_breakpoint = remove_non_address_bits_breakpoint; +} + +CORE_ADDR +gdbarch_remove_non_address_bits_memory (struct gdbarch *gdbarch, CORE_ADDR pointer) { gdb_assert (gdbarch != NULL); - gdb_assert (gdbarch->remove_non_address_bits != NULL); + gdb_assert (gdbarch->remove_non_address_bits_memory != NULL); if (gdbarch_debug >= 2) - gdb_printf (gdb_stdlog, "gdbarch_remove_non_address_bits called\n"); - return gdbarch->remove_non_address_bits (gdbarch, pointer); + gdb_printf (gdb_stdlog, "gdbarch_remove_non_address_bits_memory called\n"); + return gdbarch->remove_non_address_bits_memory (gdbarch, pointer); } void -set_gdbarch_remove_non_address_bits (struct gdbarch *gdbarch, - gdbarch_remove_non_address_bits_ftype remove_non_address_bits) +set_gdbarch_remove_non_address_bits_memory (struct gdbarch *gdbarch, + gdbarch_remove_non_address_bits_memory_ftype remove_non_address_bits_memory) { - gdbarch->remove_non_address_bits = remove_non_address_bits; + gdbarch->remove_non_address_bits_memory = remove_non_address_bits_memory; } std::string diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index 4006380076d..cc7c6d8677b 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -1232,18 +1232,55 @@ possible it should be in TARGET_READ_PC instead). Method( comment=""" On some architectures, not all bits of a pointer are significant. -On AArch64, for example, the top bits of a pointer may carry a "tag", which -can be ignored by the kernel and the hardware. The "tag" can be regarded as -additional data associated with the pointer, but it is not part of the address. +On AArch64 and amd64, for example, the top bits of a pointer may carry a +"tag", which can be ignored by the kernel and the hardware. The "tag" can be +regarded as additional data associated with the pointer, but it is not part +of the address. Given a pointer for the architecture, this hook removes all the -non-significant bits and sign-extends things as needed. It gets used to remove -non-address bits from data pointers (for example, removing the AArch64 MTE tag -bits from a pointer) and from code pointers (removing the AArch64 PAC signature -from a pointer containing the return address). +non-significant bits and sign-extends things as needed. It gets used to +remove non-address bits from pointers used for watchpoints. """, type="CORE_ADDR", - name="remove_non_address_bits", + name="remove_non_address_bits_watchpoint", + params=[("CORE_ADDR", "pointer")], + predefault="default_remove_non_address_bits", + invalid=False, +) + +Method( + comment=""" +On some architectures, not all bits of a pointer are significant. +On AArch64 and amd64, for example, the top bits of a pointer may carry a +"tag", which can be ignored by the kernel and the hardware. The "tag" can be +regarded as additional data associated with the pointer, but it is not part +of the address. + +Given a pointer for the architecture, this hook removes all the +non-significant bits and sign-extends things as needed. It gets used to +remove non-address bits from pointers used for breakpoints. +""", + type="CORE_ADDR", + name="remove_non_address_bits_breakpoint", + params=[("CORE_ADDR", "pointer")], + predefault="default_remove_non_address_bits", + invalid=False, +) + +Method( + comment=""" +On some architectures, not all bits of a pointer are significant. +On AArch64 and amd64, for example, the top bits of a pointer may carry a +"tag", which can be ignored by the kernel and the hardware. The "tag" can be +regarded as additional data associated with the pointer, but it is not part +of the address. + +Given a pointer for the architecture, this hook removes all the +non-significant bits and sign-extends things as needed. It gets used to +remove non-address bits from any pointer used to access memory. +""", + type="CORE_ADDR", + name="remove_non_address_bits_memory", params=[("CORE_ADDR", "pointer")], predefault="default_remove_non_address_bits", invalid=False, diff --git a/gdb/target.c b/gdb/target.c index 1b5aa11ed6f..b622de81e11 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1608,7 +1608,8 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object, if (len == 0) return TARGET_XFER_EOF; - memaddr = gdbarch_remove_non_address_bits (current_inferior ()->arch (), + memaddr + = gdbarch_remove_non_address_bits_memory (current_inferior ()->arch (), memaddr); /* Fill in READBUF with breakpoint shadows, or WRITEBUF with From patchwork Thu Jul 4 10:17:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 93340 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EE361384A458 for ; Thu, 4 Jul 2024 10:19:27 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) by sourceware.org (Postfix) with ESMTPS id 5061A384A80B for ; Thu, 4 Jul 2024 10:18:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5061A384A80B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5061A384A80B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720088332; cv=none; b=cUy+rVWxFCpd0InSudNa3pX2IPLfkCR/O/2SB05nCBpCeWljm1r8EdQvEbv4zI6dTGPHGk3pCpNZJxTIohEwNUeP6feUhQkikrXn9JPUX/1Y4rWEk1hsZ3ZJOPEgPxKFM4aeiZJoKpvOFOg4GNBw8/YA/4x5omBqkxj9TvTnBJE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720088332; c=relaxed/simple; bh=96qSpoZkw042rTKTZ1kGA78u26EXzzkuavCEW3z4i3o=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=NEKGMTMnshOrbCum/7FnOiwvf34qPuwrrtyhOUCj6eqLsSKKxLqzNekGP9bQogOte58M8rQhHFTJn6M6CSsoBfWiQReRl0zWlBzNc6whVmmjHW+iBy69K9aaoJyAzar/2r00T79sOJWnBhE3F8TsQB9idg5yxXpJxaDh5rhJsdg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720088329; x=1751624329; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=96qSpoZkw042rTKTZ1kGA78u26EXzzkuavCEW3z4i3o=; b=nhugfPEwNZQcoMjuVjEDlM4XxqBhzVIMLKflkYwNe8WSSLW/87d+v4Nz vDBSkGc9IM49tWt1abdTd+CdIEJ/tZDLX8Xt2KZszddhjGiKX/Kbzae6N ToeIdGqZvOF4iOPIbzkmjsyGpmdKRZQYKvAKoZZZrVASC1hI1edr2fzh2 p64xpji2o8hxp1xGcuooE3g1sTH14Z4CRjJjvYYGLdlsCD1QLnUzrezqU wthRcE7jGlwDPtfqZmHKnfI8WsvtsnBJoIrV75AAo3BgyXE59EyLl9TBR tVjMg+cJl7TEXG1XzY/elegtj9q1EuvuzdoTHPGkFSPv2zXHXjI5kp09N Q==; X-CSE-ConnectionGUID: DWu7hCcSTIagBM+cm3Rcaw== X-CSE-MsgGUID: Jt35xatAT3CyY+sL2FkmLA== X-IronPort-AV: E=McAfee;i="6700,10204,11122"; a="17501304" X-IronPort-AV: E=Sophos;i="6.09,183,1716274800"; d="scan'208";a="17501304" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Jul 2024 03:18:49 -0700 X-CSE-ConnectionGUID: 0SX7wM/7RCSZGRbU5AzFwQ== X-CSE-MsgGUID: rE3JKIXFTi+drudFow4T8g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,183,1716274800"; d="scan'208";a="50999813" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Jul 2024 03:18:47 -0700 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Cc: felix.willgerodt@intel.com, luis.machado@arm.com Subject: [PATCH v4 2/2] LAM: Enable tagged pointer support for watchpoints. Date: Thu, 4 Jul 2024 10:17:36 +0000 Message-Id: <20240704101736.3074236-3-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240704101736.3074236-1-christina.schimpe@intel.com> References: <20240704101736.3074236-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, 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~patchwork=sourceware.org@sourceware.org From: Christina Schimpe The Intel (R) linear address masking (LAM) feature modifies the checking applied to 64-bit linear addresses. With this so-called "modified canonicality check" the processor masks the metadata bits in a pointer before using it as a linear address. LAM supports two different modes that differ regarding which pointer bits are masked and can be used for metadata: LAM 48 resulting in a LAM width of 15 and LAM 57 resulting in a LAM width of 6. This patch adjusts watchpoint addresses based on the currently enabled LAM mode using the untag mask provided in the /proc//status file. As LAM can be enabled at runtime or as the configuration may change when entering an enclave, GDB checks enablement state each time a watchpoint is updated. In contrast to the patch implemented for ARM's Top Byte Ignore "Clear non-significant bits of address on memory access", it is not necessary to adjust addresses before they are passed to the target layer cache, as for LAM tagged pointers are supported by the system call to read memory. Additionally, LAM applies only to addresses used for data accesses. Thus, it is sufficient to mask addresses used for watchpoints. The following examples are based on a LAM57 enabled program. Before this patch tagged pointers were not supported for watchpoints: ~~~ (gdb) print pi_tagged $2 = (int *) 0x10007ffffffffe004 (gdb) watch *pi_tagged Hardware watchpoint 2: *pi_tagged (gdb) c Continuing. Couldn't write debug register: Invalid argument. ~~~~ Once LAM 48 or LAM 57 is enabled for the current program, GDB can now specify watchpoints for tagged addresses with LAM width 15 or 6, respectively. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 2 + gdb/amd64-linux-tdep.c | 64 ++++++++++++++++++++++++++++ gdb/testsuite/gdb.arch/amd64-lam.c | 49 +++++++++++++++++++++ gdb/testsuite/gdb.arch/amd64-lam.exp | 46 ++++++++++++++++++++ gdb/testsuite/lib/gdb.exp | 63 +++++++++++++++++++++++++++ 5 files changed, 224 insertions(+) create mode 100755 gdb/testsuite/gdb.arch/amd64-lam.c create mode 100644 gdb/testsuite/gdb.arch/amd64-lam.exp diff --git a/gdb/NEWS b/gdb/NEWS index 47677cb773a..fcbb89e8bf8 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,8 @@ *** Changes since GDB 15 +* GDB now supports watchpoints for tagged data pointers on amd64. + * Debugger Adapter Protocol changes ** The "scopes" request will now return a scope holding global diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index d7662cac572..88e14251d7d 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -43,6 +43,7 @@ #include "target-descriptions.h" #include "expop.h" #include "arch/amd64-linux-tdesc.h" +#include "inferior.h" /* The syscall's XML filename for i386. */ #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml" @@ -50,6 +51,10 @@ #include "record-full.h" #include "linux-record.h" +#include + +#define DEFAULT_TAG_MASK 0xffffffffffffffffULL + /* Mapping between the general-purpose registers in `struct user' format and GDB's register cache layout. */ @@ -1765,6 +1770,62 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch, } } +/* Extract the untagging mask based on the currently active linear address + masking (LAM) mode, which is stored in the /proc//status file. + If we cannot extract the untag mask (for example, if we don't have + execution), we assume address tagging is not enabled and return the + DEFAULT_TAG_MASK. */ + +static CORE_ADDR +amd64_linux_lam_untag_mask () +{ + if (!target_has_execution ()) + return DEFAULT_TAG_MASK; + + inferior *inf = current_inferior (); + if (inf->fake_pid_p) + return DEFAULT_TAG_MASK; + + const std::string filename = string_printf ("/proc/%d/status", inf->pid); + gdb::unique_xmalloc_ptr status_file + = target_fileio_read_stralloc (nullptr, filename.c_str ()); + + if (status_file == nullptr) + return DEFAULT_TAG_MASK; + + std::string_view status_file_view (status_file.get ()); + constexpr std::string_view untag_mask_str = "untag_mask:\t"; + const size_t found = status_file_view.find (untag_mask_str); + if (found != std::string::npos) + { + const char* start = status_file_view.data() + found + + untag_mask_str.length (); + char* endptr; + errno = 0; + unsigned long long result = std::strtoul (start, &endptr, 0); + if (errno != 0 || endptr == start) + error (_("Failed to parse untag_mask from file %s."), + std::string (filename).c_str ()); + + return result; + } + + return DEFAULT_TAG_MASK; +} + +/* Adjust watchpoint address based on the currently active linear address + masking (LAM) mode using the untag mask. Check each time for a new + mask, as LAM is enabled at runtime. */ + +static CORE_ADDR +amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch, + CORE_ADDR addr) +{ + /* Clear insignificant bits of a target address using the untag + mask. */ + return (addr & amd64_linux_lam_untag_mask ()); +} + static void amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, int num_disp_step_buffers) @@ -1819,6 +1880,9 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, set_gdbarch_get_siginfo_type (gdbarch, x86_linux_get_siginfo_type); set_gdbarch_report_signal_info (gdbarch, i386_linux_report_signal_info); + + set_gdbarch_remove_non_address_bits_watchpoint + (gdbarch, amd64_linux_remove_non_address_bits_watchpoint); } static void diff --git a/gdb/testsuite/gdb.arch/amd64-lam.c b/gdb/testsuite/gdb.arch/amd64-lam.c new file mode 100755 index 00000000000..0fe2bc6c2ad --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-lam.c @@ -0,0 +1,49 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2023-2024 Free Software Foundation, Inc. + + 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 . */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + int i; + int* pi = &i; + int* pi_tagged; + + /* Enable LAM 57. */ + errno = 0; + syscall (SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, 6); + assert_perror (errno); + + /* Add tagging at bit 61. */ + pi_tagged = (int *) ((uintptr_t) pi | (1LL << 60)); + + i = 0; /* Breakpoint here. */ + *pi = 1; + *pi_tagged = 2; + *pi = 3; + *pi_tagged = 4; + + return 0; +} diff --git a/gdb/testsuite/gdb.arch/amd64-lam.exp b/gdb/testsuite/gdb.arch/amd64-lam.exp new file mode 100644 index 00000000000..0bcbb639b66 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-lam.exp @@ -0,0 +1,46 @@ +# Copyright 2023-2024 Free Software Foundation, Inc. + +# 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 . + +# Test Linear Address Masking (LAM) support. + +require allow_lam_tests + +standard_testfile amd64-lam.c + +# Test LAM 57. +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 +} + +if { ![runto_main] } { + return -1 +} + +gdb_breakpoint [gdb_get_line_number "Breakpoint here"] +gdb_continue_to_breakpoint "Breakpoint here" + +# Test hw watchpoint for a tagged and an untagged address with hit on a +# tagged and an untagged address each. + +foreach symbol {"pi" "pi_tagged"} { + gdb_test "watch *${symbol}" + gdb_test "continue" \ + "Continuing\\..*Hardware watchpoint \[0-9\]+.*" \ + "run until watchpoint on ${symbol}" + gdb_test "continue" \ + "Continuing\\..*Hardware watchpoint \[0-9\]+.*" \ + "run until watchpoint on ${symbol}, 2nd hit" + delete_breakpoints +} diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index dfe19c9410d..4cfda74fc43 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -4154,6 +4154,69 @@ gdb_caching_proc allow_avx512fp16_tests {} { return $allow_avx512fp16_tests } +# Run a test on the target to see if it supports LAM 57. Return 1 if so, +# 0 if it does not. Based on the arch_prctl() handle ARCH_ENABLE_TAGGED_ADDR +# to enable LAM which fails if the hardware or the OS does not support LAM. + +gdb_caching_proc allow_lam_tests {} { + global gdb_prompt inferior_exited_re + + set me "allow_lam_tests" + if { ![istarget "x86_64-*-*"] } { + verbose "$me: target does not support LAM, returning 1" 2 + return 0 + } + + # Compile a test program. + set src { + #define _GNU_SOURCE + #include + #include + #include + #include + + int configure_lam () + { + errno = 0; + syscall (SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, 6); + assert_perror (errno); + return errno; + } + + int + main () { return configure_lam (); } + } + + if {![gdb_simple_compile $me $src executable ""]} { + return 0 + } + # No error message, compilation succeeded so now run it via gdb. + + set allow_lam_tests 0 + clean_restart $obj + gdb_run_cmd + gdb_expect { + -re ".*$inferior_exited_re with code.*${gdb_prompt} $" { + verbose -log "$me: LAM support not detected." + } + -re ".*Program received signal SIGABRT, Aborted.*${gdb_prompt} $" { + verbose -log "$me: LAM support not detected." + } + -re ".*$inferior_exited_re normally.*${gdb_prompt} $" { + verbose -log "$me: LAM support detected." + set allow_lam_tests 1 + } + default { + warning "\n$me: default case taken." + } + } + gdb_exit + remote_file build delete $obj + + verbose "$me: returning $allow_lam_tests" 2 + return $allow_lam_tests +} + # Run a test on the target to see if it supports btrace hardware. Return 1 if so, # 0 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite.