@ltratt
I've used conditional breakpoints and logging in lldb to make it approximate a trace-based system. This is basically letting me add conditional printfs to a program without recompiling it. That's the kind of feature I'd like to see front and centre in a debugger.
That said, I completely agree on reverse debugging. I had one test case in the Objective-C runtime that was an intermittent memory corruption bug. It triggered on one in (maybe) twenty CI runs and made the CI flaky. Occasionally I could reproduce it with a debugger attached, but never with enough information to debug.
When I was working on the Windows port, I used WinDbg. It had a time-travel mode, so I ran the test case until I got a crash, put a watchpoint on the address with the corrupted state, and ran it backwards to get to the place where the corruption happened. The fix was then trivial.
We have an internal tool that I hope we'll open source once it's a bit more mature that provides a gdbserver interface from a CPU instruction trace. This lets you single step forwards and backwards in time and inspect the state at any point.