bolts: Support dump_registers on Windows/x86 and Windows/aarch64 and fix sig_ign on Windows/x86 (#2494)

* bolts: Support dump_registers on Windows/x86

* bolts: Support dump_registers on Windows/aarch64

* bolts: Fix sig_ign() on Windows/x86

* bolts: Fix format of dump_registers under Windows

* bolts: Add test for dump_register under Windows
This commit is contained in:
Alexander Qi 2024-08-23 07:22:24 +08:00 committed by GitHub
parent 1dfd225b1b
commit 0018f7e406
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 142 additions and 20 deletions

View File

@ -454,30 +454,77 @@ pub fn dump_registers<W: Write>(
} }
/// Write the content of all important registers /// Write the content of all important registers
#[cfg(windows)] #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
pub fn dump_registers<W: Write>( pub fn dump_registers<W: Write>(
writer: &mut BufWriter<W>, writer: &mut BufWriter<W>,
context: &CONTEXT, context: &CONTEXT,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
write!(writer, "r8 : {:#016x}, ", context.R8)?; write!(writer, "r8 : {:#018x}, ", context.R8)?;
write!(writer, "r9 : {:#016x}, ", context.R9)?; write!(writer, "r9 : {:#018x}, ", context.R9)?;
write!(writer, "r10: {:#016x}, ", context.R10)?; write!(writer, "r10: {:#018x}, ", context.R10)?;
writeln!(writer, "r11: {:#016x}, ", context.R11)?; writeln!(writer, "r11: {:#018x}, ", context.R11)?;
write!(writer, "r12: {:#016x}, ", context.R12)?; write!(writer, "r12: {:#018x}, ", context.R12)?;
write!(writer, "r13: {:#016x}, ", context.R13)?; write!(writer, "r13: {:#018x}, ", context.R13)?;
write!(writer, "r14: {:#016x}, ", context.R14)?; write!(writer, "r14: {:#018x}, ", context.R14)?;
writeln!(writer, "r15: {:#016x}, ", context.R15)?; writeln!(writer, "r15: {:#018x}, ", context.R15)?;
write!(writer, "rdi: {:#016x}, ", context.Rdi)?; write!(writer, "rdi: {:#018x}, ", context.Rdi)?;
write!(writer, "rsi: {:#016x}, ", context.Rsi)?; write!(writer, "rsi: {:#018x}, ", context.Rsi)?;
write!(writer, "rbp: {:#016x}, ", context.Rbp)?; write!(writer, "rbp: {:#018x}, ", context.Rbp)?;
writeln!(writer, "rbx: {:#016x}, ", context.Rbx)?; writeln!(writer, "rbx: {:#018x}, ", context.Rbx)?;
write!(writer, "rdx: {:#016x}, ", context.Rdx)?; write!(writer, "rdx: {:#018x}, ", context.Rdx)?;
write!(writer, "rax: {:#016x}, ", context.Rax)?; write!(writer, "rax: {:#018x}, ", context.Rax)?;
write!(writer, "rcx: {:#016x}, ", context.Rcx)?; write!(writer, "rcx: {:#018x}, ", context.Rcx)?;
writeln!(writer, "rsp: {:#016x}, ", context.Rsp)?; writeln!(writer, "rsp: {:#018x}, ", context.Rsp)?;
write!(writer, "rip: {:#016x}, ", context.Rip)?; write!(writer, "rip: {:#018x}, ", context.Rip)?;
writeln!(writer, "efl: {:#016x}, ", context.EFlags)?; writeln!(writer, "efl: {:#018x}", context.EFlags)?;
Ok(())
}
/// Write the content of all important registers
#[cfg(all(target_os = "windows", target_arch = "x86"))]
#[allow(clippy::similar_names)]
pub fn dump_registers<W: Write>(
writer: &mut BufWriter<W>,
context: &CONTEXT,
) -> Result<(), std::io::Error> {
write!(writer, "eax: {:#010x}, ", context.Eax)?;
write!(writer, "ebx: {:#010x}, ", context.Ebx)?;
write!(writer, "ecx: {:#010x}, ", context.Ecx)?;
writeln!(writer, "edx: {:#010x}, ", context.Edx)?;
write!(writer, "edi: {:#010x}, ", context.Edi)?;
write!(writer, "esi: {:#010x}, ", context.Esi)?;
write!(writer, "esp: {:#010x}, ", context.Esp)?;
writeln!(writer, "ebp: {:#010x}, ", context.Ebp)?;
write!(writer, "eip: {:#010x}, ", context.Eip)?;
writeln!(writer, "efl: {:#010x} ", context.EFlags)?;
Ok(())
}
/// Write the content of all important registers
#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
#[allow(clippy::similar_names)]
pub fn dump_registers<W: Write>(
writer: &mut BufWriter<W>,
context: &CONTEXT,
) -> Result<(), std::io::Error> {
for reg in 0..29_usize {
write!(writer, "x{:02}: 0x{:016x} ", reg, unsafe {
context.Anonymous.X[reg]
})?;
if reg % 4 == 3 || reg == 28_usize {
writeln!(writer)?;
}
}
writeln!(writer, "pc : 0x{:016x} ", context.Pc)?;
writeln!(writer, "sp : 0x{:016x} ", context.Sp)?;
writeln!(writer, "fp : 0x{:016x} ", unsafe {
context.Anonymous.Anonymous.Fp
})?;
writeln!(writer, "lr : 0x{:016x} ", unsafe {
context.Anonymous.Anonymous.Lr
})?;
Ok(()) Ok(())
} }
@ -1122,3 +1169,78 @@ mod tests {
dump_registers(&mut writer, &ucontext).unwrap(); dump_registers(&mut writer, &ucontext).unwrap();
} }
} }
#[cfg(windows)]
#[cfg(test)]
mod tests {
use std::io::{stdout, BufWriter};
use std::sync::mpsc;
use windows::Win32::{
Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS},
System::{
Diagnostics::Debug::{
GetThreadContext, CONTEXT, CONTEXT_FULL_AMD64, CONTEXT_FULL_ARM64, CONTEXT_FULL_X86,
},
Threading::{GetCurrentProcess, GetCurrentThread, ResumeThread, SuspendThread},
},
};
use crate::minibsod::dump_registers;
#[test]
#[cfg_attr(miri, ignore)]
pub fn test_dump_registers() {
let (tx, rx) = mpsc::channel();
let (evt_tx, evt_rx) = mpsc::channel();
let t = std::thread::spawn(move || {
let cur = unsafe { GetCurrentThread() };
let proc = unsafe { GetCurrentProcess() };
let mut out = Default::default();
unsafe {
DuplicateHandle(
proc,
cur,
proc,
&mut out as *mut _,
0,
true,
DUPLICATE_SAME_ACCESS,
)
.unwrap()
};
tx.send(out).unwrap();
evt_rx.recv().unwrap();
});
let thread = rx.recv().unwrap();
eprintln!("thread: {:?}", thread);
unsafe { SuspendThread(thread) };
#[derive(Default)]
#[repr(align(16))]
struct Align16 {
pub ctx: CONTEXT,
}
// https://stackoverflow.com/questions/56516445/getting-0x3e6-when-calling-getthreadcontext-for-debugged-thread
let mut c = Align16::default();
if cfg!(target_arch = "x86") {
c.ctx.ContextFlags = CONTEXT_FULL_X86;
} else if cfg!(target_arch = "x86_64") {
c.ctx.ContextFlags = CONTEXT_FULL_AMD64;
} else if cfg!(target_arch = "aarch64") {
c.ctx.ContextFlags = CONTEXT_FULL_ARM64;
}
unsafe { GetThreadContext(thread, &mut c.ctx as *mut _).unwrap() };
let mut writer = BufWriter::new(stdout());
dump_registers(&mut writer, &c.ctx).unwrap();
unsafe { ResumeThread(thread) };
unsafe { CloseHandle(thread).unwrap() };
evt_tx.send(true).unwrap();
t.join().unwrap();
}
}

View File

@ -512,7 +512,7 @@ pub unsafe extern "system" fn handle_exception(
/// It is just casting into another type, nothing unsafe. /// It is just casting into another type, nothing unsafe.
#[must_use] #[must_use]
pub const unsafe fn sig_ign() -> NativeSignalHandlerType { pub const unsafe fn sig_ign() -> NativeSignalHandlerType {
core::mem::transmute(1u64) core::mem::transmute(1usize)
} }
type NativeSignalHandlerType = unsafe extern "C" fn(i32); type NativeSignalHandlerType = unsafe extern "C" fn(i32);