feat: add process crash popups
This commit is contained in:
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
#include "../desktop/font_data.cpp"
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user