feat: add process crash popups

This commit is contained in:
2026-04-07 20:15:56 +02:00
parent 54856e616b
commit 886b181bfe
17 changed files with 615 additions and 4 deletions
+48
View File
@@ -0,0 +1,48 @@
/*
* CrashReportSyscall.hpp
* SYS_CRASH_REPORT
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include "Syscall.hpp"
#include "../CrashReport.hpp"
namespace Montauk {
static int64_t Sys_CrashReport(CrashReportInfo* out) {
if (!out) return 0;
if (CrashReport::g_reportCount == 0) return 0;
int oldestIdx = (CrashReport::g_reportHead - CrashReport::g_reportCount + CrashReport::MaxReports) % CrashReport::MaxReports;
auto* rep = &CrashReport::g_reports[oldestIdx];
out->pid = rep->pid;
for (int i = 0; i < 64 && rep->processName[i]; i++) out->processName[i] = rep->processName[i];
out->processName[63] = '\0';
out->exceptionVector = rep->exceptionVector;
for (int i = 0; i < 32 && rep->exceptionName[i]; i++) out->exceptionName[i] = rep->exceptionName[i];
out->exceptionName[31] = '\0';
out->faultingAddress = rep->faultingAddress;
out->instructionPointer = rep->instructionPointer;
out->stackPointer = rep->stackPointer;
out->codeSegment = rep->codeSegment;
out->flags = rep->flags;
out->stackSegment = rep->stackSegment;
out->pfPresent = rep->pfPresent;
out->pfWrite = rep->pfWrite;
out->pfUser = rep->pfUser;
out->pfReservedWrite = rep->pfReservedWrite;
out->pfInstructionFetch = rep->pfInstructionFetch;
out->pfProtectionKey = rep->pfProtectionKey;
out->pfShadowStack = rep->pfShadowStack;
out->pfSGX = rep->pfSGX;
out->timestampTick = rep->timestampTick;
rep->valid = false;
CrashReport::g_reportCount--;
return CrashReport::g_reportCount + 1;
}
}
+3
View File
@@ -34,6 +34,7 @@
#include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
#include "IpcSyscall.hpp" // SYS_DUPHANDLE, SYS_WAIT_HANDLE, SYS_STREAM_CREATE, SYS_STREAM_READ, SYS_STREAM_WRITE, SYS_MAILBOX_CREATE, SYS_MAILBOX_SEND, SYS_MAILBOX_RECV, SYS_WAITSET_CREATE, SYS_WAITSET_ADD, SYS_WAITSET_REMOVE, SYS_WAITSET_WAIT, SYS_PROC_OPEN, SYS_SURFACE_CREATE, SYS_SURFACE_MAP, SYS_SURFACE_RESIZE
#include "LibSyscall.hpp" // SYS_LOAD_LIB, SYS_UNLOAD_LIB, SYS_DLSYM
#include "CrashReportSyscall.hpp" // SYS_CRASH_REPORT
// Assembly entry point
extern "C" void SyscallEntry();
@@ -419,6 +420,8 @@ namespace Montauk {
return (int64_t)Sys_DLSym(frame->arg1, frame->arg2);
case SYS_GETLIBBASE:
return (int64_t)Sys_GetLibBase(frame->arg1);
case SYS_CRASH_REPORT:
return Sys_CrashReport((CrashReportInfo*)frame->arg1);
default:
return -1;
}
+26
View File
@@ -212,6 +212,9 @@ namespace Montauk {
static constexpr uint64_t SYS_DLSYM = 116;
static constexpr uint64_t SYS_GETLIBBASE = 117;
/* CrashReport.hpp */
static constexpr uint64_t SYS_CRASH_REPORT = 118;
static constexpr uint32_t IPC_SIGNAL_READABLE = 1u << 0;
static constexpr uint32_t IPC_SIGNAL_WRITABLE = 1u << 1;
static constexpr uint32_t IPC_SIGNAL_PEER_CLOSED = 1u << 2;
@@ -422,6 +425,29 @@ namespace Montauk {
uint32_t _pad;
};
// Crash report (filled by kernel on process fault, returned via SYS_CRASH_REPORT)
struct CrashReportInfo {
int pid;
char processName[64];
uint8_t exceptionVector;
char exceptionName[32];
uint64_t faultingAddress;
uint64_t instructionPointer;
uint64_t stackPointer;
uint64_t codeSegment;
uint64_t flags;
uint64_t stackSegment;
uint8_t pfPresent : 1;
uint8_t pfWrite : 1;
uint8_t pfUser : 1;
uint8_t pfReservedWrite : 1;
uint8_t pfInstructionFetch : 1;
uint8_t pfProtectionKey : 1;
uint8_t pfShadowStack : 1;
uint8_t pfSGX : 1;
uint64_t timestampTick;
};
// Stack frame pushed by SyscallEntry.asm
struct SyscallFrame {
uint64_t r15, r14, r13, r12, rbp, rbx; // callee-saved
+21
View File
@@ -0,0 +1,21 @@
/*
* CrashReport.cpp
* Structured crash report implementation
* Copyright (c) 2026 Daniel Hammer
*/
#include "CrashReport.hpp"
namespace CrashReport {
Report g_reports[MaxReports];
int g_reportHead = 0;
int g_reportCount = 0;
void AddReport(const Report& report) {
g_reports[g_reportHead] = report;
g_reportHead = (g_reportHead + 1) % MaxReports;
if (g_reportCount < MaxReports) g_reportCount++;
}
} // namespace CrashReport
+50
View File
@@ -0,0 +1,50 @@
/*
* CrashReport.hpp
* Structured crash report for userspace process faults
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <cstddef>
namespace CrashReport {
static constexpr int MaxReports = 8;
struct Report {
int pid;
char processName[64];
uint8_t exceptionVector;
char exceptionName[32];
uint64_t faultingAddress;
uint64_t instructionPointer;
uint64_t stackPointer;
uint64_t codeSegment;
uint64_t flags;
uint64_t stackSegment;
// Page fault error code bits (vector 0xE / page fault only)
uint8_t pfPresent : 1;
uint8_t pfWrite : 1;
uint8_t pfUser : 1;
uint8_t pfReservedWrite : 1;
uint8_t pfInstructionFetch : 1;
uint8_t pfProtectionKey : 1;
uint8_t pfShadowStack : 1;
uint8_t pfSGX : 1;
uint64_t timestampTick;
bool valid;
};
// Kernel-side ring buffer (written by exception handlers, read by SYS_CRASH_REPORT)
extern Report g_reports[MaxReports];
extern int g_reportHead;
extern int g_reportCount;
// Add a report to the kernel ring buffer
void AddReport(const Report& report);
} // namespace CrashReport
+46
View File
@@ -12,6 +12,8 @@
#include <CppLib/Stream.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include <Sched/Scheduler.hpp>
#include "CrashReport.hpp"
#include <Timekeeping/ApicTimer.hpp>
namespace Hal {
constexpr auto InterruptGate = 0x8E;
@@ -87,6 +89,50 @@ namespace Hal {
<< ExceptionStrings[i] << " in process \""
<< proc->name << "\" (pid " << proc->pid
<< ") - process terminated";
// Capture crash report
CrashReport::Report rep;
rep.valid = true;
rep.pid = proc->pid;
for (int j = 0; j < 64 && proc->name[j]; j++) rep.processName[j] = proc->name[j];
rep.processName[63] = '\0';
rep.exceptionVector = i;
for (int j = 0; j < 32 && ExceptionStrings[i][j]; j++) rep.exceptionName[j] = ExceptionStrings[i][j];
rep.exceptionName[31] = '\0';
rep.instructionPointer = frame->IP;
rep.codeSegment = frame->CS;
rep.flags = frame->Flags;
rep.stackPointer = frame->SP;
rep.stackSegment = frame->SS;
if (i == 0x0E) {
// Page fault: read CR2 for faulting address
asm volatile("mov %%cr2, %0" : "=r"(rep.faultingAddress));
auto* pf = (System::PageFaultPanicFrame*)frame;
rep.pfPresent = pf->PageFaultError.Present;
rep.pfWrite = pf->PageFaultError.Write;
rep.pfUser = pf->PageFaultError.User;
rep.pfReservedWrite = pf->PageFaultError.ReservedWrite;
rep.pfInstructionFetch = pf->PageFaultError.InstructionFetch;
rep.pfProtectionKey = pf->PageFaultError.ProtectionKey;
rep.pfShadowStack = pf->PageFaultError.ShadowStack;
rep.pfSGX = pf->PageFaultError.SGX;
} else {
rep.faultingAddress = 0;
rep.pfPresent = 0;
rep.pfWrite = 0;
rep.pfUser = 0;
rep.pfReservedWrite = 0;
rep.pfInstructionFetch = 0;
rep.pfProtectionKey = 0;
rep.pfShadowStack = 0;
rep.pfSGX = 0;
}
rep.timestampTick = Timekeeping::GetTicks();
CrashReport::AddReport(rep);
Sched::SpawnCrashPad();
Sched::ExitProcess();
__builtin_unreachable();
} else {
+7
View File
@@ -902,4 +902,11 @@ namespace Sched {
return &processTable[slot];
}
int SpawnCrashPad() {
// 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.
static constexpr const char* crashpadPath = "0:/apps/crashpad/crashpad.elf";
return Spawn(crashpadPath, nullptr);
}
}
+4
View File
@@ -122,6 +122,10 @@ namespace Sched {
// Find a process by PID (returns nullptr if not found or not alive)
Process* GetProcessByPid(int pid);
// Spawn a crashpad process with the given crash file path as argument.
// Called by the exception handler when a process faults.
int SpawnCrashPad();
// Get a pointer to slot i in the process table (for enumeration)
Process* GetProcessSlot(int slot);
+9 -4
View File
@@ -59,7 +59,7 @@ BINDIR := bin
PROGRAMS := $(notdir $(wildcard src/*))
# Programs with custom Makefiles (built separately).
CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator desktop login shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs test_dl libloader libhello
CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator desktop login shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs test_dl libloader libhello crashpad
SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS))
# Build targets: system programs go to bin/os/, apps go to bin/apps/<name>/.
@@ -81,9 +81,9 @@ CA_CERTS := $(BINDIR)/etc/ca-certificates.crt
# Common shared assets (wallpapers, etc.)
COMMONKEEP := $(BINDIR)/common/.keep
.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs icons fonts bearssl libc tls libjpeg libjpegwrite install-apps libloader libs libhello test_dl
.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs icons fonts bearssl libc tls libjpeg libjpegwrite install-apps libloader libs libhello test_dl crashpad
all: bearssl libc libjpeg libjpegwrite tls libloader libs libhello $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs login desktop shell icons fonts install-apps test_dl $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP)
all: bearssl libc libjpeg libjpegwrite tls libloader libs libhello $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers printd printctl dialogs login desktop shell icons fonts install-apps test_dl crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP)
# Build BearSSL static library (cross-compiled for freestanding x86_64).
BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc)
@@ -277,12 +277,16 @@ printctl: bearssl libc tls
dialogs: bearssl libc tls
$(MAKE) -C src/dialogs
# Build crashpad (crash reporter popup, depends on libc).
crashpad: libc
$(MAKE) -C src/crashpad
# Build test_dl (dynamic loading test app, depends on libloader).
test_dl: libloader libs
$(MAKE) -C src/test_dl
# Install app bundles (manifests, icons, data files) into bin/apps/<name>/.
install-apps: doom rpgdemo paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator screenshot texteditor mandelbrot printers dialogs
install-apps: doom rpgdemo paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer volume music video bluetooth terminal klog procmgr calculator screenshot texteditor mandelbrot printers dialogs crashpad
../scripts/install_apps.sh
# Copy man pages into bin/man/ so mkramdisk.sh picks them up.
@@ -350,6 +354,7 @@ clean:
$(MAKE) -C src/printd clean
$(MAKE) -C src/printctl clean
$(MAKE) -C src/dialogs clean
$(MAKE) -C src/crashpad clean
$(MAKE) -C src/libloader clean
$(MAKE) -C libs/libmath clean
$(MAKE) -C libs/libhello clean
+26
View File
@@ -150,6 +150,9 @@ namespace Montauk {
static constexpr uint64_t SYS_DLSYM = 116;
static constexpr uint64_t SYS_GETLIBBASE = 117;
/* CrashReport */
static constexpr uint64_t SYS_CRASH_REPORT = 118;
static constexpr uint32_t IPC_SIGNAL_READABLE = 1u << 0;
static constexpr uint32_t IPC_SIGNAL_WRITABLE = 1u << 1;
static constexpr uint32_t IPC_SIGNAL_PEER_CLOSED = 1u << 2;
@@ -369,4 +372,27 @@ namespace Montauk {
uint64_t pageSize;
};
// Crash report (filled by kernel on process fault, returned via SYS_CRASH_REPORT)
struct CrashReportInfo {
int pid;
char processName[64];
uint8_t exceptionVector;
char exceptionName[32];
uint64_t faultingAddress;
uint64_t instructionPointer;
uint64_t stackPointer;
uint64_t codeSegment;
uint64_t flags;
uint64_t stackSegment;
uint8_t pfPresent : 1;
uint8_t pfWrite : 1;
uint8_t pfUser : 1;
uint8_t pfReservedWrite : 1;
uint8_t pfInstructionFetch : 1;
uint8_t pfProtectionKey : 1;
uint8_t pfShadowStack : 1;
uint8_t pfSGX : 1;
uint64_t timestampTick;
};
}
+5
View File
@@ -296,6 +296,11 @@ namespace montauk {
return (uint64_t)syscall1(Montauk::SYS_GETLIBBASE, (uint64_t)handle);
}
// Crash report retrieval
inline int crash_report(Montauk::CrashReportInfo* out) {
return (int)syscall1(Montauk::SYS_CRASH_REPORT, (uint64_t)out);
}
// Process management
inline void waitpid(int pid) { syscall1(Montauk::SYS_WAITPID, (uint64_t)pid); }
Binary file not shown.
+79
View File
@@ -0,0 +1,79 @@
# Makefile for crashpad (standalone Window Server app) on MontaukOS
# Copyright (c) 2026 Daniel Hammer
MAKEFLAGS += -rR
.SUFFIXES:
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
CXX := $(TOOLCHAIN_PREFIX)g++
else
CXX := g++
endif
PROG_INC := ../../include
LINK_LD := ../../link.ld
BINDIR := ../../bin
OBJDIR := obj
LIBDIR := ../../lib
CXXFLAGS := \
-std=gnu++20 \
-g -O2 -pipe \
-Wall \
-Wextra \
-Wno-unused-parameter \
-Wno-unused-function \
-nostdinc \
-ffreestanding \
-fno-stack-protector \
-fno-stack-check \
-fno-PIC \
-fno-rtti \
-fno-exceptions \
-ffunction-sections \
-fdata-sections \
-m64 \
-march=x86-64 \
-msse \
-msse2 \
-mno-red-zone \
-mcmodel=small \
-MMD -MP \
-I $(PROG_INC) \
-isystem $(PROG_INC)/libc \
-I ../../lib/bearssl/inc \
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
-isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include
LDFLAGS := \
-nostdlib \
-static \
-Wl,--build-id=none \
-Wl,--gc-sections \
-Wl,-m,elf_x86_64 \
-z max-page-size=0x1000 \
-T $(LINK_LD)
SRCS := main.cpp stb_truetype_impl.cpp font_data.cpp
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
TARGET := $(BINDIR)/apps/crashpad/crashpad.elf
LIBS := $(LIBDIR)/libc/liblibc.a
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBS)
mkdir -p $(BINDIR)/apps/crashpad
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(OBJDIR)/%.o: %.cpp Makefile
mkdir -p $(OBJDIR)
$(CXX) $(CXXFLAGS) -c $< -o $@
-include $(OBJS:.o=.d)
clean:
rm -rf $(OBJDIR) $(TARGET)
+1
View File
@@ -0,0 +1 @@
#include "../desktop/font_data.cpp"
+249
View File
@@ -0,0 +1,249 @@
/*
* main.cpp
* MontaukOS Crashpad — displays crash reports in a popup window
* Copyright (c) 2026 Daniel Hammer
*/
#include <montauk/syscall.h>
#include <montauk/heap.h>
#include <montauk/string.h>
#include <gui/standalone.hpp>
#include <gui/gui.hpp>
#include <gui/font.hpp>
using namespace gui;
static constexpr int WINDOW_W = 460;
static constexpr int WINDOW_H = 480;
static constexpr int PADDING = 12;
static constexpr int HEADER_H = 48;
static constexpr int COL1_W = 200;
static constexpr int SECTION_GAP = 10;
WsWindow g_win;
Montauk::CrashReportInfo g_report = {};
int g_scroll = 0;
// Colors - light theme matching DiskDetail
static constexpr Color BG = Color::from_rgb(0xFF, 0xFF, 0xFF);
static constexpr Color ROW_EVEN = Color::from_rgb(0xF7, 0xF7, 0xF7);
static constexpr Color ACCENT = Color::from_rgb(0x33, 0x66, 0xCC);
static constexpr Color BORDER = Color::from_rgb(0xE0, 0xE0, 0xE0);
static constexpr Color TEXT_COLOR = Color::from_rgb(0x22, 0x22, 0x22);
static constexpr Color DIM_TEXT = Color::from_rgb(0x66, 0x66, 0x66);
static constexpr Color VALUE_COL = Color::from_rgb(0x22, 0x22, 0x22);
// Custom hex formatter (avoids snprintf which isn't in freestanding libc)
static void format_hex16(char* out, uint64_t val) {
out[0] = '0';
out[1] = 'x';
static const char hex[] = "0123456789ABCDEF";
for (int i = 0; i < 16; i++) {
out[2 + i] = hex[(val >> (60 - i * 4)) & 0xF];
}
out[18] = '\0';
}
static void format_decimal(char* out, int val) {
if (val == 0) {
out[0] = '0';
out[1] = '\0';
return;
}
if (val < 0) {
*out++ = '-';
val = -val;
}
char tmp[16];
int i = 0;
while (val > 0) {
tmp[i++] = '0' + (val % 10);
val /= 10;
}
while (i > 0) {
*out++ = tmp[--i];
}
*out = '\0';
}
// Draw a section header label + horizontal rule
static void section_header(Canvas& c, int& y, int w, int fh, const char* label) {
if (y < -fh - 8 || y > c.h + fh + 8) {
y += fh + 8;
return;
}
c.text(PADDING, y, label, ACCENT);
y += fh;
c.hline(PADDING, y, w - PADDING * 2, BORDER);
y += 2;
}
// Draw one alternating table row (key left, value right)
static void table_row(Canvas& c, int& y, int row_h, int col1_w, int w,
int rowIdx, const char* key, const char* val, Color val_col) {
if (y > c.h + row_h || y < -row_h) {
y += row_h;
return;
}
if (rowIdx % 2 == 0)
c.fill_rect(PADDING, y, w - PADDING * 2, row_h, ROW_EVEN);
int ty = y + (row_h - system_font_height()) / 2;
c.text(PADDING + 8, ty, key, DIM_TEXT);
c.text(PADDING + col1_w + 8, ty, val, val_col);
y += row_h;
}
static void render() {
if (g_win.id < 0) return;
Canvas c = g_win.canvas();
c.fill(BG);
int fh = system_font_height();
int row_h = fh + 8;
int w = g_win.width;
int y = PADDING - g_scroll;
int rowIdx = 0;
// Process info header (outside table)
if (y >= -fh * 2 && y < c.h + fh) {
char buf[128];
char* p = buf;
// Process name (large, white)
const char* name = g_report.processName;
while (*name) *p++ = *name++;
*p++ = ' ';
*p++ = '(';
*p++ = 'P';
*p++ = 'I';
*p++ = 'D';
*p++ = ' ';
format_decimal(p, g_report.pid);
while (*p) p++;
*p++ = ')';
*p = '\0';
c.text(PADDING, y, buf, TEXT_COLOR);
y += fh + 4;
// Exception name below
char excbuf[64];
p = excbuf;
const char* exc = g_report.exceptionName;
while (*exc) *p++ = *exc++;
*p++ = ' ';
*p++ = '(';
*p++ = 'v';
*p++ = 'e';
*p++ = 'c';
*p++ = 't';
*p++ = 'o';
*p++ = 'r';
*p++ = ' ';
*p++ = '0';
*p++ = 'x';
static const char hex[] = "0123456789ABCDEF";
*p++ = hex[(g_report.exceptionVector >> 4) & 0xF];
*p++ = hex[g_report.exceptionVector & 0xF];
*p++ = ')';
*p++ = '\0';
c.text(PADDING, y, excbuf, DIM_TEXT);
y += fh;
} else {
y += fh + 4 + fh;
}
y += SECTION_GAP;
// Registers section
section_header(c, y, w, fh, "Registers");
char hexbuf[32];
auto draw_hex_row = [&](const char* key, uint64_t val) {
format_hex16(hexbuf, val);
table_row(c, y, row_h, COL1_W, w, rowIdx++, key, hexbuf, VALUE_COL);
};
draw_hex_row("Instruction Pointer", g_report.instructionPointer);
draw_hex_row("Code Segment", g_report.codeSegment);
draw_hex_row("Flags", g_report.flags);
draw_hex_row("Stack Pointer", g_report.stackPointer);
draw_hex_row("Stack Segment", g_report.stackSegment);
y += SECTION_GAP;
// Page Fault section (only for vector 0x0E)
if (g_report.exceptionVector == 0x0E) {
section_header(c, y, w, fh, "Page Fault");
format_hex16(hexbuf, g_report.faultingAddress);
table_row(c, y, row_h, COL1_W, w, rowIdx++, "Faulting Address (CR2)", hexbuf,
TEXT_COLOR);
// Error code bits
auto draw_pf_bit = [&](const char* label, bool val) {
Color col = val ? Color::from_rgb(0x22, 0x88, 0x22) : Color::from_rgb(0xAA, 0xAA, 0xAA);
table_row(c, y, row_h, COL1_W, w, rowIdx++, label, val ? "1" : "0", col);
};
draw_pf_bit("Present", g_report.pfPresent);
draw_pf_bit("Write", g_report.pfWrite);
draw_pf_bit("User", g_report.pfUser);
draw_pf_bit("Reserved Write", g_report.pfReservedWrite);
draw_pf_bit("Instruction Fetch", g_report.pfInstructionFetch);
draw_pf_bit("Protection Key", g_report.pfProtectionKey);
draw_pf_bit("Shadow Stack", g_report.pfShadowStack);
draw_pf_bit("SGX", g_report.pfSGX);
y += SECTION_GAP;
}
g_win.present();
}
extern "C" void _start() {
fonts::init();
// Poll for crash report
int available = montauk::crash_report(&g_report);
if (available <= 0) montauk::exit(1);
if (!g_win.create("Process Crashed", WINDOW_W, WINDOW_H)) montauk::exit(1);
render();
while (true) {
Montauk::WinEvent ev;
int r = g_win.poll(&ev);
if (r < 0) break;
if (r == 0) {
montauk::sleep_ms(16);
continue;
}
if (ev.type == 3) break; // close
if (ev.type == 0 && ev.key.pressed) {
if (ev.key.scancode == 0x01) break; // Escape
if (ev.key.scancode == 0x51) {
// Page Down: scroll down
g_scroll += 60;
render();
}
if (ev.key.scancode == 0x49) {
// Page Up: scroll up
g_scroll -= 60;
if (g_scroll < 0) g_scroll = 0;
render();
}
}
if (ev.type == 2) {
// Resize
render();
}
}
g_win.destroy();
montauk::exit(0);
}
+8
View File
@@ -0,0 +1,8 @@
[app]
name = "Crashpad"
binary = "crashpad.elf"
icon = ""
[menu]
category = "System"
visible = false
@@ -0,0 +1,33 @@
/*
* stb_truetype_impl.cpp
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
* Copyright (c) 2026 Daniel Hammer
*/
#include <cstdint>
#include <cstddef>
#include <montauk/heap.h>
#include <montauk/string.h>
#include <gui/stb_math.h>
#define STBTT_ifloor(x) ((int) stb_floor(x))
#define STBTT_iceil(x) ((int) stb_ceil(x))
#define STBTT_sqrt(x) stb_sqrt(x)
#define STBTT_pow(x,y) stb_pow(x,y)
#define STBTT_fmod(x,y) stb_fmod(x,y)
#define STBTT_cos(x) stb_cos(x)
#define STBTT_acos(x) stb_acos(x)
#define STBTT_fabs(x) stb_fabs(x)
#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x))
#define STBTT_free(x,u) ((void)(u), montauk::mfree(x))
#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n)
#define STBTT_memset(d,v,n) montauk::memset(d,v,n)
#define STBTT_strlen(x) montauk::slen(x)
#define STBTT_assert(x) ((void)(x))
#define STB_TRUETYPE_IMPLEMENTATION
#include <gui/stb_truetype.h>