Core dump for Rust
Tags: rust
Published: 2021-08-02 18:04:18

## Intro

From Wikipedia:

> In computing, a core dump,[a] memory dump, crash dump, system dump, or ABEND dump[1] consists of the recorded state of the working memory of a computer program at a specific time, generally when the program has crashed or otherwise terminated abnormally.

In GNU/Linux core dump generation is handle by the kernel. And it can pipe the generation to a user-space program like `systemd-coredump` or  `apport`. You can see if is handle by an external program looking into:

```bash
cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c
```
From `core(5)`

> The default action of certain signals is to cause a process to
terminate and produce a core dump file, a file containing an
image of the process's memory at the time of termination.  This
image can be used in a debugger (e.g., gdb(1)) to inspect the
state of the program at the time that it terminated.  A list of
the signals which cause a process to dump core can be found in
signal(7).

### Signals that generate a core dump.
- SIGABRT Abort signal from abort(3)
- SIGBUS  Bus error (bad memory access)
- SIGFPE  Floating-point exception
- SIGILL  Illegal Instruction
- SIGSEGV Invalid memory reference
See the full documentation for a complete list.

## Generate a core dump on Rust panics.

While rust panics itself help with the great information they provide. Sometimes it is really useful debug using a core dump specially if your binary has debug symbols plus the gdb wrappers provided by `rust-gdb`. 

### Instrument panic handler to generate coredump.

Most of fatal errors in Rust comes from a panic, `unwraps`  that we considered safe (probably?).
Based in a really helpful gist I found:
https://gist.github.com/epilys/a6caba03cb02cfd2880fd80755cd08b8

First modify how the panic is handled by printing the panic trace as usual, but then send a signal that generates a  core to our own process. In the example gist, the signal  is `SIGQUIT`.
```rust
pub fn panic_handler_generate_coredump() {
    let default_panic = std::panic::take_hook();

    std::panic::set_hook(Box::new(move |panic_info| {
        default_panic(panic_info);

        let pid = std::process::id();

        use libc::kill;
        use libc::SIGQUIT;

        use std::convert::TryInto;
        unsafe { kill(pid.try_into().unwrap(), SIGQUIT) };
    }));
}
fn main(){
    panic_handler_generate_coredump();
    panic!("don't Panic!")
}
``` 
### Compile config
Optional: 
```toml
[profile.dev]
opt-level = 0  # Controls the --opt-level the compiler builds with
debug = true   # Controls whether the compiler passes `-g`
```

# Enable core dump collection.

Optional: Change the path where coredump is generated
```bash
sudo sysctl -w kernel.core_pattern=/tmp/core.%u.%p.%t
```
Or check where is generated:
```
cat /proc/sys/kernel/core_pattern
```
## Modify core file size:
From : https://community.perforce.com/s/article/2979
>For most distributions the core file size limitation is set to 0 to produce no core files at all. To find out the limit on the system in question, issue the command:
```
$ ulimit -c
```
>If it is set to 0 then no core files are produced. To allow core files to be produced, set a core file size that is not 0:
```
$ ulimit -c 100000000000
```
or
```
$ ulimit -c unlimited
```
## Generate core
```sh
cargo run
```
## Debug core
```
rust-gdb <path-to-binary> /tmp/<core_path>
thread apply all bt full
#or
where
```