Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows frida support #1607

Merged
merged 99 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
f306edc
WIP: windows frida
s1341 Sep 28, 2023
0a8e8a0
Merge branch 'main' into frida_windows
s1341 Oct 5, 2023
ba8c129
frida-windows: fix hooks not present on windows
s1341 Oct 5, 2023
4bd8d3d
windows: allow building using cargo xwin
s1341 Oct 5, 2023
27987d5
frida-windows: fmrt
s1341 Oct 5, 2023
80fc05a
frida-windows: cleanup and allow asan/drcov on windows
s1341 Oct 5, 2023
e0df019
frida-windows: fmt
s1341 Oct 5, 2023
80c1262
frida-windows: fix clippy
s1341 Oct 5, 2023
f5be7ef
frida-windows: handle unknown exceptions gracefully
s1341 Oct 5, 2023
b3c06f9
frida-windows: rework shadow mapping algo
s1341 Oct 5, 2023
bbc3d13
frida-windows: add hook functions
s1341 Oct 5, 2023
285aa6e
frida-windows: hook functions; fix stack register
s1341 Oct 5, 2023
7615680
minibsod: enable for windows
s1341 Oct 10, 2023
83e5b51
check_shadow: fix edge casees
s1341 Oct 10, 2023
bc163af
asan_rt: rework and add hooks for windows
s1341 Oct 10, 2023
9f49502
inprocess: add minibsod on windows
s1341 Oct 10, 2023
2d07bbe
Fix warnings
s1341 Oct 10, 2023
d16c0d4
Merge branch 'main' into frida_windows
s1341 Oct 10, 2023
dc8e732
minibsod: disable test on windows
s1341 Oct 10, 2023
f08046b
Merge branch 'main' into frida_windows
s1341 Oct 26, 2023
9768ac5
WIP: HookRuntime
s1341 Nov 13, 2023
6ba00c8
Merge branch 'main' into frida_windows
s1341 Dec 14, 2023
b70396e
Cleanup after merge
s1341 Dec 14, 2023
4c5ebf0
Bump frida-gum version
s1341 Dec 14, 2023
5c34f18
Fix conflict marker; update frida
s1341 Dec 14, 2023
467b995
Make winsafe windows-specific
s1341 Dec 14, 2023
11cfdbc
Fmt
s1341 Dec 14, 2023
6030434
Move off of capstone
s1341 Dec 17, 2023
3aa76f0
Format
s1341 Dec 17, 2023
98e129c
Merge branch 'main' into frida_windows
s1341 Dec 17, 2023
0191744
Bump frida version
s1341 Jan 14, 2024
d8fe669
Better detection of clang++ (using cc)
s1341 Jan 14, 2024
ab0a3c2
Make AsanErrors crate public so we can use it in tests
s1341 Jan 14, 2024
2ea6056
Add helper to get immediate of operand
s1341 Jan 14, 2024
d3422b4
Use HookRuntime to hook asan functions
s1341 Jan 14, 2024
539a760
fmt
s1341 Jan 14, 2024
cb2bbc8
Implement recurisve jmp resolve
s1341 Jan 14, 2024
76c53a2
Fix reversed logic
s1341 Jan 14, 2024
7ec2456
windows_hooks: Don't die if functions are already replaced
s1341 Jan 14, 2024
cbae66d
Allow utils to work on windows
s1341 Jan 14, 2024
ba5c41b
Enable allocator hooking on windows
s1341 Jan 14, 2024
46e901b
Warnings; add trace to free
s1341 Jan 14, 2024
0fcb8cb
Make ASAN tests run windows (with cargo xwin compilation)
s1341 Jan 14, 2024
c7ff2cf
Fmt
s1341 Jan 14, 2024
8a5da72
clang-format
s1341 Jan 15, 2024
c012407
clang-format
s1341 Jan 15, 2024
1d9f044
Add more tests
s1341 Jan 16, 2024
1c08230
Fix partial range access bug in unpoisoning/shadow_check
s1341 Jan 16, 2024
597e647
Merge main
s1341 Feb 1, 2024
da3a99a
Merge branch 'main' into frida_windows
s1341 Feb 1, 2024
bc205a1
Merge branch 'main' into frida_windows
tokatoka Feb 5, 2024
f12d09b
Fix check_shadow and implement unit tests
s1341 Feb 1, 2024
6734c25
Fix hooking and PC retrieval
s1341 Feb 1, 2024
3d6d8f5
WIP: Working gdiplus fuzzing with frida-ASAN, no false positives
s1341 Feb 5, 2024
c554b97
Merge main
s1341 Feb 14, 2024
6c3a5d5
LibAFL Frida asan_rt and hook_rt fixes for frida_windows (#2095)
mineo333 May 7, 2024
ecf6af5
Fixes
s1341 May 7, 2024
0f5afa3
alloc: add tests, pass the tests
s1341 May 8, 2024
8fe08ff
HookRuntime before AsanRuntime, and don't Asan if Hooked
s1341 May 8, 2024
1b30874
hook_rt: Fixes
s1341 May 8, 2024
4a2b620
Frida windows check shadow fix (#2159)
mineo333 May 9, 2024
4b53380
Revert to Interceptor based hooks
s1341 May 9, 2024
cb8a300
Merge fixes
s1341 May 9, 2024
4e06b49
fixes
s1341 May 9, 2024
e9f15b5
format
s1341 May 9, 2024
0ab734d
Get rid of hook_rt; fixes
s1341 May 9, 2024
4dd032a
clang-format
s1341 May 9, 2024
ada3737
clang-format
s1341 May 9, 2024
ad6ea3d
Fix with_threshold
s1341 May 9, 2024
57684ab
fixes
s1341 May 9, 2024
5eae3e6
fix build.rs
s1341 May 9, 2024
5ea6feb
fmt
s1341 May 9, 2024
0ef5cfa
Fix offset to RDI on stack
s1341 May 9, 2024
a248ccd
Fix clippy
s1341 May 9, 2024
1cf48c0
Fix build.rs
s1341 May 9, 2024
fd2288c
clippy
s1341 May 9, 2024
35ea431
hook MapViewOfFile
s1341 May 9, 2024
211ef34
fmt
s1341 May 9, 2024
4f8389f
fix
s1341 May 12, 2024
f5b78ff
clippy
s1341 May 12, 2024
af07561
clippy
s1341 May 12, 2024
7887e45
Missing brace
s1341 May 12, 2024
2b05cd9
fix
s1341 May 12, 2024
c04fa47
Clippy
s1341 May 12, 2024
08bf77b
fomrrat
s1341 May 12, 2024
732cf43
fix i64 cast
s1341 May 12, 2024
78fe868
clippy exclude
s1341 May 12, 2024
355cc82
too many lines
s1341 May 12, 2024
6d10f93
Merge branch 'main' into frida_windows
domenukk May 12, 2024
09f3bed
Merge branch 'main' into frida_windows
domenukk May 13, 2024
de157ca
Undo merge fails
domenukk May 13, 2024
e3e713e
fmt
domenukk May 13, 2024
b103134
move debug print
domenukk May 13, 2024
c68faf1
Fix some frida things
domenukk May 13, 2024
11edb5e
Remove unused frida_to_cs fn for aarch64
domenukk May 13, 2024
199feb3
name
domenukk May 13, 2024
c19a522
Merge branch 'main' into frida_windows
domenukk May 13, 2024
c79aebf
Don't touch libafl_qemu
domenukk May 13, 2024
aceef40
Merge branch 'main' into frida_windows
domenukk May 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fuzzers/frida_gdiplus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libloading = "0.7"
mimalloc = { version = "*", default-features = false }
color-backtrace = "0.5"
env_logger = "0.10.0"
2 changes: 2 additions & 0 deletions fuzzers/frida_gdiplus/cargo/.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
target = "x86_64-pc-windows-msvc"
42 changes: 10 additions & 32 deletions fuzzers/frida_gdiplus/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//! going to make it compilable only for Windows, don't forget to modify the
//! `scripts/test_all_fuzzers.sh` to opt-out this fuzzer from that test.

#[cfg(unix)]
domenukk marked this conversation as resolved.
Show resolved Hide resolved
use mimalloc::MiMalloc;
#[cfg(unix)]
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;

Expand All @@ -17,8 +19,8 @@ use libafl::{
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
events::{launcher::Launcher, llmp::LlmpRestartingEventManager, EventConfig},
executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor},
feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
feedback_and_fast, feedback_or, feedback_or_fast,
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor,
Expand All @@ -32,8 +34,6 @@ use libafl::{
state::{HasCorpus, HasMetadata, StdState},
Error,
};
#[cfg(unix)]
use libafl::{feedback_and_fast, feedbacks::ConstFeedback};
use libafl_bolts::{
cli::{parse_args, FuzzerOptions},
current_nanos,
Expand All @@ -42,11 +42,11 @@ use libafl_bolts::{
tuples::{tuple_list, Merge},
AsSlice,
};
#[cfg(unix)]
use libafl_frida::asan::asan_rt::AsanRuntime;
#[cfg(unix)]
use libafl_frida::asan::errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS};
use libafl_frida::{
asan::{
asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
},
cmplog_rt::CmpLogRuntime,
coverage_rt::{CoverageRuntime, MAP_SIZE},
executor::FridaInProcessExecutor,
Expand All @@ -56,6 +56,7 @@ use libafl_targets::cmplog::CmpLogObserver;

/// The main fn, usually parsing parameters, and starting the fuzzer
pub fn main() {
env_logger::init();
color_backtrace::install();

let options = parse_args();
Expand Down Expand Up @@ -98,16 +99,11 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let gum = Gum::obtain();

let coverage = CoverageRuntime::new();
#[cfg(unix)]
let asan = AsanRuntime::new(&options);

#[cfg(unix)]
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage, asan));
#[cfg(windows)]
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage));

