What you could do is create a single new thread and pretend as though its the main thread, observing any panics on the original main thread.
Edit: your mental model should be to avoid thinking about panics (beyond avoiding them in the first place). Panics are supposed to be extremely rare, and typically something that would be difficult to recover from. They are not exceptions; they are not designed to be caught. The difficulty in dealing with them is a feature that prevents anti patterns. If something panics you have a bug.
Catching panics in Rust is meant pretty much only to avoid unwinding across an FFI boundary, since that would be undefined behavior. Pretty much every other use of `catch_unwind` is a mistake, it's not guaranteed to catch all panics (they can also just abort) so panics are rather different from exceptions. Panics are intended to be useless for control flow, unwinding exists to help debugging, and any panic indicates a bug in the invoking program.
Fundamentally panic recovery works the same way in all threads—for both the main thread and spawned threads the standard library implements panic handling by wrapping the user code in catch_unwind().[2][3] It's more or less possible to override the standard library's behavior for the main thread by wrapping all the code in your main() function in a catch_unwind() and then implementing whatever fallback behavior you want, like waiting for other threads to exit before terminating. In some cases something like this happens automatically, for instance if the main thread spawns other threads using std::thread::scope.[4]
[1]: https://doc.rust-lang.org/std/thread/#the-threading-model [2]: https://github.com/rust-lang/rust/blob/7042c269c166191cd5d8d... [3]: https://github.com/rust-lang/rust/blob/7042c269c166191cd5d8d... [4]: https://doc.rust-lang.org/std/thread/fn.scope.html
In a single-threaded program, a panic is not supposed to be "caught" and aborts everything. If the main thread panics, the program stops.
But in a multi-threaded program, a panic terminates only the thread it happened in, and the program is allowed to handle that case without termination.
I'm guessing that setting `panic=abort` changes this behavior, but I'm not sure.
Docs: https://doc.rust-lang.org/std/macro.panic.html#current-imple..., the third sentence of https://doc.rust-lang.org/std/thread/fn.spawn.html