From patchwork Fri Dec 20 20:04:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103527 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 1D7343858C51 for ; Fri, 20 Dec 2024 20:11:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1D7343858C51 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=XPrmwq81 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.21]) by sourceware.org (Postfix) with ESMTPS id A5A653858C35 for ; Fri, 20 Dec 2024 20:05:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A5A653858C35 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 A5A653858C35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.21 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725135; cv=none; b=F6u4dFEpoeFCo0khiuXX0fIv4ajYHanFxKVTD11HgyhvOGoh4LkhTCZQTfEMgpBGNqEln1v87Hzn8xJRZd7ZWCXpiVzamXBBvjGhWmV+DGE9toXf6d2kRnbdpy5Liopog+N5/j7EwQLSmQPo/AHpkKodMWA1acKSdmXrTM6qT5M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725135; c=relaxed/simple; bh=HzSJBWLhySogPtKHHz4CKeB9mqOcNB3oyGLrFkb/gj0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=X71x2AW3po1Vy0rXwOy0jXN5v93sTUjG9DPMBnU+mtBiIzAlNVQrhMSdIqsBvI6l0EO2TZOvylZkIYOB/8kDUXHxxuSTcMCfbe2G+pSNMsCgV1woAPm758Jt52CfAt32nVIY0EOp+QIK+mH4Yd3SOarpCr/39mm8zI9a7oQrce4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A5A653858C35 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725136; x=1766261136; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=HzSJBWLhySogPtKHHz4CKeB9mqOcNB3oyGLrFkb/gj0=; b=XPrmwq81+qjFCw5au6D5FPlKbp+jxbGQmMSYih7P294D3Ep3WYctoAq1 TN9tZn5GtES0K2exS0Y4SPOHw1k8E5X+qxFTt9kpql3mGRPSNsB5jbf/C iRDU18o8b/aC58q51qG5ddE9T/+qMXcTltVcKf9wMdbAbS8sqaygZ5X+X q4G9C11AWEEXRo1LsaxsWz6dfXxsN9NUpG5atjPPE7I3EoUwQYQWMJ+Qr bdCl8q/NotxaRBSx1OhSJaGmkEM2X3wo+E7BFzlMLZ/McLm+eGBSyEtM1 Fh60KQnomxVN5aVTianKEVvTM640jr/C7O4Hy8poRFflya7+LWp3LuhMj w==; X-CSE-ConnectionGUID: 2FYHle4kQJOFJYcXq23NqQ== X-CSE-MsgGUID: kA2xIQCwR+eqiaE+r0TNLA== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="35174263" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="35174263" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa113.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:36 -0800 X-CSE-ConnectionGUID: AoTVJNjFQlymIQASUjknRQ== X-CSE-MsgGUID: l50oUuX5RaWK4DIIpeZ7yw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="121877515" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:34 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment. Date: Fri, 20 Dec 2024 20:04:50 +0000 Message-Id: <20241220200501.324191-2-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-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 The procedure set_sanitizer_default has been used for the configuration of ASAN specific environment variables. However, it is actually a generic function. Rename it to append_environment so that its purpose is more clear. --- gdb/testsuite/gdb.base/libsegfault.exp | 2 +- gdb/testsuite/gdb.threads/attach-slow-waitpid.exp | 2 +- gdb/testsuite/lib/gdb.exp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gdb/testsuite/gdb.base/libsegfault.exp b/gdb/testsuite/gdb.base/libsegfault.exp index 2c16fe8932a..fb62bdb8746 100644 --- a/gdb/testsuite/gdb.base/libsegfault.exp +++ b/gdb/testsuite/gdb.base/libsegfault.exp @@ -42,7 +42,7 @@ proc gdb_spawn_with_ld_preload {lib cmdline_opts} { # ASan runtime does not come first in initial library list; you should # either link runtime to your application or manually preload it with # LD_PRELOAD. - set_sanitizer_default ASAN_OPTIONS verify_asan_link_order 0 + append_environment ASAN_OPTIONS verify_asan_link_order 0 gdb_spawn_with_cmdline_opts $cmdline_opts } diff --git a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp index 28d70daad8c..abe8d434558 100644 --- a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp +++ b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp @@ -83,7 +83,7 @@ proc gdb_spawn_with_ld_preload {lib} { # ASan runtime does not come first in initial library list; you should # either link runtime to your application or manually preload it with # LD_PRELOAD. - set_sanitizer_default ASAN_OPTIONS verify_asan_link_order 0 + append_environment ASAN_OPTIONS verify_asan_link_order 0 gdb_start } diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 7ee2043f0f8..a86f534528c 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -76,11 +76,11 @@ proc set_sanitizer { env_var var_id val } { # Add VAR_ID=VAL to ENV_VAR, unless ENV_VAR already contains a VAR_ID setting. -proc set_sanitizer_default { env_var var_id val } { +proc append_environment { env_var var_id val } { set_sanitizer_1 $env_var $var_id $val 1 } -set_sanitizer_default TSAN_OPTIONS suppressions \ +append_environment TSAN_OPTIONS suppressions \ $srcdir/../tsan-suppressions.txt # When using ThreadSanitizer we may run into the case that a race is detected, @@ -89,14 +89,14 @@ set_sanitizer_default TSAN_OPTIONS suppressions \ # Try to prevent this by setting history_size to the maximum (7) by default. # See also the ThreadSanitizer docs ( # https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags ). -set_sanitizer_default TSAN_OPTIONS history_size 7 +append_environment TSAN_OPTIONS history_size 7 # If GDB is built with ASAN (and because there are leaks), it will output a # leak report when exiting as well as exit with a non-zero (failure) status. # This can affect tests that are sensitive to what GDB prints on stderr or its # exit status. Add `detect_leaks=0` to the ASAN_OPTIONS environment variable # (which will affect any spawned sub-process) to avoid this. -set_sanitizer_default ASAN_OPTIONS detect_leaks 0 +append_environment ASAN_OPTIONS detect_leaks 0 # List of procs to run in gdb_finish. set gdb_finish_hooks [list] From patchwork Fri Dec 20 20:04:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103523 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 53CDA3858C51 for ; Fri, 20 Dec 2024 20:07:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 53CDA3858C51 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=UJj3Orrh X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.21]) by sourceware.org (Postfix) with ESMTPS id BBF493858CD1 for ; Fri, 20 Dec 2024 20:05:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BBF493858CD1 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 BBF493858CD1 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.21 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725144; cv=none; b=QjxwvAfGdxjrC1EI73B91+x8q1um9o/ZDrcCAO9z+DAqdPRdvLxNatA5jr0z2o2ILMNDFifiokgsQAXJ5PKSndswQF1tY+ezWxMsiTjZwXaiilfB3qX2fC0BjqGDywYQOg4utZCf171emMXSvJMf2atfmhGDRqoxQIzjQ3B0nkM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725144; c=relaxed/simple; bh=cFPWvaFyj/J/zQdyJf2gCj8oxqxo9q5gDVfDo3Q7CF8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ZEBx7mA2FFw3b2OOhUAD9C/KOHi9vINK6+1Y/JrzmIEU5eCZ8I8c75+o++vMxpz0m+FhgazSiRlh+fpZas7bMjyJjOs35etnMMBYxaavz32pLRaIuB5Iy1EiArGnYf2SNl0N2OVjApS4f/hDFRaLDRGivA7NY+B7AXP7JPjm/iQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BBF493858CD1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725144; x=1766261144; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=cFPWvaFyj/J/zQdyJf2gCj8oxqxo9q5gDVfDo3Q7CF8=; b=UJj3Orrhdu8gkdqAzbwG2NpxxxVMmNegOF7/AUHb14vMrRlEx6KYn6DQ Q89oV83sldA60S9sJe9W0eYojw6YkOE4NivD7nU+IhU5W/hJ0oReo97DH zaWmiKay2OnTIk2k0cjn1DFbAGMZHst3gnTdlOKiWvEZuvkUMe/GH09u4 wYhhCHCUvkPm+N0Ec21RH2yifDsxdLCgo3/u9DWINHzK4ssfj0Iae0BVo pHWHObvig9og/NU+yH4qpnwNTbfHdEw/+4wxDrzHUkRe8kaCQOcAL19Y4 WEkEN59m4ZFotDLu/M64Ywrucb4dIwKmrzEHpv0hLCG7vpVSoMzHud+NN A==; X-CSE-ConnectionGUID: 9PZdqWMMT5qtERtSApwQYg== X-CSE-MsgGUID: W/SdYgLNQ2Kp9Waxb/1eQA== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="35174323" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="35174323" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa113.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:44 -0800 X-CSE-ConnectionGUID: tj4HzxYIQ2ak7tJUNfkEDw== X-CSE-MsgGUID: AYy4S2YESK2BpwdbXsyEhg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="121877561" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:42 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 02/12] gdbserver: Add optional runtime register set type. Date: Fri, 20 Dec 2024 20:04:51 +0000 Message-Id: <20241220200501.324191-3-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-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 Some register sets can be activated and deactivated by the OS during the runtime of a process. One example register is the Intel CET shadow stack pointer. This adds a new type of register set to handle such cases. We shouldn't deactivate these regsets and should not show a warning if we fail to read them. --- gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------ gdbserver/linux-low.h | 7 ++++++- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index 50ce2b44927..355b28d9fe4 100644 --- a/gdbserver/linux-low.cc +++ b/gdbserver/linux-low.cc @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info, if (res < 0) { if (errno == EIO - || (errno == EINVAL && regset->type == OPTIONAL_REGS)) + || (errno == EINVAL + && (regset->type == OPTIONAL_REGS + || regset->type == OPTIONAL_RUNTIME_REGS))) { /* If we get EIO on a regset, or an EINVAL and the regset is - optional, do not try it again for this process mode. */ + optional, do not try it again for this process mode. + Even if the regset can be enabled at runtime it is safe + to deactivate the regset in case of EINVAL, as we know + the regset itself was the invalid argument of the ptrace + call. */ disable_regset (regsets_info, regset); } - else if (errno == ENODATA) + else if (errno == ENODATA + || (errno == ENODEV + && regset->type == OPTIONAL_RUNTIME_REGS) + || errno == ESRCH) { - /* ENODATA may be returned if the regset is currently - not "active". This can happen in normal operation, - so suppress the warning in this case. */ - } - else if (errno == ESRCH) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to read its registers. */ + /* ENODATA or ENODEV may be returned if the regset is + currently not "active". For ENODEV we additionally check + if the register set is of type OPTIONAL_RUNTIME_REGS. + This can happen in normal operation, so suppress the + warning in this case. + ESRCH should mean the process is already gone at this + point, in which case we simply ignore attempts to read + its registers. */ } else { @@ -5111,6 +5119,14 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info, optional, do not try it again for this process mode. */ disable_regset (regsets_info, regset); } + else if (errno == ENODEV + && regset->type == OPTIONAL_RUNTIME_REGS) + { + /* If we get ENODEV on a regset and the regset can be + enabled at runtime try it again for this process mode. + This can happen in normal operation, so suppress the + warning in this case. */ + } else if (errno == ESRCH) { /* At this point, ESRCH should mean the process is diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h index 5be00b8c98c..da5aa26a993 100644 --- a/gdbserver/linux-low.h +++ b/gdbserver/linux-low.h @@ -42,7 +42,12 @@ enum regset_type { GENERAL_REGS, FP_REGS, EXTENDED_REGS, - OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */ + OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. + Disable the regset instead. */ + OPTIONAL_RUNTIME_REGS, /* Some optional regsets can only be accessed + dependent on the execution flow. For such + access errors don't show a warning and don't + disable the regset. */ }; /* The arch's regsets array initializer must be terminated with a NULL From patchwork Fri Dec 20 20:04:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103522 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 63ADF3858C39 for ; Fri, 20 Dec 2024 20:07:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 63ADF3858C39 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=YFigGExh X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.21]) by sourceware.org (Postfix) with ESMTPS id E776A3858403 for ; Fri, 20 Dec 2024 20:05:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E776A3858403 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 E776A3858403 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.21 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725151; cv=none; b=JTkaDWIF9opTSmrY/Teml+dAUmFpm9Av1H8Dn6fq7of83YbLEMiWUlVUyWin5Xd6wf9+N8bzgx/3gFki3ZsYo/PeUoHlsJkmjhHmpzaJbN7Kk4673Zq8XiaiWBKazUGEyShjRXLqso7WZ3WMI50hI4+zBFYJ9ZPzpwiFZcI67pQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725151; c=relaxed/simple; bh=Dh8XS5g+1rdw82V2baxFLCwKAgYvtji0wdmZDL0BAdk=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ow4sGw8IKxRZUHt2hpafD52BRusJ//UnnGVSixV6P7vlcRQWD1kSYy7Br8sKa/JRLVgqvR0E8LVGeGs8D6okMa9Z6byfEHQyf2CWAeNTUEJYNE1yUiJ7wRrAu0M4xg5HG0d4pc+ULDXvN0agoHUKRx/yBvHfAmTFiUtYD78X5uo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E776A3858403 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725151; x=1766261151; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=Dh8XS5g+1rdw82V2baxFLCwKAgYvtji0wdmZDL0BAdk=; b=YFigGExhBsDGc7xpyva2+Hkj3UiHqzF7mRg+UttPBxGFrbdpi1H7DIV/ swgQB7/mVyWGYh1vQ6GbVed1aGVbZDj5ZVPF9ke27PcO5EN6qOXf1Vb74 p7DPCcFR7R82amDDDBLd51wjbMCpJEVKxlMaW5gufhM+miaQCdTnmIFqL jp83zwsnGT3EiJj3SB5ARzHjA10wQjZoUFTkY8O4dLoBU0SxrG197bCVL 7dgkGL22lxqF98xAxhRYw1RrU4npilJeG/sjUR29R2+zDJKQWXUmgDqAT 6qg1nDpzWTieLocIarFn9LR3k3tWdOZEf3Fj7BFuTSrGRDLmk2Z8xR7k/ A==; X-CSE-ConnectionGUID: 3xmaJCtxRHWr0xrNvjVE1w== X-CSE-MsgGUID: MhPjC5UCTLuIzUrb/q8MKA== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="35174349" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="35174349" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa113.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:51 -0800 X-CSE-ConnectionGUID: hTG+lGfFSeeCc0t5Qt0Chw== X-CSE-MsgGUID: drSPL6SPTrmPthu9H/AdeQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="121877630" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:49 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description. Date: Fri, 20 Dec 2024 20:04:52 +0000 Message-Id: <20241220200501.324191-4-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-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 On x86 the PTRACE_GETREGSET request is currently only used for the xstate regset. The size of the xstate regset is initialized to 0 such that it can be reset to the appropriate size once we know it is supported for the current target in x86_linux_read_description. However, this configuration would not just affect the xstate regset but any regset with PTRACE_GETREGSET request that is added in the future. The new regset would be misconfigured with the xstate regset size. To avoid this we add an assert for unsupported regsets and check explicitly for the note type of the register set. Reviewed-by: Thiago Jung Bauermann --- gdbserver/linux-x86-low.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc index 6c2688d3678..b023b34a0a4 100644 --- a/gdbserver/linux-x86-low.cc +++ b/gdbserver/linux-x86-low.cc @@ -894,7 +894,12 @@ x86_linux_read_description () regset++) { if (regset->get_request == PTRACE_GETREGSET) - regset->size = xsave_len; + { + if (regset->nt_type == NT_X86_XSTATE) + regset->size = xsave_len; + else + gdb_assert_not_reached ("invalid regset type."); + } else if (regset->type != GENERAL_REGS) regset->size = 0; } From patchwork Fri Dec 20 20:04:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103528 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 BB0343858C39 for ; Fri, 20 Dec 2024 20:11:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BB0343858C39 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=FBJw/Jc1 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.21]) by sourceware.org (Postfix) with ESMTPS id 660DE3858C3A for ; Fri, 20 Dec 2024 20:05:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 660DE3858C3A 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 660DE3858C3A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.21 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725157; cv=none; b=hnV1Z3sR4vbLnlL/Jjfm6cQJ7NIZnU6zUprS4VYqDSIgfIlc5dNL4JP7DYMGrcFoxmgq2YYlchCLDl6ldfE3SRyAAdb8Is3cgr8SdxbCNg+3lkLCtwkTbPfg9yHWl38bNHM7z949l2wTXNxXUBwkn+hUaFUaqoBGz7CSfKJ6Tmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725157; c=relaxed/simple; bh=rBmFimxDBVDP+Uzbpg0YLdM896kRiSnBNCKjTEwaOQw=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=JmcHg4C2EHHaz3Y28vkl6uhOw/rfKZQTFrWiz7osVzgpKN2/bdn7Zxezs7rdX6PtwZXr+nn9D6mUNJEL3p/kWAeMK+i1fJcTDmd0cuuBZU8PXHTqvBvBCONL47DxcxrUMpBZU9OHQhDTP74z2IXUR/zr5P8U9p/cZHv0wO/1QMk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 660DE3858C3A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725158; x=1766261158; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=rBmFimxDBVDP+Uzbpg0YLdM896kRiSnBNCKjTEwaOQw=; b=FBJw/Jc1xLiNEwYzR+Fojj/coHJwEXHo4FtUsLE9jRJsKWSF9rnIbqZG CFM1DuGklKW3wbwlfqdu6ijxRxZdz9U+1/LzHrs9pCuPJfU8SPw9oDMQr LDzzvYR8u9joH81upNjH+3yymOc81z5PEf1Ev+gHKpLVzK4+srazBI6KQ mGM5LjvU7JHfF12/sgVudrMEh6w62adeVXiSbCE9TTwtSTSmQAAsH0dD0 b8Wf4iF7IdujDMEgLL+3rIEWiCIpk0pesw8Md+NbZPEbG+rGPx2Q1qHJP q9S98SurFP3u9bo3JbA45LJ6AOQYTpXU96DEUrNEeWuOpqUsDQeMrLttp w==; X-CSE-ConnectionGUID: x2UVIdyGQeO0LGoVqyKwLA== X-CSE-MsgGUID: QXp5GY86T2ukdzDVhqvlzg== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="35174364" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="35174364" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa113.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:57 -0800 X-CSE-ConnectionGUID: OVLAk2U3QvaQRI2BPjvu4Q== X-CSE-MsgGUID: kRdwvaRoRz2z0YEOATeFDA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="121877688" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:05:56 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch. Date: Fri, 20 Dec 2024 20:04:53 +0000 Message-Id: <20241220200501.324191-5-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-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 This is required for a later commit which requires "bit_SHSTK". Reviewed-by: Thiago Jung Bauermann --- gdb/nat/x86-gcc-cpuid.h | 153 ++++++++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 31 deletions(-) diff --git a/gdb/nat/x86-gcc-cpuid.h b/gdb/nat/x86-gcc-cpuid.h index b0f2d239af3..a571eb8a734 100644 --- a/gdb/nat/x86-gcc-cpuid.h +++ b/gdb/nat/x86-gcc-cpuid.h @@ -1,5 +1,5 @@ /* - * Helper cpuid.h file copied from gcc-6.0.0. Code in gdb should not + * Helper cpuid.h file copied from gcc-14-2-0. Code in gdb should not * include this directly, but pull in x86-cpuid.h and use that func. */ @@ -55,7 +55,7 @@ #define bit_SSE (1 << 25) #define bit_SSE2 (1 << 26) -/* Extended Features */ +/* Extended Features (%eax == 0x80000001) */ /* %ecx */ #define bit_LAHF_LM (1 << 0) #define bit_ABM (1 << 5) @@ -68,29 +68,28 @@ #define bit_MWAITX (1 << 29) /* %edx */ -#define bit_AVX5124VNNIW (1 << 2) -#define bit_AVX5124FMAPS (1 << 3) #define bit_MMXEXT (1 << 22) #define bit_LM (1 << 29) #define bit_3DNOWP (1 << 30) -#define bit_3DNOW (1 << 31) +#define bit_3DNOW (1u << 31) -/* %ebx. */ +/* %ebx */ #define bit_CLZERO (1 << 0) +#define bit_WBNOINVD (1 << 9) -/* Extended Features (%eax == 7) */ +/* Extended Features Leaf (%eax == 7, %ecx == 0) */ /* %ebx */ #define bit_FSGSBASE (1 << 0) -#define bit_BMI (1 << 3) -#define bit_HLE (1 << 4) +#define bit_SGX (1 << 2) +#define bit_BMI (1 << 3) +#define bit_HLE (1 << 4) #define bit_AVX2 (1 << 5) #define bit_BMI2 (1 << 8) -#define bit_RTM (1 << 11) -#define bit_MPX (1 << 14) +#define bit_RTM (1 << 11) #define bit_AVX512F (1 << 16) #define bit_AVX512DQ (1 << 17) #define bit_RDSEED (1 << 18) -#define bit_ADX (1 << 19) +#define bit_ADX (1 << 19) #define bit_AVX512IFMA (1 << 21) #define bit_CLFLUSHOPT (1 << 23) #define bit_CLWB (1 << 24) @@ -99,23 +98,85 @@ #define bit_AVX512CD (1 << 28) #define bit_SHA (1 << 29) #define bit_AVX512BW (1 << 30) -#define bit_AVX512VL (1 << 31) +#define bit_AVX512VL (1u << 31) /* %ecx */ -#define bit_PREFETCHWT1 (1 << 0) +#define bit_PREFETCHWT1 (1 << 0) #define bit_AVX512VBMI (1 << 1) -#define bit_PKU (1 << 3) +#define bit_PKU (1 << 3) #define bit_OSPKE (1 << 4) +#define bit_WAITPKG (1 << 5) +#define bit_AVX512VBMI2 (1 << 6) +#define bit_SHSTK (1 << 7) +#define bit_GFNI (1 << 8) +#define bit_VAES (1 << 9) +#define bit_VPCLMULQDQ (1 << 10) +#define bit_AVX512VNNI (1 << 11) +#define bit_AVX512BITALG (1 << 12) +#define bit_AVX512VPOPCNTDQ (1 << 14) +#define bit_RDPID (1 << 22) +#define bit_KL (1 << 23) +#define bit_CLDEMOTE (1 << 25) +#define bit_MOVDIRI (1 << 27) +#define bit_MOVDIR64B (1 << 28) +#define bit_ENQCMD (1 << 29) -/* XFEATURE_ENABLED_MASK register bits (%eax == 13, %ecx == 0) */ -#define bit_BNDREGS (1 << 3) -#define bit_BNDCSR (1 << 4) +/* %edx */ +#define bit_AVX5124VNNIW (1 << 2) +#define bit_AVX5124FMAPS (1 << 3) +#define bit_UINTR (1 << 5) +#define bit_AVX512VP2INTERSECT (1 << 8) +#define bit_SERIALIZE (1 << 14) +#define bit_TSXLDTRK (1 << 16) +#define bit_PCONFIG (1 << 18) +#define bit_IBT (1 << 20) +#define bit_AMX_BF16 (1 << 22) +#define bit_AVX512FP16 (1 << 23) +#define bit_AMX_TILE (1 << 24) +#define bit_AMX_INT8 (1 << 25) + +/* Extended Features Sub-leaf (%eax == 7, %ecx == 1) */ +/* %eax */ +#define bit_SHA512 (1 << 0) +#define bit_SM3 (1 << 1) +#define bit_SM4 (1 << 2) +#define bit_RAOINT (1 << 3) +#define bit_AVXVNNI (1 << 4) +#define bit_AVX512BF16 (1 << 5) +#define bit_CMPCCXADD (1 << 7) +#define bit_AMX_COMPLEX (1 << 8) +#define bit_AMX_FP16 (1 << 21) +#define bit_HRESET (1 << 22) +#define bit_AVXIFMA (1 << 23) -/* Extended State Enumeration Sub-leaf (%eax == 13, %ecx == 1) */ +/* %edx */ +#define bit_AVXVNNIINT8 (1 << 4) +#define bit_AVXNECONVERT (1 << 5) +#define bit_AVXVNNIINT16 (1 << 10) +#define bit_PREFETCHI (1 << 14) +#define bit_USER_MSR (1 << 15) +#define bit_AVX10 (1 << 19) +#define bit_APX_F (1 << 21) + +/* Extended State Enumeration Sub-leaf (%eax == 0xd, %ecx == 1) */ #define bit_XSAVEOPT (1 << 0) #define bit_XSAVEC (1 << 1) #define bit_XSAVES (1 << 3) +/* PT sub leaf (%eax == 0x14, %ecx == 0) */ +/* %ebx */ +#define bit_PTWRITE (1 << 4) + +/* Keylocker leaf (%eax == 0x19) */ +/* %ebx */ +#define bit_AESKLE ( 1<<0 ) +#define bit_WIDEKL ( 1<<2 ) + +/* AVX10 sub leaf (%eax == 0x24) */ +/* %ebx */ +#define bit_AVX10_256 (1 << 17) +#define bit_AVX10_512 (1 << 18) + /* Signatures for different CPU implementations as returned in uses of cpuid with level 0. */ #define signature_AMD_ebx 0x68747541 @@ -170,19 +231,40 @@ #define signature_VORTEX_ecx 0x436f5320 #define signature_VORTEX_edx 0x36387865 -#define __cpuid(level, a, b, c, d) \ - __asm__ ("cpuid\n\t" \ - : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ - : "0" (level)) +#define signature_SHANGHAI_ebx 0x68532020 +#define signature_SHANGHAI_ecx 0x20206961 +#define signature_SHANGHAI_edx 0x68676e61 -#define __cpuid_count(level, count, a, b, c, d) \ - __asm__ ("cpuid\n\t" \ - : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ - : "0" (level), "2" (count)) +#ifndef __x86_64__ +/* At least one cpu (Winchip 2) does not set %ebx and %ecx + for cpuid leaf 1. Forcibly zero the two registers before + calling cpuid as a precaution. */ +#define __cpuid(level, a, b, c, d) \ + do { \ + if (__builtin_constant_p (level) && (level) != 1) \ + __asm__ __volatile__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level)); \ + else \ + __asm__ __volatile__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level), "1" (0), "2" (0)); \ + } while (0) +#else +#define __cpuid(level, a, b, c, d) \ + __asm__ __volatile__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level)) +#endif + +#define __cpuid_count(level, count, a, b, c, d) \ + __asm__ __volatile__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level), "2" (count)) /* Return highest supported input value for cpuid instruction. ext can - be either 0x0 or 0x8000000 to return highest supported value for + be either 0x0 or 0x80000000 to return highest supported value for basic or extended cpuid information. Function returns 0 if cpuid is not supported or whatever cpuid returns in eax register. If sig pointer is non-null, then first four bytes of the signature @@ -225,7 +307,7 @@ __get_cpuid_max (unsigned int __ext, unsigned int *__sig) : "i" (0x00200000)); #endif - if (!((__eax ^ __ebx) & 0x00200000)) + if (__builtin_expect (!((__eax ^ __ebx) & 0x00200000), 0)) return 0; #endif @@ -249,8 +331,9 @@ __get_cpuid (unsigned int __leaf, unsigned int *__ecx, unsigned int *__edx) { unsigned int __ext = __leaf & 0x80000000; + unsigned int __maxlevel = __get_cpuid_max (__ext, 0); - if (__get_cpuid_max (__ext, 0) < __leaf) + if (__maxlevel == 0 || __maxlevel < __leaf) return 0; __cpuid (__leaf, *__eax, *__ebx, *__ecx, *__edx); @@ -265,12 +348,20 @@ __get_cpuid_count (unsigned int __leaf, unsigned int __subleaf, unsigned int *__ecx, unsigned int *__edx) { unsigned int __ext = __leaf & 0x80000000; + unsigned int __maxlevel = __get_cpuid_max (__ext, 0); - if (__get_cpuid_max (__ext, 0) < __leaf) + if (__builtin_expect (__maxlevel == 0, 0) || __maxlevel < __leaf) return 0; __cpuid_count (__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx); return 1; } +static __inline void +__cpuidex (int __cpuid_info[4], int __leaf, int __subleaf) +{ + __cpuid_count (__leaf, __subleaf, __cpuid_info[0], __cpuid_info[1], + __cpuid_info[2], __cpuid_info[3]); +} + #endif /* GDB_NAT_X86_GCC_CPUID_H */ From patchwork Fri Dec 20 20:04:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103530 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 140503858D38 for ; Fri, 20 Dec 2024 20:13:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 140503858D38 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=Bl6tP3qw X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.21]) by sourceware.org (Postfix) with ESMTPS id 9D5B83858C2B for ; Fri, 20 Dec 2024 20:06:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9D5B83858C2B 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 9D5B83858C2B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.21 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725164; cv=none; b=cw//irQD8/8SFj/VdKN9JAK9SpFVCXp6kz1umqX6nwFv0iQQNJk91e43mXV8KAjoY2RmSfPQQMqvbIdBt360r6vzouPMzIjBfV9FggD3At6OQo4elyisV9MMP17ug06NuolFlYp4LQi+0Y63/NRyQRzmkraN0u1oK+NFHT6Xac4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725164; c=relaxed/simple; bh=t1dWdl+lsRItmrLgSj8ibzvtXVMWS4auS4yc/LJJN2o=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=IORLCzHh4/WxUe2XHsdqzlmq0a8jsdRfbbDzt/j9nN4r6S1tNVxhz7Cm3esKOimdHxdcoEB7bU1EL+bafykOTQHjac63YyJ8ibKxBaIrbeW0slVQQ02YQ2sO4tvl5jPIZ623yy40vCRDFfCzIFMY01EzwFXbtbaXo1oZZGuXj7Q= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9D5B83858C2B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725164; x=1766261164; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=t1dWdl+lsRItmrLgSj8ibzvtXVMWS4auS4yc/LJJN2o=; b=Bl6tP3qw5hgUGgu6nRFdp28ohKbgD1qLeVS8bGhbg9j32k/QOXjcCxQv 1z6Ldu/eIbeziiWDbUMDOgIP8BON+JJ/5FeOKdv0Cf8biKZseqMddluRu 0syu69CStfQng7YsVezlAg1pVLQKOmBzCj3mhGqZF1T7z1DWP+RlLdpXM JG66gJTHcFn0VmXTm4E29ssr3JbSPSlUNUGhWAUnbTTxZ29XjGCh4TTDq xSwiqPUsUYN/Oo8IrAhJJUic+ZVkZggvuvXBWtH9WpakHGi9BJC9WH/NT FPQWBfnSoRbbui7n3NGAqTow/u133CqUTltf8QFpsRnm1qatN8jp8Poid Q==; X-CSE-ConnectionGUID: VukRAgM2SZmorMdmAeyMUw== X-CSE-MsgGUID: S1yOHbMnR7OUSSd3kG/7Kw== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="35174377" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="35174377" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa113.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:03 -0800 X-CSE-ConnectionGUID: b0TOmu44S1a44qkVGdVmAA== X-CSE-MsgGUID: s4fWxwdjQYmdNwvozI8Pgg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="121877744" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:02 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86. Date: Fri, 20 Dec 2024 20:04:54 +0000 Message-Id: <20241220200501.324191-6-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-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 The XSAVE features set is organized in state components, which are a set of or parts of registers. So-called XSAVE-supported features are organized using state-component bitmaps, each bit corresonding to a single state component. The SDM uses the term xstate_bv for a state-component bitmap, which is defined as XCR0 | IA32_XSS. The control register XCR0 only contains a state-component bitmap that specifies user state components, while IA32_XSS contains a state-component bitmap that specifies supervisor state components. Until now, XCR0 is used as input for target description creation in GDB. However, a following patch will add userspace support for the CET shadow stack feature by Intel. The CET state is configured in IA32_XSS and consists of 2 state components: - State component 11 used for the 2 MSRs controlling user-mode functionality for CET (CET_U state) - State component 12 used for the 3 MSRs containing shadow-stack pointers for privilege levels 0-2 (CET_S state). Reading the CET shadow stack pointer register on linux requires a separate ptrace call using NT_X86_SHSTK. To pass the CET shadow stack enablement state we would like to pass the xstate_bv value instead of xcr0 for target description creation. To prepare for that, we rename the xcr0 mask values for target description creation to xstate_bv. However, this patch doesn't add any functional changes in GDB. Future states specified in IA32_XSS such as CET will create a combined xstate_bv_mask including xcr0 register value and its corresponding bit in the state component bitmap. This combined mask will then be used to create the target descriptions. Reviewed-by: Thiago Jung Bauermann --- gdb/amd64-tdep.c | 14 ++++---- gdb/amd64-tdep.h | 8 +++-- gdb/arch/amd64-linux-tdesc.c | 33 ++++++++--------- gdb/arch/amd64-linux-tdesc.h | 7 ++-- gdb/arch/amd64.c | 15 ++++---- gdb/arch/amd64.h | 10 ++++-- gdb/arch/i386-linux-tdesc.c | 29 ++++++++------- gdb/arch/i386-linux-tdesc.h | 5 +-- gdb/arch/i386.c | 15 ++++---- gdb/arch/i386.h | 8 ++++- gdb/arch/x86-linux-tdesc-features.c | 55 +++++++++++++++-------------- gdb/arch/x86-linux-tdesc-features.h | 25 +++++++------ gdb/i386-tdep.c | 14 ++++---- gdb/i386-tdep.h | 7 ++-- gdb/nat/x86-linux-tdesc.c | 18 +++++----- gdb/nat/x86-linux-tdesc.h | 7 ++-- gdb/x86-linux-nat.c | 11 ++++-- gdbserver/i387-fp.cc | 40 ++++++++++----------- gdbserver/linux-amd64-ipa.cc | 10 +++--- gdbserver/linux-i386-ipa.cc | 6 ++-- gdbserver/linux-x86-low.cc | 9 +++-- gdbsupport/x86-xstate.h | 4 ++- 22 files changed, 196 insertions(+), 154 deletions(-) diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index e03180b08af..37a2e3b03d4 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -3353,23 +3353,23 @@ amd64_x32_none_init_abi (gdbarch_info info, gdbarch *arch) amd64_target_description (X86_XSTATE_SSE_MASK, true)); } -/* Return the target description for a specified XSAVE feature mask. */ +/* See amd64-tdep.h. */ const struct target_desc * -amd64_target_description (uint64_t xcr0, bool segments) +amd64_target_description (uint64_t xstate_bv_mask, bool segments) { static target_desc *amd64_tdescs \ [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {}; target_desc **tdesc; - tdesc = &amd64_tdescs[(xcr0 & X86_XSTATE_AVX) ? 1 : 0] - [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0] - [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0] + tdesc = &amd64_tdescs[(xstate_bv_mask & X86_XSTATE_AVX) ? 1 : 0] + [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0] + [(xstate_bv_mask & X86_XSTATE_PKRU) ? 1 : 0] [segments ? 1 : 0]; if (*tdesc == NULL) - *tdesc = amd64_create_target_description (xcr0, false, false, - segments); + *tdesc = amd64_create_target_description (xstate_bv_mask, false, + false, segments); return *tdesc; } diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h index 7439b6e2e20..e93e3931df3 100644 --- a/gdb/amd64-tdep.h +++ b/gdb/amd64-tdep.h @@ -108,8 +108,12 @@ extern void amd64_init_abi (struct gdbarch_info info, extern void amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch, const target_desc *default_tdesc); -extern const struct target_desc *amd64_target_description (uint64_t xcr0, - bool segments); + +/* Return the target description for the specified xsave features as + defined in XSTATE_BV_MASK and SEGMENTS. */ + +extern const struct target_desc *amd64_target_description + (uint64_t xstate_bv_mask, bool segments); /* Fill register REGNUM in REGCACHE with the appropriate floating-point or SSE register value from *FXSAVE. If REGNUM is diff --git a/gdb/arch/amd64-linux-tdesc.c b/gdb/arch/amd64-linux-tdesc.c index e9c4a99806d..17dfcfeaee8 100644 --- a/gdb/arch/amd64-linux-tdesc.c +++ b/gdb/arch/amd64-linux-tdesc.c @@ -26,41 +26,42 @@ /* See arch/amd64-linux-tdesc.h. */ const struct target_desc * -amd64_linux_read_description (uint64_t xcr0, bool is_x32) +amd64_linux_read_description (uint64_t xstate_bv_mask, bool is_x32) { /* The type used for the amd64 and x32 target description caches. */ using tdesc_cache_type = std::unordered_map; /* Caches for the previously seen amd64 and x32 target descriptions, - indexed by the xcr0 value that created the target description. These - need to be static within this function to ensure they are initialised - before first use. */ + indexed by the xstate_bv_mask value that created the target + description. These need to be static within this function to ensure + they are initialised before first use. */ static tdesc_cache_type amd64_tdesc_cache, x32_tdesc_cache; tdesc_cache_type &tdesc_cache = is_x32 ? x32_tdesc_cache : amd64_tdesc_cache; - /* Only some bits are checked when creating a tdesc, but the XCR0 value - contains other feature bits that are not relevant for tdesc creation. - When indexing into the TDESC_CACHE we need to use a consistent xcr0 - value otherwise we might fail to find an existing tdesc which has the - same set of relevant bits set. */ - xcr0 &= is_x32 - ? x86_linux_x32_xcr0_feature_mask () - : x86_linux_amd64_xcr0_feature_mask (); + /* Only some bits are checked when creating a tdesc, but the + xstate_bv_mask value contains other feature bits that are not + relevant for tdesc creation. + When indexing into the TDESC_CACHE we need to use a consistent + xstate_bv_mask value otherwise we might fail to find an existing + tdesc which has the same set of relevant bits set. */ + xstate_bv_mask &= is_x32 + ? x86_linux_x32_xstate_bv_feature_mask () + : x86_linux_amd64_xstate_bv_feature_mask (); - const auto it = tdesc_cache.find (xcr0); + const auto it = tdesc_cache.find (xstate_bv_mask); if (it != tdesc_cache.end ()) return it->second.get (); /* Create the previously unseen target description. */ - target_desc_up tdesc (amd64_create_target_description (xcr0, is_x32, - true, true)); + target_desc_up tdesc (amd64_create_target_description (xstate_bv_mask, + is_x32, true, true)); x86_linux_post_init_tdesc (tdesc.get (), true); /* Add to the cache, and return a pointer borrowed from the target_desc_up. This is safe as the cache (and the pointers contained within it) are not deleted until GDB exits. */ target_desc *ptr = tdesc.get (); - tdesc_cache.emplace (xcr0, std::move (tdesc)); + tdesc_cache.emplace (xstate_bv_mask, std::move (tdesc)); return ptr; } diff --git a/gdb/arch/amd64-linux-tdesc.h b/gdb/arch/amd64-linux-tdesc.h index f6a424862bb..27a99efbe10 100644 --- a/gdb/arch/amd64-linux-tdesc.h +++ b/gdb/arch/amd64-linux-tdesc.h @@ -22,9 +22,10 @@ struct target_desc; -/* Return the AMD64 target descriptions corresponding to XCR0 and IS_X32. */ +/* Return the AMD64 target descriptions corresponding to XSTATE_BV_MASK + and IS_X32. */ -extern const target_desc *amd64_linux_read_description (uint64_t xcr0, - bool is_x32); +extern const target_desc *amd64_linux_read_description + (uint64_t xstate_bv_mask, bool is_x32); #endif /* GDB_ARCH_AMD64_LINUX_TDESC_H */ diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c index 5fc9947d489..72bd96aff76 100644 --- a/gdb/arch/amd64.c +++ b/gdb/arch/amd64.c @@ -30,14 +30,11 @@ #include "../features/i386/x32-core.c" -/* Create amd64 target descriptions according to XCR0. If IS_X32 is - true, create the x32 ones. If IS_LINUX is true, create target - descriptions for Linux. If SEGMENTS is true, then include - the "org.gnu.gdb.i386.segments" feature registers. */ +/* See amd64.h. */ target_desc * -amd64_create_target_description (uint64_t xcr0, bool is_x32, bool is_linux, - bool segments) +amd64_create_target_description (uint64_t xstate_bv_mask, bool is_x32, + bool is_linux, bool segments) { target_desc_up tdesc = allocate_target_description (); @@ -62,13 +59,13 @@ amd64_create_target_description (uint64_t xcr0, bool is_x32, bool is_linux, if (segments) regnum = create_feature_i386_64bit_segments (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_AVX) + if (xstate_bv_mask & X86_XSTATE_AVX) regnum = create_feature_i386_64bit_avx (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_AVX512) + if (xstate_bv_mask & X86_XSTATE_AVX512) regnum = create_feature_i386_64bit_avx512 (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_PKRU) + if (xstate_bv_mask & X86_XSTATE_PKRU) regnum = create_feature_i386_pkeys (tdesc.get (), regnum); return tdesc.release (); diff --git a/gdb/arch/amd64.h b/gdb/arch/amd64.h index 1c7a2bb26e9..3ce1a5557b2 100644 --- a/gdb/arch/amd64.h +++ b/gdb/arch/amd64.h @@ -21,7 +21,13 @@ #include "gdbsupport/tdesc.h" #include -target_desc *amd64_create_target_description (uint64_t xcr0, bool is_x32, - bool is_linux, bool segments); +/* Create amd64 target descriptions according to XSTATE_BV_MASK. If + IS_X32 is true, create the x32 ones. If IS_LINUX is true, create + target descriptions for Linux. If SEGMENTS is true, then include + the "org.gnu.gdb.i386.segments" feature registers. */ + +target_desc *amd64_create_target_description (uint64_t xstate_bv_mask, + bool is_x32, bool is_linux, + bool segments); #endif /* GDB_ARCH_AMD64_H */ diff --git a/gdb/arch/i386-linux-tdesc.c b/gdb/arch/i386-linux-tdesc.c index 9f12e59d214..bae8741b210 100644 --- a/gdb/arch/i386-linux-tdesc.c +++ b/gdb/arch/i386-linux-tdesc.c @@ -25,32 +25,35 @@ /* See arch/i386-linux-tdesc.h. */ const target_desc * -i386_linux_read_description (uint64_t xcr0) +i386_linux_read_description (uint64_t xstate_bv_mask) { - /* Cache of previously seen i386 target descriptions, indexed by the xcr0 - value that created the target description. This needs to be static - within this function to ensure it is initialised before first use. */ + /* Cache of previously seen i386 target descriptions, indexed by the + xstate_bv_mask value that created the target description. This + needs to be static within this function to ensure it is initialised + before first use. */ static std::unordered_map i386_tdesc_cache; - /* Only some bits are checked when creating a tdesc, but the XCR0 value - contains other feature bits that are not relevant for tdesc creation. - When indexing into the I386_TDESC_CACHE we need to use a consistent - xcr0 value otherwise we might fail to find an existing tdesc which has - the same set of relevant bits set. */ - xcr0 &= x86_linux_i386_xcr0_feature_mask (); + /* Only some bits are checked when creating a tdesc, but the + XSTATE_BV_MASK value contains other feature bits that are not + relevant for tdesc creation. When indexing into the I386_TDESC_CACHE + we need to use a consistent XSTATE_BV_MASK value otherwise we might + fail to find an existing tdesc which has the same set of relevant + bits set. */ + xstate_bv_mask &= x86_linux_i386_xstate_bv_feature_mask (); - const auto it = i386_tdesc_cache.find (xcr0); + const auto it = i386_tdesc_cache.find (xstate_bv_mask); if (it != i386_tdesc_cache.end ()) return it->second.get (); /* Create the previously unseen target description. */ - target_desc_up tdesc (i386_create_target_description (xcr0, true, false)); + target_desc_up tdesc + (i386_create_target_description (xstate_bv_mask, true, false)); x86_linux_post_init_tdesc (tdesc.get (), false); /* Add to the cache, and return a pointer borrowed from the target_desc_up. This is safe as the cache (and the pointers contained within it) are not deleted until GDB exits. */ target_desc *ptr = tdesc.get (); - i386_tdesc_cache.emplace (xcr0, std::move (tdesc)); + i386_tdesc_cache.emplace (xstate_bv_mask, std::move (tdesc)); return ptr; } diff --git a/gdb/arch/i386-linux-tdesc.h b/gdb/arch/i386-linux-tdesc.h index 4ecd674aa96..6970202ce4d 100644 --- a/gdb/arch/i386-linux-tdesc.h +++ b/gdb/arch/i386-linux-tdesc.h @@ -22,8 +22,9 @@ struct target_desc; -/* Return the i386 target description corresponding to XCR0. */ +/* Return the i386 target description corresponding to XSTATE_BV_MASK. */ -extern const struct target_desc *i386_linux_read_description (uint64_t xcr0); +extern const struct target_desc *i386_linux_read_description + (uint64_t xstate_bv_mask); #endif /* GDB_ARCH_I386_LINUX_TDESC_H */ diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c index 2072eae88ad..4a39028a472 100644 --- a/gdb/arch/i386.c +++ b/gdb/arch/i386.c @@ -29,10 +29,11 @@ #include "../features/i386/32bit-segments.c" #include "../features/i386/pkeys.c" -/* Create i386 target descriptions according to XCR0. */ +/* See i386.h. */ target_desc * -i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments) +i386_create_target_description (uint64_t xstate_bv_mask, bool is_linux, + bool segments) { target_desc_up tdesc = allocate_target_description (); @@ -44,10 +45,10 @@ i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments) long regnum = 0; - if (xcr0 & X86_XSTATE_X87) + if (xstate_bv_mask & X86_XSTATE_X87) regnum = create_feature_i386_32bit_core (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_SSE) + if (xstate_bv_mask & X86_XSTATE_SSE) regnum = create_feature_i386_32bit_sse (tdesc.get (), regnum); if (is_linux) @@ -56,13 +57,13 @@ i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments) if (segments) regnum = create_feature_i386_32bit_segments (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_AVX) + if (xstate_bv_mask & X86_XSTATE_AVX) regnum = create_feature_i386_32bit_avx (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_AVX512) + if (xstate_bv_mask & X86_XSTATE_AVX512) regnum = create_feature_i386_32bit_avx512 (tdesc.get (), regnum); - if (xcr0 & X86_XSTATE_PKRU) + if (xstate_bv_mask & X86_XSTATE_PKRU) regnum = create_feature_i386_pkeys (tdesc.get (), regnum); return tdesc.release (); diff --git a/gdb/arch/i386.h b/gdb/arch/i386.h index 1b5cc6e1095..89f8aa49b9d 100644 --- a/gdb/arch/i386.h +++ b/gdb/arch/i386.h @@ -21,7 +21,13 @@ #include "gdbsupport/tdesc.h" #include -target_desc *i386_create_target_description (uint64_t xcr0, bool is_linux, +/* Create i386 target descriptions according to XSTATE_BV_MASK. If + IS_LINUX is true, create target descriptions for Linux. If SEGMENTS + is true, then include the "org.gnu.gdb.i386.segments" feature + registers. */ + +target_desc *i386_create_target_description (uint64_t xstate_bv_mask, + bool is_linux, bool segments); #endif /* GDB_ARCH_I386_H */ diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c index f6eb112f312..3f041ece6eb 100644 --- a/gdb/arch/x86-linux-tdesc-features.c +++ b/gdb/arch/x86-linux-tdesc-features.c @@ -28,18 +28,21 @@ We want to cache target descriptions, and this is currently done in three separate caches, one each for i386, amd64, and x32. Additionally, - the caching we're discussing here is Linux only, and for Linux, the only - thing that has an impact on target description creation is the xcr0 - value. + the caching we're discussing here is Linux only. Currently for linux, + the only thing that has an impact on target description creation are + the supported features in xsave which are modelled by a xstate_bv_mask + value, which has the same format than the state component bitmap. In order to ensure the cache functions correctly we need to filter out - only those xcr0 feature bits that are relevant, we can then cache target - descriptions based on the relevant feature bits. Two xcr0 values might - be different, but have the same relevant feature bits. In this case we - would expect the two xcr0 values to map to the same cache entry. */ + only those xstate_bv_mask feature bits that are relevant, we can then + cache target descriptions based on the relevant feature bits. Two + xstate_bv_mask values might be different, but have the same relevant + feature bits. In this case we would expect the two xstate_bv_mask + values to map to the same cache entry. */ struct x86_xstate_feature { - /* The xstate feature mask. This is a mask against an xcr0 value. */ + /* The xstate feature mask. This is a mask against the state component + bitmap. */ uint64_t feature; /* Is this feature checked when creating an i386 target description. */ @@ -56,9 +59,9 @@ struct x86_xstate_feature { checked when building a target description for i386, amd64, or x32. If in the future, due to simplifications or refactoring, this table ever - ends up with 'true' for every xcr0 feature on every target type, then this - is an indication that this table should probably be removed, and that the - rest of the code in this file can be simplified. */ + ends up with 'true' for every xsave feature on every target type, then + this is an indication that this table should probably be removed, and + that the rest of the code in this file can be simplified. */ static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = { /* Feature, i386, amd64, x32. */ @@ -73,7 +76,7 @@ static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = { that are checked for when building an i386 target description. */ static constexpr uint64_t -x86_linux_i386_xcr0_feature_mask_1 () +x86_linux_i386_xstate_bv_feature_mask_1 () { uint64_t mask = 0; @@ -88,7 +91,7 @@ x86_linux_i386_xcr0_feature_mask_1 () that are checked for when building an amd64 target description. */ static constexpr uint64_t -x86_linux_amd64_xcr0_feature_mask_1 () +x86_linux_amd64_xstate_bv_feature_mask_1 () { uint64_t mask = 0; @@ -103,7 +106,7 @@ x86_linux_amd64_xcr0_feature_mask_1 () that are checked for when building an x32 target description. */ static constexpr uint64_t -x86_linux_x32_xcr0_feature_mask_1 () +x86_linux_x32_xstate_bv_feature_mask_1 () { uint64_t mask = 0; @@ -117,25 +120,25 @@ x86_linux_x32_xcr0_feature_mask_1 () /* See arch/x86-linux-tdesc-features.h. */ uint64_t -x86_linux_i386_xcr0_feature_mask () +x86_linux_i386_xstate_bv_feature_mask () { - return x86_linux_i386_xcr0_feature_mask_1 (); + return x86_linux_i386_xstate_bv_feature_mask_1 (); } /* See arch/x86-linux-tdesc-features.h. */ uint64_t -x86_linux_amd64_xcr0_feature_mask () +x86_linux_amd64_xstate_bv_feature_mask () { - return x86_linux_amd64_xcr0_feature_mask_1 (); + return x86_linux_amd64_xstate_bv_feature_mask_1 (); } /* See arch/x86-linux-tdesc-features.h. */ uint64_t -x86_linux_x32_xcr0_feature_mask () +x86_linux_x32_xstate_bv_feature_mask () { - return x86_linux_x32_xcr0_feature_mask_1 (); + return x86_linux_x32_xstate_bv_feature_mask_1 (); } #ifdef GDBSERVER @@ -143,7 +146,7 @@ x86_linux_x32_xcr0_feature_mask () /* See arch/x86-linux-tdesc-features.h. */ int -x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0) +x86_linux_xstate_bv_mask_to_tdesc_idx (uint64_t xstate_bv_mask) { /* The following table shows which features are checked for when creating the target descriptions (see nat/x86-linux-tdesc.c), the feature order @@ -160,7 +163,7 @@ x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0) for (int i = 0; i < ARRAY_SIZE (x86_linux_all_xstate_features); ++i) { - if ((xcr0 & x86_linux_all_xstate_features[i].feature) + if ((xstate_bv_mask & x86_linux_all_xstate_features[i].feature) == x86_linux_all_xstate_features[i].feature) idx |= (1 << i); } @@ -250,17 +253,17 @@ x86_linux_i386_tdesc_count () /* See arch/x86-linux-tdesc-features.h. */ uint64_t -x86_linux_tdesc_idx_to_xcr0 (int idx) +x86_linux_tdesc_idx_to_xstate_bv_mask (int idx) { - uint64_t xcr0 = 0; + uint64_t xstate_bv_mask = 0; for (int i = 0; i < ARRAY_SIZE (x86_linux_all_xstate_features); ++i) { if ((idx & (1 << i)) != 0) - xcr0 |= x86_linux_all_xstate_features[i].feature; + xstate_bv_mask |= x86_linux_all_xstate_features[i].feature; } - return xcr0; + return xstate_bv_mask; } #endif /* IN_PROCESS_AGENT */ diff --git a/gdb/arch/x86-linux-tdesc-features.h b/gdb/arch/x86-linux-tdesc-features.h index cf8351dea8e..a9dfdbc3068 100644 --- a/gdb/arch/x86-linux-tdesc-features.h +++ b/gdb/arch/x86-linux-tdesc-features.h @@ -27,17 +27,20 @@ the set of features which are checked for when creating the target description for each of amd64, x32, and i386. */ -extern uint64_t x86_linux_amd64_xcr0_feature_mask (); -extern uint64_t x86_linux_x32_xcr0_feature_mask (); -extern uint64_t x86_linux_i386_xcr0_feature_mask (); +extern uint64_t x86_linux_amd64_xstate_bv_feature_mask (); +extern uint64_t x86_linux_x32_xstate_bv_feature_mask (); +extern uint64_t x86_linux_i386_xstate_bv_feature_mask (); #ifdef GDBSERVER -/* Convert an xcr0 value into an integer. The integer will be passed from +/* Convert an XSTATE_BV_MASK value into an integer. XSTATE_BV_MASK has + the same format than the state component bitmap and does include user + and supervisor state components. The integer will be passed from gdbserver to the in-process-agent where it will then be passed through - x86_linux_tdesc_idx_to_xcr0 to get back the original xcr0 value. */ + x86_linux_tdesc_idx_to_xstate_bv_mask to get back the original mask. */ -extern int x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0); + +extern int x86_linux_xstate_bv_mask_to_tdesc_idx (uint64_t xstate_bv_mask); #endif /* GDBSERVER */ @@ -51,11 +54,13 @@ extern int x86_linux_amd64_tdesc_count (); extern int x86_linux_x32_tdesc_count (); extern int x86_linux_i386_tdesc_count (); -/* Convert an index number (as returned from x86_linux_xcr0_to_tdesc_idx) - into an xcr0 value which can then be used to create a target - description. */ +/* Convert an index number (as returned from + x86_linux_xstate_bv_mask_to_tdesc_idx) into an xstate_bv_mask + value which can then be used to create a target description. + The return mask same format than the state component bitmap and does + include user and supervisor state components.*/ -extern uint64_t x86_linux_tdesc_idx_to_xcr0 (int idx); +extern uint64_t x86_linux_tdesc_idx_to_xstate_bv_mask (int idx); #endif /* IN_PROCESS_AGENT */ diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index a552a2bee8f..54aa1294917 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -8899,23 +8899,23 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) -/* Return the target description for a specified XSAVE feature mask. */ +/* See i386-tdep.h. */ const struct target_desc * -i386_target_description (uint64_t xcr0, bool segments) +i386_target_description (uint64_t xstate_bv_mask, bool segments) { static target_desc *i386_tdescs \ [2/*SSE*/][2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {}; target_desc **tdesc; - tdesc = &i386_tdescs[(xcr0 & X86_XSTATE_SSE) ? 1 : 0] - [(xcr0 & X86_XSTATE_AVX) ? 1 : 0] - [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0] - [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0] + tdesc = &i386_tdescs[(xstate_bv_mask & X86_XSTATE_SSE) ? 1 : 0] + [(xstate_bv_mask & X86_XSTATE_AVX) ? 1 : 0] + [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0] + [(xstate_bv_mask & X86_XSTATE_PKRU) ? 1 : 0] [segments ? 1 : 0]; if (*tdesc == NULL) - *tdesc = i386_create_target_description (xcr0, false, segments); + *tdesc = i386_create_target_description (xstate_bv_mask, false, segments); return *tdesc; } diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h index 680eb027a04..3f990e71abf 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -450,8 +450,11 @@ extern int i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg); extern int i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr); -extern const struct target_desc *i386_target_description (uint64_t xcr0, - bool segments); + +/* Return the target description for the specified xsave features as + defined in XSTATE_BV_MASK and SEGMENTS. */ +extern const struct target_desc *i386_target_description + (uint64_t xstate_bv_mask, bool segments); /* Functions and variables exported from i386-bsd-tdep.c. */ diff --git a/gdb/nat/x86-linux-tdesc.c b/gdb/nat/x86-linux-tdesc.c index 1824f57c70f..c5eac277bfd 100644 --- a/gdb/nat/x86-linux-tdesc.c +++ b/gdb/nat/x86-linux-tdesc.c @@ -43,7 +43,7 @@ /* See nat/x86-linux-tdesc.h. */ const target_desc * -x86_linux_tdesc_for_tid (int tid, uint64_t *xcr0_storage, +x86_linux_tdesc_for_tid (int tid, uint64_t *xstate_bv_storage, x86_xsave_layout *xsave_layout_storage) { #ifdef __x86_64__ @@ -96,30 +96,32 @@ x86_linux_tdesc_for_tid (int tid, uint64_t *xcr0_storage, these bits being set we generate a completely empty tdesc for i386 which will be rejected by GDB. */ have_ptrace_getregset = TRIBOOL_FALSE; - *xcr0_storage = X86_XSTATE_SSE_MASK; + *xstate_bv_storage = X86_XSTATE_SSE_MASK; } else { have_ptrace_getregset = TRIBOOL_TRUE; /* Get XCR0 from XSAVE extended state. */ - *xcr0_storage = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET + uint64_t xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET / sizeof (uint64_t))]; *xsave_layout_storage - = x86_fetch_xsave_layout (*xcr0_storage, x86_xsave_length ()); + = x86_fetch_xsave_layout (xcr0, x86_xsave_length ()); + + *xstate_bv_storage = xcr0; } } - /* Use cached xcr0 value. */ - uint64_t xcr0_features_bits = *xcr0_storage & X86_XSTATE_ALL_MASK; + /* Use cached XSTATE_BV_STORAGE value. */ + uint64_t xstate_bv_features_bits = *xstate_bv_storage & X86_XSTATE_ALL_MASK; #ifdef __x86_64__ if (is_64bit) - return amd64_linux_read_description (xcr0_features_bits, is_x32); + return amd64_linux_read_description (xstate_bv_features_bits, is_x32); else #endif - return i386_linux_read_description (xcr0_features_bits); + return i386_linux_read_description (xstate_bv_features_bits); } #endif /* !IN_PROCESS_AGENT */ diff --git a/gdb/nat/x86-linux-tdesc.h b/gdb/nat/x86-linux-tdesc.h index 2a2d8697cbe..548f2f10b65 100644 --- a/gdb/nat/x86-linux-tdesc.h +++ b/gdb/nat/x86-linux-tdesc.h @@ -27,9 +27,9 @@ struct x86_xsave_layout; /* Return the target description for Linux thread TID. - The storage pointed to by XCR0_STORAGE and XSAVE_LAYOUT_STORAGE must + The storage pointed to by XSTATE_BV_STORAGE and XSAVE_LAYOUT_STORAGE must exist until the program (GDB or gdbserver) terminates, this storage is - used to cache the xcr0 and xsave layout values. The values pointed to + used to cache the xstate_bv and xsave layout values. The values pointed to by these arguments are only updated at most once, the first time this function is called if the have_ptrace_getregset global is set to TRIBOOL_UNKNOWN. @@ -45,6 +45,7 @@ struct x86_xsave_layout; returned. */ extern const target_desc *x86_linux_tdesc_for_tid - (int tid, uint64_t *xcr0_storage, x86_xsave_layout *xsave_layout_storage); + (int tid, uint64_t *xstate_bv_storage, + x86_xsave_layout *xsave_layout_storage); #endif /* GDB_NAT_X86_LINUX_TDESC_H */ diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index 2afa04f6288..d1fece717a7 100644 --- a/gdb/x86-linux-nat.c +++ b/gdb/x86-linux-nat.c @@ -97,15 +97,20 @@ const struct target_desc * x86_linux_nat_target::read_description () { /* The x86_linux_tdesc_for_tid call only reads xcr0 the first time it is - called, the xcr0 value is stored here and reused on subsequent calls. */ - static uint64_t xcr0_storage; + called. The mask is stored in XSTATE_BV_STORAGE and reused on + subsequent calls. Note that GDB currently supports features for user + state components only. However, once supervisor state components are + supported in GDB XSTATE_BV_STORAGE will not be configured based on + xcr0 only. */ + static uint64_t xstate_bv_storage; if (inferior_ptid == null_ptid) return this->beneath ()->read_description (); int tid = inferior_ptid.pid (); - return x86_linux_tdesc_for_tid (tid, &xcr0_storage, &this->m_xsave_layout); + return x86_linux_tdesc_for_tid (tid, &xstate_bv_storage, + &this->m_xsave_layout); } diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc index 0bf57a3aa5d..3e9e823827e 100644 --- a/gdbserver/i387-fp.cc +++ b/gdbserver/i387-fp.cc @@ -21,7 +21,7 @@ #include "nat/x86-xstate.h" /* Default to SSE. */ -static uint64_t x86_xcr0 = X86_XSTATE_SSE_MASK; +static uint64_t x86_xstate_bv = X86_XSTATE_SSE_MASK; static const int num_avx512_k_registers = 8; static const int num_pkeys_registers = 1; @@ -265,7 +265,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) /* The supported bits in `xstat_bv' are 8 bytes. Clear part in vector registers if its bit in xstat_bv is zero. */ - clear_bv = (~fp->xstate_bv) & x86_xcr0; + clear_bv = (~fp->xstate_bv) & x86_xstate_bv; /* Clear part in x87 and vector registers if its bit in xstat_bv is zero. */ @@ -315,7 +315,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any x87 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_X87)) + if ((x86_xstate_bv & X86_XSTATE_X87)) { int st0_regnum = find_regno (regcache->tdesc, "st0"); @@ -332,7 +332,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any SSE registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_SSE)) + if ((x86_xstate_bv & X86_XSTATE_SSE)) { int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); @@ -349,7 +349,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any AVX registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_AVX)) + if ((x86_xstate_bv & X86_XSTATE_AVX)) { int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); @@ -366,7 +366,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any K registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_K)) + if ((x86_xstate_bv & X86_XSTATE_K)) { int k0_regnum = find_regno (regcache->tdesc, "k0"); @@ -383,7 +383,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any of ZMM0H-ZMM15H registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_ZMM_H)) + if ((x86_xstate_bv & X86_XSTATE_ZMM_H)) { int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); @@ -400,7 +400,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any of ZMM16-ZMM31 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_ZMM) && num_zmm_high_registers != 0) + if ((x86_xstate_bv & X86_XSTATE_ZMM) && num_zmm_high_registers != 0) { int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h"); @@ -437,7 +437,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } /* Check if any PKEYS registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_PKRU)) + if ((x86_xstate_bv & X86_XSTATE_PKRU)) { int pkru_regnum = find_regno (regcache->tdesc, "pkru"); @@ -453,7 +453,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } } - if ((x86_xcr0 & X86_XSTATE_SSE) || (x86_xcr0 & X86_XSTATE_AVX)) + if ((x86_xstate_bv & X86_XSTATE_SSE) || (x86_xstate_bv & X86_XSTATE_AVX)) { collect_register_by_name (regcache, "mxcsr", raw); if (memcmp (raw, &fp->mxcsr, 4) != 0) @@ -465,7 +465,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) } } - if (x86_xcr0 & X86_XSTATE_X87) + if (x86_xstate_bv & X86_XSTATE_X87) { collect_register_by_name (regcache, "fioff", raw); if (memcmp (raw, &fp->fioff, 4) != 0) @@ -658,10 +658,10 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) /* The supported bits in `xstat_bv' are 8 bytes. Clear part in vector registers if its bit in xstat_bv is zero. */ - clear_bv = (~fp->xstate_bv) & x86_xcr0; + clear_bv = (~fp->xstate_bv) & x86_xstate_bv; /* Check if any x87 registers are changed. */ - if ((x86_xcr0 & X86_XSTATE_X87) != 0) + if ((x86_xstate_bv & X86_XSTATE_X87) != 0) { int st0_regnum = find_regno (regcache->tdesc, "st0"); @@ -678,7 +678,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) } } - if ((x86_xcr0 & X86_XSTATE_SSE) != 0) + if ((x86_xstate_bv & X86_XSTATE_SSE) != 0) { int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); @@ -695,7 +695,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) } } - if ((x86_xcr0 & X86_XSTATE_AVX) != 0) + if ((x86_xstate_bv & X86_XSTATE_AVX) != 0) { int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); @@ -712,7 +712,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) } } - if ((x86_xcr0 & X86_XSTATE_K) != 0) + if ((x86_xstate_bv & X86_XSTATE_K) != 0) { int k0_regnum = find_regno (regcache->tdesc, "k0"); @@ -729,7 +729,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) } } - if ((x86_xcr0 & X86_XSTATE_ZMM_H) != 0) + if ((x86_xstate_bv & X86_XSTATE_ZMM_H) != 0) { int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); @@ -746,7 +746,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) } } - if ((x86_xcr0 & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0) + if ((x86_xstate_bv & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0) { int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h"); @@ -773,7 +773,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) } } - if ((x86_xcr0 & X86_XSTATE_PKRU) != 0) + if ((x86_xstate_bv & X86_XSTATE_PKRU) != 0) { int pkru_regnum = find_regno (regcache->tdesc, "pkru"); @@ -858,5 +858,5 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) std::pair i387_get_xsave_storage () { - return { &x86_xcr0, &xsave_layout }; + return { &x86_xstate_bv, &xsave_layout }; } diff --git a/gdbserver/linux-amd64-ipa.cc b/gdbserver/linux-amd64-ipa.cc index c53758a7dbe..9450a2114e4 100644 --- a/gdbserver/linux-amd64-ipa.cc +++ b/gdbserver/linux-amd64-ipa.cc @@ -170,7 +170,7 @@ supply_static_tracepoint_registers (struct regcache *regcache, const struct target_desc * get_ipa_tdesc (int idx) { - uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx); + uint64_t xstate_bv_mask = x86_linux_tdesc_idx_to_xstate_bv_mask (idx); #if defined __ILP32__ bool is_x32 = true; @@ -178,7 +178,7 @@ get_ipa_tdesc (int idx) bool is_x32 = false; #endif - return amd64_linux_read_description (xcr0, is_x32); + return amd64_linux_read_description (xstate_bv_mask, is_x32); } /* Allocate buffer for the jump pads. The branch instruction has a @@ -247,9 +247,11 @@ initialize_low_tracepoint (void) { #if defined __ILP32__ for (int i = 0; i < x86_linux_x32_tdesc_count (); i++) - amd64_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i), true); + amd64_linux_read_description + (x86_linux_tdesc_idx_to_xstate_bv_mask (i), true); #else for (int i = 0; i < x86_linux_amd64_tdesc_count (); i++) - amd64_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i), false); + amd64_linux_read_description + (x86_linux_tdesc_idx_to_xstate_bv_mask (i), false); #endif } diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc index 2b363271ab6..ec06f16a2bf 100644 --- a/gdbserver/linux-i386-ipa.cc +++ b/gdbserver/linux-i386-ipa.cc @@ -251,9 +251,9 @@ initialize_fast_tracepoint_trampoline_buffer (void) const struct target_desc * get_ipa_tdesc (int idx) { - uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx); + uint64_t xstate_bv_mask = x86_linux_tdesc_idx_to_xstate_bv_mask (idx); - return i386_linux_read_description (xcr0); + return i386_linux_read_description (xstate_bv_mask); } /* Allocate buffer for the jump pads. On i386, we can reach an arbitrary @@ -276,5 +276,5 @@ initialize_low_tracepoint (void) { initialize_fast_tracepoint_trampoline_buffer (); for (int i = 0; i < x86_linux_i386_tdesc_count (); i++) - i386_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i)); + i386_linux_read_description (x86_linux_tdesc_idx_to_xstate_bv_mask (i)); } diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc index b023b34a0a4..4575ea2fdc0 100644 --- a/gdbserver/linux-x86-low.cc +++ b/gdbserver/linux-x86-low.cc @@ -873,7 +873,7 @@ x86_linux_read_description () bool have_ptrace_getregset_was_unknown = have_ptrace_getregset == TRIBOOL_UNKNOWN; - /* Get pointers to where we should store the xcr0 and xsave_layout + /* Get pointers to where we should store the xstate_bv and xsave_layout values. These will be filled in by x86_linux_tdesc_for_tid the first time that the function is called. Subsequent calls will not modify the stored values. */ @@ -2892,17 +2892,16 @@ x86_target::get_ipa_tdesc_idx () || tdesc == tdesc_amd64_linux_no_xml.get () #endif /* __x86_64__ */ ); - return x86_linux_xcr0_to_tdesc_idx (X86_XSTATE_SSE_MASK); + return x86_linux_xstate_bv_mask_to_tdesc_idx (X86_XSTATE_SSE_MASK); } - /* The xcr0 value and xsave layout value are cached when the target + /* The xstate_bv value and xsave layout value are cached when the target description is read. Grab their cache location, and use the cached value to calculate a tdesc index. */ std::pair storage = i387_get_xsave_storage (); - uint64_t xcr0 = *storage.first; - return x86_linux_xcr0_to_tdesc_idx (xcr0); + return x86_linux_xstate_bv_mask_to_tdesc_idx (*storage.first); } /* The linux target ops object. */ diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h index 45300b2c18d..76932c765a7 100644 --- a/gdbsupport/x86-xstate.h +++ b/gdbsupport/x86-xstate.h @@ -83,8 +83,10 @@ constexpr bool operator!= (const x86_xsave_layout &lhs, #define X86_XSTATE_AVX_AVX512_PKU_MASK (X86_XSTATE_AVX_MASK\ | X86_XSTATE_AVX512 | X86_XSTATE_PKRU) -#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK) +/* Supported mask of state-component bitmap xstate_bv. The SDM defines + xstate_bv as XCR0 | IA32_XSS. */ +#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK) #define X86_XSTATE_SSE_SIZE 576 #define X86_XSTATE_AVX_SIZE 832 From patchwork Fri Dec 20 20:04:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103533 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 9FC753858D38 for ; Fri, 20 Dec 2024 20:15:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9FC753858D38 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=AYgOT7Sj X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by sourceware.org (Postfix) with ESMTPS id 32787385841F for ; Fri, 20 Dec 2024 20:06:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 32787385841F 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 32787385841F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725175; cv=none; b=H8e0iEbWZASgv72Z/qsadDG1gOnssTK5UtDyK3ZQDfhEh2EkVU3B6XoEUJkLpnZlWCdqduhkZcUjVYOcJnsi/mrQndX22AdUKV4NrchEDgXYLqaDU6kBApBFdsVHB1DcYFUy/A+4v5mNTHabQZeQ4rdqF+Mci5ykDTCOnjFay+U= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725175; c=relaxed/simple; bh=EogguoGvJkfTNsBhvzaHDZ7tY4jJBJMo1OkRD2qKJMk=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=IwbdzKezSmHpNd8cNhi5qYmV1Yi9JH83tMtZVTA3jq7dSggLT8RotLTdjfKWY5ndsiopPJB0W3WKeSFY6a27QSi27fD/8vM/yRbTRT+jvHJuwhKgiWmEDinLnaHnRUvL7/6P94zisxVsXvCm/E1NtVT0U60we9cOyHl1/mAM4pw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 32787385841F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725170; x=1766261170; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=EogguoGvJkfTNsBhvzaHDZ7tY4jJBJMo1OkRD2qKJMk=; b=AYgOT7SjyqE5TInoT9jMUtodZ8cWcJPSOCMfgHYtgXMFOx7D995WOYPy i+TRlF8EeRgyRpv4y5UKlmZUUMCp+BTVSzaDoeph94e+1BU9Yp1Mt+CRP 8xPFVjVIxHSmLyQ8Xn0prFKMP0L9Bm/l2it/p0WgXCV0fXL6YoT6+v49h kkIfS7kYN9lSCItKhtN2it32HHn8EL+EWnWJvPo0UxogeF2Noe+JvdWDt dK+y9lN0eTzt2sVJC+dFBn/iZRwSdZy59k7MM9uuW7p+EuvnMMr3L90Rr BAQ5Gv54ZbCGROrJbBIYGXmvxb0/igoip9wcx9fOw/eF7Vfpsr/Hb9UE1 A==; X-CSE-ConnectionGUID: MNUDhw0YRaq8ZgUGgdZ8vQ== X-CSE-MsgGUID: CjlZHXOiQS6GwOH5vJ0XQQ== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="52689139" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="52689139" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:09 -0800 X-CSE-ConnectionGUID: ZnbSTnHMRL25pDY+2hMrjQ== X-CSE-MsgGUID: 7qY5o+qHQXG8ShxLjq6kCw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="98809937" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:08 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register. Date: Fri, 20 Dec 2024 20:04:55 +0000 Message-Id: <20241220200501.324191-7-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 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 This patch adds the user mode register PL3_SSP which is part of the Intel(R) Control-Flow Enforcement Technology (CET) feature for support of shadow stack. For now, only native and remote debugging support for shadow stack userspace on amd64 linux are covered by this patch including 64 bit and x32 support. 32 bit support is not covered due to missing linux kernel support. This patch requires fixing the test gdb.base/inline-frame-cycle-unwind which is failing in case the shadow stack pointer is unavailable. Such a state is possible if shadow stack is disabled for the current thread but supported by HW. This test uses the Python unwinder inline-frame-cycle-unwind.py which fakes the cyclic stack cycle by reading the pending frame's registers and adding them to the unwinder: ~~~ for reg in pending_frame.architecture().registers("general"): val = pending_frame.read_register(reg) unwinder.add_saved_register(reg, val) return unwinder ~~~ However, in case the python unwinder is used we add a register (pl3_ssp) that is unavailable. This leads to a NOT_AVAILABLE_ERROR caught in gdb/frame-unwind.c:frame_unwind_try_unwinder and it is continued with standard unwinders. This destroys the faked cyclic behavior and the stack is further unwinded after frame 5. In the working scenario an error should be triggered: ~~~ bt 0 inline_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:49^M 1 normal_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:32^M 2 0x000055555555516e in inline_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:45^M 3 normal_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:32^M 4 0x000055555555516e in inline_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:45^M 5 normal_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:32^M Backtrace stopped: previous frame identical to this frame (corrupt stack?) (gdb) PASS: gdb.base/inline-frame-cycle-unwind.exp: cycle at level 5: backtrace when the unwind is broken at frame 5 ~~~ To fix the Python unwinder, we simply skip the unavailable registers. --- gdb/amd64-linux-nat.c | 17 +++++ gdb/amd64-linux-tdep.c | 1 + gdb/amd64-tdep.c | 6 +- gdb/amd64-tdep.h | 1 + gdb/arch/amd64.c | 10 +++ gdb/arch/i386.c | 4 ++ gdb/arch/x86-linux-tdesc-features.c | 1 + gdb/doc/gdb.texinfo | 4 ++ gdb/features/Makefile | 2 + gdb/features/i386/32bit-ssp.c | 14 ++++ gdb/features/i386/32bit-ssp.xml | 11 +++ gdb/features/i386/64bit-ssp.c | 14 ++++ gdb/features/i386/64bit-ssp.xml | 11 +++ gdb/i386-tdep.c | 18 ++++- gdb/i386-tdep.h | 4 ++ gdb/nat/x86-linux-tdesc.c | 2 + gdb/nat/x86-linux.c | 55 +++++++++++++++ gdb/nat/x86-linux.h | 4 ++ gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 22 ++++++ gdb/testsuite/gdb.arch/amd64-ssp.exp | 50 ++++++++++++++ .../gdb.base/inline-frame-cycle-unwind.py | 4 ++ gdb/testsuite/lib/gdb.exp | 69 +++++++++++++++++++ gdb/x86-linux-nat.c | 50 ++++++++++++-- gdb/x86-linux-nat.h | 11 +++ gdb/x86-tdep.c | 22 ++++++ gdb/x86-tdep.h | 9 +++ gdbserver/linux-x86-low.cc | 28 +++++++- gdbsupport/x86-xstate.h | 5 +- 28 files changed, 440 insertions(+), 9 deletions(-) create mode 100644 gdb/features/i386/32bit-ssp.c create mode 100644 gdb/features/i386/32bit-ssp.xml create mode 100644 gdb/features/i386/64bit-ssp.c create mode 100644 gdb/features/i386/64bit-ssp.xml create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack.c create mode 100644 gdb/testsuite/gdb.arch/amd64-ssp.exp diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index c3b7a19b5cb..df246408eaa 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -32,6 +32,7 @@ #include "amd64-tdep.h" #include "amd64-linux-tdep.h" #include "i386-linux-tdep.h" +#include "x86-tdep.h" #include "gdbsupport/x86-xstate.h" #include "x86-linux-nat.h" @@ -237,6 +238,14 @@ amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) if (have_ptrace_getregset == TRIBOOL_TRUE) { + if ((regnum == -1 && tdep->ssp_regnum > 0) + || (regnum != -1 && regnum == tdep->ssp_regnum)) + { + x86_linux_fetch_ssp (regcache, tid); + if (regnum != -1) + return; + } + /* Pre-4.14 kernels have a bug (fixed by commit 0852b374173b "x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs") that sometimes causes the mxcsr location in @@ -302,6 +311,14 @@ amd64_linux_nat_target::store_registers (struct regcache *regcache, int regnum) if (have_ptrace_getregset == TRIBOOL_TRUE) { gdb::byte_vector xstateregs (tdep->xsave_layout.sizeof_xsave); + if ((regnum == -1 && tdep->ssp_regnum > 0) + || (regnum != -1 && regnum == tdep->ssp_regnum)) + { + x86_linux_store_ssp (regcache, tid); + if (regnum != -1) + return; + } + struct iovec iov; iov.iov_base = xstateregs.data (); diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 2c76a1de5a8..8ed381e1a2c 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -105,6 +105,7 @@ int amd64_linux_gregset_reg_offset[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* PKEYS register pkru */ + -1, /* CET user mode register PL3_SSP. */ /* End of hardware registers */ 21 * 8, 22 * 8, /* fs_base and gs_base. */ diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 37a2e3b03d4..a298333e70a 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -3197,6 +3197,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch, tdep->num_pkeys_regs = 1; } + if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pl3_ssp") != nullptr) + tdep->ssp_regnum = AMD64_PL3_SSP_REGNUM; + tdep->num_byte_regs = 20; tdep->num_word_regs = 16; tdep->num_dword_regs = 16; @@ -3359,12 +3362,13 @@ const struct target_desc * amd64_target_description (uint64_t xstate_bv_mask, bool segments) { static target_desc *amd64_tdescs \ - [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {}; + [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*CET_U*/][2/*segments*/] = {}; target_desc **tdesc; tdesc = &amd64_tdescs[(xstate_bv_mask & X86_XSTATE_AVX) ? 1 : 0] [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0] [(xstate_bv_mask & X86_XSTATE_PKRU) ? 1 : 0] + [(xstate_bv_mask & X86_XSTATE_CET_U) ? 1 : 0] [segments ? 1 : 0]; if (*tdesc == NULL) diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h index e93e3931df3..fad28649a5a 100644 --- a/gdb/amd64-tdep.h +++ b/gdb/amd64-tdep.h @@ -81,6 +81,7 @@ enum amd64_regnum AMD64_ZMM0H_REGNUM, AMD64_ZMM31H_REGNUM = AMD64_ZMM0H_REGNUM + 31, AMD64_PKRU_REGNUM, + AMD64_PL3_SSP_REGNUM, AMD64_FSBASE_REGNUM, AMD64_GSBASE_REGNUM }; diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c index 72bd96aff76..2c45cb637ec 100644 --- a/gdb/arch/amd64.c +++ b/gdb/arch/amd64.c @@ -28,6 +28,8 @@ #include "../features/i386/64bit-sse.c" #include "../features/i386/pkeys.c" +#include "../features/i386/64bit-ssp.c" +#include "../features/i386/32bit-ssp.c" #include "../features/i386/x32-core.c" /* See amd64.h. */ @@ -68,5 +70,13 @@ amd64_create_target_description (uint64_t xstate_bv_mask, bool is_x32, if (xstate_bv_mask & X86_XSTATE_PKRU) regnum = create_feature_i386_pkeys (tdesc.get (), regnum); + if (xstate_bv_mask & X86_XSTATE_CET_U) + { + if (!is_x32) + regnum = create_feature_i386_64bit_ssp (tdesc.get (), regnum); + else + regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum); + } + return tdesc.release (); } diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c index 4a39028a472..59daaa4c583 100644 --- a/gdb/arch/i386.c +++ b/gdb/arch/i386.c @@ -28,6 +28,7 @@ #include "../features/i386/32bit-avx512.c" #include "../features/i386/32bit-segments.c" #include "../features/i386/pkeys.c" +#include "../features/i386/32bit-ssp.c" /* See i386.h. */ @@ -66,5 +67,8 @@ i386_create_target_description (uint64_t xstate_bv_mask, bool is_linux, if (xstate_bv_mask & X86_XSTATE_PKRU) regnum = create_feature_i386_pkeys (tdesc.get (), regnum); + if (xstate_bv_mask & X86_XSTATE_CET_U) + regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum); + return tdesc.release (); } diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c index 3f041ece6eb..e57b6320ce7 100644 --- a/gdb/arch/x86-linux-tdesc-features.c +++ b/gdb/arch/x86-linux-tdesc-features.c @@ -65,6 +65,7 @@ struct x86_xstate_feature { static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = { /* Feature, i386, amd64, x32. */ + { X86_XSTATE_CET_U, false, true, true }, { X86_XSTATE_PKRU, true, true, true }, { X86_XSTATE_AVX512, true, true, true }, { X86_XSTATE_AVX, true, true, true }, diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7b6000abbea..c6c6fcaa17f 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -49750,6 +49750,10 @@ The @samp{org.gnu.gdb.i386.pkeys} feature is optional. It should describe a single register, @samp{pkru}. It is a 32-bit register valid for i386 and amd64. +The @samp{org.gnu.gdb.i386.pl3_ssp} feature is optional. It should describe the +user mode register @samp{pl3_ssp} which has 64 bits on amd64. Following the +restriction of the Linux kernel, only amd64 is supported for now. + @node LoongArch Features @subsection LoongArch Features @cindex target descriptions, LoongArch Features diff --git a/gdb/features/Makefile b/gdb/features/Makefile index 7c10f203faa..5f918ca77e3 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -223,6 +223,7 @@ FEATURE_XMLFILES = aarch64-core.xml \ i386/32bit-avx.xml \ i386/32bit-avx512.xml \ i386/32bit-segments.xml \ + i386/32bit-ssp.xml \ i386/64bit-avx512.xml \ i386/64bit-core.xml \ i386/64bit-segments.xml \ @@ -230,6 +231,7 @@ FEATURE_XMLFILES = aarch64-core.xml \ i386/64bit-linux.xml \ i386/64bit-sse.xml \ i386/pkeys.xml \ + i386/64bit-ssp.xml \ i386/x32-core.xml \ loongarch/base32.xml \ loongarch/base64.xml \ diff --git a/gdb/features/i386/32bit-ssp.c b/gdb/features/i386/32bit-ssp.c new file mode 100644 index 00000000000..991bae3c1e6 --- /dev/null +++ b/gdb/features/i386/32bit-ssp.c @@ -0,0 +1,14 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: 32bit-ssp.xml */ + +#include "gdbsupport/tdesc.h" + +static int +create_feature_i386_32bit_ssp (struct target_desc *result, long regnum) +{ + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.i386.pl3_ssp"); + tdesc_create_reg (feature, "pl3_ssp", regnum++, 1, NULL, 32, "data_ptr"); + return regnum; +} diff --git a/gdb/features/i386/32bit-ssp.xml b/gdb/features/i386/32bit-ssp.xml new file mode 100644 index 00000000000..d17e7004eec --- /dev/null +++ b/gdb/features/i386/32bit-ssp.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/gdb/features/i386/64bit-ssp.c b/gdb/features/i386/64bit-ssp.c new file mode 100644 index 00000000000..5468099ddf6 --- /dev/null +++ b/gdb/features/i386/64bit-ssp.c @@ -0,0 +1,14 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: 64bit-ssp.xml */ + +#include "gdbsupport/tdesc.h" + +static int +create_feature_i386_64bit_ssp (struct target_desc *result, long regnum) +{ + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.i386.pl3_ssp"); + tdesc_create_reg (feature, "pl3_ssp", regnum++, 1, NULL, 64, "data_ptr"); + return regnum; +} diff --git a/gdb/features/i386/64bit-ssp.xml b/gdb/features/i386/64bit-ssp.xml new file mode 100644 index 00000000000..a0688d018a5 --- /dev/null +++ b/gdb/features/i386/64bit-ssp.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 54aa1294917..b338029d990 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -8353,7 +8353,8 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep, const struct tdesc_feature *feature_core; const struct tdesc_feature *feature_sse, *feature_avx, *feature_avx512, - *feature_pkeys, *feature_segments; + *feature_pkeys, *feature_segments, + *feature_pl3_ssp; int i, num_regs, valid_p; if (! tdesc_has_registers (tdesc)) @@ -8379,6 +8380,9 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep, /* Try PKEYS */ feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys"); + /* Try Shadow Stack. */ + feature_pl3_ssp = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pl3_ssp"); + valid_p = 1; /* The XCR0 bits. */ @@ -8494,6 +8498,15 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep, tdep->pkeys_register_names[i]); } + if (feature_pl3_ssp != nullptr) + { + if (tdep->ssp_regnum < 0) + tdep->ssp_regnum = I386_PL3_SSP_REGNUM; + + valid_p &= tdesc_numbered_register (feature_pl3_ssp, tdesc_data, + tdep->ssp_regnum, "pl3_ssp"); + } + return valid_p; } @@ -8785,6 +8798,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* No segment base registers. */ tdep->fsbase_regnum = -1; + /* No shadow stack pointer register. */ + tdep->ssp_regnum = -1; + tdesc_arch_data_up tdesc_data = tdesc_data_alloc (); set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction); diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h index 3f990e71abf..8912a72cc6e 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -191,6 +191,9 @@ struct i386_gdbarch_tdep : gdbarch_tdep_base /* PKEYS register names. */ const char * const *pkeys_register_names = nullptr; + /* Shadow stack pointer register. */ + int ssp_regnum = 0; + /* Register number for %fsbase. Set this to -1 to indicate the absence of segment base registers. */ int fsbase_regnum = 0; @@ -293,6 +296,7 @@ enum i386_regnum I386_ZMM0H_REGNUM, /* %zmm0h */ I386_ZMM7H_REGNUM = I386_ZMM0H_REGNUM + 7, I386_PKRU_REGNUM, + I386_PL3_SSP_REGNUM, I386_FSBASE_REGNUM, I386_GSBASE_REGNUM }; diff --git a/gdb/nat/x86-linux-tdesc.c b/gdb/nat/x86-linux-tdesc.c index c5eac277bfd..60ab23eb795 100644 --- a/gdb/nat/x86-linux-tdesc.c +++ b/gdb/nat/x86-linux-tdesc.c @@ -110,6 +110,8 @@ x86_linux_tdesc_for_tid (int tid, uint64_t *xstate_bv_storage, = x86_fetch_xsave_layout (xcr0, x86_xsave_length ()); *xstate_bv_storage = xcr0; + if (x86_check_ssp_support (tid)) + *xstate_bv_storage |= X86_XSTATE_CET_U; } } diff --git a/gdb/nat/x86-linux.c b/gdb/nat/x86-linux.c index ad3ed3c2289..0b3a0d438dd 100644 --- a/gdb/nat/x86-linux.c +++ b/gdb/nat/x86-linux.c @@ -17,6 +17,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "elf/common.h" +#include "gdbsupport/common-defs.h" +#include "nat/gdb_ptrace.h" +#include "nat/linux-ptrace.h" +#include "nat/x86-cpuid.h" +#include #include "x86-linux.h" #include "x86-linux-dregs.h" #include "nat/gdb_ptrace.h" @@ -126,3 +132,52 @@ x86_linux_ptrace_get_arch_size (int tid) return x86_linux_arch_size (false, false); #endif } + +bool +x86_check_ssp_support (const int tid) +{ + /* It's not enough to check shadow stack support with the ptrace call + below only, as we cannot distinguish between shadow stack not enabled + for the current thread and shadow stack is not supported by HW. In + both scenarios the ptrace call fails with ENODEV. In case shadow + stack is not enabled for the current thread, we still want to return + true. */ + unsigned int eax, ebx, ecx, edx; + + __get_cpuid_count (7, 0, &eax, &ebx, &ecx, &edx); + + if ((ecx & bit_SHSTK) == 0) + return false; + + /* Further check for NT_X86_SHSTK kernel support. */ + uint64_t ssp; + iovec iov {&ssp, sizeof (ssp) }; + + errno = 0; + int res = ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov); + if (res < 0) + { + if (errno == EINVAL) + { + /* The errno EINVAL for a PTRACE_GETREGSET call indicates that + kernel support is not available. */ + return false; + } + else if (errno == ENODEV) + { + /* At this point, since we already checked CPUID, the errno + ENODEV for a PTRACE_GETREGSET call indicates that shadow + stack is not enabled for the current thread. As it could be + enabled later, we still want to return true here. */ + return true; + } + else + { + warning (_("Unknown ptrace error for NT_X86_SHSTK: %s"), + safe_strerror (errno)); + return false; + } + } + + return true; +} diff --git a/gdb/nat/x86-linux.h b/gdb/nat/x86-linux.h index 7c0ac7718b6..e0df4effcde 100644 --- a/gdb/nat/x86-linux.h +++ b/gdb/nat/x86-linux.h @@ -75,4 +75,8 @@ struct x86_linux_arch_size extern x86_linux_arch_size x86_linux_ptrace_get_arch_size (int tid); +/* Check shadow stack hardware and kernel support. */ + +extern bool x86_check_ssp_support (const int tid); + #endif /* GDB_NAT_X86_LINUX_H */ diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c new file mode 100644 index 00000000000..643ef2d5f56 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2018-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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.arch/amd64-ssp.exp b/gdb/testsuite/gdb.arch/amd64-ssp.exp new file mode 100644 index 00000000000..6ddc875b9a3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-ssp.exp @@ -0,0 +1,50 @@ +# Copyright 2018-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 accessing the shadow stack pointer register. + +require allow_ssp_tests + +standard_testfile amd64-shadow-stack.c + +save_vars { ::env(GLIBC_TUNABLES) } { + + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" + + if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + additional_flags="-fcf-protection=return"] } { + return -1 + } + + if {![runto_main]} { + return -1 + } + + # Read PL3_SSP register. + set ssp_main [get_hexadecimal_valueof "\$pl3_ssp" "read pl3_ssp value"] + + # Write PL3_SSP register. + gdb_test "print /x \$pl3_ssp = 0x12345678" "= 0x12345678" "set pl3_ssp value" + gdb_test "print /x \$pl3_ssp" "= 0x12345678" "read pl3_ssp value after setting" + + # Restore original value. + gdb_test "print /x \$pl3_ssp = $ssp_main" "= $ssp_main" "restore original pl3_ssp" + + # Potential CET violations often only occur after resuming normal execution. + # Therefore, it is important to test normal program continuation after + # configuring the shadow stack pointer. + gdb_continue_to_end +} + diff --git a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py index 278fa857d5d..94d553a8cce 100644 --- a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py +++ b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py @@ -65,6 +65,10 @@ class TestUnwinder(Unwinder): for reg in pending_frame.architecture().registers("general"): val = pending_frame.read_register(reg) + # Having unavailable registers leads to a fall back to the standard + # unwinders. Don't add unavailable registers to avoid this. + if (str (val) == ""): + continue unwinder.add_saved_register(reg, val) return unwinder diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index a86f534528c..fc35456f1d3 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -4225,6 +4225,75 @@ gdb_caching_proc allow_tsx_tests {} { return $allow_tsx_tests } +# Run a test on the target to check if it supports x86 shadow stack. Return 1 +# if shadow stack is enabled, 0 otherwise. + +gdb_caching_proc allow_ssp_tests {} { + global srcdir subdir gdb_prompt hex + + set me "allow_ssp_tests" + + if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } { + verbose "$me: target known to not support shadow stack." + return 0 + } + + # There is no need to check the actual HW in addition to ptrace support. + # We need both checks and ptrace will tell us about the HW state. + set compile_flags "{additional_flags=-fcf-protection=return}" + set src { int main() { return 0; } } + if {![gdb_simple_compile $me $src executable $compile_flags]} { + return 0 + } + + save_vars { ::env(GLIBC_TUNABLES) } { + + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" + + # No error message, compilation succeeded so now run it via gdb. + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load $obj + if {![runto_main]} { + return 0 + } + set shadow_stack_disabled_re "()" + if {[istarget *-*-linux*]} { + # Starting with v6.6., the Linux kernel supports CET shadow stack. + # Dependent on the target we can see a nullptr or "" + # when shadow stack is supported by HW and the linux kernel but + # not enabled for the current thread (for example due to a lack + # of compiler or glibc support for -fcf-protection). + set shadow_stack_disabled_re "$shadow_stack_disabled_re|(.*0x0)" + } + + set allow_ssp_tests 0 + gdb_test_multiple "print \$pl3_ssp" "test shadow stack support" { + -re -wrap "(.*$hex)((?!(.*0x0)).)" { + verbose -log "$me: Shadow stack support detected." + set allow_ssp_tests 1 + } + -re -wrap $shadow_stack_disabled_re { + # In case shadow stack is not enabled (for example due to a + # lack of compiler or glibc support for -fcf-protection). + verbose -log "$me: Shadow stack is not enabled." + } + -re -wrap "void" { + # In case we don't have hardware or kernel support. + verbose -log "$me: No shadow stack support." + } + } + + gdb_exit + } + + remote_file build delete $obj + + verbose "$me: returning $allow_ssp_tests" 2 + return $allow_ssp_tests +} + # Run a test on the target to see if it supports avx512bf16. Return 1 if so, # 0 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite. diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index d1fece717a7..5bbd4640e30 100644 --- a/gdb/x86-linux-nat.c +++ b/gdb/x86-linux-nat.c @@ -41,6 +41,7 @@ #include "nat/x86-linux.h" #include "nat/x86-linux-dregs.h" #include "nat/linux-ptrace.h" +#include "x86-tdep.h" #include "nat/x86-linux-tdesc.h" /* linux_nat_target::low_new_fork implementation. */ @@ -97,11 +98,10 @@ const struct target_desc * x86_linux_nat_target::read_description () { /* The x86_linux_tdesc_for_tid call only reads xcr0 the first time it is - called. The mask is stored in XSTATE_BV_STORAGE and reused on - subsequent calls. Note that GDB currently supports features for user - state components only. However, once supervisor state components are - supported in GDB XSTATE_BV_STORAGE will not be configured based on - xcr0 only. */ + called. Also it checks the enablement state of features which are + not configured in xcr0, such as CET shadow stack. Once the supported + features are identified, the XSTATE_BV_STORAGE value is configured + accordingly and preserved for subsequent calls of this function. */ static uint64_t xstate_bv_storage; if (inferior_ptid == null_ptid) @@ -215,6 +215,46 @@ x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr) } +/* See x86-linux-nat.h. */ + +void +x86_linux_fetch_ssp (regcache *regcache, const int tid) +{ + uint64_t ssp = 0x0; + iovec iov {&ssp, sizeof (ssp)}; + + /* The shadow stack may be enabled and disabled at runtime. Reading the + ssp might fail as shadow stack was not activated for the current + thread. We don't want to show a warning but silently return. The + register will be shown as unavailable for the user. */ + if (ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov) != 0) + return; + + x86_supply_ssp (regcache, ssp); +} + +/* See x86-linux-nat.h. */ + +void +x86_linux_store_ssp (const regcache *regcache, const int tid) +{ + uint64_t ssp = 0x0; + iovec iov {&ssp, sizeof (ssp)}; + x86_collect_ssp (regcache, ssp); + + /* Starting with v6.6., the Linux kernel supports CET shadow stack. + Dependent on the target the ssp register can be unavailable or + nullptr when shadow stack is supported by HW and the linux kernel but + not enabled for the current thread. In case of nullptr, GDB tries to + restore the shadow stack pointer after an inferior call. The ptrace + call with PTRACE_SETREGSET will fail here with errno ENODEV. We + don't want to throw an error in this case but silently continue. */ + errno = 0; + if ((ptrace (PTRACE_SETREGSET, tid, NT_X86_SHSTK, &iov) != 0) + && (errno != ENODEV)) + perror_with_name (_("Failed to write pl3_ssp register")); +} + void _initialize_x86_linux_nat (); void _initialize_x86_linux_nat () diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h index 3c2241bb0b6..d5dc1908090 100644 --- a/gdb/x86-linux-nat.h +++ b/gdb/x86-linux-nat.h @@ -92,4 +92,15 @@ struct x86_linux_nat_target : public x86_nat_target extern ps_err_e x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr); +/* Fetch the value of the shadow stack pointer register from process/thread + TID and store it to GDB's register cache. */ + +extern void x86_linux_fetch_ssp (regcache *regcache, const int tid); + +/* Read the value of the shadow stack pointer from GDB's register cache + and store it in the shadow stack pointer register of process/thread TID. + Throw an error in case of failure. */ + +extern void x86_linux_store_ssp (const regcache *regcache, const int tid); + #endif /* GDB_X86_LINUX_NAT_H */ diff --git a/gdb/x86-tdep.c b/gdb/x86-tdep.c index e50b5fb9fa4..08fb0e8d82d 100644 --- a/gdb/x86-tdep.c +++ b/gdb/x86-tdep.c @@ -17,10 +17,32 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "defs.h" +#include "i386-tdep.h" #include "x86-tdep.h" #include "symtab.h" +/* See x86-tdep.h. */ + +void +x86_supply_ssp (regcache *regcache, const uint64_t ssp) +{ + i386_gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + gdb_assert (tdep != nullptr && tdep->ssp_regnum > 0); + regcache->raw_supply (tdep->ssp_regnum, &ssp); +} + +/* See x86-tdep.h. */ + +void +x86_collect_ssp (const regcache *regcache, uint64_t& ssp) +{ + i386_gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + gdb_assert (tdep != nullptr && tdep->ssp_regnum > 0); + regcache->raw_collect (tdep->ssp_regnum, &ssp); +} + /* Check whether NAME is included in NAMES[LO] (inclusive) to NAMES[HI] (exclusive). */ diff --git a/gdb/x86-tdep.h b/gdb/x86-tdep.h index 2b5853adb8a..fcb3909b33e 100644 --- a/gdb/x86-tdep.h +++ b/gdb/x86-tdep.h @@ -20,6 +20,15 @@ #ifndef GDB_X86_TDEP_H #define GDB_X86_TDEP_H +/* Fill SSP to the shadow stack pointer in GDB's REGCACHE. */ + +extern void x86_supply_ssp (regcache *regcache, const uint64_t ssp); + +/* Collect the value of the shadow stack pointer in GDB's REGCACHE and + write it to SSP. */ + +extern void x86_collect_ssp (const regcache *regcache, uint64_t& ssp); + /* Checks whether PC lies in an indirect branch thunk using registers REGISTER_NAMES[LO] (inclusive) to REGISTER_NAMES[HI] (exclusive). */ diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc index 4575ea2fdc0..0e668c23b2a 100644 --- a/gdbserver/linux-x86-low.cc +++ b/gdbserver/linux-x86-low.cc @@ -253,7 +253,8 @@ static const int x86_64_regmap[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1 /* pkru */ + -1, /* pkru */ + -1 /* CET user mode register PL3_SSP. */ }; #define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0])) @@ -405,6 +406,18 @@ x86_target::low_cannot_fetch_register (int regno) return regno >= I386_NUM_REGS; } +static void +x86_fill_ssp_reg (regcache *regcache, void *buf) +{ + collect_register_by_name (regcache, "pl3_ssp", buf); +} + +static void +x86_store_ssp_reg (regcache *regcache, const void *buf) +{ + supply_register_by_name (regcache, "pl3_ssp", buf); +} + static void collect_register_i386 (struct regcache *regcache, int regno, void *buf) { @@ -544,6 +557,8 @@ static struct regset_info x86_regsets[] = x86_fill_gregset, x86_store_gregset }, { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_XSTATE, 0, EXTENDED_REGS, x86_fill_xstateregset, x86_store_xstateregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_SHSTK, 0, + OPTIONAL_RUNTIME_REGS, x86_fill_ssp_reg, x86_store_ssp_reg }, # ifndef __x86_64__ # ifdef HAVE_PTRACE_GETFPXREGS { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, 0, sizeof (elf_fpxregset_t), @@ -897,6 +912,17 @@ x86_linux_read_description () { if (regset->nt_type == NT_X86_XSTATE) regset->size = xsave_len; + else if (regset->nt_type == NT_X86_SHSTK) + { + /* We must configure the size of the NT_X86_SHSTK regset + from non-zero value to it's appropriate size, even though + the ptrace call is only tested for NT_X86_XSTATE request, + because the NT_X86_SHSTK regset is of type + OPTIONAL_RUNTIME_REGS. A ptrace call with NT_X86_SHSTK + request may only be successful later on, once shadow + stack is enabled for the current thread. */ + regset->size = sizeof (CORE_ADDR); + } else gdb_assert_not_reached ("invalid regset type."); } diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h index 76932c765a7..9dbf3be6404 100644 --- a/gdbsupport/x86-xstate.h +++ b/gdbsupport/x86-xstate.h @@ -28,6 +28,7 @@ #define X86_XSTATE_ZMM_H_ID 6 #define X86_XSTATE_ZMM_ID 7 #define X86_XSTATE_PKRU_ID 9 +#define X86_XSTATE_CET_U_ID 11 /* The extended state feature bits. */ #define X86_XSTATE_X87 (1ULL << X86_XSTATE_X87_ID) @@ -42,6 +43,7 @@ | X86_XSTATE_ZMM) #define X86_XSTATE_PKRU (1ULL << X86_XSTATE_PKRU_ID) +#define X86_XSTATE_CET_U (1ULL << X86_XSTATE_CET_U_ID) /* Total size of the XSAVE area extended region and offsets of register states within the region. Offsets are set to 0 to @@ -86,7 +88,8 @@ constexpr bool operator!= (const x86_xsave_layout &lhs, /* Supported mask of state-component bitmap xstate_bv. The SDM defines xstate_bv as XCR0 | IA32_XSS. */ -#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK) +#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK\ + | X86_XSTATE_CET_U) #define X86_XSTATE_SSE_SIZE 576 #define X86_XSTATE_AVX_SIZE 832 From patchwork Fri Dec 20 20:04:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103531 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 4903D3858C51 for ; Fri, 20 Dec 2024 20:13:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4903D3858C51 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=lC9nLkWf X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by sourceware.org (Postfix) with ESMTPS id 336723858D3C for ; Fri, 20 Dec 2024 20:06:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 336723858D3C 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 336723858D3C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725176; cv=none; b=eLpkmwQ8ilW+HxdqeHrmi17TvhzTJGlKws6Ck5/2tnRJGm0WpODFpfHJqXCQiSaM6BJJ5UcC2hHAC//PCn2rMxPuXR92xxfWqPXhFR6WpRAu95qupFXXNlwpoTruZL4fg9Pxb0VvMMXA4QYQlcoEMIkz422A6lQekAXMD6uw7FA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725176; c=relaxed/simple; bh=inXJeMQtdcd2Odin8V5/1LzO82wf1WYrYICvZ/70Ugo=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=eEKxrYsBAclQurKhtx8tncw2Yb7K9iCEonB3OLkzJZZrItCycgdZIczJtFKa98J6RAx/9PixNsU+6F3xlpG7Yjx8C9ktAzGK56iHx9XhyKHcbGFLYMgCvGU6dCz9fm7YUfy2VuDxowV1ekMZkWNuRctjLLZgD9L+3fh3GPnmArY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 336723858D3C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725176; x=1766261176; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=inXJeMQtdcd2Odin8V5/1LzO82wf1WYrYICvZ/70Ugo=; b=lC9nLkWfgUKqZZeEMvyImvNcTwmUKQGor6zQBxr+Rz3mLq6MynBHzsl9 h7pDJvBBNm/yW/vpj8Iyy1IZfjdmohQ8jr/Cwsm24pWpnzPELuAlIgqH0 0Lx318CNrfug0+p6VN2OpMWzpi9QobhzZUeuu5f0fqzrEiwGH9eDsOzOh 8SzgTHuWx9P/UYSQ99IHFoVA11Lk2waB+g6eOHmfjBoPn3/lTsroK2u/o EkMdyO7q0eqbe5dlbkNYKqkIRPrnEqtVGhFHaDZQ1etIzgfVKvJhSD0iT ONTe+LfownKlePC0CWxOW/1TamiONeezTCZs30lyRKEzL3gZHS1ylmVik Q==; X-CSE-ConnectionGUID: y4HPHSirQkm3W0wpl9yKBA== X-CSE-MsgGUID: 4yaDCZEHRUe6YTKOgxoHnw== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="52689144" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="52689144" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:16 -0800 X-CSE-ConnectionGUID: mu7A2fcARX2ghMjxYMbiQA== X-CSE-MsgGUID: NXpp1nvFRBCwymqPF07FZQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="98809956" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:14 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack. Date: Fri, 20 Dec 2024 20:04:56 +0000 Message-Id: <20241220200501.324191-8-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 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: Felix Willgerodt Intel's Control-Flow Enforcement Technology (CET) provides the shadow stack feature for the x86 architecture. This commit adds support to write and read the shadow-stack node in corefiles. This helps debugging return address violations post-mortem. The format is synced with the linux kernel commit "x86: Add PTRACE interface for shadow stack". As the linux kernel restricts shadow stack support to 64-bit, apply the fix for amd64 only. Co-Authored-By: Christina Schimpe Reviewed-by: Thiago Jung Bauermann --- bfd/elf.c | 24 +++++++++ gdb/amd64-linux-tdep.c | 52 +++++++++++++++++-- .../gdb.arch/amd64-shadow-stack-corefile.exp | 50 ++++++++++++++++++ 3 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp diff --git a/bfd/elf.c b/bfd/elf.c index 78394319bf0..23f1ebcd83c 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -10365,6 +10365,12 @@ elfcore_grok_xstatereg (bfd *abfd, Elf_Internal_Note *note) return elfcore_make_note_pseudosection (abfd, ".reg-xstate", note); } +static bool +elfcore_grok_sspreg (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-ssp", note); +} + static bool elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note) { @@ -11060,6 +11066,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return true; + case NT_X86_SHSTK: /* Linux CET extension. */ + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_sspreg (abfd, note); + else + return true; + case NT_PPC_VMX: if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) @@ -12510,6 +12523,15 @@ elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz, note_name, NT_X86_XSTATE, xfpregs, size); } +static char * +elfcore_write_sspreg (bfd *abfd, char *buf, int *bufsiz, + const void *ssp, int size) +{ + const char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_X86_SHSTK, ssp, size); +} + char * elfcore_write_x86_segbases (bfd *abfd, char *buf, int *bufsiz, const void *regs, int size) @@ -13105,6 +13127,8 @@ elfcore_write_register_note (bfd *abfd, return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-x86-segbases") == 0) return elfcore_write_x86_segbases (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-ssp") == 0) + return elfcore_write_sspreg (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-ppc-vmx") == 0) return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-ppc-vsx") == 0) diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 8ed381e1a2c..95f643b1217 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -44,6 +44,7 @@ #include "expop.h" #include "arch/amd64-linux-tdesc.h" #include "inferior.h" +#include "x86-tdep.h" /* The syscall's XML filename for i386. */ #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml" @@ -1586,6 +1587,14 @@ amd64_linux_record_signal (struct gdbarch *gdbarch, return 0; } +/* Get shadow stack pointer state from core dump. */ + +static bool +amd64_linux_core_read_ssp_state_p (bfd *abfd) +{ + return bfd_get_section_by_name (abfd, ".reg-ssp") != NULL; +} + /* Get Linux/x86 target description from core dump. */ static const struct target_desc * @@ -1595,11 +1604,14 @@ amd64_linux_core_read_description (struct gdbarch *gdbarch, { /* Linux/x86-64. */ x86_xsave_layout layout; - uint64_t xcr0 = i386_linux_core_read_xsave_info (abfd, layout); - if (xcr0 == 0) - xcr0 = X86_XSTATE_SSE_MASK; + uint64_t xstate_bv_mask = i386_linux_core_read_xsave_info (abfd, layout); + if (xstate_bv_mask == 0) + xstate_bv_mask = X86_XSTATE_SSE_MASK; + + if (amd64_linux_core_read_ssp_state_p (abfd)) + xstate_bv_mask |= X86_XSTATE_CET_U; - return amd64_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK, + return amd64_linux_read_description (xstate_bv_mask & X86_XSTATE_ALL_MASK, gdbarch_ptr_bit (gdbarch) == 32); } @@ -1630,6 +1642,30 @@ static const struct regset amd64_linux_xstateregset = amd64_linux_collect_xstateregset }; +static void +amd64_linux_supply_ssp (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *ssp, size_t len) +{ + x86_supply_ssp (regcache, *static_cast (ssp)); +} + +static void +amd64_linux_collect_ssp (const struct regset *regset, + const struct regcache *regcache, int regnum, + void *ssp, size_t len) +{ + x86_collect_ssp (regcache, *static_cast (ssp)); +} + +/* Shadow stack pointer register. */ + +static const struct regset amd64_linux_ssp_register + { + NULL, amd64_linux_supply_ssp, amd64_linux_collect_ssp + }; + + /* Iterate over core file register note sections. */ static void @@ -1646,6 +1682,14 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, cb (".reg-xstate", tdep->xsave_layout.sizeof_xsave, tdep->xsave_layout.sizeof_xsave, &amd64_linux_xstateregset, "XSAVE extended state", cb_data); + + /* SSP can be unavailable. Thus, we need to check the register status + in case we write a core file (regcache != nullptr). */ + if (tdep->ssp_regnum > 0 + && (regcache == nullptr + || REG_VALID == regcache->get_register_status (tdep->ssp_regnum))) + cb (".reg-ssp", 8, 8, &amd64_linux_ssp_register, + "shadow stack pointer", cb_data); } /* The instruction sequences used in x86_64 machines for a diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp new file mode 100644 index 00000000000..25cc1529f0d --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp @@ -0,0 +1,50 @@ +# Copyright 2021-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 the shadow stack pointer note in core dumps. + +require allow_ssp_tests + +standard_testfile amd64-shadow-stack.c +set gcorefile ${binfile}.gcore + +save_vars { ::env(GLIBC_TUNABLES) } { + + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" + + if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + additional_flags="-fcf-protection=return"] } { + return -1 + } + + if { ![runto_main] } { + return -1 + } + + # Save ssp for comparison in the corefile session. + set ssp [get_hexadecimal_valueof "\$pl3_ssp" ""] + + if { ![gdb_gcore_cmd $gcorefile "save a corefile"] } { + return -1 + } + + # Now restart gdb and load the corefile. + clean_restart ${binfile} + + gdb_test "core ${gcorefile}" \ + "Core was generated by .*" "re-load generated corefile" + + gdb_test "print /x \$pl3_ssp" "= $ssp" +} From patchwork Fri Dec 20 20:04:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103532 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 915823858406 for ; Fri, 20 Dec 2024 20:15:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 915823858406 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=T0KHBo+a X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by sourceware.org (Postfix) with ESMTPS id F2F0F3858C51 for ; Fri, 20 Dec 2024 20:06:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F2F0F3858C51 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 F2F0F3858C51 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725182; cv=none; b=s6drjLNDtOvhCyCselrqvBUbRlP3KHfkhz65Vc/dnf/KkUbumlKynlq1u14MKl287+blCaPjJqIKQznPKT6ZDebDeZuBvHMszxif5Ob5Dny+3JEBKErhQBouIKVaBm7A9jiVAJng9sHl+gmpTOAdqaUbZQiFs9ZvCI/l/pDYifk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725182; c=relaxed/simple; bh=rP6g/QBQvx8ANTQDY4zuejW0xnpp2WgIILLbHxrVCW0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=NdcT5avvx6cXW6XeJmSjNWE36rycWrqzrUuHiJKkVGE0tRCdjOAlL60y2voiPcjXYG4NIoyI69iqjfnV4yRPUtUAVdLDukoOrE+edum+2XfLibEWVBdWPEfum/XdnqD67bNYJoBzQzDSMAsRIB0Y6xDi5YEP4i3FaxsVIXTGTxU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F2F0F3858C51 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725182; x=1766261182; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=rP6g/QBQvx8ANTQDY4zuejW0xnpp2WgIILLbHxrVCW0=; b=T0KHBo+awE6hoOyP9pqrDTlF5+bu0caYioSz1SYpUJBtvOiTxmWlA1Ls uP0xbjIRzsVKK/FGz3v5Zpe2ges3xxvmCkXUw9yyQTyn7oFPpP+tETqL2 YZQOCkEQ1/gYzF/O67UG1dGw5dT4QN+FJ0IepWxr6b/dTxqeleydrWBwH uQAGEwhjiajEZA1tShfZ0wSnwyME6duJM5oe9Y/3jYsLUrl+fIFH9S44G rIKtauC5IlpmFglmrahI8U6xzBJUmwzGbEjxvKQ4N6n1aFoxwlQQhlmQl g7gcGkrZj9GakYOZ50cxcY/coZ5eEGYkKMvG24scfv8CqbKjckXs8UeKA g==; X-CSE-ConnectionGUID: RIf6daTHR/SbrdTGBRnM0w== X-CSE-MsgGUID: GjdMS6fiRFSSZVDJIZTn+g== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="52689151" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="52689151" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:21 -0800 X-CSE-ConnectionGUID: AbqDQygNQeSF+c9cAdjkgw== X-CSE-MsgGUID: /HbXJ9grRDGX02JdE5/QEg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="98809959" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:20 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux. Date: Fri, 20 Dec 2024 20:04:57 +0000 Message-Id: <20241220200501.324191-9-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 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 Unwind the $pl3_ssp register. We now have an updated value for the shadow stack pointer when moving up or down the frame level. Note that $pl3_ssp can become unavailable when moving to a frame before the shadow stack enablement. In the example below, shadow stack is enabled in the function 'call1'. Thus, when moving to a frame level above the function, $pl3_ssp will become unavaiable. Following the restriction of the linux kernel, implement the unwinding for amd64 linux only. Before this patch: ~~~ Breakpoint 1, call2 (j=3) at sample.c:44 44 return 42; (gdb) p $pl3_ssp $1 = (void *) 0x7ffff79ffff8 (gdb) up 55 call2 (3); (gdb) p $pl3_ssp $2 = (void *) 0x7ffff79ffff8 (gdb) up 68 call1 (43); (gdb) p $pl3_ssp $3 = (void *) 0x7ffff79ffff8 ~~~ After this patch: ~~~ Breakpoint 1, call2 (j=3) at sample.c:44 44 return 42; (gdb) p $pl3_ssp $1 = (void *) 0x7ffff79ffff8 (gdb) up 55 call2 (3); (gdb) p $pl3_ssp $2 = (void *) 0x7ffff7a00000 (gdb) up 68 call1 (43i); (gdb) p $pl3_ssp $3 = ~~~ As we now have an updated value for each selected frame, the return command is now enabled for shadow stack enabled programs, too. We therefore add a test for the return command and shadow stack support, and for an updated shadow stack pointer after a frame level change. Reviewed-by: Thiago Jung Bauermann --- gdb/amd64-linux-tdep.c | 69 +++++++++++++++ gdb/linux-tdep.c | 47 ++++++++++ gdb/linux-tdep.h | 7 ++ .../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++ gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++ 5 files changed, 224 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 95f643b1217..895feac85e8 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -45,6 +45,8 @@ #include "arch/amd64-linux-tdesc.h" #include "inferior.h" #include "x86-tdep.h" +#include "dwarf2/frame.h" +#include "frame-unwind.h" /* The syscall's XML filename for i386. */ #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml" @@ -1873,6 +1875,72 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch, return (addr & amd64_linux_lam_untag_mask ()); } +static value * +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame, + void **this_cache, int regnum) +{ + value *v = frame_unwind_got_register (this_frame, regnum, regnum); + gdb_assert (v != nullptr); + + gdbarch *gdbarch = get_frame_arch (this_frame); + + if (v->entirely_available () && !v->optimized_out ()) + { + int size = register_size (gdbarch, regnum); + bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (), + size, byte_order); + + /* Starting with v6.6., the Linux kernel supports CET shadow stack. + Using /proc/PID/smaps we can only check if the current shadow + stack pointer SSP points to shadow stack memory. Only if this is + the case a valid previous shadow stack pointer can be + calculated. */ + std::pair range; + if (linux_address_in_shadow_stack_mem_range (ssp, &range)) + { + /* The shadow stack grows downwards. To compute the previous + shadow stack pointer, we need to increment SSP. + For x32 the shadow stack elements are still 64-bit aligned. + Thus, we cannot use gdbarch_addr_bit to compute the new stack + pointer. */ + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch); + const int bytes_per_word + = (binfo->bits_per_word / binfo->bits_per_byte); + CORE_ADDR new_ssp = ssp + bytes_per_word; + + /* If NEW_SSP points to the end of or before (<=) the current + shadow stack memory range we consider NEW_SSP as valid (but + empty). */ + if (new_ssp <= range.second) + return frame_unwind_got_address (this_frame, regnum, new_ssp); + } + } + + /* Return a value which is marked as unavailable in case we could not + calculate a valid previous shadow stack pointer. */ + value *retval + = value::allocate_register (get_next_frame_sentinel_okay (this_frame), + regnum, register_type (gdbarch, regnum)); + retval->mark_bytes_unavailable (0, retval->type ()->length ()); + return retval; +} + +static void +amd64_init_reg (gdbarch *gdbarch, int regnum, dwarf2_frame_state_reg *reg, + const frame_info_ptr &this_frame) +{ + if (regnum == gdbarch_pc_regnum (gdbarch)) + reg->how = DWARF2_FRAME_REG_RA; + else if (regnum == gdbarch_sp_regnum (gdbarch)) + reg->how = DWARF2_FRAME_REG_CFA; + else if (regnum == AMD64_PL3_SSP_REGNUM) + { + reg->how = DWARF2_FRAME_REG_FN; + reg->loc.fn = amd64_linux_dwarf2_prev_ssp; + } +} + static void amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, int num_disp_step_buffers) @@ -1927,6 +1995,7 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, set_gdbarch_remove_non_address_bits_watchpoint (gdbarch, amd64_linux_remove_non_address_bits_watchpoint); + dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg); } static void diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index d3452059ce2..3a20b12c3d7 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -47,6 +47,7 @@ #include #include +#include /* This enum represents the values that the user can choose when informing the Linux kernel about which memory mappings will be @@ -96,6 +97,10 @@ struct smaps_vmflags /* Memory map has memory tagging enabled. */ unsigned int memory_tagging : 1; + + /* Memory map used for shadow stack. */ + + unsigned int shadow_stack_memory : 1; }; /* Data structure that holds the information contained in the @@ -537,6 +542,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v) v->shared_mapping = 1; else if (strcmp (s, "mt") == 0) v->memory_tagging = 1; + else if (strcmp (s, "ss") == 0) + v->shadow_stack_memory = 1; } } @@ -2744,6 +2751,46 @@ show_dump_excluded_mappings (struct ui_file *file, int from_tty, " flag is %s.\n"), value); } +/* See linux-tdep.h. */ + +bool +linux_address_in_shadow_stack_mem_range + (CORE_ADDR addr, std::pair *range) +{ + if (!target_has_execution () || current_inferior ()->fake_pid_p) + return false; + + const int pid = current_inferior ()->pid; + + std::string smaps_file = string_printf ("/proc/%d/smaps", pid); + + gdb::unique_xmalloc_ptr data + = target_fileio_read_stralloc (nullptr, smaps_file.c_str ()); + + if (data == nullptr) + return false; + + const std::vector smaps + = parse_smaps_data (data.get (), std::move (smaps_file)); + + auto find_addr_mem_range = [&addr] (const smaps_data &map) + { + bool addr_in_mem_range + = (addr >= map.start_address && addr < map.end_address); + return (addr_in_mem_range && map.vmflags.shadow_stack_memory); + }; + auto it = std::find_if (smaps.begin (), smaps.end (), find_addr_mem_range); + + if (it != smaps.end ()) + { + range->first = it->start_address; + range->second = it->end_address; + return true; + } + + return false; +} + /* To be called from the various GDB_OSABI_LINUX handlers for the various GNU/Linux architectures and machine types. diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h index bf4220bf75b..97dcc75a79c 100644 --- a/gdb/linux-tdep.h +++ b/gdb/linux-tdep.h @@ -117,4 +117,11 @@ extern CORE_ADDR linux_get_hwcap2 (); extern struct link_map_offsets *linux_ilp32_fetch_link_map_offsets (); extern struct link_map_offsets *linux_lp64_fetch_link_map_offsets (); +/* Returns true if ADDR belongs to a shadow stack memory range. If this + is the case, assign the shadow stack memory range to RANGE + [start_address, end_address). */ + +extern bool linux_address_in_shadow_stack_mem_range + (CORE_ADDR addr, std::pair *range); + #endif /* GDB_LINUX_TDEP_H */ diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp new file mode 100644 index 00000000000..17f32ce3964 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp @@ -0,0 +1,88 @@ +# Copyright 2018-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 shadow stack enabling for frame level update and the return command. + +require allow_ssp_tests + +standard_testfile amd64-shadow-stack.c + +save_vars { ::env(GLIBC_TUNABLES) } { + + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" + + if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + {debug additional_flags="-fcf-protection=return"}] } { + return -1 + } + + clean_restart ${binfile} + if { ![runto_main] } { + return -1 + } + + set call1_line [ gdb_get_line_number "break call1" ] + set call2_line [ gdb_get_line_number "break call2" ] + + # Extract shadow stack pointer inside main, call1 and call2 function. + gdb_breakpoint $call1_line + gdb_breakpoint $call2_line + set ssp_main [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in main"] + gdb_continue_to_breakpoint "break call1" ".*break call1.*" + set ssp_call1 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call1"] + gdb_continue_to_breakpoint "break call2" ".*break call2.*" + set ssp_call2 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call2"] + + with_test_prefix "test frame level update" { + gdb_test "up" "call1.*" "move to frame 1" + gdb_test "print /x \$pl3_ssp" "= $ssp_call1" "check pl3_ssp of frame 1" + gdb_test "up" "main.*" "move to frame 2" + gdb_test "print /x \$pl3_ssp" "= $ssp_main" "check pl3_ssp of frame 2" + gdb_test "frame 0" "call2.*" "move to frame 0" + gdb_test "print /x \$pl3_ssp" "= $ssp_call2" "check pl3_ssp of frame 0" + } + + with_test_prefix "test return from current frame" { + gdb_test "return (int) 1" "#0.*call1.*" \ + "Test shadow stack return from current frame" \ + "Make.*return now\\? \\(y or n\\) " "y" + + # Potential CET violations often only occur after resuming normal execution. + # Therefore, it is important to test normal program continuation after + # testing the return command. + gdb_continue_to_end + } + + clean_restart ${binfile} + if { ![runto_main] } { + return -1 + } + + with_test_prefix "test return from past frame" { + gdb_breakpoint $call2_line + gdb_continue_to_breakpoint "break call2" ".*break call2.*" + + gdb_test "frame 1" ".*in call1.*" + + gdb_test "return (int) 1" "#0.*main.*" \ + "Test shadow stack return from past frame" \ + "Make.*return now\\? \\(y or n\\) " "y" + + # Potential CET violations often only occur after resuming normal execution. + # Therefore, it is important to test normal program continuation after + # testing the return command. + gdb_continue_to_end + } +} diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c index 643ef2d5f56..80389730bc2 100644 --- a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c @@ -15,8 +15,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +static int +call2 () +{ + return 42; /* break call2. */ +} + +static int +call1 () +{ + return call2 (); /* break call1. */ +} + int main () { + call1 (); /* break main. */ return 0; } From patchwork Fri Dec 20 20:04:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103524 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 38E3D3858416 for ; Fri, 20 Dec 2024 20:09:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 38E3D3858416 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=DMqanGkg X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by sourceware.org (Postfix) with ESMTPS id BED613858C3A for ; Fri, 20 Dec 2024 20:06:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BED613858C3A 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 BED613858C3A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725188; cv=none; b=YINuiVcnZsswDpIWD+HCL5VGMflIRTQPleDrPH4+MIkb3glA3t9DrG9+k23tgQ8b7SlRUxKMavfxjrH33/M9dlWNsiNQbB9NSMM1O/LXi7Gcw5X/iw0FsuparlQykNOBuh3N/zBSBiVHiC0yzwVILi+E9empBVOIc1yRiwFda48= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725188; c=relaxed/simple; bh=zhUsPmvC8tq3P+b+e326FO+bP/m6DCbNrV7XFbUC5fg=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=YNhbNLgXJuOi8IvEwLY29qkqnijwvbGrU7Xrk62yOPw3yfTnmK1or0rQHSZ0xuG61WI0+53V6zcwE8Q9GVDfvWldVls2Xhk/+bchNCWKcU+TKNZ+vwnzCFyOUIlqfNWNm0qe/f5DOq7jbhwDA7/gAks4SYGipUXVrV+rcth4BJE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BED613858C3A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725188; x=1766261188; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=zhUsPmvC8tq3P+b+e326FO+bP/m6DCbNrV7XFbUC5fg=; b=DMqanGkga8G5IxGS9Y4qVhQ9D9vXuo4fDK4PSpwVeWNVuOg+mr6HFDyS 3Eef7WOdpVdHloM2tRl04bpc3tk4Gf2Fv8mQaZr+aPcZvaRpBaor9fP3+ ZWZsevAcIVdGUglFH0gnTFsK7oEIHKVND569uMH4NB+4A/GUDTI086fEK WVmcgvLqsmWWL6YnBgLYMwo3TLHvX9WK/EhPxmuEmLDg4qfwtYwAUj58y 9BNaFV2ayLGCAZlQfMRw5RAn/ENraDYizj9p90USRgi23orjdooRfjbb1 +/wDhBmnWd7Z4ovyVtUEZYgcg2UPhL6MbzN/2VObAZjuMLhdMEAGMz4We A==; X-CSE-ConnectionGUID: Yt7kdoq2R16ENZ2HJ+uMxA== X-CSE-MsgGUID: vrDbgZXERdCD+R4cFe2v8g== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="52689153" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="52689153" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:27 -0800 X-CSE-ConnectionGUID: j2Qq+njKQUi4MuoPlPEr0Q== X-CSE-MsgGUID: TS3CNO48Th67vJDywFyS5A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="98809961" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:26 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support. Date: Fri, 20 Dec 2024 20:04:58 +0000 Message-Id: <20241220200501.324191-10-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.3 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 Inferior calls in GDB reset the current PC to the beginning of the function that is called. As no call instruction is executed the new return address needs to be pushed to the shadow stack and the shadow stack pointer needs to be updated. This commit adds a new gdbarch method to push an address on the shadow stack. The method is used to adapt the function 'call_function_by_hand_dummy' for inferior call shadow stack support. --- gdb/gdbarch-gen.c | 32 ++++++++++++++++++++++++++++++++ gdb/gdbarch-gen.h | 14 ++++++++++++++ gdb/gdbarch_components.py | 16 ++++++++++++++++ gdb/infcall.c | 6 ++++++ 4 files changed, 68 insertions(+) diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index d05c7a3cbdf..c33c476dfdb 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -260,6 +260,7 @@ struct gdbarch gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags; gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings; gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes; + gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -531,6 +532,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of get_pc_address_flags, invalid_p == 0. */ /* Skip verify of read_core_file_mappings, invalid_p == 0. */ /* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */ + /* Skip verify of shadow_stack_push, has predicate. */ if (!log.empty ()) internal_error (_("verify_gdbarch: the following are invalid ...%s"), log.c_str ()); @@ -1396,6 +1398,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: use_target_description_from_corefile_notes = <%s>\n", host_address_to_string (gdbarch->use_target_description_from_corefile_notes)); + gdb_printf (file, + "gdbarch_dump: gdbarch_shadow_stack_push_p() = %d\n", + gdbarch_shadow_stack_push_p (gdbarch)); + gdb_printf (file, + "gdbarch_dump: shadow_stack_push = <%s>\n", + host_address_to_string (gdbarch->shadow_stack_push)); if (gdbarch->dump_tdep != NULL) gdbarch->dump_tdep (gdbarch, file); } @@ -5507,3 +5515,27 @@ set_gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, { gdbarch->use_target_description_from_corefile_notes = use_target_description_from_corefile_notes; } + +bool +gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->shadow_stack_push != NULL; +} + +void +gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->shadow_stack_push != NULL); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_shadow_stack_push called\n"); + gdbarch->shadow_stack_push (gdbarch, new_addr); +} + +void +set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, + gdbarch_shadow_stack_push_ftype shadow_stack_push) +{ + gdbarch->shadow_stack_push = shadow_stack_push; +} diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index 9fda85f860f..ff14a3666b9 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1778,3 +1778,17 @@ extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarc typedef bool (gdbarch_use_target_description_from_corefile_notes_ftype) (struct gdbarch *gdbarch, struct bfd *corefile_bfd); extern bool gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, struct bfd *corefile_bfd); extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes); + +/* Some targets support special hardware-assisted control-flow protection + technologies. For example, Intel's Control-flow Enforcement Technology (CET) + provides a shadow stack and indirect branch tracking. + To enable inferior calls the function shadow_stack_push has to be provided. + + Push the address NEW_ADDR on the shadow stack and update the shadow stack + pointer. */ + +extern bool gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch); + +typedef void (gdbarch_shadow_stack_push_ftype) (struct gdbarch *gdbarch, CORE_ADDR new_addr); +extern void gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr); +extern void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stack_push_ftype *shadow_stack_push); diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index cc7c6d8677b..52f265e8e0e 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2815,3 +2815,19 @@ The corefile's bfd is passed through COREFILE_BFD. predefault="default_use_target_description_from_corefile_notes", invalid=False, ) + +Method( + comment=""" +Some targets support special hardware-assisted control-flow protection +technologies. For example, Intel's Control-flow Enforcement Technology (CET) +provides a shadow stack and indirect branch tracking. +To enable inferior calls the function shadow_stack_push has to be provided. + +Push the address NEW_ADDR on the shadow stack and update the shadow stack +pointer. +""", + type="void", + name="shadow_stack_push", + params=[("CORE_ADDR", "new_addr")], + predicate=True, +) diff --git a/gdb/infcall.c b/gdb/infcall.c index 6399278c6ae..3a4f1e35a2f 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -1453,6 +1453,12 @@ call_function_by_hand_dummy (struct value *function, bp_addr, args.size (), args.data (), sp, return_method, struct_addr); + /* Push the return address of the inferior (bp_addr) on the shadow stack + and update the shadow stack pointer. As we don't execute a call + instruction to start the inferior we need to handle this manually. */ + if (gdbarch_shadow_stack_push_p (gdbarch)) + gdbarch_shadow_stack_push (gdbarch, bp_addr); + /* Set up a frame ID for the dummy frame so we can pass it to set_momentary_breakpoint. We need to give the breakpoint a frame ID so that the breakpoint code can correctly re-identify the From patchwork Fri Dec 20 20:04:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103529 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 D56AE3858401 for ; Fri, 20 Dec 2024 20:12:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D56AE3858401 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=fQ1bEfxn X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by sourceware.org (Postfix) with ESMTPS id 6D18F385840B for ; Fri, 20 Dec 2024 20:06:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6D18F385840B 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 6D18F385840B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725193; cv=none; b=sW2tBx8ck5kPNgTjrR2F3wezRVlj5xbzZynWC13bNri0TPzz/ZLqr/DY58QIRPJdqW6YfvdxyJ5CBY6yWgTMTn5jExn/zSqZpumv0cfOl9ozuZgbIX94JqeNUtrYcKBNfWJthtbDZSIBXD9sEecfHLZpOr7gv3eoAod48NJCBBM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725193; c=relaxed/simple; bh=IM281C+m2thQxTKTYMfYI2UQkizH76f8/OkAJMp5Wgc=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=M7T0cigr5WlO0Yj+wKXolfJHs8swTlsf96dQFCnQAg+1umECKoD6IV/TWp1BFXiDWzSLni7z5TQ8pjilA0vbQ4CTdrjvmVR/6KUPBe/1RmPk62KiCKlM6J334muNK0dejRAHzGdLFQF+P/h6prEmG2B6FyXcLBl0hgEqyMv7wcc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6D18F385840B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725194; x=1766261194; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=IM281C+m2thQxTKTYMfYI2UQkizH76f8/OkAJMp5Wgc=; b=fQ1bEfxnhdbewx57XiFamevybKra/c7C9tkV6sEevkN67D0IUFU0x7iU 96TAXkNM1gFHHG2tgLCwKxwaATVrQSdjxun24gD+l2ZDWxy/QwjxsTPFC 5f4j5EUNeXucIF3Sj/QZfFLtsTgdyhRzZmLXBTj7US3CLykRjFp56k/Bj d3WvFP7iPMBMbfZbg9jjxrI7QR6/OS2jhG5xjust63Qp+VH99EMEgq0SL 0P55Dtyt1mZmw/2sA5kJ/NMqqDBe1vhNNiAdflH3mh5WKP1XFrHwT/xAr GCbU9M8d9mlJjMYb5AZFskQcniITN4igStmVa1E0/RDmsFd3ZXhCcEtVJ g==; X-CSE-ConnectionGUID: x5sX9Ie5T3eZYPaBuSqohA== X-CSE-MsgGUID: eCS5BrnvQbmgRh2CD9ADrg== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="52689156" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="52689156" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:33 -0800 X-CSE-ConnectionGUID: DcyUjB0UQfKXQHqW7WSXyQ== X-CSE-MsgGUID: N8SSZFLXRduktRcYN4VPPQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="98809965" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:31 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls. Date: Fri, 20 Dec 2024 20:04:59 +0000 Message-Id: <20241220200501.324191-11-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.3 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 This patch enables inferior calls to support Intel's Control-Flow Enforcement Technology (CET), which provides the shadow stack feature for the x86 architecture. Following the restriction of the linux kernel, enable inferior calls for amd64 only. Reviewed-by: Thiago Jung Bauermann --- gdb/amd64-linux-tdep.c | 89 +++++++++++++++++-- gdb/doc/gdb.texinfo | 29 ++++++ .../gdb.arch/amd64-shadow-stack-cmds.exp | 55 +++++++++++- 3 files changed, 164 insertions(+), 9 deletions(-) diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 895feac85e8..ef59cfcb7e4 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -1875,6 +1875,82 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch, return (addr & amd64_linux_lam_untag_mask ()); } +/* Read the shadow stack pointer register and return its value, if + possible. */ + +static std::optional +amd64_linux_get_shadow_stack_pointer (gdbarch *gdbarch) +{ + const i386_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep == nullptr || tdep->ssp_regnum < 0) + return {}; + + CORE_ADDR ssp; + regcache *regcache = get_thread_regcache (inferior_thread ()); + if (regcache_raw_read_unsigned (regcache, tdep->ssp_regnum, &ssp) + != REG_VALID) + return {}; + + /* Starting with v6.6., the Linux kernel supports CET shadow stack. + Dependent on the target the ssp register can be invalid or nullptr + when shadow stack is supported by HW and the linux kernel but not + enabled for the current thread. */ + if (ssp == 0x0) + return {}; + + return ssp; +} + +/* Return the number of bytes required to update the shadow stack pointer + by one element. For x32 the shadow stack elements are still 64-bit + aligned. Thus, gdbarch_addr_bit cannot be used to compute the new + stack pointer. */ + +static inline int +amd64_linux_shadow_stack_element_size_aligned (gdbarch *gdbarch) +{ + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch); + return (binfo->bits_per_word / binfo->bits_per_byte); +} + + +/* If shadow stack is enabled, push the address NEW_ADDR on the shadow + stack and increment the shadow stack pointer accordingly. */ + +static void +amd64_linux_shadow_stack_push (gdbarch *gdbarch, CORE_ADDR new_addr) +{ + std::optional ssp = amd64_linux_get_shadow_stack_pointer (gdbarch); + if (!ssp.has_value ()) + return; + + /* The shadow stack grows downwards. To push addresses on the stack, + we need to decrement SSP. */ + const int element_size + = amd64_linux_shadow_stack_element_size_aligned (gdbarch); + const CORE_ADDR new_ssp = *ssp - element_size; + + /* Starting with v6.6., the Linux kernel supports CET shadow stack. + Using /proc/PID/smaps we can only check if NEW_SSP points to shadow + stack memory. If it doesn't, we assume the stack is full. */ + std::pair memrange; + if (!linux_address_in_shadow_stack_mem_range (new_ssp, &memrange)) + error (_("No space left on the shadow stack.")); + + /* On x86 there can be a shadow stack token at bit 63. For x32, the + address size is only 32 bit. Thus, we must use ELEMENT_SIZE (and + not gdbarch_addr_bit) to determine the width of the address to be + written. */ + const bfd_endian byte_order = gdbarch_byte_order (gdbarch); + write_memory_unsigned_integer (new_ssp, element_size, byte_order, + (ULONGEST) new_addr); + + i386_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + regcache *regcache = get_thread_regcache (inferior_thread ()); + regcache_raw_write_unsigned (regcache, tdep->ssp_regnum, new_ssp); +} + static value * amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame, void **this_cache, int regnum) @@ -1900,14 +1976,9 @@ amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame, if (linux_address_in_shadow_stack_mem_range (ssp, &range)) { /* The shadow stack grows downwards. To compute the previous - shadow stack pointer, we need to increment SSP. - For x32 the shadow stack elements are still 64-bit aligned. - Thus, we cannot use gdbarch_addr_bit to compute the new stack - pointer. */ - const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch); - const int bytes_per_word - = (binfo->bits_per_word / binfo->bits_per_byte); - CORE_ADDR new_ssp = ssp + bytes_per_word; + shadow stack pointer, we need to increment SSP. */ + CORE_ADDR new_ssp + = ssp + amd64_linux_shadow_stack_element_size_aligned (gdbarch); /* If NEW_SSP points to the end of or before (<=) the current shadow stack memory range we consider NEW_SSP as valid (but @@ -1995,6 +2066,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, set_gdbarch_remove_non_address_bits_watchpoint (gdbarch, amd64_linux_remove_non_address_bits_watchpoint); + + set_gdbarch_shadow_stack_push (gdbarch, amd64_linux_shadow_stack_push); dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg); } diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index c6c6fcaa17f..4bed63cb0a1 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -26836,6 +26836,35 @@ registers @end itemize +@subsubsection Intel @dfn{Control-flow Enforcement Technology} (CET). +@cindex Intel Control-flow Enforcement Technology (CET). + +Control-flow Enforcement Technology (CET) provides two capabilities to defend +against ``Return-oriented Programming'' and ``call/jmp-oriented +programming'' style control-flow attacks: + +@itemize @bullet +@item Shadow Stack: +A shadow stack is a second stack for a program. It holds the return +addresses pushed by the call instruction. The @code{RET} instruction pops the +return addresses from both call and shadow stack. If the return addresses from +the two stacks do not match, the processor signals a control protection +exception. +@item Indirect Branch Tracking (IBT): +When IBT is enabled, the CPU implements a state machine that tracks indirect +@code{JMP} and @code{CALL} instructions. The state machine can be either IDLE +or WAIT_FOR_ENDBRANCH. In WAIT_FOR_ENDBRANCH state the next instruction in +the program stream must be an @code{ENDBR} instruction, otherwise the +processor signals a control protection exception. +@end itemize + +Impact on Call/Print: +Inferior calls in @value{GDBN} reset the current PC to the beginning of the +function that is called. No call instruction is executed, but the @code{RET} +instruction actually is. To avoid a control protection exception due to the +missing return address on the shadow stack, @value{GDBN} pushes the new return +address to the shadow stack and updates the shadow stack pointer. + @node Alpha @subsection Alpha diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp index 17f32ce3964..df654f9db5d 100644 --- a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp @@ -13,12 +13,29 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Test shadow stack enabling for frame level update and the return command. +# Test shadow stack enabling for frame level update, the return and the +# call command. +# As potential CET violations often only occur after resuming normal +# execution, test normal program continuation after each return or call +# command. require allow_ssp_tests standard_testfile amd64-shadow-stack.c +proc restart_and_run_infcall_call2 {} { + global binfile + clean_restart ${binfile} + if { ![runto_main] } { + return -1 + } + set inside_infcall_str "The program being debugged stopped while in a function called from GDB" + gdb_breakpoint [ gdb_get_line_number "break call2" ] + gdb_continue_to_breakpoint "break call2" ".*break call2.*" + gdb_test "call (int) call2()" \ + "Breakpoint \[0-9\]*, call2.*$inside_infcall_str.*" +} + save_vars { ::env(GLIBC_TUNABLES) } { append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" @@ -33,6 +50,42 @@ save_vars { ::env(GLIBC_TUNABLES) } { return -1 } + with_test_prefix "test inferior call and continue" { + gdb_breakpoint [ gdb_get_line_number "break call1" ] + gdb_continue_to_breakpoint "break call1" ".*break call1.*" + + gdb_test "call (int) call2()" "= 42" + + gdb_continue_to_end + } + + with_test_prefix "test return inside an inferior call" { + restart_and_run_infcall_call2 + + gdb_test "return" "\#0.*call2.*" \ + "Test shadow stack return inside an inferior call" \ + "Make.*return now\\? \\(y or n\\) " "y" + + gdb_continue_to_end + } + + with_test_prefix "test return 'above' an inferior call" { + restart_and_run_infcall_call2 + + gdb_test "frame 2" "call2 ().*" "move to frame 'above' inferior call" + + gdb_test "return" "\#0.*call1.*" \ + "Test shadow stack return 'above' an inferior call" \ + "Make.*return now\\? \\(y or n\\) " "y" + + gdb_continue_to_end + } + + clean_restart ${binfile} + if { ![runto_main] } { + return -1 + } + set call1_line [ gdb_get_line_number "break call1" ] set call2_line [ gdb_get_line_number "break call2" ] From patchwork Fri Dec 20 20:05:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103525 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 079603858406 for ; Fri, 20 Dec 2024 20:09:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 079603858406 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=W7JVfmhQ X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by sourceware.org (Postfix) with ESMTPS id BC9763858C35 for ; Fri, 20 Dec 2024 20:06:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BC9763858C35 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 BC9763858C35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725199; cv=none; b=kOFDBvLS6wujEzGq8wniCntlCO1fbfK/wu9dP+LqrJdsyYghfI7LxOmdkY+Cup7fVorJZe4ljzkmx+MpYhDsdkoNxFVdKPbSvfFlasr03K2b3+cKVhqO7WEoLLha3UnLziFat5fOfuY4ytf05lYcDnj0weS53sh8PDDJ/Fi8Y5w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725199; c=relaxed/simple; bh=tyYS4vzrPHH7ifXLWJjmfmmkYyZ8Ev4c1qLsxsLrDq8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=rJ15zEiOdhd/lZwjIyY552T9EwO+qjkzNNqevmPY1vXr4akao22ROa00x+1hQ0USqGaqcOg+PmvMvSWUhEw/8dOJr4CEZXq5qF6/h7tW/TcLQ5IE93tCMH7v2/bAqTa87ePr+WmgJy8CVzjzb6M+1V9gFq4By+DOFgHnhcwPJs4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BC9763858C35 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725199; x=1766261199; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=tyYS4vzrPHH7ifXLWJjmfmmkYyZ8Ev4c1qLsxsLrDq8=; b=W7JVfmhQhXkKRh6me//JDwOR3cXEAXjwKLBT2DpkFQaUfw3dQ77S5IbH 0lwUydjmg5BGlHtNpNCDXMEcWnGD0mvZXKcS2NPKNXEP+Y3e5/YHdTHLx wlST66NNv1vllqLltuLyuE1KvwCLFnE+FHGEwHAiqbX9tQT4gZK1sPQvh xMf/GCxUL8Ri47V6FPYLjtd2rfIk6QMIM48e3GahDFr+1jdAvE/vNySsG p9E4ULrjMAiOH2WiPPoJqeDgP/DHGNWv0c0iidXnQ8f9cXCJepwb6hWak b4ndAJzh+Qw2J4xdmCmgao2rlYrKHBYzQHBcq8Br/MzsrxiEu4zfs2n/I Q==; X-CSE-ConnectionGUID: qdp+hGj6Tp6quc9mek/wdw== X-CSE-MsgGUID: 7jU4PDr6SCGas6FTw8j6Mg== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="52689162" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="52689162" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:38 -0800 X-CSE-ConnectionGUID: dsA7MUKnTiSA86uTXNAdKA== X-CSE-MsgGUID: grIxnOMuRVedfVVQnOBwpg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="98809983" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:37 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer. Date: Fri, 20 Dec 2024 20:05:00 +0000 Message-Id: <20241220200501.324191-12-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.3 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 This patch is required by the following commit. --- gdb/arch-utils.c | 8 ++++++++ gdb/arch-utils.h | 5 +++++ gdb/gdbarch-gen.c | 22 ++++++++++++++++++++++ gdb/gdbarch-gen.h | 6 ++++++ gdb/gdbarch_components.py | 10 ++++++++++ 5 files changed, 51 insertions(+) diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index a2ed2a2c011..3aedb3f2600 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1218,6 +1218,14 @@ default_gdbarch_return_value readbuf, writebuf); } +/* See arch-utils.h. */ + +std::optional +default_get_shadow_stack_pointer (gdbarch *gdbarch) +{ + return {}; +} + obstack *gdbarch_obstack (gdbarch *arch) { return &arch->obstack; diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index b59e2ad70c2..471be9c282d 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -325,4 +325,9 @@ extern enum return_value_convention default_gdbarch_return_value struct regcache *regcache, struct value **read_value, const gdb_byte *writebuf); +/* Default implementation of gdbarch default_get_shadow_stack_pointer + method. */ +extern std::optional default_get_shadow_stack_pointer + (gdbarch *gdbarch); + #endif /* GDB_ARCH_UTILS_H */ diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index c33c476dfdb..72638f01ad7 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -261,6 +261,7 @@ struct gdbarch gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings; gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes; gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr; + gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer = default_get_shadow_stack_pointer; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -533,6 +534,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of read_core_file_mappings, invalid_p == 0. */ /* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */ /* Skip verify of shadow_stack_push, has predicate. */ + /* Skip verify of get_shadow_stack_pointer, invalid_p == 0. */ if (!log.empty ()) internal_error (_("verify_gdbarch: the following are invalid ...%s"), log.c_str ()); @@ -1404,6 +1406,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: shadow_stack_push = <%s>\n", host_address_to_string (gdbarch->shadow_stack_push)); + gdb_printf (file, + "gdbarch_dump: get_shadow_stack_pointer = <%s>\n", + host_address_to_string (gdbarch->get_shadow_stack_pointer)); if (gdbarch->dump_tdep != NULL) gdbarch->dump_tdep (gdbarch, file); } @@ -5539,3 +5544,20 @@ set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, { gdbarch->shadow_stack_push = shadow_stack_push; } + +std::optional +gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_shadow_stack_pointer != NULL); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_get_shadow_stack_pointer called\n"); + return gdbarch->get_shadow_stack_pointer (gdbarch); +} + +void +set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, + gdbarch_get_shadow_stack_pointer_ftype get_shadow_stack_pointer) +{ + gdbarch->get_shadow_stack_pointer = get_shadow_stack_pointer; +} diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index ff14a3666b9..ff511b4a9e0 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1783,6 +1783,8 @@ extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbar technologies. For example, Intel's Control-flow Enforcement Technology (CET) provides a shadow stack and indirect branch tracking. To enable inferior calls the function shadow_stack_push has to be provided. + The method get_shadow_stack_pointer has to be provided to enable displaced + stepping. Push the address NEW_ADDR on the shadow stack and update the shadow stack pointer. */ @@ -1792,3 +1794,7 @@ extern bool gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch); typedef void (gdbarch_shadow_stack_push_ftype) (struct gdbarch *gdbarch, CORE_ADDR new_addr); extern void gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr); extern void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stack_push_ftype *shadow_stack_push); + +typedef std::optional (gdbarch_get_shadow_stack_pointer_ftype) (struct gdbarch *gdbarch); +extern std::optional gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch); +extern void set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer); diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index 52f265e8e0e..df70cb082a4 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2822,6 +2822,8 @@ Some targets support special hardware-assisted control-flow protection technologies. For example, Intel's Control-flow Enforcement Technology (CET) provides a shadow stack and indirect branch tracking. To enable inferior calls the function shadow_stack_push has to be provided. +The method get_shadow_stack_pointer has to be provided to enable displaced +stepping. Push the address NEW_ADDR on the shadow stack and update the shadow stack pointer. @@ -2831,3 +2833,11 @@ pointer. params=[("CORE_ADDR", "new_addr")], predicate=True, ) + +Method( + type="std::optional", + name="get_shadow_stack_pointer", + params=[], + predefault="default_get_shadow_stack_pointer", + invalid=False, +) From patchwork Fri Dec 20 20:05:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 103526 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 05099385841F for ; Fri, 20 Dec 2024 20:10:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 05099385841F Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=W0b+gHLq X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) by sourceware.org (Postfix) with ESMTPS id 7E5EE3858420 for ; Fri, 20 Dec 2024 20:06:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7E5EE3858420 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 7E5EE3858420 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725204; cv=none; b=RUDer57ZYuiaq71om9DW6aecQ43i0Le+SgJ5EJoJrwVpSCzAQsl5xRZ5cBmd4tg5BST3xhj8E1wMv3vV28tdw9gj4iRxK51PZXUSwOG4N+6206zbzIYtELyzP2iafym3XPp93N/X/5lDwWDP9+8AKhTutnM+u3uCfHl1Q2OXciw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1734725204; c=relaxed/simple; bh=GiLKGjXsTXz0dckO0P7nqoId+Mp+uEWd48EG3AKFMTA=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=irPt9RCv9cBWOf8qqdBiezV6mEVXHAad6d/a1B843/tuuVdWx5EANVZMtfobwcVbrKIN7N7sRXBk0dRcAVHfvqa7vO4RUxRBI4IQuaMKaxsv8dXVZEkh9TspKT5DH8V8va9a76K0tX7/NK4yXvZ3LRJDEx7h50WpvH5yE7O2P+Q= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7E5EE3858420 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734725204; x=1766261204; h=from:to:subject:date:message-id:in-reply-to:references: mime-version:content-transfer-encoding; bh=GiLKGjXsTXz0dckO0P7nqoId+Mp+uEWd48EG3AKFMTA=; b=W0b+gHLqbQkmFyahQ8LQMqMGvf2cqB4TB+DFaVOYHD4LUc6T8+xyvn8h SQmqdtgSU18vXJ/t4Hrp3JLDIt4F7wdmBAEeMD37PIsVLqu1+RABgsIn4 N/pZjihb/FZM7wFZNAVVrg2JxUSrnc4SWIi1Dxm+uLiVPockRUq9Al9PX MjUQZRnQqrD4lz2D+sx0NnNVvo6HOVkLg2uSNVoRWRrbWjxdaDBrvbdO+ nVBwenB7WoOBVs/ghXcbyKxQt62gdcYL3OGAy/hCpW6K+Wp6OSRvU0ZgW mUe8hRZqC69fCqjbJBW1EjoZ5KU4DSrED5k+pA4a2d7VfAE8hYsQdl1iO g==; X-CSE-ConnectionGUID: 2EYK+pWBSH2Ak5Ta4ThJzQ== X-CSE-MsgGUID: 86n2161eQAyHGdTmAEj5jQ== X-IronPort-AV: E=McAfee;i="6700,10204,11292"; a="46663187" X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="46663187" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:43 -0800 X-CSE-ConnectionGUID: gkMw4+oUSdqxEqdjGxxbAg== X-CSE-MsgGUID: F1Uxj1GER5e1OUsIsWzm8A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="103673385" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by ORVIESA003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2024 12:06:43 -0800 From: "Schimpe, Christina" To: gdb-patches@sourceware.org Subject: [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux. Date: Fri, 20 Dec 2024 20:05:01 +0000 Message-Id: <20241220200501.324191-13-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241220200501.324191-1-christina.schimpe@intel.com> References: <20241220200501.324191-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 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 This patch enables displaced stepping to support Intel's Control-Flow Enforcement Technology (CET), which provides the shadow stack feature for the x86 architecture. Following the restriction of the linux kernel, enable displaced stepping for amd64 only. If displaced stepping is active and the single stepped instruction is a call instruction, the return address atop the stack is the address following the copied instruction. However, to allow normal program execution it has to be the address following the original instruction. Due to that reason, the return address is corrected in amd64_displaced_step_fixup and i386_displaced_step_fixup. To avoid a control-protection exception if shadow stack is active, the shadow stack top address must be corrected as well. Reviewed-By: Eli Zaretskii --- gdb/amd64-linux-tdep.c | 2 + gdb/amd64-tdep.c | 12 +++ gdb/doc/gdb.texinfo | 11 ++- gdb/i386-tdep.c | 12 +++ .../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 +++++++++++++++++++ 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index ef59cfcb7e4..a034d75dd52 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -2068,6 +2068,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, (gdbarch, amd64_linux_remove_non_address_bits_watchpoint); set_gdbarch_shadow_stack_push (gdbarch, amd64_linux_shadow_stack_push); + set_gdbarch_get_shadow_stack_pointer (gdbarch, + amd64_linux_get_shadow_stack_pointer); dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg); } diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index a298333e70a..988a4cb285b 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -1747,6 +1747,18 @@ amd64_displaced_step_fixup (struct gdbarch *gdbarch, displaced_debug_printf ("relocated return addr at %s to %s", paddress (gdbarch, rsp), paddress (gdbarch, retaddr)); + + /* If shadow stack is enabled, we need to correct the return address + on the shadow stack too. */ + std::optional ssp = gdbarch_get_shadow_stack_pointer (gdbarch); + if (ssp.has_value ()) + { + write_memory_unsigned_integer (*ssp, retaddr_len, byte_order, + retaddr); + displaced_debug_printf ("relocated shadow stack return addr at %s " + "to %s", paddress (gdbarch, *ssp), + paddress (gdbarch, retaddr)); + } } } diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 4bed63cb0a1..022c944ea5c 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -26858,12 +26858,20 @@ the program stream must be an @code{ENDBR} instruction, otherwise the processor signals a control protection exception. @end itemize -Impact on Call/Print: +Impact on GDB commands: +@itemize @bullet +@item Call/Print: Inferior calls in @value{GDBN} reset the current PC to the beginning of the function that is called. No call instruction is executed, but the @code{RET} instruction actually is. To avoid a control protection exception due to the missing return address on the shadow stack, @value{GDBN} pushes the new return address to the shadow stack and updates the shadow stack pointer. +@item Step: +With displaced stepping, @value{GDBN} may run an out of line copy of a call +instruction. In this case, the wrong return address is pushed on the shadow +stack. @value{GDBN} corrects this value to avoid a control protection +exception. For more details on displaced stepping, see @ref{displaced-stepping}. +@end itemize @node Alpha @subsection Alpha @@ -41579,6 +41587,7 @@ GLOBAL Disassembler_2 (Matches current architecture) @cindex out-of-line single-stepping @item set displaced-stepping @itemx show displaced-stepping +@anchor{displaced-stepping} Control whether or not @value{GDBN} will do @dfn{displaced stepping} if the target supports it. Displaced stepping is a way to single-step over breakpoints without removing them from the inferior, by executing diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index b338029d990..ec98b52c649 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -899,6 +899,18 @@ i386_displaced_step_fixup (struct gdbarch *gdbarch, displaced_debug_printf ("relocated return addr at %s to %s", paddress (gdbarch, esp), paddress (gdbarch, retaddr)); + + /* If shadow stack is enabled, we need to correct the return address + on the shadow stack too. */ + std::optional ssp = gdbarch_get_shadow_stack_pointer (gdbarch); + if (ssp.has_value ()) + { + write_memory_unsigned_integer (*ssp, retaddr_len, byte_order, + retaddr); + displaced_debug_printf ("relocated shadow stack return addr at %s " + "to %s", paddress (gdbarch, *ssp), + paddress (gdbarch, retaddr)); + } } } diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp new file mode 100644 index 00000000000..493ca0100cb --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp @@ -0,0 +1,84 @@ +# Copyright 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 continue from call instructions with shadow stack and displaced +# stepping being enabled. + +require allow_ssp_tests support_displaced_stepping + +standard_testfile amd64-shadow-stack.c + +save_vars { ::env(GLIBC_TUNABLES) } { + + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" + + if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + additional_flags="-fcf-protection=return"] } { + return -1 + } + + # Enable displaced stepping. + gdb_test_no_output "set displaced-stepping on" + gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*" + + if { ![runto_main] } { + return -1 + } + + # Get the address of the call1 instruction. + set call1_addr -1 + gdb_test_multiple "disassemble main" "" { + -re -wrap "($hex) <\\+($decimal)>:\\s*call\\s*0x.*.*" { + set call1_addr $expect_out(1,string) + pass $gdb_test_name + } + } + + if { $call1_addr == -1 } { + return -1 + } + + # Get the address of the call2 instruction. + set call2_addr -1 + gdb_test_multiple "disassemble call1" "" { + -re -wrap "($hex) <\\+($decimal)>:\\s*call\\s*0x.*.*" { + set call2_addr $expect_out(1,string) + pass $gdb_test_name + } + } + + if { $call2_addr == -1 } { + return -1 + } + + gdb_test "break *$call1_addr" \ + "Breakpoint $decimal at $hex.*" \ + "break at the address of the call1 instruction" + + gdb_test "break *$call2_addr" \ + "Breakpoint $decimal at $hex.*" \ + "break at the address of the call2 instruction" + + gdb_test "continue" \ + "Breakpoint $decimal, $call1_addr in main ().*" \ + "continue until call1 instruction" + + # Test continue from breakpoint at call1 and call2 instructions. + gdb_test "continue" \ + "Breakpoint $decimal, $call2_addr in call1 ().*" \ + "continue from call1 instruction" + + gdb_continue_to_end "continue from call2 instruction" +}