//
// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr(
"edges",
Expand All @@ -128,15 +124,12 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
);

// Feedbacks to recognize an input as solution
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
// true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new())
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());

// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
Expand Down Expand Up @@ -176,14 +169,11 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

#[cfg(unix)]
let observers = tuple_list!(
edges_observer,
time_observer,
AsanErrorsObserver::new(&ASAN_ERRORS)
);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);

// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
Expand Down Expand Up @@ -243,14 +233,11 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
TimeFeedback::with_observer(&time_observer)
);

#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());

// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
Expand Down Expand Up @@ -291,14 +278,11 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

#[cfg(unix)]
let observers = tuple_list!(
edges_observer,
time_observer,
AsanErrorsObserver::new(&ASAN_ERRORS)
);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);

// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
Expand Down Expand Up @@ -373,14 +357,11 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
TimeFeedback::with_observer(&time_observer)
);

#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());

// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
Expand Down Expand Up @@ -421,14 +402,11 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

#[cfg(unix)]
let observers = tuple_list!(
edges_observer,
time_observer,
AsanErrorsObserver::new(&ASAN_ERRORS)
);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);

// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
Expand Down
8 changes: 7 additions & 1 deletion fuzzers/frida_libpng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ reqwest = { version = "0.11.4", features = ["blocking"] }


