()
| 13 | } |
| 14 | |
| 15 | pub(crate) fn stack_trace_64() -> SmallVec<[StackFrame; 10]> { |
| 16 | let mut context = unsafe { core::mem::zeroed::<CONTEXT>() }; |
| 17 | let mut unwind_history_table = unsafe { core::mem::zeroed::<UNWIND_HISTORY_TABLE>() }; |
| 18 | let mut image_base = 0u64; |
| 19 | let mut handler_data: PVOID = null_mut(); |
| 20 | let mut establisher_frame = 0u64; |
| 21 | let nv_context = unsafe { core::mem::zeroed::<KNONVOLATILE_CONTEXT_POINTERS>() }; |
| 22 | |
| 23 | unsafe { |
| 24 | RtlCaptureContext(&mut context); |
| 25 | } |
| 26 | |
| 27 | let mut frame = 0u64; |
| 28 | let mut res = SmallVec::new(); |
| 29 | |
| 30 | unsafe { |
| 31 | loop { |
| 32 | let runtime_function = |
| 33 | RtlLookupFunctionEntry(context.Rip, &mut image_base, &mut unwind_history_table); |
| 34 | |
| 35 | if runtime_function.is_null() { |
| 36 | if context.Rsp < 0x7FFF_FFFF_FFFFu64 { |
| 37 | break; |
| 38 | } |
| 39 | context.Rip = *(context.Rsp as *const ULONG64); |
| 40 | context.Rsp += 8; |
| 41 | } else { |
| 42 | RtlVirtualUnwind( |
| 43 | 0, |
| 44 | image_base, |
| 45 | context.Rip, |
| 46 | runtime_function, |
| 47 | &mut context, |
| 48 | &mut handler_data, |
| 49 | &mut establisher_frame, |
| 50 | null_mut(), |
| 51 | ); |
| 52 | } |
| 53 | |
| 54 | let reg_names = [ |
| 55 | "Rax", "Rcx", "Rdx", "Rbx", "Rsp", "Rbp", "Rsi", "Rdi", "R8", "R9", "R10", "R11", |
| 56 | "R12", "R13", "R14", "R15", |
| 57 | ]; |
| 58 | |
| 59 | // println!("FRAME {:02}: Rip={:x} Rsp={:x} Rbp={:x}", frame, context.Rip, context.Rsp, context.Rbp); |
| 60 | for i in 0..16 { |
| 61 | if let Some(reg) = nv_context.Anonymous2.IntegerContext[i].as_ref() { |
| 62 | /* println!( |
| 63 | " -> Saved register '{}' on stack at {:x} (=> {:x})", |
| 64 | reg_names[i], reg, *reg |
| 65 | );*/ |
| 66 | } |
| 67 | } |
| 68 | res.push(StackFrame { |
| 69 | rbp: context.Rbp as _, |
| 70 | rsp: context.Rsp as _, |
| 71 | }); |
| 72 | if context.Rip == 0 { |
no outgoing calls
no test coverage detected