crashes - 1-3-7/disrobe GitHub Wiki
disrobe crash <file> triages a crash record without a debugger: Linux ELF core files (32- and 64-bit, either byte order) and minidumps written by Windows (MiniDumpWriteDump, Task Manager, WER), Breakpad or Crashpad.
disrobe crash core.4242 # fault, threads, modules, memory totals
disrobe crash app.dmp --registers # also every thread's registers
disrobe crash core.4242 --json- The fault. For a core: the signal with its name and
si_codereason (SIGSEGV SEGV_MAPERR,SIGBUS BUS_ADRALN,SIGFPE FPE_INTDIV), the faulting data address forSIGSEGVandSIGBUS, the faulting instruction forSIGILL,SIGFPEandSIGTRAP, and the sending process and user for signals sent withkillortgkill. For a minidump: the exception code with its name (EXCEPTION_ACCESS_VIOLATION,STATUS_STACK_BUFFER_OVERRUN, C++ and CLR exceptions), the faulting instruction, the access kind and data address of an access violation, and every exception parameter. Each address is placed in its module asmodule+offset. - Threads, the faulting one marked. Registers are decoded for x86-64, x86, AArch64, 32-bit Arm and RISC-V 64 cores, and for x86-64, x86 and ARM64 minidump contexts; the faulting thread of a minidump shows the context saved with the exception, as a debugger's exception-context view does. Every thread's instruction pointer is placed as
module+offset, and minidump thread names are shown. - Return-address candidates: the words above each thread's stack pointer (64 KiB at most) that point into executable memory of a mapped module. This is a stack scan, not an unwound backtrace; frames can be missing or stale.
- Modules. A core's mapped files come from its
NT_FILEnote, each with the GNU build ID read from its in-memory ELF header when the core captured that page. When the core captured the dynamic loader's state, each shared library also carries the name the loader gave it (loader_name), read the way a debugger reads it: from the executable's program headers (AT_PHDR) to its dynamic section,DT_DEBUGtor_debug, and along thelink_maplist. The kernel records resolved paths (/usr/lib/x86_64-linux-gnu/libc.so.6) where the loader and debuggers name the path it opened (/lib/x86_64-linux-gnu/libc.so.6). A minidump's modules carry their PDB name and identity (GUID and age, the key a symbol server uses), timestamp and checksum. - The process: PID, parent, user and group, name and command line from
NT_PRPSINFO, the executable (the module holdingAT_ENTRY, orAT_EXECFN), the auxiliary vector withAT_EXECFNandAT_PLATFORMread back as strings, and from a minidump the operating system version, processor count, PID and start time, plus the command line a Breakpad Linux minidump records. - Memory totals (segments, bytes described, bytes captured, executable ranges) and a count of every note or stream by type.
crates/disrobe-dataforensics/tests/crash_reference.rs grades two ways.
- Minidumps written by Windows: a Python script starts three named threads, captures its own CPU context, plants marker values in fifteen registers and an instruction pointer 0x1234 bytes into the Python DLL, and asks
dbghelp!MiniDumpWriteDumpfor a dump with that context as an access-violation exception and for a second dump without one. The report must match what the process itself recorded through Windows APIs: OS version and build (RtlGetVersion), PID and start time (GetProcessTimes), thread names, the faulting thread and its registers, the fault aspython3xx.dll+0x1234, every module's path, base and size (EnumProcessModulesEx), and the PDB identity and timestamp of the Python DLL andntdll.dllasSymSrvGetFileIndexInfoWcomputes them. Every waiting thread's instruction pointer must fall in a module. A changed exception code or register value must fail the comparison, and 300 corrupted dumps must produce a report or a typed error. This runs on Windows hosts. - Kernel-written cores: four authored C programs (a null read,
abort, a fault in one of four threads, unbounded recursion) are built with gcc and run on a GitHub-hosted Ubuntu runner, and the kernel's cores are committed with gdb's view of each (corpus/crash/linux/runner/). The report must match gdb on the signal, the command line, the set of threads and the faulting one, every thread's program counter, every register of the faulting thread, and each shared library gdb lists, named by the loader and covering gdb's address range (crates/disrobe-dataforensics/tests/linux_core_reference.rs). A flipped program-counter byte in a core and a changed gdb fact each fail the comparison. - ELF cores: a Python script writes six cores byte by byte in the order the Linux kernel writes them (x86-64, the same with more than 65,535-header numbering through section 0, AArch64, i386, RISC-V 64 and big-endian PowerPC 64) and records what it wrote. GNU
readelfmust list the same notes,NT_FILEtable andPT_LOADcount before the test trusts a core. The report must then match every register, thread, signal, reason, address, module with its build ID, auxiliary-vector entry and string, stack-scan candidate and memory total. A changed register, mapped path or build ID must fail the comparison, and 600 corrupted cores must produce a report or a typed error.
- Stacks are scanned, not unwound: no CFI,
.pdataor frame-pointer walking, and no symbol names. - Core registers for other machines (MIPS, PowerPC, s390x, LoongArch) are not decoded; the report names this, and the rest of the core is still read.
- Signal names follow the generic Linux numbering; cores from MIPS, SPARC, Alpha and PA-RISC show signal numbers without names.
- 32-bit Arm minidump contexts are not decoded. The x86 and ARM64 minidump layouts follow the Windows SDK definitions but have no Windows-written dump in the grader.
- Threads, modules, segments, notes, auxiliary-vector entries, the scan window and candidates per thread are bounded, and the report's
problemslist names every bound reached and every part it could not read.