[dependencies]
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression",
"llmp_bind_public", "frida_cli", "errors_backtrace" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" }
frida-gum = { version = "0.13.2", features = [ "auto-download", "event-sink", "invocation-listener"] }
libafl_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libloading = "0.7"
mimalloc = { version = "*", default-features = false }
color-backtrace = "0.5"
<<<<<<< Updated upstream
domenukk marked this conversation as resolved.
Show resolved Hide resolved
=======
log = "0.4.20"
>>>>>>> Stashed changes
env_logger = "0.10.0"
2 changes: 1 addition & 1 deletion fuzzers/frida_libpng/harness.cc
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static char *allocation = NULL;
__attribute__((noinline)) void func3(char *alloc) {
// printf("func3\n");
#ifdef _WIN32
if (rand() == 0) {
if ((rand() % 2) == 0) {
alloc[0x1ff] = 0xde;
printf("alloc[0x200]: %d\n", alloc[0x200]);
}
Expand Down
4 changes: 3 additions & 1 deletion fuzzers/frida_libpng/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ use libafl_targets::cmplog::CmpLogObserver;

/// The main fn, usually parsing parameters, and starting the fuzzer
pub fn main() {
env_logger::init();
color_backtrace::install();
log::info!("hello!");
domenukk marked this conversation as resolved.
Show resolved Hide resolved

let options = parse_args();

Expand Down Expand Up @@ -98,7 +100,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {

#[cfg(unix)]
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage, asan));
FridaInstrumentationHelper::new(&gum, options, tuple_list!(asan, coverage));
#[cfg(windows)]
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, &options, tuple_list!(coverage));
Expand Down
17 changes: 14 additions & 3 deletions libafl/src/executors/inprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ impl InProcessHandlers {
{
unsafe {
let data = &mut GLOBAL_STATE;
#[cfg(feature = "std")]
windows_exception_handler::setup_panic_hook::<E, EM, OF, Z>();
//#[cfg(feature = "std")]
//windows_exception_handler::setup_panic_hook::<E, EM, OF, Z>();
setup_exception_handler(data)?;
compiler_fence(Ordering::SeqCst);

Expand Down Expand Up @@ -1029,7 +1029,7 @@ pub mod windows_exception_handler {
sync::atomic::{compiler_fence, Ordering},
};
#[cfg(feature = "std")]
use std::panic;
use std::{io::Write, panic};

use libafl_bolts::os::windows_exceptions::{
ExceptionCode, Handler, CRASH_EXCEPTIONS, EXCEPTION_HANDLERS_SIZE, EXCEPTION_POINTERS,
Expand Down Expand Up @@ -1261,6 +1261,17 @@ pub mod windows_exception_handler {
let exception_list = data.exceptions();
if exception_list.contains(&code) {
log::error!("Crashed with {code}");
#[cfg(all(feature = "std"))]
domenukk marked this conversation as resolved.
Show resolved Hide resolved
{
let mut bsod = Vec::new();
{
let mut writer = std::io::BufWriter::new(&mut bsod);
libafl_bolts::minibsod::generate_minibsod(&mut writer, exception_pointers)
.unwrap();
writer.flush().unwrap();
}
log::error!("{}", std::str::from_utf8(&bsod).unwrap());
}
} else {
// log::trace!("Exception code received, but {code} is not in CRASH_EXCEPTIONS");
is_crash = false;
Expand Down
2 changes: 1 addition & 1 deletion libafl_bolts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub mod fs;
#[cfg(feature = "alloc")]
pub mod llmp;
pub mod math;
#[cfg(all(feature = "std", unix))]
#[cfg(feature = "std")]
pub mod minibsod;
pub mod os;
#[cfg(feature = "alloc")]
Expand Down
84 changes: 83 additions & 1 deletion libafl_bolts/src/minibsod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ use std::io::{BufWriter, Write};
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
use std::process::Command;

#[cfg(unix)]
use libc::siginfo_t;
#[cfg(windows)]
use windows::Win32::System::Diagnostics::Debug::{CONTEXT, EXCEPTION_POINTERS};

#[cfg(unix)]
use crate::os::unix_signals::{ucontext_t, Signal};

/// Write the content of all important registers
Expand Down Expand Up @@ -353,7 +357,7 @@ pub fn dump_registers<W: Write>(
write!(writer, "cs : {:#016x}, ", ucontext.sc_cs)?;
Ok(())
}
///

/// Write the content of all important registers
#[cfg(all(
any(target_os = "solaris", target_os = "illumos"),
Expand Down Expand Up @@ -393,6 +397,35 @@ pub fn dump_registers<W: Write>(
Ok(())
}

/// Write the content of all important registers
#[cfg(windows)]
#[allow(clippy::similar_names)]
pub fn dump_registers<W: Write>(
writer: &mut BufWriter<W>,
context: &CONTEXT,
) -> Result<(), std::io::Error> {
write!(writer, "r8 : {:#016x}, ", context.R8)?;
write!(writer, "r9 : {:#016x}, ", context.R9)?;
write!(writer, "r10: {:#016x}, ", context.R10)?;
writeln!(writer, "r11: {:#016x}, ", context.R11)?;
write!(writer, "r12: {:#016x}, ", context.R12)?;
write!(writer, "r13: {:#016x}, ", context.R13)?;
write!(writer, "r14: {:#016x}, ", context.R14)?;
writeln!(writer, "r15: {:#016x}, ", context.R15)?;
write!(writer, "rdi: {:#016x}, ", context.Rdi)?;
write!(writer, "rsi: {:#016x}, ", context.Rsi)?;
write!(writer, "rbp: {:#016x}, ", context.Rbp)?;
writeln!(writer, "rbx: {:#016x}, ", context.Rbx)?;
write!(writer, "rdx: {:#016x}, ", context.Rdx)?;
write!(writer, "rax: {:#016x}, ", context.Rax)?;
write!(writer, "rcx: {:#016x}, ", context.Rcx)?;
writeln!(writer, "rsp: {:#016x}, ", context.Rsp)?;
write!(writer, "rip: {:#016x}, ", context.Rip)?;
writeln!(writer, "efl: {:#016x}, ", context.EFlags)?;

Ok(())
}

#[allow(clippy::unnecessary_wraps)]
#[cfg(not(any(
target_vendor = "apple",
Expand All @@ -402,6 +435,7 @@ pub fn dump_registers<W: Write>(
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
windows,
any(target_os = "solaris", target_os = "illumos"),
)))]
fn dump_registers<W: Write>(
Expand Down Expand Up @@ -615,6 +649,7 @@ fn write_crash<W: Write>(
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
windows,
any(target_os = "solaris", target_os = "illumos"),
)))]
fn write_crash<W: Write>(
Expand All @@ -628,6 +663,33 @@ fn write_crash<W: Write>(
Ok(())
}

#[cfg(windows)]
fn write_crash<W: Write>(
writer: &mut BufWriter<W>,
exception_pointers: *mut EXCEPTION_POINTERS,
) -> Result<(), std::io::Error> {
// TODO add fault addr for other platforms.
unsafe {
writeln!(
writer,
"Received exception {:0x} at address {:x}",
(*exception_pointers)
.ExceptionRecord
.as_mut()
.unwrap()
.ExceptionCode
.0,
(*exception_pointers)
.ExceptionRecord
.as_mut()
.unwrap()
.ExceptionAddress as usize
)
}?;

Ok(())
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn write_minibsod<W: Write>(writer: &mut BufWriter<W>) -> Result<(), std::io::Error> {
match std::fs::read_to_string("/proc/self/maps") {
Expand Down Expand Up @@ -853,6 +915,26 @@ pub fn generate_minibsod<W: Write>(
write_minibsod(writer)
}

/// Generates a mini-BSOD given an EXCEPTION_POINTERS structure.
#[cfg(windows)]
#[allow(clippy::non_ascii_literal, clippy::too_many_lines)]
pub fn generate_minibsod<W: Write>(
writer: &mut BufWriter<W>,
exception_pointers: *mut EXCEPTION_POINTERS,
) -> Result<(), std::io::Error> {
writeln!(writer, "{:━^100}", " CRASH ")?;
write_crash(writer, exception_pointers)?;
writeln!(writer, "{:━^100}", " REGISTERS ")?;
dump_registers(writer, unsafe {
(*exception_pointers).ContextRecord.as_mut().unwrap()
})?;
writeln!(writer, "{:━^100}", " BACKTRACE ")?;
writeln!(writer, "{:?}", backtrace::Backtrace::new())?;
writeln!(writer, "{:━^100}", " MAPS ")?;
write_minibsod(writer)
}

#[cfg(unix)]
#[cfg(test)]
mod tests {

Expand Down
Loading