[RFC,5/5] HACK frame inner than comparison for Arm M-profile sec ext

Message ID 1667641476-31602-5-git-send-email-vanekt@fbl.cz
State New
Series [RFC,1/5] gdb/arm: Introduce control_s and control_ns registers |

Commit Message

Tomas Vanek Nov. 5, 2022, 9:44 a.m. UTC
  !!This change is not intended to be merged to the GDB code!!

Arm M-profile can use two stacks or four stack with the security
extension. core_addr_lessthan() used in set_gdbarch_inner_than()
can break stack unwinding with a false warning
"previous frame inner to this frame (corrupt stack?)"
when the active stack is switched to another one located below
the first one.

Unfortunately the settable comparison function used
in set_gdbarch_inner_than() takes just lhs and rhs addresses as arguments.
Therefore the possibility to avoid the comparison of addresses
from two different stack is very limited or impossible.

This hack abuses the internal RAM mapping to non-secure and secure/callable
areas used in STM32L5 device to prevent false unwinding fails
when switching secure/non-secure mode.

How to solve the problem correctly? Please advise...

Add a settable value
"set arm unwind-inner-check 0"
to switch off the inner frame check on user request?

Rework frame_id_inner() and gdbarch to allow a smarter comparator
with access to frame details?

Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
 gdb/arm-tdep.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)


diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 4fac09b..1c683ca 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -876,6 +876,16 @@  class target_arm_instruction_reader : public arm_instruction_reader
+static int
+arm_m_sec_ext_inner_than (CORE_ADDR lhs, CORE_ADDR rhs)
+  if ((lhs & 0xfff00000) == 0x20000000
+      && (rhs & 0xfff00000) == 0x30000000)
+    return false;
+  return (lhs < rhs);
 /* Remove useless bits from addresses in a running program.  */
 static CORE_ADDR
 arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
@@ -10725,7 +10735,9 @@  enum arm_vfp_cprc_base_type
   set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
   /* The stack grows downward.  */
-  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_inner_than (gdbarch, have_sec_ext ?
+				   arm_m_sec_ext_inner_than :
+				   core_addr_lessthan);
   /* Breakpoint manipulation.  */
   set_gdbarch_breakpoint_kind_from_pc (gdbarch, arm_breakpoint_kind_from_pc);