8000 Does minidump-writer support dumping stack without crash? · Issue #37 · rust-minidump/minidump-writer · GitHub
[go: up one dir, main page]

Skip to content

Does minidump-writer support dumping stack without crash? #37

Closed

Description

@simon-fu

Sometimes there are bugs in the program that one thread may run into dead loop and burn cpu.
We can spawn watch-dog thread to monitor all thread and dump stack if dead-loop occur.
So it can be very helpful if minidump-writer supports dumping stack without crash.

Activity

  1. simon-fu commented on Jun 26, 2022

    @simon-fu
    Author

    or in other words, how to make CrashContext without crashing for linux/macos/windows ?

  2. Jake-Shadle commented on Jun 30, 2022

    @Jake-Shadle
    Collaborator

    For Linux the crash context is optional, but you are correct that it should also be optional for windows and mac as well. That being said, it's also fairly trivial to generate a crash context for Mac and Windows manually.

    // Unsafe function
    use windows_sys::Win32::{
        System::{
            Diagnostics::Debug::{
                RtlCaptureContext, EXCEPTION_POINTERS, EXCEPTION_RECORD,
            },
            Threading::GetCurrentThreadId,
        },
    };
    
    let mut exception_record: EXCEPTION_RECORD = std::mem::zeroed();
    let mut exception_context = std::mem::MaybeUninit::uninit();
    
    // Get the CPU context
    RtlCaptureContext(exception_context.as_mut_ptr());
    
    let mut exception_context = exception_context.assume_init();
    
    let exception_ptrs = EXCEPTION_POINTERS {
        ExceptionRecord: &mut exception_record,
        ContextRecord: &mut exception_context,
    };
    
    let exception_code = <a Windows windows_sys::Win32::Foundation::STATUS_* exception code>;
    exception_record.ExceptionCode = exception_code;
    
    let cc = crash_context::CrashContext {
        exception_pointers: (&exception_ptrs as *const EXCEPTION_POINTERS)
            .cast(),
        process_id: std::process::id(),
        thread_id: GetCurrentThreadId(), // or even better, the id of the thread that got stuck
        exception_code,
    };
    // Unsafe function
    let cc = crash_context::CrashContext {
        task: mach2::traps::mach_task_self(),
        thread: mach2::mach_init::mach_thread_self(), // preferably the id of the thread that is stuck
        handler_thread: mach2::mach_init::mach_thread_self(),
        exception: None, // or optionally fill out the exception info
    };
  3. simon-fu commented on Jul 8, 2022

    @simon-fu
    Author

    Thanks @Jake-Shadle for the reply
    For linux, there are two args that MinidumpWriter::new(process: Pid, blamed_thread: Pid)
    How to fill with MinidumpWriter::new with args of process and blamed_thread ?

  4. Jake-Shadle commented on Jul 8, 2022

    @Jake-Shadle
    Collaborator

    If you're dumping the same process you could use std::process:id() to get the process identifier, the thread identifier you either retrieve in the thread itself by calling libc::gettid() or if you have a JoinHandle or similar you can get the thread id with https://doc.rust-lang.org/std/os/unix/thread/trait.JoinHandleExt.html#tymethod.as_pthread_t

  5. simon-fu commented on Jul 8, 2022

    @simon-fu
    Author

    @Jake-Shadle
    I use libc::gettid() and fail to build with error undefined reference to `gettid'
    And I change to libc::syscall(libc::SYS_gettid) and build success
    However, after cargo run it print error message:
    No threads left to suspend out of 9

  6. Jake-Shadle commented on Jul 8, 2022

    @Jake-Shadle
    Collaborator

    That is most likely because you need to the mark the process as dumpable with libc::syscall(libc::SYS_prctl, PR_SET_DUMPABLE, 1, 0, 0, 0) otherwise most/all ptrace operations will fail. You might also run into problems using minidumper in the same process, it was never designed for that so it has no protections against suspending the thread that is currently executing, the man page doesn't say anything AFAICT about special behavior for attaching to the currently executing thread, so I'm assuming it will actually send SIGSTOP to the thread and dead lock your program, so you could try adding logic to ignore stopping the thread if it is the same thread id as the current thread.

  7. simon-fu commented on Jul 8, 2022

    @simon-fu
    Author

    libc::syscall(libc::SYS_prctl, PR_SET_DUMPABLE, 1, 0, 0, 0) did not work and still "No threads left to suspend out of 9"
    I give up and plan to dump in another process
    Thank you very much @Jake-Shadle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0