<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/101943>101943</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
llvm17/18/trunk Insufficient DWARF debug_frame information for CMSE none-secure call
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
dearlam
</td>
</tr>
</table>
<pre>
Cortex-M55 (or Cortex-M33 I assume)
with -mcmse -gdwarf-4 -fomit-frame-pointer
The DWARF FDE for a function with attribute _\_\_attribute\_\_((cmse_nonsecure_entry))_
that calls via a function pointer with attribute _\_\_attribute\_\_((cmse_nonsecure_call))_
does not describe all movements to register SP (stack pointer) which is the Canonical Frame Address
register (Dwarf_regnum_13) in the CIE.
This means it is not possible for a debugger to correctly unwind and show the call stack from callee to caller
(and beyond) because it looks in (Secure) stack memory for the pushed LR (link register) contents at the CFA offset the
DWARF describes, which is incorrect.
Compile with
_clang -c -march=armv8.1m.main+mve -target arm-none-eabi -Os -mcmse -gdwarf-4 -fomit-frame-pointer -mfloat-abi=hard -o sec_to_nonsec_call.o sec_to_nonsec_call.c_
(or -mcpu=cortex-m55, maybe also -I or -isystem for the path to arm_cmse.h header with a strange install)
sec_to_nonsec_call.c:
```
#include <arm_cmse.h>
#define CALL_ATTRIB __attribute__((cmse_nonsecure_call))
#define ENTRY_ATTRIB __attribute__((cmse_nonsecure_entry))
typedef void (*NS_ENTRY_POINT)(unsigned int) CALL_ATTRIB;
volatile NS_ENTRY_POINT nonsec_func = 0;
ENTRY_ATTRIB
void my_sec_func(unsigned int a_param)
{
if (nonsec_func != 0)
{
nonsec_func(a_param);
}
}
```
then disassemble
```
llvm-objdump -d --mcpu=cortex-m55 sec_to_nonsec_call.o > sec_to_nonsec_call.o.disasm.txt
```
and decode the DWARF
```
llvm-objdump --dwarf=frames --mcpu=cortex-m55 sec_to_nonsec_call.o > sec_to_nonsec_call.o.objdump_frames.txt
```
[ or in newer llvm versions
```
llvm-dwarfdump.exe --debug-frame --mcpu=cortex-m55 sec_to_nonsec_call.o > sec_to_nonsec_call.o.dwarfdump_frames.txt
```
]
See there is no corresponding _DW_CFA_def_cfa_offset:+32_ and _DW_CFA_def_cfa_offset:+136_
(CIE Data alignment is -4)
for instructions that move the SP register matching the function call 'nonsec_func(a_param);'
```
push.w {r4, r5, r6, r7, r8, r9, r10, r11}
bic r1, r1, #0x1
sub sp, #0x88
vlstm sp
clrm {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, apsr}
blxns r1
```
The problem can be more easily observed here
[Compiler Explorer 9Yx3c7hnT](https://godbolt.org/z/9Yx3c7hnT)
Looking at the directives in the emitted assembler, neither the
_push.w \{r4, r5, r6, r7, r8, r9, r10, r11}_
nor the
_sub sp, #136_
- which both move the CFA/SP to lower memory addresses -
have matching directives, where one could reasonably expect
_.cfi_def_cfa_offset 32 ;// 8*4_
and
_.cfi_def_cfa_offset 136 ;// 34 *4_
respectively.
This is using trunk (as I haven't tried an llvm 19.1.0 rc1 yet).
It also reproduces with llvm 17.0.6 and llvm 18.1.8.
Using Compiler Explorer it also exists for versions back to llvm armv7a-clang 11.0.0
Version 10.0.1 does not support the cmse attributes.
Using _-mfix-cmse-cve-2021-35465_ for VLLDM, where supported, makes no difference as that is the restore part of the code.
I believe the bug is caused by ARMExpandPseudoInsts.cpp
[ARMExpandPseudoInsts.cpp line 1555ff](https://github.com/llvm/llvm-project/blob/d8b985c9490664f7ec923e59cf6c603d998179ae/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp#L1555)
where function _ARMExpandPseudo::CMSEPushCalleeSaves()_
uses _ARM::t2STMDB_UPD_
and also where function _ARMExpandPseudo::CMSESaveClearFPRegsV81()_ makes space for the later _VLSTM_
near
```
BuildMI(MBB, MBBI, DL, TII->get(ARM::tSUBspi), ARM::SP)
.addReg(ARM::SP)
.addImm(CMSE_FP_SAVE_SIZE >> 2)
.add(predOps(ARMCC::AL));
```
does not use sequences to add Call Frame Information
(as used by [ARMBaseInstrInfo.cpp line 6468ff](https://github.com/llvm/llvm-project/blob/55255669077b191043b1a8920107890815151835/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp#L6468)
)
```
MachineFunction &MF = *MBB.getParent();
int64_t StackPosEntry =
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, new_8byte_aligned_offset));
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
.addCFIIndex(StackPosEntry)
.setMIFlags(MachineInstr::FrameSetup);
```
Similarly _ARMExpandPseudo::CMSERestoreFPRegsV81()_ does not adjust the CFA, despite the SP register moving back to higher memory addresses, where I'd expect similar statements but with negative value and {_}MachineInstr::FrameDestroy{_}.
_CMSEPopCalleeSaves()_ also makes no CFA adjustments.
Note there are also _ARMExpandPseudo::CMSESaveClearFPRegsV8()_ and _CMSERestoreFPRegsV8()_ similarly lacking.
PARTIAL WORKAROUND?
Remove _-fomit-frame-pointer_ (or use {_}-fno-omit-frame-pointer{_}).
This means the SP is copied to register r7 and a .setfp r7 directive
```
.setfp r7, sp
mov r7, sp
.cfi_def_cfa_register r7
```
This in turn leads to the corresponding DWARF changing the CFA base register with
DW_CFA_def_cfa_register: reg7
so adjustments to SP by the setup code are of course possible and the link register's value can be found in memory, in theory...
BUT the later CLRM wipes out the R7 contents in order to leak nothing at the _blxns_
transition from secure to none-secure.
I think this is just as Requirement 54 of
[https://github.com/ARM-software/acle/releases/download/r2024Q2/cmse-1.4.pdf]
expects.
So, sadly, it is not even a partial workaround.
Moreover, use of framepointer grows code size so it cannot be a project default.
This being for embedded target we need to be able to debug exactly what we will ship.
Our debugger is able to recognise the FNC_RETURN pattern created by blxns instruction and has privileged access to the banked Secure stack memory in house.
And there's no requirement to clear register SP because it is banked, so does not leak information as section 4.3.1 'Information leakage' of cmse-1.4 describes.
Indeed for none secure calls with stack based arguments or return value the toolchain needs to take significant steps to validate and copy these from one stack to another.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysWVtz27qu_jXKC8YaS_JFfsiDL_GM58Rtjp2uNfu8aCgRsrkikdok5ST7158BKd8SN-3ae3dauZZJEADxAR9IZozYScT7YDgLhos71tq90vccma5YfZcr_n4_V9riW289HEIQp0rD8UWSwAqYMW2NQTwJ-ougP30Vdg-9uqgNQm_HX5kuewPolaoWtldqVmOvUUJa1H5895zHwbR_-eZ5j7D4c7pZwnLxAKXSwKBsZWGFkuAWYdZqkbcWIQuGc_fv9Or4IojTIE5JmUwqabBoNWYorX4nheNJ5heze2ahYFVl4CDY5Uqdrv_hiiT6akGu0IBUFjiaQoscgVUV1OqANUprwCrQuBOGlt4-kduNZcXLUZ0gnoB32eteFHsQBuweYc6kkqJgFSzJ0TDlXKMxfsmTvCBOF7QtmcadbOssSkickF7E6iG83gZhoEYmDQhL65DSjTJG5BV228Ixb3c71KR1obTGwlbv0MpXITkwycHs1auTTn4Ab0mpVe2-I7p59L9jSMQpzcrxXUlOuuVYsNYgaVAp9WJI2SBOt865NMCLrLFW-t0pRYs1rdkjh8cNja2EfDm5lKYUSlrnama94cspqLI06L56RXz8HbfIBPEcTv4WsjP1yl1zVTeiQhcul--zomJyB70CejXTxT5IFkzXhzSM6rBmQgbxrD4g9CzTO7TAdN2TSmIPWS6g9938HqKgV5eVYrbHchEkiz3THHoKDBaZVV04ulgMb74ssitIOqj36qJpg2RReMjXwyF5oWbvLmSNgt4KaJgw78ZifXY-s3vaV6brjDQP97BHxk9IAmM1kzsEIY3t0PGTfHBL0yA5Dhz1u7-d0omQRdVyhCCZnxcPkofTAI6lkAjz6eNjNn1-3qxmkJ1xnP0KwR_lPHx73vzj9wVdJJ8u97w3yLGEgxIc3JTpt23mpT59X317doPTVrpEzUFIS_F7oX6QzLyog6qYpfC7FgCd6yipQZAsoH-acan8UYbgUL9nxwkflgaWNUyz-uyI8exyy7q0BKIkW64WjiO_9mnm1YSfyLn-uJBHSeKsSnJ78nhxVHIBN-PF7lECF4YZg3Ve4c1BVXWoeyr_i7d1Az0Ovc-guI2xIHm4-UPoVqxD-2Zvq9WF_6eiSGmRY6E4OpC5_PSFALjWvOdyR5AsXNIw_wU7OtGZF_hLey4BPpxR3hASJL6idprCAbURSpqbMsBb42ygRUN8Q7KJio9Pg_-NjTlK_7VJw8WlPVt0W6LR10hfB02jJBdyB9niz2y-nGYcy6woWeYLDSWxeJbEmSuSX42JklF2ysrz1QMsmGXAKrGTxBdozd7gBKzSOdZY3ToOQ9yAWUcuXNRsn87coma22JOG9MOJ9LgyHcTjr-AWj2_vElXd8PUat8F4pgdUN7SrHnrknmP3TN1z4p5R339EZ-C6-bkoPiQCAB35sfQM4qT_FnUKmDb_NNg0p2Fpein5UBlbfxhumm7Hoah0HfQnAJSddOwWTNzz71njPtx01hh9Mg7y6o2CfeLNueVOYsGNVnmFRJYk5Ai10gjIjKjeQeUG9QE5UOSdgNWREA0Pb02lNGqY_OMtKcZ7-UxRG6d7axvjImsZxMud4rmqbKj0LoiX_wri5Xn4dVV-VOqFgqWjTFwQ_xEHNEf2iLWwFjkc06kmmyUKQsaZVl25O7sKmGA4_3eCpQOHVD9d5XNUnGLiDK5eR-9yZfdnvMyX5KjtE9GZSlGy6ogm8_SaMqmfv2cHPEPq7B5PHCk5KIlQqLbioJEZJVlevQO-NVjYWwUsC4tSfMgIkMTgAEh7B0QXBtmpOvy2kCgZXUhJBnAhhxKX17x6_9wMCAOtcSlDt_KFqjwzsAKyXQbx2ILVgkJA-pweTcIo7IMuInhHYi5XElfWs0iNjVa8LdB4fuinjsN-OHLJ0X9PwyhMu_k_nA6fQ110EvFNGGscHz2WFcipS6BdJGnEv8es54l5FIX9sMPcH344RP2wH0ZwatVM2zRK-9B3ZPxE9cyVTlmvLsVbj4b0igP24n4c9ZLhYDTMnDp_PD4u1ueQ6MQi98T6xa0GXJQlapQFAusSeNfkaTSWUkDDtAVVenUUx2u_Qo6VwC6C83ZHs10TxSF_h-lm_fDWMMmfDLZcraSxJiya5qpaD2c_GwYVEd9oOByW5c2MIuy-zcNC1UG8JGd3H71Gq78o1ONlXqk8iJc8zSfpsJgMJv3RaFCOsZjECQ4nRTkqRv2ETyZpNJ4wvJAjaN6z65OCeDndrP3ztj1x8khqfshj3vGncpd9mE52JNP5evvw1Jr93PWoW-ZwnJ5b-JaAT1P9cBtvn9eLWfbjaXGGow_F316OFplXyPTyaYM780cadSt2cWEaVuCpxaoYVfDsj8ft8_qYAJHpr_hg9zFrRcXXqyBO17MZhd16NlvR5-KRns-rVS9IHpyD07OB2x8z0wjXjczh9Hr79DNCf_URMs43uLsU-DdmruqaiM96-5Atn7Lt9I-HbLv6vwficUTl4t8WFMRpo5F_b4zXZD73ukwfu5Ysmd2me6cs0BoEg_9sCZrunIZxDhQj3ZnLSpZK14x2-nyaQSnTI8-jasYMUpBqGn1G1GgwSv9TRA2H8XA4Gk3643EeTaL-IMkjlk7iftQfp5N-Gg2jYZQmw18j6pOShCZS8aIJntzg919E3ppRacTlEQpBPFovXUsaxNP1bBbu0D4xjdTipld93aUsIe1okFnYWla8PCnzQC01SfkiBtZL2n63RWQThf58vlytzjTZB0JRigWW85J99_Q7TmVbVY11TMb9kfiapfm7xczxb-RHpn4MoBsafwLcyjq4Ue_yqIrO2HgOHzA3X66y1bft8-bH_Hn1_dvVAcTPQtxZxfEtiNMrB_1ipkG7Xi0rtiNkdPvkvOM1cZ7bom2br1CyFbWomK7ev0hyG1-_PqW4E8IY_6s19ky95sDRNMLe6F7UgQrusazvxW5_g52dS-0qiMe8o1tgvK5gLLPdqWveWk8_JO4Y8R84sKpFx0CC8SwLxoufeGaBxmr13g26KsWZKySq-VxHfHU4lfz5ctrZ7rS5EvJN2WN_yXR38vY36shpQeozb2zC8Xdz2r-KFUT1r5R4mm6eV9NH-PP75n-mm-8_vi2CpDt-2KCjy9mtU8msuzWgzNk5qFdK1btxI-B__UgSL86guwggMqMaopmXB-V67AxkLpjLhr6fOPhvVMXPgCib7ptvP0zz62m1Onx48_tzr3j6hVU_6QyFb7taLaFCxl0x8mTw8ujBn2EXeyZ3xz6fAi1nBs-eOx9XfziEOJ2YJ1Ma3ali1GWg0rrbJypuJNxQjnCE1EWqKqnf0QbPlwa0R46_XB_Jj02Htq7PLVUrOVno8UxO9F2m0u9heBUgsx_PF4xo_rhZw6to0IBqfR7ZjM_n_UKC0tzfVlTIXijn7C-62sx15ceLIc2kEa5WuQsLf4hLU93xvP8aHjk3yXmhp-uSXBZjBjb4z1Zol2JgOABVnhr1L2r8dLPuGVXaV6aJ_LKiog-NFTKX0pZcvcpKMU5v4348-N84iJeu54jCQdjw8nRA5fPddT7ZKheUjFfesaerHTygBOaaC8EqeFX6hWnaiavpa6VRHXx7T7BWJTggH-8hdlq9Gh8ERvwLwShaomCSlsiRFvC8BTiWrK3sZ7znSHtCXBfrHDknrPvLkVcEiR76JIpCyip_CQX4xtzl0ys1TK8Ir6KqwOxF0y3wvdXn6yphTrM1FmonhfE1Zvltnm0enn9svkHDrEUtodDIrKdwLj4uD9hcRO-ZgUaLg6hwR-1vUaA5QTJn8gU5-Aur69sqIWGvWnPdvk09RGjrx6426IsYsgoKSu5XN4QXV2TkPLee22J1Lqwu2sWZn1JwGvQmDMIkjCCIxxf81U1gO1LC4bgLrvOF2HXLKTntCu0YYeMIFX-r6qqqt5syDwemd63PHooMcVnMw5_8ZZWqij1zp8PYZTb2QsG0k6IUBZMWjMXG_XJgleDM-sRSqMblIYMesE4T2xEERlBHHd7x-4RPkgm7w_toHMfpIO2Px3f7-wGLEjaKRkVRlHk5KflwjOPJICn64wmbDEd34p6w1k_7w346HCTjMMoZGxU8Z3ESj1KOwaCPNRNVSOQ6VHp3J4xp8T7qR5NBclexHCvjLtvjWOIruF-DOA6Gizt97yh93u5MMOhXgprYkxgrbIVuQDQO4mWUBvHSn8CspGnLUhSCguN4ZZm3O3-EfbXhtDlU_i-zlz_tvWt1df-3ew6nPWWjzrzDffz_AQAA__8knvwW">