From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by sourceware.org (Postfix) with ESMTPS id 8266B386EC33 for ; Fri, 14 Jan 2022 16:38:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8266B386EC33 Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 20EB2xY3020480 for ; Fri, 14 Jan 2022 17:38:17 +0100 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3dk45au5mh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Fri, 14 Jan 2022 17:38:17 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id DEEED10002A for ; Fri, 14 Jan 2022 17:38:16 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id D6CAA2194FE for ; Fri, 14 Jan 2022 17:38:16 +0100 (CET) Received: from gnx2104.gnb.st.com (10.75.127.51) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Fri, 14 Jan 2022 17:38:16 +0100 From: Christophe Lyon To: CC: , Christophe Lyon Subject: [PATCH 4/5] gdb/arm: Add support for multiple stack pointers on Cortex-M Date: Fri, 14 Jan 2022 17:35:31 +0100 Message-ID: <20220114163552.4107885-4-christophe.lyon@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220114163552.4107885-1-christophe.lyon@foss.st.com> References: <20220114163552.4107885-1-christophe.lyon@foss.st.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Originating-IP: [10.75.127.51] X-ClientProxiedBy: SFHDAG2NODE1.st.com (10.75.127.4) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-14_06,2022-01-14_01,2021-12-02_01 X-Spam-Status: No, score=-8.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: , X-List-Received-Date: Fri, 14 Jan 2022 16:38:21 -0000 V8-M architecture with Security extension features four stack pointers to handle Secure and Non-secure modes. This patch adds support to switch between them as needed during unwinding, and replaces all updates of cache->prev_sp with calls to arm_cache_set_prev_sp. It makes sure that arm_analyze_prologue updates the right SP as needed. --- gdb/arch/arm.h | 9 +- gdb/arm-tdep.c | 229 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 217 insertions(+), 21 deletions(-) diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h index 638780011fc..ea36a0015cc 100644 --- a/gdb/arch/arm.h +++ b/gdb/arch/arm.h @@ -52,6 +52,11 @@ enum gdb_regnum { ARM_MSP_REGNUM, /* Cortex-M Main Stack Pointer. */ ARM_PSP_REGNUM, /* Cortex-M Process Stack Pointer. */ + ARM_MSP_S_REGNUM, /* Cortex-M Secure Main Stack Pointer. */ + ARM_MSP_NS_REGNUM, /* Cortex-M Non-secure Main Stack Pointer. */ + ARM_PSP_S_REGNUM, /* Cortex-M Secure Process Stack Pointer. */ + ARM_PSP_NS_REGNUM, /* Cortex-M Non-secure Process Stack Pointer. */ + /* Other useful registers. */ ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */ THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */ @@ -67,8 +72,8 @@ enum arm_register_counts { ARM_NUM_ARG_REGS = 4, /* Number of floating point argument registers. */ ARM_NUM_FP_ARG_REGS = 4, - /* Number of registers (old, defined as ARM_PSP_REGNUM + 1. */ - ARM_NUM_REGS = ARM_PSP_REGNUM + 1 + /* Number of registers (old, defined as ARM_PSP_NS_REGNUM + 1. */ + ARM_NUM_REGS = ARM_PSP_NS_REGNUM + 1 }; /* Enum describing the different kinds of breakpoints. */ diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index a345df959d1..8115361d914 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -275,7 +275,19 @@ struct arm_prologue_cache /* The stack pointer at the time this frame was created; i.e. the caller's stack pointer when this function was called. It is used to identify this frame. */ - CORE_ADDR prev_sp; + CORE_ADDR sp; + + /* Additional stack pointers used by M-profile with Security extension. */ + CORE_ADDR msp_s; + CORE_ADDR msp_ns; + CORE_ADDR psp_s; + CORE_ADDR psp_ns; + + /* Active stack pointer. */ + gdb_regnum active_sp_regnum; + + bool have_sec_ext; + bool is_m; /* The frame base for this frame is just prev_sp - frame size. FRAMESIZE is the distance from the frame pointer to the @@ -293,6 +305,10 @@ struct arm_prologue_cache static void arm_cache_init (struct arm_prologue_cache *cache, struct gdbarch *gdbarch) { + cache->have_sec_ext = false; + cache->is_m = false; + cache->active_sp_regnum = ARM_SP_REGNUM; + cache->framesize = 0; cache->framereg = 0; cache->saved_regs = trad_frame_alloc_saved_regs (gdbarch); @@ -302,9 +318,181 @@ static void arm_cache_init (struct arm_prologue_cache *cache, struct frame_info *frame) { struct gdbarch *gdbarch = get_frame_arch (frame); - cache->prev_sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM); + arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch); + gdb::optional sp; + cache->sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM); arm_cache_init (cache, gdbarch); + + cache->have_sec_ext = tdep->have_sec_ext; + cache->is_m = tdep->is_m; + +#define INIT_ARM_CACHE_SP(regnum, member) do { \ + CORE_ADDR val = get_frame_register_unsigned (frame, (regnum)); \ + if (val == cache->sp || (sp.has_value () && val == *sp)) \ + { \ + cache->active_sp_regnum = (regnum); \ + } \ + (member) = val; \ + } while (0) + + if (tdep->have_sec_ext) + { + INIT_ARM_CACHE_SP (ARM_MSP_S_REGNUM, cache->msp_s); + INIT_ARM_CACHE_SP (ARM_MSP_NS_REGNUM, cache->msp_ns); + INIT_ARM_CACHE_SP (ARM_PSP_S_REGNUM, cache->psp_s); + INIT_ARM_CACHE_SP (ARM_PSP_NS_REGNUM, cache->psp_ns); + /* Use MSP_S as default stack pointer. */ + if (cache->active_sp_regnum == ARM_SP_REGNUM) + cache->active_sp_regnum = ARM_MSP_S_REGNUM; + } + else if (tdep->is_m) + { + INIT_ARM_CACHE_SP (ARM_MSP_REGNUM, cache->msp_s); + INIT_ARM_CACHE_SP (ARM_PSP_REGNUM, cache->psp_s); + } + else + { + INIT_ARM_CACHE_SP (ARM_SP_REGNUM, cache->msp_s); + } + #undef INIT_ARM_CACHE_SP +} + +static gdb::optional +arm_cache_get_sp_register (struct arm_prologue_cache *cache, int regnum) +{ + if (cache->have_sec_ext) + { + switch (regnum) + { + case ARM_MSP_S_REGNUM: + return cache->msp_s; + case ARM_MSP_NS_REGNUM: + return cache->msp_ns; + case ARM_PSP_S_REGNUM: + return cache->psp_s; + case ARM_PSP_NS_REGNUM: + return cache->psp_ns; + case ARM_SP_REGNUM: + return cache->sp; + } + } + else if (cache->is_m) + { + switch (regnum) + { + case ARM_MSP_REGNUM: + return cache->msp_s; + case ARM_PSP_REGNUM: + return cache->psp_s; + case ARM_SP_REGNUM: + return cache->sp; + } + } + else + { + switch (regnum) + { + case ARM_SP_REGNUM: + return cache->sp; + } + } + return {}; +} + +static CORE_ADDR +arm_cache_get_prev_sp (struct arm_prologue_cache *cache) +{ + gdb::optional val + = arm_cache_get_sp_register (cache, cache->active_sp_regnum); + if (val.has_value ()) + return *val; + + gdb_assert_not_reached ("Invalid SP selection"); + return 0; +} + +static void +arm_cache_set_prev_sp (struct arm_prologue_cache *cache, CORE_ADDR val) +{ + if (cache->have_sec_ext) + { + switch (cache->active_sp_regnum) + { + case ARM_MSP_S_REGNUM: + cache->msp_s = val; + return; + case ARM_MSP_NS_REGNUM: + cache->msp_ns = val; + return; + case ARM_PSP_S_REGNUM: + cache->psp_s = val; + return; + case ARM_PSP_NS_REGNUM: + cache->psp_ns = val; + return; + case ARM_SP_REGNUM: + cache->sp = val; + return; + } + } + else if (cache->is_m) + { + switch (cache->active_sp_regnum) + { + case ARM_MSP_REGNUM: + cache->msp_s = val; + return; + case ARM_PSP_REGNUM: + cache->psp_s = val; + return; + case ARM_SP_REGNUM: + cache->sp = val; + return; + } + } + else + { + switch (cache->active_sp_regnum) + { + case ARM_SP_REGNUM: + cache->sp = val; + return; + } + } + + gdb_assert_not_reached ("Invalid SP selection"); +} + +static bool +arm_cache_is_sp_register (struct arm_prologue_cache *cache, int regnum) +{ + switch (regnum) + { + case ARM_SP_REGNUM: + case ARM_MSP_REGNUM: + case ARM_MSP_S_REGNUM: + case ARM_MSP_NS_REGNUM: + case ARM_PSP_REGNUM: + case ARM_PSP_S_REGNUM: + case ARM_PSP_NS_REGNUM: + return true; + default: + return false; + } +} + +static void +arm_cache_switch_prev_sp (struct arm_prologue_cache *cache, gdb_regnum sp_regnum) +{ + gdb_assert (sp_regnum != ARM_SP_REGNUM); + if (cache->have_sec_ext) + gdb_assert (sp_regnum != ARM_MSP_REGNUM && sp_regnum != ARM_PSP_REGNUM); + + if (!arm_cache_is_sp_register (cache, sp_regnum)) + gdb_assert_not_reached ("Invalid SP selection"); + + cache->active_sp_regnum = sp_regnum; } namespace { @@ -1826,6 +2014,8 @@ arm_analyze_prologue (struct gdbarch *gdbarch, for (regno = 0; regno < ARM_FPS_REGNUM; regno++) if (stack.find_reg (gdbarch, regno, &offset)) cache->saved_regs[regno].set_addr (offset); + + arm_cache_set_prev_sp (cache, regs[ARM_SP_REGNUM].k); } arm_debug_printf ("Prologue scan stopped at %s", @@ -1947,14 +2137,14 @@ arm_make_prologue_cache (struct frame_info *this_frame) if (unwound_fp == 0) return cache; - cache->prev_sp = unwound_fp + cache->framesize; + arm_cache_set_prev_sp (cache, unwound_fp + cache->framesize); /* Calculate actual addresses of saved registers using offsets determined by arm_scan_prologue. */ for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++) if (cache->saved_regs[reg].is_addr ()) cache->saved_regs[reg].set_addr (cache->saved_regs[reg].addr () - + cache->prev_sp); + + arm_cache_get_prev_sp (cache)); return cache; } @@ -1980,7 +2170,7 @@ arm_prologue_unwind_stop_reason (struct frame_info *this_frame, return UNWIND_OUTERMOST; /* If we've hit a wall, stop. */ - if (cache->prev_sp == 0) + if (arm_cache_get_prev_sp (cache) == 0) return UNWIND_OUTERMOST; return UNWIND_NO_REASON; @@ -2010,7 +2200,7 @@ arm_prologue_this_id (struct frame_info *this_frame, if (!func) func = pc; - id = frame_id_build (cache->prev_sp, func); + id = frame_id_build (arm_cache_get_prev_sp (cache), func); *this_id = id; } @@ -2044,7 +2234,8 @@ arm_prologue_prev_register (struct frame_info *this_frame, identified by the next frame's stack pointer at the time of the call. The value was already reconstructed into PREV_SP. */ if (prev_regnum == ARM_SP_REGNUM) - return frame_unwind_got_constant (this_frame, prev_regnum, cache->prev_sp); + return frame_unwind_got_constant (this_frame, prev_regnum, + arm_cache_get_prev_sp (cache)); /* The CPSR may have been changed by the call instruction and by the called function. The only bit we can reconstruct is the T bit, @@ -2682,7 +2873,7 @@ arm_exidx_fill_cache (struct frame_info *this_frame, gdb_byte *entry) = vsp - get_frame_register_unsigned (this_frame, cache->framereg); /* We already got the previous SP. */ - cache->prev_sp = vsp; + arm_cache_set_prev_sp (cache, vsp); return cache; } @@ -2805,14 +2996,14 @@ arm_make_epilogue_frame_cache (struct frame_info *this_frame) arm_scan_prologue (this_frame, cache); /* Since we are in epilogue, the SP has been restored. */ - cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + arm_cache_set_prev_sp (cache, get_frame_register_unsigned (this_frame, ARM_SP_REGNUM)); /* Calculate actual addresses of saved registers using offsets determined by arm_scan_prologue. */ for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++) if (cache->saved_regs[reg].is_addr ()) cache->saved_regs[reg].set_addr (cache->saved_regs[reg].addr () - + cache->prev_sp); + + arm_cache_get_prev_sp (cache)); return cache; } @@ -2840,7 +3031,7 @@ arm_epilogue_frame_this_id (struct frame_info *this_frame, if (func == 0) func = pc; - (*this_id) = frame_id_build (cache->prev_sp, pc); + (*this_id) = frame_id_build (arm_cache_get_prev_sp (cache), pc); } /* Implementation of function hook 'prev_register' in @@ -2962,7 +3153,7 @@ arm_make_stub_cache (struct frame_info *this_frame) cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); arm_cache_init (cache, this_frame); - cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + arm_cache_set_prev_sp (cache, get_frame_register_unsigned (this_frame, ARM_SP_REGNUM)); return cache; } @@ -2980,7 +3171,7 @@ arm_stub_this_id (struct frame_info *this_frame, *this_cache = arm_make_stub_cache (this_frame); cache = (struct arm_prologue_cache *) *this_cache; - *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame)); + *this_id = frame_id_build (arm_cache_get_prev_sp (cache), get_frame_pc (this_frame)); } static int @@ -3100,12 +3291,12 @@ arm_m_exception_cache (struct frame_info *this_frame) cache->saved_regs[ARM_FPSCR_REGNUM].set_addr (unwound_sp + 0x60); /* Offset 0x64 is reserved. */ - cache->prev_sp = unwound_sp + 0x68; + arm_cache_set_prev_sp (cache, unwound_sp + 0x68); } else { /* Standard stack frame type used. */ - cache->prev_sp = unwound_sp + 0x20; + arm_cache_set_prev_sp (cache, unwound_sp + 0x20); } /* Check EXC_RETURN bit S if Secure or Non-secure stack used. */ @@ -3127,7 +3318,7 @@ arm_m_exception_cache (struct frame_info *this_frame) previous context's stack pointer. */ if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr) && (xpsr & (1 << 9)) != 0) - cache->prev_sp += 4; + arm_cache_set_prev_sp (cache, arm_cache_get_prev_sp (cache) + 4); return cache; } @@ -3147,7 +3338,7 @@ arm_m_exception_this_id (struct frame_info *this_frame, cache = (struct arm_prologue_cache *) *this_cache; /* Our frame ID for a stub frame is the current SP and LR. */ - *this_id = frame_id_build (cache->prev_sp, + *this_id = frame_id_build (arm_cache_get_prev_sp (cache), get_frame_pc (this_frame)); } @@ -3168,7 +3359,7 @@ arm_m_exception_prev_register (struct frame_info *this_frame, /* The value was already reconstructed into PREV_SP. */ if (prev_regnum == ARM_SP_REGNUM) return frame_unwind_got_constant (this_frame, prev_regnum, - cache->prev_sp); + arm_cache_get_prev_sp (cache)); return trad_frame_get_prev_register (this_frame, cache->saved_regs, prev_regnum); @@ -3213,7 +3404,7 @@ arm_normal_frame_base (struct frame_info *this_frame, void **this_cache) *this_cache = arm_make_prologue_cache (this_frame); cache = (struct arm_prologue_cache *) *this_cache; - return cache->prev_sp - cache->framesize; + return arm_cache_get_prev_sp (cache) - cache->framesize; } struct frame_base arm_normal_base = { -- 2.25.1