feat: add support for console sessions to crashpad and crash handling in kernel

This commit is contained in:
2026-06-18 12:56:29 +02:00
parent e3c551b9f6
commit ac25a4edd5
5 changed files with 141 additions and 37 deletions
+1 -1
View File
@@ -12,4 +12,4 @@
#pragma once #pragma once
#define MONTAUK_BUILD_NUMBER 112 #define MONTAUK_BUILD_NUMBER 115
+1 -1
View File
@@ -141,7 +141,7 @@ namespace Hal {
rep.timestampTick = Timekeeping::GetTicks(); rep.timestampTick = Timekeeping::GetTicks();
CrashReport::AddReport(rep); CrashReport::AddReport(rep);
Sched::SpawnCrashPad(); Sched::SpawnCrashPad(proc->pid);
Sched::ExitProcess(); Sched::ExitProcess();
__builtin_unreachable(); __builtin_unreachable();
+49 -3
View File
@@ -1388,11 +1388,57 @@ namespace Sched {
return &processTable[slot]; return &processTable[slot];
} }
int SpawnCrashPad() { int SpawnCrashPad(int crasherPid) {
// Spawn crashpad as a child of init (slot 0), not the crashing process. // Spawn crashpad as a child of init (slot 0), not the crashing process.
// We can't use the current process context since we're in ExitProcess. // The crasher is still alive here (we run before its ExitProcess), but
// it is about to die, so we must not parent the crashpad to it.
static constexpr const char* crashpadPath = "0:/apps/crashpad/crashpad.elf"; static constexpr const char* crashpadPath = "0:/apps/crashpad/crashpad.elf";
return Spawn(crashpadPath, nullptr);
// If the crashing process had a redirected console (i.e. it was running
// under terminal.elf in a console session), hand the crashpad a write
// handle to that same out-stream so it can surface a textual crash
// report to the console user when no desktop is running.
Process* crasher = GetProcessByPid(crasherPid);
int crasherSlot = Ipc::SlotForPid(crasherPid);
bool inheritRedir = crasher && crasher->redirected &&
crasher->ioOutHandle >= 0 && crasherSlot >= 0;
Ipc::Object* outObj = nullptr;
Ipc::HandleType outType = Ipc::HandleType::None;
uint32_t outRights = 0;
if (inheritRedir) {
if (!Ipc::SnapshotHandleForSlot(crasherSlot, crasher->ioOutHandle,
outType, outObj, outRights) ||
outType != Ipc::HandleType::Stream || outObj == nullptr) {
inheritRedir = false;
}
}
// Deferred start when inheriting, so we can wire ioOutHandle before _start.
int childPid = Spawn(crashpadPath, nullptr, /*startReady=*/!inheritRedir);
if (childPid < 0 || !inheritRedir) return childPid;
Process* child = GetProcessByPid(childPid);
int childSlot = Ipc::SlotForPid(childPid);
if (child && childSlot >= 0) {
// Installing with RightWrite retains the stream (writerRefs++/refs++),
// so it outlives the crasher's imminent ExitProcess teardown. The
// snapshot above and this install run back-to-back with no blocking
// call between, while the crasher's handle still pins the stream.
int h = Ipc::InstallHandleForSlot(childSlot, outObj, Ipc::HandleType::Stream,
Ipc::RightWrite | Ipc::RightWait | Ipc::RightDup);
if (h >= 0) {
child->ioOutHandle = h;
child->redirected = true;
child->parentPid = crasherPid;
child->termCols = crasher->termCols;
child->termRows = crasher->termRows;
}
}
// Always start it (even if wiring failed -> it just falls back to silent).
StartProcess(childPid);
return childPid;
} }
} }
+5 -3
View File
@@ -190,9 +190,11 @@ namespace Sched {
// Find a process by PID (returns nullptr if not found or not alive) // Find a process by PID (returns nullptr if not found or not alive)
Process* GetProcessByPid(int pid); Process* GetProcessByPid(int pid);
// Spawn a crashpad process with the given crash file path as argument. // Spawn the crashpad to report on a faulted process (pid `crasherPid`).
// Called by the exception handler when a process faults. // Called by the exception handler when a process faults. If the crasher had
int SpawnCrashPad(); // a redirected console, the crashpad inherits its out-stream so it can print
// a textual report to a console session with no desktop.
int SpawnCrashPad(int crasherPid);
// Get a pointer to slot i in the process table (for enumeration) // Get a pointer to slot i in the process table (for enumeration)
Process* GetProcessSlot(int slot); Process* GetProcessSlot(int slot);
+57 -1
View File
@@ -1,6 +1,6 @@
/* /*
* main.cpp * main.cpp
* MontaukOS Crashpad — displays crash reports in a popup window * MontaukOS Crashpad - renders process crash information
* Copyright (c) 2026 Daniel Hammer * Copyright (c) 2026 Daniel Hammer
*/ */
@@ -13,6 +13,20 @@
using namespace gui; using namespace gui;
static bool is_desktop_running() {
static montauk::abi::ProcInfo procs[256];
int count = montauk::proclist(procs, 256);
if (count <= 0) return false;
int self_pid = montauk::getpid();
for (int i = 0; i < count; i++) {
if (montauk::streq(procs[i].name, "0:/os/desktop.elf")) {
return true;
}
}
return false;
}
static constexpr int WINDOW_W = 460; static constexpr int WINDOW_W = 460;
static constexpr int WINDOW_H = 480; static constexpr int WINDOW_H = 480;
static constexpr int PADDING = 12; static constexpr int PADDING = 12;
@@ -201,6 +215,42 @@ static void render() {
g_win.present(); g_win.present();
} }
// ==== Console (no-desktop) crash report ====
// When no desktop is running, the crashpad is spawned with its stdout
// redirected to the same out-stream as the crashed process (wired up by the
// kernel in SpawnCrashPad), so montauk::print() lands in the console terminal.
static void emit(const char* s) { montauk::print(s); }
static void emit_kv_hex(const char* key, uint64_t val) {
char buf[32];
emit(" ");
emit(key);
emit(": ");
format_hex16(buf, val);
emit(buf);
emit("\n");
}
static void render_console() {
char num[16];
emit("\n\033[1;31m*** Process crashed ***\033[0m\n");
emit("Process: ");
emit(g_report.processName);
emit(" (pid ");
format_decimal(num, g_report.pid);
emit(num);
emit(")\n");
emit("Exception: ");
emit(g_report.exceptionName);
emit("\n");
emit_kv_hex("RIP", g_report.instructionPointer);
emit_kv_hex("RSP", g_report.stackPointer);
emit_kv_hex("RFLAGS", g_report.flags);
if (g_report.exceptionVector == 0x0E)
emit_kv_hex("CR2 (fault addr)", g_report.faultingAddress);
emit("\n");
}
extern "C" void _start() { extern "C" void _start() {
fonts::init(); fonts::init();
@@ -208,6 +258,7 @@ extern "C" void _start() {
int available = montauk::crash_report(&g_report); int available = montauk::crash_report(&g_report);
if (available <= 0) montauk::exit(1); if (available <= 0) montauk::exit(1);
if (is_desktop_running()) {
if (!g_win.create("Process Crashed", WINDOW_W, WINDOW_H)) montauk::exit(1); if (!g_win.create("Process Crashed", WINDOW_W, WINDOW_H)) montauk::exit(1);
render(); render();
@@ -245,5 +296,10 @@ extern "C" void _start() {
} }
g_win.destroy(); g_win.destroy();
} else {
// No desktop: print a textual report to the redirected console.
render_console();
}
montauk::exit(0); montauk::exit(0);
} }