Repository: rust
Issue: `-C force-frame-pointers=yes` not respected by `-Z build-std` or `opt-level = "z"`
Labels: C-bug,needs-triage

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

So I've got a project I'm trying to debug, but I'm running into something of an issue. The setup is that I have RISC-V CPUs (`riscv32imc-unknown-none-elf`) debuggable over JTAG using OpenOCD + GDB. I would like to be able to get a backtrace out of GDB in the case that a program panics, but previously I was never able to guarantee that such a trace would be there since the stack would collapse as soon as execution entered into `core::panicking::panic` or the like. The way I was attempting to get backtraces from GDB was by doing something to the effect of
```gdb
file target/riscv32imc-unknown-none-elf/release/crate
set remotetimeout unlimited
break crate::panic_handler

target extended-remote :3333
load

define hook-stop
printf "!!!!! hit panic, execution has stopped !!!!!\n"
backtrace
disconnect
quit 1
end

continue
```

I figured that if I:
- Added `panic = "abort"` to the release profile in`Cargo.toml`
- Switched to nightly
- Added the following to `.cargo/config.toml`:
```toml
[build]
# ...
# added:
rustflags = [
    # ...
    "-C", "force-frame-pointers=yes",
]
# ...

[unstable]
build-std = ["core", "panic_abort"]
```
Then in theory, I should be guaranteed to get backtraces. So I wrote a simple program:
```rs
#![no_std]
#![no_main]

// The particular impl here doesn't matter.
use some_hal_crate::uart::Uart;
use riscv_rt::entry;

const UART_ADDR: *const () = (0b11 << 30) as *const ();

// And neither does the implementation here - I'm just using it for some extra debugging output.
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
    let mut uart = Uart::new(UART_ADDR);
    writeln!(uart, "{info:?}").unwrap();
}

#[entry]
fn main() -> ! {
    skooks();
    loop {}
}

misadventures! {
    am i glad hes frozen in_ there and that were out here and_ that_ hes_ the
    sheriff and__ that__ were_ frozen_ out_ here_ and___ that___ were__ in__
    there__ and____ i_ just remembered were___ out__ here__ what i__ want to know
    is wheres the_ caveman
}

macro_rules! misadventures {
    (@rev [] [$($rev:ident)*]) => {
        misadventures! {
            @defs [skooks $($rev)*]
        }
    };
    (@rev [$first:ident $($rest:ident)*] [$($rev:ident)*]) => {
        misadventures! {
            @rev [$($rest)*] [$first $($rev)*]
        }
    };
    (@defs [$last:ident]) => {
        #[inline(never)]
        fn $last() {
            panic!();
        }
    };
    (@defs [$n0:ident $n1:ident $($rest:ident)*]) => {
        #[inline(never)]
        fn $n0() {
            $n1();
        }

        misadventures! {
            @defs [$n1 $($rest)*]
        }
    };
    ($($words:ident)+) => {
        misadventures! {
            @rev [$($words)+] []
        }
    }
}

pub(crate) use misadventures;
```
However, I have two problem cases:
1. In debug builds, the stack trace disappears as soon as execution enters the panicking code (`crate::am::panic_cold_explicit` I believe). Until then, I get a full trace (very nice!).
2. In release builds (with `debug = true`, `split-debuginfo = "unpacked"`, and `opt-level = "z"`), the stack trace is never deeper than `#0` and `#1` in GDB. It reports `Backtrace stopped: frame did not save the PC`.

`panic = "abort"` was used for all of my testing.

### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

This was done on `nightly-2024-11-18`.

</p>
</details>