summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minidump-writer/README.md
blob: 20962c913f02d0faffb7347fe6045fedd4354fee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<div align="center">

# `minidump-writer`

**Rust rewrite of Breakpad's minidump_writer (client)**

[![Rust CI](https://github.com/rust-minidump/minidump-writer/actions/workflows/ci.yml/badge.svg)](https://github.com/rust-minidump/minidump-writer/actions/workflows/ci.yml)
[![crates.io](https://img.shields.io/crates/v/minidump-writer.svg)](https://crates.io/crates/minidump-writer)
[![docs.rs](https://docs.rs/minidump-writer/badge.svg)](https://docs.rs/minidump-writer)

</div>

This project is currently being very actively brought up from nothing, and is really ultimately many separate client implementations for different platforms.

## Usage / Examples

The primary use case of this crate is for creating a minidump for an **external** process (ie a process other than the one that writes the minidump) as writing minidumps from within a crashing process is inherently unreliable. That being said, there are scenarios where creating a minidump can be useful outside of a crash scenario thus each supported platforms has a way to generate a minidump for a local process as well.

For more information on how to dump an external process you can check out the documentation or code for the [minidumper](https://docs.rs/minidumper/latest/minidumper/) crate.

### Linux

#### Local process

```rust
fn write_minidump() {
    // At a minimum, the crashdump writer needs to know the process and thread that you want to dump
    let mut writer = minidump_writer::minidump_writer::MinidumpWriter::new(
        std::process::id() as _,
        // This gets the current thread, but you could get the id for any thread
        // in the current process
        unsafe { libc::syscall(libc::SYS_gettid) } as i32
    );

    // If provided with a full [crash_context::CrashContext](https://docs.rs/crash-context/latest/crash_context/struct.CrashContext.html),
    // the crash will contain more info on the crash cause, such as the signal
    //writer.set_crash_context(minidump_writer::crash_context::CrashContext { inner: crash_context });

    // Here we could add more context or modify how the minidump is written, eg
    // Add application specific memory blocks to the minidump
    //writer.set_app_memory()
    // Sanitize stack memory before it is written to the minidump by replacing
    // non-pointer values with a sentinel value
    //writer.sanitize_stack();

    let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file");
    writer.dump(&mut minidump_file).expect("failed to write minidump");
}
```

#### External process

```rust
fn write_minidump(crash_context: crash_context::CrashContext) {
    // At a minimum, the crashdump writer needs to know the process and thread that the crash occurred in
    let mut writer = minidump_writer::minidump_writer::MinidumpWriter::new(crash_context.pid, crash_context.tid);

    // If provided with a full [crash_context::CrashContext](https://docs.rs/crash-context/latest/crash_context/struct.CrashContext.html),
    // the crash will contain more info on the crash cause, such as the signal
    writer.set_crash_context(minidump_writer::crash_context::CrashContext { inner: crash_context });

    // Here we could add more context or modify how the minidump is written, eg
    // Add application specific memory blocks to the minidump
    //writer.set_app_memory()
    // Sanitize stack memory before it is written to the minidump by replacing
    // non-pointer values with a sentinel value
    //writer.sanitize_stack();

    let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file");
    writer.dump(&mut minidump_file).expect("failed to write minidump");
}
```

### Windows

#### Local process

```rust
fn write_minidump() {
    let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file");
    
    // Attempts to the write the minidump
    minidump_writer::minidump_writer::MinidumpWriter::dump_local_context(
        // The exception code, presumably one of STATUS_*. Defaults to STATUS_NONCONTINUABLE_EXCEPTION if not specified
        None,
        // If not specified, uses the current thread as the "crashing" thread,
        // so this is equivalent to passing `None`, but it could be any thread
        // in the process
        Some(unsafe { windows_sys::Win32::System::Threading::GetCurrentThreadId() }),
        &mut minidump_file,
    ).expect("failed to write minidump");;
}
```

#### External process

```rust
fn write_minidump(crash_context: crash_context::CrashContext) {
    use std::io::{Read, Seek};

    // Create the file to write the minidump to. Unlike MacOS and Linux, the
    // system call used to write the minidump only supports outputting to a file
    let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file");
    // Attempts to the write the minidump for the crash context
    minidump_writer::minidump_writer::MinidumpWriter::dump_crash_context(crash_context, &mut minidump_file).expect("failed to write minidump");;

    let mut minidump_contents = Vec::with_capacity(minidump_file.stream_position().expect("failed to get stream length") as usize);
    minidump_file.rewind().expect("failed to rewind minidump file");

    minidump_file.read_to_end(&mut minidump_contents).expect("failed to read minidump");
}
```

### MacOS

#### Local process

```rust
fn write_minidump() {
    // Defaults to dumping the current process and thread.
    let mut writer = minidump_writer::minidump_writer::MinidumpWriter::new(None, None)?;

    let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file");
    writer.dump(&mut minidump_file).expect("failed to write minidump");
}
```

#### External process

```rust
fn write_minidump(crash_context: crash_context::CrashContext) {
    let mut writer = minidump_writer::minidump_writer::MinidumpWriter::with_crash_context(crash_context)?;

    let mut minidump_file = std::fs::File::create("example_dump.mdmp").expect("failed to create file");
    writer.dump(&mut minidump_file).expect("failed to write minidump");
}
```

## Client Statuses

- ✅ Usable, but care should be taken in production environments
- ⚠️ Implemented (ie compiles), but untested and needs more work to be usable
- ⭕️ Unimplemented, but could be implemented in the future
- ❌ Unimplemented, and unlikely to ever be implemented

| Arch      | unknown-linux-gnu | unknown-linux-musl | linux-android | pc-windows-msvc | apple-darwin | apple-ios |
----------- | ----------------- | ------------------ | ------------- | --------------- | ------------ | --------- |
`x86_64`    | ✅                | ✅                 | ⚠️            | ✅              | ✅           | ⭕️        |
`i686`      | ✅                | ✅                 | ❌            | ⭕️              | ❌           | ❌        |
`arm`       | ⚠️                | ⚠️                 | ⚠️            | ⭕️              | ❌           | ❌        |
`aarch64`   | ⚠️                | ⚠️                 | ⚠️            | ⭕️              | ✅           | ⭕️        |
`mips`      | ⭕️                | ⭕️                 | ❌            | ❌              | ❌           | ❌        |
`mips64`    | ⭕️                | ⭕️                 | ❌            | ❌              | ❌           | ❌        |
`powerpc`   | ⭕️                | ⭕️                 | ❌            | ❌              | ❌           | ❌        |
`powerpc64` | ⭕️                | ⭕️                 | ❌            | ❌              | ❌           | ❌        |