From patchwork Sat Nov 5 09:44:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomas Vanek X-Patchwork-Id: 59992 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 6581C3857B8E for ; Sat, 5 Nov 2022 09:45:59 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from smtp00.avonet.cz (smtp00.avonet.cz [217.112.162.55]) by sourceware.org (Postfix) with ESMTP id AECEC385841B for ; Sat, 5 Nov 2022 09:45:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AECEC385841B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=fbl.cz Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=fbl.cz Received: from ktus.lan (217-115-245-101.cust.avonet.cz [217.115.245.101]) by smtp00.avonet.cz (Postfix) with ESMTP id 4N4CKF6Tfcz1xry; Sat, 5 Nov 2022 10:45:21 +0100 (CET) From: Tomas Vanek To: gdb-patches@sourceware.org Subject: [RFC PATCH 4/5] gdb/arm: Unwinding of secure procedure with cmse_nonsecure_entry attribute Date: Sat, 5 Nov 2022 10:44:35 +0100 Message-Id: <1667641476-31602-4-git-send-email-vanekt@fbl.cz> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1667641476-31602-1-git-send-email-vanekt@fbl.cz> References: <1667641476-31602-1-git-send-email-vanekt@fbl.cz> X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_FAIL, SPF_HELO_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.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tomas Vanek Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" This patch depends on pending: "gdb/arm: PR 29738 Cache value for stack pointers for dwarf2 frames" A secure procedure with cmse_nonsecure_entry attribute is compiled with an epilogue ending by a return to the non-secure mode: bxns lr When a non-secure context called such procedure, the dwarf2 unwinder did not know about cmse_nonsecure_entry attribute, did not see 'bxns' at the return and therefore assumed a normal return keeping the security state unchanged. This caused incorrect unwinding of the frames following this one as the secure stack was used instead of non-secure. Detect a procedure with cmse_nonsecure_entry attribute when unwinding a secure frame. Change the security state to non-secure and use the proper stack if the cmse_nonsecure_entry was detected. The detection of the cmse_nonsecure_entry attribute is based on the split secure gateway veneer and the rest of procedure with the name prefixed by '__acle_se_'. This is documented in https://developer.arm.com/documentation/100748/0619/Security-features-supported-in-Arm-Compiler-for-Embedded/Overview-of-building-Secure-and-Non-secure-images-with-the-Armv8-M-Security-Extension and GCC conforms this model too. To choose main or process non-secure stack we need xPSR and SPSEL bit of CONTROL_NS. For simplicity CONTROL_NS is not tracked for changes in the inner frames, the CONTROL_NS value is passed unchanged from the innermost frame. Signed-off-by: Tomas Vanek --- gdb/arm-tdep.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 4180277..4fac09b 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -5125,6 +5125,7 @@ enum arm_vfp_cprc_base_type frame_info_ptr this_frame) { arm_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + bool is_sp = (regnum == ARM_SP_REGNUM); if (is_pacbti_pseudo (gdbarch, regnum)) { @@ -5140,12 +5141,10 @@ enum arm_vfp_cprc_base_type reg->how = DWARF2_FRAME_REG_FN; reg->loc.fn = arm_dwarf2_prev_register; } - else if (regnum == ARM_SP_REGNUM) - reg->how = DWARF2_FRAME_REG_CFA; - else if (arm_is_alternative_sp_register (tdep, regnum)) + else if (is_sp || arm_is_alternative_sp_register (tdep, regnum)) { /* Identify what stack pointers that are synced with sp. */ - bool override_with_sp_value = false; + bool override_with_sp_value = is_sp; if (tdep->have_sec_ext) { @@ -5165,24 +5164,88 @@ enum arm_vfp_cprc_base_type = get_frame_register_unsigned (this_frame, tdep->m_profile_psp_ns_regnum); + bool is_secure = (sp == msp_s || sp == psp_s); + bool return_to_ns = false; + if (is_secure) + { + CORE_ADDR func = get_frame_func (this_frame); + struct bound_minimal_symbol sym + = lookup_minimal_symbol_by_pc (func); + if (sym.minsym) + { + const char *name = sym.minsym->natural_name (); + arm_debug_printf ("ret to ns check minsym %s", name); + return_to_ns = strncmp (name, "__acle_se_", 10) == 0; + } + } + + bool ns_process_stack = false; + if (return_to_ns && + (is_sp || + regnum == tdep->m_profile_msp_s_regnum || + regnum == tdep->m_profile_psp_s_regnum)) + { + bool spsel = true; + + if (tdep->m_profile_control_ns_regnum >= 0) + { + ULONGEST control_ns + = get_frame_register_unsigned (this_frame, + tdep->m_profile_control_ns_regnum); + spsel = (control_ns & (1 << 1)) != 0; + } + + if (spsel) + { + ULONGEST xpsr = get_frame_register_unsigned (this_frame, + ARM_PS_REGNUM); + ns_process_stack = (xpsr & 0x1ff) == 0; + } + + if (is_sp) + { + reg->how = DWARF2_FRAME_REG_SAVED_GDB_REG; + reg->loc.reg = ns_process_stack ? + tdep->m_profile_psp_ns_regnum : + tdep->m_profile_msp_ns_regnum; + return; + } + } + + if (return_to_ns) + { + if (regnum == tdep->m_profile_msp_regnum) + { + reg->how = DWARF2_FRAME_REG_SAVED_GDB_REG; + reg->loc.reg = tdep->m_profile_msp_ns_regnum; + return; + } + else if (regnum == tdep->m_profile_psp_regnum) + { + reg->how = DWARF2_FRAME_REG_SAVED_GDB_REG; + reg->loc.reg = tdep->m_profile_psp_ns_regnum; + return; + } + } + bool is_msp = (regnum == tdep->m_profile_msp_regnum) && (msp_s == sp || msp_ns == sp); bool is_msp_s = (regnum == tdep->m_profile_msp_s_regnum) - && (msp_s == sp); + && (msp_s == sp || (return_to_ns && !ns_process_stack)); bool is_msp_ns = (regnum == tdep->m_profile_msp_ns_regnum) && (msp_ns == sp); bool is_psp = (regnum == tdep->m_profile_psp_regnum) && (psp_s == sp || psp_ns == sp); bool is_psp_s = (regnum == tdep->m_profile_psp_s_regnum) - && (psp_s == sp); + && (psp_s == sp || (return_to_ns && ns_process_stack)); bool is_psp_ns = (regnum == tdep->m_profile_psp_ns_regnum) && (psp_ns == sp); - override_with_sp_value = is_msp || is_msp_s || is_msp_ns + override_with_sp_value = is_sp || is_msp || is_msp_s || is_msp_ns || is_psp || is_psp_s || is_psp_ns; } - else if (tdep->is_m) + else if (tdep->is_m && !is_sp) { CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);